Mantid
Loading...
Searching...
No Matches
MatrixWorkspace.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 +
12#include "MantidAPI/Run.h"
13#include "MantidAPI/Sample.h"
23#include "MantidIndexing/GlobalSpectrumIndex.h"
24#include "MantidIndexing/IndexInfo.h"
27#include "MantidKernel/MDUnit.h"
32
33#include "MantidTypes/SpectrumDefinition.h"
34
35#include <boost/algorithm/string/join.hpp>
36#include <boost/algorithm/string/regex.hpp>
37
38#include <cmath>
39#include <functional>
40#include <numeric>
41#include <utility>
42
45using Mantid::Types::Core::DateAndTime;
46
47namespace {
49auto accumulate_if_finite = [](const double accumulator, const double newValue) {
50 if (std::isfinite(newValue)) {
51 return accumulator + newValue;
52 } else {
53 return accumulator;
54 }
55};
56} // namespace
57
58namespace Mantid::API {
59using std::size_t;
60using namespace Geometry;
61using Kernel::V3D;
62
63namespace {
65Kernel::Logger g_log("MatrixWorkspace");
66constexpr const double EPSILON{1.0e-9};
67
76std::string appendUnitDenominatorUsingPer(std::string yLabel, const MatrixWorkspace &workspace, bool useLatex) {
77 if (useLatex) {
78 std::string xLabel = workspace.getAxis(0)->unit()->label().latex();
79 if (!xLabel.empty())
80 yLabel += " per $" + workspace.getAxis(0)->unit()->label().latex() + "$";
81 } else {
82 std::string xLabel = workspace.getAxis(0)->unit()->label().ascii();
83 if (!xLabel.empty())
84 yLabel += " per " + workspace.getAxis(0)->unit()->label().ascii();
85 }
86 return yLabel;
87}
88
95std::string replacePerWithLatex(std::string yLabel) {
96 std::vector<std::string> splitVec;
97 boost::split_regex(splitVec, yLabel, boost::regex(" per "));
98 if (splitVec.size() > 1) {
99 yLabel = splitVec[0];
100 splitVec.erase(splitVec.begin());
101 std::string unitString = boost::algorithm::join(splitVec, " ");
102 if (!yLabel.empty())
103 yLabel += " ";
104 yLabel += "(" + unitString + ")$^{-1}$";
105 }
106 return yLabel;
107}
108
109} // namespace
110const std::string MatrixWorkspace::xDimensionId = "xDimension";
111const std::string MatrixWorkspace::yDimensionId = "yDimension";
112
115 : IMDWorkspace(), ExperimentInfo(), m_axes(), m_isInitialized(false), m_YUnit(), m_YUnitLabel(), m_masks(),
116 m_marker_size(6.) {}
117
119 : IMDWorkspace(other), ExperimentInfo(other), m_indexInfo(std::make_unique<Indexing::IndexInfo>(other.indexInfo())),
120 m_isInitialized(other.m_isInitialized), m_YUnit(other.m_YUnit), m_YUnitLabel(other.m_YUnitLabel),
121 m_masks(other.m_masks), m_indexInfoNeedsUpdate(false), m_marker_size(6.) {
122 m_axes.resize(other.m_axes.size());
123 for (size_t i = 0; i < m_axes.size(); ++i)
124 m_axes[i] = std::unique_ptr<Axis>(other.m_axes[i]->clone(this));
125 m_isCommonBinsFlag.store(other.m_isCommonBinsFlag.load());
126 m_isCommonBinsFlagValid.store(other.m_isCommonBinsFlagValid.load());
127 // TODO: Do we need to init m_monitorWorkspace?
128}
129
131// RJT, 3/10/07: The Analysis Data Service needs to be able to delete
132// workspaces, so I moved this from protected to public.
134
140const Indexing::IndexInfo &MatrixWorkspace::indexInfo() const {
141 std::lock_guard<std::mutex> lock(m_indexInfoMutex);
142 // Individual SpectrumDefinitions in SpectrumInfo may have changed. Due to a
143 // copy-on-write mechanism the definitions stored in IndexInfo may then be out
144 // of sync (definitions in SpectrumInfo have been updated).
145 m_indexInfo->setSpectrumDefinitions(spectrumInfo().sharedSpectrumDefinitions());
146 // If spectrum numbers are set in ISpectrum this flag will be true
148 std::vector<Indexing::SpectrumNumber> spectrumNumbers;
149 for (size_t i = 0; i < getNumberHistograms(); ++i)
150 spectrumNumbers.emplace_back(getSpectrum(i).getSpectrumNo());
151 m_indexInfo->setSpectrumNumbers(std::move(spectrumNumbers));
153 }
154 return *m_indexInfo;
155}
156
160void MatrixWorkspace::setIndexInfo(const Indexing::IndexInfo &indexInfo) {
161 // Comparing the *local* size of the indexInfo.
162 if (indexInfo.size() != getNumberHistograms())
163 throw std::invalid_argument("MatrixWorkspace::setIndexInfo: IndexInfo size "
164 "does not match number of histograms in "
165 "workspace");
166
167 m_indexInfo = std::make_unique<Indexing::IndexInfo>(indexInfo);
169 if (!m_indexInfo->spectrumDefinitions())
171 // Fails if spectrum definitions contain invalid indices.
173 // This sets the SpectrumDefinitions for the SpectrumInfo, which may seem
174 // counterintuitive at first -- why would setting IndexInfo modify internals
175 // of SpectrumInfo? However, logically it would not make sense to assign
176 // SpectrumDefinitions in an assignment of SpectrumInfo: Changing
177 // SpectrumDefinitions requires also changes at a higher level of a workspace
178 // (in particular the histograms, which would need to be regrouped as well).
179 // Thus, assignment of SpectrumInfo should just check for compatible
180 // SpectrumDefinitions and assign other data (such as per-spectrum masking
181 // flags, which do not exist yet). Furthermore, since currently detector
182 // groupings are still stored in ISpectrum (in addition to the
183 // SpectrumDefinitions in SpectrumInfo), an assigment of SpectrumDefinitions
184 // in SpectrumInfo would lead to inconsistent workspaces. SpectrumDefinitions
185 // are thus assigned by IndexInfo, which acts at a highler level and is
186 // typically used at construction time of a workspace, i.e., there is no data
187 // in histograms yet which would need to be regrouped.
188 setSpectrumDefinitions(m_indexInfo->spectrumDefinitions());
189}
190
192void MatrixWorkspace::setIndexInfoWithoutISpectrumUpdate(const Indexing::IndexInfo &indexInfo) {
193 // Comparing the *local* size of the indexInfo.
194 if (indexInfo.size() != getNumberHistograms())
195 throw std::invalid_argument("MatrixWorkspace::setIndexInfo: IndexInfo size "
196 "does not match number of histograms in "
197 "workspace");
200 setSpectrumDefinitions(m_indexInfo->spectrumDefinitions());
201}
202
204const std::string MatrixWorkspace::toString() const {
205 std::ostringstream os;
206 os << id() << "\n"
207 << "Title: " << getTitle() << "\n"
208 << "Histograms: " << getNumberHistograms() << "\n"
209 << "Bins: ";
210
211 try {
212 os << blocksize() << "\n";
213 } catch (std::length_error &) {
214 os << "variable\n"; // TODO shouldn't use try/catch
215 }
216
217 if (isHistogramData())
218 os << "Histogram\n";
219 else
220 os << "Data points\n";
221
222 os << "X axis: ";
223 if (axes() > 0) {
224 Axis *ax = getAxis(0);
225 if (ax && ax->unit())
226 os << ax->unit()->caption() << " / " << ax->unit()->label().ascii();
227 else
228 os << "Not set";
229 } else {
230 os << "N/A";
231 }
232 os << "\n"
233 << "Y axis: " << YUnitLabel() << "\n";
234
235 os << "Distribution: " << (isDistribution() ? "True" : "False") << "\n";
236
238 return os.str();
239}
240
251void MatrixWorkspace::initialize(const std::size_t &NVectors, const std::size_t &XLength, const std::size_t &YLength) {
252 // Check validity of arguments
253 if (NVectors == 0 || XLength == 0 || YLength == 0) {
254 throw std::out_of_range("All arguments to init must be positive and non-zero");
255 }
256
257 // Bypass the initialization if the workspace has already been initialized.
258 if (m_isInitialized)
259 return;
260
262 m_indexInfo = std::make_unique<Indexing::IndexInfo>(NVectors);
263
264 // Invoke init() method of the derived class inside a try/catch clause
265 try {
266 this->init(NVectors, XLength, YLength);
267 } catch (std::runtime_error &) {
268 throw;
269 }
270
271 // Indicate that this workspace has been initialized to prevent duplicate
272 // attempts.
273 m_isInitialized = true;
274}
275
276void MatrixWorkspace::initialize(const std::size_t &NVectors, const HistogramData::Histogram &histogram) {
277 Indexing::IndexInfo indices(NVectors);
278 // Empty SpectrumDefinitions to indicate no default mapping to detectors.
279 indices.setSpectrumDefinitions(std::vector<SpectrumDefinition>(NVectors));
280 return initialize(indices, histogram);
281}
282
283void MatrixWorkspace::initialize(const Indexing::IndexInfo &indexInfo, const HistogramData::Histogram &histogram) {
284 // Check validity of arguments
285 if (indexInfo.size() == 0 || histogram.x().empty()) {
286 throw std::out_of_range("All arguments to init must be positive and non-zero");
287 }
288
289 // Bypass the initialization if the workspace has already been initialized.
290 if (m_isInitialized)
291 return;
295
296 // Indicate that this workspace has been initialized to prevent duplicate
297 // attempts.
298 m_isInitialized = true;
299}
300
301//---------------------------------------------------------------------------------------
306void MatrixWorkspace::setTitle(const std::string &t) {
308
309 // A MatrixWorkspace contains uniquely one Run object, hence for this
310 // workspace
311 // keep the Run object run_title property the same as the workspace title
312 Run &run = mutableRun();
313 run.addProperty("run_title", t, true);
314}
315
320const std::string MatrixWorkspace::getTitle() const {
321 if (run().hasProperty("run_title")) {
322 std::string title = run().getProperty("run_title")->value();
323 return title;
324 } else
325 return Workspace::getTitle();
326}
327
332void MatrixWorkspace::setPlotType(const std::string &t) {
333 Run &run = mutableRun();
335
336 if (v.isValid(t) == "") {
337 run.addProperty("plot_type", t, true);
338 } else {
339 std::string validValues = std::accumulate(
340 validPlotTypes.begin() + 1, validPlotTypes.end(), validPlotTypes.front(),
341 [](const std::string &valuesString, const std::string &plotType) { return valuesString + ", " + plotType; });
342 throw std::invalid_argument("Invalid plot type '" + t + "'. Must be one of: " + validValues);
343 }
344}
345
350std::string MatrixWorkspace::getPlotType() const {
351 std::string plotType;
352 if (run().hasProperty("plot_type")) {
353 plotType = run().getProperty("plot_type")->value();
354 } else {
355 plotType = "plot";
356 }
357 return plotType;
358}
359
365void MatrixWorkspace::setMarkerStyle(const std::string &markerType) {
367
368 if (v.isValid(markerType) == "") {
369 m_marker = markerType;
370 } else {
371 std::string validValues =
372 std::accumulate(validMarkerStyles.begin() + 1, validMarkerStyles.end(), validMarkerStyles.front(),
373 [](const std::string &valuesString, const std::string &markerStyle) {
374 return valuesString + ", " + markerStyle;
375 });
376 throw std::invalid_argument("Invalid marker type '" + markerType + "'. Must be one of: " + validValues);
377 }
378}
379
386 if (m_marker.empty())
387 return Kernel::ConfigService::Instance().getString("plots.markerworkspace.MarkerStyle");
388 else
389 return m_marker;
390}
391
397void MatrixWorkspace::setMarkerSize(const float size) {
398 if (size > 0)
400}
407
409 for (size_t j = 0; j < getNumberHistograms(); ++j) {
410 auto &spec = getSpectrum(j);
411 try {
412 if (map.indexIsSpecNumber())
413 spec.setDetectorIDs(map.getDetectorIDsForSpectrumNo(spec.getSpectrumNo()));
414 else
415 spec.setDetectorIDs(map.getDetectorIDsForSpectrumIndex(j));
416 } catch (std::out_of_range &exception) {
417 // Get here if the spectrum number is not in the map.
418 spec.clearDetectorIDs();
419 g_log.debug(exception.what());
420 g_log.debug() << "Spectrum number " << spec.getSpectrumNo() << " not in map.\n";
421 }
422 }
423}
424
434void MatrixWorkspace::rebuildSpectraMapping(const bool includeMonitors, const specnum_t specNumOffset) {
435 if (sptr_instrument->nelements() == 0) {
436 return;
437 }
438
439 std::vector<detid_t> pixelIDs = this->getInstrument()->getDetectorIDs(!includeMonitors);
440
441 try {
442 size_t index = 0;
443 std::vector<detid_t>::const_iterator iend = pixelIDs.end();
444 for (std::vector<detid_t>::const_iterator it = pixelIDs.begin(); it != iend; ++it) {
445 // The detector ID
446 const detid_t detId = *it;
447 const auto specNo = specnum_t(index + specNumOffset);
448
449 if (index < this->getNumberHistograms()) {
450 auto &spec = getSpectrum(index);
451 spec.setSpectrumNo(specNo);
452 spec.setDetectorID(detId);
453 }
454
455 index++;
456 }
457
458 } catch (std::runtime_error &) {
459 throw;
460 }
461}
462
468 auto const *ax = dynamic_cast<SpectraAxis *>(this->m_axes[1].get());
469 if (!ax)
470 throw std::runtime_error("MatrixWorkspace::getSpectrumToWorkspaceIndexMap: "
471 "axis[1] is not a SpectraAxis, so I cannot "
472 "generate a map.");
473 try {
474 return ax->getSpectraIndexMap();
475 } catch (std::runtime_error &) {
476 g_log.error() << "MatrixWorkspace::getSpectrumToWorkspaceIndexMap: no elements!";
477 throw;
478 }
479}
480
490 auto const *ax = dynamic_cast<SpectraAxis *>(this->m_axes[1].get());
491 if (!ax)
492 throw std::runtime_error("MatrixWorkspace::getSpectrumToWorkspaceIndexMap: "
493 "axis[1] is not a SpectraAxis, so I cannot "
494 "generate a map.");
495
496 // Find the min/max spectra IDs
497 specnum_t min = std::numeric_limits<specnum_t>::max(); // So that any number
498 // will be less than this
499 specnum_t max = -std::numeric_limits<specnum_t>::max(); // So that any number
500 // will be greater than
501 // this
502 size_t length = ax->length();
503 for (size_t i = 0; i < length; i++) {
504 specnum_t spec = ax->spectraNo(i);
505 if (spec < min)
506 min = spec;
507 if (spec > max)
508 max = spec;
509 }
510
511 // Offset so that the "min" value goes to index 0
512 offset = -min;
513
514 // Size correctly
515 std::vector<size_t> out(max - min + 1, 0);
516
517 // Make the vector
518 for (size_t i = 0; i < length; i++) {
519 specnum_t spec = ax->spectraNo(i);
520 out[spec + offset] = i;
521 }
522
523 return out;
524}
525
530 bool retVal = false;
531
532 // Loop through the workspace index
533 for (size_t workspaceIndex = 0; workspaceIndex < this->getNumberHistograms(); workspaceIndex++) {
534 auto detList = getSpectrum(workspaceIndex).getDetectorIDs();
535 if (detList.size() > 1) {
536 retVal = true;
537 break;
538 }
539 }
540 return retVal;
541}
542
557 bool ignoreIfNoValidDets) const {
558 detid2index_map map;
559 const auto &specInfo = spectrumInfo();
560
561 // Loop through the workspace index
562 for (size_t workspaceIndex = 0; workspaceIndex < this->getNumberHistograms(); ++workspaceIndex) {
563 // Workspaces can contain invalid detector IDs. hasDetectors will silently ignore them until this is fixed.
564 if (ignoreIfNoValidDets && !specInfo.hasDetectors(workspaceIndex)) {
565 continue;
566 }
567 auto detList = getSpectrum(workspaceIndex).getDetectorIDs();
568
569 if (throwIfMultipleDets) {
570 if (detList.size() > 1) {
571 throw std::runtime_error("MatrixWorkspace::getDetectorIDToWorkspaceIndexMap(): more than 1 "
572 "detector for one histogram! I cannot generate a map of detector "
573 "ID to workspace index.");
574 }
575
576 // Set the KEY to the detector ID and the VALUE to the workspace index.
577 if (detList.size() == 1)
578 map[*detList.begin()] = workspaceIndex;
579 } else {
580 // Allow multiple detectors per workspace index
581 for (auto det : detList)
582 map[det] = workspaceIndex;
583 }
584
585 // Ignore if the detector list is empty.
586 }
587
588 return map;
589}
590
604 bool throwIfMultipleDets) const {
605 // Make a correct initial size
606 std::vector<size_t> out;
607 detid_t minId = 0;
608 detid_t maxId = 0;
609 this->getInstrument()->getMinMaxDetectorIDs(minId, maxId);
610 offset = -minId;
611 const int outSize = maxId - minId + 1;
612 // Allocate at once
613 out.resize(outSize, std::numeric_limits<size_t>::max());
614
615 for (size_t workspaceIndex = 0; workspaceIndex < getNumberHistograms(); ++workspaceIndex) {
616 // Get the list of detectors from the WS index
617 const auto &detList = this->getSpectrum(workspaceIndex).getDetectorIDs();
618
619 if (throwIfMultipleDets && (detList.size() > 1))
620 throw std::runtime_error("MatrixWorkspace::getDetectorIDToWorkspaceIndexVector(): more than 1 "
621 "detector for one histogram! I cannot generate a map of detector ID "
622 "to workspace index.");
623
624 // Allow multiple detectors per workspace index, or,
625 // If only one is allowed, then this has thrown already
626 for (auto det : detList) {
627 int index = det + offset;
628 if (index < 0 || index >= outSize) {
629 g_log.debug() << "MatrixWorkspace::getDetectorIDToWorkspaceIndexVector("
630 "): detector ID found ("
631 << det << " at workspace index " << workspaceIndex << ") is invalid.\n";
632 } else
633 // Save it at that point.
634 out[index] = workspaceIndex;
635 }
636
637 } // (for each workspace index)
638 return out;
639}
640
647std::vector<size_t> MatrixWorkspace::getIndicesFromSpectra(const std::vector<specnum_t> &spectraList) const {
648 // Clear the output index list
649 std::vector<size_t> indexList;
650 indexList.reserve(this->getNumberHistograms());
651
652 auto iter = spectraList.cbegin();
653 while (iter != spectraList.cend()) {
654 for (size_t i = 0; i < this->getNumberHistograms(); ++i) {
655 if (this->getSpectrum(i).getSpectrumNo() == *iter) {
656 indexList.emplace_back(i);
657 break;
658 }
659 }
660 ++iter;
661 }
662 return indexList;
663}
664
672 for (size_t i = 0; i < this->getNumberHistograms(); ++i) {
673 if (this->getSpectrum(i).getSpectrumNo() == specNo)
674 return i;
675 }
676 throw std::runtime_error("Could not find spectrum number in any spectrum.");
677}
678
690std::vector<size_t> MatrixWorkspace::getIndicesFromDetectorIDs(const std::vector<detid_t> &detIdList) const {
691 if (m_indexInfo->size() != m_indexInfo->globalSize())
692 throw std::runtime_error("MatrixWorkspace: Using getIndicesFromDetectorIDs "
693 "in a parallel run is most likely incorrect. "
694 "Aborting.");
695
696 // create a set because looking for existence of value is faster than from vector
697 std::set<detid_t> detIdSet(detIdList.cbegin(), detIdList.cend());
698
699 // create a mapping of detector number to workspace index
700 std::map<detid_t, std::set<size_t>> detectorIDtoWSIndices;
701 const size_t NUM_HIST = getNumberHistograms();
702 for (size_t i = 0; i < NUM_HIST; ++i) {
703 const auto &detIDs = getSpectrum(i).getDetectorIDs();
704 for (const auto &detID : detIDs) {
705 // only add things to the map that are being asked for
706 if (detIdSet.count(detID) > 0) {
707 detectorIDtoWSIndices[detID].insert(i);
708 }
709 }
710 }
711
712 // create a vector of workspace indices with the same order as the input list
713 std::vector<size_t> indexList;
714 indexList.reserve(detIdList.size());
715 for (const auto &detId : detIdList) {
716 const auto wsIndices = detectorIDtoWSIndices.find(detId);
717 if (wsIndices != detectorIDtoWSIndices.end()) {
718 std::copy(wsIndices->second.cbegin(), wsIndices->second.cend(), std::back_inserter(indexList));
719 }
720 }
721
722 return indexList;
723}
724
732std::vector<specnum_t> MatrixWorkspace::getSpectraFromDetectorIDs(const std::vector<detid_t> &detIdList) const {
733 std::vector<specnum_t> spectraList;
734
735 // Try every detector in the list
736 for (auto detId : detIdList) {
737 bool foundDet = false;
738 specnum_t foundSpecNum = 0;
739
740 // Go through every histogram
741 for (size_t i = 0; i < this->getNumberHistograms(); i++) {
742 if (this->getSpectrum(i).hasDetectorID(detId)) {
743 foundDet = true;
744 foundSpecNum = this->getSpectrum(i).getSpectrumNo();
745 break;
746 }
747 }
748
749 if (foundDet)
750 spectraList.emplace_back(foundSpecNum);
751 } // for each detector ID in the list
752 return spectraList;
753}
754
756 double xmin;
757 double xmax;
758 this->getXMinMax(xmin, xmax); // delegate to the proper code
759 return xmin;
760}
761
763 double xmin;
764 double xmax;
765 this->getXMinMax(xmin, xmax); // delegate to the proper code
766 return xmax;
767}
768
769void MatrixWorkspace::getXMinMax(double &xmin, double &xmax) const {
770 // set to crazy values to start
771 xmin = std::numeric_limits<double>::max();
772 xmax = -1.0 * xmin;
773 size_t numberOfSpectra = this->getNumberHistograms();
774
775 // determine the data range
776 for (size_t workspaceIndex = 0; workspaceIndex < numberOfSpectra; workspaceIndex++) {
777 const auto &xData = this->x(workspaceIndex);
778 const double xfront = xData.front();
779 const double xback = xData.back();
780 if (std::isfinite(xfront) && std::isfinite(xback)) {
781 if (xfront < xmin)
782 xmin = xfront;
783 if (xback > xmax)
784 xmax = xback;
785 }
786 }
787}
788
802void MatrixWorkspace::getIntegratedSpectra(std::vector<double> &out, const double minX, const double maxX,
803 const bool entireRange) const {
804 out.resize(this->getNumberHistograms(), 0.0);
805
806 // offset for histogram data, because the x axis is not the same size for histogram and point data.
807 const size_t histogramOffset = this->isHistogramData() ? 1 : 0;
808
809 // Run in parallel if the implementation is threadsafe
811 for (int wksp_index = 0; wksp_index < static_cast<int>(this->getNumberHistograms()); wksp_index++) {
812 // Get Handle to data
813 const Mantid::MantidVec &xData = this->readX(wksp_index);
814 const auto &yData = this->y(wksp_index);
815 // If it is a 1D workspace, no need to integrate
816 if ((xData.size() <= 1 + histogramOffset) && (!yData.empty())) {
817 out[wksp_index] = yData[0];
818 } else {
819 // Iterators for limits - whole range by default
820 Mantid::MantidVec::const_iterator lowit, highit;
821 lowit = xData.begin();
822 highit = xData.end() - histogramOffset;
823
824 // But maybe we don't want the entire range?
825 if (!entireRange) {
826 // If the first element is lower that the xmin then search for new lowit
827 if ((*lowit) < minX)
828 lowit = std::lower_bound(xData.begin(), xData.end(), minX);
829 // If the last element is higher that the xmax then search for new highit
830 if (*(highit - 1 + histogramOffset) > maxX)
831 highit = std::upper_bound(lowit, xData.end(), maxX);
832 }
833
834 // Get the range for the y vector
835 Mantid::MantidVec::difference_type distmin = std::distance(xData.begin(), lowit);
836 Mantid::MantidVec::difference_type distmax = std::distance(xData.begin(), highit);
837 double sum(0.0);
838 if (distmin <= distmax) {
839 // Integrate
840 sum = std::accumulate(yData.begin() + distmin, yData.begin() + distmax, 0.0, accumulate_if_finite);
841 }
842 // Save it in the vector
843 out[wksp_index] = sum;
844 }
845 }
846}
847
848std::vector<double> MatrixWorkspace::getIntegratedCountsForWorkspaceIndices(const std::vector<size_t> &workspaceIndices,
849 const double minX, const double maxX,
850 const bool entireRange) const {
851 std::vector<double> integratedSpectra;
852 getIntegratedSpectra(integratedSpectra, minX, maxX, entireRange);
853 std::vector<double> detectorCounts;
854 std::transform(workspaceIndices.cbegin(), workspaceIndices.cend(), std::back_inserter(detectorCounts),
855 [&](const auto &wsIndex) { return integratedSpectra[wsIndex]; });
856 return detectorCounts;
857}
858
869 const auto &dets = getSpectrum(workspaceIndex).getDetectorIDs();
870 Instrument_const_sptr localInstrument = getInstrument();
871 if (!localInstrument) {
872 g_log.debug() << "No instrument defined.\n";
873 throw Kernel::Exception::NotFoundError("Instrument not found", "");
874 }
875
876 const size_t ndets = dets.size();
877 if (ndets == 1) {
878 // If only 1 detector for the spectrum number, just return it
879 return localInstrument->getDetector(*dets.begin());
880 } else if (ndets == 0) {
881 throw Kernel::Exception::NotFoundError("MatrixWorkspace::getDetector(): No "
882 "detectors for this workspace "
883 "index.",
884 "");
885 }
886 // Else need to construct a DetectorGroup and return that
887 auto dets_ptr = localInstrument->getDetectors(dets);
888 return std::make_shared<Geometry::DetectorGroup>(dets_ptr);
889}
890
899
901 Geometry::IComponent_const_sptr source = instrument->getSource();
902 Geometry::IComponent_const_sptr sample = instrument->getSample();
903 if (source == nullptr || sample == nullptr) {
905 "Instrument not sufficiently defined: failed to get source and/or "
906 "sample");
907 }
908
909 const Kernel::V3D samplePos = sample->getPos();
910 const Kernel::V3D beamLine = samplePos - source->getPos();
911
912 if (beamLine.nullVector()) {
913 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
914 }
915 // Get the instrument up axis.
916 const V3D &thetaSignAxis = instrument->getReferenceFrame()->vecThetaSign();
917 return det.getSignedTwoTheta(samplePos, beamLine, thetaSignAxis);
918}
919
928 Instrument_const_sptr instrument = this->getInstrument();
929 Geometry::IComponent_const_sptr source = instrument->getSource();
930 Geometry::IComponent_const_sptr sample = instrument->getSample();
931 if (source == nullptr || sample == nullptr) {
933 "Instrument not sufficiently defined: failed to get source and/or "
934 "sample");
935 }
936
937 const Kernel::V3D samplePos = sample->getPos();
938 const Kernel::V3D beamLine = samplePos - source->getPos();
939
940 if (beamLine.nullVector()) {
941 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
942 }
943 return det.getTwoTheta(samplePos, beamLine);
944}
945
947int MatrixWorkspace::axes() const { return static_cast<int>(m_axes.size()); }
948
955Axis *MatrixWorkspace::getAxis(const std::size_t &axisIndex) const {
956 if (axisIndex >= m_axes.size()) {
957 throw Kernel::Exception::IndexError(axisIndex, m_axes.size(), "Argument to getAxis is invalid for this workspace");
958 }
959
960 return m_axes[axisIndex].get();
961}
962
972void MatrixWorkspace::replaceAxis(const std::size_t &axisIndex, std::unique_ptr<Axis> newAxis) {
973 // First check that axisIndex is in range
974 if (axisIndex >= m_axes.size()) {
975 throw Kernel::Exception::IndexError(axisIndex, m_axes.size(), "Value of axisIndex is invalid for this workspace");
976 }
977 // If we're OK, then delete the old axis and set the pointer to the new one
978 m_axes[axisIndex] = std::move(newAxis);
979}
980
986 if (!this->isCommonBins()) {
987 return false;
988 }
989
990 if (this->getNumberHistograms() == 0) {
991 return false;
992 }
993
994 const auto &x0 = this->x(0);
995 if (x0.size() < 2) {
996 return false;
997 }
998
999 // guard against all axis elements being equal
1000 if (x0[1] == x0[0]) {
1001 return false;
1002 }
1003
1004 double diff = x0[1] / x0[0];
1005 if (!std::isfinite(diff)) {
1006 return false;
1007 }
1008 // ignore final bin, since it may be a different size
1009 for (size_t i = 1; i < x0.size() - 2; ++i) {
1010 if (std::isfinite(x0[i + 1]) && std::isfinite(x0[i])) {
1011 if (std::abs(x0[i + 1] / x0[i] - diff) > EPSILON) {
1012 return false;
1013 }
1014 } else {
1015 return false;
1016 }
1017 }
1018 return true;
1019}
1020
1025size_t MatrixWorkspace::numberOfAxis() const { return m_axes.size(); }
1026
1028void MatrixWorkspace::setYUnit(const std::string &newUnit) { m_YUnit = newUnit; }
1029
1036std::string MatrixWorkspace::YUnitLabel(bool useLatex /* = false */, bool plotAsDistribution /* = false */) const {
1037 std::string retVal;
1038 if (!m_YUnitLabel.empty()) {
1039 retVal = m_YUnitLabel;
1040 // If a custom label has been set and we are dividing by bin width when
1041 // plotting (i.e. plotAsDistribution = true and the workspace is not a
1042 // distribution), we must append the x-unit as a divisor. We assume the
1043 // custom label contains the correct units for the data.
1044 if (plotAsDistribution && !this->isDistribution())
1045 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
1046 } else {
1047 retVal = m_YUnit;
1048 // If no custom label is set and the workspace is a distribution we need to
1049 // append the divisor's unit to the label. If the workspace is not a
1050 // distribution, but we are plotting it as a distribution, we must append
1051 // the divisor's unit.
1052 if (plotAsDistribution || this->isDistribution())
1053 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
1054 }
1055 if (useLatex)
1056 retVal = replacePerWithLatex(retVal);
1057 return retVal;
1058}
1059
1061void MatrixWorkspace::setYUnitLabel(const std::string &newLabel) { m_YUnitLabel = newLabel; }
1062
1068 return getSpectrum(0).yMode() == HistogramData::Histogram::YMode::Frequencies;
1069}
1070
1074 if (isDistribution() == newValue)
1075 return;
1076 HistogramData::Histogram::YMode ymode =
1077 newValue ? HistogramData::Histogram::YMode::Frequencies : HistogramData::Histogram::YMode::Counts;
1078 for (size_t i = 0; i < getNumberHistograms(); ++i)
1079 getSpectrum(i).setYMode(ymode);
1080}
1081
1087 // all spectra *should* have the same behavior
1088 return isHistogramDataByIndex(0);
1089}
1090
1096bool MatrixWorkspace::isHistogramDataByIndex(const std::size_t index) const {
1097 bool isHist = (x(index).size() != y(index).size());
1098
1099 // TODOHIST temporary sanity check
1100 if (isHist) {
1101 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::BinEdges) {
1102 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1103 "Histogram::Xmode is not BinEdges");
1104 }
1105 } else {
1106 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::Points) {
1107 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1108 "Histogram::Xmode is not Points");
1109 }
1110 }
1111 return isHist;
1112}
1113
1119 std::lock_guard<std::mutex> lock{m_isCommonBinsMutex};
1120 const bool isFlagValid{m_isCommonBinsFlagValid.exchange(true)};
1121 if (isFlagValid) {
1122 return m_isCommonBinsFlag;
1123 }
1124 m_isCommonBinsFlag = true;
1125 const size_t numHist = this->getNumberHistograms();
1126 // there being only one or zero histograms is accepted as not being an error
1127 if (numHist <= 1) {
1128 return m_isCommonBinsFlag;
1129 }
1130
1131 // First check if the x-axis shares a common ptr.
1132 const HistogramData::HistogramX *first = &x(0);
1133 for (size_t i = 1; i < numHist; ++i) {
1134 if (&x(i) != first) {
1135 m_isCommonBinsFlag = false;
1136 break;
1137 }
1138 }
1139
1140 // If true, we may return here.
1141 if (m_isCommonBinsFlag) {
1142 return m_isCommonBinsFlag;
1143 }
1144
1145 m_isCommonBinsFlag = true;
1146 // Check that that size of each histogram is identical.
1147 const size_t numBins = x(0).size();
1148 for (size_t i = 1; i < numHist; ++i) {
1149 if (x(i).size() != numBins) {
1150 m_isCommonBinsFlag = false;
1151 return m_isCommonBinsFlag;
1152 }
1153 }
1154
1155 const auto &x0 = x(0);
1156 // Check that the values of each histogram are identical.
1158 for (int i = 1; i < static_cast<int>(numHist); ++i) {
1159 if (m_isCommonBinsFlag) {
1160 const auto specIndex = static_cast<std::size_t>(i);
1161 const auto &xi = x(specIndex);
1162 for (size_t j = 0; j < numBins; ++j) {
1163 const double a = x0[j];
1164 const double b = xi[j];
1165 // Check for NaN and infinity before comparing for equality
1166 if (std::isfinite(a) && std::isfinite(b)) {
1167 if (std::abs(a - b) > EPSILON) {
1168 m_isCommonBinsFlag = false;
1169 break;
1170 }
1171 // Otherwise we check that both are NaN or both are infinity
1172 } else if ((std::isnan(a) != std::isnan(b)) || (std::isinf(a) != std::isinf(b))) {
1173 m_isCommonBinsFlag = false;
1174 break;
1175 }
1176 }
1177 }
1178 }
1179 return m_isCommonBinsFlag;
1180}
1181
1187 if (!this->isCommonBins())
1188 return false;
1189
1190 const HistogramData::HistogramX bins = x(0);
1191
1192 for (size_t i = 0; i < bins.size(); ++i) {
1193 if (std::trunc(bins[i]) != bins[i])
1194 return false;
1195 }
1196 return true;
1197}
1198
1213void MatrixWorkspace::maskBin(const size_t &workspaceIndex, const size_t &binIndex, const double &weight) {
1214 // First check the workspaceIndex is valid
1215 if (workspaceIndex >= this->getNumberHistograms())
1216 throw Kernel::Exception::IndexError(workspaceIndex, this->getNumberHistograms(),
1217 "MatrixWorkspace::maskBin,workspaceIndex");
1218 // Then check the bin index
1219 if (binIndex >= y(workspaceIndex).size())
1220 throw Kernel::Exception::IndexError(binIndex, y(workspaceIndex).size(), "MatrixWorkspace::maskBin,binIndex");
1221
1222 // this function is marked parallel critical
1223 flagMasked(workspaceIndex, binIndex, weight);
1224
1225 // this is the actual result of the masking that most algorithms and plotting
1226 // implementations will see, the bin mask flags defined above are used by only
1227 // some algorithms
1228 // If the weight is 0, nothing more needs to be done after flagMasked above
1229 // (i.e. NaN and Inf will also stay intact)
1230 // If the weight is not 0, NaN and Inf values are set to 0,
1231 // whereas other values are scaled by (1 - weight)
1232 if (weight != 0.) {
1233 double &yData = this->mutableY(workspaceIndex)[binIndex];
1234 (std::isnan(yData) || std::isinf(yData)) ? yData = 0. : yData *= (1 - weight);
1235 double &eData = this->mutableE(workspaceIndex)[binIndex];
1236 (std::isnan(eData) || std::isinf(eData)) ? eData = 0. : eData *= (1 - weight);
1237 }
1238}
1239
1248void MatrixWorkspace::flagMasked(const size_t &index, const size_t &binIndex, const double &weight) {
1249 // Writing to m_masks is not thread-safe, so put in some protection
1251 // First get a reference to the list for this spectrum (or create a new
1252 // list)
1253 MaskList &binList = m_masks[index];
1254 binList[binIndex] = weight;
1255 }
1256}
1257
1262bool MatrixWorkspace::hasMaskedBins(const size_t &workspaceIndex) const {
1263 // First check the workspaceIndex is valid. Return false if it isn't (decided
1264 // against throwing here).
1265 if (workspaceIndex >= this->getNumberHistograms())
1266 return false;
1267 return m_masks.find(workspaceIndex) != m_masks.end();
1268}
1269
1273bool MatrixWorkspace::hasAnyMaskedBins() const { return !m_masks.empty(); }
1274
1281const MatrixWorkspace::MaskList &MatrixWorkspace::maskedBins(const size_t &workspaceIndex) const {
1282 auto it = m_masks.find(workspaceIndex);
1283 // Throw if there are no masked bins for this spectrum. The caller should
1284 // check first using hasMaskedBins!
1285 if (it == m_masks.end()) {
1286 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1287 }
1288
1289 return it->second;
1290}
1291
1292std::vector<size_t> MatrixWorkspace::maskedBinsIndices(const size_t &workspaceIndex) const {
1293 auto it = m_masks.find(workspaceIndex);
1294 // Throw if there are no masked bins for this spectrum. The caller should
1295 // check first using hasMaskedBins!
1296 if (it == m_masks.end()) {
1297 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1298 }
1299
1300 auto maskedBinsList = it->second;
1301 std::vector<size_t> maskedIds;
1302 maskedIds.reserve(maskedBinsList.size());
1303
1304 std::transform(maskedBinsList.begin(), maskedBinsList.end(), std::back_inserter(maskedIds),
1305 [](const auto &mb) { return mb.first; });
1306 return maskedIds;
1307}
1308
1314void MatrixWorkspace::setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins) {
1315 m_masks[workspaceIndex] = maskedBins;
1316}
1317
1323void MatrixWorkspace::setUnmaskedBins(const size_t workspaceIndex) { m_masks.erase(workspaceIndex); }
1324
1334void MatrixWorkspace::setMonitorWorkspace(const std::shared_ptr<MatrixWorkspace> &monitorWS) {
1335 if (monitorWS.get() == this) {
1336 throw std::runtime_error("To avoid memory leak, monitor workspace"
1337 " can not be the same workspace as the host workspace");
1338 }
1339 m_monitorWorkspace = monitorWS;
1340}
1341
1344std::shared_ptr<MatrixWorkspace> MatrixWorkspace::monitorWorkspace() const { return m_monitorWorkspace; }
1345
1350 // 3 doubles per histogram bin.
1351 return 3 * size() * sizeof(double) + run().getMemorySize();
1352}
1353
1358 size_t total = 0;
1359 auto lastX = this->refX(0);
1360 for (size_t wi = 0; wi < getNumberHistograms(); wi++) {
1361 auto X = this->refX(wi);
1362 // If the pointers are the same
1363 if (!(X == lastX) || wi == 0)
1364 total += (*X).size() * sizeof(double);
1365 }
1366 return total;
1367}
1368
1377Types::Core::DateAndTime MatrixWorkspace::getFirstPulseTime() const { return this->run().getFirstPulseTime(); }
1378
1387Types::Core::DateAndTime MatrixWorkspace::getLastPulseTime() const { return this->run().getLastPulseTime(); }
1388
1397std::size_t MatrixWorkspace::yIndexOfX(const double xValue, const std::size_t &index,
1398 [[maybe_unused]] const double tolerance) const {
1399 if (index >= getNumberHistograms())
1400 throw std::out_of_range("MatrixWorkspace::yIndexOfX - Index out of range.");
1401
1402 const auto &xValues = this->x(index);
1403 const bool ascendingOrder = xValues.front() < xValues.back();
1404 const auto minX = ascendingOrder ? xValues.front() : xValues.back();
1405 const auto maxX = ascendingOrder ? xValues.back() : xValues.front();
1406
1408 if (xValue < minX || xValue > maxX)
1409 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1410 "the range of the min and max bin edges.");
1411
1412 return binIndexOfValue(xValues, xValue, ascendingOrder);
1413 } else {
1414 if (xValue < minX - tolerance || xValue > maxX + tolerance)
1415 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1416 "range for this point data.");
1417
1418 return xIndexOfValue(xValues, xValue, tolerance);
1419 }
1420}
1421
1429std::size_t MatrixWorkspace::binIndexOfValue(HistogramData::HistogramX const &xValues, const double xValue,
1430 const bool ascendingOrder) const {
1431 std::size_t hops;
1432 if (ascendingOrder) {
1433 auto lowerIter = std::lower_bound(xValues.cbegin(), xValues.cend(), xValue);
1434
1435 // If we are pointing at the first value then we want to be in the first bin
1436 if (lowerIter == xValues.cbegin())
1437 ++lowerIter;
1438
1439 hops = std::distance(xValues.cbegin(), lowerIter);
1440 } else {
1441 auto lowerIter = std::lower_bound(xValues.crbegin(), xValues.crend(), xValue);
1442
1443 if (lowerIter == xValues.crbegin())
1444 ++lowerIter;
1445
1446 hops = xValues.size() - std::distance(xValues.crbegin(), lowerIter);
1447 }
1448 // The bin index is offset by one from the number of hops between iterators as
1449 // they start at zero (for a histogram workspace)
1450 return hops - 1;
1451}
1452
1461std::size_t MatrixWorkspace::xIndexOfValue(const HistogramData::HistogramX &xValues, const double xValue,
1462 const double tolerance) const {
1463 auto const iter = std::find_if(xValues.cbegin(), xValues.cend(), [&xValue, &tolerance](double const &value) {
1464 return std::abs(xValue - value) <= tolerance;
1465 });
1466 if (iter != xValues.cend())
1467 return std::distance(xValues.cbegin(), iter);
1468 else
1469 throw std::invalid_argument("MatrixWorkspace::yIndexOfX - the X value provided could not be found "
1470 "in the workspace containing point data.");
1471}
1472
1473uint64_t MatrixWorkspace::getNPoints() const { return static_cast<uint64_t>(this->size()); }
1474
1475//================================= FOR MDGEOMETRY
1476//====================================================
1477
1478size_t MatrixWorkspace::getNumDims() const { return 2; }
1479
1480std::string MatrixWorkspace::getDimensionIdFromAxis(const int &axisIndex) const {
1481 std::string id;
1482 if (0 == axisIndex) {
1483 id = xDimensionId;
1484 } else if (1 == axisIndex) {
1485 id = yDimensionId;
1486 } else {
1487 throw std::invalid_argument("Cannot have an index for a MatrixWorkspace "
1488 "axis that is not == 0 or == 1");
1489 }
1490 return id;
1491}
1492
1493//===============================================================================
1495public:
1496 MWDimension(const Axis *axis, std::string dimensionId)
1497 : m_axis(*axis), m_dimensionId(std::move(dimensionId)),
1498 m_haveEdges(dynamic_cast<const BinEdgeAxis *>(&m_axis) != nullptr),
1499 m_frame(std::make_unique<Geometry::GeneralFrame>(m_axis.unit()->label(), m_axis.unit()->label())) {}
1500
1502 std::string getName() const override {
1503 const auto &unit = m_axis.unit();
1504 if (unit && unit->unitID() != "Empty")
1505 return unit->caption();
1506 else
1507 return m_axis.title();
1508 }
1509
1511 const Kernel::UnitLabel getUnits() const override { return m_axis.unit()->label(); }
1512
1516 const std::string &getDimensionId() const override { return m_dimensionId; }
1517
1519 bool getIsIntegrated() const override { return m_axis.length() == 1; }
1520
1522 coord_t getMinimum() const override { return coord_t(m_axis.getMin()); }
1523
1525 coord_t getMaximum() const override { return coord_t(m_axis.getMax()); }
1526
1529 size_t getNBins() const override {
1530 if (m_haveEdges)
1531 return m_axis.length() - 1;
1532 else
1533 return m_axis.length();
1534 }
1535
1537 size_t getNBoundaries() const override { return m_axis.length(); }
1538
1540 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1541 throw std::runtime_error("Not implemented");
1542 }
1543
1545 coord_t getX(size_t ind) const override { return coord_t(m_axis(ind)); }
1546
1552 coord_t getBinWidth() const override {
1553 size_t nsteps = (m_haveEdges) ? this->getNBins() : this->getNBins() - 1;
1554 return (getMaximum() - getMinimum()) / static_cast<coord_t>(nsteps);
1555 }
1556
1557 // Dimensions must be xml serializable.
1558 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1559
1560 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1561 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1562
1563private:
1564 const Axis &m_axis;
1565 const std::string m_dimensionId;
1566 const bool m_haveEdges;
1568};
1569
1570//===============================================================================
1575public:
1576 MWXDimension(const MatrixWorkspace *ws, std::string dimensionId)
1577 : m_ws(ws), m_X(ws->readX(0)), m_dimensionId(std::move(dimensionId)),
1578 m_frame(std::make_unique<Geometry::GeneralFrame>(m_ws->getAxis(0)->unit()->label(),
1579 m_ws->getAxis(0)->unit()->label())) {}
1580
1582 std::string getName() const override {
1583 const auto *axis = m_ws->getAxis(0);
1584 const auto &unit = axis->unit();
1585 if (unit && unit->unitID() != "Empty")
1586 return unit->caption();
1587 else
1588 return axis->title();
1589 }
1590
1592 const Kernel::UnitLabel getUnits() const override { return m_ws->getAxis(0)->unit()->label(); }
1593
1597 const std::string &getDimensionId() const override { return m_dimensionId; }
1598
1600 bool getIsIntegrated() const override { return m_X.size() == 1; }
1601
1603 coord_t getMinimum() const override { return coord_t(m_X.front()); }
1604
1606 coord_t getMaximum() const override { return coord_t(m_X.back()); }
1607
1610 size_t getNBins() const override { return (m_ws->isHistogramData()) ? m_X.size() - 1 : m_X.size(); }
1611
1613 size_t getNBoundaries() const override { return m_X.size(); }
1614
1616 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1617 throw std::runtime_error("Not implemented");
1618 }
1619
1621 coord_t getX(size_t ind) const override { return coord_t(m_X[ind]); }
1622
1623 // Dimensions must be xml serializable.
1624 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1625 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1626 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1627
1628private:
1634 const std::string m_dimensionId;
1637};
1638
1639std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimension(size_t index) const {
1640 if (index == 0) {
1641 return std::make_shared<MWXDimension>(this, xDimensionId);
1642 } else if (index == 1) {
1643 Axis *yAxis = this->getAxis(1);
1644 return std::make_shared<MWDimension>(yAxis, yDimensionId);
1645 } else
1646 throw std::invalid_argument("MatrixWorkspace only has 2 dimensions.");
1647}
1648
1649std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimensionWithId(std::string id) const {
1650 int nAxes = this->axes();
1651 std::shared_ptr<IMDDimension> dim;
1652 for (int i = 0; i < nAxes; i++) {
1653 const std::string knownId = getDimensionIdFromAxis(i);
1654 if (knownId == id) {
1655 dim = std::make_shared<MWDimension>(this->getAxis(i), id);
1656 break;
1657 }
1658 }
1659
1660 if (nullptr == dim) {
1661 std::string message = "Cannot find id : " + id;
1662 throw std::overflow_error(message);
1663 }
1664 return dim;
1665}
1666
1674std::vector<std::unique_ptr<IMDIterator>>
1676 // Find the right number of cores to use
1677 size_t numCores = suggestedNumCores;
1678 if (!this->threadSafe())
1679 numCores = 1;
1680 size_t numElements = this->getNumberHistograms();
1681 if (numCores > numElements)
1682 numCores = numElements;
1683 if (numCores < 1)
1684 numCores = 1;
1685
1686 // Create one iterator per core, splitting evenly amongst spectra
1687 std::vector<std::unique_ptr<IMDIterator>> out;
1688 for (size_t i = 0; i < numCores; i++) {
1689 size_t begin = (i * numElements) / numCores;
1690 size_t end = ((i + 1) * numElements) / numCores;
1691 if (end > numElements)
1692 end = numElements;
1693 out.emplace_back(std::make_unique<MatrixWorkspaceMDIterator>(this, function, begin, end));
1694 }
1695 return out;
1696}
1697
1715
1723 const Mantid::API::MDNormalization &normalization) const {
1724 if (this->axes() != 2)
1725 throw std::invalid_argument("MatrixWorkspace::getSignalAtCoord() - "
1726 "Workspace can only have 2 axes, found " +
1727 std::to_string(this->axes()));
1728
1729 // First, find the workspace index
1730 Axis const *ax1 = this->getAxis(1);
1731 size_t wi(-1);
1732 try {
1733 wi = ax1->indexOfValue(coords[1]);
1734 } catch (std::out_of_range &) {
1735 return std::numeric_limits<double>::quiet_NaN();
1736 }
1737
1738 const size_t nhist = this->getNumberHistograms();
1739 const auto &yVals = this->y(wi);
1740 double yBinSize(1.0); // only applies for volume normalization & numeric axis
1741 if (normalization == VolumeNormalization && ax1->isNumeric()) {
1742 size_t uVI = 0; // unused vertical index.
1743 double currentVertical = ax1->operator()(wi, uVI);
1744 if (wi + 1 == nhist && nhist > 1) // On the boundary, look back to get diff
1745 {
1746 yBinSize = currentVertical - ax1->operator()(wi - 1, uVI);
1747 } else {
1748 yBinSize = ax1->operator()(wi + 1, uVI) - currentVertical;
1749 }
1750 }
1751
1752 if (wi < nhist) {
1753 const auto &xVals = x(wi);
1754 size_t i;
1755 try {
1756 coord_t xCoord = coords[0];
1757 if (isHistogramData())
1758 i = Kernel::VectorHelper::indexOfValueFromEdges(xVals.rawData(), xCoord);
1759 else
1760 i = Kernel::VectorHelper::indexOfValueFromCenters(xVals.rawData(), xCoord);
1761 } catch (std::out_of_range &) {
1762 return std::numeric_limits<double>::quiet_NaN();
1763 }
1764
1765 double yVal = yVals[i];
1766 // What is our normalization factor?
1767 switch (normalization) {
1768 case NoNormalization:
1769 return yVal;
1770 case VolumeNormalization: {
1771 // Divide the signal by the area
1772 auto volume = yBinSize * (xVals[i + 1] - xVals[i]);
1773 if (volume == 0.0) {
1774 return std::numeric_limits<double>::quiet_NaN();
1775 }
1776 return yVal / volume;
1777 }
1779 // Not yet implemented, may not make sense
1780 return yVal;
1781 }
1782 // This won't happen
1783 return yVal;
1784 } else {
1785 return std::numeric_limits<double>::quiet_NaN();
1786 }
1787}
1788
1797 const Mantid::API::MDNormalization &normalization) const {
1798 return getSignalAtCoord(coords, normalization);
1799}
1800
1801/*
1802MDMasking for a Matrix Workspace has not been implemented.
1803@param :
1804*/
1805void MatrixWorkspace::setMDMasking(std::unique_ptr<Mantid::Geometry::MDImplicitFunction> /*maskingRegion*/) {
1806 throw std::runtime_error("MatrixWorkspace::setMDMasking has no implementation");
1807}
1808
1809/*
1810Clear MDMasking for a Matrix Workspace has not been implemented.
1811*/
1813 throw std::runtime_error("MatrixWorkspace::clearMDMasking has no implementation");
1814}
1815
1822
1823// Check if this class has an oriented lattice on a sample object
1825
1837 size_t start, size_t stop, size_t width, size_t indexStart,
1838 size_t indexEnd) const {
1839 // width must be provided (for now)
1840 if (width == 0) {
1841 throw std::runtime_error("Cannot create image with width 0");
1842 }
1843
1844 size_t nHist = getNumberHistograms();
1845 // use all spectra by default
1846 if (stop == 0) {
1847 stop = nHist;
1848 }
1849
1850 // check start and stop
1851 if (stop < start) {
1852 throw std::runtime_error("Cannot create image for an empty data set.");
1853 }
1854
1855 if (start >= nHist) {
1856 throw std::runtime_error("Cannot create image: start index is out of range");
1857 }
1858
1859 if (stop >= nHist) {
1860 throw std::runtime_error("Cannot create image: stop index is out of range");
1861 }
1862
1863 // calculate image geometry
1864 size_t dataSize = stop - start + 1;
1865 size_t height = dataSize / width;
1866
1867 // and check that the data fits exactly into this geometry
1868 if (height * width != dataSize) {
1869 throw std::runtime_error("Cannot create image: the data set cannot form a rectangle.");
1870 }
1871
1872 size_t nBins = blocksize();
1873 bool isHisto = isHistogramData();
1874
1875 // default indexEnd is the last index of the X vector
1876 if (indexEnd == 0) {
1877 indexEnd = nBins;
1878 if (!isHisto && indexEnd > 0)
1879 --indexEnd;
1880 }
1881
1882 // check the x-range indices
1883 if (indexEnd < indexStart) {
1884 throw std::runtime_error("Cannot create image for an empty data set.");
1885 }
1886
1887 if (indexStart >= nBins || indexEnd > nBins || (!isHisto && indexEnd == nBins)) {
1888 throw std::runtime_error("Cannot create image: integration interval is out of range.");
1889 }
1890
1891 // initialize the image
1892 auto image = std::make_shared<MantidImage>(height);
1893 if (!isHisto)
1894 ++indexEnd;
1895
1896 // deal separately with single-binned workspaces: no integration is required
1897 if (isHisto && indexEnd == indexStart + 1) {
1899 for (int i = 0; i < static_cast<int>(height); ++i) {
1900 auto &row = (*image)[i];
1901 row.resize(width);
1902 size_t spec = start + static_cast<size_t>(i) * width;
1903 for (size_t j = 0; j < width; ++j, ++spec) {
1904 row[j] = (this->*read)(spec)[indexStart];
1905 }
1906 }
1907 } else {
1908 // each image pixel is integrated over the x-range [indexStart,indexEnd)
1910 for (int i = 0; i < static_cast<int>(height); ++i) {
1911 auto &row = (*image)[i];
1912 row.resize(width);
1913 size_t spec = start + static_cast<size_t>(i) * width;
1914 for (size_t j = 0; j < width; ++j, ++spec) {
1915 auto &V = (this->*read)(spec);
1916 row[j] = std::accumulate(V.begin() + indexStart, V.begin() + indexEnd, 0.0);
1917 }
1918 }
1919 }
1920
1921 return image;
1922}
1923
1924std::pair<int64_t, int64_t> MatrixWorkspace::findY(double value, const std::pair<int64_t, int64_t> &idx) const {
1925 std::pair<int64_t, int64_t> out(-1, -1);
1926 const int64_t numHists = static_cast<int64_t>(this->getNumberHistograms());
1927 if (std::isnan(value)) {
1928 for (int64_t i = idx.first; i < numHists; ++i) {
1929 const auto &Y = this->y(i);
1930 if (auto it = std::find_if(std::next(Y.begin(), idx.second), Y.end(), [](double v) { return std::isnan(v); });
1931 it != Y.end()) {
1932 out = {i, std::distance(Y.begin(), it)};
1933 break;
1934 }
1935 }
1936 } else {
1937 for (int64_t i = idx.first; i < numHists; ++i) {
1938 const auto &Y = this->y(i);
1939 if (auto it = std::find(std::next(Y.begin(), idx.second), Y.end(), value); it != Y.end()) {
1940 out = {i, std::distance(Y.begin(), it)};
1941 break;
1942 }
1943 }
1944 }
1945 return out;
1946}
1947
1954std::pair<size_t, size_t> MatrixWorkspace::getImageStartEndXIndices(size_t i, double startX, double endX) const {
1955 if (startX == EMPTY_DBL())
1956 startX = x(i).front();
1957 auto pStart = getXIndex(i, startX, true);
1958 if (pStart.second != 0.0) {
1959 throw std::runtime_error("Start X value is required to be on bin boundary.");
1960 }
1961 if (endX == EMPTY_DBL())
1962 endX = x(i).back();
1963 auto pEnd = getXIndex(i, endX, false, pStart.first);
1964 if (pEnd.second != 0.0) {
1965 throw std::runtime_error("End X value is required to be on bin boundary.");
1966 }
1967 return std::make_pair(pStart.first, pEnd.first);
1968}
1969
1978MantidImage_sptr MatrixWorkspace::getImageY(size_t start, size_t stop, size_t width, double startX, double endX) const {
1979 auto p = getImageStartEndXIndices(0, startX, endX);
1980 return getImage(&MatrixWorkspace::readY, start, stop, width, p.first, p.second);
1981}
1982
1991MantidImage_sptr MatrixWorkspace::getImageE(size_t start, size_t stop, size_t width, double startX, double endX) const {
1992 auto p = getImageStartEndXIndices(0, startX, endX);
1993 return getImage(&MatrixWorkspace::readE, start, stop, width, p.first, p.second);
1994}
1995
2008std::pair<size_t, double> MatrixWorkspace::getXIndex(size_t i, double x, bool isLeft, size_t start) const {
2009 auto &X = this->x(i);
2010 auto nx = X.size();
2011
2012 // if start out of range - search failed
2013 if (start >= nx)
2014 return std::make_pair(nx, 0.0);
2015 if (start > 0 && start == nx - 1) {
2016 // starting with the last index is allowed for right boundary search
2017 if (!isLeft)
2018 return std::make_pair(start, 0.0);
2019 return std::make_pair(nx, 0.0);
2020 }
2021
2022 // consider point data with single value
2023 if (nx == 1) {
2024 assert(start == 0);
2025 if (isLeft)
2026 return x <= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2027 return x >= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2028 }
2029
2030 // left boundaries below start value map to the start value
2031 if (x <= X[start]) {
2032 return isLeft ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2033 }
2034 // right boundary search returns last x value for all values above it
2035 if (x >= X.back()) {
2036 return !isLeft ? std::make_pair(nx - 1, 0.0) : std::make_pair(nx, 0.0);
2037 }
2038
2039 // general case: find the boundary index and bin fraction
2040 auto end = X.end();
2041 for (auto ix = X.begin() + start + 1; ix != end; ++ix) {
2042 if (*ix >= x) {
2043 auto index = static_cast<size_t>(std::distance(X.begin(), ix));
2044 if (isLeft)
2045 --index;
2046 return std::make_pair(index, std::abs((X[index] - x) / (*ix - *(ix - 1))));
2047 }
2048 }
2049 // I don't think we can ever get here
2050 return std::make_pair(nx, 0.0);
2051}
2052
2061void MatrixWorkspace::setImage(MantidVec &(MatrixWorkspace::*dataVec)(const std::size_t), const MantidImage &image,
2062 size_t start, [[maybe_unused]] bool parallelExecution) {
2063
2064 if (image.empty())
2065 return;
2066 if (image[0].empty())
2067 return;
2068
2069 if (blocksize() != 1) {
2070 throw std::runtime_error("Cannot set image: a single bin workspace is expected.");
2071 }
2072
2073 size_t height = image.size();
2074 size_t width = image.front().size();
2075 size_t dataSize = width * height;
2076
2077 if (start + dataSize > getNumberHistograms()) {
2078 throw std::runtime_error("Cannot set image: image is bigger than workspace.");
2079 }
2080
2081 PARALLEL_FOR_IF(parallelExecution)
2082 for (int i = 0; i < static_cast<int>(height); ++i) {
2083 auto &row = image[i];
2084 if (row.size() != width) {
2085 throw std::runtime_error("Canot set image: image is corrupted.");
2086 }
2087 size_t spec = start + static_cast<size_t>(i) * width;
2088 auto rowEnd = row.end();
2089 for (auto pixel = row.begin(); pixel != rowEnd; ++pixel, ++spec) {
2090 (this->*dataVec)(spec)[0] = *pixel;
2091 }
2092 }
2093}
2094
2101void MatrixWorkspace::setImageY(const MantidImage &image, size_t start, bool parallelExecution) {
2102 setImage(&MatrixWorkspace::dataY, image, start, parallelExecution);
2103}
2104
2111void MatrixWorkspace::setImageE(const MantidImage &image, size_t start, bool parallelExecution) {
2112 setImage(&MatrixWorkspace::dataE, image, start, parallelExecution);
2113}
2114
2116
2124 setDetectorGrouping(index, getSpectrum(index).getDetectorIDs());
2125}
2126
2128 const auto &detInfo = detectorInfo();
2129 size_t numberOfDetectors{detInfo.size()};
2130 if (numberOfDetectors == 0) {
2131 // Default to empty spectrum definitions if there is no instrument.
2132 m_indexInfo->setSpectrumDefinitions(std::vector<SpectrumDefinition>(m_indexInfo->size()));
2133 return;
2134 }
2135 size_t numberOfSpectra = numberOfDetectors * detInfo.scanCount();
2136 if (numberOfSpectra != m_indexInfo->globalSize())
2137 throw std::invalid_argument("MatrixWorkspace: IndexInfo does not contain spectrum definitions so "
2138 "building a 1:1 mapping from spectra to detectors was attempted, but "
2139 "the number of spectra in the workspace is not equal to the number of "
2140 "detectors in the instrument.");
2141 std::vector<SpectrumDefinition> specDefs(m_indexInfo->size());
2142 if (!detInfo.isScanning() && (numberOfSpectra == m_indexInfo->size())) {
2143 for (size_t i = 0; i < numberOfSpectra; ++i)
2144 specDefs[i].add(i);
2145 } else {
2146 size_t specIndex = 0;
2147 size_t globalSpecIndex = 0;
2148 for (size_t detIndex = 0; detIndex < detInfo.size(); ++detIndex) {
2149 for (size_t time = 0; time < detInfo.scanCount(); ++time) {
2150 if (m_indexInfo->isOnThisPartition(Indexing::GlobalSpectrumIndex(globalSpecIndex++)))
2151 specDefs[specIndex++].add(detIndex, time);
2152 }
2153 }
2154 }
2155 m_indexInfo->setSpectrumDefinitions(std::move(specDefs));
2156}
2157
2159 const auto &detInfo = detectorInfo();
2160 const auto &allDetIDs = detInfo.detectorIDs();
2161 const auto &specDefs = m_indexInfo->spectrumDefinitions();
2162 const auto indexInfoSize = static_cast<int64_t>(m_indexInfo->size());
2163 enum class ErrorCode { None, InvalidDetIndex, InvalidTimeIndex };
2164 std::atomic<ErrorCode> errorValue(ErrorCode::None);
2165#pragma omp parallel for
2166 for (int64_t i = 0; i < indexInfoSize; ++i) {
2167 auto &spec = getSpectrum(i);
2168 // Prevent setting flags that require spectrum definition updates
2169 spec.setMatrixWorkspace(nullptr, i);
2170 spec.setSpectrumNo(static_cast<specnum_t>(m_indexInfo->spectrumNumber(i)));
2171 std::set<detid_t> detIDs;
2172 for (const auto &index : (*specDefs)[i]) {
2173 const size_t detIndex = index.first;
2174 const size_t timeIndex = index.second;
2175 if (detIndex >= allDetIDs.size()) {
2176 errorValue = ErrorCode::InvalidDetIndex;
2177 } else if (timeIndex >= detInfo.scanCount()) {
2178 errorValue = ErrorCode::InvalidTimeIndex;
2179 } else {
2180 detIDs.insert(allDetIDs[detIndex]);
2181 }
2182 }
2183 spec.setDetectorIDs(std::move(detIDs));
2184 }
2185 switch (errorValue) {
2186 case ErrorCode::InvalidDetIndex:
2187 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2188 "detector index, i.e., the spectrum definition does not match "
2189 "the instrument in the workspace.");
2190 case ErrorCode::InvalidTimeIndex:
2191 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2192 "time index for a detector, i.e., the spectrum definition does "
2193 "not match the instrument in the workspace.");
2194 case ErrorCode::None:; // nothing to do
2195 }
2196}
2197
2198} // namespace Mantid::API
2199
2201namespace Mantid::Kernel {
2202
2203template <>
2205IPropertyManager::getValue<Mantid::API::MatrixWorkspace_sptr>(const std::string &name) const {
2206 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2207 if (prop) {
2208 return *prop;
2209 } else {
2210 std::string message =
2211 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<MatrixWorkspace>.";
2212 throw std::runtime_error(message);
2213 }
2214}
2215
2216template <>
2218IPropertyManager::getValue<Mantid::API::MatrixWorkspace_const_sptr>(const std::string &name) const {
2219 auto const *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2220 if (prop) {
2221 return prop->operator()();
2222 } else {
2223 std::string message =
2224 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<MatrixWorkspace>.";
2225 throw std::runtime_error(message);
2226 }
2227}
2228
2229} // namespace Mantid::Kernel
2230
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
double height
Definition GetAllEi.cpp:155
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
const double EPSILON(1.0E-10)
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_CRITICAL(name)
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
double tolerance
Class to represent the axis of a workspace.
Definition Axis.h:30
virtual double getMin() const =0
returns min value defined on axis
virtual double getMax() const =0
returns max value defined on axis
const std::string & title() const
Returns the user-defined title for this axis.
Definition Axis.cpp:20
virtual size_t indexOfValue(const double value) const =0
Find the index of the given double value.
virtual std::size_t length() const =0
Get the length of the axis.
virtual bool isNumeric() const
Returns true if the axis is numeric.
Definition Axis.h:52
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
Definition Axis.cpp:28
Stores numeric values that are assumed to be bin edge values.
Definition BinEdgeAxis.h:20
This class is shared by a few Workspace types and holds information related to a particular experimen...
Run & mutableRun()
Writable version of the run object.
const SpectrumInfo & spectrumInfo() const
Return a reference to the SpectrumInfo object.
const Geometry::DetectorInfo & detectorInfo() const
Return a const reference to the DetectorInfo object.
const Run & run() const
Run details object access.
Geometry::Instrument_const_sptr getInstrument() const
Returns the parameterized instrument.
const Sample & sample() const
Sample accessors.
const std::string toString() const
Returns a string description of the object.
void setDetectorGrouping(const size_t index, const std::set< detid_t > &detIDs) const
Sets the detector grouping for the spectrum with the given index.
void setSpectrumDefinitions(Kernel::cow_ptr< std::vector< SpectrumDefinition > > spectrumDefinitions)
Sets the SpectrumDefinition for all spectra.
void setNumberOfDetectorGroups(const size_t count) const
Sets the number of detector groups.
Geometry::Instrument_const_sptr sptr_instrument
The base (unparametrized) instrument.
Basic MD Workspace Abstract Class.
virtual LinePlot getLinePlot(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize) const
Method to generate a line plot through a MD-workspace.
HistogramData::Histogram::YMode yMode() const
Definition ISpectrum.h:104
specnum_t getSpectrumNo() const
bool hasDetectorID(const detid_t detID) const
Return true if the given detector ID is in the list for this ISpectrum.
virtual HistogramData::Histogram histogram() const
Returns the Histogram associated with this spectrum.
Definition ISpectrum.h:94
void setYMode(HistogramData::Histogram::YMode ymode)
Definition ISpectrum.h:105
const std::set< detid_t > & getDetectorIDs() const
Get a const reference to the detector IDs set.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
const Types::Core::DateAndTime getFirstPulseTime() const
Return the first pulse time from sample logs.
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:91
const Types::Core::DateAndTime getLastPulseTime() const
Return the last pulse time from sample logs.
coord_t getX(size_t ind) const override
Get coordinate for index;.
size_t getNBoundaries() const override
number of bin boundaries (axis points)
const Geometry::MDFrame_const_uptr m_frame
const std::string m_dimensionId
std::string getName() const override
the name of the dimennlsion as can be displayed along the axis
std::string toXMLString() const override
size_t getNBins() const override
number of bins dimension have (an integrated has one).
const Kernel::MDUnit & getMDUnits() const override
coord_t getMinimum() const override
const Kernel::UnitLabel getUnits() const override
const std::string & getDimensionId() const override
short name which identify the dimension among other dimension.
coord_t getBinWidth() const override
Return the bin width taking into account if the stored values are actually bin centres or not.
void setRange(size_t, coord_t, coord_t) override
Change the extents and number of bins.
coord_t getMaximum() const override
const Geometry::MDFrame & getMDFrame() const override
bool getIsIntegrated() const override
if the dimension is integrated (e.g. have single bin)
MWDimension(const Axis *axis, std::string dimensionId)
An implementation of IMDDimension for MatrixWorkspace that points to the X vector of the first spectr...
const Geometry::MDFrame & getMDFrame() const override
coord_t getX(size_t ind) const override
Get coordinate for index;.
const Geometry::MDFrame_const_uptr m_frame
Unit.
const MatrixWorkspace * m_ws
Workspace we refer to.
std::string getName() const override
the name of the dimennlsion as can be displayed along the axis
const Kernel::UnitLabel getUnits() const override
size_t getNBins() const override
number of bins dimension have (an integrated has one).
size_t getNBoundaries() const override
number of axis points (bin boundaries)
MWXDimension(const MatrixWorkspace *ws, std::string dimensionId)
const std::string & getDimensionId() const override
short name which identify the dimension among other dimension.
MantidVec m_X
Cached X vector.
const std::string m_dimensionId
Dimension ID string.
bool getIsIntegrated() const override
if the dimension is integrated (e.g. have single bin)
std::string toXMLString() const override
void setRange(size_t, coord_t, coord_t) override
Change the extents and number of bins.
coord_t getMinimum() const override
coord_t the minimum extent of this dimension
coord_t getMaximum() const override
const Kernel::MDUnit & getMDUnits() const override
Base MatrixWorkspace Abstract Class.
std::string YUnitLabel(bool useLatex=false, bool plotAsDistribution=false) const
Returns a caption for the units of the data in the workspace.
const MaskList & maskedBins(const size_t &workspaceIndex) const
Returns the list of masked bins for a spectrum.
virtual std::pair< int64_t, int64_t > findY(double value, const std::pair< int64_t, int64_t > &idx={0, 0}) const
Find first index in Y equal to value.
void setMarkerStyle(const std::string &markerType)
Set the marker style for plotting.
std::vector< specnum_t > getSpectraFromDetectorIDs(const std::vector< detid_t > &detIdList) const
Converts a list of detector IDs to the corresponding spectrum numbers.
virtual Types::Core::DateAndTime getFirstPulseTime() const
Return the time of the first pulse received, by accessing the run's sample logs to find the proton_ch...
std::vector< std::unique_ptr< IMDIterator > > createIterators(size_t suggestedNumCores=1, Mantid::Geometry::MDImplicitFunction *function=nullptr) const override
Create iterators.
void rebuildSpectraMapping(const bool includeMonitors=true, const specnum_t specNumOffset=1)
Build the default spectra mapping, most likely wanted after an instrument update.
const MantidVec & readE(std::size_t const index) const
Deprecated, use e() instead.
virtual ISpectrum & getSpectrum(const size_t index)=0
Return the underlying ISpectrum ptr at the given workspace index.
std::vector< std::unique_ptr< Axis > > m_axes
A vector of pointers to the axes for this workspace.
virtual size_t getMemorySizeForXAxes() const
Returns the memory used (in bytes) by the X axes, handling ragged bins.
double detectorSignedTwoTheta(const Geometry::IDetector &det) const
Returns the signed 2Theta scattering angle for a detector.
std::pair< size_t, size_t > getImageStartEndXIndices(size_t i, double startX, double endX) const
Get start and end x indices for images.
virtual void updateSpectraUsing(const SpectrumDetectorMapping &map)
bool hasAnyMaskedBins() const
Does this workspace contain any masked bins.
virtual bool isHistogramDataByIndex(std::size_t index=0) const
Whether the specified histogram contains histogram data (ie bins)
virtual std::vector< size_t > getDetectorIDToWorkspaceIndexVector(detid_t &offset, bool throwIfMultipleDets=false) const
Return a vector where: The index into the vector = DetectorID (pixel ID) + offset The value at that i...
Types::Core::DateAndTime getLastPulseTime() const
Return the time of the last pulse received, by accessing the run's sample logs to find the proton_cha...
virtual bool isCommonLogBins() const
Returns true if the workspace contains common X bins with log spacing.
std::pair< size_t, double > getXIndex(size_t i, double x, bool isLeft=true, size_t start=0) const
Return an index in the X vector for an x-value close to a given value.
void setUnmaskedBins(const size_t workspaceIndex)
Removes the mask from an index.
bool m_isInitialized
Has this workspace been initialised?
std::unique_ptr< Indexing::IndexInfo > m_indexInfo
std::atomic< bool > m_indexInfoNeedsUpdate
static const std::string xDimensionId
Dimension id for x-dimension.
double detectorTwoTheta(const Geometry::IDetector &det) const
Returns the 2Theta scattering angle for a detector.
std::string m_YUnit
The unit for the data values (e.g. Counts)
void updateCachedDetectorGrouping(const size_t index) const override
Update detector grouping for spectrum with given index.
virtual std::size_t blocksize() const =0
Returns the size of each block of data returned by the dataY accessors.
signal_t getSignalAtCoord(const coord_t *coords, const Mantid::API::MDNormalization &normalization) const override
Get the signal at a coordinate in the workspace.
MantidImage_sptr getImageY(size_t start=0, size_t stop=0, size_t width=0, double startX=EMPTY_DBL(), double endX=EMPTY_DBL()) const
Create an image of Ys.
std::shared_ptr< MatrixWorkspace > m_monitorWorkspace
A workspace holding monitor data relating to the main data in the containing workspace (null if none)...
virtual double getXMin() const
void initialize(const std::size_t &NVectors, const std::size_t &XLength, const std::size_t &YLength)
Initialize the workspace.
virtual void setMonitorWorkspace(const std::shared_ptr< MatrixWorkspace > &monitorWS)
Sets the internal monitor workspace to the provided workspace.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
void setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins)
Set the list of masked bins for given workspaceIndex.
std::size_t binIndexOfValue(Mantid::HistogramData::HistogramX const &xValues, const double xValue, const bool ascendingOrder) const
Returns the bin index of the given X value.
bool hasMaskedBins(const size_t &workspaceIndex) const
Does this spectrum contain any masked bins.
virtual bool hasOrientedLattice() const override
void setTitle(const std::string &) override
Sets MatrixWorkspace title.
bool hasGroupedDetectors() const
Does the workspace has any grouped detectors?
virtual std::vector< size_t > getSpectrumToWorkspaceIndexVector(specnum_t &offset) const
Return a vector where: The index into the vector = spectrum number + offset The value at that index =...
std::map< size_t, double > MaskList
Masked bins for each spectrum are stored as a set of pairs containing <bin index, weight>
std::mutex m_isCommonBinsMutex
A mutex protecting the update of m_isCommonBinsFlag.
virtual void setImageE(const MantidImage &image, size_t start=0, bool parallelExecution=true)
Copy the data from an image to this workspace's errors.
std::vector< size_t > getIndicesFromSpectra(const std::vector< specnum_t > &spectraList) const
Converts a list of spectrum numbers to the corresponding workspace indices.
void setImage(MantidVec &(MatrixWorkspace::*dataVec)(const std::size_t), const MantidImage &image, size_t start, bool parallelExecution)
Copy data from an image.
std::size_t yIndexOfX(const double xValue, const std::size_t &index=0, const double tolerance=0.0) const
Returns the y index which corresponds to the X Value provided.
~MatrixWorkspace() override
Delete.
std::map< int64_t, MaskList > m_masks
The set of masked bins in a map keyed on workspace index.
virtual void setImageY(const MantidImage &image, size_t start=0, bool parallelExecution=true)
Copy the data (Y's) from an image to this workspace.
virtual MantidVec & dataE(const std::size_t index)
Deprecated, use mutableE() instead. Returns the error data.
bool isDistribution() const
Are the Y-values dimensioned?
void flagMasked(const size_t &index, const size_t &binIndex, const double &weight=1.0)
Writes the masking weight to m_masks (doesn't alter y-values).
virtual Kernel::cow_ptr< HistogramData::HistogramX > refX(const std::size_t index) const
Deprecated, use sharedX() instead. Returns a pointer to the x data.
MantidImage_sptr getImageE(size_t start=0, size_t stop=0, size_t width=0, double startX=EMPTY_DBL(), double endX=EMPTY_DBL()) const
Create an image of Es.
void setMDMasking(std::unique_ptr< Mantid::Geometry::MDImplicitFunction > maskingRegion) override
Apply masking.
void maskBin(const size_t &workspaceIndex, const size_t &binIndex, const double &weight=1.0)
Called by the algorithm MaskBins to mask a single bin for the first time, algorithms that later propa...
std::string getMarkerStyle() const
Get the marker style for plotting.
std::shared_ptr< MatrixWorkspace > monitorWorkspace() const
Returns a pointer to the internal monitor workspace.
LinePlot getLinePlot(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize) const override
Generate a line plot through the matrix workspace.
std::vector< size_t > maskedBinsIndices(const size_t &workspaceIndex) const
virtual bool isIntegerBins() const
Returns true if the workspace has common, integer X bins.
HistogramData::Histogram histogram(const size_t index) const
Returns the Histogram at the given workspace index.
std::vector< size_t > getIndicesFromDetectorIDs(const std::vector< detid_t > &detIdList) const
Converts a list of detector IDs to the corresponding workspace indices.
const std::string getTitle() const override
Gets MatrixWorkspace title (same as Run object run_title property)
void setDistribution(bool newValue)
Set the flag for whether the Y-values are dimensioned.
size_t getMemorySize() const override
Get the footprint in memory in bytes.
const Indexing::IndexInfo & indexInfo() const
Returns a const reference to the IndexInfo object of the workspace.
virtual void getIntegratedSpectra(std::vector< double > &out, const double minX, const double maxX, const bool entireRange) const
Return a vector with the integrated counts for all spectra withing the given range.
float getMarkerSize() const
Get the size of the marker for plotting.
uint64_t getNPoints() const override
Gets the number of points available on the workspace.
std::string getPlotType() const
Gets MatrixWorkspace plot_type.
const MantidVec & readY(std::size_t const index) const
Deprecated, use y() instead.
detid2index_map getDetectorIDToWorkspaceIndexMap(bool throwIfMultipleDets=false, bool ignoreIfNoValidDets=false) const
Return a map where: KEY is the DetectorID (pixel ID) VALUE is the Workspace Index.
std::atomic< bool > m_isCommonBinsFlagValid
Flag indicating if the common bins flag is in a valid state.
std::string getDimensionIdFromAxis(const int &axisIndex) const
Getter for the dimension id based on the axis.
virtual Axis * getAxis(const std::size_t &axisIndex) const
Get a non owning pointer to a workspace axis.
void setPlotType(const std::string &)
Sets MatrixWorkspace plot_type.
std::vector< double > getIntegratedCountsForWorkspaceIndices(const std::vector< size_t > &workspaceIndices, const double minX, const double maxX, const bool entireRange) const
size_t getNumDims() const override
virtual double getXMax() const
std::atomic< bool > m_isCommonBinsFlag
Flag indicating whether the data has common bins.
HistogramData::HistogramE & mutableE(const size_t index) &
void setIndexInfoWithoutISpectrumUpdate(const Indexing::IndexInfo &indexInfo)
Variant of setIndexInfo, used by WorkspaceFactoryImpl.
static const std::string yDimensionId
Dimensin id for y-dimension.
spec2index_map getSpectrumToWorkspaceIndexMap() const
Return a map where: KEY is the Spectrum # VALUE is the Workspace Index.
const MantidVec & readX(std::size_t const index) const
Deprecated, use x() instead.
size_t getIndexFromSpectrumNumber(const specnum_t specNo) const
Given a spectrum number, find the corresponding workspace index.
MatrixWorkspace()
Default constructor.
void replaceAxis(const std::size_t &axisIndex, std::unique_ptr< Axis > newAxis)
Replaces one of the workspace's axes with the new one provided.
virtual void getXMinMax(double &xmin, double &xmax) const
virtual std::size_t size() const =0
Returns the number of single indexable items in the workspace.
virtual void init(const std::size_t &NVectors, const std::size_t &XLength, const std::size_t &YLength)=0
Initialises the workspace.
MantidImage_sptr getImage(const MantidVec &(MatrixWorkspace::*read)(std::size_t const) const, size_t start, size_t stop, size_t width, size_t indexStart, size_t indexEnd) const
Create an MantidImage instance.
virtual MantidVec & dataY(const std::size_t index)
Deprecated, use mutableY() instead. Returns the y data.
const std::string toString() const override
String description of state.
HistogramData::HistogramY & mutableY(const size_t index) &
Mantid::Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const override
void setYUnitLabel(const std::string &newLabel)
Sets a new caption for the data (Y axis) in the workspace.
signal_t getSignalWithMaskAtCoord(const coord_t *coords, const Mantid::API::MDNormalization &normalization) const override
Get the signal at a coordinate in the workspace.
void setMarkerSize(const float markerSize)
Set the size of the marker for plotting.
std::shared_ptr< const Mantid::Geometry::IMDDimension > getDimension(size_t index) const override
Get a dimension.
virtual bool isCommonBins() const
Returns true if the workspace contains common X bins.
std::shared_ptr< const Geometry::IDetector > getDetector(const size_t workspaceIndex) const
Get the effective detector for the given spectrum.
void setYUnit(const std::string &newUnit)
Sets a new unit for the data (Y axis) in the workspace.
size_t numberOfAxis() const
Will return the number of Axis currently stored in the workspace it is not always safe to assume it i...
std::string m_YUnitLabel
A text label for use when plotting spectra.
virtual bool isHistogramData() const
Returns true if the workspace contains data in histogram form (as opposed to point-like)
void setIndexInfo(const Indexing::IndexInfo &indexInfo)
Sets the IndexInfo object of the workspace.
void clearMDMasking() override
Clear exsting masking.
std::size_t xIndexOfValue(const Mantid::HistogramData::HistogramX &xValues, const double xValue, const double tolerance) const
Returns the X index of the given X value.
std::shared_ptr< const Mantid::Geometry::IMDDimension > getDimensionWithId(std::string id) const override
Get a dimension.
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
size_t getMemorySize() const override
Return an approximate memory size for the object in bytes.
Definition Run.cpp:517
bool hasOrientedLattice() const
Definition Sample.cpp:178
Class to represent the spectra axis of a workspace.
Definition SpectraAxis.h:31
A minimal class to hold the mapping between the spectrum number and its related detector ID numbers f...
const std::set< detid_t > & getDetectorIDsForSpectrumNo(const specnum_t spectrumNo) const
const std::set< detid_t > & getDetectorIDsForSpectrumIndex(const size_t spectrumIndex) const
bool threadSafe() const override
Marks the workspace as safe for multiple threads to edit data simutaneously.
Definition Workspace.h:66
virtual void setTitle(const std::string &)
Set the title of the workspace.
Definition Workspace.cpp:27
virtual const std::string getTitle() const
Get the workspace title.
Definition Workspace.cpp:47
GeneralFrame : Any MDFrame that isn't related to momemtum transfer.
Interface class for detector objects.
Definition IDetector.h:43
virtual double getTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis) const =0
Gives the angle of this detector object with respect to an axis.
virtual double getSignedTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis, const Kernel::V3D &instrumentUp) const =0
Gives the signed angle of this detector object with respect to an axis.
The class describes one dimension of multidimensional dataset representing an orthogonal dimension an...
MDFrame : The coordinate frame for a dimension, or set of dimensions in a multidimensional workspace.
Definition MDFrame.h:22
An "ImplicitFunction" defining a hyper-cuboid-shaped region in N dimensions.
virtual const std::string id() const =0
A string ID for the class.
Exception for index errors.
Definition Exception.h:284
Exception for errors associated with the instrument definition.
Definition Exception.h:220
Exception for when an item is not found in a collection.
Definition Exception.h:145
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
MDUnit : Unit type for multidimensional data types.
Definition MDUnit.h:20
The concrete, templated class for properties.
virtual std::string value() const =0
Returns the value of the property as a string.
A specialised Property class for holding a series of time-value pairs.
A base-class for the a class that is able to return unit labels in different representations.
Definition UnitLabel.h:20
Class for 3D vectors.
Definition V3D.h:34
bool nullVector(const double tolerance=1e-3) const noexcept
Determine if the point is null.
Definition V3D.cpp:238
std::vector< std::vector< double > > MantidImage
typedef for the image type
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
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< MantidImage > MantidImage_sptr
shared pointer to MantidImage
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:167
std::unique_ptr< const MDFrame > MDFrame_const_uptr
Definition MDFrame.h:37
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition IDetector.h:102
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
size_t MANTID_KERNEL_DLL indexOfValueFromCenters(const std::vector< double > &bin_centers, const double value)
Gets the bin of a value from a vector of bin centers and throws exception if out of range.
size_t MANTID_KERNEL_DLL indexOfValueFromEdges(const std::vector< double > &bin_edges, const double value)
Gets the bin of a value from a vector of bin edges.
SpecialCoordinateSystem
Special coordinate systems for Q3D.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition V3D.h:352
std::unordered_map< specnum_t, size_t > spec2index_map
Map with key = spectrum number, value = workspace index.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition MDTypes.h:27
int32_t detid_t
Typedef for a detector ID.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
const std::vector< std::string > validPlotTypes
double signal_t
Typedef for the signal recorded in a MDBox, etc.
Definition MDTypes.h:36
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
const std::vector< std::string > validMarkerStyles
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
Holds X, Y, E for a line plot.