Mantid
Loading...
Searching...
No Matches
PaddingAndApodization.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
12
19#include "MantidHistogramData/Histogram.h"
24
25#include <cmath>
26#include <numeric>
27#include <vector>
28
29namespace Mantid::Algorithms {
30
31using namespace Kernel;
32using namespace DataObjects;
33using namespace HistogramData;
34using API::Progress;
35using std::size_t;
36
37// Register the class into the algorithm factory
38DECLARE_ALGORITHM(PaddingAndApodization)
39
40
44 declareProperty(
45 std::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
46 "The name of the input 2D workspace.");
47 declareProperty(
48 std::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
49 "The name of the output 2D workspace.");
50 declareProperty(
51 "ApodizationFunction", "None",
52 std::make_shared<Mantid::Kernel::StringListValidator>(std::vector<std::string>{"None", "Lorentz", "Gaussian"}),
53 "The apodization function to apply to the data");
54 declareProperty("DecayConstant", 1.5, "The decay constant for the apodization function.");
55 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<int>>();
56 mustBePositive->setLower(0);
57 declareProperty("Padding", 0, mustBePositive,
58 "The amount of padding to add to the data,"
59 "it is the number of multiples of the data set."
60 "i.e 0 means no padding and 1 will double the number of data points.");
61 declareProperty("NegativePadding", false,
62 "If true padding is added to "
63 "both sides of the original data. Both sides "
64 "share the padding");
65}
66
71 // Get original workspace
72 API::MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
73 auto numSpectra = inputWS->getNumberHistograms();
74 // Create output workspace with same dimensions as input
75 API::MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
76 if (inputWS != outputWS) {
77 outputWS = create<API::MatrixWorkspace>(*inputWS);
78 }
79
80 // Share the X values
81 for (size_t i = 0; i < static_cast<size_t>(numSpectra); ++i) {
82 outputWS->setSharedX(i, inputWS->sharedX(i));
83 }
84
85 std::vector<int> spectra;
86 spectra = std::vector<int>(numSpectra);
87 std::iota(spectra.begin(), spectra.end(), 0);
88
89 Progress prog(this, 0.0, 1.0, numSpectra + spectra.size());
90 if (inputWS != outputWS) {
91
92 // Copy all the Y and E data
93 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
94 for (int64_t i = 0; i < int64_t(numSpectra); ++i) {
96
97 if (std::find(spectra.begin(), spectra.end(), i) != spectra.end()) {
98 const auto index = static_cast<size_t>(i);
99 outputWS->setSharedY(index, inputWS->sharedY(index));
100 outputWS->setSharedE(index, inputWS->sharedE(index));
101 }
102 prog.report();
104 }
106 }
107 const std::string method = getProperty("ApodizationFunction");
108 const double decayConstant = getProperty("DecayConstant");
109 const int padding = getProperty("Padding");
110 fptr apodizationFunction = getApodizationFunction(method);
111 // Do the specified spectra only
112 auto specLength = static_cast<int>(spectra.size());
113 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
114 for (int i = 0; i < specLength; ++i) {
116 const auto specNum = static_cast<size_t>(spectra[i]);
117
118 if (spectra[i] > static_cast<int>(numSpectra)) {
119 throw std::invalid_argument("The spectral index " + std::to_string(spectra[i]) +
120 " is greater than the number of spectra!");
121 }
122 // Create output ws
123 outputWS->setHistogram(specNum, applyApodizationFunction(addPadding(inputWS->histogram(specNum), padding),
124 decayConstant, apodizationFunction));
125 prog.report();
127 }
129 setProperty("OutputWorkspace", outputWS);
130}
131
132using fptr = double (*)(const double, const double);
140 if (method == "None") {
142 } else if (method == "Lorentz") {
144 } else if (method == "Gaussian") {
146 }
147 throw std::invalid_argument("The apodization function selected " + method + " is not a valid option");
148}
156HistogramData::Histogram PaddingAndApodization::applyApodizationFunction(const HistogramData::Histogram &histogram,
157 const double decayConstant, fptr function) {
158 HistogramData::Histogram result(histogram);
159
160 auto &xData = result.mutableX();
161 auto &yData = result.mutableY();
162 auto &eData = result.mutableE();
163
164 for (size_t i = 0; i < yData.size(); ++i) {
165 yData[i] *= function(xData[i], decayConstant);
166 eData[i] *= function(xData[i], decayConstant);
167 }
168
169 return result;
170}
180HistogramData::Histogram PaddingAndApodization::addPadding(const HistogramData::Histogram &histogram,
181 const int padding) {
182 if (padding == 0) {
183 return histogram;
184 }
185
186 auto &xData = histogram.x();
187 auto &yData = histogram.y();
188 auto &eData = histogram.e();
189 auto incEData = eData.size() > 0 ? true : false;
190 // assume approx evenly spaced
191 if (xData.size() < 2) {
192 throw std::invalid_argument("The xData does not contain "
193 "enought data points to add padding"
194 "dx = 0");
195 }
196 const double dx = xData[1] - xData[0];
197 const auto dataSize = yData.size() * (1 + padding);
198
199 // Create histogram with the same structure as histogram
200 HistogramData::Histogram result(histogram);
201 // Resize result to new size.
202 result.resize(dataSize);
203 auto &newXData = result.mutableX();
204 auto &newYData = result.mutableY();
205 auto &newEData = result.mutableE();
206
207 // Start x counter at 1 dx below the first value to make
208 // the std::generate algorithm work correctly.
209 double x = xData.front() - dx;
210 size_t offset = 0;
211 bool negativePadding = getProperty("NegativePadding");
212 if (negativePadding) {
213 // non-zero offset is for padding before the data
214 offset = padding * yData.size() / 2;
215 x -= dx * double(offset);
216 }
217
218 // This covers all x values, no need to copy from xData
219 std::generate(newXData.begin(), newXData.end(), [&x, &dx] {
220 x += dx;
221 return x;
222 });
223
224 // Do not rely on Histogram::resize to fill the extra elements with 0s
225 // Fill in all ys with 0s first
226 std::fill(newYData.begin(), newYData.end(), 0.0);
227 // Then copy the old yData to the appropriate positions
228 std::copy(yData.begin(), yData.end(), newYData.begin() + offset);
229
230 if (incEData) {
231 // The same reasoning as for ys
232 std::fill(newEData.begin(), newEData.end(), 0.0);
233 std::copy(eData.begin(), eData.end(), newEData.begin() + offset);
234 }
235
236 return result;
237}
238
239} // 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.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
Takes a workspace as input and applies a apodization function and/or padding.
void exec() override
Executes the algorithm.
HistogramData::Histogram addPadding(const HistogramData::Histogram &histogram, const int padding)
Adds padding to the data.
double(*)(const double, const double) fptr
HistogramData::Histogram applyApodizationFunction(const HistogramData::Histogram &histogram, const double decayConstant, fptr function)
Applies the appodization function to the data.
fptr getApodizationFunction(const std::string &method)
Gets a pointer to the relevant apodization function.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
double none(const double, const double)
Returns no apodization function.
double lorentz(double time, double decayConstant)
Returns the evaluation of the Lorentz (an exponential decay) apodization function at a time (t) and d...
double gaussian(const double time, const double decayConstant)
Returns the evaluation of the Gaussian apodization function at a time (t) and decay constant tau: f =...
double(*)(const double, const double) fptr
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
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