Mantid
Loading...
Searching...
No Matches
SmoothData.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
12
13namespace Mantid::Algorithms {
14
15// Register the algorithm into the AlgorithmFactory
16DECLARE_ALGORITHM(SmoothData)
17
18using namespace Kernel;
19using namespace API;
20using HistogramData::Histogram;
21
23 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input),
24 "Name of the input workspace");
25 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
26 "The name of the workspace to be created as the output of the algorithm");
27 std::vector<int> npts0{3};
28 auto min = std::make_shared<Kernel::ArrayBoundedValidator<int>>();
29 min->setLower(3);
30 // The number of points to use in the smoothing.
31 declareProperty(std::make_unique<ArrayProperty<int>>("NPoints", std::move(npts0), std::move(min), Direction::Input),
32 "The number of points to average over (minimum 3). If an even number is\n"
33 "given, it will be incremented by 1 to make it odd (default value 3)");
35 "GroupingWorkspace", "", Direction::Input, PropertyMode::Optional),
36 "Optional: GroupingWorkspace to use for vector of NPoints.");
37}
38
40 // Get the input properties
41 inputWorkspace = getProperty("InputWorkspace");
42
43 std::vector<int> nptsGroup = getProperty("NPoints");
44 Mantid::DataObjects::GroupingWorkspace_sptr groupWS = getProperty("GroupingWorkspace");
45 if (groupWS) {
46 udet2group.clear();
47 int64_t nGroups;
48 groupWS->makeDetectorIDToGroupVector(udet2group, nGroups);
49 }
50
51 // Check that the number of points in the smoothing isn't larger than the
52 // spectrum length
53 const auto vecSize = static_cast<int>(inputWorkspace->blocksize());
54
55 // Create the output workspace
57
58 Progress progress(this, 0.0, 1.0, inputWorkspace->getNumberHistograms());
60 for (int i = 0; i < static_cast<int>(inputWorkspace->getNumberHistograms()); ++i) {
62 int npts = nptsGroup[0];
63 if (groupWS) {
64 const int group = validateSpectrumInGroup(static_cast<size_t>(i));
65 if (group == -1) {
66 npts = 3;
67 } else {
68 assert(group != 0);
69 npts = nptsGroup[group - 1];
70 }
71 }
72 if (npts >= vecSize) {
73 g_log.error("The number of averaging points requested is larger than the "
74 "spectrum length");
75 throw std::out_of_range("The number of averaging points requested is "
76 "larger than the spectrum length");
77 }
78 // Number of smoothing points must always be an odd number, so add 1 if it
79 // isn't.
80 if (!(npts % 2)) {
81 g_log.information("Adding 1 to number of smoothing points, since it must "
82 "always be odd");
83 ++npts;
84 }
85
86 outputWorkspace->setHistogram(i, smooth(inputWorkspace->histogram(i), npts));
87
88 progress.report();
90 } // Loop over spectra
92
93 // Set the output workspace to its property
94 setProperty("OutputWorkspace", outputWorkspace);
95} // namespace Algorithms
96//=============================================================================
103 const auto &dets = inputWorkspace->getSpectrum(wi).getDetectorIDs();
104 if (dets.empty()) // Not in group
105 {
106 g_log.debug() << wi << " <- this workspace index is empty!\n";
107 return -1;
108 }
109
110 auto it = dets.cbegin();
111 if (*it < 0) // bad pixel id
112 return -1;
113
114 try { // what if index out of range?
115 const int group = udet2group.at(*it);
116 if (group <= 0)
117 return -1;
118 ++it;
119 for (; it != dets.end(); ++it) // Loop all other udets
120 {
121 if (udet2group.at(*it) != group)
122 return -1;
123 }
124 return group;
125 } catch (...) {
126 }
127
128 return -1;
129}
130
132Histogram smooth(const Histogram &histogram, int npts) {
133 if (npts == 0)
134 return histogram;
135 int halfWidth = (npts - 1) / 2;
136
137 Histogram smoothed(histogram);
138
139 const auto &Y = histogram.y();
140 const auto &E = histogram.e();
141 auto &newY = smoothed.mutableY();
142 auto &newE = smoothed.mutableE();
143 // Use total to help hold our moving average
144 double total = 0.0, totalE = 0.0;
145 // First push the values ahead of the current point onto total
146 for (int k = 0; k < halfWidth; ++k) {
147 if (Y[k] == Y[k])
148 total += Y[k]; // Exclude if NaN
149 totalE += E[k] * E[k];
150 }
151 // Now calculate the smoothed values for the 'end' points, where the number
152 // contributing
153 // to the smoothing will be less than NPoints
154 for (int j = 0; j <= halfWidth; ++j) {
155 const int index = j + halfWidth;
156 if (Y[index] == Y[index])
157 total += Y[index]; // Exclude if NaN
158 newY[j] = total / (index + 1);
159 totalE += E[index] * E[index];
160 newE[j] = sqrt(totalE) / (index + 1);
161 }
162 // This is the main part, where each data point is the average of NPoints
163 // points centred on the
164 // current point. Note that the statistical error will be reduced by
165 // sqrt(npts) because more
166 // data is now contributing to each point.
167 const auto vecSize = static_cast<int>(histogram.size());
168 for (int k = halfWidth + 1; k < vecSize - halfWidth; ++k) {
169 const int kp = k + halfWidth;
170 const int km = k - halfWidth - 1;
171 total += (Y[kp] != Y[kp] ? 0.0 : Y[kp]) - (Y[km] != Y[km] ? 0.0 : Y[km]); // Exclude if NaN
172 newY[k] = total / npts;
173 totalE += E[kp] * E[kp] - E[km] * E[km];
174 // Use of a moving average can lead to rounding error where what should be
175 // zero actually comes out as a tiny negative number - bad news for sqrt
176 // so protect
177 newE[k] = std::sqrt(std::abs(totalE)) / npts;
178 }
179 // This deals with the 'end' at the tail of each spectrum
180 for (int l = vecSize - halfWidth; l < vecSize; ++l) {
181 const int index = l - halfWidth;
182 total -= (Y[index - 1] != Y[index - 1] ? 0.0 : Y[index - 1]); // Exclude if NaN
183 newY[l] = total / (vecSize - index);
184 totalE -= E[index - 1] * E[index - 1];
185 newE[l] = std::sqrt(std::abs(totalE)) / (vecSize - index);
186 }
187 return smoothed;
188}
189
190} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
Definition: MultiThreaded.h:94
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
std::vector< int > udet2group
Definition: SmoothData.h:62
void init() override
Initialisation code.
Definition: SmoothData.cpp:22
API::MatrixWorkspace_const_sptr inputWorkspace
Definition: SmoothData.h:63
int validateSpectrumInGroup(size_t wi)
Verify that all the contributing detectors to a spectrum belongs to the same group.
Definition: SmoothData.cpp:102
void exec() override
Execution code.
Definition: SmoothData.cpp:39
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
HistogramData::Histogram smooth(const HistogramData::Histogram &histogram, int npts)
std::shared_ptr< GroupingWorkspace > GroupingWorkspace_sptr
shared pointer to the GroupingWorkspace class
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
Definition: MultiThreaded.h:22
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54