Mantid
Loading...
Searching...
No Matches
SliceMD.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 +
17
18using namespace Mantid::Kernel;
19using namespace Mantid::API;
20using namespace Mantid::Geometry;
21using namespace Mantid::DataObjects;
22
23namespace Mantid::MDAlgorithms {
24
25// Register the algorithm into the AlgorithmFactory
26DECLARE_ALGORITHM(SliceMD)
27
28//----------------------------------------------------------------------------------------------
31void SliceMD::init() {
32 declareProperty(std::make_unique<WorkspaceProperty<IMDWorkspace>>("InputWorkspace", "", Direction::Input),
33 "An input MDWorkspace.");
34
35 // Properties for specifying the slice to perform.
36 this->initSlicingProps();
37
38 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
39 "Name of the output MDEventWorkspace.");
40
41 declareProperty(std::make_unique<FileProperty>("OutputFilename", "", FileProperty::OptionalSave, ".nxs"),
42 "Optional: Specify a NeXus file to write if you want the output "
43 "workspace to be file-backed.");
44
45 declareProperty(std::make_unique<PropertyWithValue<int>>("Memory", -1),
46 "If OutputFilename is specified to use a file back end:\n"
47 " The amount of memory (in MB) to allocate to the in-memory cache.\n"
48 " If not specified, a default of 40% of free physical memory is used.");
49
50 declareProperty("TakeMaxRecursionDepthFromInput", true, "Copy the maximum recursion depth from the input workspace.");
51
52 auto mustBePositiveInteger = std::make_shared<BoundedValidator<int>>();
53 mustBePositiveInteger->setLower(0);
54
55 declareProperty("MaxRecursionDepth", 1000, mustBePositiveInteger,
56 "Sets the maximum recursion depth to use. Can be used to "
57 "constrain the workspaces internal structure");
58 setPropertySettings("MaxRecursionDepth",
59 std::make_unique<EnabledWhenProperty>("TakeMaxRecursionDepthFromInput", IS_EQUAL_TO, "0"));
60
61 setPropertyGroup("OutputFilename", "File Back-End");
62 setPropertyGroup("Memory", "File Back-End");
63}
64
65//----------------------------------------------------------------------------------------------
73template <size_t nd, size_t ond> inline void copyEvent(const MDLeanEvent<nd> &srcEvent, MDLeanEvent<ond> &newEvent) {
74 // Nothing extra copy - this is no-op
75 UNUSED_ARG(srcEvent);
76 UNUSED_ARG(newEvent);
77}
78
79//----------------------------------------------------------------------------------------------
87template <size_t nd, size_t ond> inline void copyEvent(const MDEvent<nd> &srcEvent, MDEvent<ond> &newEvent) {
88 newEvent.setDetectorId(srcEvent.getDetectorID());
89 newEvent.setExpInfoIndex(srcEvent.getExpInfoIndex());
90}
91
92//----------------------------------------------------------------------------------------------
99template <typename MDE, size_t nd, typename OMDE, size_t ond>
101 // Create the ouput workspace
103 for (auto &binDimension : m_binDimensions) {
104 outWS->addDimension(binDimension);
105 }
107 outWS->initialize();
108 // Copy settings from the original box controller
110
111 // store wrute buffer size for the future
112 // uint64_t writeBufSize =
113 // bc->getFileIO()getDiskBuffer().getWriteBufferSize();
114 // and disable write buffer (if any) for input MD Events for this algorithm
115 // purposes;
116 // bc->setCacheParameters(1,0);
117
119 // Use the "number of bins" as the "split into" parameter for the top level
120 for (size_t od = 0; od < m_binDimensions.size(); od++) {
121 obc->setSplitTopInto(od, m_binDimensions[od]->getNBins());
122 obc->setSplitInto(od, bc->getSplitInto(od));
123 }
124 obc->setSplitThreshold(bc->getSplitThreshold());
125
126 bool bTakeDepthFromInputWorkspace = getProperty("TakeMaxRecursionDepthFromInput");
127 int tempDepth = getProperty("MaxRecursionDepth");
128 size_t maxDepth = bTakeDepthFromInputWorkspace ? bc->getMaxDepth() : size_t(tempDepth);
129 obc->setMaxDepth(maxDepth);
130
131 // size_t outputSize = writeBufSize;
132 // obc->setCacheParameters(sizeof(OMDE),outputSize);
133
134 obc->resetNumBoxes();
135 // Perform the first box splitting
136 outWS->splitBox();
137 size_t lastNumBoxes = obc->getTotalNumMDBoxes();
138
139 // --- File back end ? ----------------
140 std::string filename = getProperty("OutputFilename");
141 if (!filename.empty()) {
142
143 // First save to the NXS file
144 g_log.notice() << "Running SaveMD to create file back-end\n";
145 auto alg = createChildAlgorithm("SaveMD");
146 alg->setPropertyValue("Filename", filename);
147 alg->setProperty("InputWorkspace", outWS);
148 alg->setProperty("MakeFileBacked", true);
149 alg->executeAsChildAlg();
150
151 if (!obc->isFileBacked())
152 throw std::runtime_error("SliceMD with file-backed output: Can not set "
153 "up file-backed output workspace ");
154
155 auto IOptr = obc->getFileIO();
156 size_t outBufSize = IOptr->getWriteBufferSize();
157 // the buffer size for resulting workspace; reasonable size is at least 10
158 // data chunk sizes (nice to verify)
159 if (outBufSize < 10 * IOptr->getDataChunk()) {
160 outBufSize = 10 * IOptr->getDataChunk();
161 IOptr->setWriteBufferSize(outBufSize);
162 }
163 }
164
165 // Function defining which events (in the input dimensions) to place in the
166 // output
167 auto function = this->getImplicitFunctionForChunk(nullptr, nullptr);
168
169 std::vector<API::IMDNode *> boxes;
170 // Leaf-only; no depth limit; with the implicit function passed to it.
171 ws->getBox()->getBoxes(boxes, 1000, true, function.get());
172 // Sort boxes by file position IF file backed. This reduces seeking time,
173 // hopefully.
174 bool fileBackedWS = bc->isFileBacked();
175 if (fileBackedWS)
177
178 auto prog = std::make_unique<Progress>(this, 0.0, 1.0, boxes.size());
179
180 // The root of the output workspace
181 MDBoxBase<OMDE, ond> *outRootBox = outWS->getBox();
182
183 // if target workspace has events, we should count them as added
184 uint64_t totalAdded = outWS->getNEvents();
185 uint64_t numSinceSplit = 0;
186
187 // Go through every box for this chunk.
188 // PARALLEL_FOR_IF( !bc->isFileBacked() )
189 for (int i = 0; i < int(boxes.size()); i++) {
190 auto *box = dynamic_cast<MDBox<MDE, nd> *>(boxes[i]);
191 // Perform the binning in this separate method.
192 if (box && !box->getIsMasked()) {
193 // An array to hold the rotated/transformed coordinates
194 coord_t outCenter[ond];
195
196 const std::vector<MDE> &events = box->getConstEvents();
197
198 for (auto it = events.cbegin(); it != events.cend(); ++it) {
199 // Cache the center of the event (again for speed)
200 const coord_t *inCenter = it->getCenter();
201
202 if (function->isPointContained(inCenter)) {
203 // Now transform to the output dimensions
204 m_transformFromOriginal->apply(inCenter, outCenter);
205
206 // Create the event
207 OMDE newEvent(it->getSignal(), it->getErrorSquared(), outCenter);
208 // Copy extra data, if any
209 copyEvent(*it, newEvent);
210 // Add it to the workspace
211 if (outRootBox->addEvent(newEvent))
212 numSinceSplit++;
213 }
214 }
215 box->releaseEvents();
216
217 // Ask BC if one needs to split boxes
218 if (obc->shouldSplitBoxes(totalAdded, numSinceSplit, lastNumBoxes))
219 // if (numSinceSplit > 20000000 || (i == int(boxes.size()-1)))
220 {
221 // This splits up all the boxes according to split thresholds and sizes.
223 ThreadPool tp(ts);
224 outWS->splitAllIfNeeded(ts);
225 tp.joinAll();
226 // Accumulate stats
227 totalAdded += numSinceSplit;
228 numSinceSplit = 0;
229 lastNumBoxes = obc->getTotalNumMDBoxes();
230 // Progress reporting
231 if (!fileBackedWS)
232 prog->report(i);
233 }
234 if (fileBackedWS) {
235 if (!(i % 10))
236 prog->report(i);
237 }
238 } // is box
239
240 } // for each box in the vector
241 prog->report();
242
243 outWS->splitAllIfNeeded(nullptr);
244 // Refresh all cache.
245 outWS->refreshCache();
246
247 // Account for events that were added after the last split
248 totalAdded += numSinceSplit;
249 g_log.notice() << totalAdded << " " << OMDE::getTypeName() << "s added to the output workspace.\n";
250
251 if (outWS->isFileBacked()) {
252 // Update the file-back-end
253 g_log.notice() << "Running SaveMD\n";
254 auto alg = createChildAlgorithm("SaveMD");
255 alg->setProperty("UpdateFileBackEnd", true);
256 alg->setProperty("InputWorkspace", outWS);
257 alg->executeAsChildAlg();
258 }
259
260 try {
261 outWS->copyExperimentInfos(*ws);
262 } catch (std::runtime_error &) {
263 g_log.warning() << this->name() << " was not able to copy experiment info to output workspace " << outWS->getName()
264 << '\n';
265 }
266
267 // Pass on the display normalization from the input event workspace to the
268 // output event workspace
269 IMDEventWorkspace_sptr outEvent = std::dynamic_pointer_cast<IMDEventWorkspace>(outWS);
270 outEvent->setDisplayNormalization(ws->displayNormalization());
271 outEvent->setDisplayNormalizationHisto(ws->displayNormalizationHisto());
272 // return the size of the input workspace write buffer to its initial value
273 // bc->setCacheParameters(sizeof(MDE),writeBufSize);
274 this->setProperty("OutputWorkspace", outEvent);
275}
276
277//----------------------------------------------------------------------------------------------
279template <typename MDE, size_t nd> void SliceMD::doExec(typename MDEventWorkspace<MDE, nd>::sptr ws) {
280 if (m_outD == 0)
281 throw std::runtime_error("No output dimensions specified!");
282
283 // Templated method needs to call another templated method depending on the #
284 // of output dimensions.
285 if (MDE::getTypeName() == "MDLeanEvent") {
286 if (m_outD == 1)
287 this->slice<MDE, nd, MDLeanEvent<1>, 1>(ws);
288 else if (m_outD == 2)
289 this->slice<MDE, nd, MDLeanEvent<2>, 2>(ws);
290 else if (m_outD == 3)
291 this->slice<MDE, nd, MDLeanEvent<3>, 3>(ws);
292 else if (m_outD == 4)
293 this->slice<MDE, nd, MDLeanEvent<4>, 4>(ws);
294 else
295 throw std::runtime_error("Number of output dimensions > 4. This is not currently handled.");
296 } else if (MDE::getTypeName() == "MDEvent") {
297 if (m_outD == 1)
298 this->slice<MDE, nd, MDEvent<1>, 1>(ws);
299 else if (m_outD == 2)
300 this->slice<MDE, nd, MDEvent<2>, 2>(ws);
301 else if (m_outD == 3)
302 this->slice<MDE, nd, MDEvent<3>, 3>(ws);
303 else if (m_outD == 4)
304 this->slice<MDE, nd, MDEvent<4>, 4>(ws);
305 else
306 throw std::runtime_error("Number of output dimensions > 4. This is not currently handled.");
307 } else
308 throw std::runtime_error("Unexpected MDEvent type '" + MDE::getTypeName() + "'. This is not currently handled.");
309}
310
311//----------------------------------------------------------------------------------------------
315 // Input MDEventWorkspace
316 m_inWS = getProperty("InputWorkspace");
317
318 // Run through the properties to create the transform you need
320
322}
323
324} // 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 UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
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
Kernel::Logger & g_log
Definition: Algorithm.h:451
@ OptionalSave
to specify a file to write to but an empty string is
Definition: FileProperty.h:50
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
void addDimension(const std::shared_ptr< Mantid::Geometry::IMDDimension > &dim)
Add a dimension.
Definition: MDGeometry.cpp:234
void copyExperimentInfos(const MultipleExperimentInfos &other)
Copy the experiment infos from another.
A property class for workspaces.
const std::string & getName() const override
Get the workspace name.
Definition: Workspace.cpp:58
Templated super-class of a multi-dimensional event "box".
Definition: MDBoxBase.h:50
virtual size_t addEvent(const MDE &point)=0
Add a single event.
Templated class for a multi-dimensional event "box".
Definition: MDBox.h:45
const std::vector< MDE > & getConstEvents() const
Get vector of constant events to use.
Templated class for the multi-dimensional event workspace.
Mantid::API::MDNormalization displayNormalization() const override
void splitBox() override
Split the top-level MDBox into a MDGridBox.
std::shared_ptr< MDEventWorkspace< MDE, nd > > sptr
Typedef for a shared pointer of this kind of event workspace.
void splitAllIfNeeded(Kernel::ThreadScheduler *ts) override
Split all boxes that exceed the split threshold.
void setCoordinateSystem(const Kernel::SpecialCoordinateSystem coordSystem) override
Set the coordinate system.
Mantid::API::MDNormalization displayNormalizationHisto() const override
Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const override
Get the coordinate system.
void refreshCache() override
Refresh the cache (integrated signal of each box)
void initialize() override
Perform initialization after dimensions (and others) have been set.
Mantid::API::BoxController_sptr getBoxController() override
Returns the BoxController used in this workspace.
uint64_t getNEvents() const override
Templated class holding data about a neutron detection event in N-dimensions (for example,...
Definition: MDEvent.h:36
uint16_t getExpInfoIndex() const
Definition: MDEvent.h:175
void setDetectorId(int32_t id)
Sets the detectorId of this event.
Definition: MDEvent.h:195
void setExpInfoIndex(uint16_t index)
Sets the expInfoIndex of this event.
Definition: MDEvent.h:179
int32_t getDetectorID() const
Definition: MDEvent.h:191
Templated class holding data about a neutron detection event in N-dimensions (for example,...
Definition: MDLeanEvent.h:60
static std::string getTypeName()
Definition: MDLeanEvent.h:305
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
The concrete, templated class for properties.
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.
Algorithm that can take a slice out of an original MDEventWorkspace while preserving all the events c...
Definition: SliceMD.h:22
const std::string name() const override
Algorithm's name for identification.
Definition: SliceMD.h:34
void exec() override
Run the algorithm.
Definition: SliceMD.cpp:314
void slice(typename DataObjects::MDEventWorkspace< MDE, nd >::sptr ws)
Method to actually do the slice.
Definition: SliceMD.cpp:100
void doExec(typename DataObjects::MDEventWorkspace< MDE, nd >::sptr ws)
Helper method.
Definition: SliceMD.cpp:279
std::unique_ptr< API::CoordTransform > m_transformFromOriginal
Coordinate transformation to save in the output workspace (original->binned)
std::unique_ptr< Mantid::Geometry::MDImplicitFunction > getImplicitFunctionForChunk(const size_t *const chunkMin, const size_t *const chunkMax)
Create an implicit function for picking boxes, based on the indexes in the output MDHistoWorkspace.
void createTransform()
Read the algorithm properties and creates the appropriate transforms for slicing the MDEventWorkspace...
Mantid::API::IMDWorkspace_sptr m_inWS
Input workspace.
size_t m_outD
Number of dimensions in the output (binned) workspace.
std::vector< Mantid::Geometry::MDHistoDimension_sptr > m_binDimensions
Bin dimensions to actually use.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
void copyEvent(const MDLeanEvent< nd > &srcEvent, MDLeanEvent< ond > &newEvent, const uint16_t expInfoIndexOffset)
Copy the extra data (not signal, error or coordinates) from one event to another with different numbe...
Definition: MergeMD.cpp:161
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition: MDTypes.h:27
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54