Mantid
Loading...
Searching...
No Matches
ReplicateMD.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 +
10#include "MantidAPI/Progress.h"
15#include "MantidKernel/Utils.h"
16#include <memory>
17#include <sstream>
18#include <string>
19#include <utility>
20
21namespace Mantid::MDAlgorithms {
22
23using namespace Mantid::Kernel;
24using namespace Mantid::API;
25using namespace Mantid::Geometry;
26using namespace Mantid::DataObjects;
27
28namespace {
29
37IMDDimension_const_sptr findMatchingDimension(const IMDHistoWorkspace &toSearch, const IMDDimension &forDim) {
39 try {
40 // This will throw if it doesn't exist.
41 foundDim = toSearch.getDimensionWithId(forDim.getDimensionId());
42 } catch (std::invalid_argument &) {
43 // Do nothing.
44 }
45 return foundDim;
46}
47
57size_t findReplicationDimension(const IMDHistoWorkspace &shapeWS, const IMDHistoWorkspace &dataWS) {
58 size_t index = -1;
59 for (size_t i = 0; i < shapeWS.getNumDims(); ++i) {
60 const auto shapeDim = shapeWS.getDimension(i);
61
62 const auto dataDim = findMatchingDimension(dataWS, *shapeDim);
63 if (!dataDim || dataDim->getIsIntegrated()) {
64 index = i;
65 break;
66 }
67 }
68 return index;
69}
70
77std::vector<int> findAxes(const IMDHistoWorkspace &shapeWS, const IMDHistoWorkspace &dataWS) {
78
79 std::vector<int> axes;
80 for (size_t i = 0; i < dataWS.getNumDims(); ++i) {
81 const auto dataDim = dataWS.getDimension(i);
82 if (!dataDim->getIsIntegrated()) {
83 auto index = static_cast<int>(shapeWS.getDimensionIndexById(dataDim->getDimensionId()));
84 axes.emplace_back(index);
85 }
86 }
87 return axes;
88}
89
109size_t linearIndexToLinearIndex(const size_t &nDimsShape, const size_t &shapeReplicationIndex,
110 const std::vector<size_t> &indexMaxShape, const std::vector<size_t> &indexMakerShape,
111 size_t const &sourceIndex, std::vector<size_t> const &indexMakerData,
112 const size_t &nDimsData) {
113 std::vector<size_t> vecShapeIndexes(nDimsShape);
114 Utils::NestedForLoop::GetIndicesFromLinearIndex(nDimsShape, sourceIndex, &indexMakerShape[0], &indexMaxShape[0],
115 &vecShapeIndexes[0]);
116
117 vecShapeIndexes.erase(vecShapeIndexes.begin() + shapeReplicationIndex);
118
119 const size_t targetIndex = Utils::NestedForLoop::GetLinearIndex(nDimsData, &vecShapeIndexes[0], &indexMakerData[0]);
120
121 return targetIndex;
122}
123} // namespace
124
125// Register the algorithm into the AlgorithmFactory
126DECLARE_ALGORITHM(ReplicateMD)
127
128//----------------------------------------------------------------------------------------------
129
130
131const std::string ReplicateMD::name() const { return "ReplicateMD"; }
132
134int ReplicateMD::version() const { return 1; }
135
137const std::string ReplicateMD::category() const { return "MDAlgorithms\\Creation"; }
138
140const std::string ReplicateMD::summary() const {
141 return "This is an algorithm to create a higher dimensional dataset by "
142 "replicating along an additional axis";
143}
144
152 const std::vector<int> &axes) {
153
154 auto transposeMD = this->createChildAlgorithm("TransposeMD", 0.0, 0.5);
155 transposeMD->setProperty("InputWorkspace", toTranspose);
156 transposeMD->setProperty("Axes", axes);
157 transposeMD->execute();
158 IMDHistoWorkspace_sptr outputWS = transposeMD->getProperty("OutputWorkspace");
159 return std::dynamic_pointer_cast<const MDHistoWorkspace>(outputWS);
160}
161
167std::map<std::string, std::string> ReplicateMD::validateInputs() {
168 std::map<std::string, std::string> errorMap;
169 IMDHistoWorkspace_sptr shapeWS = this->getProperty("ShapeWorkspace");
170 IMDHistoWorkspace_sptr dataWS = this->getProperty("DataWorkspace");
171 if (shapeWS->getNumNonIntegratedDims() != dataWS->getNumNonIntegratedDims() + 1) {
172 errorMap.emplace("DataWorkspace", "Expect to have n-1 non-interated dimensions of ShapeWorkspace");
173 }
174
175 size_t nonMatchingCount = 0;
176 bool haveMatchingIntegratedDims = false;
177 for (size_t i = 0; i < shapeWS->getNumDims(); ++i) {
178 const auto shapeDim = shapeWS->getDimension(i);
179
180 // Attempt to match dimensions in both input workspaces based on Ids.
181 const auto dataDim = findMatchingDimension(*dataWS, *shapeDim);
182 if (dataDim) {
183 if (dataDim->getIsIntegrated()) {
184 if (!shapeDim->getIsIntegrated()) {
185 // We count this as a non-matching dimension
186 ++nonMatchingCount;
187 } else {
188 haveMatchingIntegratedDims = true;
189 }
190 } else {
191 // Check bin sizes match between the two dimensions
192 if (shapeDim->getNBins() != dataDim->getNBins()) {
193 std::stringstream stream;
194 stream << "Dimension with id " << shapeDim->getDimensionId()
195 << " in ShapeWorkspace has a different number of bins as the "
196 "same id dimension in the DataWorkspace";
197 errorMap.emplace("DataWorkspace", stream.str());
198 } else if (haveMatchingIntegratedDims) {
199 errorMap.emplace("ShapeWorkspace", "Extra integrated dimensions must be only "
200 "the last dimensions, e.g.:\n\nThis is allowed:\n "
201 "Shape: {10, 5, 1, 1}\n Data: { 1, 5, 1, 1}\n\nBut "
202 "this is not:\n Shape: {10, 1, 5, 1}\n Data: { 1, 1, "
203 "5, 1}\n\nUse TransposeMD to re-arrange dimensions.");
204 break;
205 }
206 }
207 } else {
208 ++nonMatchingCount;
209 }
210 }
211
212 // Check number of missing/integrated dimensions
213 if (nonMatchingCount != 1) {
214 errorMap.emplace("DataWorkspace", "There should be ONLY 1 dimension present "
215 "in the ShapeWorkspace that is not present "
216 "(or integrated out) in the DataWorkspace");
217 }
218
219 return errorMap;
220}
221
222//----------------------------------------------------------------------------------------------
226 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("ShapeWorkspace", "", Direction::Input),
227 "An input workspace defining the shape of the output.");
228 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("DataWorkspace", "", Direction::Input),
229 "An input workspace containing the data to replicate.");
230 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("OutputWorkspace", "", Direction::Output),
231 "An output workspace with replicated data.");
232}
233
239 MDHistoWorkspace_sptr shapeWS;
240 {
241 IMDHistoWorkspace_sptr temp = this->getProperty("ShapeWorkspace");
242 shapeWS = std::dynamic_pointer_cast<MDHistoWorkspace>(temp);
243 }
244
245 return shapeWS;
246}
247
254 {
255 IMDHistoWorkspace_sptr temp = this->getProperty("DataWorkspace");
256 dataWS = std::dynamic_pointer_cast<MDHistoWorkspace>(temp);
257 }
258
259 return dataWS;
260}
261
262//----------------------------------------------------------------------------------------------
266
269
270 const size_t nDimsShape = shapeWS->getNumDims();
271 size_t nDimsData = dataWS->getNumDims();
272 Progress progress(this, 0.0, 1.0, size_t(shapeWS->getNPoints()));
273
274 /*
275 We transpose the input so that we have the same order of dimensions in data
276 as in the shape. This is important. If they are not in the same order, then
277 the linear index -> linear index calculation below will not work correctly.
278 */
279 MDHistoWorkspace_const_sptr transposedDataWS = dataWS;
280 if (nDimsData <= nDimsShape) {
281 auto axes = findAxes(*shapeWS, *dataWS);
282 // Check that the indices stored in axes are compatible with the
283 // dimensionality of the data workspace
284 const auto numberOfDimensionsOfDataWorkspace = static_cast<int>(nDimsData);
285 const auto found = std::find_if(axes.cbegin(), axes.cend(), [numberOfDimensionsOfDataWorkspace](const auto &axis) {
286 return axis >= numberOfDimensionsOfDataWorkspace;
287 });
288 if (found != axes.cend()) {
289 std::string message = "ReplicateMD: Cannot transpose the data workspace. Attempting to "
290 "swap dimension index " +
291 std::to_string(std::distance(static_cast<const int *>(&axes[0]), &(*found))) +
292 " with index " + std::to_string(*found) +
293 ", but the dimensionality of the data workspace is " + std::to_string(nDimsData);
294 throw std::runtime_error(message);
295 }
296 transposedDataWS = transposeMD(dataWS, axes);
297 nDimsData = transposedDataWS->getNumDims();
298 }
299
300 // Set up index maker for shape
301 std::vector<size_t> indexMakerShape(nDimsShape);
302 std::vector<size_t> indexMaxShape(nDimsShape);
303 for (size_t i = 0; i < nDimsShape; ++i) {
304 indexMaxShape[i] = shapeWS->getDimension(i)->getNBins();
305 }
306 Utils::NestedForLoop::SetUpIndexMaker(nDimsShape, &indexMakerShape[0], &indexMaxShape[0]);
307
308 // Set up index maker for data.
309 std::vector<size_t> indexMakerData(nDimsData);
310 std::vector<size_t> indexMaxData(nDimsData);
311 for (size_t i = 0; i < nDimsData; ++i) {
312 indexMaxData[i] = transposedDataWS->getDimension(i)->getNBins();
313 }
314 Utils::NestedForLoop::SetUpIndexMaker(nDimsData, &indexMakerData[0], &indexMaxData[0]);
315
316 // Dimension index into the shape workspace where we will be replicating
317 const size_t shapeReplicationIndex = findReplicationDimension(*shapeWS, *transposedDataWS);
318
319 // Create the output workspace from the shape.
320 MDHistoWorkspace_sptr outputWS(shapeWS->clone());
321 const int nThreads = Mantid::API::FrameworkManager::Instance().getNumOMPThreads(); // NThreads to Request
322
323 // collection of iterators
324 auto iterators = outputWS->createIterators(nThreads, nullptr);
325
327 for (int it = 0; it < int(iterators.size()); ++it) { // NOLINT
328
330 auto outIt = dynamic_cast<MDHistoWorkspaceIterator *>(iterators[it].get());
331
332 // Iterate over the output workspace
333 do {
334
335 const auto sourceIndex = outIt->getLinearIndex();
336
337 // Figure out the linear index in the data.
338 const size_t targetIndex = linearIndexToLinearIndex(nDimsShape, shapeReplicationIndex, indexMaxShape,
339 indexMakerShape, sourceIndex, indexMakerData, nDimsData);
340
341 // Copy the data across
342 outputWS->setSignalAt(sourceIndex, transposedDataWS->getSignalAt(targetIndex));
343 outputWS->setErrorSquaredAt(sourceIndex, transposedDataWS->getErrorAt(targetIndex) *
344 transposedDataWS->getErrorAt(targetIndex));
345 outputWS->setNumEventsAt(sourceIndex, transposedDataWS->getNumEventsAt(targetIndex));
346 outputWS->setMDMaskAt(sourceIndex, transposedDataWS->getIsMaskedAt(targetIndex));
347 progress.report();
348
349 } while (outIt->next());
350
352 }
354
355 this->setProperty("OutputWorkspace", outputWS);
356}
357
358} // namespace Mantid::MDAlgorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Abstract interface to MDHistoWorkspace, for use in exposing to Python.
virtual std::shared_ptr< const Mantid::Geometry::IMDDimension > getDimension(size_t index) const
Get a dimension.
size_t getDimensionIndexById(const std::string &id) const
Get the index of the dimension that matches the ID given.
virtual std::shared_ptr< const Mantid::Geometry::IMDDimension > getDimensionWithId(std::string id) const
Get a dimension.
virtual size_t getNumDims() const
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
An implementation of IMDIterator that iterates through a MDHistoWorkspace.
size_t getLinearIndex() const override
Getter for the linear index.
The class describes one dimension of multidimensional dataset representing an orthogonal dimension an...
virtual const std::string & getDimensionId() const =0
short name which identify the dimension among other dimension.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
ReplicateMD : Algorithm header for ReplicateMD.
Definition ReplicateMD.h:28
std::shared_ptr< Mantid::DataObjects::MDHistoWorkspace > getDataWorkspace() const
fetches and down casts
void exec() override
Execute the algorithm.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
std::map< std::string, std::string > validateInputs() override
Valdiate the algorithm inputs.
void init() override
Initialize the algorithm's properties.
const std::string category() const override
Algorithm's category for identification.
std::shared_ptr< Mantid::DataObjects::MDHistoWorkspace > getShapeWorkspace() const
fetches and down casts
int version() const override
Algorithm's version for identification.
std::shared_ptr< const Mantid::DataObjects::MDHistoWorkspace > transposeMD(std::shared_ptr< Mantid::DataObjects::MDHistoWorkspace > const &toTranspose, const std::vector< int > &axes)
Transpose the input data workspace according to the axis provided.
std::shared_ptr< IMDHistoWorkspace > IMDHistoWorkspace_sptr
shared pointer to Mantid::API::IMDHistoWorkspace
std::shared_ptr< MDHistoWorkspace > MDHistoWorkspace_sptr
A shared pointer to a MDHistoWorkspace.
std::shared_ptr< const MDHistoWorkspace > MDHistoWorkspace_const_sptr
A shared pointer to a const MDHistoWorkspace.
std::shared_ptr< const IMDDimension > IMDDimension_const_sptr
Shared Pointer to const IMDDimension.
size_t GetLinearIndex(const size_t numDims, const size_t *index, const size_t *index_maker)
Return a linear index from dimensional indices of a nested for loop.
Definition Utils.h:125
void GetIndicesFromLinearIndex(const size_t numDims, const size_t linear_index, const size_t *index_maker, const size_t *index_max, size_t *out_indices)
Set up a nested for loop by creating an array of counters.
Definition Utils.h:144
void SetUpIndexMaker(const size_t numDims, size_t *out, const size_t *index_max)
Set up an "index maker" for a nested for loop.
Definition Utils.h:104
STL namespace.
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