Mantid
Loading...
Searching...
No Matches
MDHistoWorkspace.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
16#include "MantidKernel/Utils.h"
17#include "MantidKernel/VMD.h"
19
20#include <boost/optional.hpp>
21#include <boost/scoped_array.hpp>
22#include <cmath>
23#include <map>
24#include <memory>
25
26using namespace Mantid::Kernel;
27using namespace Mantid::Geometry;
28using namespace Mantid::API;
29
30namespace Mantid::DataObjects {
31//----------------------------------------------------------------------------------------------
44 Mantid::API::MDNormalization displayNormalization)
45 : IMDHistoWorkspace(), numDimensions(0), m_nEventsContributed(std::numeric_limits<uint64_t>::quiet_NaN()),
46 m_coordSystem(None), m_displayNormalization(displayNormalization) {
47 std::vector<Mantid::Geometry::MDHistoDimension_sptr> dimensions;
48 if (dimX)
49 dimensions.emplace_back(std::move(dimX));
50 if (dimY)
51 dimensions.emplace_back(std::move(dimY));
52 if (dimZ)
53 dimensions.emplace_back(std::move(dimZ));
54 if (dimT)
55 dimensions.emplace_back(std::move(dimT));
56 this->init(dimensions);
57}
58
59//----------------------------------------------------------------------------------------------
65MDHistoWorkspace::MDHistoWorkspace(std::vector<Mantid::Geometry::MDHistoDimension_sptr> &dimensions,
66 Mantid::API::MDNormalization displayNormalization)
67 : IMDHistoWorkspace(), numDimensions(0), m_nEventsContributed(std::numeric_limits<uint64_t>::quiet_NaN()),
68 m_coordSystem(None), m_displayNormalization(displayNormalization) {
69 this->init(dimensions);
70}
71
72//----------------------------------------------------------------------------------------------
78MDHistoWorkspace::MDHistoWorkspace(std::vector<Mantid::Geometry::IMDDimension_sptr> &dimensions,
79 Mantid::API::MDNormalization displayNormalization)
80 : IMDHistoWorkspace(), numDimensions(0), m_nEventsContributed(std::numeric_limits<uint64_t>::quiet_NaN()),
81 m_coordSystem(None), m_displayNormalization(displayNormalization) {
82 this->init(dimensions);
83}
84
85//----------------------------------------------------------------------------------------------
91 : IMDHistoWorkspace(other), m_nEventsContributed(other.m_nEventsContributed), m_coordSystem(other.m_coordSystem),
92 m_displayNormalization(other.m_displayNormalization) {
93 // Dimensions are copied by the copy constructor of MDGeometry
94 this->cacheValues();
95 // Allocate the linear arrays
96 m_signals = std::vector<signal_t>(m_length);
97 m_errorsSquared = std::vector<signal_t>(m_length);
98 m_numEvents = std::vector<signal_t>(m_length);
99 m_masks = std::make_unique<bool[]>(m_length);
100 // Now copy all the data
101 std::copy_n(other.m_signals.begin(), m_length, m_signals.begin());
102 std::copy_n(other.m_errorsSquared.begin(), m_length, m_errorsSquared.begin());
103 std::copy_n(other.m_numEvents.begin(), m_length, m_numEvents.begin());
104 std::copy_n(other.m_masks.get(), m_length, m_masks.get());
105}
106
107//----------------------------------------------------------------------------------------------
111void MDHistoWorkspace::init(std::vector<Mantid::Geometry::MDHistoDimension_sptr> &dimensions) {
112 std::vector<IMDDimension_sptr> dim2;
113 dim2.reserve(dimensions.size());
114 std::transform(dimensions.cbegin(), dimensions.cend(), std::back_inserter(dim2),
115 [](const auto dimension) { return std::dynamic_pointer_cast<IMDDimension>(dimension); });
116 this->init(dim2);
118}
119
120//----------------------------------------------------------------------------------------------
124void MDHistoWorkspace::init(std::vector<Mantid::Geometry::IMDDimension_sptr> &dimensions) {
125 MDGeometry::initGeometry(dimensions);
126 this->cacheValues();
127
128 // Allocate the linear arrays
129 m_signals = std::vector<signal_t>(m_length);
130 m_errorsSquared = std::vector<signal_t>(m_length);
131 m_numEvents = std::vector<signal_t>(m_length);
132 m_masks = std::make_unique<bool[]>(m_length);
133 // Initialize them to NAN (quickly)
134 signal_t nan = std::numeric_limits<signal_t>::quiet_NaN();
135 this->setTo(nan, nan, nan);
137}
138
139//----------------------------------------------------------------------------------------------
144 // Copy the dimensions array
146
147 // For indexing.
148 if (numDimensions < 4)
149 indexMultiplier = std::vector<size_t>(4);
150 else
151 indexMultiplier = std::vector<size_t>(numDimensions);
152
153 // For quick indexing, accumulate these values
154 // First multiplier
155 indexMultiplier[0] = m_dimensions[0]->getNBins();
156 for (size_t d = 1; d < numDimensions; d++)
157 indexMultiplier[d] = indexMultiplier[d - 1] * m_dimensions[d]->getNBins();
158
159 // This is how many dense data points
161
162 // Now fix things for < 4 dimensions. Indices > the number of dimensions will
163 // be ignored (*0)
164 for (size_t d = numDimensions - 1; d < 4; d++)
165 indexMultiplier[d] = 0;
166
167 // Compute the volume of each cell.
168 coord_t volume = 1.0;
169 for (size_t i = 0; i < numDimensions; ++i)
170 volume *= m_dimensions[i]->getBinWidth();
171 m_inverseVolume = 1.0f / volume;
172
173 // Continue with the vertexes array
174 this->initVertexesArray();
176}
177//----------------------------------------------------------------------------------------------
183 size_t nd = numDimensions;
184 // How many vertices does one box have? 2^nd, or bitwise shift left 1 by nd
185 // bits
186 size_t numVertices = size_t{1} << numDimensions;
187
188 // Allocate the array of the right size
189 m_vertexesArray = std::vector<coord_t>(nd * numVertices);
190
191 // For each vertex, increase an integeer
192 for (size_t i = 0; i < numVertices; ++i) {
193 // Start point index in the output array;
194 size_t outIndex = i * nd;
195
196 // Coordinates of the vertex
197 for (size_t d = 0; d < nd; d++) {
198 // Use a bit mask to look at each bit of the integer we are iterating
199 // through.
200 size_t mask = size_t{1} << d;
201 if ((i & mask) > 0) {
202 // Bit is 1, use the max of the dimension
203 m_vertexesArray[outIndex + d] = m_dimensions[d]->getX(1);
204 } else {
205 // Bit is 0, use the min of the dimension
206 m_vertexesArray[outIndex + d] = m_dimensions[d]->getX(0);
207 }
208 } // (for each dimension)
209 }
210
211 // Now set the m_boxLength and origin
212 m_boxLength = std::vector<coord_t>(nd);
213 m_origin = std::vector<coord_t>(nd);
214 for (size_t d = 0; d < nd; d++) {
215 m_boxLength[d] = m_dimensions[d]->getX(1) - m_dimensions[d]->getX(0);
216 m_origin[d] = m_dimensions[d]->getX(0);
217 }
218
219 // The index calculator
220 m_indexMax = std::vector<size_t>(numDimensions);
221 for (size_t d = 0; d < nd; d++)
222 m_indexMax[d] = m_dimensions[d]->getNBins();
223 m_indexMaker = std::vector<size_t>(numDimensions);
225}
226
227//----------------------------------------------------------------------------------------------
235 std::fill_n(m_signals.begin(), m_length, signal);
236 std::fill_n(m_errorsSquared.begin(), m_length, errorSquared);
237 std::fill_n(m_numEvents.begin(), m_length, numEvents);
238 std::fill_n(m_masks.get(), m_length, false);
239 m_nEventsContributed = static_cast<uint64_t>(numEvents) * m_length;
240}
241
242//----------------------------------------------------------------------------------------------
250 signal_t errorSquared) {
251 if (numDimensions < 3)
252 throw std::invalid_argument("Need 3 dimensions for ImplicitFunction.");
253 Mantid::coord_t coord[3];
254 for (size_t x = 0; x < m_dimensions[0]->getNBins(); x++) {
255 coord[0] = m_dimensions[0]->getX(x);
256 for (size_t y = 0; y < m_dimensions[1]->getNBins(); y++) {
257 coord[1] = m_dimensions[1]->getX(y);
258 for (size_t z = 0; z < m_dimensions[2]->getNBins(); z++) {
259 coord[2] = m_dimensions[2]->getX(z);
260
261 if (!function->isPointContained(coord)) {
262 m_signals[x + indexMultiplier[0] * y + indexMultiplier[1] * z] = signal;
263 m_errorsSquared[x + indexMultiplier[0] * y + indexMultiplier[1] * z] = errorSquared;
264 }
265 }
266 }
267 }
268}
269
270//----------------------------------------------------------------------------------------------
280std::unique_ptr<coord_t[]> MDHistoWorkspace::getVertexesArray(size_t linearIndex, size_t &numVertices) const {
281 // How many vertices does one box have? 2^nd, or bitwise shift left 1 by nd
282 // bits
283 numVertices = static_cast<size_t>(1) << numDimensions; // Cast avoids warning about
284 // result of 32-bit shift
285 // implicitly converted to 64 bits
286 // on MSVC
287
288 // Index into each dimension. Built from the linearIndex.
289 size_t dimIndexes[10];
291 dimIndexes);
292
293 // The output vertexes coordinates
294 auto out = std::make_unique<coord_t[]>(numDimensions * numVertices);
295 for (size_t i = 0; i < numVertices; ++i) {
296 size_t outIndex = i * numDimensions;
297 // Offset the 0th box by the position of this linear index, in each
298 // dimension
299 for (size_t d = 0; d < numDimensions; d++)
300 out[outIndex + d] = m_vertexesArray[outIndex + d] + m_boxLength[d] * static_cast<coord_t>(dimIndexes[d]);
301 }
302
303 return out;
304}
305
306//----------------------------------------------------------------------------------------------
313 // Index into each dimension. Built from the linearIndex.
314 size_t dimIndexes[10];
316 dimIndexes);
317
318 // The output vertexes coordinates
319 VMD out(numDimensions);
320 // Offset the 0th box by the position of this linear index, in each dimension,
321 // plus a half
322 for (size_t d = 0; d < numDimensions; d++)
323 out[d] = m_vertexesArray[d] + m_boxLength[d] * (static_cast<coord_t>(dimIndexes[d]) + 0.5f);
324 return out;
325}
326
327//----------------------------------------------------------------------------------------------
336 const Mantid::API::MDNormalization &normalization) const {
337 size_t linearIndex = this->getLinearIndexAtCoord(coords);
338 if (linearIndex < m_length) {
339 signal_t normalizer = getNormalizationFactor(normalization, linearIndex);
340 return m_signals[linearIndex] * normalizer;
341 } else
342 return std::numeric_limits<signal_t>::quiet_NaN();
343}
344
345//----------------------------------------------------------------------------------------------
355 const Mantid::API::MDNormalization &normalization) const {
356 size_t linearIndex = this->getLinearIndexAtCoord(coords);
357 if (linearIndex == std::numeric_limits<size_t>::max() || this->getIsMaskedAt(linearIndex)) {
358 return MDMaskValue;
359 }
360 return getSignalAtCoord(coords, normalization);
361}
362
363//----------------------------------------------------------------------------------------------
370 // Build up the linear index, dimension by dimension
371 size_t linearIndex = 0;
372 for (size_t d = 0; d < numDimensions; d++) {
373 coord_t x = coords[d] - m_origin[d];
374 auto ix = size_t(x / m_boxLength[d]);
375 if (ix >= m_indexMax[d] || (x < 0))
376 return size_t(-1);
377 linearIndex += ix * m_indexMaker[d];
378 }
379 return linearIndex;
380}
381
382//----------------------------------------------------------------------------------------------
391std::vector<std::unique_ptr<Mantid::API::IMDIterator>>
393 size_t numCores = suggestedNumCores;
394 if (!this->threadSafe())
395 numCores = 1;
396 size_t numElements = this->getNPoints();
397 if (numCores > numElements)
398 numCores = numElements;
399 if (numCores < 1)
400 numCores = 1;
401
402 // Create one iterator per core, splitting evenly amongst spectra
403 std::vector<std::unique_ptr<IMDIterator>> out;
404 for (size_t i = 0; i < numCores; i++) {
405 size_t begin = (i * numElements) / numCores;
406 size_t end = ((i + 1) * numElements) / numCores;
407 if (end > numElements)
408 end = numElements;
409
410 // Clone the MDImplicitFunction if necessary.
411 Mantid::Geometry::MDImplicitFunction *clonedFunction = function;
412 if (function)
413 clonedFunction = new Mantid::Geometry::MDImplicitFunction(*function);
414
415 out.emplace_back(std::make_unique<MDHistoWorkspaceIterator>(this, clonedFunction, begin, end));
416 }
417 return out;
418}
419
420//----------------------------------------------------------------------------------------------
423
424//----------------------------------------------------------------------------------------------
426std::vector<signal_t> MDHistoWorkspace::getSignalDataVector() const {
427 std::vector<signal_t> out;
428 out.resize(m_length, 0.0);
429 for (size_t i = 0; i < m_length; ++i)
430 out[i] = m_signals[i];
431 // This copies again! :(
432 return out;
433}
434
436std::vector<signal_t> MDHistoWorkspace::getErrorDataVector() const {
437 std::vector<signal_t> out;
438 out.resize(m_length, 0.0);
439 for (size_t i = 0; i < m_length; ++i)
440 out[i] = m_errorsSquared[i];
441 // This copies again! :(
442 return out;
443}
444
447bool pointInWorkspace(const MDHistoWorkspace *ws, const VMD &point) {
448 for (size_t d = 0; d < ws->getNumDims(); d++) {
450 if ((point[d] < dim->getMinimum()) || (point[d] > dim->getMaximum()))
451 return false;
452 }
453 return true;
454}
455
456//----------------------------------------------------------------------------------------------
470
471 return this->getLinePoints(start, end, normalize, true);
472}
473
474//----------------------------------------------------------------------------------------------
492 const bool bin_centres) const {
493 LinePlot line;
494
495 size_t nd = this->getNumDims();
496 if (start.getNumDims() != nd)
497 throw std::runtime_error("Start point must have the same number of "
498 "dimensions as the workspace.");
499 if (end.getNumDims() != nd)
500 throw std::runtime_error("End point must have the same number of dimensions as the workspace.");
501
502 // Unit-vector of the direction
503 VMD dir = end - start;
504 const auto length = dir.normalize();
505
506 const std::set<coord_t> boundaries = getBinBoundariesOnLine(start, end, nd, dir, length);
507
508 if (boundaries.empty()) {
509 this->makeSinglePointWithNaN(line.x, line.y, line.e);
510
511 // Require x.size() = y.size()+1 if recording bin boundaries
512 if (!bin_centres)
513 line.x.emplace_back(length);
514
515 return line;
516 } else {
517 // Get the first point
518 std::set<coord_t>::iterator it;
519 it = boundaries.cbegin();
520
521 coord_t lastLinePos = *it;
522 VMD lastPos = start + (dir * lastLinePos);
523 if (!bin_centres) {
524 line.x.emplace_back(lastLinePos);
525 }
526
527 ++it;
528 for (; it != boundaries.cend(); ++it) {
529 // This is our current position along the line
530 const coord_t linePos = *it;
531
532 // This is the full position at this boundary
533 VMD pos = start + (dir * linePos);
534
535 // Position in the middle of the bin
536 VMD middle = (pos + lastPos) * 0.5;
537
538 // Find the signal in this bin
539 const auto linearIndex = this->getLinearIndexAtCoord(middle.getBareArray());
540
541 if (bin_centres && !(linearIndex == std::numeric_limits<size_t>::max() || this->getIsMaskedAt(linearIndex))) {
542 auto bin_centrePos = static_cast<coord_t>((linePos + lastLinePos) * 0.5);
543 line.x.emplace_back(bin_centrePos);
544 } else if (!bin_centres)
545 line.x.emplace_back(linePos);
546
547 if (linearIndex < m_length) {
548
549 auto normalizer = getNormalizationFactor(normalize, linearIndex);
550 // And add the normalized signal/error to the list too
551 auto signal = this->getSignalAt(linearIndex) * normalizer;
552 if (std::isinf(signal)) {
553 // The plotting library (qwt) doesn't like infs.
554 signal = std::numeric_limits<signal_t>::quiet_NaN();
555 }
556 if (!bin_centres || !this->getIsMaskedAt(linearIndex)) {
557 line.y.emplace_back(signal);
558 line.e.emplace_back(this->getErrorAt(linearIndex) * normalizer);
559 }
560 // Save the position for next bin
561 lastPos = pos;
562 } else {
563 // Invalid index. This shouldn't happen
564 line.y.emplace_back(std::numeric_limits<signal_t>::quiet_NaN());
565 line.e.emplace_back(std::numeric_limits<signal_t>::quiet_NaN());
566 }
567
568 lastLinePos = linePos;
569
570 } // for each unique boundary
571
572 // If all bins were masked
573 if (line.x.empty()) {
574 this->makeSinglePointWithNaN(line.x, line.y, line.e);
575 }
576 }
577 return line;
578}
579
580//----------------------------------------------------------------------------------------------
593 return this->getLinePoints(start, end, normalize, false);
594}
595
596//----------------------------------------------------------------------------------------------
605 signal_t normalizer = 1.0;
606 switch (normalize) {
607 case NoNormalization:
608 return normalizer;
610 return m_inverseVolume;
612 return 1.0 / m_numEvents[linearIndex];
613 }
614 return normalizer;
615}
616
617//----------------------------------------------------------------------------------------------
627std::set<coord_t> MDHistoWorkspace::getBinBoundariesOnLine(const VMD &start, const VMD &end, size_t nd, const VMD &dir,
628 coord_t length) const {
629 std::set<coord_t> boundaries;
630
631 // Start with the start/end points, if they are within range.
632 if (pointInWorkspace(this, start))
633 boundaries.insert(0.0f);
634 if (pointInWorkspace(this, end))
635 boundaries.insert(length);
636
637 // Next, we go through each dimension and see where the bin boundaries
638 // intersect the line.
639 for (size_t d = 0; d < nd; d++) {
641 coord_t lineStartX = start[d];
642
643 if (dir[d] != 0.0) {
644 auto nbounds = dim->getNBoundaries();
645 for (size_t i = 0; i < nbounds; i++) {
646 // Position in this coordinate
647 coord_t thisX = dim->getX(i);
648 // Position along the line. Is this between the start and end of it?
649 coord_t linePos = (thisX - lineStartX) / dir[d];
650 if (linePos >= 0 && linePos <= length) {
651 // Full position
652 VMD pos = start + (dir * linePos);
653 // This is a boundary if the line point is inside the workspace
654 if (pointInWorkspace(this, pos))
655 boundaries.insert(linePos);
656 }
657 }
658 }
659 }
660 return boundaries;
661}
662
663//==============================================================================================
664//============================== ARITHMETIC OPERATIONS
665//=========================================
666//==============================================================================================
667
668//----------------------------------------------------------------------------------------------
676void MDHistoWorkspace::checkWorkspaceSize(const MDHistoWorkspace &other, const std::string &operation) {
677 if (other.getNumDims() != this->getNumDims())
678 throw std::invalid_argument("Cannot perform the " + operation +
679 " operation on this MDHistoWorkspace. The "
680 "number of dimensions does not match.");
681 if (other.m_length != this->m_length)
682 throw std::invalid_argument("Cannot perform the " + operation +
683 " operation on this MDHistoWorkspace. The "
684 "length of the signals vector does not match.");
685}
686
687//----------------------------------------------------------------------------------------------
693 add(b);
694 return *this;
695}
696
697//----------------------------------------------------------------------------------------------
703 checkWorkspaceSize(b, "add");
704 for (size_t i = 0; i < m_length; ++i) {
705 m_signals[i] += b.m_signals[i];
707 m_numEvents[i] += b.m_numEvents[i];
708 }
710}
711
712//----------------------------------------------------------------------------------------------
718void MDHistoWorkspace::add(const signal_t signal, const signal_t error) {
719 signal_t errorSquared = error * error;
720 for (size_t i = 0; i < m_length; ++i) {
721 m_signals[i] += signal;
722 m_errorsSquared[i] += errorSquared;
723 }
724}
725
726//----------------------------------------------------------------------------------------------
732 subtract(b);
733 return *this;
734}
735
736//----------------------------------------------------------------------------------------------
742 checkWorkspaceSize(b, "subtract");
743 for (size_t i = 0; i < m_length; ++i) {
744 m_signals[i] -= b.m_signals[i];
746 m_numEvents[i] += b.m_numEvents[i];
747 }
749}
750
751//----------------------------------------------------------------------------------------------
758 signal_t errorSquared = error * error;
759 for (size_t i = 0; i < m_length; ++i) {
760 m_signals[i] -= signal;
761 m_errorsSquared[i] += errorSquared;
762 }
763}
764
765//----------------------------------------------------------------------------------------------
774 multiply(b_ws);
775 return *this;
776}
777
778//----------------------------------------------------------------------------------------------
790 checkWorkspaceSize(b_ws, "multiply");
791 for (size_t i = 0; i < m_length; ++i) {
792 signal_t a = m_signals[i];
793 signal_t da2 = m_errorsSquared[i];
794
795 signal_t b = b_ws.m_signals[i];
796 signal_t db2 = b_ws.m_errorsSquared[i];
797
798 signal_t f = a * b;
799 signal_t df2 = da2 * b * b + db2 * a * a;
800
801 m_signals[i] = f;
802 m_errorsSquared[i] = df2;
803 }
804}
805
806//----------------------------------------------------------------------------------------------
819 signal_t b = signal;
820 signal_t db2 = error * error;
821
822 for (size_t i = 0; i < m_length; ++i) {
823 signal_t a = m_signals[i];
824 signal_t da2 = m_errorsSquared[i];
825
826 signal_t f = a * b;
827 signal_t df2 = da2 * b * b + db2 * a * a;
828
829 m_signals[i] = f;
830 m_errorsSquared[i] = df2;
831 }
832}
833
834//----------------------------------------------------------------------------------------------
843 divide(b_ws);
844 return *this;
845}
846
847//----------------------------------------------------------------------------------------------
859 checkWorkspaceSize(b_ws, "divide");
860 for (size_t i = 0; i < m_length; ++i) {
861 signal_t a = m_signals[i];
862 signal_t da2 = m_errorsSquared[i];
863
864 signal_t b = b_ws.m_signals[i];
865 signal_t db2 = b_ws.m_errorsSquared[i];
866
867 signal_t f = a / b;
868 signal_t df2 = da2 / (b * b) + db2 * f * f / (b * b);
869
870 m_signals[i] = f;
871 m_errorsSquared[i] = df2;
872 }
873}
874
875//----------------------------------------------------------------------------------------------
888 signal_t b = signal;
889 signal_t db2 = error * error;
890 signal_t db2_relative = db2 / (b * b);
891 for (size_t i = 0; i < m_length; ++i) {
892 signal_t a = m_signals[i];
893 signal_t da2 = m_errorsSquared[i];
894
895 signal_t f = a / b;
896 signal_t df2 = da2 / (b * b) + db2_relative * f * f;
897
898 m_signals[i] = f;
899 m_errorsSquared[i] = df2;
900 }
901}
902
903//----------------------------------------------------------------------------------------------
909void MDHistoWorkspace::log(double filler) {
910 for (size_t i = 0; i < m_length; ++i) {
911 signal_t a = m_signals[i];
912 signal_t da2 = m_errorsSquared[i];
913 if (a <= 0) {
914 m_signals[i] = filler;
915 m_errorsSquared[i] = 0;
916 } else {
917 m_signals[i] = std::log(a);
918 m_errorsSquared[i] = da2 / (a * a);
919 }
920 }
921}
922
923//----------------------------------------------------------------------------------------------
929void MDHistoWorkspace::log10(double filler) {
930 for (size_t i = 0; i < m_length; ++i) {
931 signal_t a = m_signals[i];
932 signal_t da2 = m_errorsSquared[i];
933 if (a <= 0) {
934 m_signals[i] = filler;
935 m_errorsSquared[i] = 0;
936 } else {
937 m_signals[i] = std::log10(a);
938 m_errorsSquared[i] = 0.1886117 * da2 / (a * a); // 0.1886117 = ln(10)^-2
939 }
940 }
941}
942
943//----------------------------------------------------------------------------------------------
950 for (size_t i = 0; i < m_length; ++i) {
951 signal_t f = std::exp(m_signals[i]);
952 signal_t da2 = m_errorsSquared[i];
953 m_signals[i] = f;
954 m_errorsSquared[i] = f * f * da2;
955 }
956}
957
958//----------------------------------------------------------------------------------------------
965void MDHistoWorkspace::power(double exponent) {
966 double exponent_squared = exponent * exponent;
967 for (size_t i = 0; i < m_length; ++i) {
968 signal_t a = m_signals[i];
969 signal_t f = std::pow(a, exponent);
970 signal_t da2 = m_errorsSquared[i];
971 m_signals[i] = f;
972 m_errorsSquared[i] = f * f * exponent_squared * da2 / (a * a);
973 }
974}
975
976//==============================================================================================
977//============================== BOOLEAN OPERATIONS
978//============================================
979//==============================================================================================
980
981//----------------------------------------------------------------------------------------------
983
991 checkWorkspaceSize(b, "&= (and)");
992 for (size_t i = 0; i < m_length; ++i) {
993 m_signals[i] = ((m_signals[i] != 0 && !m_masks[i]) && (b.m_signals[i] != 0 && !b.m_masks[i])) ? 1.0 : 0.0;
994 m_errorsSquared[i] = 0;
995 }
996 return *this;
997}
999
1000//----------------------------------------------------------------------------------------------
1008 checkWorkspaceSize(b, "|= (or)");
1009 for (size_t i = 0; i < m_length; ++i) {
1010 m_signals[i] = ((m_signals[i] != 0 && !m_masks[i]) || (b.m_signals[i] != 0 && !b.m_masks[i])) ? 1.0 : 0.0;
1011 m_errorsSquared[i] = 0;
1012 }
1013 return *this;
1014}
1015
1016//----------------------------------------------------------------------------------------------
1025 checkWorkspaceSize(b, "^= (xor)");
1026 for (size_t i = 0; i < m_length; ++i) {
1027 m_signals[i] = ((m_signals[i] != 0 && !m_masks[i]) ^ (b.m_signals[i] != 0 && !b.m_masks[i])) ? 1.0 : 0.0;
1028 m_errorsSquared[i] = 0;
1029 }
1030 return *this;
1031}
1032
1033//----------------------------------------------------------------------------------------------
1040 for (size_t i = 0; i < m_length; ++i) {
1041 m_signals[i] = (m_signals[i] == 0.0 || m_masks[i]) ? 1.0 : 0.0;
1042 m_errorsSquared[i] = 0.0;
1043 }
1044}
1045
1046//----------------------------------------------------------------------------------------------
1055 checkWorkspaceSize(b, "lessThan");
1056 for (size_t i = 0; i < m_length; ++i) {
1057 m_signals[i] = (m_signals[i] < b.m_signals[i]) ? 1.0 : 0.0;
1058 m_errorsSquared[i] = 0.0;
1059 }
1060}
1061
1062//----------------------------------------------------------------------------------------------
1071 for (size_t i = 0; i < m_length; ++i) {
1072 m_signals[i] = (m_signals[i] < signal) ? 1.0 : 0.0;
1073 m_errorsSquared[i] = 0.0;
1074 }
1075}
1076
1077//----------------------------------------------------------------------------------------------
1086 checkWorkspaceSize(b, "greaterThan");
1087 for (size_t i = 0; i < m_length; ++i) {
1088 m_signals[i] = (m_signals[i] > b.m_signals[i]) ? 1.0 : 0.0;
1089 m_errorsSquared[i] = 0;
1090 }
1091}
1092
1093//----------------------------------------------------------------------------------------------
1102 for (size_t i = 0; i < m_length; ++i) {
1103 m_signals[i] = (m_signals[i] > signal) ? 1.0 : 0.0;
1104 m_errorsSquared[i] = 0;
1105 }
1106}
1107
1108//----------------------------------------------------------------------------------------------
1118 checkWorkspaceSize(b, "equalTo");
1119 for (size_t i = 0; i < m_length; ++i) {
1120 signal_t diff = fabs(m_signals[i] - b.m_signals[i]);
1121 m_signals[i] = (diff < tolerance) ? 1.0 : 0.0;
1122 m_errorsSquared[i] = 0;
1123 }
1124}
1125
1126//----------------------------------------------------------------------------------------------
1136 for (size_t i = 0; i < m_length; ++i) {
1137 signal_t diff = fabs(m_signals[i] - signal);
1138 m_signals[i] = (diff < tolerance) ? 1.0 : 0.0;
1139 m_errorsSquared[i] = 0;
1140 }
1141}
1142
1143//----------------------------------------------------------------------------------------------
1160 checkWorkspaceSize(mask, "setUsingMask");
1161 checkWorkspaceSize(values, "setUsingMask");
1162 for (size_t i = 0; i < m_length; ++i) {
1163 if (mask.m_signals[i] != 0.0) {
1164 m_signals[i] = values.m_signals[i];
1165 m_errorsSquared[i] = values.m_errorsSquared[i];
1166 }
1167 }
1168}
1169
1170//----------------------------------------------------------------------------------------------
1188 signal_t errorSquared = error * error;
1189 checkWorkspaceSize(mask, "setUsingMask");
1190 for (size_t i = 0; i < m_length; ++i) {
1191 if (mask.m_signals[i] != 0.0) {
1192 m_signals[i] = signal;
1193 m_errorsSquared[i] = errorSquared;
1194 }
1195 }
1196}
1197
1203void MDHistoWorkspace::setMDMasking(std::unique_ptr<Mantid::Geometry::MDImplicitFunction> maskingRegion) {
1204 if (maskingRegion != nullptr) {
1205 for (size_t i = 0; i < this->getNPoints(); ++i) {
1206 // If the function masks the point, then mask it, otherwise leave it as it
1207 // is.
1208 if (maskingRegion->isPointContained(this->getCenter(i))) {
1209 this->setMDMaskAt(i, true);
1210 }
1211 }
1212 }
1213}
1214
1220void MDHistoWorkspace::setMDMaskAt(const size_t &index, bool mask) {
1221 m_masks[index] = mask;
1222 if (mask) {
1223 // Set signal and error of masked points to the value of MDMaskValue
1224 this->setSignalAt(index, MDMaskValue);
1225 this->setErrorSquaredAt(index, MDMaskValue);
1226 }
1227}
1228
1235 for (size_t i = 0; i < this->getNPoints(); ++i) {
1236 m_masks[i] = false;
1237 }
1238}
1239
1241 volatile uint64_t cach = this->m_nEventsContributed;
1242 if (cach != this->m_nEventsContributed) {
1243 if (m_numEvents.empty())
1244 m_nEventsContributed = std::numeric_limits<uint64_t>::quiet_NaN();
1245 else
1247 }
1248 return m_nEventsContributed;
1249}
1250
1252 uint64_t sum(0);
1253 for (size_t i = 0; i < m_length; ++i)
1254 sum += uint64_t(m_numEvents[i]);
1255
1256 return sum;
1257}
1258
1262GNU_DIAG_OFF("strict-aliasing")
1263Kernel::SpecialCoordinateSystem MDHistoWorkspace::getSpecialCoordinateSystem() const {
1265 auto coordinatesFromMDFrames = converter(this);
1266 auto coordinates = m_coordSystem;
1267 if (coordinatesFromMDFrames) {
1268 coordinates = coordinatesFromMDFrames.get();
1269 }
1270 return coordinates;
1271}
1272
1278 m_coordSystem = coordinateSystem;
1279}
1280
1285size_t MDHistoWorkspace::sizeOfElement() { return (3 * sizeof(signal_t)) + sizeof(bool); }
1286
1291 return m_displayNormalization; // Normalize by the number of events.
1292}
1293
1298 return displayNormalization(); // Normalize by the number of events.
1299}
1300
1302 m_displayNormalization = preferredNormalization;
1303}
1304
1305} // namespace Mantid::DataObjects
double error
Definition: IndexPeaks.cpp:133
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define fabs(x)
Definition: Matrix.cpp:22
double tolerance
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
Abstract interface to MDHistoWorkspace, for use in exposing to Python.
void makeSinglePointWithNaN(std::vector< coord_t > &x, std::vector< signal_t > &y, std::vector< signal_t > &e) const
Make a single point with NaN as the signal and error This can be returned when there would otherwise ...
void initGeometry(const std::vector< std::shared_ptr< Geometry::IMDDimension > > &dimensions)
Initialize the geometry.
Definition: MDGeometry.cpp:139
virtual std::shared_ptr< const Mantid::Geometry::IMDDimension > getDimension(size_t index) const
Get a dimension.
Definition: MDGeometry.cpp:161
std::vector< std::shared_ptr< Geometry::IMDDimension > > m_dimensions
Vector of the dimensions used, in the order X Y Z t, etc.
Definition: MDGeometry.h:123
virtual size_t getNumDims() const
Definition: MDGeometry.cpp:148
bool threadSafe() const override
Marks the workspace as safe for multiple threads to edit data simutaneously.
Definition: Workspace.h:67
MDFrameFromMDWorkspace: Each dimension of the MDWorkspace contains an MDFrame.
MDHistoWorkspace & operator*=(const MDHistoWorkspace &b_ws)
Perform the *= operation, element-by-element, for two MDHistoWorkspace's.
virtual std::vector< signal_t > getErrorDataVector() const
size_t getLinearIndexAtCoord(const coord_t *coords) const
Get the linear index into the histo array at these coordinates.
coord_t m_inverseVolume
Inverse of the volume of EACH cell.
uint64_t sumNContribEvents() const
sum the array of contributing events m_numEvents array
std::unique_ptr< bool[]> m_masks
Linear array of masks for each bin.
void init(std::vector< Mantid::Geometry::MDHistoDimension_sptr > &dimensions)
Constructor helper method.
void clearMDMasking() override
Clear masking.
MDHistoWorkspace & operator^=(const MDHistoWorkspace &b)
A boolean ^= (xor) operation, element-by-element, for two MDHistoWorkspace's.
virtual std::vector< signal_t > getSignalDataVector() const
Return a vector containing a copy of the signal data in the workspace.
LinePlot getLinePlot(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize) const override
Obtain coordinates for a line plot through a MDWorkspace.
Kernel::VMD getCenter(size_t linearIndex) const override
Return the position of the center of a bin at a given position.
signal_t getSignalAtCoord(const coord_t *coords, const Mantid::API::MDNormalization &normalization) const override
Returns the (normalized) signal at a given coordinates.
MDHistoWorkspace(Mantid::Geometry::MDHistoDimension_sptr dimX, Mantid::Geometry::MDHistoDimension_sptr dimY=Mantid::Geometry::MDHistoDimension_sptr(), Mantid::Geometry::MDHistoDimension_sptr dimZ=Mantid::Geometry::MDHistoDimension_sptr(), Mantid::Geometry::MDHistoDimension_sptr dimT=Mantid::Geometry::MDHistoDimension_sptr(), Mantid::API::MDNormalization displayNormalization=Mantid::API::NoNormalization)
Constructor given the 4 dimensions.
LinePlot getLineData(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize) const override
Obtain coordinates for a line plot through a MDWorkspace.
std::vector< size_t > m_indexMax
Max index into each dimension.
size_t getMemorySize() const override
Return the memory used, in bytes.
void setDisplayNormalization(const Mantid::API::MDNormalization &preferredNormalization) override
size_t numDimensions
Number of dimensions in this workspace.
void equalTo(const MDHistoWorkspace &b, const signal_t tolerance=1e-5)
Turn this workspace into a boolean workspace, where signal[i] -> becomes true (1.0) if it is == b[i].
signal_t getErrorAt(size_t index) const override
Get the error of the signal at the specified index.
void subtract(const MDHistoWorkspace &b)
Perform the -= operation, element-by-element, for two MDHistoWorkspace's.
LinePlot getLinePoints(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize, const bool bin_centres) const
Obtain coordinates for a line plot through a MDWorkspace.
void setCoordinateSystem(const Kernel::SpecialCoordinateSystem coordinateSystem) override
Set the special coordinate system.
void applyImplicitFunction(Mantid::Geometry::MDImplicitFunction *function, signal_t signal, signal_t errorSquared)
Apply an implicit function to each point; if false, set to the given value.
std::set< coord_t > getBinBoundariesOnLine(const Kernel::VMD &start, const Kernel::VMD &end, size_t nd, const Kernel::VMD &dir, coord_t length) const
Get ordered list of boundaries in position-along-the-line coordinates.
Mantid::API::MDNormalization displayNormalization() const override
Preferred visual normalization method.
Mantid::API::MDNormalization displayNormalizationHisto() const override
Preferred visual normalization method.
void power(double exponent)
Perform the power function (signal^exponent) on each signal S in the workspace.
signal_t getSignalAt(size_t index) const override
Get the signal at the specified index.
std::vector< coord_t > m_origin
Vector of the origin in each dimension.
static size_t sizeOfElement()
Get the size of an element in the HistoWorkspace.
std::vector< std::unique_ptr< Mantid::API::IMDIterator > > createIterators(size_t suggestedNumCores=1, Mantid::Geometry::MDImplicitFunction *function=nullptr) const override
Create IMDIterators from this MDHistoWorkspace.
signal_t getNormalizationFactor(const API::MDNormalization &normalize, size_t linearIndex) const
Find the normalization factor.
uint64_t m_nEventsContributed
the number of events, contributed into the workspace;
MDHistoWorkspace & operator+=(const MDHistoWorkspace &b)
Perform the += operation, element-by-element, for two MDHistoWorkspace's.
uint64_t getNPoints() const override
Get the number of points (bins in this case) associated with the workspace;.
std::vector< signal_t > m_errorsSquared
Linear array of errors for each bin.
std::vector< coord_t > m_boxLength
Vector of the length of the box in each dimension.
void log10(double filler=0.0)
Perform the base-10 logarithm on each signal in the workspace.
size_t m_length
Length of the m_signals / m_errorsSquared arrays.
void exp()
Perform the exp() function on each signal in the workspace.
void log(double filler=0.0)
Perform the natural logarithm on each signal in the workspace.
MDHistoWorkspace & operator&=(const MDHistoWorkspace &b)
void initVertexesArray()
After initialization, call this to initialize the vertexes array to the vertexes of the 0th box.
std::vector< size_t > m_indexMaker
For converting to/from linear index to tdimensions.
std::unique_ptr< coord_t[]> getVertexesArray(size_t linearIndex, size_t &numVertices) const
For the volume at the given linear index, Return the vertices of every corner of the box,...
void checkWorkspaceSize(const MDHistoWorkspace &other, const std::string &operation)
Check if the two workspace's sizes match (for comparison or element-by-element operation.
std::vector< coord_t > m_vertexesArray
Pre-calculated vertexes array for the 0th box.
signal_t getSignalWithMaskAtCoord(const coord_t *coords, const Mantid::API::MDNormalization &normalization) const override
Returns the (normalized) signal at a given coordinates.
void divide(const MDHistoWorkspace &b_ws)
Perform the /= operation, element-by-element, for two MDHistoWorkspace's.
uint64_t getNEvents() const override
get number of contributed events
bool getIsMaskedAt(size_t index) const
Getter for the masking at a specified linear index.
Mantid::API::MDNormalization m_displayNormalization
Display normalization to use.
MDHistoWorkspace & operator|=(const MDHistoWorkspace &b)
A boolean |= (or) operation, element-by-element, for two MDHistoWorkspace's.
void add(const MDHistoWorkspace &b)
Perform the += operation, element-by-element, for two MDHistoWorkspace's.
void greaterThan(const MDHistoWorkspace &b)
Turn this workspace into a boolean workspace, where signal[i] -> becomes true (1.0) if it is > b[i].
std::vector< size_t > indexMultiplier
To find the index into the linear array, dim0 + indexMultiplier[0]*dim1 + ...
MDHistoWorkspace & operator/=(const MDHistoWorkspace &b_ws)
Perform the /= operation, element-by-element, for two MDHistoWorkspace's.
std::vector< signal_t > m_signals
Linear array of signals for each bin.
void setSignalAt(size_t index, signal_t value) override
Sets the signal at the specified index.
void cacheValues()
When all dimensions have been initialized, this caches all the necessary values for later use.
void setMDMasking(std::unique_ptr< Mantid::Geometry::MDImplicitFunction > maskingRegion) override
Apply masking.
void setErrorSquaredAt(size_t index, signal_t value) override
Sets the error (squared) at the specified index.
void operatorNot()
A boolean not operation, performed in-place.
void lessThan(const MDHistoWorkspace &b)
Turn this workspace into a boolean workspace, where signal[i] -> becomes true (1.0) if it is < b[i].
void setMDMaskAt(const size_t &index, bool mask)
Apply masking.
void setUsingMask(const MDHistoWorkspace &mask, const MDHistoWorkspace &values)
Copy the values from another workspace onto this workspace, but only where a mask is true (non-zero)
void multiply(const MDHistoWorkspace &b_ws)
Perform the *= operation, element-by-element, for two MDHistoWorkspace's.
void setTo(signal_t signal, signal_t errorSquared, signal_t numEvents) override
Sets all signals/errors in the workspace to the given values.
MDHistoWorkspace & operator-=(const MDHistoWorkspace &b)
Perform the -= operation, element-by-element, for two MDHistoWorkspace's.
std::vector< signal_t > m_numEvents
Number of contributing events for each bin.
Kernel::SpecialCoordinateSystem m_coordSystem
An "ImplicitFunction" defining a hyper-cuboid-shaped region in N dimensions.
virtual bool isPointContained(const coord_t *coords)
Is a point in MDimensions contained by this ImplicitFunction? If the point is bounded by ALL planes c...
TYPE normalize()
Normalize this vector to unity length.
Definition: VMD.cpp:427
size_t getNumDims() const
Definition: VMD.cpp:236
static const signal_t MDMaskValue
Definition: IMDWorkspace.h:25
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::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const NexusHDF5Descriptor &descriptor)
Get the number of events in the currently opened group.
bool pointInWorkspace(const MDHistoWorkspace *ws, const VMD &point)
std::shared_ptr< MDHistoDimension > MDHistoDimension_sptr
Shared pointer to a MDHistoDimension.
std::shared_ptr< const IMDDimension > IMDDimension_const_sptr
Shared Pointer to const IMDDimension.
Definition: IMDDimension.h:101
void GetIndicesFromLinearIndex(const size_t numDims, const size_t linear_index, const size_t *index_maker, const size_t *index_max, size_t *out_indices)
Set up a nested for loop by creating an array of counters.
Definition: Utils.h:144
void SetUpIndexMaker(const size_t numDims, size_t *out, const size_t *index_max)
Set up an "index maker" for a nested for loop.
Definition: Utils.h:104
SpecialCoordinateSystem
Special coordinate systems for Q3D.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition: V3D.h:341
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.
Definition: IMDWorkspace.h:48
std::vector< signal_t > y
Definition: IMDWorkspace.h:50
std::vector< signal_t > e
Definition: IMDWorkspace.h:51