Mantid
Loading...
Searching...
No Matches
TransformMD.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 +
15#include "MantidKernel/System.h"
16
17using namespace Mantid::Kernel;
18using namespace Mantid::API;
19using namespace Mantid::DataObjects;
21
22namespace Mantid::MDAlgorithms {
23
24// Register the algorithm into the AlgorithmFactory
25DECLARE_ALGORITHM(TransformMD)
26
27//----------------------------------------------------------------------------------------------
29const std::string TransformMD::name() const { return "TransformMD"; }
30
32int TransformMD::version() const { return 1; }
33
35const std::string TransformMD::category() const { return "MDAlgorithms\\Transforms"; }
36
37//----------------------------------------------------------------------------------------------
38
39//----------------------------------------------------------------------------------------------
43 declareProperty(std::make_unique<WorkspaceProperty<IMDWorkspace>>("InputWorkspace", "", Direction::Input),
44 "Any input MDWorkspace.");
45
46 std::vector<double> defaultScaling(1, 1.0);
47 declareProperty(std::make_unique<ArrayProperty<double>>("Scaling", std::move(defaultScaling)),
48 "Scaling value multiplying each coordinate. Default "
49 "1.\nEither a single value or a list for each dimension.");
50
51 std::vector<double> defaultOffset(1, 0.0);
52 declareProperty(std::make_unique<ArrayProperty<double>>("Offset", std::move(defaultOffset)),
53 "Offset value to add to each coordinate. Default 0.\nEither "
54 "a single value or a list for each dimension.");
55
56 declareProperty(std::make_unique<WorkspaceProperty<IMDWorkspace>>("OutputWorkspace", "", Direction::Output),
57 "Name of the output MDWorkspace.");
58}
59
60//----------------------------------------------------------------------------------------------
65template <typename MDE, size_t nd>
67 std::vector<API::IMDNode *> boxes;
68 // Get ALL the boxes, including MDGridBoxes.
69 ws->getBox()->getBoxes(boxes, 1000, false);
70
71 // If file backed, sort them first.
72 if (ws->isFileBacked())
74
76 for (int i = 0; i < static_cast<int>(boxes.size()); i++) { // NOLINT
78 auto *box = dynamic_cast<MDBoxBase<MDE, nd> *>(boxes[i]);
79 if (box) {
81 }
83 }
85}
86
87//----------------------------------------------------------------------------------------------
93void TransformMD::reverse(signal_t *array, size_t arrayLength) {
94 for (size_t i = 0; i < (arrayLength / 2); i++) {
95 signal_t temp = array[i];
96 array[i] = array[(arrayLength - 1) - i];
97 array[(arrayLength - 1) - i] = temp;
98 }
99}
100
101//----------------------------------------------------------------------------------------------
107
108 inWS = getProperty("InputWorkspace");
109 outWS = getProperty("OutputWorkspace");
110 std::string outName = getPropertyValue("OutputWorkspace");
111
112 if (std::dynamic_pointer_cast<MatrixWorkspace>(inWS))
113 throw std::runtime_error("TransformMD can only transform a "
114 "MDHistoWorkspace or a MDEventWorkspace.");
115
116 if (outWS != inWS) {
117 // NOT in-place. So first we clone inWS into outWS
118 auto clone = createChildAlgorithm("CloneMDWorkspace", 0.0, 0.5, true);
119 clone->setProperty("InputWorkspace", inWS);
120 clone->executeAsChildAlg();
121 outWS = clone->getProperty("OutputWorkspace");
122 }
123
124 if (!outWS)
125 throw std::runtime_error("Invalid output workspace.");
126
127 size_t nd = outWS->getNumDims();
128 m_scaling = getProperty("Scaling");
129 m_offset = getProperty("Offset");
130
131 // Replicate single values
132 if (m_scaling.size() == 1)
133 m_scaling = std::vector<double>(nd, m_scaling[0]);
134 if (m_offset.size() == 1)
135 m_offset = std::vector<double>(nd, m_offset[0]);
136
137 // Check the size
138 if (m_scaling.size() != nd)
139 throw std::invalid_argument("Scaling argument must be either length 1 or "
140 "match the number of dimensions.");
141 if (m_offset.size() != nd)
142 throw std::invalid_argument("Offset argument must be either length 1 or "
143 "match the number of dimensions.");
144
145 // Transform the dimensions
146 outWS->transformDimensions(m_scaling, m_offset);
147
148 MDHistoWorkspace_sptr histo = std::dynamic_pointer_cast<MDHistoWorkspace>(outWS);
149 IMDEventWorkspace_sptr event = std::dynamic_pointer_cast<IMDEventWorkspace>(outWS);
150
151 if (histo) {
152 // Recalculate all the values since the dimensions changed.
153 histo->cacheValues();
154 // Expect first 3 dimensions to be -1 for changing conventions
155 for (int i = 0; i < static_cast<int>(m_scaling.size()); i++)
156 if (m_scaling[i] < 0) {
157 std::vector<int> axes(m_scaling.size()); // vector with ints.
158 std::iota(std::begin(axes), std::end(axes), 0); // Fill with 0, 1, ...
159 axes[0] = i;
160 axes[i] = 0;
161 if (i > 0)
162 histo = transposeMD(histo, axes);
163 signal_t *signals = histo->mutableSignalArray();
164 signal_t *errorsSq = histo->mutableErrorSquaredArray();
165 signal_t *numEvents = histo->mutableNumEventsArray();
166
167 // Find the extents
168 size_t nPoints = static_cast<size_t>(histo->getDimension(0)->getNBins());
169 size_t mPoints = 1;
170 for (size_t k = 1; k < histo->getNumDims(); k++) {
171 mPoints *= static_cast<size_t>(histo->getDimension(k)->getNBins());
172 }
173 // other dimensions
174 for (size_t j = 0; j < mPoints; j++) {
175 this->reverse(signals + j * nPoints, nPoints);
176 this->reverse(errorsSq + j * nPoints, nPoints);
177 this->reverse(numEvents + j * nPoints, nPoints);
178 }
179
180 histo = transposeMD(histo, axes);
181 }
182
183 // Pass on the display normalization from the input workspace
184 histo->setDisplayNormalization(inWS->displayNormalizationHisto());
185
186 this->setProperty("OutputWorkspace", histo);
187 } else if (event) {
188 // Call the method for this type of MDEventWorkspace.
190 Progress *prog2 = nullptr;
192 ThreadPool tp(ts, 0, prog2);
193 event->splitAllIfNeeded(ts);
194 // prog2->resetNumSteps( ts->size(), 0.4, 0.6);
195 tp.joinAll();
196 event->refreshCache();
197 // Set the special coordinate system.
198 IMDEventWorkspace_sptr inEvent = std::dynamic_pointer_cast<IMDEventWorkspace>(inWS);
199 event->setCoordinateSystem(inEvent->getSpecialCoordinateSystem());
200
201 if (m_scaling[0] < 0) {
202 // Only need these 2 algorithms for transforming with negative number
203 std::vector<double> extents;
204 std::vector<std::string> names, units;
205 for (size_t d = 0; d < nd; d++) {
206 Geometry::IMDDimension_const_sptr dim = event->getDimension(d);
207 // Find the extents
208 extents.emplace_back(dim->getMinimum());
209 extents.emplace_back(dim->getMaximum());
210 names.emplace_back(std::string(dim->getName()));
211 units.emplace_back(dim->getUnits());
212 }
213 Algorithm_sptr create_alg = createChildAlgorithm("CreateMDWorkspace");
214 create_alg->setProperty("Dimensions", static_cast<int>(nd));
215 create_alg->setProperty("EventType", event->getEventTypeName());
216 create_alg->setProperty("Extents", extents);
217 create_alg->setProperty("Names", names);
218 create_alg->setProperty("Units", units);
219 create_alg->setPropertyValue("OutputWorkspace", "__none");
220 create_alg->executeAsChildAlg();
221 Workspace_sptr none = create_alg->getProperty("OutputWorkspace");
222
223 AnalysisDataService::Instance().addOrReplace(outName, event);
224 AnalysisDataService::Instance().addOrReplace("__none", none);
225 Mantid::API::BoxController_sptr boxController = event->getBoxController();
226 std::vector<int> splits;
227 for (size_t d = 0; d < nd; d++) {
228 splits.emplace_back(static_cast<int>(boxController->getSplitInto(d)));
229 }
230 Algorithm_sptr merge_alg = createChildAlgorithm("MergeMD");
231 merge_alg->setPropertyValue("InputWorkspaces", outName + ",__none");
232 merge_alg->setProperty("SplitInto", splits);
233 merge_alg->setProperty("SplitThreshold", static_cast<int>(boxController->getSplitThreshold()));
234 merge_alg->setProperty("MaxRecursionDepth", 13);
235 merge_alg->executeAsChildAlg();
236 event = merge_alg->getProperty("OutputWorkspace");
237 AnalysisDataService::Instance().remove("__none");
238 }
239 this->setProperty("OutputWorkspace", event);
240 }
241}
248MDHistoWorkspace_sptr TransformMD::transposeMD(MDHistoWorkspace_sptr &toTranspose, const std::vector<int> &axes) {
249
250 auto transposeMD = this->createChildAlgorithm("TransposeMD", 0.0, 0.5);
251 transposeMD->setProperty("InputWorkspace", toTranspose);
252 transposeMD->setProperty("Axes", axes);
253 transposeMD->execute();
254 IMDHistoWorkspace_sptr outputWS = transposeMD->getProperty("OutputWorkspace");
255 return std::dynamic_pointer_cast<MDHistoWorkspace>(outputWS);
256}
257
258} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
static std::unique_ptr< QThreadPool > tp
#define CALL_MDEVENT_FUNCTION(funcname, workspace)
Macro that makes it possible to call a templated method for a MDEventWorkspace using a IMDEventWorksp...
#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_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_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#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
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
static void sortObjByID(std::vector< IMDNode * > &boxes)
Static method for sorting a list of MDBoxBase pointers by their file position, ascending.
Definition: IMDNode.h:292
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
Templated super-class of a multi-dimensional event "box".
Definition: MDBoxBase.h:50
void transformDimensions(std::vector< double > &scaling, std::vector< double > &offset) override
std::shared_ptr< MDEventWorkspace< MDE, nd > > sptr
Typedef for a shared pointer of this kind of event workspace.
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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
A Thread Pool implementation that keeps a certain number of threads running (normally,...
Definition: ThreadPool.h:36
A First-In-First-Out Thread Scheduler.
The ThreadScheduler object defines how tasks are allocated to threads and in what order.
Scale and/or offset the coordinates of a MDWorkspace.
Definition: TransformMD.h:20
const std::string category() const override
Algorithm's category for identification.
Definition: TransformMD.cpp:35
std::vector< double > m_offset
Definition: TransformMD.h:39
void reverse(signal_t *array, size_t arrayLength)
Swap the array elements.
Definition: TransformMD.cpp:93
Mantid::DataObjects::MDHistoWorkspace_sptr transposeMD(Mantid::DataObjects::MDHistoWorkspace_sptr &toTranspose, const std::vector< int > &axes)
Transpose the input data workspace according to the axis provided.
void doTransform(typename Mantid::DataObjects::MDEventWorkspace< MDE, nd >::sptr ws)
Perform the transform on a MDEventWorkspace.
Definition: TransformMD.cpp:66
std::vector< double > m_scaling
Definition: TransformMD.h:38
int version() const override
Algorithm's version for identification.
Definition: TransformMD.cpp:32
void init() override
Initialize the algorithm's properties.
Definition: TransformMD.cpp:42
void exec() override
Execute the algorithm.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
std::shared_ptr< IMDHistoWorkspace > IMDHistoWorkspace_sptr
shared pointer to Mantid::API::IMDHistoWorkspace
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
Definition: IMDWorkspace.h:146
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition: Algorithm.h:61
std::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const NexusHDF5Descriptor &descriptor)
Get the number of events in the currently opened group.
std::shared_ptr< MDHistoWorkspace > MDHistoWorkspace_sptr
A shared pointer to a MDHistoWorkspace.
std::shared_ptr< const IMDDimension > IMDDimension_const_sptr
Shared Pointer to const IMDDimension.
Definition: IMDDimension.h:101
double signal_t
Typedef for the signal recorded in a MDBox, etc.
Definition: MDTypes.h:36
STL namespace.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54