-
Notifications
You must be signed in to change notification settings - Fork 122
/
SplineInterpolation.cpp
259 lines (213 loc) · 8.91 KB
/
SplineInterpolation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#include "MantidAPI/TextAxis.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidAPI/Progress.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidCurveFitting/Algorithms/SplineInterpolation.h"
namespace Mantid {
namespace CurveFitting {
namespace Algorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(SplineInterpolation)
using namespace API;
using namespace Kernel;
using Functions::CubicSpline;
//----------------------------------------------------------------------------------------------
/** Constructor
*/
SplineInterpolation::SplineInterpolation()
: m_cspline(boost::make_shared<CubicSpline>()) {}
//----------------------------------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string SplineInterpolation::name() const {
return "SplineInterpolation";
}
/// Algorithm's version for identification. @see Algorithm::version
int SplineInterpolation::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string SplineInterpolation::category() const {
return "Optimization;CorrectionFunctions\\BackgroundCorrections";
}
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void SplineInterpolation::init() {
declareProperty(make_unique<WorkspaceProperty<>>("WorkspaceToMatch", "",
Direction::Input),
"The workspace which defines the points of the spline.");
declareProperty(
make_unique<WorkspaceProperty<>>("WorkspaceToInterpolate", "",
Direction::Input),
"The workspace on which to perform the interpolation algorithm.");
declareProperty(
make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
Direction::Output),
"The workspace containing the calculated points and derivatives");
declareProperty(make_unique<WorkspaceProperty<WorkspaceGroup>>(
"OutputWorkspaceDeriv", "", Direction::Output,
PropertyMode::Optional),
"The workspace containing the calculated derivatives");
auto validator = boost::make_shared<BoundedValidator<int>>(0, 2);
declareProperty("DerivOrder", 2, validator,
"Order to derivatives to calculate.");
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void SplineInterpolation::exec() {
// read in algorithm parameters
int order = static_cast<int>(getProperty("DerivOrder"));
// set input workspaces
MatrixWorkspace_sptr mws = getProperty("WorkspaceToMatch");
MatrixWorkspace_sptr iws = getProperty("WorkspaceToInterpolate");
int histNo = static_cast<int>(iws->getNumberHistograms());
// vector of multiple derivative workspaces
std::vector<MatrixWorkspace_sptr> derivs(histNo);
// warn user that we only use first spectra in matching workspace
if (mws->getNumberHistograms() > 1) {
g_log.warning()
<< "Algorithm can only interpolate against a single data set. "
"Only the first data set will be used.\n";
}
// convert data to binned data as required
MatrixWorkspace_sptr mwspt = convertBinnedData(mws);
MatrixWorkspace_const_sptr iwspt = convertBinnedData(iws);
MatrixWorkspace_sptr outputWorkspace = setupOutputWorkspace(mws, iws);
Progress pgress(this, 0.0, 1.0, histNo);
// for each histogram in workspace, calculate interpolation and derivatives
for (int i = 0; i < histNo; ++i) {
// Create and instance of the cubic spline function
m_cspline = boost::make_shared<CubicSpline>();
// set the interpolation points
setInterpolationPoints(iwspt, i);
// compare the data set against our spline
calculateSpline(mwspt, outputWorkspace, i);
outputWorkspace->setX(i, mws->refX(0));
// check if we want derivatives
if (order > 0) {
derivs[i] = WorkspaceFactory::Instance().create(mws, order);
auto vAxis = new API::NumericAxis(order);
// calculate the derivatives for each order chosen
for (int j = 0; j < order; ++j) {
vAxis->setValue(j, j + 1);
derivs[i]->setX(j, mws->refX(0));
calculateDerivatives(mwspt, derivs[i], j + 1);
}
derivs[i]->replaceAxis(1, vAxis);
}
pgress.report();
}
// Store the output workspaces
std::string derivWsName = getPropertyValue("OutputWorkspaceDeriv");
if (order > 0 && derivWsName != "") {
// Store derivatives in a grouped workspace
WorkspaceGroup_sptr wsg = WorkspaceGroup_sptr(new WorkspaceGroup);
for (int i = 0; i < histNo; ++i) {
wsg->addWorkspace(derivs[i]);
}
setProperty("OutputWorkspaceDeriv", wsg);
}
setProperty("OutputWorkspace", outputWorkspace);
}
/**Copy the meta data for the input workspace to an output workspace and create
*it with the desired number of spectra.
* Also labels the axis of each spectra with Yi, where i is the index
*
* @param mws :: The input workspace to match
* @param iws :: The input workspace to interpolate
* @return The pointer to the newly created workspace
*/
API::MatrixWorkspace_sptr
SplineInterpolation::setupOutputWorkspace(API::MatrixWorkspace_sptr mws,
API::MatrixWorkspace_sptr iws) const {
size_t numSpec = iws->getNumberHistograms();
MatrixWorkspace_sptr outputWorkspace =
WorkspaceFactory::Instance().create(mws, numSpec);
// Use the vertical axis form the workspace to interpolate on the output WS
Axis *vAxis = iws->getAxis(1)->clone(mws.get());
outputWorkspace->replaceAxis(1, vAxis);
return outputWorkspace;
}
/**Convert a binned workspace to point data
*
* @param workspace :: The input workspace
* @return the converted workspace containing point data
*/
MatrixWorkspace_sptr
SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) const {
if (workspace->isHistogramData()) {
size_t histNo = workspace->getNumberHistograms();
size_t size = workspace->readY(0).size();
// make a new workspace for the point data
MatrixWorkspace_sptr pointWorkspace =
WorkspaceFactory::Instance().create(workspace, histNo, size, size);
// loop over each histogram
for (size_t i = 0; i < histNo; ++i) {
const auto &xValues = workspace->readX(i);
const auto &yValues = workspace->readY(i);
auto &newXValues = pointWorkspace->dataX(i);
auto &newYValues = pointWorkspace->dataY(i);
// set x values to be average of bin bounds
for (size_t j = 0; j < size; ++j) {
newXValues[j] = (xValues[j] + xValues[j + 1]) / 2;
newYValues[j] = yValues[j];
}
}
return pointWorkspace;
}
return workspace;
}
/** Sets the points defining the spline
*
* @param inputWorkspace :: The input workspace containing the points of the
*spline
* @param row :: The row of spectra to use
*/
void SplineInterpolation::setInterpolationPoints(
MatrixWorkspace_const_sptr inputWorkspace, const int row) const {
const auto &xIn = inputWorkspace->readX(row);
const auto &yIn = inputWorkspace->readY(row);
int size = static_cast<int>(xIn.size());
// pass x attributes and y parameters to CubicSpline
m_cspline->setAttributeValue("n", size);
for (int i = 0; i < size; ++i) {
m_cspline->setXAttribute(i, xIn[i]);
m_cspline->setParameter(i, yIn[i]);
}
}
/** Calculate the derivatives of the given order from the interpolated points
*
* @param inputWorkspace :: The input workspace
* @param outputWorkspace :: The output workspace
* @param order :: The order of derivatives to calculate
*/
void SplineInterpolation::calculateDerivatives(
API::MatrixWorkspace_const_sptr inputWorkspace,
API::MatrixWorkspace_sptr outputWorkspace, int order) const {
// get x and y parameters from workspaces
size_t nData = inputWorkspace->readY(0).size();
const double *xValues = inputWorkspace->readX(0).data();
double *yValues = outputWorkspace->dataY(order - 1).data();
// calculate the derivatives
m_cspline->derivative1D(yValues, xValues, nData, order);
}
/** Calculate the interpolation of the input points against the spline
*
* @param inputWorkspace :: The input workspace
* @param outputWorkspace :: The output workspace
* @param row :: The row of spectra to use
*/
void SplineInterpolation::calculateSpline(
MatrixWorkspace_const_sptr inputWorkspace,
MatrixWorkspace_sptr outputWorkspace, int row) const {
// setup input parameters
size_t nData = inputWorkspace->readY(0).size();
const double *xValues = inputWorkspace->readX(0).data();
double *yValues = outputWorkspace->dataY(row).data();
// calculate the interpolation
m_cspline->function1D(yValues, xValues, nData);
}
} // namespace Algorithms
} // namespace CurveFitting
} // namespace Mantid