Mantid
Loading...
Searching...
No Matches
PerformIndexOperations.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 +
11#include <boost/algorithm/string.hpp>
12#include <boost/regex.hpp>
13#include <utility>
14
15using namespace Mantid::Kernel;
16using namespace Mantid::API;
17
18namespace {
23class Command {
24public:
25 virtual bool isValid() const { return true; }
26
27 virtual MatrixWorkspace_sptr execute(MatrixWorkspace_sptr input) const = 0;
28
29 virtual MatrixWorkspace_sptr executeAndAppend(MatrixWorkspace_sptr inputWS, MatrixWorkspace_sptr toAppend) const {
30 if (!this->isValid()) {
31 return toAppend;
32 } else {
33 MatrixWorkspace_sptr current = this->execute(std::move(inputWS));
34 Mantid::API::AlgorithmManagerImpl &factory = Mantid::API::AlgorithmManager::Instance();
35 auto conjoinWorkspaceAlg = factory.create("ConjoinWorkspaces");
36 conjoinWorkspaceAlg->setChild(true);
37 conjoinWorkspaceAlg->initialize();
38 conjoinWorkspaceAlg->setProperty("InputWorkspace1", toAppend);
39 conjoinWorkspaceAlg->setProperty("InputWorkspace2", current);
40 conjoinWorkspaceAlg->setProperty("CheckMatchingBins", false);
41 conjoinWorkspaceAlg->execute();
42 MatrixWorkspace_sptr outWS = conjoinWorkspaceAlg->getProperty("InputWorkspace1");
43 return outWS;
44 }
45 }
46
47 virtual ~Command() = default;
48};
49
51using VecCommands = std::vector<std::shared_ptr<Command>>;
52
56class NullCommand : public Command {
57 bool isValid() const override { return false; }
58 MatrixWorkspace_sptr execute(MatrixWorkspace_sptr /*input*/) const override {
59 throw std::runtime_error("Should not be attempting ::execute on a NullCommand");
60 }
61};
62
66class AdditionCommand : public Command {
67private:
68 std::vector<int> m_indexes;
69
70public:
71 explicit AdditionCommand(std::vector<int> indexes) : m_indexes(std::move(indexes)) {}
72
73 MatrixWorkspace_sptr execute(MatrixWorkspace_sptr inputWS) const override {
75 if (!m_indexes.empty()) {
76 Mantid::API::AlgorithmManagerImpl &factory = Mantid::API::AlgorithmManager::Instance();
77 auto sumSpectraAlg = factory.create("SumSpectra");
78 sumSpectraAlg->setChild(true);
79 sumSpectraAlg->initialize();
80 sumSpectraAlg->setProperty("InputWorkspace", inputWS);
81 sumSpectraAlg->setProperty("ListOfWorkspaceIndices", m_indexes);
82 sumSpectraAlg->setPropertyValue("OutputWorkspace", "outWS");
83 sumSpectraAlg->execute();
84 outWS = sumSpectraAlg->getProperty("OutputWorkspace");
85 }
86 return outWS;
87 }
88};
89
93class CropCommand : public Command {
94private:
95 std::vector<int> m_indexes;
96
97public:
98 explicit CropCommand(std::vector<int> indexes) : m_indexes(std::move(indexes)) {}
99
100 MatrixWorkspace_sptr execute(MatrixWorkspace_sptr inputWS) const override {
101
103 for (size_t i = 0; i < m_indexes.size(); ++i) {
104 Mantid::API::AlgorithmManagerImpl &factory = Mantid::API::AlgorithmManager::Instance();
105 auto cropWorkspaceAlg = factory.create("CropWorkspace");
106 cropWorkspaceAlg->setChild(true);
107 cropWorkspaceAlg->initialize();
108 cropWorkspaceAlg->setProperty("InputWorkspace", inputWS);
109 cropWorkspaceAlg->setProperty("StartWorkspaceIndex", m_indexes[i]);
110 cropWorkspaceAlg->setProperty("EndWorkspaceIndex", m_indexes[i]);
111 cropWorkspaceAlg->setPropertyValue("OutputWorkspace", "outWS");
112 cropWorkspaceAlg->execute();
113 MatrixWorkspace_sptr subRange = cropWorkspaceAlg->getProperty("OutputWorkspace");
114 if (i == 0) {
115 outWS = subRange;
116 } else {
117 auto conjoinWorkspaceAlg = factory.create("ConjoinWorkspaces");
118 conjoinWorkspaceAlg->setChild(true);
119 conjoinWorkspaceAlg->initialize();
120 conjoinWorkspaceAlg->setProperty("InputWorkspace1", outWS);
121 conjoinWorkspaceAlg->setProperty("InputWorkspace2", subRange);
122 conjoinWorkspaceAlg->setProperty("CheckMatchingBins", false);
123 conjoinWorkspaceAlg->execute();
124 outWS = conjoinWorkspaceAlg->getProperty("InputWorkspace1");
125 }
126 }
127 return outWS;
128 }
129};
130
134class CommandParser {
135public:
136 virtual Command *interpret(const std::string &instruction) const = 0;
137
138 virtual ~CommandParser() = default;
139};
140
142using VecCommandParsers = std::vector<std::shared_ptr<CommandParser>>;
143
147template <typename ProductType> class CommandParserBase : public CommandParser {
148public:
149 Command *interpret(const std::string &instruction) const override {
150 Command *command = nullptr;
151 boost::regex ex = getRegex();
152 if (boost::regex_match(instruction, ex)) {
153 auto indexes = Mantid::Kernel::Strings::parseRange(instruction, ",", getSeparator());
154 command = new ProductType(indexes);
155 } else {
156 command = new NullCommand;
157 }
158 return command;
159 }
160
161private:
162 virtual std::string getSeparator() const = 0;
163 virtual boost::regex getRegex() const = 0;
164};
165
169class AdditionParserRange : public CommandParserBase<AdditionCommand> {
170public:
171private:
172 boost::regex getRegex() const override {
173 static const boost::regex r(R"(^\s*[0-9]+\s*\-\s*[0-9]+\s*$)");
174 return r;
175 }
176 std::string getSeparator() const override { return "-"; }
177};
178
182class AdditionParser : public CommandParser {
183public:
184 Command *interpret(const std::string &instruction) const override {
185 Command *command = nullptr;
186 static const boost::regex ex(R"(^\s*[0-9]+\s*\+\s*[0-9]+\s*$)");
187 if (boost::regex_match(instruction, ex)) {
188 std::vector<std::string> arguments;
189 boost::split(arguments, instruction, boost::is_any_of("+"));
190 int minIndex = -1;
191 int maxIndex = -1;
192 Mantid::Kernel::Strings::convert<int>(arguments.front(), minIndex);
193 Mantid::Kernel::Strings::convert<int>(arguments.back(), maxIndex);
194 std::vector<int> indexes;
195 indexes.emplace_back(minIndex);
196 indexes.emplace_back(maxIndex);
197 command = new AdditionCommand(indexes);
198 } else {
199 command = new NullCommand;
200 }
201 return command;
202 }
203};
204
208class CropParserRange : public CommandParserBase<CropCommand> {
209public:
210private:
211 boost::regex getRegex() const override {
212 static const boost::regex r(R"(^\s*[0-9]+\s*:\s*[0-9]+\s*$)");
213 return r;
214 }
215 std::string getSeparator() const override { return ":"; }
216};
217
221class CropParserIndex : public CommandParser {
222public:
223 Command *interpret(const std::string &instruction) const override {
224 Command *command = nullptr;
225 static const boost::regex ex("^\\s*[0-9]+\\s*$");
226 if (boost::regex_match(instruction, ex)) {
227 int index = -1;
228 Mantid::Kernel::Strings::convert<int>(instruction, index);
229 std::vector<int> indexes(1, index);
230 command = new CropCommand(indexes);
231 } else {
232 command = new NullCommand;
233 }
234 return command;
235 }
236};
237} // namespace
238
239namespace Mantid::Algorithms {
240
241// Register the algorithm into the AlgorithmFactory
242DECLARE_ALGORITHM(PerformIndexOperations)
243
244//------------------------------------------------------------------------------
246const std::string PerformIndexOperations::name() const { return "PerformIndexOperations"; }
247
249int PerformIndexOperations::version() const { return 1; }
250
252const std::string PerformIndexOperations::category() const { return "Transforms\\Grouping"; }
253
254//------------------------------------------------------------------------------
255
256//------------------------------------------------------------------------------
260 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
261 "Input to processes workspace.");
262 declareProperty(std::make_unique<PropertyWithValue<std::string>>("ProcessingInstructions", "", Direction::Input),
263 "Processing instructions. See full instruction list.");
264 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
265 "Output processed workspace");
266}
267
276VecCommands interpret(const std::string &processingInstructions) {
277 std::vector<std::string> processingInstructionsSplit;
278 boost::split(processingInstructionsSplit, processingInstructions, boost::is_any_of(","));
279
280 VecCommandParsers commandParsers{std::make_shared<AdditionParserRange>(), std::make_shared<CropParserRange>(),
281 std::make_shared<CropParserIndex>(), std::make_shared<AdditionParser>()};
282
283 VecCommands commands;
284 for (const auto &candidate : processingInstructionsSplit) {
285 bool parserFound = false;
286 for (const auto &commandParser : commandParsers) {
287 Command *command = commandParser->interpret(candidate);
288 std::shared_ptr<Command> commandSptr(command);
289 if (commandSptr->isValid()) // Do not record invalid commands.
290 {
291 parserFound = true;
292 commands.emplace_back(commandSptr);
293 }
294 }
295 if (!parserFound) {
296 throw std::invalid_argument("Cannot interpret " + candidate);
297 }
298 }
299 return commands;
300}
301
302//------------------------------------------------------------------------------
306 MatrixWorkspace_sptr inputWorkspace = this->getProperty("InputWorkspace");
307 const std::string processingInstructions = this->getProperty("ProcessingInstructions");
308
309 boost::regex re(R"(^\s*[0-9]+\s*$|^(\s*,*[0-9]+(\s*(,|:|\+|\-)\s*)*[0-9]*)*$)");
310 if (!boost::regex_match(processingInstructions, re)) {
311 throw std::invalid_argument("ProcessingInstructions are not well formed: " + processingInstructions);
312 }
313
314 if (processingInstructions.empty()) {
315 auto cloneWS = this->createChildAlgorithm("CloneWorkspace");
316 cloneWS->initialize();
317 cloneWS->setProperty("InputWorkspace", inputWorkspace);
318 cloneWS->execute();
319 Workspace_sptr tmp = cloneWS->getProperty("OutputWorkspace");
320 MatrixWorkspace_sptr outWS = std::dynamic_pointer_cast<MatrixWorkspace>(tmp);
321 this->setProperty("OutputWorkspace", outWS);
322 } else {
323 // Interpret the instructions.
324 VecCommands commands = interpret(processingInstructions);
325
326 // Execute the commands.
327 auto command = commands[0];
328 MatrixWorkspace_sptr outWS = command->execute(inputWorkspace);
329 for (size_t j = 1; j < commands.size(); ++j) {
330 outWS = commands[j]->executeAndAppend(inputWorkspace, outWS);
331 }
332
333 this->setProperty("OutputWorkspace", outWS);
334 }
335}
336
337} // namespace Mantid::Algorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
gsl_vector * tmp
std::map< DeltaEMode::Type, std::string > index
The AlgorithmManagerImpl class is responsible for controlling algorithm instances.
IAlgorithm_sptr create(const std::string &algName, const int &version=-1)
Creates a managed algorithm with the option of choosing a version.
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) override
Create a Child Algorithm.
Kernel::IPropertyManager::TypedValue getProperty(const std::string &name) const override
Get the property held by this object.
A property class for workspaces.
PerformIndexOperations : Crop and sum a workspace according to the parsed workspace index operations ...
void init() override
Initialize the algorithm's properties.
int version() const override
Algorithm's version for identification.
void exec() override
Execute the algorithm.
const std::string category() const override
Algorithm's category for identification.
The concrete, templated class for properties.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
VecCommands interpret(const std::string &processingInstructions)
Interpret the instructions as an ordered list of commands that can be executed later.
MANTID_KERNEL_DLL std::vector< int > parseRange(const std::string &str, const std::string &elemSep=",", const std::string &rangeSep="-")
Parses a number range, e.g.
Definition Strings.cpp:1101
STL namespace.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54