Mantid
Loading...
Searching...
No Matches
FFTSmooth2.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 +
19
20#include <boost/algorithm/string/detail/classification.hpp>
21#include <boost/algorithm/string/split.hpp>
22
24
25// Register the class into the algorithm factory
26DECLARE_ALGORITHM(FFTSmooth2)
27
28using namespace Kernel;
29using namespace API;
30
31namespace {
32enum class FilterType { ZERO, BUTTERWORTH, enum_count };
33const std::vector<std::string> filterTypes{"Zeroing", "Butterworth"};
35} // namespace
36
37namespace {
38typedef std::size_t param_t;
45class FFTParamsProperty : public ArrayProperty<param_t> {
46public:
47 FFTParamsProperty(std::string const &name, std::vector<param_t> const &defaultValue)
48 : ArrayProperty<param_t>(name, defaultValue) {}
49 std::string setValue(std::string const &value) override {
50 std::string valueCopy(value);
51 boost::trim(valueCopy);
52 for (char const delim : m_delims) {
53 valueCopy = Kernel::Strings::replaceAll(valueCopy, delim, m_sep);
54 }
55 std::vector<param_t> result;
56 toValue(valueCopy, result);
57 *this = result;
58 return "";
59 }
60
61 // Unhide the base class assignment operator
62 using PropertyWithValue<std::vector<param_t>>::operator=;
63
64private:
65 static char constexpr m_sep = ',';
66 static char constexpr m_delims[] = {'\t', ' ', ':', ';'};
67};
68} // namespace
69
74 "The name of the input workspace.");
77 "The name of the output workspace.");
78
79 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
80 mustBePositive->setLower(0);
81 declareProperty(PropertyNames::WKSP_INDEX, 0, mustBePositive, "Workspace index for smoothing");
82
84 "The type of the applied filter");
85
86 declareProperty(std::make_unique<FFTParamsProperty>(PropertyNames::PARAMS, std::vector<param_t>(2, 2)),
87 "The filter parameters:\n"
88 "For Zeroing, 1 parameter: 'n' - an integer greater than 1 "
89 "meaning that the Fourier coefficients with frequencies "
90 "outside the 1/n of the original range will be set to zero.\n"
91 "For Butterworth, 2 parameters: 'n' and 'order', giving the "
92 "1/n truncation and the smoothing order.\n");
93
95 "Ignores the requirement that X bins be linear and of the same size.\n"
96 "Set this to true if you are using log binning.\n"
97 "The output X axis will be the same as the input either way.");
98 declareProperty(PropertyNames::ALL_SPECTRA, false, "Smooth all spectra");
99}
100
101std::map<std::string, std::string> FFTSmooth2::validateInputs() {
102 std::map<std::string, std::string> issues;
104 auto groupWS = dynamic_cast<API::WorkspaceGroup const *>(inWS.get());
105 if (groupWS != nullptr) {
106 for (std::size_t idx = 0; idx < groupWS->size(); idx++) {
107 auto subissues = this->actuallyValidateInputs(groupWS->getItem(idx));
108 for (auto const &[key, value] : subissues) {
109 std::string new_key = key + "_" + std::to_string(idx);
110 issues[new_key] = value;
111 }
112 }
113 } else {
114 issues = this->actuallyValidateInputs(inWS);
115 }
116 return issues;
117}
118
119std::map<std::string, std::string> FFTSmooth2::actuallyValidateInputs(API::Workspace_sptr const &ws) {
120 std::map<std::string, std::string> issues;
121
122 // verify a matrix workspace has been passed
123 auto inWS = dynamic_cast<API::MatrixWorkspace const *>(ws.get());
124 if (!inWS) {
125 issues[PropertyNames::INPUT_WKSP] = "FFTSmooth requires an input matrix workspace";
126 return issues;
127 }
128 // verify the spectrum workspace index
130 if (wi >= static_cast<int>(inWS->getNumberHistograms())) {
131 issues[PropertyNames::INPUT_WKSP] = "Property WorkspaceIndex is out of range";
133 return issues;
134 }
135
136 // Check that the x values are evenly spaced
137 bool ignoreXBins = getProperty(PropertyNames::IGNORE_X_BINS);
138 if (!ignoreXBins) {
139 const auto &X = inWS->x(wi);
140 double dx = (X.back() - X.front()) / static_cast<double>(X.size() - 1);
141 for (size_t i = 0; i < X.size() - 2; i++) {
142 if (std::abs(dx - X[i + 1] + X[i]) / dx > 1e-7) {
143 issues[PropertyNames::INPUT_WKSP] = "X axis must be linear (all bins have same width). This can be ignored if "
144 "IgnoreXBins is set to true.";
146 break;
147 }
148 }
149 }
150
151 // Check that the parameters are valid
152 std::vector<param_t> params = getProperty(PropertyNames::PARAMS);
153 std::string const trunc_err = "Cutoff parameter must be an integer > 1. ";
154 std::string const order_err = "Butterworth filter order must be an integer >= 1. ";
155 std::string err_msg;
156 if (params.size() > 0 && params[0] <= 1) {
157 err_msg += trunc_err;
158 }
159 if (params.size() > 1 && params[1] < 1) {
160 err_msg += order_err;
161 }
162 if (params.size() > 2) {
163 err_msg += "Too many parameters passed";
164 }
165 if (!err_msg.empty()) {
166 issues[PropertyNames::PARAMS] = std::move(err_msg);
167 }
168 return issues;
169}
170
175
176 // retrieve parameters
177 std::size_t n = 2, order = 2;
178 std::vector<std::size_t> params = getProperty(PropertyNames::PARAMS);
179 if (params.size() == 1) {
180 n = params[0];
181 } else if (params.size() == 2) {
182 n = params[0];
183 order = params[1];
184 }
185
186 std::size_t dn = inWS->y(0).size();
187
188 // set smoothing method based on user setting
190 std::function<std::vector<double>(std::vector<double> const &)> smoothMethod;
191 switch (type) {
192 case FilterType::ZERO: {
193 // NOTE this algorithm used a cutoff *period*, whereas fftSmooth
194 // uses a cutoff number (a quantum number). The below adjusted cutoff is precisely
195 // the value needed for fftSmooth to have the same result as the prior behavior
196 // This takes into account BOTH the symmetrization op below, AND the halfcomplex packing
197 // | symm_size = 2 * dn
198 // | halfcomplex size of symm = symm_size / 2 = dn
199 // so correct size to use is dn
200 unsigned adjusted_cutoff = (n > dn ? 1 : static_cast<unsigned>((dn + 1) / n));
201 smoothMethod = [adjusted_cutoff](std::vector<double> const &y) {
202 return Kernel::Smoothing::fftSmooth(y, adjusted_cutoff);
203 };
204 break;
205 }
206 case FilterType::BUTTERWORTH: {
207 // see note above about adjusted cutoff
208 unsigned adjusted_cutoff = (n > dn ? 1 : static_cast<unsigned>((dn + 1) / n));
209 smoothMethod = [adjusted_cutoff, order](std::vector<double> const &y) {
210 return Kernel::Smoothing::fftButterworthSmooth(y, adjusted_cutoff, static_cast<unsigned int>(order));
211 };
212 break;
213 }
214 default: {
215 smoothMethod = [](std::vector<double> const &y) { return y; };
216 }
217 }
218
219 // First spectrum in input
221 // By default only do one
222 std::size_t send = s0 + 1;
223 if (getProperty(PropertyNames::ALL_SPECTRA)) { // Except if AllSpectra
224 s0 = 0;
225 send = inWS->getNumberHistograms();
226 }
227 // Create output
229 API::WorkspaceFactory::Instance().create(inWS, send - s0, inWS->x(0).size(), inWS->y(0).size());
230
231 Progress progress(this, 0.0, 1.0, 4 * (send - s0));
232
233 for (std::size_t spec = s0; spec < send; spec++) {
234 progress.report();
235
236 // Symmetrize the input vector.
237 // The below pictograph illustrates the transformation from original to "symmetrized"
238 // o : oo o
239 // oo o| : |o oo oo o|
240 // o oo | ----> | oo o o oo |
241 // o | : | o |
242 // ^i=0 ^i=dn-1 : ^i=1 ^i=dn ^i=2*dn-1
243 // NOTE it's unknown why this operation was originally added.
244 // It is necessary to retain this operation to support legacy behavior.
245 std::vector<double> symY(2 * dn);
246 for (std::size_t i = 0; i < dn; i++) {
247 symY[dn + i] = inWS->y(spec)[i];
248 symY[dn - i] = inWS->y(spec)[i];
249 }
250 symY.front() = inWS->y(spec).back();
251
252 // Apply the filter
253 progress.report("Applying Filter");
254 std::vector<double> tmpY = smoothMethod(symY);
255
256 // assign
258 outWS->setSharedX(spec, inWS->sharedX(spec));
259 outWS->mutableY(spec).assign(tmpY.cbegin() + dn, tmpY.cend());
260 } else {
261 outWS->setSharedX(0, inWS->sharedX(spec));
262 outWS->mutableY(0).assign(tmpY.cbegin() + dn, tmpY.cend());
263 }
264 }
265
267}
268} // namespace Mantid::Algorithms::FFTSmooth
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
static char constexpr m_sep
static char constexpr m_delims[]
const std::vector< std::string > filterTypes
double value
The value of the point.
Definition FitMW.cpp:51
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Base MatrixWorkspace Abstract Class.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
Class to hold a set of workspaces.
A property class for workspaces.
void init() override
Initialisation method. Declares properties to be used in algorithm.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
void exec() override
Executes the algorithm.
std::map< std::string, std::string > actuallyValidateInputs(API::Workspace_sptr const &)
Mantid::Kernel::EnumeratedString< FilterType, &filterTypes > FILTER
Support for a property that holds an array of values.
A concrete property based on user options of a finite list of strings.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string const OUTPUT_WKSP("OutputWorkspace")
std::string const INPUT_WKSP("InputWorkspace")
std::string const IGNORE_X_BINS("IgnoreXBins")
std::string const ALL_SPECTRA("AllSpectra")
std::string const WKSP_INDEX("WorkspaceIndex")
std::vector< Y > fftButterworthSmooth(std::vector< Y > const &input, unsigned const cutoff, unsigned const order)
Performs FFT smoothing on the input data, using a Butterworth filter NOTE: the input data MUST be def...
std::vector< Y > fftSmooth(std::vector< Y > const &input, unsigned const cutoff)
Performs FFT smoothing on the input data, with high frequencies set to zero NOTE: the input data MUST...
MANTID_KERNEL_DLL std::string replaceAll(std::string const &input, char const to_replace, char const substitute)
Return a string with all occurrences of indicated character replaced by the new character.
Definition Strings.cpp:90
void toValue(const std::string &strvalue, T &value)
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54