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 const size_t &sourceIndex, std::vector<size_t> &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
153 auto transposeMD = this->createChildAlgorithm("TransposeMD", 0.0, 0.5);
154 transposeMD->setProperty("InputWorkspace", toTranspose);
155 transposeMD->setProperty("Axes", axes);
156 transposeMD->execute();
157 IMDHistoWorkspace_sptr outputWS = transposeMD->getProperty("OutputWorkspace");
158 return std::dynamic_pointer_cast<const MDHistoWorkspace>(outputWS);
159}
160
166std::map<std::string, std::string> ReplicateMD::validateInputs() {
167 std::map<std::string, std::string> errorMap;
168 IMDHistoWorkspace_sptr shapeWS = this->getProperty("ShapeWorkspace");
169 IMDHistoWorkspace_sptr dataWS = this->getProperty("DataWorkspace");
170 if (shapeWS->getNumNonIntegratedDims() != dataWS->getNumNonIntegratedDims() + 1) {
171 errorMap.emplace("DataWorkspace", "Expect to have n-1 non-interated dimensions of ShapeWorkspace");
172 }
173
174 size_t nonMatchingCount = 0;
175 bool haveMatchingIntegratedDims = false;
176 for (size_t i = 0; i < shapeWS->getNumDims(); ++i) {
177 const auto shapeDim = shapeWS->getDimension(i);
178
179 // Attempt to match dimensions in both input workspaces based on Ids.
180 const auto dataDim = findMatchingDimension(*dataWS, *shapeDim);
181 if (dataDim) {
182 if (dataDim->getIsIntegrated()) {
183 if (!shapeDim->getIsIntegrated()) {
184 // We count this as a non-matching dimension
185 ++nonMatchingCount;
186 } else {
187 haveMatchingIntegratedDims = true;
188 }
189 } else {
190 // Check bin sizes match between the two dimensions
191 if (shapeDim->getNBins() != dataDim->getNBins()) {
192 std::stringstream stream;
193 stream << "Dimension with id " << shapeDim->getDimensionId()
194 << " in ShapeWorkspace has a different number of bins as the "
195 "same id dimension in the DataWorkspace";
196 errorMap.emplace("DataWorkspace", stream.str());
197 } else if (haveMatchingIntegratedDims) {
198 errorMap.emplace("ShapeWorkspace", "Extra integrated dimensions must be only "
199 "the last dimensions, e.g.:\n\nThis is allowed:\n "
200 "Shape: {10, 5, 1, 1}\n Data: { 1, 5, 1, 1}\n\nBut "
201 "this is not:\n Shape: {10, 1, 5, 1}\n Data: { 1, 1, "
202 "5, 1}\n\nUse TransposeMD to re-arrange dimensions.");
203 break;
204 }
205 }
206 } else {
207 ++nonMatchingCount;
208 }
209 }
210
211 // Check number of missing/integrated dimensions
212 if (nonMatchingCount != 1) {
213 errorMap.emplace("DataWorkspace", "There should be ONLY 1 dimension present "
214 "in the ShapeWorkspace that is not present "
215 "(or integrated out) in the DataWorkspace");
216 }
217
218 return errorMap;
219}
220
221//----------------------------------------------------------------------------------------------
225 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("ShapeWorkspace", "", Direction::Input),
226 "An input workspace defining the shape of the output.");
227 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("DataWorkspace", "", Direction::Input),
228 "An input workspace containing the data to replicate.");
229 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("OutputWorkspace", "", Direction::Output),
230 "An output workspace with replicated data.");
231}
232
238 MDHistoWorkspace_sptr shapeWS;
239 {
240 IMDHistoWorkspace_sptr temp = this->getProperty("ShapeWorkspace");
241 shapeWS = std::dynamic_pointer_cast<MDHistoWorkspace>(temp);
242 }
243
244 return shapeWS;
245}
246
253 {
254 IMDHistoWorkspace_sptr temp = this->getProperty("DataWorkspace");
255 dataWS = std::dynamic_pointer_cast<MDHistoWorkspace>(temp);
256 }
257
258 return dataWS;
259}
260
261//----------------------------------------------------------------------------------------------
265
268
269 const size_t nDimsShape = shapeWS->getNumDims();
270 size_t nDimsData = dataWS->getNumDims();
271 Progress progress(this, 0.0, 1.0, size_t(shapeWS->getNPoints()));
272
273 /*
274 We transpose the input so that we have the same order of dimensions in data
275 as in the shape. This is important. If they are not in the same order, then
276 the linear index -> linear index calculation below will not work correctly.
277 */
278 MDHistoWorkspace_const_sptr transposedDataWS = dataWS;
279 if (nDimsData <= nDimsShape) {
280 auto axes = findAxes(*shapeWS, *dataWS);
281 // Check that the indices stored in axes are compatible with the
282 // dimensionality of the data workspace
283 const auto numberOfDimensionsOfDataWorkspace = static_cast<int>(nDimsData);
284 const auto found = std::find_if(axes.cbegin(), axes.cend(), [numberOfDimensionsOfDataWorkspace](const auto &axis) {
285 return axis >= numberOfDimensionsOfDataWorkspace;
286 });
287 if (found != axes.cend()) {
288 std::string message = "ReplicateMD: Cannot transpose the data workspace. Attempting to "
289 "swap dimension index " +
290 std::to_string(std::distance(static_cast<const int *>(&axes[0]), &(*found))) +
291 " with index " + std::to_string(*found) +
292 ", but the dimensionality of the data workspace is " + std::to_string(nDimsData);
293 throw std::runtime_error(message);
294 }
295 transposedDataWS = transposeMD(dataWS, axes);
296 nDimsData = transposedDataWS->getNumDims();
297 }
298
299 // Set up index maker for shape
300 std::vector<size_t> indexMakerShape(nDimsShape);
301 std::vector<size_t> indexMaxShape(nDimsShape);
302 for (size_t i = 0; i < nDimsShape; ++i) {
303 indexMaxShape[i] = shapeWS->getDimension(i)->getNBins();
304 }
305 Utils::NestedForLoop::SetUpIndexMaker(nDimsShape, &indexMakerShape[0], &indexMaxShape[0]);
306
307 // Set up index maker for data.
308 std::vector<size_t> indexMakerData(nDimsData);
309 std::vector<size_t> indexMaxData(nDimsData);
310 for (size_t i = 0; i < nDimsData; ++i) {
311 indexMaxData[i] = transposedDataWS->getDimension(i)->getNBins();
312 }
313 Utils::NestedForLoop::SetUpIndexMaker(nDimsData, &indexMakerData[0], &indexMaxData[0]);
314
315 // Dimension index into the shape workspace where we will be replicating
316 const size_t shapeReplicationIndex = findReplicationDimension(*shapeWS, *transposedDataWS);
317
318 // Create the output workspace from the shape.
319 MDHistoWorkspace_sptr outputWS(shapeWS->clone());
320 const int nThreads = Mantid::API::FrameworkManager::Instance().getNumOMPThreads(); // NThreads to Request
321
322 // collection of iterators
323 auto iterators = outputWS->createIterators(nThreads, nullptr);
324
326 for (int it = 0; it < int(iterators.size()); ++it) { // NOLINT
327
329 auto outIt = dynamic_cast<MDHistoWorkspaceIterator *>(iterators[it].get());
330
331 // Iterate over the output workspace
332 do {
333
334 const auto sourceIndex = outIt->getLinearIndex();
335
336 // Figure out the linear index in the data.
337 const size_t targetIndex = linearIndexToLinearIndex(nDimsShape, shapeReplicationIndex, indexMaxShape,
338 indexMakerShape, sourceIndex, indexMakerData, nDimsData);
339
340 // Copy the data across
341 outputWS->setSignalAt(sourceIndex, transposedDataWS->getSignalAt(targetIndex));
342 outputWS->setErrorSquaredAt(sourceIndex, transposedDataWS->getErrorAt(targetIndex) *
343 transposedDataWS->getErrorAt(targetIndex));
344 outputWS->setNumEventsAt(sourceIndex, transposedDataWS->getNumEventsAt(targetIndex));
345 outputWS->setMDMaskAt(sourceIndex, transposedDataWS->getIsMaskedAt(targetIndex));
346 progress.report();
347
348 } while (outIt->next());
349
351 }
353
354 this->setProperty("OutputWorkspace", outputWS);
355}
356
357} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#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...
Definition: MultiThreaded.h:94
#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.
Definition: Algorithm.cpp:1913
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
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
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.
Definition: MDGeometry.cpp:161
size_t getDimensionIndexById(const std::string &id) const
Get the index of the dimension that matches the ID given.
Definition: MDGeometry.cpp:224
virtual std::shared_ptr< const Mantid::Geometry::IMDDimension > getDimensionWithId(std::string id) const
Get a dimension.
Definition: MDGeometry.cpp:172
virtual size_t getNumDims() const
Definition: MDGeometry.cpp:148
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...
Definition: IMDDimension.h:39
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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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< const Mantid::DataObjects::MDHistoWorkspace > transposeMD(std::shared_ptr< Mantid::DataObjects::MDHistoWorkspace > &toTranspose, const std::vector< int > &axes)
Transpose the input data workspace according to the axis provided.
std::shared_ptr< Mantid::DataObjects::MDHistoWorkspace > getShapeWorkspace() const
fetches and down casts
int version() const override
Algorithm's version for identification.
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.
Definition: IMDDimension.h:101
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
size_t GetLinearIndex(const size_t numDims, size_t *index, size_t *index_maker)
Return a linear index from dimensional indices of a nested for loop.
Definition: Utils.h:125
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