-
Notifications
You must be signed in to change notification settings - Fork 122
/
Stitch1DMany.cpp
396 lines (348 loc) · 16.4 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
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAlgorithms/Stitch1DMany.h"
#include "MantidAPI/ADSValidator.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/WorkspaceHistory.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidAlgorithms/RunCombinationHelpers/RunCombinationHelper.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/RebinParamsValidator.h"
#include "MantidKernel/VisibleWhenProperty.h"
#include <memory>
using namespace Mantid::Kernel;
using namespace Mantid::API;
namespace Mantid {
namespace Algorithms {
DECLARE_ALGORITHM(Stitch1DMany)
/// Initialize the algorithm's properties.
void Stitch1DMany::init() {
declareProperty(std::make_unique<ArrayProperty<std::string>>(
"InputWorkspaces", std::make_shared<ADSValidator>()),
"List or group of MatrixWorkspaces");
declareProperty(std::make_unique<WorkspaceProperty<Workspace>>(
"OutputWorkspace", "", Direction::Output),
"Stitched workspace.");
declareProperty(std::make_unique<ArrayProperty<double>>(
"Params", std::make_shared<RebinParamsValidator>(true),
Direction::Input),
"Rebinning Parameters, see Rebin algorithm for format.");
declareProperty(std::make_unique<ArrayProperty<double>>("StartOverlaps",
Direction::Input),
"Start overlaps for stitched workspaces "
"(number of input workspaces minus one).");
declareProperty(
std::make_unique<ArrayProperty<double>>("EndOverlaps", Direction::Input),
"End overlaps for stitched workspaces "
"(number of input workspaces minus one).");
declareProperty(std::make_unique<PropertyWithValue<bool>>(
"ScaleRHSWorkspace", true, Direction::Input),
"Scaling either with respect to first (first hand side, LHS) "
"or second (right hand side, RHS) workspace.");
declareProperty(std::make_unique<PropertyWithValue<bool>>(
"UseManualScaleFactors", false, Direction::Input),
"True to use provided values for the scale factor.");
declareProperty(std::make_unique<ArrayProperty<double>>("ManualScaleFactors",
Direction::Input),
"Either a single scale factor which will be applied to all "
"input workspaces or individual scale factors "
"(number of input workspaces minus one)");
setPropertySettings("ManualScaleFactors",
std::make_unique<VisibleWhenProperty>(
"UseManualScaleFactors", IS_EQUAL_TO, "1"));
declareProperty(
std::make_unique<ArrayProperty<double>>("OutScaleFactors",
Direction::Output),
"The actual used values for the scaling factors at each stitch step.");
auto scaleFactorFromPeriodValidator =
std::make_shared<BoundedValidator<int>>();
scaleFactorFromPeriodValidator->setLower(1);
declareProperty(std::make_unique<PropertyWithValue<int>>(
"ScaleFactorFromPeriod", 1,
scaleFactorFromPeriodValidator, Direction::Input),
"Provided index of period to obtain scale factor from; "
"periods are indexed from 1 and used only if stitching group "
"workspaces, UseManualScaleFactors is true and "
"ManualScaleFactors is set to default.");
auto useManualScaleFactorsTrue =
VisibleWhenProperty("UseManualScaleFactors", IS_EQUAL_TO, "1");
auto manualScaleFactorsDefault =
VisibleWhenProperty("ManualScaleFactors", IS_DEFAULT);
auto scaleFactorFromPeriodVisible = std::make_unique<VisibleWhenProperty>(
useManualScaleFactorsTrue, manualScaleFactorsDefault, AND);
setPropertySettings("ScaleFactorFromPeriod",
std::move(scaleFactorFromPeriodVisible));
}
/// Load and validate the algorithm's properties.
std::map<std::string, std::string> Stitch1DMany::validateInputs() {
std::map<std::string, std::string> issues;
const std::vector<std::string> inputWorkspacesStr =
this->getProperty("InputWorkspaces");
if (inputWorkspacesStr.size() < 2)
issues["InputWorkspaces"] = "Nothing to stitch";
else {
try { // input workspaces must be group or MatrixWorkspaces
auto workspaces = RunCombinationHelper::unWrapGroups(inputWorkspacesStr);
/*
* Column: one column of MatrixWorkspaces or several columns of
* MatrixWorkspaces from a group
* Row: each period only for groups
*/
m_inputWSMatrix.reserve(inputWorkspacesStr.size());
std::vector<MatrixWorkspace_sptr> column;
for (const auto &ws : inputWorkspacesStr) {
auto groupWS =
AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(ws);
if (groupWS) {
for (size_t i = 0; i < groupWS->size(); i++) {
auto inputMatrix =
std::dynamic_pointer_cast<MatrixWorkspace>(groupWS->getItem(i));
if (inputMatrix) {
column.emplace_back(inputMatrix);
} else
issues["InputWorkspaces"] =
"Input workspace " + ws + " must be a MatrixWorkspace";
}
m_inputWSMatrix.emplace_back(column);
column.clear();
} else {
auto inputMatrix =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(ws);
column.emplace_back(inputMatrix);
}
}
if (m_inputWSMatrix.empty()) { // no group workspaces
// A column of matrix workspaces will be stitched
RunCombinationHelper combHelper;
combHelper.setReferenceProperties(column.front());
for (const auto &ws : column) {
// check if all the others are compatible with the reference
std::string compatible = combHelper.checkCompatibility(ws, true);
if (!compatible.empty()) {
if (!(compatible ==
"spectra must have either Dx values or not; ") ||
(ws->isHistogramData())) // Issue only for point data
issues["RHSWorkspace"] = "Workspace " + ws->getName() +
" is not compatible: " + compatible +
"\n";
}
}
m_inputWSMatrix.emplace_back(column);
} else if (m_inputWSMatrix.size() !=
inputWorkspacesStr.size()) { // not only group workspaces
issues["InputWorkspaces"] = "All input workspaces must be groups";
} else { // only group workspaces
// Each row of matrix workspaces will be stitched
for (size_t spec = 1; spec < m_inputWSMatrix.front().size(); ++spec) {
for (const auto &ws : m_inputWSMatrix) {
if (ws.size() != m_inputWSMatrix.front().size()) {
issues["InputWorkspaces"] = "Size mismatch of group workspaces";
} else {
RunCombinationHelper combHelper;
combHelper.setReferenceProperties(ws[0]);
// check if all the others are compatible with the reference
std::string compatible =
combHelper.checkCompatibility(ws[spec], true);
if (!compatible.empty())
issues["InputWorkspaces"] =
"Workspace " + ws[spec]->getName() +
" is not compatible: " + compatible + "\n";
}
}
}
int scaleFactorFromPeriod = this->getProperty("ScaleFactorFromPeriod");
// Period -1 corresponds to workspace index
m_scaleFactorFromPeriod = static_cast<size_t>(--scaleFactorFromPeriod);
if (m_scaleFactorFromPeriod >= m_inputWSMatrix.front().size()) {
std::stringstream expectedRange;
expectedRange << m_inputWSMatrix.front().size() + 1;
issues["ScaleFactorFromPeriod"] =
"Period index out of range, must be smaller than " +
expectedRange.str();
}
}
m_startOverlaps = this->getProperty("StartOverlaps");
m_endOverlaps = this->getProperty("EndOverlaps");
m_scaleRHSWorkspace = this->getProperty("ScaleRHSWorkspace");
m_params = this->getProperty("Params");
// Either stitch MatrixWorkspaces or workspaces of the group
size_t numStitchableWS = (workspaces.size() == inputWorkspacesStr.size())
? workspaces.size()
: inputWorkspacesStr.size();
std::stringstream expectedVal;
expectedVal << numStitchableWS - 1;
if (!m_startOverlaps.empty() &&
m_startOverlaps.size() != numStitchableWS - 1)
issues["StartOverlaps"] = "Expected " + expectedVal.str() + " value(s)";
if (m_startOverlaps.size() != m_endOverlaps.size())
issues["EndOverlaps"] = "EndOverlaps must have the same number of "
"entries as StartOverlaps.";
m_useManualScaleFactors = this->getProperty("UseManualScaleFactors");
m_manualScaleFactors = this->getProperty("ManualScaleFactors");
if (!m_manualScaleFactors.empty()) {
if (m_manualScaleFactors.size() == 1) {
// Single value: fill with list of the same scale factor value
m_manualScaleFactors = std::vector<double>(
numStitchableWS - 1, m_manualScaleFactors.front());
} else if (m_manualScaleFactors.size() != numStitchableWS - 1) {
if ((numStitchableWS - 1) == 1)
issues["ManualScaleFactors"] = "Must be a single value";
else
issues["ManualScaleFactors"] =
"Must be a single value for all input workspaces or " +
expectedVal.str() + " values";
}
} else { // if not a group, no period scaling possible
if (m_useManualScaleFactors && (m_inputWSMatrix.size() == 1))
issues["ManualScaleFactors"] = "Must contain scale factors";
}
} catch (const std::exception &e) {
issues["InputWorkspaces"] = std::string(e.what());
}
}
return issues;
}
/// Execute the algorithm.
void Stitch1DMany::exec() {
if (m_inputWSMatrix.size() > 1) { // groups
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
const bool usingScaleFromPeriod =
m_useManualScaleFactors && isDefault("ManualScaleFactors");
if (!usingScaleFromPeriod) {
for (size_t i = 0; i < m_inputWSMatrix.front().size(); ++i) {
outName = groupName;
std::vector<double> scaleFactors;
doStitch1DMany(i, m_useManualScaleFactors, outName, scaleFactors);
// Add the resulting workspace to the list to be grouped together
toGroup.emplace_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
std::string tempOutName;
std::vector<double> periodScaleFactors;
constexpr bool storeInADS = false;
doStitch1DMany(m_scaleFactorFromPeriod, false, tempOutName,
periodScaleFactors, storeInADS);
// Iterate over each period
for (size_t i = 0; i < m_inputWSMatrix.front().size(); ++i) {
std::vector<MatrixWorkspace_sptr> inMatrix;
inMatrix.reserve(m_inputWSMatrix.size());
std::transform(m_inputWSMatrix.begin(), m_inputWSMatrix.end(),
std::back_inserter(inMatrix),
[i](const auto &ws) { return ws[i]; });
outName = groupName;
Workspace_sptr outStitchedWS;
doStitch1D(inMatrix, periodScaleFactors, outStitchedWS, outName);
// Add name of stitched workspaces to group list and ADS
toGroup.emplace_back(outName);
AnalysisDataService::Instance().addOrReplace(outName, outStitchedWS);
}
}
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);
} else {
std::string tempOutName;
doStitch1D(m_inputWSMatrix.front(), m_manualScaleFactors, m_outputWorkspace,
tempOutName);
}
// Save output
this->setProperty("OutputWorkspace", m_outputWorkspace);
this->setProperty("OutScaleFactors", m_scaleFactors);
}
/** Performs the Stitch1D algorithm at a specific workspace index.
* @param toStitch :: Vector of workspaces to be stitched
* @param manualScaleFactors :: Provided values for scaling factors
* @param outWS :: Output stitched workspace
* @param outName :: Output stitched workspace name
*/
void Stitch1DMany::doStitch1D(std::vector<MatrixWorkspace_sptr> &toStitch,
const std::vector<double> &manualScaleFactors,
Workspace_sptr &outWS, std::string &outName) {
auto lhsWS = toStitch.front();
outName += "_" + lhsWS->getName();
for (size_t i = 1; i < toStitch.size(); i++) {
auto rhsWS = toStitch[i];
outName += "_" + rhsWS->getName();
IAlgorithm_sptr alg = createChildAlgorithm("Stitch1D");
alg->initialize();
alg->setProperty("LHSWorkspace", lhsWS);
alg->setProperty("RHSWorkspace", rhsWS);
if (m_startOverlaps.size() > i - 1) {
alg->setProperty("StartOverlap", m_startOverlaps[i - 1]);
alg->setProperty("EndOverlap", m_endOverlaps[i - 1]);
}
alg->setProperty("Params", m_params);
alg->setProperty("ScaleRHSWorkspace", m_scaleRHSWorkspace);
alg->setProperty("UseManualScaleFactor", m_useManualScaleFactors);
if (m_useManualScaleFactors)
alg->setProperty("ManualScaleFactor", manualScaleFactors[i - 1]);
alg->execute();
lhsWS = alg->getProperty("OutputWorkspace");
double outScaleFactor = alg->getProperty("OutScaleFactor");
m_scaleFactors.emplace_back(outScaleFactor);
if (!isChild()) {
// Copy each input workspace's history into our output workspace's
// history
for (const auto &inputWS : toStitch) {
lhsWS->history().addHistory(inputWS->getHistory());
}
}
}
outWS = lhsWS;
}
/** Performs the Stitch1DMany algorithm at a specific period
* @param period :: The period index we are stitching at
* @param useManualScaleFactors :: True to use provided values for scale
* factors
* @param outName :: Output stitched workspace name
* @param outScaleFactors :: Actual values used for scale factors
* @param storeInADS :: Whether to store in ADS or not
*/
void Stitch1DMany::doStitch1DMany(const size_t period,
const bool useManualScaleFactors,
std::string &outName,
std::vector<double> &outScaleFactors,
const bool storeInADS) {
// List of workspaces to stitch
std::vector<std::string> toProcess;
for (const auto &ws : m_inputWSMatrix) {
const std::string &wsName = ws[period]->getName();
toProcess.emplace_back(wsName);
outName += "_" + wsName;
}
IAlgorithm_sptr alg = createChildAlgorithm("Stitch1DMany");
alg->initialize();
alg->setAlwaysStoreInADS(storeInADS);
alg->setProperty("InputWorkspaces", toProcess);
if (!outName.empty())
alg->setProperty("OutputWorkspace", outName);
alg->setProperty("StartOverlaps", m_startOverlaps);
alg->setProperty("EndOverlaps", m_endOverlaps);
alg->setProperty("Params", m_params);
alg->setProperty("ScaleRHSWorkspace", m_scaleRHSWorkspace);
alg->setProperty("UseManualScaleFactors", useManualScaleFactors);
if (useManualScaleFactors)
alg->setProperty("ManualScaleFactors", m_manualScaleFactors);
alg->execute();
outScaleFactors = alg->getProperty("OutScaleFactors");
}
} // namespace Algorithms
} // namespace Mantid