Mantid
Loading...
Searching...
No Matches
DataProcessorAlgorithm.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 "MantidKernel/System.h"
20#include "Poco/Path.h"
21#include <stdexcept>
22#include <utility>
23
24#ifdef MPI_BUILD
25#include <boost/mpi.hpp>
26#endif
27
28using namespace Mantid::Kernel;
29using namespace Mantid::API;
30
31namespace Mantid::API {
32
33//----------------------------------------------------------------------------------------------
36template <class Base>
38 : m_useMPI(false), m_loadAlg("Load"), m_accumulateAlg("Plus"), m_loadAlgFileProp("Filename"),
39 m_propertyManagerPropertyName("ReductionProperties") {
40 Base::enableHistoryRecordingForChild(true);
41}
42
43//---------------------------------------------------------------------------------------------
64template <class Base>
65std::shared_ptr<Algorithm>
66GenericDataProcessorAlgorithm<Base>::createChildAlgorithm(const std::string &name, const double startProgress,
67 const double endProgress, const bool enableLogging,
68 const int &version) {
69 // call parent method to create the child algorithm
70 auto alg = Algorithm::createChildAlgorithm(name, startProgress, endProgress, enableLogging, version);
71 alg->enableHistoryRecordingForChild(this->isRecordingHistoryForChild());
72 if (this->isRecordingHistoryForChild()) {
73 // pass pointer to the history object created in Algorithm to the child
74 alg->trackAlgorithmHistory(Base::m_history);
75 }
76 return alg;
77}
78
79template <class Base> void GenericDataProcessorAlgorithm<Base>::setLoadAlg(const std::string &alg) {
80 if (alg.empty())
81 throw std::invalid_argument("Cannot set load algorithm to empty string");
82 m_loadAlg = alg;
83}
84
85template <class Base> void GenericDataProcessorAlgorithm<Base>::setLoadAlgFileProp(const std::string &filePropName) {
86 if (filePropName.empty()) {
87 throw std::invalid_argument("Cannot set the load algorithm file property name");
88 }
89 m_loadAlgFileProp = filePropName;
90}
91
92template <class Base> void GenericDataProcessorAlgorithm<Base>::setAccumAlg(const std::string &alg) {
93 if (alg.empty())
94 throw std::invalid_argument("Cannot set accumulate algorithm to empty string");
95 m_accumulateAlg = alg;
96}
97
98template <class Base> void GenericDataProcessorAlgorithm<Base>::setPropManagerPropName(const std::string &propName) {
99 m_propertyManagerPropertyName = propName;
100}
101
110template <class Base>
112 const std::string &nameInPropManager) {
113 m_nameToPMName[nameInProp] = nameInPropManager;
114}
115
127template <class Base>
129 if (!alg->existsProperty(name)) {
130 std::stringstream msg;
131 msg << "Algorithm \"" << alg->name() << "\" does not have property \"" << name << "\"";
132 throw std::runtime_error(msg.str());
133 }
134
135 auto prop = alg->getPointerToProperty(name);
136 Base::declareProperty(std::unique_ptr<Property>(prop->clone()), prop->documentation());
137}
138
147template <class Base> std::string GenericDataProcessorAlgorithm<Base>::getPropertyValue(const std::string &name) const {
148 // explicitly specifying a property wins
149 if (!Base::isDefault(name)) {
150 return Algorithm::getPropertyValue(name);
151 }
152
153 // return it if it is in the held property manager
154 auto mapping = m_nameToPMName.find(name);
155 if (mapping != m_nameToPMName.end()) {
156 auto pm = this->getProcessProperties();
157 if (pm->existsProperty(mapping->second)) {
158 return pm->getPropertyValue(mapping->second);
159 }
160 }
161
162 // let the parent class version win
163 return Algorithm::getPropertyValue(name);
164}
165
173template <class Base>
175 // explicitely specifying a property wins
176 if (!Base::isDefault(name)) {
177 return Base::getProperty(name);
178 }
179
180 // return it if it is in the held property manager
181 auto mapping = m_nameToPMName.find(name);
182 if (mapping != m_nameToPMName.end()) {
183 auto pm = this->getProcessProperties();
184 if (pm->existsProperty(mapping->second)) {
185 return pm->getProperty(mapping->second);
186 }
187 }
188
189 // let the parent class version win
190 return Algorithm::getProperty(name);
191}
192
193template <class Base>
195 UNUSED_ARG(filename);
196
197 throw std::runtime_error("DataProcessorAlgorithm::determineChunk is not implemented");
198}
199
200template <class Base> MatrixWorkspace_sptr GenericDataProcessorAlgorithm<Base>::loadChunk(const size_t rowIndex) {
201 UNUSED_ARG(rowIndex);
202
203 throw std::runtime_error("DataProcessorAlgorithm::loadChunk is not implemented");
204}
205
212 Workspace_sptr outputWS = std::move(partialWS);
213#ifdef MPI_BUILD
214 auto gatherAlg = createChildAlgorithm("GatherWorkspaces");
215 gatherAlg->setLogging(true);
216 gatherAlg->setAlwaysStoreInADS(true);
217 gatherAlg->setProperty("InputWorkspace", partialWS);
218 gatherAlg->setProperty("PreserveEvents", true);
219 gatherAlg->setPropertyValue("OutputWorkspace", "_total");
220 gatherAlg->execute();
221
222 if (isMainThread()) {
223 outputWS = AnalysisDataService::Instance().retrieve("_total");
224 }
225#endif
226
227 return outputWS;
228}
229
236template <class Base>
238 [[maybe_unused]] const std::string &outputWSName) {
239#ifdef MPI_BUILD
240 std::string threadOutput = partialWSName;
241 Workspace_sptr partialWS = AnalysisDataService::Instance().retrieve(partialWSName);
242 auto gatherAlg = createChildAlgorithm("GatherWorkspaces");
243 gatherAlg->setLogging(true);
244 gatherAlg->setAlwaysStoreInADS(true);
245 gatherAlg->setProperty("InputWorkspace", partialWS);
246 gatherAlg->setProperty("PreserveEvents", true);
247 gatherAlg->setPropertyValue("OutputWorkspace", outputWSName);
248 gatherAlg->execute();
249
250 if (isMainThread())
251 threadOutput = outputWSName;
252#else
253 const std::string &threadOutput = partialWSName;
254
255#endif
256 Workspace_sptr outputWS = AnalysisDataService::Instance().retrieve(threadOutput);
257 return outputWS;
258}
259
266template <class Base>
267void GenericDataProcessorAlgorithm<Base>::saveNexus(const std::string &outputWSName, const std::string &outputFile) {
268#ifdef MPI_BUILD
269 if (boost::mpi::communicator().rank() <= 0 && !outputFile.empty()) {
270#else
271 if (!outputFile.empty()) {
272#endif
273 auto saveAlg = createChildAlgorithm("SaveNexus");
274 saveAlg->setPropertyValue("Filename", outputFile);
275 saveAlg->setPropertyValue("InputWorkspace", outputWSName);
276 saveAlg->execute();
277 }
278}
279
282 bool mainThread;
283#ifdef MPI_BUILD
284 mainThread = (boost::mpi::communicator().rank() == 0);
285#else
286 mainThread = true;
287#endif
288 return mainThread;
289}
290
293#ifdef MPI_BUILD
294 return boost::mpi::communicator().size();
295#else
296 return 1;
297#endif
298}
299
305template <class Base>
306Workspace_sptr GenericDataProcessorAlgorithm<Base>::load(const std::string &inputData, const bool loadQuiet) {
307 Workspace_sptr inputWS;
308
309 // First, check whether we have the name of an existing workspace
310 if (AnalysisDataService::Instance().doesExist(inputData)) {
311 inputWS = AnalysisDataService::Instance().retrieve(inputData);
312 } else {
313 std::string foundFile = FileFinder::Instance().getFullPath(inputData);
314 if (foundFile.empty()) {
315 // Get facility extensions
316 FacilityInfo facilityInfo = ConfigService::Instance().getFacility();
317 const std::vector<std::string> facilityExts = facilityInfo.extensions();
318 foundFile = FileFinder::Instance().findRun(inputData, facilityExts);
319 }
320
321 if (!foundFile.empty()) {
322 Poco::Path p(foundFile);
323 const std::string outputWSName = p.getBaseName();
324
325 auto loadAlg = createChildAlgorithm(m_loadAlg);
326 loadAlg->setProperty(m_loadAlgFileProp, foundFile);
327 if (!loadQuiet) {
328 loadAlg->setAlwaysStoreInADS(true);
329 }
330
331// Set up MPI if available
332#ifdef MPI_BUILD
333 // First, check whether the loader allows use to chunk the data
334 if (loadAlg->existsProperty("ChunkNumber") && loadAlg->existsProperty("TotalChunks")) {
335 m_useMPI = true;
336 // The communicator containing all processes
337 boost::mpi::communicator world;
338 g_log.notice() << "Chunk/Total: " << world.rank() + 1 << "/" << world.size() << '\n';
339 loadAlg->setPropertyValue("OutputWorkspace", outputWSName);
340 loadAlg->setProperty("ChunkNumber", world.rank() + 1);
341 loadAlg->setProperty("TotalChunks", world.size());
342 }
343#endif
344 loadAlg->execute();
345
346 if (loadQuiet) {
347 inputWS = loadAlg->getProperty("OutputWorkspace");
348 } else {
349 inputWS = AnalysisDataService::Instance().retrieve(outputWSName);
350 }
351 } else
352 throw std::runtime_error("DataProcessorAlgorithm::load could process any data");
353 }
354 return inputWS;
355}
356
365template <class Base>
366std::shared_ptr<PropertyManager>
367GenericDataProcessorAlgorithm<Base>::getProcessProperties(const std::string &propertyManager) const {
368 std::string propertyManagerName(propertyManager);
369 if (propertyManager.empty() && (!m_propertyManagerPropertyName.empty())) {
370 if (!Base::existsProperty(m_propertyManagerPropertyName)) {
371 std::stringstream msg;
372 msg << "Failed to find property \"" << m_propertyManagerPropertyName << "\"";
373 throw Exception::NotFoundError(msg.str(), this->name());
374 }
375 propertyManagerName = this->getPropertyValue(m_propertyManagerPropertyName);
376 }
377
378 std::shared_ptr<PropertyManager> processProperties;
379 if (PropertyManagerDataService::Instance().doesExist(propertyManagerName)) {
380 processProperties = PropertyManagerDataService::Instance().retrieve(propertyManagerName);
381 } else {
382 Base::getLogger().notice() << "Could not find property manager\n";
383 processProperties = std::make_shared<PropertyManager>();
384 PropertyManagerDataService::Instance().addOrReplace(propertyManagerName, processProperties);
385 }
386 return processProperties;
387}
388
389template <class Base>
390std::vector<std::string> GenericDataProcessorAlgorithm<Base>::splitInput(const std::string &input) {
391 UNUSED_ARG(input);
392 throw std::runtime_error("DataProcessorAlgorithm::splitInput is not implemented");
393}
394
396 throw std::runtime_error("DataProcessorAlgorithm::forwardProperties is not implemented");
397}
398
399//------------------------------------------------------------------------------------------
400// Binary opration implementations for DPA so it can record history
401//------------------------------------------------------------------------------------------
402
409template <class Base>
412 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>("Divide", lhs,
413 rhs);
414}
415
422template <class Base>
424 const double &rhsValue) {
425 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>(
426 "Divide", lhs, createWorkspaceSingleValue(rhsValue));
427}
428
437template <class Base>
440 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>("Divide", lhs,
441 rhs);
442}
443
452template <class Base>
454 const double &rhsValue) {
455 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>(
456 "Multiply", lhs, createWorkspaceSingleValue(rhsValue));
457}
458
465template <class Base>
468 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>("Plus", lhs,
469 rhs);
470}
471
478template <class Base>
480 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>(
481 "Plus", lhs, createWorkspaceSingleValue(rhsValue));
482}
483
490template <class Base>
493 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>("Minus", lhs,
494 rhs);
495}
496
504template <class Base>
506 const double &rhsValue) {
507 return this->executeBinaryAlgorithm<MatrixWorkspace_sptr, MatrixWorkspace_sptr, MatrixWorkspace_sptr>(
508 "Minus", lhs, createWorkspaceSingleValue(rhsValue));
509}
510
516template <class Base>
518 MatrixWorkspace_sptr retVal = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1);
519 retVal->dataY(0)[0] = rhsValue;
520
521 return retVal;
522}
523
525
530
532
533} // namespace Mantid::API
const std::vector< double > & rhs
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
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
Data processor algorithm to be used as a parent to workflow algorithms.
std::shared_ptr< Kernel::PropertyManager > getProcessProperties(const std::string &propertyManager=std::string()) const
Get the property manager object of a given name from the property manager data service,...
MatrixWorkspace_sptr createWorkspaceSingleValue(const double &rhsValue)
Create a matrix workspace from a single number.
Workspace_sptr assemble(Workspace_sptr partialWS)
Assemble the partial workspaces from all MPI processes.
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.
virtual ITableWorkspace_sptr determineChunk(const std::string &filename)
bool isMainThread()
Return true if we are running on the main thread.
void saveNexus(const std::string &outputWSName, const std::string &outputFile)
Save a workspace as a nexus file, with check for which thread we are executing in.
void copyProperty(const API::Algorithm_sptr &alg, const std::string &name)
Copy a property from an existing algorithm.
Kernel::IPropertyManager::TypedValue getProperty(const std::string &name) const override
Get the property held by this object.
std::vector< std::string > splitInput(const std::string &input)
std::string getPropertyValue(const std::string &name) const override
Get the property held by this object.
void setLoadAlgFileProp(const std::string &filePropName)
int getNThreads()
Return the number of MPI processes running.
MatrixWorkspace_sptr plus(const MatrixWorkspace_sptr lhs, const MatrixWorkspace_sptr rhs)
Add a matrix workspace to another matrix workspace.
MatrixWorkspace_sptr minus(const MatrixWorkspace_sptr lhs, const MatrixWorkspace_sptr rhs)
Subract a matrix workspace by another matrix workspace.
MatrixWorkspace_sptr multiply(const MatrixWorkspace_sptr lhs, const MatrixWorkspace_sptr rhs)
Multiply a matrix workspace by another matrix workspace.
virtual MatrixWorkspace_sptr loadChunk(const size_t rowIndex)
void setPropManagerPropName(const std::string &propName)
Workspace_sptr load(const std::string &inputData, const bool loadQuiet=false)
Determine what kind of input data we have and load it.
void mapPropertyName(const std::string &nameInProp, const std::string &nameInPropManager)
Declare mapping of property name to name in the PropertyManager.
MatrixWorkspace_sptr divide(const MatrixWorkspace_sptr lhs, const MatrixWorkspace_sptr rhs)
Divide a matrix workspace by another matrix workspace.
Exception for when an item is not found in a collection.
Definition: Exception.h:145
A class that holds information about a facility.
Definition: FacilityInfo.h:36
const std::vector< std::string > extensions() const
Returns a list of file extensions.
Definition: FacilityInfo.h:48
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition: Algorithm.h:61
static MatrixWorkspace_sptr createWorkspaceSingleValue(const double &rhsValue)
Creates a temporary single value workspace the error is set to zero.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
Utility class that enables the getProperty() method to effectively be templated on the return type.