Mantid
Loading...
Searching...
No Matches
SplineSmoothing.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 +
11#include "MantidAPI/Progress.h"
12#include "MantidAPI/TextAxis.h"
16
17#include <algorithm>
18
20
21// Register the algorithm into the AlgorithmFactory
22DECLARE_ALGORITHM(SplineSmoothing)
23
24using namespace API;
25using namespace Kernel;
26using Functions::BSpline;
27//----------------------------------------------------------------------------------------------
30SplineSmoothing::SplineSmoothing()
31 : M_START_SMOOTH_POINTS(10), m_cspline(std::make_shared<BSpline>()), m_inputWorkspace(),
32 m_inputWorkspacePointData(), m_derivativeWorkspaceGroup(new WorkspaceGroup) {}
33
34//----------------------------------------------------------------------------------------------
36const std::string SplineSmoothing::name() const { return "SplineSmoothing"; }
37
39int SplineSmoothing::version() const { return 1; }
40
42const std::string SplineSmoothing::category() const {
43 return "Optimization;CorrectionFunctions\\BackgroundCorrections";
44}
45
46//----------------------------------------------------------------------------------------------
49void SplineSmoothing::init() {
50 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
51 "The workspace on which to perform the smoothing algorithm.");
52
53 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
54 "The workspace containing the calculated points");
55
56 declareProperty(std::make_unique<WorkspaceProperty<WorkspaceGroup>>("OutputWorkspaceDeriv", "", Direction::Output,
58 "The workspace containing the calculated derivatives");
59
60 auto validator = std::make_shared<BoundedValidator<int>>();
61 validator->setLower(0);
62 validator->setUpper(2);
63 declareProperty("DerivOrder", 0, validator, "Order to derivatives to calculate.");
64
65 auto errorSizeValidator = std::make_shared<BoundedValidator<double>>();
66 errorSizeValidator->setLower(0.0);
67 declareProperty("Error", 0.05, errorSizeValidator, "The amount of error we wish to tolerate in smoothing");
68
69 auto numOfBreaks = std::make_shared<BoundedValidator<int>>();
70 numOfBreaks->setLower(0);
71 declareProperty("MaxNumberOfBreaks", 0, numOfBreaks,
72 "To set the positions of the break-points, default 0 "
73 "equally spaced real values in interval 0.0 - 1.0");
74}
75
76//----------------------------------------------------------------------------------------------
79void SplineSmoothing::exec() {
80 m_inputWorkspace = getProperty("InputWorkspace");
81
82 auto histNo = static_cast<int>(m_inputWorkspace->getNumberHistograms());
83 int order = static_cast<int>(getProperty("DerivOrder"));
84
87
88 if (order > 0 && getPropertyValue("OutputWorkspaceDeriv").empty()) {
89 throw std::runtime_error("You must specify an output workspace for the spline derivatives.");
90 }
91
92 Progress pgress(this, 0.0, 1.0, histNo);
93 for (int i = 0; i < histNo; ++i) {
96 pgress.report();
97 }
98
99 if (m_inputWorkspace->isHistogramData()) {
101 }
102
103 setProperty("OutputWorkspace", m_outputWorkspace);
104
105 if (m_derivativeWorkspaceGroup->size() > 0) {
106 setProperty("OutputWorkspaceDeriv", m_derivativeWorkspaceGroup);
107 }
108}
109
114void SplineSmoothing::smoothSpectrum(const int index) {
115 m_cspline = std::make_shared<BSpline>();
116 m_cspline->setAttributeValue("Uniform", false);
117
118 // choose some smoothing points from input workspace
121
122 m_outputWorkspace->setPoints(index, m_inputWorkspace->points(index));
123
125}
126
132void SplineSmoothing::calculateSpectrumDerivatives(const int index, const int order) {
133 if (order > 0) {
135
136 for (int j = 0; j < order; ++j) {
137 derivs->setSharedX(j, m_inputWorkspace->sharedX(index));
139 }
140
141 m_derivativeWorkspaceGroup->addWorkspace(derivs);
142 }
143}
144
150void SplineSmoothing::performAdditionalFitting(const MatrixWorkspace_sptr &ws, const int row) {
151 // perform additional fitting of the points
152 auto fit = createChildAlgorithm("Fit");
153 fit->setProperty("Function", std::dynamic_pointer_cast<IFunction>(m_cspline));
154 fit->setProperty("InputWorkspace", ws);
155 fit->setProperty("MaxIterations", 5);
156 fit->setProperty("WorkspaceIndex", row);
157 fit->execute();
158}
159
168API::MatrixWorkspace_sptr SplineSmoothing::setupOutputWorkspace(const MatrixWorkspace_sptr &inws,
169 const int size) const {
170 // Must pass a shared pointer instead of a reference as the
171 // workspace factory will not accept raw pointers.
172 MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(inws, size);
173
174 // create labels for output workspace
175 auto tAxis = std::make_unique<API::TextAxis>(size);
176 for (int i = 0; i < size; ++i) {
177 const std::string index = std::to_string(i);
178 tAxis->setLabel(i, "Y" + index);
179 }
180 outputWorkspace->replaceAxis(1, std::move(tAxis));
181
182 return outputWorkspace;
183}
184
190MatrixWorkspace_sptr SplineSmoothing::convertBinnedData(MatrixWorkspace_sptr workspace) {
191 if (workspace->isHistogramData()) {
192 auto alg = createChildAlgorithm("ConvertToPointData");
193 alg->setProperty("InputWorkspace", workspace);
194 alg->execute();
195 return alg->getProperty("OutputWorkspace");
196 } else {
197 return workspace;
198 }
199}
200
205void SplineSmoothing::convertToHistogram() {
206 auto alg = createChildAlgorithm("ConvertToHistogram");
207 alg->setProperty("InputWorkspace", m_outputWorkspace);
208 alg->execute();
209 m_outputWorkspace = alg->getProperty("OutputWorkspace");
210}
211
219void SplineSmoothing::calculateSmoothing(const MatrixWorkspace &inputWorkspace, MatrixWorkspace &outputWorkspace,
220 size_t row) const {
221 // define the spline's parameters
222 const auto &xIn = inputWorkspace.x(row);
223 const size_t nData = xIn.size();
224 const double *xValues = &(xIn[0]);
225 double *yValues = &(outputWorkspace.mutableY(row)[0]);
226
227 // calculate the smoothing
228 m_cspline->function1D(yValues, xValues, nData);
229}
230
239void SplineSmoothing::calculateDerivatives(const MatrixWorkspace &inputWorkspace, API::MatrixWorkspace &outputWorkspace,
240 const int order, const size_t row) const {
241 const auto &xIn = inputWorkspace.x(row);
242 const double *xValues = &(xIn[0]);
243 double *yValues = &(outputWorkspace.mutableY(order - 1)[0]);
244 const size_t nData = xIn.size();
245
246 m_cspline->derivative1D(yValues, xValues, nData, order);
247}
248
258bool SplineSmoothing::checkSmoothingAccuracy(const int start, const int end, const double *ys,
259 const double *ysmooth) const {
260 double error = getProperty("Error");
261
262 // for all values between the selected indices
263 for (int i = start; i < end; ++i) {
264 // check if the difference between points is greater than our error
265 // tolerance
266 double ydiff = fabs(ys[i] - ysmooth[i]);
267 if (ydiff > error && (end - start) > 1) {
268 return false;
269 }
270 }
271
272 return true;
273}
274
281void SplineSmoothing::addSmoothingPoints(const std::set<int> &points, const double *xs, const double *ys) const {
282 // resize the number of attributes
283 auto num_points = static_cast<int>(points.size());
284 std::vector<double> breakPoints;
285 breakPoints.reserve(num_points);
286 // set each of the x and y points to redefine the spline
287
288 std::transform(points.begin(), points.end(), std::back_inserter(breakPoints),
289 [&xs](const auto &point) { return xs[point]; });
290
291 m_cspline->setAttribute("EndX", API::IFunction::Attribute(breakPoints.back()));
292 m_cspline->setAttribute("StartX", API::IFunction::Attribute(breakPoints.front()));
293 m_cspline->setAttribute("BreakPoints", API::IFunction::Attribute(breakPoints));
294
295 int i = 0;
296 for (auto const &point : points) {
297 m_cspline->setParameter(i, ys[point]);
298 ++i;
299 }
300}
301
309void SplineSmoothing::selectSmoothingPoints(const MatrixWorkspace &inputWorkspace, const size_t row) {
310 std::set<int> smoothPts;
311 const auto &xs = inputWorkspace.x(row);
312 const auto &ys = inputWorkspace.y(row);
313
314 // retrieving number of breaks
315 int maxBreaks = static_cast<int>(getProperty("MaxNumberOfBreaks"));
316
317 auto xSize = static_cast<int>(xs.size());
318
319 // evenly space initial points over data set
320 int delta;
321
322 // if retrieved value is default zero/default
323 bool incBreaks = false;
324
325 if (maxBreaks != 0) {
326 // number of points to start with
327 int numSmoothPts(maxBreaks);
328 delta = xSize / numSmoothPts;
329 // include maxBreaks when != 0
330 incBreaks = true;
331 } else {
332 int numSmoothPts(M_START_SMOOTH_POINTS);
333 delta = xSize / numSmoothPts;
334 }
335
336 for (int i = 0; i < xSize; i += delta) {
337 smoothPts.insert(i);
338 }
339 smoothPts.insert(xSize - 1);
340
341 bool resmooth(true);
342 while (resmooth) {
343
344 if (incBreaks) {
345 if (smoothPts.size() > static_cast<unsigned>(maxBreaks + 2)) {
346 break;
347 }
348
349 } else {
350 if (smoothPts.size() >= xs.size() - 1) {
351 break;
352 }
353 }
354
355 addSmoothingPoints(smoothPts, &xs[0], &ys[0]);
356 resmooth = false;
357
358 // calculate the spline and retrieve smoothed points
359 std::vector<double> ysmooth(xSize);
360 m_cspline->function1D(ysmooth.data(), &xs[0], xSize);
361
362 // iterate over smoothing points
363 auto iter = smoothPts.cbegin();
364 int start = *iter;
365
366 for (++iter; iter != smoothPts.cend(); ++iter) {
367 int end = *iter;
368
369 // check each point falls within our range of error.
370 bool accurate = checkSmoothingAccuracy(start, end, &ys[0], ysmooth.data());
371
372 // if not, flag for resmoothing and add another point between these two
373 // data points
374 if (!accurate) {
375 resmooth = true;
376 smoothPts.insert((start + end) / 2);
377 }
378
379 start = end;
380 }
381 }
382}
383
384} // namespace Mantid::CurveFitting::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double error
Definition: IndexPeaks.cpp:133
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define fabs(x)
Definition: Matrix.cpp:22
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
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
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
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
Base MatrixWorkspace Abstract Class.
const HistogramData::HistogramX & x(const size_t index) const
HistogramData::HistogramY & mutableY(const size_t index) &
const HistogramData::HistogramY & y(const size_t index) const
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
Class to hold a set of workspaces.
A property class for workspaces.
bool checkSmoothingAccuracy(const int start, const int end, const double *ys, const double *ysmooth) const
check if the difference between smoothing points and data points is within a certain error bound
void selectSmoothingPoints(const API::MatrixWorkspace &inputWorkspace, const size_t row)
choose points to define a spline and smooth the data
std::shared_ptr< Functions::BSpline > m_cspline
CubicSpline member used to perform smoothing.
void calculateDerivatives(const API::MatrixWorkspace &inputWorkspace, API::MatrixWorkspace &outputWorkspace, const int order, const size_t row) const
calculate the derivatives for a set of points on the spline
API::MatrixWorkspace_sptr convertBinnedData(API::MatrixWorkspace_sptr workspace)
Converts histogram data to point data later processing convert a binned workspace to point data.
void addSmoothingPoints(const std::set< int > &points, const double *xs, const double *ys) const
add a set of smoothing points to the spline
API::MatrixWorkspace_sptr m_inputWorkspace
pointer to the input workspace
const int M_START_SMOOTH_POINTS
number of smoothing points to start with
API::MatrixWorkspace_sptr m_outputWorkspace
pointer to the smoothed output workspace
void calculateSmoothing(const API::MatrixWorkspace &inputWorkspace, API::MatrixWorkspace &outputWorkspace, const size_t row) const
calculate the spline based on the smoothing points chosen
API::MatrixWorkspace_sptr m_inputWorkspacePointData
pointer to the input workspace converted to point data
void convertToHistogram()
Handle converting point data back to histograms.
void performAdditionalFitting(const API::MatrixWorkspace_sptr &ws, const int row)
Use an existing fit function to tidy smoothing.
API::MatrixWorkspace_sptr setupOutputWorkspace(const API::MatrixWorkspace_sptr &inws, const int size) const
setup an output workspace using meta data from inws and taking a number of spectra
void calculateSpectrumDerivatives(const int index, const int order)
calculate derivatives for a single spectrum
API::WorkspaceGroup_sptr m_derivativeWorkspaceGroup
pointer to the output workspace group of derivatives
void smoothSpectrum(const int index)
smooth a single spectrum of the workspace
A wrapper around Eigen functions implementing a B-spline.
Definition: BSpline.h:28
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
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
STL namespace.
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