Mantid
Loading...
Searching...
No Matches
MDGridBox.hxx
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 +
13#include "MantidKernel/Task.h"
17#include "MantidKernel/Timer.h"
18#include "MantidKernel/Utils.h"
20#include <boost/math/special_functions/round.hpp>
21#include <optional>
22#include <ostream>
23
24// These pragmas ignores the warning in the ctor where "d<nd-1" for nd=1.
25// This is okay (though would be better if it were for only that function
26#if (defined(__INTEL_COMPILER))
27#pragma warning disable 186
28#elif defined(__GNUC__)
29#pragma GCC diagnostic ignored "-Wtype-limits"
30#endif
31
32namespace Mantid {
33namespace DataObjects {
34
37
38//-----------------------------------------------------------------------------------------------
44TMDE(MDGridBox)::MDGridBox(API::BoxController *const bc, const uint32_t depth,
45 const std::vector<Mantid::Geometry::MDDimensionExtents<coord_t>> &extentsVector)
46 : MDBoxBase<MDE, nd>(bc, depth, UNDEF_SIZET, extentsVector), numBoxes(0), m_Children(), diagonalSquared(0.f),
47 nPoints(0) {
48 initGridBox();
49}
50
57TMDE(MDGridBox)::MDGridBox(std::shared_ptr<API::BoxController> &bc, const uint32_t depth,
58 const std::vector<Mantid::Geometry::MDDimensionExtents<coord_t>> &extentsVector)
59 : MDBoxBase<MDE, nd>(bc.get(), depth, UNDEF_SIZET, extentsVector), numBoxes(0), m_Children(), diagonalSquared(0.f),
60 nPoints(0) {
61 initGridBox();
62}
63
65template <typename MDE, size_t nd> size_t MDGridBox<MDE, nd>::initGridBox() {
66 if (!this->m_BoxController)
67 throw std::runtime_error("MDGridBox::ctor(): No BoxController specified in box.");
68
69 // How many is it split?
70 // If we are at the top level and we have a specific top level split, then set
71 // it.
72 std::optional<std::vector<size_t>> splitTopInto = this->m_BoxController->getSplitTopInto();
73 if (this->getDepth() == 0 && splitTopInto) {
74 for (size_t d = 0; d < nd; d++)
75 split[d] = splitTopInto.value()[d];
76 } else {
77 for (size_t d = 0; d < nd; d++)
78 split[d] = this->m_BoxController->getSplitInto(d);
79 }
80
81 // Compute sizes etc.
82 size_t tot = computeSizesFromSplit();
83 if (tot == 0)
84 throw std::runtime_error("MDGridBox::ctor(): Invalid splitting criterion (one was zero).");
85 return tot;
86}
87
88//-----------------------------------------------------------------------------------------------
92TMDE(MDGridBox)::MDGridBox(MDBox<MDE, nd> *box)
93 : MDBoxBase<MDE, nd>(*box, box->getBoxController()), split(), splitCumul(), m_SubBoxSize(), numBoxes(0),
94 m_Children(), diagonalSquared(0.f), nPoints(0) {
95 size_t totalSize = initGridBox();
96
97 double ChildVol(1);
98 for (size_t d = 0; d < nd; d++)
99 ChildVol *= m_SubBoxSize[d];
100
101 // Splitting an input MDBox requires creating a bunch of children
102 fillBoxShell(totalSize, coord_t(1. / ChildVol));
103
104 // Prepare to distribute the events that were in the box before, this will
105 // load missing events from HDD in file based ws if there are some.
106 const std::vector<MDE> &events = box->getConstEvents();
107 // just add event to the existing internal box
108 for (const auto &evnt : events)
109 addEvent(evnt);
110
111 // Copy the cached numbers from the incoming box. This is quick - don't need
112 // to refresh cache
113 this->nPoints = box->getNPoints();
114
115 // Clear the old box and delete it from disk buffer if one is used.
116 box->clear();
117}
120template <typename MDE, size_t nd>
121void MDGridBox<MDE, nd>::fillBoxShell(const size_t tot, const coord_t ChildInverseVolume) {
122 // Create the array of MDBox contents.
123 this->m_Children.clear();
124 this->m_Children.reserve(tot);
125 this->numBoxes = tot;
126
127 size_t indices[nd];
128 for (size_t d = 0; d < nd; d++)
129 indices[d] = 0;
130
131 // get inital free ID for the boxes, which would be created by this command
132 // Splitting an input MDBox requires creating a bunch of children
133 // But the IDs of these children MUST be sequential. Hence the critical block
134 // within claimIDRange,
135 // which would produce sequental ranges in multithreaded environment
136 size_t ID0 = this->m_BoxController->claimIDRange(tot);
137
138 for (size_t i = 0; i < tot; i++) {
139 // Create the box
140 // (Increase the depth of this box to one more than the parent (this))
141 auto splitBox = new MDBox<MDE, nd>(this->m_BoxController, this->m_depth + 1, UNDEF_SIZET, size_t(ID0 + i));
142 // This MDGridBox is the parent of the new child.
143 splitBox->setParent(this);
144
145 // Set the extents of this box.
146 for (size_t d = 0; d < nd; d++) {
147 double min = double(this->extents[d].getMin()) + double(indices[d]) * m_SubBoxSize[d];
148 double max = min + m_SubBoxSize[d];
149 splitBox->setExtents(d, min, max);
150 }
151 splitBox->setInverseVolume(ChildInverseVolume); // Set the cached inverse volume
152 m_Children.emplace_back(splitBox);
153
154 // Increment the indices, rolling back as needed
155 indices[0]++;
156 for (size_t d = 0; d < nd - 1; d++) // This is not run if nd=1; that's okay,
157 // you can ignore the warning
158 {
159 if (indices[d] >= split[d]) {
160 indices[d] = 0;
161 indices[d + 1]++;
162 }
163 }
164 } // for each box
165}
166
167//-----------------------------------------------------------------------------------------------
176TMDE(MDGridBox)::MDGridBox(const MDGridBox<MDE, nd> &other, Mantid::API::BoxController *const otherBC)
177 : MDBoxBase<MDE, nd>(other, otherBC), numBoxes(other.numBoxes), m_Children(),
178 diagonalSquared(other.diagonalSquared), nPoints(other.nPoints) {
179 for (size_t d = 0; d < nd; d++) {
180 split[d] = other.split[d];
181 splitCumul[d] = other.splitCumul[d];
182 m_SubBoxSize[d] = other.m_SubBoxSize[d];
183 m_SubBoxSizeInv[d] = other.m_SubBoxSizeInv[d];
184 }
185 // Copy all the boxes
186 m_Children.clear();
187 m_Children.reserve(numBoxes);
188 for (size_t i = 0; i < other.m_Children.size(); i++) {
189 API::IMDNode *otherBox = other.m_Children[i];
190 const MDBox<MDE, nd> *otherMDBox = dynamic_cast<const MDBox<MDE, nd> *>(otherBox);
191 const MDGridBox<MDE, nd> *otherMDGridBox = dynamic_cast<const MDGridBox<MDE, nd> *>(otherBox);
192 if (otherMDBox) {
193 auto newBox = new MDBox<MDE, nd>(*otherMDBox, otherBC);
194 newBox->setParent(this);
195 m_Children.emplace_back(newBox);
196 } else if (otherMDGridBox) {
197 auto newBox = new MDGridBox<MDE, nd>(*otherMDGridBox, otherBC);
198 newBox->setParent(this);
199 m_Children.emplace_back(newBox);
200 } else {
201 throw std::runtime_error("MDGridBox::copy_ctor(): an unexpected child box type was found.");
202 }
203 }
204}
205
206//-----------------------------------------------------------------------------------------------
214TMDE(void MDGridBox)::transformDimensions(std::vector<double> &scaling, std::vector<double> &offset) {
216 this->computeSizesFromSplit();
217}
218
219//-----------------------------------------------------------------------------------------------
223TMDE(size_t MDGridBox)::computeSizesFromSplit() {
224 // Do some computation based on how many splits per each dim.
225 size_t tot = 1;
226 double diagSum(0);
227 for (size_t d = 0; d < nd; d++) {
228 // Cumulative multiplier, for indexing
229 splitCumul[d] = tot;
230 tot *= split[d];
231 // Length of the side of a box in this dimension
232 m_SubBoxSize[d] = static_cast<double>(this->extents[d].getSize()) / static_cast<double>(split[d]);
233 m_SubBoxSizeInv[d] = 1.0 / m_SubBoxSize[d];
234 // Accumulate the squared diagonal length.
235 diagSum += m_SubBoxSize[d] * m_SubBoxSize[d];
236 }
237 diagonalSquared = static_cast<coord_t>(diagSum);
238
239 return tot;
240}
241
242//-----------------------------------------------------------------------------------------------
245 // Delete all contained boxes (this should fire the MDGridBox destructors
246 // recursively).
247 auto it = m_Children.begin();
248 for (; it != m_Children.end(); ++it)
249 delete *it;
250 m_Children.clear();
251}
252
253//-----------------------------------------------------------------------------------------------
255TMDE(void MDGridBox)::clear() {
256 this->m_signal = 0.0;
257 this->m_errorSquared = 0.0;
258 auto it = m_Children.begin();
259 for (; it != m_Children.end(); ++it) {
260 (*it)->clear();
261 }
262}
263
264//-----------------------------------------------------------------------------------------------
266TMDE(size_t MDGridBox)::getNumDims() const { return nd; }
267
268//-----------------------------------------------------------------------------------------------
270TMDE(size_t MDGridBox)::getDataInMemorySize() const {
271 size_t nPoints(0);
272 for (size_t i = 0; i < numBoxes; i++)
273 nPoints += m_Children[i]->getDataInMemorySize();
274 return nPoints;
275}
276
277//-----------------------------------------------------------------------------------------------
281TMDE(size_t MDGridBox)::getNumMDBoxes() const {
282 size_t total = 0;
283 auto it = m_Children.begin();
284 for (; it != m_Children.end(); ++it) {
285 total += (*it)->getNumMDBoxes();
286 }
287 return total;
288}
289
290//-----------------------------------------------------------------------------------------------
293TMDE(size_t MDGridBox)::getNumChildren() const { return numBoxes; }
294
295//-----------------------------------------------------------------------------------------------
300TMDE(API::IMDNode *MDGridBox)::getChild(size_t index) { return m_Children[index]; }
301
302//-----------------------------------------------------------------------------------------------
311TMDE(void MDGridBox)::setChildren(const std::vector<API::IMDNode *> &otherBoxes, const size_t indexStart,
312 const size_t indexEnd) {
313 m_Children.clear();
314 m_Children.reserve(indexEnd - indexStart + 1);
315 auto it = otherBoxes.begin() + indexStart;
316 auto it_end = otherBoxes.begin() + indexEnd;
317 // Set the parent of each new child box.
318 for (; it != it_end; it++) {
319 m_Children.emplace_back(dynamic_cast<MDBoxBase<MDE, nd> *>(*it));
320 m_Children.back()->setParent(this);
321 }
322 numBoxes = m_Children.size();
323}
324
325//-----------------------------------------------------------------------------------------------
331TMDE(inline size_t MDGridBox)::getLinearIndex(size_t *indices) const {
332 size_t out_linear_index = 0;
333 for (size_t d = 0; d < nd; d++)
334 out_linear_index += (indices[d] * splitCumul[d]);
335 return out_linear_index;
336}
337
338//-----------------------------------------------------------------------------------------------
346TMDE(void MDGridBox)::refreshCache(Kernel::ThreadScheduler *ts) {
347 // Clear your total
348 nPoints = 0;
349 this->m_signal = 0;
350 this->m_errorSquared = 0;
351 this->m_totalWeight = 0;
352
353 if (!ts) {
354 //--------- Serial -----------
355 for (MDBoxBase<MDE, nd> *ibox : m_Children) {
356
357 // Refresh the cache (does nothing for MDBox)
358 ibox->refreshCache();
359
360 // Add up what's in there
361 nPoints += ibox->getNPoints();
362 this->m_signal += ibox->getSignal();
363 this->m_errorSquared += ibox->getErrorSquared();
364 this->m_totalWeight += ibox->getTotalWeight();
365 }
366 } else {
367 //---------- Parallel refresh --------------
368 throw std::runtime_error("Not implemented");
369 }
370}
371//-----------------------------------------------------------------------------------------------
378TMDE(void MDGridBox)::calculateGridCaches() {
379 // Clear your total
380 nPoints = 0;
381 this->m_signal = 0;
382 this->m_errorSquared = 0;
383 this->m_totalWeight = 0;
384
385 for (MDBoxBase<MDE, nd> *ibox : m_Children) {
386
387 // does nothing for MDBox
388 ibox->calculateGridCaches();
389
390 // Add up what's in there
391 nPoints += ibox->getNPoints();
392 this->m_signal += ibox->getSignal();
393 this->m_errorSquared += ibox->getErrorSquared();
394 this->m_totalWeight += ibox->getTotalWeight();
395 }
396}
397//-----------------------------------------------------------------------------------------------
400TMDE(std::vector<MDE> *MDGridBox)::getEventsCopy() {
401 auto out = new std::vector<MDE>();
402 // Make the copy
403 // out->insert(out->begin(), data.begin(), data.end());
404 return out;
405}
406
407//-----------------------------------------------------------------------------------------------
415TMDE(void MDGridBox)::getBoxes(std::vector<API::IMDNode *> &outBoxes, size_t maxDepth, bool leafOnly) {
416 // Add this box, unless we only want the leaves
417 if (!leafOnly)
418 outBoxes.emplace_back(this);
419
420 if (this->getDepth() < maxDepth) {
421 for (API::IMDNode *child : m_Children) {
422 // Recursively go deeper, if needed
423 child->getBoxes(outBoxes, maxDepth, leafOnly);
424 }
425 } else {
426 // Oh, we reached the max depth and want only leaves.
427 // ... so we consider this box to be a leaf too.
428 if (leafOnly)
429 outBoxes.emplace_back(this);
430 }
431}
432
433GNU_DIAG_OFF("maybe-uninitialized")
434//-----------------------------------------------------------------------------------------------
451TMDE(void MDGridBox)::getBoxes(std::vector<API::IMDNode *> &outBoxes, size_t maxDepth, bool leafOnly,
452 Mantid::Geometry::MDImplicitFunction *function) {
453 // Add this box, unless we only want the leaves
454 if (!leafOnly)
455 outBoxes.emplace_back(this);
456
457 if (this->getDepth() < maxDepth) {
458 // OK, let's look for children that are either touching or completely
459 // contained by the implicit function.
460
461 // The number of vertices in each dimension is the # split[d] + 1
462 size_t vertices_max[nd];
463 Kernel::Utils::NestedForLoop::SetUp(nd, vertices_max, 0);
464
465 // Total number of vertices for all the boxes
466 size_t numVertices = 1;
467 for (size_t d = 0; d < nd; ++d) {
468 vertices_max[d] = split[d] + 1;
469 numVertices *= vertices_max[d];
470 }
471
472 // The function is limited by this many planes
473 size_t numPlanes = function->getNumPlanes();
474
475 // This array will hold whether each vertex is contained by each plane.
476 auto vertexContained = new bool[numVertices * numPlanes];
477
478 // The index to the vertex in each dimension
479 size_t vertexIndex[nd];
480 Kernel::Utils::NestedForLoop::SetUp(nd, vertexIndex, 0);
481 // To get indexes in the array of vertexes
482 size_t vertexIndexMaker[nd];
483 Kernel::Utils::NestedForLoop::SetUpIndexMaker(nd, vertexIndexMaker, vertices_max);
484 // To get indexes in the array of BOXES
485 size_t boxIndexMaker[nd];
486 Kernel::Utils::NestedForLoop::SetUpIndexMaker(nd, boxIndexMaker, split);
487
488 size_t linearVertexIndex = 0;
489 for (linearVertexIndex = 0; linearVertexIndex < numVertices; linearVertexIndex++) {
490 // Get the nd-dimensional index
491 Kernel::Utils::NestedForLoop::GetIndicesFromLinearIndex(nd, linearVertexIndex, vertexIndexMaker, vertices_max,
492 vertexIndex);
493
494 // Coordinates of this vertex
495 coord_t vertexCoord[nd];
496 for (size_t d = 0; d < nd; ++d)
497 vertexCoord[d] = this->extents[d].getMin() + coord_t(double(vertexIndex[d]) * m_SubBoxSize[d]);
498
499 // Now check each plane to see if the vertex is bounded by it
500 for (size_t p = 0; p < numPlanes; p++) {
501 // Save whether this vertex is contained by this plane
502 vertexContained[p * numVertices + linearVertexIndex] = function->getPlane(p).isPointInside(vertexCoord);
503 }
504 }
505
506 // OK, now we have an array saying which vertex is contained by which plane.
507
508 // This is the number of vertices for each box, e.g. 8 in 3D
509 size_t verticesPerBox = 1 << nd;
510
511 /* There is a fixed relationship betwen a vertex (in a linear index) and its
512 * neighbors for a given box. This array calculates this: */
513 auto vertexNeighborsOffsets = new size_t[verticesPerBox];
514
515 for (size_t i = 0; i < verticesPerBox; i++) {
516 // Index (in n-dimensions) of this neighbor)
517 size_t vertIndex[nd];
518 for (size_t d = 0; d < nd; d++) {
519 vertIndex[d] = 0;
520 // Use a bit mask to iterate through the 2^nd neighbor options
521 size_t mask = size_t{1} << d;
522 if (i & mask)
523 vertIndex[d] = 1;
524 }
525 size_t linIndex = Kernel::Utils::NestedForLoop::GetLinearIndex(nd, vertIndex, vertexIndexMaker);
526 vertexNeighborsOffsets[i] = linIndex;
527 }
528
529 // Go through all the boxes
530 size_t boxIndex[nd];
531 Kernel::Utils::NestedForLoop::SetUp(nd, boxIndex, 0);
532
533 bool allDone = false;
534 while (!allDone) {
535 // Find the linear index into the BOXES array.
536 size_t boxLinearIndex = Kernel::Utils::NestedForLoop::GetLinearIndex(nd, boxIndex, boxIndexMaker);
537 API::IMDNode *box = m_Children[boxLinearIndex];
538
539 // std::cout << "Box at " << Strings::join(boxIndex, boxIndex+nd,
540 // ", ")
541 // << " (" << box->getExtentsStr() << ") ";
542
543 // Find the linear index of the upper left vertex of the box.
544 // (note that we're using the VERTEX index maker to find the linear index
545 // in that LARGER array)
546 size_t vertLinearIndex = Kernel::Utils::NestedForLoop::GetLinearIndex(nd, boxIndex, vertexIndexMaker);
547
548 // OK, now its time to see if the box is touching or contained or out of
549 // it.
550 // Recall that:
551 // - if a plane has NO vertices, then the box DOES NOT TOUCH
552 // - if EVERY plane has EVERY vertex, then the box is CONTAINED
553 // - if EVERY plane has at least one vertex, then the box is TOUCHING
554
555 size_t numPlanesWithAllVertexes = 0;
556
557 bool boxIsNotTouching = false;
558
559 // Go plane by plane
560 for (size_t p = 0; p < numPlanes; p++) {
561 size_t numVertexesInThisPlane = 0;
562 // Evaluate the 2^nd vertexes for this box.
563 for (size_t i = 0; i < verticesPerBox; i++) {
564 // (the index of the vertex is) = vertLinearIndex +
565 // vertexNeighborsOffsets[i]
566 if (vertexContained[p * numVertices + vertLinearIndex + vertexNeighborsOffsets[i]])
567 numVertexesInThisPlane++;
568 }
569
570 // Plane with no vertexes = NOT TOUCHING. You can exit now
571 if (numVertexesInThisPlane == 0) {
572 boxIsNotTouching = true;
573 break;
574 }
575
576 // Plane has all the vertexes
577 if (numVertexesInThisPlane == verticesPerBox)
578 numPlanesWithAllVertexes++;
579 } // (for each plane)
580
581 // Is there a chance that the box is contained?
582 if (!boxIsNotTouching) {
583
584 if (numPlanesWithAllVertexes == numPlanes) {
585 // All planes have all vertexes
586 // The box is FULLY CONTAINED
587 // So we can get ALL children and don't need to check the implicit
588 // function
589 box->getBoxes(outBoxes, maxDepth, leafOnly);
590 } else {
591 // There is a chance the box is touching. Keep checking with implicit
592 // functions
593 box->getBoxes(outBoxes, maxDepth, leafOnly, function);
594 }
595 } else {
596 // std::cout << " is not touching at all.\n";
597 }
598
599 // Move on to the next box in the list
600 allDone = Kernel::Utils::NestedForLoop::Increment(nd, boxIndex, split);
601 }
602
603 // Clean up.
604 delete[] vertexContained;
605 delete[] vertexNeighborsOffsets;
606
607 } // Not at max depth
608 else {
609 // Oh, we reached the max depth and want only leaves.
610 // ... so we consider this box to be a leaf too.
611 if (leafOnly)
612 outBoxes.emplace_back(this);
613 }
614}
615GNU_DIAG_ON("maybe-uninitialized")
616//-----------------------------------------------------------------------------------------------
621template <typename MDE, size_t nd> const API::IMDNode *MDGridBox<MDE, nd>::getBoxAtCoord(const coord_t *coords) {
622 size_t index = 0;
623 for (size_t d = 0; d < nd; d++) {
624 coord_t x = coords[d];
625 int i = int((x - this->extents[d].getMin()) / m_SubBoxSize[d]);
626 // NOTE: No bounds checking is done (for performance).
627 // Accumulate the index
628 index += (i * splitCumul[d]);
629 }
630
631 // Add it to the contained box
632 if (index < numBoxes) // avoid segfaults for floating point round-off errors.
633 return m_Children[index]->getBoxAtCoord(coords);
634 else
635 return nullptr;
636}
637
638//-----------------------------------------------------------------------------------------------
649TMDE(void MDGridBox)::splitContents(size_t index, Kernel::ThreadScheduler *ts) {
650 // You can only split it if it is a MDBox (not MDGridBox).
651 MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(m_Children[index]);
652 if (!box)
653 return;
654 // Track how many MDBoxes there are in the overall workspace
655 this->m_BoxController->trackNumBoxes(box->getDepth());
656 // Construct the grid box. This should take the object out of the disk MRU
657 auto gridbox = new MDGridBox<MDE, nd>(box);
658
659 // Delete the old ungridded box
660 delete m_Children[index];
661 // And now we have a gridded box instead of a boring old regular box.
662 m_Children[index] = gridbox;
663
664 if (ts) {
665 // Create a task to split the newly created MDGridBox.
666 ts->push(std::make_shared<Kernel::FunctionTask>(std::bind(&MDGridBox<MDE, nd>::splitAllIfNeeded, &*gridbox, ts)));
667 } else {
668 gridbox->splitAllIfNeeded(nullptr);
669 }
670}
671
672//-----------------------------------------------------------------------------------------------
679TMDE(size_t MDGridBox)::getChildIndexFromID(size_t childId) const {
680 for (size_t index = 0; index < numBoxes; index++) {
681 if (m_Children[index]->getID() == childId)
682 return index;
683 }
684 return UNDEF_SIZET;
685}
686
687//-----------------------------------------------------------------------------------------------
694TMDE(void MDGridBox)::splitAllIfNeeded(Kernel::ThreadScheduler *ts) {
695 for (size_t i = 0; i < numBoxes; ++i) {
696 MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(m_Children[i]);
697 if (box) {
698 // Plain MD-Box. Does it need to be split?
699 if (this->m_BoxController->willSplit(box->getNPoints(), box->getDepth())) {
700 // The MDBox needs to split into a grid box.
701 if (!ts) {
702 // ------ Perform split serially (no ThreadPool) ------
703 auto gridBox = new MDGridBox<MDE, nd>(box);
704 // Track how many MDBoxes there are in the overall workspace
705 this->m_BoxController->trackNumBoxes(box->getDepth());
706 // Replace in the array
707 m_Children[i] = gridBox;
708 // Delete the old box
709 delete box;
710 // Now recursively check if this NEW grid box's contents should be
711 // split too
712 gridBox->splitAllIfNeeded(nullptr);
713 } else {
714 // ------ Perform split in parallel (using ThreadPool) ------
715 // So we create a task to split this MDBox,
716 // Task is : this->splitContents(i, ts);
717 ts->push(
718 std::make_shared<Kernel::FunctionTask>(std::bind(&MDGridBox<MDE, nd>::splitContents, &*this, i, ts)));
719 }
720 } else {
721 // This box does NOT have enough events to be worth splitting, if it do
722 // have at least something in memory then,
723 Kernel::ISaveable *const pSaver(box->getISaveable());
724 if (pSaver && box->getDataInMemorySize() > 0) {
725 // Mark the box as "to-write" in DiskBuffer. If the buffer is full,
726 // the boxes will be dropped on disk
727
728 this->m_BoxController->getFileIO()->toWrite(pSaver);
729 }
730 }
731 } else {
732 // It should be a MDGridBox
733 MDGridBox<MDE, nd> *gridBox = dynamic_cast<MDGridBox<MDE, nd> *>(m_Children[i]);
734 if (gridBox) {
735 // Now recursively check if this old grid box's contents should be split
736 // too
737 if (!ts || (this->nPoints < this->m_BoxController->getAddingEvents_eventsPerTask()))
738 // Go serially if there are only a few points contained (less
739 // overhead).
740 gridBox->splitAllIfNeeded(ts);
741 else
742 // Go parallel if this is a big enough gridbox.
743 // Task is : gridBox->splitAllIfNeeded(ts);
744 ts->push(
745 std::make_shared<Kernel::FunctionTask>(std::bind(&MDGridBox<MDE, nd>::splitAllIfNeeded, &*gridBox, ts)));
746 }
747 }
748 }
749}
750
766TMDE(void MDGridBox)::integrateSphere(API::CoordTransform &radiusTransform, const coord_t radiusSquared,
767 signal_t &signal, signal_t &errorSquared, const coord_t innerRadiusSquared,
768 const bool useOnePercentBackgroundCorrection) const {
769 // We start by looking at the vertices at every corner of every box contained,
770 // to see which boxes are partially contained/fully contained.
771
772 // One entry with the # of vertices in this box contained; start at 0.
773 std::vector<size_t> verticesContained(numBoxes, 0);
774
775 // Set to true if there is a possibility of the box at least partly touching
776 // the integration volume.
777 std::vector<bool> boxMightTouch(numBoxes, 0);
778
779 // How many vertices does one box have? 2^nd, or bitwise shift left 1 by nd
780 // bits
781 size_t maxVertices = 1 << nd;
782
783 // set up caches for box sizes and min box values
784 coord_t boxSize[nd];
785 coord_t minBoxVal[nd];
786
787 // The number of vertices in each dimension is the # split[d] + 1
788 size_t vertices_max[nd];
789 Kernel::Utils::NestedForLoop::SetUp(nd, vertices_max, 0);
790 for (size_t d = 0; d < nd; ++d) {
791 vertices_max[d] = split[d] + 1;
792 // cache box sizes and min box valyes for performance
793 boxSize[d] = static_cast<coord_t>(m_SubBoxSize[d]);
794 minBoxVal[d] = static_cast<coord_t>(this->extents[d].getMin());
795 }
796
797 // The index to the vertex in each dimension
798 size_t vertexIndex[nd];
799 Kernel::Utils::NestedForLoop::SetUp(nd, vertexIndex, 0);
800 size_t boxIndex[nd];
801 Kernel::Utils::NestedForLoop::SetUp(nd, boxIndex, 0);
802 size_t indexMaker[nd];
803 Kernel::Utils::NestedForLoop::SetUpIndexMaker(nd, indexMaker, split);
804
805 bool allDone = false;
806 while (!allDone) {
807 // Coordinates of this vertex
808 coord_t vertexCoord[nd];
809 for (size_t d = 0; d < nd; ++d)
810 vertexCoord[d] = static_cast<coord_t>(vertexIndex[d]) * boxSize[d] + minBoxVal[d];
811 // static_cast<coord_t>(vertexIndex[d]) * boxSize[d] + this->extents[d].min
812
813 // Is this vertex contained?
814 coord_t out[nd];
815 radiusTransform.apply(vertexCoord, out);
816 if (out[0] < radiusSquared && out[0] > innerRadiusSquared) {
817 // Yes, this vertex is contained within the integration volume!
818 // std::cout << "vertex at " << vertexCoord[0] << ", " <<
819 // vertexCoord[1] << ", " << vertexCoord[2] << " is contained\n";
820
821 // This vertex is shared by up to 2^nd adjacent boxes (left-right along
822 // each dimension).
823 for (size_t neighb = 0; neighb < maxVertices; ++neighb) {
824 // The index of the box is the same as the vertex, but maybe - 1 in each
825 // possible combination of dimensions
826 bool badIndex = false;
827 // Build the index of the neighbor
828 for (size_t d = 0; d < nd; d++) {
829 boxIndex[d] = vertexIndex[d] - ((neighb & ((size_t)1 << d)) >> d); //(this does a bitwise and mask,
830 // shifted back to 1 to subtract 1
831 // to the dimension)
832 // Taking advantage of the fact that unsigned(0)-1 = some large
833 // POSITIVE number.
834 if (boxIndex[d] >= split[d]) {
835 badIndex = true;
836 break;
837 }
838 }
839 if (!badIndex) {
840 // Convert to linear index
841 size_t linearIndex = Kernel::Utils::NestedForLoop::GetLinearIndex(nd, boxIndex, indexMaker);
842 // So we have one more vertex touching this box that is contained in
843 // the integration volume. Whew!
844 verticesContained[linearIndex]++;
845 // std::cout << "... added 1 vertex to box " <<
846 // boxes[linearIndex]->getExtentsStr() << "\n";
847 }
848 }
849 }
850
851 // Increment the counter(s) in the nested for loops.
852 allDone = Kernel::Utils::NestedForLoop::Increment(nd, vertexIndex, vertices_max);
853 }
854
855 // NOTE:
856 // The following section is just trying to uncover the peak center so that
857 // we can compute the distance bewteen peak center and box center correctly
858 // without worrying about the skew coming from coordTransformDistnace.
859 auto tmpRadiusTransform = dynamic_cast<CoordTransformDistance *>(&radiusTransform);
860 if (tmpRadiusTransform == nullptr) {
861 throw std::runtime_error("radiusTransform has to be CoordTransformDistance");
862 }
863 auto peakCenter = tmpRadiusTransform->getCenter();
864 double peakRadius = std::sqrt(radiusSquared);
865 double peakInnerRadius = std::sqrt(innerRadiusSquared);
866
867 // OK, we've done counting all the vertices.
868 // Now let's go through and check each box.
869 for (size_t bIndex = 0; bIndex < numBoxes; ++bIndex) {
870 API::IMDNode *box = m_Children[bIndex];
871
872 // First, check if we have reached the base case where the box is completely
873 // enveloped by the peak
874 if (verticesContained[bIndex] >= maxVertices) {
875 // Use the integrated sum of signal in the box
876 signal += box->getSignal();
877 errorSquared += box->getErrorSquared();
878 continue; // move on to next
879 }
880
881 // Second, check if there is at least one vertex in the integration volume,
882 // and kick off recursive search until we reach the base case
883 if (verticesContained[bIndex] > 0) {
884 box->integrateSphere(radiusTransform, radiusSquared, signal, errorSquared, innerRadiusSquared,
885 useOnePercentBackgroundCorrection);
886 continue;
887 }
888
889 // Last, no vertices in the integration volume
890 // -- there are only two cases (see below) where we can
891 // skip the box and its children, and it requires
892 // the knowledge of how box and peak are spatially
893 // positioned in Euclidian space.
894 // NOTE:
895 // For ellipsoid, we are using the long semi-axis, which
896 // means we will inevitablly search some empty boxes, but
897 // this is by design as we do not want to miss any box
898 // that might contain events we need to collect.
899 coord_t boxCenter[nd];
900 box->getCenter(boxCenter);
901 double distPeakCenterToBoxCenter = 0.0;
902 for (size_t i = 0; i < nd; ++i) {
903 distPeakCenterToBoxCenter += (boxCenter[i] - peakCenter[i]) * (boxCenter[i] - peakCenter[i]);
904 }
905 distPeakCenterToBoxCenter = std::sqrt(distPeakCenterToBoxCenter);
906 double boxRadius = std::sqrt(diagonalSquared);
907
908 // - Box is completely isolated from peak
909 // distPeakCenterToBoxCenter - peakRadius > boxRadius
910 // -> stop search and move on
911 if (distPeakCenterToBoxCenter - peakRadius > boxRadius) {
912 // Debug output
913 // std::ostringstream debugmsg;
914 // debugmsg << "R_peak = " << peakRadius << "\n"
915 // << "R_box = " << boxRadius << "\n"
916 // << "Peak Center: ";
917 // for (size_t i = 0; i < nd; ++i) {
918 // debugmsg << peakCenter[i] << ",";
919 // }
920 // debugmsg << "\n"
921 // << "Box center: ";
922 // for (size_t i = 0; i < nd; ++i) {
923 // debugmsg << boxCenter[i] << ",";
924 // }
925 // debugmsg << "\n"
926 // << "distPeakCenterToBoxCenter = " << distPeakCenterToBoxCenter
927 // << "\n";
928 // std::cout << debugmsg.str();
929 continue;
930 }
931 // - Tiny box falls into the donut hole
932 // distPeakCenterToBoxCenter + boxRadius < peakInnerRadius
933 // -> stop search and move on
934 if (peakInnerRadius > 0 && distPeakCenterToBoxCenter + boxRadius < peakInnerRadius) {
935 continue;
936 }
937 // - All other cases, we need to refine the box, i.e. recursively
938 // search the child box
939 box->integrateSphere(radiusTransform, radiusSquared, signal, errorSquared, innerRadiusSquared,
940 useOnePercentBackgroundCorrection);
941 } // (for each box)
942}
943
944//-----------------------------------------------------------------------------------------------
955TMDE(void MDGridBox)::centroidSphere(API::CoordTransform &radiusTransform, const coord_t radiusSquared,
956 coord_t *centroid, signal_t &signal) const {
957 for (size_t i = 0; i < numBoxes; ++i) {
958 // Go through each contained box
959 API::IMDNode *box = m_Children[i];
960 coord_t boxCenter[nd];
961 box->getCenter(boxCenter);
962
963 // Distance from center to the peak integration center
964 coord_t out[nd];
965 radiusTransform.apply(boxCenter, out);
966
967 if (out[0] < diagonalSquared * 0.72 + radiusSquared) {
968 // If the center is closer than the size of the box, then it MIGHT be
969 // touching.
970 // (We multiply by 0.72 (about sqrt(2)) to look for half the diagonal).
971 // NOTE! Watch out for non-spherical transforms!
972
973 // Go down one level to keep centroiding
974 box->centroidSphere(radiusTransform, radiusSquared, centroid, signal);
975 }
976 } // (for each box)
977}
978//-----------------------------------------------------------------------------------------------
979GNU_DIAG_OFF("array-bounds")
995TMDE(void MDGridBox)::integrateCylinder(Mantid::API::CoordTransform &radiusTransform, const coord_t radius,
996 const coord_t length, signal_t &signal, signal_t &errorSquared,
997 std::vector<signal_t> &signal_fit) const {
998 // We start by looking at the vertices at every corner of every box contained,
999 // to see which boxes are partially contained/fully contained.
1000
1001 // One entry with the # of vertices in this box contained; start at 0.
1002 auto verticesContained = new size_t[numBoxes];
1003 memset(verticesContained, 0, numBoxes * sizeof(size_t));
1004
1005 // Set to true if there is a possibility of the box at least partly touching
1006 // the integration volume.
1007 auto boxMightTouch = new bool[numBoxes];
1008 memset(boxMightTouch, 0, numBoxes * sizeof(bool));
1009
1010 // How many vertices does one box have? 2^nd, or bitwise shift left 1 by nd
1011 // bits
1012 size_t maxVertices = 1 << nd;
1013
1014 // set up caches for box sizes and min box values
1015 coord_t boxSize[nd];
1016 coord_t minBoxVal[nd];
1017
1018 // The number of vertices in each dimension is the # split[d] + 1
1019 size_t vertices_max[nd];
1020 Kernel::Utils::NestedForLoop::SetUp(nd, vertices_max, 0);
1021 for (size_t d = 0; d < nd; ++d) {
1022 vertices_max[d] = split[d] + 1;
1023 // cache box sizes and min box valyes for performance
1024 boxSize[d] = static_cast<coord_t>(m_SubBoxSize[d]);
1025 minBoxVal[d] = static_cast<coord_t>(this->extents[d].getMin());
1026 }
1027
1028 // The index to the vertex in each dimension
1029 size_t vertexIndex[nd];
1030 Kernel::Utils::NestedForLoop::SetUp(nd, vertexIndex, 0);
1031 size_t boxIndex[nd];
1032 Kernel::Utils::NestedForLoop::SetUp(nd, boxIndex, 0);
1033 size_t indexMaker[nd];
1034 Kernel::Utils::NestedForLoop::SetUpIndexMaker(nd, indexMaker, split);
1035
1036 size_t numSteps = signal_fit.size();
1037 double deltaQ = length / static_cast<double>(numSteps - 1);
1038 bool allDone = false;
1039 while (!allDone) {
1040 // Coordinates of this vertex
1041 coord_t vertexCoord[nd];
1042 for (size_t d = 0; d < nd; ++d)
1043 vertexCoord[d] = static_cast<coord_t>(vertexIndex[d]) * boxSize[d] + minBoxVal[d];
1044 // static_cast<coord_t>(vertexIndex[d]) * boxSize[d] + this->extents[d].min
1045
1046 // Is this vertex contained?
1047 coord_t out[2]; // radius and length of cylinder
1048 radiusTransform.apply(vertexCoord, out);
1049 if (out[0] < radius && std::fabs(out[1]) < 0.5 * length) {
1050 // Yes, this vertex is contained within the integration volume!
1051 // std::cout << "vertex at " << vertexCoord[0] << ", " <<
1052 // vertexCoord[1] << ", " << vertexCoord[2] << " is contained\n";
1053
1054 // This vertex is shared by up to 2^nd adjacent boxes (left-right along
1055 // each dimension).
1056 for (size_t neighb = 0; neighb < maxVertices; ++neighb) {
1057 // The index of the box is the same as the vertex, but maybe - 1 in each
1058 // possible combination of dimensions
1059 bool badIndex = false;
1060 // Build the index of the neighbor
1061 for (size_t d = 0; d < nd; d++) {
1062 boxIndex[d] = vertexIndex[d] - ((neighb & ((size_t)1 << d)) >> d); //(this does a bitwise and mask,
1063 // shifted back to 1 to subtract 1
1064 // to the dimension)
1065 // Taking advantage of the fact that unsigned(0)-1 = some large
1066 // POSITIVE number.
1067 if (boxIndex[d] >= split[d]) {
1068 badIndex = true;
1069 break;
1070 }
1071 }
1072 if (!badIndex) {
1073 // Convert to linear index
1074 size_t linearIndex = Kernel::Utils::NestedForLoop::GetLinearIndex(nd, boxIndex, indexMaker);
1075 // So we have one more vertex touching this box that is contained in
1076 // the integration volume. Whew!
1077 verticesContained[linearIndex]++;
1078 // std::cout << "... added 1 vertex to box " <<
1079 // boxes[linearIndex]->getExtentsStr() << "\n";
1080 }
1081 }
1082 }
1083
1084 // Increment the counter(s) in the nested for loops.
1085 allDone = Kernel::Utils::NestedForLoop::Increment(nd, vertexIndex, vertices_max);
1086 }
1087
1088 // OK, we've done all the vertices. Now we go through and check each box.
1089 for (size_t i = 0; i < numBoxes; ++i) {
1090 API::IMDNode *box = m_Children[i];
1091 // Box partially contained?
1092 bool partialBox = false;
1093
1094 // Is this box fully contained?
1095 if (verticesContained[i] >= maxVertices) {
1096 std::vector<coord_t> coordTable;
1097 size_t nColumns;
1098 box->getEventsData(coordTable, nColumns);
1099 if (nColumns > 0 && nd > 1) {
1100 size_t nEvents = coordTable.size() / nColumns;
1101 size_t skipCol = 2; // lean events
1102 if (nColumns == 7)
1103 skipCol += 2; // events
1104 for (size_t k = 0; k < nEvents; k++) {
1105 coord_t eventCenter[nd];
1106 for (size_t l = 0; l < nd; l++)
1107 eventCenter[l] = coordTable[k * nColumns + skipCol + l];
1108 coord_t out[nd];
1109 radiusTransform.apply(eventCenter, out);
1110 // add event to appropriate y channel
1111 size_t xchannel = static_cast<size_t>(std::floor(out[1] / deltaQ)) + numSteps / 2;
1112
1113 if (xchannel < numSteps)
1114 signal_fit[xchannel] += coordTable[k * nColumns];
1115 }
1116 }
1117 // box->releaseEvents();
1118 // Use the integrated sum of signal in the box
1119 signal += box->getSignal();
1120 errorSquared += box->getErrorSquared();
1121
1122 // std::cout << "box at " << i << " (" << box->getExtentsStr() <<
1123 // ") is fully contained. Vertices = " << verticesContained[i] <<
1124 // "\n";
1125 // Go on to the next box
1126 continue;
1127 }
1128
1129 if (verticesContained[i] == 0) {
1130 // There is a chance that this part of the box is within integration
1131 // volume,
1132 // even if no vertex of it is.
1133 coord_t boxCenter[nd];
1134 box->getCenter(boxCenter);
1135
1136 // Distance from center to the peak integration center
1137 coord_t out[nd];
1138 radiusTransform.apply(boxCenter, out);
1139 if ((nd >= 1) && out[0] < std::sqrt(diagonalSquared * 0.72 + radius * radius) &&
1140 (nd >= 2 && std::fabs(out[1]) < std::sqrt(diagonalSquared * 0.72 + 0.25 * length * length))) {
1141 // If the center is closer than the size of the box, then it MIGHT be
1142 // touching.
1143 // (We multiply by 0.72 (about sqrt(2)) to look for half the diagonal).
1144 // NOTE! Watch out for non-spherical transforms!
1145 // std::cout << "box at " << i << " is maybe touching\n";
1146 partialBox = true;
1147 }
1148 } else {
1149 partialBox = true;
1150 // std::cout << "box at " << i << " has a vertex touching\n";
1151 }
1152
1153 // We couldn't rule out that the box might be partially contained.
1154 if (partialBox) {
1155 // Use the detailed integration method.
1156 box->integrateCylinder(radiusTransform, radius, length, signal, errorSquared, signal_fit);
1157 // std::cout << ".signal=" << signal << "\n";
1158 }
1159 } // (for each box)
1160
1161 // std::cout << "Depth " << this->getDepth() << " with " <<
1162 // numFullyContained << " fully contained; " << numPartiallyContained << "
1163 // partial. Signal = " << signal <<"\n";
1164
1165 delete[] verticesContained;
1166 delete[] boxMightTouch;
1167}
1168GNU_DIAG_ON("array-bounds")
1169
1170
1174TMDE(bool MDGridBox)::getIsMasked() const {
1175 bool isMasked = false;
1176 for (size_t i = 0; i < numBoxes; ++i) {
1177 // Go through each contained box
1178 API::IMDNode *box = m_Children[i];
1179 if (box->getIsMasked()) {
1180 isMasked = true;
1181 break;
1182 }
1183 }
1184 return isMasked;
1185}
1186
1188TMDE(void MDGridBox)::mask() {
1189 for (size_t i = 0; i < numBoxes; ++i) {
1190 // Go through each contained box
1191 API::IMDNode *box = m_Children[i];
1192 box->mask();
1193 }
1194}
1195
1197TMDE(void MDGridBox)::unmask() {
1198 for (size_t i = 0; i < numBoxes; ++i) {
1199 // Go through each contained box
1200 API::IMDNode *box = m_Children[i];
1201 box->unmask();
1202 }
1203}
1204//------------------------------------------------------------------------------------------------------------------------------------------------------------
1205//------------------------------------------------------------------------------------------------------------------------------------------------------------
1206//------------------------------------------------------------------------------------------------------------------------------------------------------------
1207/* Internal TMP class to simplify adding events to the box for events and lean
1208 * events using single interface. One would nead to overload the box class
1209 * otherwise*/
1210template <typename MDE, size_t nd> struct IF_EVENT {
1211public:
1212 // create generic events from array of events data and add them to the grid
1213 // box
1214 static inline void EXEC(MDGridBox<MDE, nd> *pBox, const std::vector<signal_t> &sigErrSq,
1215 const std::vector<coord_t> &Coord, const std::vector<uint16_t> &expInfoIndex,
1216 const std::vector<uint16_t> &goniometerIndex, const std::vector<uint32_t> &detectorId,
1217 size_t nEvents) {
1218 for (size_t i = 0; i < nEvents; i++)
1219 pBox->addEvent(MDEvent<nd>(sigErrSq[2 * i], sigErrSq[2 * i + 1], expInfoIndex[i], goniometerIndex[i],
1220 detectorId[i], &Coord[i * nd]));
1221 }
1222};
1223/* Specialize for the case of LeanEvent */
1224template <size_t nd> struct IF_EVENT<MDLeanEvent<nd>, nd> {
1225public:
1226 // create lean events from array of events data and add them to the grid box
1227 static inline void EXEC(MDGridBox<MDLeanEvent<nd>, nd> *pBox, const std::vector<signal_t> &sigErrSq,
1228 const std::vector<coord_t> &Coord, const std::vector<uint16_t> & /*expInfoIndex*/,
1229 const std::vector<uint16_t> & /*goniometerIndex*/,
1230 const std::vector<uint32_t> & /*detectorId*/, size_t nEvents) {
1231 for (size_t i = 0; i < nEvents; i++)
1232 pBox->addEvent(MDLeanEvent<nd>(sigErrSq[2 * i], sigErrSq[2 * i + 1], &Coord[i * nd]));
1233 }
1234};
1235
1249TMDE(size_t MDGridBox)::buildAndAddEvents(const std::vector<signal_t> &sigErrSq, const std::vector<coord_t> &Coord,
1250 const std::vector<uint16_t> &expInfoIndex,
1251 const std::vector<uint16_t> &goniometerIndex,
1252 const std::vector<uint32_t> &detectorId) {
1253
1254 size_t nEvents = sigErrSq.size() / 2;
1255 IF_EVENT<MDE, nd>::EXEC(this, sigErrSq, Coord, expInfoIndex, goniometerIndex, detectorId, nEvents);
1256
1257 return 0;
1258}
1259
1268TMDE(void MDGridBox)::buildAndAddEvent(const signal_t Signal, const signal_t errorSq, const std::vector<coord_t> &point,
1269 uint16_t expInfoIndex, uint16_t goniometerIndex, uint32_t detectorId) {
1270 this->addEvent(IF<MDE, nd>::BUILD_EVENT(Signal, errorSq, &point[0], expInfoIndex, goniometerIndex, detectorId));
1271}
1272
1273//-----------------------------------------------------------------------------------------------
1286TMDE(void MDGridBox)::buildAndAddEventUnsafe(const signal_t Signal, const signal_t errorSq,
1287 const std::vector<coord_t> &point, uint16_t expInfoIndex,
1288 uint16_t goniometerIndex, uint32_t detectorId) {
1289 this->addEventUnsafe(IF<MDE, nd>::BUILD_EVENT(Signal, errorSq, &point[0], expInfoIndex, goniometerIndex, detectorId));
1290}
1291
1292//-----------------------------------------------------------------------------------------------
1305TMDE(inline size_t MDGridBox)::addEvent(const MDE &event) {
1306 size_t cindex = calculateChildIndex(event);
1307
1308 // We can erroneously get cindex == numBoxes for events which fall on the
1309 // upper boundary of the last child box, so add these events to the last box
1310 if (cindex == numBoxes)
1311 cindex = numBoxes - 1;
1312
1313 if (cindex < numBoxes)
1314 return m_Children[cindex]->addEvent(event);
1315 else
1316 return 0;
1317}
1318
1319//-----------------------------------------------------------------------------------------------
1336TMDE(inline size_t MDGridBox)::addEventUnsafe(const MDE &event) {
1337 size_t cindex = calculateChildIndex(event);
1338
1339 // We can erroneously get cindex == numBoxes for events which fall on the
1340 // upper boundary of the last child box, so add these events to the last box
1341 if (cindex == numBoxes)
1342 cindex = numBoxes - 1;
1343
1344 if (cindex < numBoxes)
1345 return m_Children[cindex]->addEventUnsafe(event);
1346 else
1347 return 0;
1348}
1349
1356TMDE(inline void MDGridBox)::setChild(size_t index, MDGridBox<MDE, nd> *newChild) {
1357 // Delete the old box (supposetly ungridded);
1358 delete this->m_Children[index];
1359 // set new box, supposetly gridded
1360 this->m_Children[index] = newChild;
1361}
1364TMDE(void MDGridBox)::setFileBacked(const uint64_t /*fileLocation*/, const size_t /*fileSize*/,
1365 const bool /*markSaved*/) {
1366 throw(Kernel::Exception::NotImplementedError("Recursive file backed is not "
1367 "yet implemented (unclear how "
1368 "to set file location etc)"));
1369}
1372TMDE(void MDGridBox)::setFileBacked() {
1373 for (size_t i = 0; i < this->numBoxes; i++) {
1374 m_Children[i]->setFileBacked();
1375 }
1376}
1389TMDE(void MDGridBox)::clearFileBacked(bool loadDiskBackedData) {
1390 auto it = m_Children.begin();
1391 auto it_end = m_Children.end();
1392 for (; it != it_end; it++) {
1393 (*it)->clearFileBacked(loadDiskBackedData);
1394 }
1395}
1396
1400TMDE(size_t MDGridBox)::calculateChildIndex(const MDE &event) const {
1401 size_t cindex(0);
1402 for (size_t d = 0; d < nd; d++) {
1403 // Accumulate the index
1404 const auto coordinate = event.getCenter(d);
1405 const auto offset = coordinate - this->extents[d].getMin();
1406 const int splitD = static_cast<int>(split[d]);
1407 // clamp to splitD-1: FP rounding can place an in-box coordinate one slot past the last valid child
1408 auto childIndex = static_cast<int>(offset * m_SubBoxSizeInv[d]);
1409 if (childIndex == splitD && coordinate <= this->extents[d].getMax())
1410 childIndex = splitD - 1;
1411 cindex += childIndex * splitCumul[d];
1412 }
1413 return cindex;
1414}
1415} // namespace DataObjects
1416
1417} // namespace Mantid
std::map< DeltaEMode::Type, std::string > index
#define UNDEF_SIZET
Definition MDTypes.h:61
#define TMDE(decl)
Macro TMDE to make declaring template functions faster.
Definition MDTypes.h:52
#define GNU_DIAG_ON(x)
#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.
Unique SingleValueParameter Declaration for InputNDimensions.
virtual void mask()=0
Setter for masking the box.
virtual void integrateCylinder(Mantid::API::CoordTransform &radiusTransform, const coord_t radius, const coord_t length, signal_t &signal, signal_t &errorSquared, std::vector< signal_t > &signal_fit) const =0
Cylinder (peak) integration The CoordTransform object could be used for more cylinder reduces the dim...
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 void centroidSphere(Mantid::API::CoordTransform &radiusTransform, const coord_t radiusSquared, coord_t *centroid, signal_t &signal) const =0
Find the centroid of all events contained within by doing a weighted average of their coordinates.
virtual bool getIsMasked() const =0
Getter for the masking.
virtual signal_t getErrorSquared() const =0
virtual void getEventsData(std::vector< coord_t > &coordTable, size_t &nColumns) const =0
The method to convert events in a box into a table of coodrinates/signal/errors casted into coord_t t...
virtual void getCenter(coord_t *const) const =0
virtual void unmask()=0
Setter for unmasking the box.
virtual signal_t getSignal() const =0
Templated super-class of a multi-dimensional event "box".
Definition MDBoxBase.h:49
uint32_t getDepth() const override
For testing, mostly: return the recursion depth of this box.
Definition MDBoxBase.h:275
void transformDimensions(std::vector< double > &scaling, std::vector< double > &offset) override
Transform the dimensions contained in this box x' = x*scaling + offset.
Definition MDBoxBase.hxx:78
Templated class for a multi-dimensional event "box".
Definition MDBox.h:45
Kernel::ISaveable * getISaveable() override
Definition MDBox.hxx:160
void splitAllIfNeeded(Mantid::Kernel::ThreadScheduler *=nullptr) override
Definition MDBox.h:155
uint64_t getNPoints() const override
Returns the total number of points (events) in this box either they are all in memory,...
Definition MDBox.hxx:213
size_t getDataInMemorySize() const override
Definition MDBox.h:87
Templated class holding data about a neutron detection event in N-dimensions (for example,...
Definition MDEvent.h:40
Templated class for a GRIDDED multi-dimensional event "box".
Definition MDGridBox.h:42
void splitAllIfNeeded(Kernel::ThreadScheduler *ts=nullptr) override
Goes through all the sub-boxes and splits them if they contain enough events to be worth it.
size_t addEvent(const MDE &event) override
Add a single MDLeanEvent to the grid box.
void clear() override
Clear any points contained.
size_t initGridBox()
common part of MDGridBox contstructor;
Definition MDGridBox.hxx:65
void fillBoxShell(const size_t tot, const coord_t ChildInverseVolume)
Internal function to do main job of filling in a GridBox contents (part of the constructor)
Templated class holding data about a neutron detection event in N-dimensions (for example,...
Definition MDLeanEvent.h:64
Simple class that holds the extents (min/max) of a given dimension in a MD workspace or MDBox.
An "ImplicitFunction" defining a hyper-cuboid-shaped region in N dimensions.
Marks code as not implemented yet.
Definition Exception.h:138
An interface for objects that can be cached or saved to disk.
Definition ISaveable.h:28
The ThreadScheduler object defines how tasks are allocated to threads and in what order.
void split(const int A, int &S, int &V)
Split a number into the sign and positive value.
Definition Acomp.cpp:42
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,...
Definition MDTypes.h:27
double signal_t
Typedef for the signal recorded in a MDBox, etc.
Definition MDTypes.h:36
STL namespace.
static void EXEC(MDGridBox< MDLeanEvent< nd >, nd > *pBox, const std::vector< signal_t > &sigErrSq, const std::vector< coord_t > &Coord, const std::vector< uint16_t > &, const std::vector< uint16_t > &, const std::vector< uint32_t > &, size_t nEvents)
static void EXEC(MDGridBox< MDE, nd > *pBox, const std::vector< signal_t > &sigErrSq, const std::vector< coord_t > &Coord, const std::vector< uint16_t > &expInfoIndex, const std::vector< uint16_t > &goniometerIndex, const std::vector< uint32_t > &detectorId, size_t nEvents)