37#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 4 || (__GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ > 0)))
42namespace DataObjects {
45Kernel::Logger logger(
"MDEventWorkspace");
55 m_displayNormalization(preferredNormalization), m_displayNormalizationHisto(preferredNormalizationHisto),
56 m_coordSystem(Kernel::
None) {
58 data = std::make_unique<MDBox<MDE, nd>>(m_BoxController.get(), 0);
65 :
IMDEventWorkspace(other), m_BoxController(other.m_BoxController->clone()), data(),
66 m_displayNormalization(other.m_displayNormalization),
67 m_displayNormalizationHisto(other.m_displayNormalizationHisto), m_coordSystem(other.m_coordSystem) {
72 data = std::make_unique<MDBox<MDE, nd>>(*mdbox, m_BoxController.get());
73 }
else if (mdgridbox) {
74 data = std::make_unique<MDGridBox<MDE, nd>>(*mdgridbox, m_BoxController.get());
76 throw std::runtime_error(
"MDEventWorkspace::copy_ctor(): unexpected data box type found.");
101 if (m_BoxController->isFileBacked()) {
102 data->clearFileBacked(LoadFileBackedData);
103 m_BoxController->clearFileBacked();
111 if (m_dimensions.size() != nd)
112 throw std::runtime_error(
"MDEventWorkspace::initialize() called with an "
113 "incorrect number of m_dimensions set. Use "
114 "addDimension() first to add the right number of "
115 "dimension info objects.");
117 throw std::runtime_error(
"MDEventWorkspace::initialize() called on a "
118 "MDEventWorkspace containing a MDGridBox. You "
119 "should call initialize() before adding any "
121 double minSize[nd], maxSize[nd];
122 for (
size_t d = 0;
d < nd;
d++) {
123 minSize[
d] = m_dimensions[
d]->getMinimum();
124 maxSize[
d] = m_dimensions[
d]->getMaximum();
126 data->setExtents(minSize, maxSize);
132 std::ostringstream out;
133 out <<
"MDEventWorkspace<" << MDE::getTypeName() <<
"," << getNumDims() <<
">";
167 double numBoxes = pow(
double(bc->getNumSplit()),
double(minDepth));
168 double memoryToUse = numBoxes * double(
sizeof(
MDBox<MDE, nd>)) / 1024.0;
170 if (
double(stats.
availMem()) < memoryToUse) {
171 std::ostringstream mess;
172 mess <<
"Not enough memory available for the given MinRecursionDepth! "
173 <<
"MinRecursionDepth is set to " << minDepth <<
", which would create " << numBoxes <<
" boxes using "
174 << memoryToUse <<
" kB of memory."
175 <<
" You have " << stats.
availMem() <<
" kB available.\n";
176 throw std::runtime_error(mess.str());
179 for (
size_t depth = 1; depth < minDepth; depth++) {
181 std::vector<API::IMDNode *> boxes;
183 this->getBox()->getBoxes(boxes, depth - 1,
false);
184 for (
const auto box : boxes) {
198 size_t realDepth = 0;
199 std::vector<size_t> numMD = m_BoxController->getNumMDBoxes();
200 for (
size_t i = 0; i < numMD.size(); i++)
204 auto splitTop = m_BoxController->getSplitTopInto();
205 std::vector<coord_t> out;
206 for (
size_t d = 0;
d < nd;
d++) {
207 size_t finestSplit = 1;
210 finestSplit *= splitTop.value()[
d];
213 for (; i < realDepth; i++)
214 finestSplit *= m_BoxController->getSplitInto(
d);
217 out.emplace_back((dim->getMaximum() - dim->getMinimum()) /
static_cast<coord_t>(finestSplit));
234 this->data->
getBoxes(boxes, 10000,
true, function);
236 this->data->getBoxes(boxes, 10000,
true);
239 size_t numCores = suggestedNumCores;
242 size_t numElements = boxes.size();
243 if (numCores > numElements)
244 numCores = numElements;
249 std::vector<std::unique_ptr<API::IMDIterator>> out;
250 for (
size_t i = 0; i < numCores; i++) {
251 size_t begin = (i * numElements) / numCores;
252 size_t end = ((i + 1) * numElements) / numCores;
253 if (end > numElements)
270 if (!isInBounds(coords)) {
271 return std::numeric_limits<signal_t>::quiet_NaN();
275 return getNormalizedSignal(box, normalization);
282 switch (normalization) {
283 case API::NoNormalization:
285 case API::VolumeNormalization:
287 case API::NumEventsNormalization:
293 return std::numeric_limits<signal_t>::quiet_NaN();
300 switch (normalization) {
302 return box->getError();
304 return box->getError() * box->getInverseVolume();
306 return box->getError() /
static_cast<double>(box->getNPoints());
308 return box->getError();
311 return std::numeric_limits<signal_t>::quiet_NaN();
315 for (size_t
d = 0;
d < nd;
d++) {
317 if (data->getExtents(
d).outside(
x))
334 if (!isInBounds(coords)) {
335 return std::numeric_limits<signal_t>::quiet_NaN();
340 return API::MDMaskValue;
342 return API::MDMaskValue;
344 return getNormalizedSignal(box, normalization);
360 size_t depth) const {
362 std::vector<API::IMDNode *> boxes;
364 this->data->getBoxes(boxes, depth,
true);
365 auto it = boxes.begin();
366 auto it_end = boxes.end();
367 for (; it != it_end; ++it) {
370 for (
size_t d = 0;
d < nd;
d++)
376 for (
size_t d = 0;
d < nd;
d++) {
377 if (out[d].isUndefined())
378 out[
d].setExtents(this->getDimension(d)->getMinimum(), this->getDimension(d)->getMaximum());
387 std::vector<
std::string> out;
388 std::ostringstream mess;
391 mem = (this->m_BoxController->getTotalNumMDBoxes() *
sizeof(
MDBox<MDE, nd>)) / 1024;
392 mess << m_BoxController->getTotalNumMDBoxes() <<
" MDBoxes (" << mem <<
" kB)";
393 out.emplace_back(mess.str());
396 mem = (this->m_BoxController->getTotalNumMDGridBoxes() *
sizeof(
MDGridBox<MDE, nd>)) / 1024;
397 mess << m_BoxController->getTotalNumMDGridBoxes() <<
" MDGridBoxes (" << mem <<
" kB)";
398 out.emplace_back(mess.str());
417 if (m_BoxController->isFileBacked()) {
418 mess <<
"File backed: ";
419 double avail = double(m_BoxController->getFileIO()->getWriteBufferSize() *
sizeof(MDE)) / (1024 * 1024);
420 double used = double(m_BoxController->getFileIO()->getWriteBufferUsed() *
sizeof(MDE)) / (1024 * 1024);
421 mess <<
"Write buffer: " << used <<
" of " << avail <<
" MB. ";
422 out.emplace_back(mess.str());
426 if (this->fileNeedsUpdating())
427 mess <<
" (needs updating)";
429 mess <<
": " << this->m_BoxController->getFileIO()->getFileName();
430 out.emplace_back(mess.str());
433 mess <<
"Not file backed.";
434 out.emplace_back(mess.str());
443template <
typename BOXTYPE>
bool SortBoxesByID(
const BOXTYPE &a,
const BOXTYPE &b) {
return a->getID() < b->getID(); }
453 std::vector<API::IMDNode *> boxes;
454 std::vector<MDBoxBase<MDE, nd> *> boxes_filtered;
455 this->getBox()->getBoxes(boxes, 1000,
false);
456 boxes_filtered.reserve(boxes.size());
458 std::transform(boxes.cbegin(), boxes.cend(), std::back_inserter(boxes_filtered),
459 [](
const auto box) { return dynamic_cast<MDBoxBase<MDE, nd> *>(box); });
463 std::sort(boxes_filtered.begin(), boxes_filtered.end(), SortBoxesByID<ibox_t>);
466 int numRows = int(boxes_filtered.size());
468 ws->addColumn(
"int",
"ID");
469 ws->addColumn(
"int",
"Depth");
470 ws->addColumn(
"int",
"# children");
471 ws->addColumn(
"int",
"File Pos.");
472 ws->addColumn(
"int",
"File Size");
473 ws->addColumn(
"int",
"EventVec Size");
474 ws->addColumn(
"str",
"OnDisk?");
475 ws->addColumn(
"str",
"InMemory?");
476 ws->addColumn(
"str",
"Changes?");
477 ws->addColumn(
"str",
"Extents");
479 for (
int i = 0; i < int(boxes_filtered.size()); i++) {
483 ws->cell<
int>(i, col++) =
int(box->
getID());
485 ws->cell<
int>(i, col++) =
int(box->
getDepth());
491 ws->cell<
int>(i, col++) = pSaver ?
int(pSaver->getFilePosition()) : -1;
492 ws->cell<
int>(i, col++) = pSaver ?
int(pSaver->getFileSize()) : 0;
493 ws->cell<
int>(i, col++) = mdbox ?
int(mdbox->getDataInMemorySize()) : -1;
494 if (mdbox && pSaver) {
495 ws->cell<std::string>(i, col++) = (pSaver->wasSaved() ?
"yes" :
"no");
496 ws->cell<std::string>(i, col++) = (pSaver->isLoaded() ?
"yes" :
"no");
498 bool isDataAdded = (mdbox->isDataAdded());
499 ws->cell<std::string>(i, col++) =
500 std::string(isDataAdded ?
"Added " :
"") + std::string(pSaver->isBusy() ?
"Modif." :
"");
502 ws->cell<std::string>(i, col++) = (pSaver ?
"-" :
"NA");
503 ws->cell<std::string>(i, col++) = (pSaver ?
"-" :
"NA");
504 ws->cell<std::string>(i, col++) = (pSaver ?
"-" :
"NA");
508 logger.information() << tim <<
" to create the MDBox data table.\n";
516 if (this->m_BoxController->isFileBacked()) {
519 total = this->m_BoxController->getFileIO()->getWriteBufferUsed() *
sizeof(MDE);
522 total = this->getNPoints() *
sizeof(MDE);
525 total += this->m_BoxController->getTotalNumMDBoxes() *
sizeof(
MDBox<MDE, nd>);
526 total += this->m_BoxController->getTotalNumMDGridBoxes() *
sizeof(
MDGridBox<MDE, nd>);
557 this->m_BoxController->trackNumBoxes(data->getDepth());
560 throw std::runtime_error(
"MDEventWorkspace::splitBox() expected its data "
561 "to be a MDBox* to split to MDGridBox.");
562 auto tempGridBox = std::make_unique<MDGridBox<MDE, nd>>(box);
564 data = std::move(tempGridBox);
585 throw std::runtime_error(
"Not implemented yet");
611 data->refreshCache();
636 std::vector<coord_t> smallest_box_sizes = this->estimateResolution();
640 for (
size_t d = 0;
d < num_d;
d++) {
641 auto line_start = start[
d];
642 auto line_end = end[
d];
643 auto box_size = smallest_box_sizes[
d];
644 auto dir_current_dim = dir[
d];
647 size_t num_boundaries =
static_cast<size_t>(ceil(std::abs(line_end - line_start) / box_size)) + 1;
651 if (dir_current_dim != 0.0) {
652 getBoundariesInDimension(start, dir, num_boundaries, length, dir_current_dim, box_size, mid_points);
673 const size_t num_boundaries, const
coord_t length,
676 auto lastPos = start;
679 coord_t line_pos_of_box_centre = 0;
681 auto last_id = std::numeric_limits<size_t>::max();
683 for (
size_t i = 1; i <= num_boundaries; i++) {
684 size_t current_id = std::numeric_limits<size_t>::max();
687 auto linePos =
static_cast<coord_t>(this_x /
fabs(dir_current_dim));
689 auto pos = start + (dir * linePos);
692 auto middle = (pos + lastPos) * 0.5;
695 if (box !=
nullptr) {
696 current_id = box->
getID();
698 }
else if (i == num_boundaries) {
699 current_id = std::numeric_limits<size_t>::max();
705 if ((current_id != last_id && i != 1)) {
708 if (line_pos_of_box_centre >= 0 && line_pos_of_box_centre <= length &&
fabs(linePos - lastLinePos) > 1e-5) {
709 mid_points.insert(line_pos_of_box_centre);
711 lastLinePos = previousLinePos;
713 line_pos_of_box_centre =
static_cast<coord_t>((linePos + lastLinePos) * 0.5);
714 previousLinePos = linePos;
716 last_id = current_id;
732 auto num_dims = this->getNumDims();
733 if (start.getNumDims() != num_dims)
734 throw std::runtime_error(
"Start point must have the same number of "
735 "dimensions as the workspace.");
736 if (end.getNumDims() != num_dims)
737 throw std::runtime_error(
"End point must have the same number of dimensions as the workspace.");
743 const std::set<coord_t> mid_points = getBoxBoundaryBisectsOnLine(start, end, num_dims, dir, length);
747 if (mid_points.empty()) {
748 makeSinglePointWithNaN(line.
x, line.
y, line.
e);
752 for (
const auto &line_pos : mid_points) {
761 line.
x.emplace_back(line_pos);
762 signal_t signal = this->getNormalizedSignal(box, normalize);
763 if (std::isinf(signal)) {
765 signal = std::numeric_limits<signal_t>::quiet_NaN();
767 line.
y.emplace_back(signal);
768 line.
e.emplace_back(this->getNormalizedError(box, normalize));
775 if (line.
x.empty()) {
776 makeSinglePointWithNaN(line.
x, line.
y, line.
e);
787 std::vector<API::IMDNode *> toMaskBoxes;
790 this->data->getBoxes(toMaskBoxes, 10000,
true, maskingRegion.get());
791 for (
const auto box : toMaskBoxes) {
803 std::vector<API::IMDNode *> allBoxes;
805 this->data->getBoxes(allBoxes, 10000,
true);
806 for (
const auto box : allBoxes) {
817 auto coordinatesFromMDFrames = converter(
this);
818 auto coordinates = m_coordSystem;
820 if (coordinatesFromMDFrames) {
821 coordinates = coordinatesFromMDFrames.value();
831 m_coordSystem = coordSystem;
840 m_displayNormalizationHisto = preferredNormalizationHisto;
853 m_displayNormalization = preferredNormalization;
#define TMDE(decl)
Macro TMDE to make declaring template functions faster.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
This class is used by MDBox and MDGridBox in order to intelligently determine optimal behavior.
Abstract base class for multi-dimension event workspaces (MDEventWorkspace).
virtual void clear()=0
Clear all contained data including precalculated averages.
virtual void mask()=0
Setter for masking the box.
virtual void getBoxes(std::vector< IMDNode * > &boxes, size_t maxDepth, bool leafOnly)=0
Fill a vector with all the boxes who are the childred of this one up to a certain depth.
virtual size_t getNumChildren() const =0
Get the # of children MDBoxBase'es (non-recursive)
virtual coord_t getInverseVolume() const =0
virtual bool getIsMasked() const =0
Getter for the masking.
virtual size_t getID() const =0
virtual uint64_t getNPoints() const =0
Get total number of points both in memory and on file if present;.
virtual void clearFileBacked(bool loadFileData)=0
if node was fileBacked, the method clears file-backed information
virtual void unmask()=0
Setter for unmasking the box.
virtual Mantid::Geometry::MDDimensionExtents< coord_t > & getExtents(size_t dim)=0
virtual Kernel::ISaveable * getISaveable()=0
Return the pointer to the structure responsible for saving the box on disk if the workspace occupies ...
virtual const IMDNode * getBoxAtCoord(const coord_t *)=0
virtual signal_t getSignal() const =0
Templated super-class of a multi-dimensional event "box".
std::string getExtentsStr() const
Returns the extents as a string, for convenience.
uint32_t getDepth() const override
For testing, mostly: return the recursion depth of this box.
size_t getID() const override
MDBoxIterator: iterate through MDBoxBase hierarchy down to a given maximum depth.
Templated class for a multi-dimensional event "box".
Templated class for the multi-dimensional event workspace.
MDFrameFromMDWorkspace: Each dimension of the MDWorkspace contains an MDFrame.
Templated class for a GRIDDED multi-dimensional event "box".
size_t getNumChildren() const override
void splitContents(size_t index, Kernel::ThreadScheduler *ts=nullptr)
Split a box that is contained in the GridBox, at the given index, into a MDGridBox.
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
Simple class that holds the extents (min/max) of a given dimension in a MD workspace or MDBox.
void expand(MDDimensionExtents &other)
An "ImplicitFunction" defining a hyper-cuboid-shaped region in N dimensions.
CPUTimer : Timer that uses the CPU time, rather than wall-clock time to measure execution time.
Marks code as not implemented yet.
An interface for objects that can be cached or saved to disk.
This class is responsible for memory statistics.
std::size_t availMem() const
Returns the available memory of the system in kiB.
The ThreadScheduler object defines how tasks are allocated to threads and in what order.
TYPE normalize()
Normalize this vector to unity length.
const TYPE * getBareArray() const
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
MDNormalization
Enum describing different ways to normalize the signal in a MDWorkspace.
@ VolumeNormalization
Divide the signal by the volume of the box/bin.
@ NumEventsNormalization
Divide the signal by the number of events that contributed to it.
@ NoNormalization
Don't normalize = return raw counts.
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
bool SortBoxesByID(const BOXTYPE &a, const BOXTYPE &b)
Comparator for sorting MDBoxBase'es by ID.
std::shared_ptr< const IMDDimension > IMDDimension_const_sptr
Shared Pointer to const IMDDimension.
SpecialCoordinateSystem
Special coordinate systems for Q3D.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Helper class which provides the Collimation Length for SANS instruments.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
double signal_t
Typedef for the signal recorded in a MDBox, etc.
Holds X, Y, E for a line plot.
std::vector< signal_t > y
std::vector< signal_t > e