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 +
14
15#include <boost/algorithm/string/detail/classification.hpp>
16#include <boost/algorithm/string/split.hpp>
17
18namespace Mantid::Algorithms {
19
20// Register the class into the algorithm factory
21DECLARE_ALGORITHM(FFTSmooth2)
22
23using namespace Kernel;
24using namespace API;
25
28 declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
29 "The name of the input workspace.");
30 declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
31 "The name of the output workspace.");
32
33 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
34 mustBePositive->setLower(0);
35 declareProperty("WorkspaceIndex", 0, mustBePositive, "Workspace index for smoothing");
36
37 std::vector<std::string> type{"Zeroing", "Butterworth"};
38 declareProperty("Filter", "Zeroing", std::make_shared<StringListValidator>(type), "The type of the applied filter");
39 declareProperty("Params", "",
40 "The filter parameters:\n"
41 "For Zeroing, 1 parameter: 'n' - an integer greater than 1 "
42 "meaning that the Fourier coefficients with frequencies "
43 "outside the 1/n of the original range will be set to zero.\n"
44 "For Butterworth, 2 parameters: 'n' and 'order', giving the "
45 "1/n truncation and the smoothing order.\n");
46
47 declareProperty("IgnoreXBins", false,
48 "Ignores the requirement that X bins be linear and of the same size.\n"
49 "Set this to true if you are using log binning.\n"
50 "The output X axis will be the same as the input either way.");
51 declareProperty("AllSpectra", false, "Smooth all spectra");
52}
53
57 API::MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
59 bool ignoreXBins = getProperty("IgnoreXBins");
60
61 // First spectrum in input
62 int s0 = getProperty("WorkspaceIndex");
63 // By default only do one
64 int send = s0 + 1;
65 if (getProperty("AllSpectra")) { // Except if AllSpectra
66 s0 = 0;
67 send = static_cast<int>(inWS->getNumberHistograms());
68 }
69 // Create output
71 API::WorkspaceFactory::Instance().create(inWS, send - s0, inWS->x(0).size(), inWS->y(0).size());
72
73 // Symmetrize the input spectrum
74 auto dn = static_cast<int>(inWS->y(0).size());
76 API::WorkspaceFactory::Instance().create("Workspace2D", 1, inWS->x(0).size() + dn, inWS->y(0).size() + dn);
77
78 Progress progress(this, 0.0, 1.0, 4 * (send - s0));
79
80 for (int spec = s0; spec < send; spec++) {
81 // Save the starting x value so it can be restored after all transforms.
82 double x0 = inWS->x(spec)[0];
83
84 double dx = (inWS->x(spec).back() - inWS->x(spec).front()) / (static_cast<double>(inWS->x(spec).size()) - 1.0);
85
86 progress.report();
87
88 auto &symX = symmWS->mutableX(0);
89 auto &symY = symmWS->mutableY(0);
90
91 for (int i = 0; i < dn; i++) {
92 symX[dn + i] = inWS->x(spec)[i];
93 symY[dn + i] = inWS->y(spec)[i];
94
95 symX[dn - i] = x0 - dx * i;
96 symY[dn - i] = inWS->y(spec)[i];
97 }
98 symY.front() = inWS->y(spec).back();
99 symX.front() = x0 - dx * dn;
100 if (inWS->isHistogramData())
101 symX.back() = inWS->x(spec).back();
102
103 // setProperty("OutputWorkspace",symmWS); return;
104
105 progress.report("Calculating FFT");
106 // Forward Fourier transform
107 auto fft = createChildAlgorithm("RealFFT", 0, 0.5);
108 fft->setProperty("InputWorkspace", symmWS);
109 fft->setProperty("WorkspaceIndex", 0);
110 fft->setProperty("IgnoreXBins", ignoreXBins);
111 try {
112 fft->execute();
113 } catch (...) {
114 g_log.error("Error in direct FFT algorithm");
115 throw;
116 }
117
118 API::MatrixWorkspace_sptr unfilteredWS = fft->getProperty("OutputWorkspace");
119 API::MatrixWorkspace_sptr filteredWS;
120
121 // Apply the filter
122 std::string type = getProperty("Filter");
123
124 if (type == "Zeroing") {
125 std::string sn = getProperty("Params");
126 int n;
127 if (sn.empty())
128 n = 2;
129 else
130 n = std::stoi(sn);
131 if (n <= 1)
132 throw std::invalid_argument("Truncation parameter must be an integer > 1");
133
134 progress.report("Zero Filter");
135
136 zero(n, unfilteredWS, filteredWS);
137 } else if (type == "Butterworth") {
138 int n, order;
139
140 std::string string_params = getProperty("Params");
141 std::vector<std::string> params;
142 boost::split(params, string_params, boost::algorithm::detail::is_any_ofF<char>(" ,:;\t"));
143 if (params.size() != 2) {
144 n = 2;
145 order = 2;
146 } else {
147 std::string param0 = params.at(0);
148 std::string param1 = params.at(1);
149 n = std::stoi(param0);
150 order = std::stoi(param1);
151 }
152 if (n <= 1)
153 throw std::invalid_argument("Truncation parameter must be an integer > 1");
154 if (order < 1)
155 throw std::invalid_argument("Butterworth filter order must be an integer >= 1");
156
157 progress.report("ButterWorth Filter");
158 Butterworth(n, order, unfilteredWS, filteredWS);
159 }
160
161 progress.report("Backward Transformation");
162 // Backward transform
163 fft = createChildAlgorithm("RealFFT", 0.5, 1.);
164 fft->setProperty("InputWorkspace", filteredWS);
165 fft->setProperty("Transform", "Backward");
166 fft->setProperty("IgnoreXBins", ignoreXBins);
167 try {
168 fft->execute();
169 } catch (...) {
170 g_log.error("Error in inverse FFT algorithm");
171 throw;
172 }
173 API::MatrixWorkspace_sptr tmpWS = fft->getProperty("OutputWorkspace");
174
175 // FIXME: The intent of the following line is not clear. std::floor or
176 // std::ceil should
177 // probably be used.
178 dn = static_cast<int>(tmpWS->blocksize()) / 2;
179
180 if (getProperty("AllSpectra")) {
181 outWS->setSharedX(spec, inWS->sharedX(spec));
182 outWS->mutableY(spec).assign(tmpWS->y(0).cbegin() + dn, tmpWS->y(0).cend());
183 } else {
184 outWS->setSharedX(0, inWS->sharedX(spec));
185 outWS->mutableY(0).assign(tmpWS->y(0).cbegin() + dn, tmpWS->y(0).cend());
186 }
187 }
188
189 setProperty("OutputWorkspace", outWS);
190}
191
199 auto mx = static_cast<int>(unfilteredWS->x(0).size());
200 auto my = static_cast<int>(unfilteredWS->y(0).size());
201 int ny = my / n;
202
203 if (ny == 0)
204 ny = 1;
205
206 filteredWS = API::WorkspaceFactory::Instance().create(unfilteredWS, 2, mx, my);
207
208 filteredWS->setSharedX(0, unfilteredWS->sharedX(0));
209 filteredWS->setSharedX(1, unfilteredWS->sharedX(0));
210
211 std::copy(unfilteredWS->y(0).cbegin(), unfilteredWS->y(0).begin() + ny, filteredWS->mutableY(0).begin());
212
213 std::copy(unfilteredWS->y(1).cbegin(), unfilteredWS->y(1).begin() + ny, filteredWS->mutableY(1).begin());
214}
215
229void FFTSmooth2::Butterworth(int n, int order, API::MatrixWorkspace_sptr &unfilteredWS,
230 API::MatrixWorkspace_sptr &filteredWS) {
231 auto mx = static_cast<int>(unfilteredWS->x(0).size());
232 auto my = static_cast<int>(unfilteredWS->y(0).size());
233 int ny = my / n;
234
235 if (ny == 0)
236 ny = 1;
237
238 filteredWS = API::WorkspaceFactory::Instance().create(unfilteredWS, 2, mx, my);
239
240 filteredWS->setSharedX(0, unfilteredWS->sharedX(0));
241 filteredWS->setSharedX(1, unfilteredWS->sharedX(0));
242
243 auto &Yr = unfilteredWS->y(0);
244 auto &Yi = unfilteredWS->y(1);
245 auto &yr = filteredWS->mutableY(0);
246 auto &yi = filteredWS->mutableY(1);
247
248 double cutoff = ny;
249
250 for (int i = 0; i < my; i++) {
251 double scale = 1.0 / (1.0 + pow(static_cast<double>(i) / cutoff, 2 * order));
252 yr[i] = scale * Yr[i];
253 yi[i] = scale * Yi[i];
254 }
255}
256
257} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
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
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Definition: Algorithm.cpp:842
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.
void exec() override
Executes the algorithm.
Definition: FFTSmooth2.cpp:56
void init() override
Initialisation method. Declares properties to be used in algorithm.
Definition: FFTSmooth2.cpp:27
void zero(int n, API::MatrixWorkspace_sptr &unfilteredWS, API::MatrixWorkspace_sptr &filteredWS)
Smoothing by zeroing.
Definition: FFTSmooth2.cpp:198
void Butterworth(int n, int order, API::MatrixWorkspace_sptr &unfilteredWS, API::MatrixWorkspace_sptr &filteredWS)
Smoothing using Butterworth filter.
Definition: FFTSmooth2.cpp:229
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
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
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54