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