Mantid
Loading...
Searching...
No Matches
Stitch1DMany.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 +
19#include <memory>
20
21using namespace Mantid::Kernel;
22using namespace Mantid::API;
23
24namespace Mantid::Algorithms {
25DECLARE_ALGORITHM(Stitch1DMany)
26
27
28void Stitch1DMany::init() {
29
30 declareProperty(std::make_unique<ArrayProperty<std::string>>("InputWorkspaces", std::make_shared<ADSValidator>()),
31 "List or group of MatrixWorkspaces");
32
33 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
34 "Stitched workspace.");
35
36 declareProperty(
37 std::make_unique<ArrayProperty<double>>("Params", std::make_shared<RebinParamsValidator>(true), Direction::Input),
38 "Rebinning Parameters, see Rebin algorithm for format.");
39
40 declareProperty(std::make_unique<ArrayProperty<double>>("StartOverlaps", Direction::Input),
41 "Start overlaps for stitched workspaces "
42 "(number of input workspaces minus one).");
43
44 declareProperty(std::make_unique<ArrayProperty<double>>("EndOverlaps", Direction::Input),
45 "End overlaps for stitched workspaces "
46 "(number of input workspaces minus one).");
47
48 // This property is allowed to be Unset, as it no longer has an effect
49 declareProperty(
50 std::make_unique<PropertyWithValue<OptionalBool>>("ScaleRHSWorkspace", OptionalBool::Unset, Direction::Input),
51 "Scaling either with respect to first (first hand side, LHS) "
52 "or second (right hand side, RHS) workspace. "
53 "This property no longer has an effect, please use the IndexOfReference property instead.");
54 // Hide this property from the GUI as it now has no effect and will eventually be removed
55 setPropertySettings("ScaleRHSWorkspace", std::make_unique<InvisibleProperty>());
56
57 declareProperty(std::make_unique<PropertyWithValue<bool>>("UseManualScaleFactors", false, Direction::Input),
58 "True to use provided values for the scale factor.");
59
60 declareProperty(std::make_unique<ArrayProperty<double>>("ManualScaleFactors", Direction::Input),
61 "Either a single scale factor which will be applied to all "
62 "input workspaces or individual scale factors "
63 "(number of input workspaces minus one)");
64 setPropertySettings("ManualScaleFactors",
65 std::make_unique<VisibleWhenProperty>("UseManualScaleFactors", IS_EQUAL_TO, "1"));
66
67 declareProperty(std::make_unique<ArrayProperty<double>>("OutScaleFactors", Direction::Output),
68 "The actual used values for the scaling factors at each stitch step.");
69
70 auto scaleFactorFromPeriodValidator = std::make_shared<BoundedValidator<int>>();
71 scaleFactorFromPeriodValidator->setLower(1);
72 declareProperty(std::make_unique<PropertyWithValue<int>>("ScaleFactorFromPeriod", 1, scaleFactorFromPeriodValidator,
74 "Provided index of period to obtain scale factor from; "
75 "periods are indexed from 1 and used only if stitching group "
76 "workspaces, UseManualScaleFactors is true and "
77 "ManualScaleFactors is set to default.");
78
79 auto useManualScaleFactorsTrue = VisibleWhenProperty("UseManualScaleFactors", IS_EQUAL_TO, "1");
80 auto manualScaleFactorsDefault = VisibleWhenProperty("ManualScaleFactors", IS_DEFAULT);
81 auto scaleFactorFromPeriodVisible =
82 std::make_unique<VisibleWhenProperty>(useManualScaleFactorsTrue, manualScaleFactorsDefault, AND);
83
84 setPropertySettings("ScaleFactorFromPeriod", std::move(scaleFactorFromPeriodVisible));
85
86 auto indexValidator = std::make_shared<BoundedValidator<int>>();
87 indexValidator->setLower(-1);
88 declareProperty("IndexOfReference", 0, indexValidator,
89 "Index of the workspace to be used as reference for scaling, or -1 to choose the last workspace as "
90 "the reference.");
91}
92
94std::map<std::string, std::string> Stitch1DMany::validateInputs() {
95 std::map<std::string, std::string> issues;
96 const std::vector<std::string> inputWorkspacesStr = this->getProperty("InputWorkspaces");
97 if (inputWorkspacesStr.size() < 2)
98 issues["InputWorkspaces"] = "Nothing to stitch";
99 else {
100 try { // input workspaces must be group or MatrixWorkspaces
101 auto workspaces = RunCombinationHelper::unWrapGroups(inputWorkspacesStr);
102 /*
103 * Column: one column of MatrixWorkspaces or several columns of
104 * MatrixWorkspaces from a group
105 * Row: each period only for groups
106 */
107 m_inputWSMatrix.reserve(inputWorkspacesStr.size());
111 m_inputWSMatrix.clear();
112 std::vector<MatrixWorkspace_sptr> column;
113 for (const auto &ws : inputWorkspacesStr) {
114 auto groupWS = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(ws);
115 if (groupWS) {
116 for (size_t i = 0; i < groupWS->size(); i++) {
117 auto inputMatrix = std::dynamic_pointer_cast<MatrixWorkspace>(groupWS->getItem(i));
118 if (inputMatrix) {
119 column.emplace_back(inputMatrix);
120 } else
121 issues["InputWorkspaces"] = "Input workspace " + ws + " must be a MatrixWorkspace";
122 }
123 m_inputWSMatrix.emplace_back(column);
124 column.clear();
125 } else {
126 auto inputMatrix = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(ws);
127 column.emplace_back(inputMatrix);
128 }
129 }
130 if (!isDefault("IndexOfReference")) {
131 m_indexOfReference = static_cast<int>(this->getProperty("IndexOfReference"));
132 if (m_indexOfReference > -1 && static_cast<size_t>(m_indexOfReference) >= column.size() &&
133 static_cast<size_t>(m_indexOfReference) >= m_inputWSMatrix.size()) {
134 issues["IndexOfReference"] = "The index of reference workspace is larger than the number of "
135 "provided workspaces.";
136 }
137 }
138
139 if (m_inputWSMatrix.empty()) { // no group workspaces
140 // A column of matrix workspaces will be stitched
141 RunCombinationHelper combHelper;
142 combHelper.setReferenceProperties(column.front());
143 for (const auto &ws : column) {
144 // check if all the others are compatible with the reference
145 std::string compatible = combHelper.checkCompatibility(ws, true);
146 if (!compatible.empty()) {
147 if (!(compatible == "spectra must have either Dx values or not; ") ||
148 (ws->isHistogramData())) // Issue only for point data
149 issues["RHSWorkspace"] = "Workspace " + ws->getName() + " is not compatible: " + compatible + "\n";
150 }
151 }
152 m_inputWSMatrix.emplace_back(column);
153 } else if (m_inputWSMatrix.size() != inputWorkspacesStr.size()) { // not only group workspaces
154 issues["InputWorkspaces"] = "All input workspaces must be groups";
155 } else { // only group workspaces
156 // Each row of matrix workspaces will be stitched
157 for (size_t spec = 1; spec < m_inputWSMatrix.front().size(); ++spec) {
158 for (const auto &ws : m_inputWSMatrix) {
159 if (ws.size() != m_inputWSMatrix.front().size()) {
160 issues["InputWorkspaces"] = "Size mismatch of group workspaces";
161 } else {
162 RunCombinationHelper combHelper;
163 combHelper.setReferenceProperties(ws[0]);
164 // check if all the others are compatible with the reference
165 std::string compatible = combHelper.checkCompatibility(ws[spec], true);
166 if (!compatible.empty())
167 issues["InputWorkspaces"] =
168 "Workspace " + ws[spec]->getName() + " is not compatible: " + compatible + "\n";
169 }
170 }
171 }
172 int scaleFactorFromPeriod = this->getProperty("ScaleFactorFromPeriod");
173 // Period -1 corresponds to workspace index
174 m_scaleFactorFromPeriod = static_cast<size_t>(--scaleFactorFromPeriod);
175 if (m_scaleFactorFromPeriod >= m_inputWSMatrix.front().size()) {
176 std::stringstream expectedRange;
177 expectedRange << m_inputWSMatrix.front().size() + 1;
178 issues["ScaleFactorFromPeriod"] = "Period index out of range, must be smaller than " + expectedRange.str();
179 }
180 }
181
182 m_startOverlaps = this->getProperty("StartOverlaps");
183 m_endOverlaps = this->getProperty("EndOverlaps");
184 m_params = this->getProperty("Params");
185
186 // Either stitch MatrixWorkspaces or workspaces of the group
187 size_t numStitchableWS =
188 (workspaces.size() == inputWorkspacesStr.size()) ? workspaces.size() : inputWorkspacesStr.size();
189 std::stringstream expectedVal;
190 expectedVal << numStitchableWS - 1;
191 if (!m_startOverlaps.empty() && m_startOverlaps.size() != numStitchableWS - 1)
192 issues["StartOverlaps"] = "Expected " + expectedVal.str() + " value(s)";
193
194 if (m_startOverlaps.size() != m_endOverlaps.size())
195 issues["EndOverlaps"] = "EndOverlaps must have the same number of "
196 "entries as StartOverlaps.";
197
198 m_useManualScaleFactors = this->getProperty("UseManualScaleFactors");
199 m_manualScaleFactors = this->getProperty("ManualScaleFactors");
200
201 if (!m_manualScaleFactors.empty()) {
202 if (m_manualScaleFactors.size() == 1) {
203 // Single value: fill with list of the same scale factor value
204 m_manualScaleFactors = std::vector<double>(numStitchableWS - 1, m_manualScaleFactors.front());
205 } else if (m_manualScaleFactors.size() != numStitchableWS - 1) {
206 if ((numStitchableWS - 1) == 1)
207 issues["ManualScaleFactors"] = "Must be a single value";
208 else
209 issues["ManualScaleFactors"] =
210 "Must be a single value for all input workspaces or " + expectedVal.str() + " values";
211 }
212 } else { // if not a group, no period scaling possible
213 if (m_useManualScaleFactors && (m_inputWSMatrix.size() == 1))
214 issues["ManualScaleFactors"] = "Must contain scale factors";
215 }
216 } catch (const std::exception &e) {
217 issues["InputWorkspaces"] = std::string(e.what());
218 }
219 }
220 return issues;
221}
222
225 if (static_cast<OptionalBool>(this->getProperty("ScaleRHSWorkspace")) != OptionalBool::Unset) {
226 g_log.warning("The ScaleRHSWorkspace property no longer has any effect. Please see documentation on the "
227 "IndexOfReference parameter and use that instead.");
228 }
229
230 if (m_inputWSMatrix.size() > 1) { // groups
231 std::vector<std::string> toGroup; // List of workspaces to be grouped
232 std::string groupName = this->getProperty("OutputWorkspace");
233 std::string outName;
234
235 // Determine whether or not we are scaling workspaces using scale
236 // factors from a specific period
237 const bool usingScaleFromPeriod = m_useManualScaleFactors && isDefault("ManualScaleFactors");
238 if (!usingScaleFromPeriod) {
239 for (size_t i = 0; i < m_inputWSMatrix.front().size(); ++i) {
240
241 outName = groupName;
242 std::vector<double> scaleFactors;
244 // Add the resulting workspace to the list to be grouped together
245 toGroup.emplace_back(outName);
246
247 // Add the scalefactors to the list so far
248 m_scaleFactors.insert(m_scaleFactors.end(), scaleFactors.begin(), scaleFactors.end());
249 }
250 } else {
251 // Obtain scale factors for the specified period
252 std::string tempOutName;
253 std::vector<double> periodScaleFactors;
254 constexpr bool storeInADS = false;
255
256 doStitch1DMany(m_scaleFactorFromPeriod, false, tempOutName, periodScaleFactors, m_indexOfReference, storeInADS);
257
258 // Iterate over each period
259 for (size_t i = 0; i < m_inputWSMatrix.front().size(); ++i) {
260 std::vector<MatrixWorkspace_sptr> inMatrix;
261 inMatrix.reserve(m_inputWSMatrix.size());
262
263 std::transform(m_inputWSMatrix.begin(), m_inputWSMatrix.end(), std::back_inserter(inMatrix),
264 [i](const auto &ws) { return ws[i]; });
265
266 Workspace_sptr outStitchedWS;
267 doStitch1D(inMatrix, periodScaleFactors, outStitchedWS);
268 // Add name of stitched workspaces to group list and ADS
269 outName = createChildWorkspaceName(groupName, i);
270 toGroup.emplace_back(outName);
271 AnalysisDataService::Instance().addOrReplace(outName, outStitchedWS);
272 }
273 }
274
275 auto groupAlg = createChildAlgorithm("GroupWorkspaces");
276 groupAlg->initialize();
277 groupAlg->setAlwaysStoreInADS(true);
278 groupAlg->setProperty("InputWorkspaces", toGroup);
279 groupAlg->setProperty("OutputWorkspace", groupName);
280 groupAlg->execute();
281
282 m_outputWorkspace = AnalysisDataService::Instance().retrieveWS<Workspace>(groupName);
283 } else {
285 }
286 // Save output
287 this->setProperty("OutputWorkspace", m_outputWorkspace);
288 this->setProperty("OutScaleFactors", m_scaleFactors);
289}
290
296void Stitch1DMany::doStitch1D(std::vector<MatrixWorkspace_sptr> &toStitch,
297 const std::vector<double> &manualScaleFactors, Workspace_sptr &outWS) {
298
299 auto &lhsWS = toStitch.front();
300 // Support Python list syntax for selecting the last element in the list
301 auto indexOfReference = m_indexOfReference == -1 ? toStitch.size() - 1 : m_indexOfReference;
302
303 for (size_t i = 1; i < toStitch.size(); i++) {
304 auto rhsWS = toStitch[i];
305 // Scale the LHS ws until we have scaled to the reference ws. After that we scale the RHS ws to keep the scaling.
306 auto scaleRHSWorkspace = i > indexOfReference;
307
308 auto alg = createChildAlgorithm("Stitch1D");
309 alg->initialize();
310 alg->setProperty("LHSWorkspace", lhsWS);
311 alg->setProperty("RHSWorkspace", rhsWS);
312 if (m_startOverlaps.size() > i - 1) {
313 alg->setProperty("StartOverlap", m_startOverlaps[i - 1]);
314 alg->setProperty("EndOverlap", m_endOverlaps[i - 1]);
315 }
316 alg->setProperty("Params", m_params);
317 alg->setProperty("ScaleRHSWorkspace", scaleRHSWorkspace);
318 alg->setProperty("UseManualScaleFactor", m_useManualScaleFactors);
320 alg->setProperty("ManualScaleFactor", manualScaleFactors[i - 1]);
321 alg->execute();
322
323 lhsWS = alg->getProperty("OutputWorkspace");
324 double outScaleFactor = alg->getProperty("OutScaleFactor");
325 m_scaleFactors.emplace_back(outScaleFactor);
326
327 if (!isChild()) {
328 // Copy each input workspace's history into our output workspace's
329 // history
330 for (const auto &inputWS : toStitch) {
331 lhsWS->history().addHistory(inputWS->getHistory());
332 }
333 }
334 }
335
336 outWS = lhsWS;
337}
338
348void Stitch1DMany::doStitch1DMany(const size_t period, const bool useManualScaleFactors, std::string &outName,
349 std::vector<double> &outScaleFactors, const int indexOfReference,
350 const bool storeInADS) {
351
352 // List of workspaces to stitch
353 std::vector<std::string> toProcess;
354
355 for (const auto &ws : m_inputWSMatrix) {
356 const std::string &wsName = ws[period]->getName();
357 toProcess.emplace_back(wsName);
358 }
359
360 outName = createChildWorkspaceName(outName, period);
361
362 auto alg = createChildAlgorithm("Stitch1DMany");
363 alg->initialize();
364 alg->setAlwaysStoreInADS(storeInADS);
365 alg->setProperty("InputWorkspaces", toProcess);
366 if (!outName.empty())
367 alg->setProperty("OutputWorkspace", outName);
368 alg->setProperty("StartOverlaps", m_startOverlaps);
369 alg->setProperty("EndOverlaps", m_endOverlaps);
370 alg->setProperty("Params", m_params);
371 alg->setProperty("UseManualScaleFactors", useManualScaleFactors);
372 if (useManualScaleFactors)
373 alg->setProperty("ManualScaleFactors", m_manualScaleFactors);
374 alg->setProperty("IndexOfReference", indexOfReference);
375 alg->execute();
376
377 outScaleFactors = alg->getProperty("OutScaleFactors");
378}
379
384std::string Stitch1DMany::createChildWorkspaceName(const std::string &groupName, const size_t periodIndex) {
385 return groupName + "_" + std::to_string(periodIndex + 1);
386}
387
388} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::string getName(const IMDDimension &self)
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 isChild() const override
To query whether algorithm is a child.
Kernel::Logger & g_log
Definition Algorithm.h:422
bool isDefault(const std::string &name) const
Base MatrixWorkspace Abstract Class.
Class to hold a set of workspaces.
A property class for workspaces.
Base Workspace Abstract Class.
Definition Workspace.h:29
static std::vector< std::string > unWrapGroups(const std::vector< std::string > &)
Flattens the list of group workspaces (if any) into list of workspaces.
void setReferenceProperties(const API::MatrixWorkspace_sptr &)
Sets the properties of the reference (usually first) workspace, to later check the compatibility of t...
std::string checkCompatibility(const API::MatrixWorkspace_sptr &, bool checkNumberHistograms=false)
Compares the properties of the input workspace with the reference.
Stitch1DMany : Stitches multiple Matrix Workspaces together into a single output.
void exec() override
Overwrites Algorithm method.
std::vector< double > m_scaleFactors
std::vector< std::vector< API::MatrixWorkspace_sptr > > m_inputWSMatrix
std::vector< double > m_params
API::Workspace_sptr m_outputWorkspace
std::vector< double > m_endOverlaps
void doStitch1D(std::vector< API::MatrixWorkspace_sptr > &toStitch, const std::vector< double > &manualScaleFactors, API::Workspace_sptr &outWS)
Performs the Stitch1D algorithm at a specific workspace index.
std::vector< double > m_startOverlaps
std::map< std::string, std::string > validateInputs() override
Validates algorithm inputs.
std::vector< double > m_manualScaleFactors
void doStitch1DMany(const size_t period, const bool useManualScaleFactors, std::string &outName, std::vector< double > &outScaleFactors, const int indexOfReference, const bool storeInADS=true)
Performs the Stitch1DMany algorithm at a specific period.
std::string createChildWorkspaceName(const std::string &groupName, const size_t periodIndex)
Creates a correctly formatted name for a stitched child workspace in a workspace group.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
Same as EnabledWhenProperty, but returns the value for the isVisible() property instead of the isEnab...
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
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