-
Notifications
You must be signed in to change notification settings - Fork 121
/
Stitch1DMany.cpp
406 lines (341 loc) · 15.5 KB
/
Stitch1DMany.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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
#include "MantidAlgorithms/Stitch1DMany.h"
#include "MantidAPI/ADSValidator.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/WorkspaceHistory.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/RebinParamsValidator.h"
#include <boost/make_shared.hpp>
using namespace Mantid::Kernel;
using namespace Mantid::API;
namespace Mantid {
namespace Algorithms {
DECLARE_ALGORITHM(Stitch1DMany)
/** Initialize the algorithm's properties.
*/
void Stitch1DMany::init() {
declareProperty(
Kernel::make_unique<ArrayProperty<std::string>>(
"InputWorkspaces", boost::make_shared<ADSValidator>()),
"Input Workspaces. List of histogram workspaces to stitch together. At "
"least 2 workspaces must be supplied for stitching and all must be of "
"the same type.");
declareProperty(make_unique<WorkspaceProperty<Workspace>>(
"OutputWorkspace", "", Direction::Output),
"Output stitched workspace.");
declareProperty(make_unique<ArrayProperty<double>>(
"Params", boost::make_shared<RebinParamsValidator>(false),
Direction::Input),
"Rebinning Parameters. See Rebin for format.");
declareProperty(
make_unique<ArrayProperty<double>>("StartOverlaps", Direction::Input),
"Start overlaps for stitched workspaces. If specified, the number of "
"StartOverlaps must be 1 less than the number of input workspaces. "
"Optional.");
declareProperty(
make_unique<ArrayProperty<double>>("EndOverlaps", Direction::Input),
"End overlaps for stitched workspaces. If specified, the number of "
"EndOverlaps must be the same as the number of StartOverlaps. Optional.");
declareProperty(make_unique<PropertyWithValue<bool>>("ScaleRHSWorkspace",
true, Direction::Input),
"Scaling either with respect to workspace 1 or workspace 2");
declareProperty(make_unique<PropertyWithValue<bool>>("UseManualScaleFactor",
false, Direction::Input),
"True to use a provided value for the scale factor.");
auto manualScaleFactorValidator =
boost::make_shared<BoundedValidator<double>>();
manualScaleFactorValidator->setLower(0);
manualScaleFactorValidator->setExclusive(true);
declareProperty(make_unique<PropertyWithValue<double>>(
"ManualScaleFactor", 1.0, manualScaleFactorValidator,
Direction::Input),
"Provided value for the scale factor.");
declareProperty(
make_unique<ArrayProperty<double>>("OutScaleFactors", Direction::Output),
"The actual used values for the scaling factors at each stitch step.");
auto scaleFactorFromPeriodValidator =
boost::make_shared<BoundedValidator<int>>();
scaleFactorFromPeriodValidator->setLower(1);
declareProperty(make_unique<PropertyWithValue<int>>(
"ScaleFactorFromPeriod", 1,
scaleFactorFromPeriodValidator, Direction::Input),
"Provided index of period to obtain scale factor from. "
"Periods are indexed from 1. Used only if stitching group "
"workspaces, UseManualScaleFactor is true and "
"ManualScaleFactor is set to default.");
}
/** Load and validate the algorithm's properties.
*/
std::map<std::string, std::string> Stitch1DMany::validateInputs() {
std::map<std::string, std::string> errors;
const std::vector<std::string> inputWorkspacesStr =
this->getProperty("InputWorkspaces");
// Add all input workspaces to the matrix
std::vector<Workspace_sptr> inputWorkspaces;
for (const auto &ws : inputWorkspacesStr) {
inputWorkspaces.push_back(
AnalysisDataService::Instance().retrieveWS<Workspace>(ws));
}
m_inputWSMatrix.push_back(inputWorkspaces);
// Add common errors
validateCommonInputs(errors);
errors.insert(errors.begin(), errors.end());
return errors;
}
/** Load and validate the algorithm's properties for workspace groups.
*/
void Stitch1DMany::validateGroupWorkspacesInputs() {
std::map<std::string, std::string> errors;
const std::vector<std::string> inputWorkspacesStr =
this->getProperty("InputWorkspaces");
// Add all group workspaces and their constituent workspaces to their
// respective containers
for (const auto &groupWSName : inputWorkspacesStr) {
auto groupWS =
AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(groupWSName);
std::vector<Workspace_sptr> inputWorkspaces;
for (size_t i = 0; i < groupWS->size(); i++) {
inputWorkspaces.push_back(groupWS->getItem(i));
}
m_inputWSMatrix.push_back(inputWorkspaces);
m_inputWSGroups.push_back(groupWS);
}
size_t numWSInGroup = m_inputWSMatrix[0].size();
// Check all workspace groups are the same size
for (auto &inputWsGroup : m_inputWSGroups) {
if (inputWsGroup->size() != numWSInGroup) {
errors["InputWorkspaces"] = "All workspace groups must be the same size.";
break;
}
}
int scaleFactorFromPeriod = this->getProperty("ScaleFactorFromPeriod");
m_scaleFactorFromPeriod = (size_t)scaleFactorFromPeriod;
m_scaleFactorFromPeriod--; // To account for period being indexed from 1
if (m_scaleFactorFromPeriod >= m_inputWSGroups.size())
errors["ScaleFactorFromPeriod"] = "Period index out of range";
// Log all errors and throw a runtime error if an error is found
validateCommonInputs(errors);
if (errors.size() > 0) {
auto &warnLog = getLogger().warning();
for (auto &error : errors) {
warnLog << "Invalid value for " << error.first << ": " << error.second
<< "\n";
}
throw std::runtime_error("Some invalid Properties found");
}
}
/** Load and validate properties common to both group and non-group workspaces.
*/
void Stitch1DMany::validateCommonInputs(
std::map<std::string, std::string> &errors) {
const std::vector<std::string> inputWorkspacesStr =
this->getProperty("InputWorkspaces");
if (inputWorkspacesStr.size() < 2)
errors["InputWorkspaces"] = "At least 2 input workspaces required.";
// Check that all the workspaces are of the same type
const std::string id = m_inputWSMatrix[0][0]->id();
for (auto &period : m_inputWSMatrix) {
for (auto &inputWS : period) {
if (inputWS->id() != id) {
errors["InputWorkspaces"] = "All workspaces must be the same type.";
break;
}
}
}
m_startOverlaps = this->getProperty("StartOverlaps");
m_endOverlaps = this->getProperty("EndOverlaps");
m_scaleRHSWorkspace = this->getProperty("ScaleRHSWorkspace");
m_params = this->getProperty("Params");
m_numWSPerGroup = m_inputWSMatrix[0].size();
m_numWSPerPeriod = m_inputWSMatrix.size();
size_t numStitchableWS =
(m_numWSPerPeriod > 1) ? m_numWSPerPeriod : m_numWSPerGroup;
if (!m_startOverlaps.empty() && m_startOverlaps.size() != numStitchableWS - 1)
errors["StartOverlaps"] = "If given, StartOverlaps must have one fewer "
"entries than the number of input workspaces.";
if (m_startOverlaps.size() != m_endOverlaps.size())
errors["EndOverlaps"] =
"EndOverlaps must have the same number of entries as StartOverlaps.";
m_useManualScaleFactor = this->getProperty("UseManualScaleFactor");
m_manualScaleFactor = this->getProperty("ManualScaleFactor");
}
/** Execute the algorithm.
*/
void Stitch1DMany::exec() {
MatrixWorkspace_sptr lhsWS =
boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[0][0]);
for (size_t i = 1; i < m_numWSPerGroup; i++) {
MatrixWorkspace_sptr rhsWS =
boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[0][i]);
double outScaleFactor;
doStitch1D(lhsWS, rhsWS, i, m_startOverlaps, m_endOverlaps, m_params,
m_scaleRHSWorkspace, m_useManualScaleFactor, m_manualScaleFactor,
lhsWS, outScaleFactor);
m_scaleFactors.push_back(outScaleFactor);
}
m_outputWorkspace = lhsWS;
// Save output
this->setProperty("OutputWorkspace", m_outputWorkspace);
this->setProperty("OutScaleFactors", m_scaleFactors);
}
/** Performs the Stitch1D algorithm at a specific workspace index.
* @param lhsWS :: The left-hand workspace to be stitched
* @param rhsWS :: The right-hand workspace to be stitched
* @param wsIndex :: The index of the rhs workspace being stitched
* @param startOverlaps :: Start overlaps for stitched workspaces
* @param endOverlaps :: End overlaps for stitched workspaces
* @param params :: Rebinning parameters
* @param scaleRhsWS :: Scaling either with respect to left or right workspaces
* @param useManualScaleFactor :: True to use a provided value for scale factor
* @param manualScaleFactor :: Provided value for scaling factor
* @param outWS :: Output stitched workspace
* @param outScaleFactor :: Actual value used for scale factor
*/
void Stitch1DMany::doStitch1D(
MatrixWorkspace_sptr lhsWS, MatrixWorkspace_sptr rhsWS,
const size_t wsIndex, const std::vector<double> &startOverlaps,
const std::vector<double> &endOverlaps, const std::vector<double> ¶ms,
const bool scaleRhsWS, const bool useManualScaleFactor,
const double manualScaleFactor, MatrixWorkspace_sptr &outWS,
double &outScaleFactor) {
IAlgorithm_sptr alg = createChildAlgorithm("Stitch1D");
alg->initialize();
alg->setProperty("LHSWorkspace", lhsWS);
alg->setProperty("RHSWorkspace", rhsWS);
if (startOverlaps.size() > wsIndex - 1) {
alg->setProperty("StartOverlap", startOverlaps[wsIndex - 1]);
alg->setProperty("EndOverlap", endOverlaps[wsIndex - 1]);
}
alg->setProperty("Params", params);
alg->setProperty("ScaleRHSWorkspace", scaleRhsWS);
alg->setProperty("UseManualScaleFactor", useManualScaleFactor);
if (useManualScaleFactor)
alg->setProperty("ManualScaleFactor", manualScaleFactor);
alg->execute();
outWS = alg->getProperty("OutputWorkspace");
outScaleFactor = alg->getProperty("OutScaleFactor");
if (!isChild()) {
// Copy each input workspace's history into our output workspace's history
for (auto &inputWS : m_inputWSMatrix[0]) {
outWS->history().addHistory(inputWS->getHistory());
}
}
}
/** Performs the Stitch1DMany algorithm at a specific period
* @param inputWSGroups :: The set of workspace groups to be stitched
* @param period :: The period index we are stitching at
* @param storeInADS :: True to store in the AnalysisDataService
* @param startOverlaps :: Start overlaps for stitched workspaces
* @param endOverlaps :: End overlaps for stitched workspaces
* @param params :: Rebinning parameters
* @param scaleRhsWS :: Scaling either with respect to left or right workspaces
* @param useManualScaleFactor :: True to use a provided value for scale factor
* @param manualScaleFactor :: Provided value for scaling factor
* @param outName :: Output stitched workspace name
* @param outScaleFactors :: Actual values used for scale factors
*/
void Stitch1DMany::doStitch1DMany(
std::vector<WorkspaceGroup_sptr> inputWSGroups, const size_t period,
const bool storeInADS, const std::vector<double> &startOverlaps,
const std::vector<double> &endOverlaps, const std::vector<double> ¶ms,
const bool scaleRhsWS, const bool useManualScaleFactor,
const double manualScaleFactor, std::string &outName,
std::vector<double> &outScaleFactors) {
// List of workspaces to stitch
std::vector<std::string> toProcess;
for (auto &groupWs : inputWSGroups) {
const std::string &wsName = groupWs->getItem(period)->getName();
toProcess.push_back(wsName);
outName += "_" + wsName;
}
IAlgorithm_sptr alg = createChildAlgorithm("Stitch1DMany");
alg->initialize();
alg->setChild(false);
alg->setAlwaysStoreInADS(storeInADS);
alg->setProperty("InputWorkspaces", toProcess);
alg->setProperty("OutputWorkspace", outName);
alg->setProperty("StartOverlaps", startOverlaps);
alg->setProperty("EndOverlaps", endOverlaps);
alg->setProperty("Params", params);
alg->setProperty("ScaleRHSWorkspace", scaleRhsWS);
alg->setProperty("UseManualScaleFactor", useManualScaleFactor);
if (useManualScaleFactor)
alg->setProperty("ManualScaleFactor", manualScaleFactor);
alg->execute();
outScaleFactors = alg->getProperty("OutScaleFactors");
}
bool Stitch1DMany::checkGroups() {
std::vector<std::string> wsNames = getProperty("InputWorkspaces");
try {
if (AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(wsNames[0]))
return true;
} catch (...) {
}
return false;
}
bool Stitch1DMany::processGroups() {
validateGroupWorkspacesInputs();
std::vector<std::string> toGroup; // List of workspaces to be grouped
std::string groupName = this->getProperty("OutputWorkspace");
std::string outName;
// Determine whether or not we are scaling workspaces using scale factors from
// a specific period
Property *manualSF = this->getProperty("ManualScaleFactor");
bool usingScaleFromPeriod = m_useManualScaleFactor && manualSF->isDefault();
if (!usingScaleFromPeriod) {
for (size_t i = 0; i < m_numWSPerGroup; ++i) {
outName = groupName;
std::vector<double> scaleFactors;
doStitch1DMany(m_inputWSGroups, i, true, m_startOverlaps, m_endOverlaps,
m_params, m_scaleRHSWorkspace, m_useManualScaleFactor,
m_manualScaleFactor, outName, scaleFactors);
// Add the resulting workspace to the list to be grouped together
toGroup.push_back(outName);
// Add the scalefactors to the list so far
m_scaleFactors.insert(m_scaleFactors.end(), scaleFactors.begin(),
scaleFactors.end());
}
} else {
// Obtain scale factors for the specified period
outName = groupName;
std::vector<double> periodScaleFactors;
doStitch1DMany(m_inputWSGroups, m_scaleFactorFromPeriod, false,
m_startOverlaps, m_endOverlaps, m_params,
m_scaleRHSWorkspace, false, m_manualScaleFactor, outName,
periodScaleFactors);
// Iterate over each period
for (size_t i = 0; i < m_numWSPerGroup; i++) {
auto lhsWS =
boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[0][i]);
outName = groupName + "_" + lhsWS->getName();
// Perform stiching on the workspace for each group of that period
for (size_t j = 1; j < m_numWSPerPeriod; j++) {
auto rhsWS =
boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[j][i]);
outName += "_" + rhsWS->getName(); // add name
double outScaleFactor;
doStitch1D(lhsWS, rhsWS, j, m_startOverlaps, m_endOverlaps, m_params,
m_scaleRHSWorkspace, m_useManualScaleFactor,
periodScaleFactors[j - 1], lhsWS, outScaleFactor);
m_scaleFactors.push_back(outScaleFactor);
}
// Add name of stitched workspaces to group list and ADS
toGroup.push_back(outName);
AnalysisDataService::Instance().addOrReplace(outName, lhsWS);
}
}
IAlgorithm_sptr groupAlg = createChildAlgorithm("GroupWorkspaces");
groupAlg->initialize();
groupAlg->setAlwaysStoreInADS(true);
groupAlg->setProperty("InputWorkspaces", toGroup);
groupAlg->setProperty("OutputWorkspace", groupName);
groupAlg->execute();
m_outputWorkspace =
AnalysisDataService::Instance().retrieveWS<Workspace>(groupName);
this->setProperty("OutputWorkspace", m_outputWorkspace);
this->setProperty("OutScaleFactors", m_scaleFactors);
return true;
}
} // namespace Algorithms
} // namespace Mantid