26using namespace Kernel;
27using Functions::CubicSpline;
32SplineInterpolation::SplineInterpolation() : m_cspline(
std::make_shared<
CubicSpline>()) {}
36const std::string SplineInterpolation::name()
const {
return "SplineInterpolation"; }
39int SplineInterpolation::version()
const {
return 1; }
42const std::string SplineInterpolation::category()
const {
43 return "Optimization;CorrectionFunctions\\BackgroundCorrections";
47const std::string SplineInterpolation::summary()
const {
48 return "Interpolates a set of spectra onto a spline defined by a second "
49 "input workspace. Optionally, this algorithm can also calculate "
50 "derivatives up to order 2 as a side product";
56void SplineInterpolation::init() {
58 "The workspace which defines the points of the spline.");
61 "The workspace on which to perform the interpolation algorithm.");
64 "The workspace containing the calculated points and derivatives");
68 "The workspace containing the calculated derivatives");
70 auto validator = std::make_shared<BoundedValidator<int>>(0, 2);
71 declareProperty(
"DerivOrder", 2, validator,
"Order to derivatives to calculate.");
74 "Set to true to perform linear "
75 "interpolation if only 2 points are "
82std::map<std::string, std::string> SplineInterpolation::validateInputs() {
84 std::map<std::string, std::string> result;
93 const size_t binsNo = iwsValid->blocksize();
97 result[
"WorkspaceToInterpolate"] =
"Workspace must have minimum 2 points.";
98 }
else if (binsNo == 2) {
100 result[
"WorkspaceToInterpolate"] =
"Workspace has only 2 points, "
101 "you can enable linear interpolation by "
102 "setting the property Linear2Points. Otherwise "
103 "provide a minimum of 3 points.";
104 }
else if (derivOrder == 2) {
105 result[
"DerivOrder"] =
"Linear interpolation is requested, hence "
106 "derivative order can be maximum 1.";
109 }
catch (std::length_error &) {
110 result[
"WorkspaceToInterpolate"] =
"The input workspace does not have "
111 "the same number of bins per spectrum";
114 result[
"WorkspaceToInterpolate"] =
"The input is not a MatrixWorkspace";
123void SplineInterpolation::exec() {
126 const auto order =
static_cast<size_t>(derivOrder);
132 const size_t histNo = iws->getNumberHistograms();
133 const size_t binsNo = iws->blocksize();
134 const size_t histNoToMatch = mws->getNumberHistograms();
137 std::vector<MatrixWorkspace_sptr> derivs(histNo);
140 if (histNoToMatch > 1 && !iws->isCommonBins()) {
141 g_log.
warning() <<
"The workspace to interpolate doesn't have common bins, SplineInterpolation algorithm will use "
142 "the x-axis of the first spectrum.\n";
147 Progress pgress(
this, 0.0, 1.0, histNo);
151 for (
size_t i = 0; i < histNo; ++i) {
153 auto vAxis = std::make_unique<NumericAxis>(order);
154 for (
size_t j = 0; j < order; ++j) {
155 vAxis->setValue(j,
static_cast<int>(j) + 1.);
156 derivs[i]->setSharedX(j, mws->sharedX(0));
158 derivs[i]->replaceAxis(1, std::move(vAxis));
172 for (
size_t i = 0; i < histNo; ++i) {
174 m_cspline = std::make_shared<CubicSpline>();
180 for (
size_t j = 0; j < order; ++j) {
189 if (!std::is_sorted(mwspt->x(0).rawData().begin(), mwspt->x(0).rawData().end())) {
190 throw std::runtime_error(
"X-axis of the workspace to match is not sorted. "
191 "Consider calling SortXAxis before.");
194 for (
size_t i = 0; i < histNo; ++i) {
196 std::unique_ptr<gsl_interp_accel, void (*)(gsl_interp_accel *)> acc(gsl_interp_accel_alloc(),
197 gsl_interp_accel_free);
198 std::unique_ptr<gsl_interp, void (*)(gsl_interp *)> linear(gsl_interp_alloc(gsl_interp_linear, binsNo),
200 gsl_interp_linear->init(linear.get(), &(iwspt->x(i)[0]), &(iwspt->y(i)[0]), binsNo);
206 for (
size_t k = range.first; k < range.second; ++k) {
207 gsl_interp_linear->eval(linear.get(), &(iwspt->x(i)[0]), &(iwspt->y(i)[0]), binsNo, mwspt->x(0)[k], acc.get(),
208 &(outputWorkspace->mutableY(i)[k]));
211 gsl_interp_linear->eval_deriv(linear.get(), &(iwspt->x(i)[0]), &(iwspt->y(i)[0]), binsNo, mwspt->x(0)[k],
212 acc.get(), &(derivs[i]->mutableY(0)[k]));
221 if (order > 0 && !
isDefault(
"OutputWorkspaceDeriv")) {
224 for (
size_t i = 0; i < histNo; ++i) {
225 wsg->addWorkspace(derivs[i]);
242 const size_t numSpec = iws->getNumberHistograms();
245 for (
size_t i = 0; i < numSpec; ++i) {
246 outputWorkspace->setSharedX(i, mws->sharedX(0));
249 auto vAxis = std::unique_ptr<Axis>(iws->getAxis(1)->clone(mws.get()));
250 outputWorkspace->replaceAxis(1, std::move(vAxis));
251 return outputWorkspace;
261 g_log.
warning(
"Histogram data provided, converting to point data");
263 converter->initialize();
264 converter->setProperty(
"InputWorkspace",
workspace);
265 converter->execute();
266 return converter->getProperty(
"OutputWorkspace");
279 const size_t row)
const {
280 const auto &xIn = inputWorkspace->x(row);
281 const auto &yIn = inputWorkspace->y(row);
282 const size_t size = xIn.size();
285 m_cspline->setAttributeValue(
"n",
static_cast<int>(size));
287 for (
size_t i = 0; i < size; ++i) {
301 const size_t order)
const {
303 const size_t nData = inputWorkspace->y(0).size();
304 const double *xValues = &(inputWorkspace->x(0)[0]);
305 double *yValues = &(outputWorkspace->mutableY(order - 1)[0]);
308 m_cspline->derivative1D(yValues, xValues, nData, order);
320 const size_t nData = inputWorkspace->y(0).size();
321 const double *xValues = &(inputWorkspace->x(0)[0]);
322 double *yValues = &(outputWorkspace->mutableY(row)[0]);
325 m_cspline->function1D(yValues, xValues, nData);
338 const size_t row,
const std::pair<size_t, size_t> &indices,
339 const bool doDerivs, std::vector<MatrixWorkspace_sptr> &derivs)
const {
341 const double yFirst = iwspt->y(row).front();
342 const double yLast = iwspt->y(row).back();
343 for (
size_t bin = 0; bin < indices.first; ++bin) {
344 ows->mutableY(row)[bin] = yFirst;
347 derivs[row]->mutableY(0)[bin] = 0.;
350 const size_t numBins = ows->blocksize();
351 for (
size_t bin = indices.second; bin < numBins; ++bin) {
352 ows->mutableY(row)[bin] = yLast;
355 derivs[row]->mutableY(0)[bin] = 0.;
374 auto xAxisIn = iwspt->x(row).rawData();
375 std::sort(xAxisIn.begin(), xAxisIn.end());
376 const auto &xAxisOut = mwspt->x(0).rawData();
378 size_t firstIndex = 0;
379 size_t lastIndex = xAxisOut.size();
381 if (xAxisOut.front() >= xAxisIn.back()) {
382 lastIndex = firstIndex;
383 }
else if (xAxisOut.back() <= xAxisIn.front()) {
384 firstIndex = lastIndex;
386 for (
size_t i = 0; i < xAxisOut.size(); ++i) {
387 if (xAxisOut[i] > xAxisIn.front()) {
392 for (
size_t i = 0; i < xAxisOut.size(); ++i) {
393 if (xAxisOut[i] > xAxisIn.back()) {
401 ": Will perform flat extrapolation outside bin range: " +
std::to_string(firstIndex) +
" to " +
406 return std::make_pair(firstIndex, lastIndex);
#define DECLARE_ALGORITHM(classname)
IPeaksWorkspace_sptr workspace
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
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.
bool isDefault(const std::string &name) const
Helper class for reporting progress from algorithms.
Class to hold a set of workspaces.
A property class for workspaces.
API::MatrixWorkspace_sptr setupOutputWorkspace(const API::MatrixWorkspace_sptr &mws, const API::MatrixWorkspace_sptr &iws) const
setup an output workspace using meta data from inws and taking a number of spectra
API::MatrixWorkspace_sptr convertBinnedData(API::MatrixWorkspace_sptr workspace)
convert a binned workspace to point data using ConvertToPointData
void calculateSpline(const API::MatrixWorkspace_const_sptr &inputWorkspace, const API::MatrixWorkspace_sptr &outputWorkspace, const size_t row) const
Calculate the interpolation of the input workspace against the spline and store it in outputWorkspace...
std::pair< size_t, size_t > findInterpolationRange(const API::MatrixWorkspace_const_sptr &iwspt, const API::MatrixWorkspace_sptr &mwspt, const size_t row)
Find the the interpolation range.
void setInterpolationPoints(const API::MatrixWorkspace_const_sptr &inputWorkspace, const size_t row) const
set the points that define the spline used for interpolation of a workspace
void extrapolateFlat(const API::MatrixWorkspace_sptr &ows, const API::MatrixWorkspace_const_sptr &iwspt, const size_t row, const std::pair< size_t, size_t > &indices, const bool doDerivs, std::vector< API::MatrixWorkspace_sptr > &derivs) const
Extrapolates flat for the points outside the x-range.
void calculateDerivatives(const API::MatrixWorkspace_const_sptr &inputWorkspace, const API::MatrixWorkspace_sptr &outputWorkspace, const size_t order) const
Calculate the derivatives of the input workspace from the spline.
std::shared_ptr< Functions::CubicSpline > m_cspline
CubicSpline member used to perform interpolation.
A wrapper around GSL functions implementing cubic spline interpolation.
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.
void warning(const std::string &msg)
Logs at warning level.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.