Mantid
Loading...
Searching...
No Matches
MDEventWorkspace.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 +
21#include "MantidKernel/Logger.h"
22#include "MantidKernel/Memory.h"
24#include "MantidKernel/Task.h"
27#include "MantidKernel/Timer.h"
28#include "MantidKernel/Utils.h"
30
31#include <algorithm>
32#include <functional>
33#include <iomanip>
34#include <ostream>
35
36// Test for gcc 4.4
37#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 4 || (__GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ > 0)))
38GNU_DIAG_OFF("strict-aliasing")
39#endif
40
41namespace Mantid {
42namespace DataObjects {
43
44namespace {
45Kernel::Logger logger("MDEventWorkspace");
46}
47
48//-----------------------------------------------------------------------------------------------
53 Mantid::API::MDNormalization preferredNormalizationHisto)
54 : API::IMDEventWorkspace(), m_BoxController(new API::BoxController(nd)), data(),
55 m_displayNormalization(preferredNormalization), m_displayNormalizationHisto(preferredNormalizationHisto),
56 m_coordSystem(Kernel::None) {
57 // First box is at depth 0, and has this default boxController
58 data = std::make_unique<MDBox<MDE, nd>>(m_BoxController.get(), 0);
59}
60
61//-----------------------------------------------------------------------------------------------
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) {
68
69 const MDBox<MDE, nd> *mdbox = dynamic_cast<const MDBox<MDE, nd> *>(other.data.get());
70 const MDGridBox<MDE, nd> *mdgridbox = dynamic_cast<const MDGridBox<MDE, nd> *>(other.data.get());
71 if (mdbox) {
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());
75 } else {
76 throw std::runtime_error("MDEventWorkspace::copy_ctor(): unexpected data box type found.");
77 }
78}
79
84TMDE(void MDEventWorkspace)::setFileBacked(const std::string & /*fileName*/) {
85 throw Kernel::Exception::NotImplementedError(" Not yet implemented");
86}
87/*
88 * Set filebacked on the contained box
89 */
90TMDE(void MDEventWorkspace)::setFileBacked() { this->getBox()->setFileBacked(); }
100TMDE(void MDEventWorkspace)::clearFileBacked(bool LoadFileBackedData) {
101 if (m_BoxController->isFileBacked()) {
102 data->clearFileBacked(LoadFileBackedData);
103 m_BoxController->clearFileBacked();
104 }
105}
106//-----------------------------------------------------------------------------------------------
110TMDE(void MDEventWorkspace)::initialize() {
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.");
116 if (isGridBox())
117 throw std::runtime_error("MDEventWorkspace::initialize() called on a "
118 "MDEventWorkspace containing a MDGridBox. You "
119 "should call initialize() before adding any "
120 "events!");
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();
125 }
126 data->setExtents(minSize, maxSize);
127}
128
129//-----------------------------------------------------------------------------------------------
131TMDE(const std::string MDEventWorkspace)::id() const {
132 std::ostringstream out;
133 out << "MDEventWorkspace<" << MDE::getTypeName() << "," << getNumDims() << ">";
134 return out.str();
135}
136
137//-----------------------------------------------------------------------------------------------
141TMDE(std::string MDEventWorkspace)::getEventTypeName() const { return MDE::getTypeName(); }
142
143//-----------------------------------------------------------------------------------------------
145TMDE(size_t MDEventWorkspace)::getNumDims() const { return nd; }
146
147//-----------------------------------------------------------------------------------------------
149TMDE(uint64_t MDEventWorkspace)::getNPoints() const { return data->getNPoints(); }
150
151//-----------------------------------------------------------------------------------------------
165TMDE(void MDEventWorkspace)::setMinRecursionDepth(size_t minDepth) {
166 API::BoxController_sptr bc = this->getBoxController();
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());
177 }
178
179 for (size_t depth = 1; depth < minDepth; depth++) {
180 // Get all the MDGridBoxes in the workspace
181 std::vector<API::IMDNode *> boxes;
182 boxes.clear();
183 this->getBox()->getBoxes(boxes, depth - 1, false);
184 for (const auto box : boxes) {
185 MDGridBox<MDE, nd> *gbox = dynamic_cast<MDGridBox<MDE, nd> *>(box);
186 if (gbox) {
187 // Split ALL the contents.
188 for (size_t j = 0; j < gbox->getNumChildren(); j++)
189 gbox->splitContents(j, nullptr);
190 }
191 }
192 }
193}
194
195//-----------------------------------------------------------------------------------------------
197TMDE(std::vector<coord_t> MDEventWorkspace)::estimateResolution() const {
198 size_t realDepth = 0;
199 std::vector<size_t> numMD = m_BoxController->getNumMDBoxes();
200 for (size_t i = 0; i < numMD.size(); i++)
201 if (numMD[i] > 0)
202 realDepth = i;
203
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;
208 size_t i = 0;
209 if (splitTop) {
210 finestSplit *= splitTop.value()[d];
211 i = 1;
212 }
213 for (; i < realDepth; i++)
214 finestSplit *= m_BoxController->getSplitInto(d);
215 Geometry::IMDDimension_const_sptr dim = this->getDimension(d);
216 // Calculate the bin size at the smallest split amount
217 out.emplace_back((dim->getMaximum() - dim->getMinimum()) / static_cast<coord_t>(finestSplit));
218 }
219 return out;
220}
221
222//-----------------------------------------------------------------------------------------------
228TMDE(std::vector<std::unique_ptr<Mantid::API::IMDIterator>> MDEventWorkspace)::createIterators(
229 size_t suggestedNumCores, Mantid::Geometry::MDImplicitFunction *function) const {
230 // Get all the boxes in this workspaces
231 std::vector<API::IMDNode *> boxes;
232 // TODO: Should this be leaf only? Depends on most common use case
233 if (function)
234 this->data->getBoxes(boxes, 10000, true, function);
235 else
236 this->data->getBoxes(boxes, 10000, true);
237
238 // Calculate the right number of cores
239 size_t numCores = suggestedNumCores;
240 if (!this->threadSafe())
241 numCores = 1;
242 size_t numElements = boxes.size();
243 if (numCores > numElements)
244 numCores = numElements;
245 if (numCores < 1)
246 numCores = 1;
247
248 // Create one iterator per core, splitting evenly amongst spectra
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)
254 end = numElements;
255 out.emplace_back(std::make_unique<MDBoxIterator<MDE, nd>>(boxes, begin, end));
256 }
257 return out;
258}
259
260//-----------------------------------------------------------------------------------------------
268TMDE(signal_t MDEventWorkspace)::getSignalAtCoord(const coord_t *coords,
269 const Mantid::API::MDNormalization &normalization) const {
270 if (!isInBounds(coords)) {
271 return std::numeric_limits<signal_t>::quiet_NaN();
272 }
273 // If you got here, then the point is in the workspace.
274 const API::IMDNode *box = data->getBoxAtCoord(coords);
275 return getNormalizedSignal(box, normalization);
276}
277
278TMDE(signal_t MDEventWorkspace)::getNormalizedSignal(const API::IMDNode *box,
279 const Mantid::API::MDNormalization &normalization) const {
280 if (box) {
281 // What is our normalization factor?
282 switch (normalization) {
283 case API::NoNormalization:
284 return box->getSignal();
285 case API::VolumeNormalization:
286 return box->getSignal() * box->getInverseVolume();
287 case API::NumEventsNormalization:
288 return box->getSignal() / static_cast<double>(box->getNPoints());
289 default:
290 return box->getSignal();
291 }
292 } else
293 return std::numeric_limits<signal_t>::quiet_NaN();
294}
295
296TMDE(signal_t MDEventWorkspace)::getNormalizedError(const API::IMDNode *box,
297 const Mantid::API::MDNormalization &normalization) const {
298 if (box) {
299 // What is our normalization factor?
300 switch (normalization) {
302 return box->getError();
304 return box->getError() * box->getInverseVolume();
306 return box->getError() / static_cast<double>(box->getNPoints());
307 default:
308 return box->getError();
309 }
310 } else
311 return std::numeric_limits<signal_t>::quiet_NaN();
312}
313
314TMDE(bool MDEventWorkspace)::isInBounds(const coord_t *coords) const {
315 for (size_t d = 0; d < nd; d++) {
316 coord_t x = coords[d];
317 if (data->getExtents(d).outside(x))
318 return false;
319 }
320 return true;
321}
322
323//----------------------------------------------------------------------------------------------
332TMDE(signal_t MDEventWorkspace)::getSignalWithMaskAtCoord(const coord_t *coords,
333 const Mantid::API::MDNormalization &normalization) const {
334 if (!isInBounds(coords)) {
335 return std::numeric_limits<signal_t>::quiet_NaN();
336 }
337 // Check if masked
338 const API::IMDNode *box = data->getBoxAtCoord(coords);
339 if (!box)
340 return API::MDMaskValue;
341 if (box->getIsMasked()) {
342 return API::MDMaskValue;
343 }
344 return getNormalizedSignal(box, normalization);
345}
346
347//-----------------------------------------------------------------------------------------------
360 size_t depth) const {
361 std::vector<Mantid::Geometry::MDDimensionExtents<coord_t>> out(nd);
362 std::vector<API::IMDNode *> boxes;
363 // Get all the end (leaf) 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) {
368 API::IMDNode *box = *it;
369 if (box->getNPoints() > 0) {
370 for (size_t d = 0; d < nd; d++)
371 box->getExtents(d).expand(out[d]);
372 }
373 }
374
375 // Fix any missing dimensions (for empty workspaces)
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());
379 }
380 return out;
381}
382
383//-----------------------------------------------------------------------------------------------
386TMDE(std::vector<std::string> MDEventWorkspace)::getBoxControllerStats() const {
387 std::vector<std::string> out;
388 std::ostringstream mess;
389
390 size_t mem;
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());
394 mess.str("");
395
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());
399 mess.str("");
400
401 // mess << "Avg recursion depth: " << m_BoxController->getAverageDepth();
402 // out.emplace_back(mess.str()); mess.str("");
403 //
404 // mess << "Recursion Coverage %: ";
405 // const std::vector<size_t> & num = m_BoxController->getNumMDBoxes();
406 // const std::vector<double> & max = m_BoxController->getMaxNumMDBoxes();
407 // for (size_t i=0; i<num.size(); i++)
408 // {
409 // if (i > 0) mess << ", ";
410 // double pct = (double(num[i]) / double(max[i] * 100));
411 // if (pct > 0 && pct < 1e-2) mess << std::scientific; else mess <<
412 // std::fixed;
413 // mess << std::setprecision(2) << pct;
414 // }
415 // out.emplace_back(mess.str()); mess.str("");
416
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());
423 mess.str("");
424
425 mess << "File";
426 if (this->fileNeedsUpdating())
427 mess << " (needs updating)";
428
429 mess << ": " << this->m_BoxController->getFileIO()->getFileName();
430 out.emplace_back(mess.str());
431 mess.str("");
432 } else {
433 mess << "Not file backed.";
434 out.emplace_back(mess.str());
435 mess.str("");
436 }
437
438 return out;
439}
440
441//-----------------------------------------------------------------------------------------------
443template <typename BOXTYPE> bool SortBoxesByID(const BOXTYPE &a, const BOXTYPE &b) { return a->getID() < b->getID(); }
444
445//-----------------------------------------------------------------------------------------------
447TMDE(Mantid::API::ITableWorkspace_sptr MDEventWorkspace)::makeBoxTable(size_t start, size_t num) {
449 UNUSED_ARG(start);
450 UNUSED_ARG(num);
451
452 // Boxes to show
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());
457
458 std::transform(boxes.cbegin(), boxes.cend(), std::back_inserter(boxes_filtered),
459 [](const auto box) { return dynamic_cast<MDBoxBase<MDE, nd> *>(box); });
460
461 // Now sort by ID
462 using ibox_t = MDBoxBase<MDE, nd> *;
463 std::sort(boxes_filtered.begin(), boxes_filtered.end(), SortBoxesByID<ibox_t>);
464
465 // Create the table
466 int numRows = int(boxes_filtered.size());
467 TableWorkspace_sptr ws(new TableWorkspace(numRows));
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");
478
479 for (int i = 0; i < int(boxes_filtered.size()); i++) {
480 MDBoxBase<MDE, nd> *box = boxes_filtered[i];
481 int col = 0;
482
483 ws->cell<int>(i, col++) = int(box->getID());
484 ;
485 ws->cell<int>(i, col++) = int(box->getDepth());
486 ws->cell<int>(i, col++) = int(box->getNumChildren());
487
488 MDBox<MDE, nd> *mdbox = dynamic_cast<MDBox<MDE, nd> *>(box);
489 Kernel::ISaveable const *const pSaver(box->getISaveable());
490
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");
497
498 bool isDataAdded = (mdbox->isDataAdded());
499 ws->cell<std::string>(i, col++) =
500 std::string(isDataAdded ? "Added " : "") + std::string(pSaver->isBusy() ? "Modif." : "");
501 } else {
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");
505 }
506 ws->cell<std::string>(i, col++) = box->getExtentsStr();
507 }
508 logger.information() << tim << " to create the MDBox data table.\n";
509 return ws;
510}
511
512//-----------------------------------------------------------------------------------------------
514TMDE(size_t MDEventWorkspace)::getMemorySize() const {
515 size_t total = 0;
516 if (this->m_BoxController->isFileBacked()) {
517 // File-backed workspace
518 // How much is in the cache?
519 total = this->m_BoxController->getFileIO()->getWriteBufferUsed() * sizeof(MDE);
520 } else {
521 // All the events
522 total = this->getNPoints() * sizeof(MDE);
523 }
524 // The MDBoxes are always in memory
525 total += this->m_BoxController->getTotalNumMDBoxes() * sizeof(MDBox<MDE, nd>);
526 total += this->m_BoxController->getTotalNumMDGridBoxes() * sizeof(MDGridBox<MDE, nd>);
527 return total;
528}
529
530//-----------------------------------------------------------------------------------------------
537TMDE(size_t MDEventWorkspace)::addEvent(const MDE &event) { return data->addEvent(event); }
538
539//-----------------------------------------------------------------------------------------------
546TMDE(size_t MDEventWorkspace)::addEvents(const std::vector<MDE> &events) { return data->addEvents(events); }
547
548//-----------------------------------------------------------------------------------------------
552TMDE(void MDEventWorkspace)::splitBox() {
553 // Want MDGridBox
554 MDGridBox<MDE, nd> *gridBox = dynamic_cast<MDGridBox<MDE, nd> *>(data.get());
555 if (!gridBox) {
556 // Track how many MDBoxes there are in the overall workspace
557 this->m_BoxController->trackNumBoxes(data->getDepth());
558 MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(data.get());
559 if (!box)
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);
563
564 data = std::move(tempGridBox);
565 }
566}
567
568//-----------------------------------------------------------------------------------------------
575TMDE(void MDEventWorkspace)::splitAllIfNeeded(Kernel::ThreadScheduler *ts) { data->splitAllIfNeeded(ts); }
576
577//-----------------------------------------------------------------------------------------------
583TMDE(void MDEventWorkspace)::splitTrackedBoxes(Kernel::ThreadScheduler *ts) {
584 UNUSED_ARG(ts);
585 throw std::runtime_error("Not implemented yet");
586 // // Get a COPY of the vector (to avoid thread-safety issues)
587 // std::vector<void *> boxes = this->getBoxController()->getBoxesToSplit();
588 // //PRAGMA_OMP( parallel for )
589 // for (int i=0; i<int(boxes.size()); i++)
590 // {
591 // MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(boxes[i]);
592 // if (box)
593 // {
594 // MDGridBox<MDE,nd> * parent = dynamic_cast<MDGridBox<MDE,nd>
595 // *>(box->getParent());
596 // if (parent)
597 // {
598 // parent->splitContents(parent->getChildIndexFromID(box->getId()),
599 // ts);
600 // }
601 // }
602 // }
603}
604
605//-----------------------------------------------------------------------------------------------
609TMDE(void MDEventWorkspace)::refreshCache() {
610 // Function is overloaded and recursive; will check all sub-boxes
611 data->refreshCache();
612 // TODO ThreadPool
613}
614
615//----------------------------------------------------------------------------------------------
626TMDE(std::set<coord_t> MDEventWorkspace)::getBoxBoundaryBisectsOnLine(const Mantid::Kernel::VMD &start,
627 const Mantid::Kernel::VMD &end,
628 const size_t num_d,
629 const Mantid::Kernel::VMD &dir,
630 const coord_t length) const {
631 std::set<coord_t> mid_points;
632
633 // Get the smallest box size along each dimension
634 // We'll assume all boxes are this size and filter out any boundaries
635 // which are not real later (by checking for unique box IDs)
636 std::vector<coord_t> smallest_box_sizes = this->estimateResolution();
637
638 // Next, we go through each dimension and see where the box boundaries
639 // intersect the line.
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];
645
646 // +1 to get the last box
647 size_t num_boundaries = static_cast<size_t>(ceil(std::abs(line_end - line_start) / box_size)) + 1;
648
649 // If the line has some component in this dimension then look for boundaries
650 // it crosses
651 if (dir_current_dim != 0.0) {
652 getBoundariesInDimension(start, dir, num_boundaries, length, dir_current_dim, box_size, mid_points);
653 }
654 }
655 return mid_points;
656}
657
658//----------------------------------------------------------------------------------------------
672TMDE(void MDEventWorkspace)::getBoundariesInDimension(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &dir,
673 const size_t num_boundaries, const coord_t length,
674 const coord_t dir_current_dim, const coord_t box_size,
675 std::set<coord_t> &mid_points) const {
676 auto lastPos = start;
677 coord_t lastLinePos = 0;
678 coord_t previousLinePos = 0;
679 coord_t line_pos_of_box_centre = 0;
680 const API::IMDNode *box = nullptr;
681 auto last_id = std::numeric_limits<size_t>::max();
682
683 for (size_t i = 1; i <= num_boundaries; i++) {
684 size_t current_id = std::numeric_limits<size_t>::max();
685 // Position along the line
686 coord_t this_x = static_cast<coord_t>(i) * box_size;
687 auto linePos = static_cast<coord_t>(this_x / fabs(dir_current_dim));
688 // Full position
689 auto pos = start + (dir * linePos);
690
691 // Get box using midpoint as using boundary would be ambiguous
692 auto middle = (pos + lastPos) * 0.5;
693 box = this->data->getBoxAtCoord(middle.getBareArray());
694 lastPos = pos;
695 if (box != nullptr) {
696 current_id = box->getID();
697 // Make sure we get the last box
698 } else if (i == num_boundaries) {
699 current_id = std::numeric_limits<size_t>::max();
700 } else
701 continue;
702 // If we haven't already a point for this box...
703 // This filters out the extra boundaries that don't really exist that
704 // we gained by assuming all boxes are the size of the smallest box
705 if ((current_id != last_id && i != 1)) {
706 // Check line position is within limits of the line and not too close to
707 // previous position
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);
710 }
711 lastLinePos = previousLinePos;
712 }
713 line_pos_of_box_centre = static_cast<coord_t>((linePos + lastLinePos) * 0.5);
714 previousLinePos = linePos;
715
716 last_id = current_id;
717 }
718}
719
720//-----------------------------------------------------------------------------------------------
730::getLinePlot(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end,
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.");
738
739 // Unit-vector of the direction
740 Mantid::Kernel::VMD dir = end - start;
741 const auto length = dir.normalize();
742
743 const std::set<coord_t> mid_points = getBoxBoundaryBisectsOnLine(start, end, num_dims, dir, length);
744
745 LinePlot line;
746
747 if (mid_points.empty()) {
748 makeSinglePointWithNaN(line.x, line.y, line.e);
749 return line;
750 } else {
751
752 for (const auto &line_pos : mid_points) {
753 // This position in coordinates of the workspace is
754 Mantid::Kernel::VMD ws_pos = start + (dir * line_pos);
755
756 if (isInBounds(ws_pos.getBareArray())) {
757 auto box = this->data->getBoxAtCoord(ws_pos.getBareArray());
758
759 // If the box is not masked then record the signal and error here
760 if (box && !box->getIsMasked()) {
761 line.x.emplace_back(line_pos);
762 signal_t signal = this->getNormalizedSignal(box, normalize);
763 if (std::isinf(signal)) {
764 // The plotting library (qwt) doesn't like infs.
765 signal = std::numeric_limits<signal_t>::quiet_NaN();
766 }
767 line.y.emplace_back(signal);
768 line.e.emplace_back(this->getNormalizedError(box, normalize));
769 }
770 }
771 }
772 }
773
774 // If everything was masked
775 if (line.x.empty()) {
776 makeSinglePointWithNaN(line.x, line.y, line.e);
777 }
778 return line;
779}
780
785TMDE(void MDEventWorkspace)::setMDMasking(std::unique_ptr<Mantid::Geometry::MDImplicitFunction> maskingRegion) {
786 if (maskingRegion) {
787 std::vector<API::IMDNode *> toMaskBoxes;
788
789 // Apply new masks
790 this->data->getBoxes(toMaskBoxes, 10000, true, maskingRegion.get());
791 for (const auto box : toMaskBoxes) {
792 box->clear();
793 box->clearFileBacked(false);
794 box->mask();
795 }
796 }
797}
798
802TMDE(void MDEventWorkspace)::clearMDMasking() {
803 std::vector<API::IMDNode *> allBoxes;
804 // Clear old masks
805 this->data->getBoxes(allBoxes, 10000, true);
806 for (const auto box : allBoxes) {
807 box->unmask();
808 }
809}
810
815TMDE(Kernel::SpecialCoordinateSystem MDEventWorkspace)::getSpecialCoordinateSystem() const {
817 auto coordinatesFromMDFrames = converter(this);
818 auto coordinates = m_coordSystem;
819
820 if (coordinatesFromMDFrames) {
821 coordinates = coordinatesFromMDFrames.value();
822 }
823 return coordinates;
824}
825
830TMDE(void MDEventWorkspace)::setCoordinateSystem(const Kernel::SpecialCoordinateSystem coordSystem) {
831 m_coordSystem = coordSystem;
832}
833
838TMDE(void MDEventWorkspace)::setDisplayNormalizationHisto(
839 const Mantid::API::MDNormalization preferredNormalizationHisto) {
840 m_displayNormalizationHisto = preferredNormalizationHisto;
841}
842
846TMDE(API::MDNormalization MDEventWorkspace)::displayNormalizationHisto() const { return m_displayNormalizationHisto; }
847
852TMDE(void MDEventWorkspace)::setDisplayNormalization(const Mantid::API::MDNormalization preferredNormalization) {
853 m_displayNormalization = preferredNormalization;
854}
855
859TMDE(API::MDNormalization MDEventWorkspace)::displayNormalization() const { return m_displayNormalization; }
860
861} // namespace DataObjects
862
863} // namespace Mantid
#define TMDE(decl)
Macro TMDE to make declaring template functions faster.
Definition MDTypes.h:52
#define fabs(x)
Definition Matrix.cpp:22
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
#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".
Definition MDBoxBase.h:50
std::string getExtentsStr() const
Returns the extents as a string, for convenience.
Definition MDBoxBase.h:188
uint32_t getDepth() const override
For testing, mostly: return the recursion depth of this box.
Definition MDBoxBase.h:286
size_t getID() const override
Definition MDBoxBase.h:71
MDBoxIterator: iterate through MDBoxBase hierarchy down to a given maximum depth.
Templated class for a multi-dimensional event "box".
Definition MDBox.h:45
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".
Definition MDGridBox.h:42
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.
Definition CPUTimer.h:24
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
This class is responsible for memory statistics.
Definition Memory.h:28
std::size_t availMem() const
Returns the available memory of the system in kiB.
Definition Memory.cpp:402
The ThreadScheduler object defines how tasks are allocated to threads and in what order.
TYPE normalize()
Normalize this vector to unity length.
Definition VMD.cpp:427
const TYPE * getBareArray() const
Definition VMD.cpp:248
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.
Definition IMDIterator.h:25
@ VolumeNormalization
Divide the signal by the volume of the box/bin.
Definition IMDIterator.h:29
@ NumEventsNormalization
Divide the signal by the number of events that contributed to it.
Definition IMDIterator.h:31
@ NoNormalization
Don't normalize = return raw counts.
Definition IMDIterator.h:27
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.
Definition V3D.h:352
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.
Holds X, Y, E for a line plot.