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 const std::vector<detid_t> pixelIDs = this->getInstrument()->getDetectorIDs(!includeMonitors);
440
441 try {
442 const size_t NUM_HIST = this->getNumberHistograms();
443 size_t index = 0;
444 std::vector<detid_t>::const_iterator iend = pixelIDs.end();
445 for (std::vector<detid_t>::const_iterator it = pixelIDs.begin(); it != iend; ++it) {
446 // The detector ID
447 const detid_t detId = *it;
448 const auto specNo = specnum_t(index + specNumOffset);
449
450 if (index < NUM_HIST) {
451 auto &spec = getSpectrum(index);
452 spec.setSpectrumNo(specNo);
453 spec.setDetectorID(detId);
454 }
455
456 index++;
457 }
458
459 } catch (std::runtime_error &) {
460 throw;
461 }
462}
463
469 auto const *ax = dynamic_cast<SpectraAxis *>(this->m_axes[1].get());
470 if (!ax)
471 throw std::runtime_error("MatrixWorkspace::getSpectrumToWorkspaceIndexMap: "
472 "axis[1] is not a SpectraAxis, so I cannot "
473 "generate a map.");
474 try {
475 return ax->getSpectraIndexMap();
476 } catch (std::runtime_error &) {
477 g_log.error() << "MatrixWorkspace::getSpectrumToWorkspaceIndexMap: no elements!";
478 throw;
479 }
480}
481
491 auto const *ax = dynamic_cast<SpectraAxis *>(this->m_axes[1].get());
492 if (!ax)
493 throw std::runtime_error("MatrixWorkspace::getSpectrumToWorkspaceIndexMap: "
494 "axis[1] is not a SpectraAxis, so I cannot "
495 "generate a map.");
496
497 // Find the min/max spectra IDs
498 specnum_t min = std::numeric_limits<specnum_t>::max(); // So that any number
499 // will be less than this
500 specnum_t max = -std::numeric_limits<specnum_t>::max(); // So that any number
501 // will be greater than
502 // this
503 size_t length = ax->length();
504 for (size_t i = 0; i < length; i++) {
505 specnum_t spec = ax->spectraNo(i);
506 if (spec < min)
507 min = spec;
508 if (spec > max)
509 max = spec;
510 }
511
512 // Offset so that the "min" value goes to index 0
513 offset = -min;
514
515 // Size correctly
516 std::vector<size_t> out(max - min + 1, 0);
517
518 // Make the vector
519 for (size_t i = 0; i < length; i++) {
520 specnum_t spec = ax->spectraNo(i);
521 out[spec + offset] = i;
522 }
523
524 return out;
525}
526
531 bool retVal = false;
532
533 // Loop through the workspace index
534 for (size_t workspaceIndex = 0; workspaceIndex < this->getNumberHistograms(); workspaceIndex++) {
535 auto detList = getSpectrum(workspaceIndex).getDetectorIDs();
536 if (detList.size() > 1) {
537 retVal = true;
538 break;
539 }
540 }
541 return retVal;
542}
543
558 bool ignoreIfNoValidDets) const {
559 detid2index_map map;
560 const auto &specInfo = spectrumInfo();
561
562 // Loop through the workspace index
563 for (size_t workspaceIndex = 0; workspaceIndex < this->getNumberHistograms(); ++workspaceIndex) {
564 // Workspaces can contain invalid detector IDs. hasDetectors will silently ignore them until this is fixed.
565 if (ignoreIfNoValidDets && !specInfo.hasDetectors(workspaceIndex)) {
566 continue;
567 }
568 auto detList = getSpectrum(workspaceIndex).getDetectorIDs();
569
570 if (throwIfMultipleDets) {
571 if (detList.size() > 1) {
572 throw std::runtime_error("MatrixWorkspace::getDetectorIDToWorkspaceIndexMap(): more than 1 "
573 "detector for one histogram! I cannot generate a map of detector "
574 "ID to workspace index.");
575 }
576
577 // Set the KEY to the detector ID and the VALUE to the workspace index.
578 if (detList.size() == 1)
579 map[*detList.begin()] = workspaceIndex;
580 } else {
581 // Allow multiple detectors per workspace index
582 for (auto det : detList)
583 map[det] = workspaceIndex;
584 }
585
586 // Ignore if the detector list is empty.
587 }
588
589 return map;
590}
591
605 bool throwIfMultipleDets) const {
606 // Make a correct initial size
607 std::vector<size_t> out;
608 detid_t minId = 0;
609 detid_t maxId = 0;
610 this->getInstrument()->getMinMaxDetectorIDs(minId, maxId);
611 offset = -minId;
612 const int outSize = maxId - minId + 1;
613 // Allocate at once
614 out.resize(outSize, std::numeric_limits<size_t>::max());
615
616 for (size_t workspaceIndex = 0; workspaceIndex < getNumberHistograms(); ++workspaceIndex) {
617 // Get the list of detectors from the WS index
618 const auto &detList = this->getSpectrum(workspaceIndex).getDetectorIDs();
619
620 if (throwIfMultipleDets && (detList.size() > 1))
621 throw std::runtime_error("MatrixWorkspace::getDetectorIDToWorkspaceIndexVector(): more than 1 "
622 "detector for one histogram! I cannot generate a map of detector ID "
623 "to workspace index.");
624
625 // Allow multiple detectors per workspace index, or,
626 // If only one is allowed, then this has thrown already
627 for (auto det : detList) {
628 int index = det + offset;
629 if (index < 0 || index >= outSize) {
630 g_log.debug() << "MatrixWorkspace::getDetectorIDToWorkspaceIndexVector("
631 "): detector ID found ("
632 << det << " at workspace index " << workspaceIndex << ") is invalid.\n";
633 } else
634 // Save it at that point.
635 out[index] = workspaceIndex;
636 }
637
638 } // (for each workspace index)
639 return out;
640}
641
648std::vector<size_t> MatrixWorkspace::getIndicesFromSpectra(const std::vector<specnum_t> &spectraList) const {
649 // Clear the output index list
650 std::vector<size_t> indexList;
651 indexList.reserve(this->getNumberHistograms());
652
653 auto iter = spectraList.cbegin();
654 while (iter != spectraList.cend()) {
655 for (size_t i = 0; i < this->getNumberHistograms(); ++i) {
656 if (this->getSpectrum(i).getSpectrumNo() == *iter) {
657 indexList.emplace_back(i);
658 break;
659 }
660 }
661 ++iter;
662 }
663 return indexList;
664}
665
673 for (size_t i = 0; i < this->getNumberHistograms(); ++i) {
674 if (this->getSpectrum(i).getSpectrumNo() == specNo)
675 return i;
676 }
677 throw std::runtime_error("Could not find spectrum number in any spectrum.");
678}
679
691std::vector<size_t> MatrixWorkspace::getIndicesFromDetectorIDs(const std::vector<detid_t> &detIdList) const {
692 if (m_indexInfo->size() != m_indexInfo->globalSize())
693 throw std::runtime_error("MatrixWorkspace: Using getIndicesFromDetectorIDs "
694 "in a parallel run is most likely incorrect. "
695 "Aborting.");
696
697 // create a set because looking for existence of value is faster than from vector
698 std::set<detid_t> detIdSet(detIdList.cbegin(), detIdList.cend());
699
700 // create a mapping of detector number to workspace index
701 std::map<detid_t, std::set<size_t>> detectorIDtoWSIndices;
702 const size_t NUM_HIST = getNumberHistograms();
703 for (size_t i = 0; i < NUM_HIST; ++i) {
704 const auto &detIDs = getSpectrum(i).getDetectorIDs();
705 for (const auto &detID : detIDs) {
706 // only add things to the map that are being asked for
707 if (detIdSet.count(detID) > 0) {
708 detectorIDtoWSIndices[detID].insert(i);
709 }
710 }
711 }
712
713 // create a vector of workspace indices with the same order as the input list
714 std::vector<size_t> indexList;
715 indexList.reserve(detIdList.size());
716 for (const auto &detId : detIdList) {
717 const auto wsIndices = detectorIDtoWSIndices.find(detId);
718 if (wsIndices != detectorIDtoWSIndices.end()) {
719 std::copy(wsIndices->second.cbegin(), wsIndices->second.cend(), std::back_inserter(indexList));
720 }
721 }
722
723 return indexList;
724}
725
733std::vector<specnum_t> MatrixWorkspace::getSpectraFromDetectorIDs(const std::vector<detid_t> &detIdList) const {
734 std::vector<specnum_t> spectraList;
735
736 // Try every detector in the list
737 for (auto detId : detIdList) {
738 bool foundDet = false;
739 specnum_t foundSpecNum = 0;
740
741 // Go through every histogram
742 for (size_t i = 0; i < this->getNumberHistograms(); i++) {
743 if (this->getSpectrum(i).hasDetectorID(detId)) {
744 foundDet = true;
745 foundSpecNum = this->getSpectrum(i).getSpectrumNo();
746 break;
747 }
748 }
749
750 if (foundDet)
751 spectraList.emplace_back(foundSpecNum);
752 } // for each detector ID in the list
753 return spectraList;
754}
755
757 double xmin;
758 double xmax;
759 this->getXMinMax(xmin, xmax); // delegate to the proper code
760 return xmin;
761}
762
764 double xmin;
765 double xmax;
766 this->getXMinMax(xmin, xmax); // delegate to the proper code
767 return xmax;
768}
769
770void MatrixWorkspace::getXMinMax(double &xmin, double &xmax) const {
771 // set to crazy values to start
772 xmin = std::numeric_limits<double>::max();
773 xmax = -1.0 * xmin;
774 size_t numberOfSpectra = this->getNumberHistograms();
775
776 // determine the data range
777 for (size_t workspaceIndex = 0; workspaceIndex < numberOfSpectra; workspaceIndex++) {
778 const auto &xData = this->x(workspaceIndex);
779 const double xfront = xData.front();
780 const double xback = xData.back();
781 if (std::isfinite(xfront) && std::isfinite(xback)) {
782 if (xfront < xmin)
783 xmin = xfront;
784 if (xback > xmax)
785 xmax = xback;
786 }
787 }
788}
789
803void MatrixWorkspace::getIntegratedSpectra(std::vector<double> &out, const double minX, const double maxX,
804 const bool entireRange) const {
805 out.resize(this->getNumberHistograms(), 0.0);
806
807 // offset for histogram data, because the x axis is not the same size for histogram and point data.
808 const size_t histogramOffset = this->isHistogramData() ? 1 : 0;
809
810 // Run in parallel if the implementation is threadsafe
812 for (int wksp_index = 0; wksp_index < static_cast<int>(this->getNumberHistograms()); wksp_index++) {
813 // Get Handle to data
814 const Mantid::MantidVec &xData = this->readX(wksp_index);
815 const auto &yData = this->y(wksp_index);
816 // If it is a 1D workspace, no need to integrate
817 if ((xData.size() <= 1 + histogramOffset) && (!yData.empty())) {
818 out[wksp_index] = yData[0];
819 } else {
820 // Iterators for limits - whole range by default
821 Mantid::MantidVec::const_iterator lowit, highit;
822 lowit = xData.begin();
823 highit = xData.end() - histogramOffset;
824
825 // But maybe we don't want the entire range?
826 if (!entireRange) {
827 // If the first element is lower that the xmin then search for new lowit
828 if ((*lowit) < minX)
829 lowit = std::lower_bound(xData.begin(), xData.end(), minX);
830 // If the last element is higher that the xmax then search for new highit
831 if (*(highit - 1 + histogramOffset) > maxX)
832 highit = std::upper_bound(lowit, xData.end(), maxX);
833 }
834
835 // Get the range for the y vector
836 Mantid::MantidVec::difference_type distmin = std::distance(xData.begin(), lowit);
837 Mantid::MantidVec::difference_type distmax = std::distance(xData.begin(), highit);
838 double sum(0.0);
839 if (distmin <= distmax) {
840 // Integrate
841 sum = std::accumulate(yData.begin() + distmin, yData.begin() + distmax, 0.0, accumulate_if_finite);
842 }
843 // Save it in the vector
844 out[wksp_index] = sum;
845 }
846 }
847}
848
849std::vector<double> MatrixWorkspace::getIntegratedCountsForWorkspaceIndices(const std::vector<size_t> &workspaceIndices,
850 const double minX, const double maxX,
851 const bool entireRange) const {
852 std::vector<double> integratedSpectra;
853 getIntegratedSpectra(integratedSpectra, minX, maxX, entireRange);
854 std::vector<double> detectorCounts;
855 std::transform(workspaceIndices.cbegin(), workspaceIndices.cend(), std::back_inserter(detectorCounts),
856 [&](const auto &wsIndex) { return integratedSpectra[wsIndex]; });
857 return detectorCounts;
858}
859
870 const auto &dets = getSpectrum(workspaceIndex).getDetectorIDs();
871 Instrument_const_sptr localInstrument = getInstrument();
872 if (!localInstrument) {
873 g_log.debug() << "No instrument defined.\n";
874 throw Kernel::Exception::NotFoundError("Instrument not found", "");
875 }
876
877 const size_t ndets = dets.size();
878 if (ndets == 1) {
879 // If only 1 detector for the spectrum number, just return it
880 return localInstrument->getDetector(*dets.begin());
881 } else if (ndets == 0) {
882 throw Kernel::Exception::NotFoundError("MatrixWorkspace::getDetector(): No "
883 "detectors for this workspace "
884 "index.",
885 "");
886 }
887 // Else need to construct a DetectorGroup and return that
888 auto dets_ptr = localInstrument->getDetectors(dets);
889 return std::make_shared<Geometry::DetectorGroup>(dets_ptr);
890}
891
900
902 Geometry::IComponent_const_sptr source = instrument->getSource();
903 Geometry::IComponent_const_sptr sample = instrument->getSample();
904 if (source == nullptr || sample == nullptr) {
906 "Instrument not sufficiently defined: failed to get source and/or "
907 "sample");
908 }
909
910 const Kernel::V3D samplePos = sample->getPos();
911 const Kernel::V3D beamLine = samplePos - source->getPos();
912
913 if (beamLine.nullVector()) {
914 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
915 }
916 // Get the instrument up axis.
917 const V3D &thetaSignAxis = instrument->getReferenceFrame()->vecThetaSign();
918 return det.getSignedTwoTheta(samplePos, beamLine, thetaSignAxis);
919}
920
929 Instrument_const_sptr instrument = this->getInstrument();
930 Geometry::IComponent_const_sptr source = instrument->getSource();
931 Geometry::IComponent_const_sptr sample = instrument->getSample();
932 if (source == nullptr || sample == nullptr) {
934 "Instrument not sufficiently defined: failed to get source and/or "
935 "sample");
936 }
937
938 const Kernel::V3D samplePos = sample->getPos();
939 const Kernel::V3D beamLine = samplePos - source->getPos();
940
941 if (beamLine.nullVector()) {
942 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
943 }
944 return det.getTwoTheta(samplePos, beamLine);
945}
946
948int MatrixWorkspace::axes() const { return static_cast<int>(m_axes.size()); }
949
956Axis *MatrixWorkspace::getAxis(const std::size_t &axisIndex) const {
957 if (axisIndex >= m_axes.size()) {
958 throw Kernel::Exception::IndexError(axisIndex, m_axes.size(), "Argument to getAxis is invalid for this workspace");
959 }
960
961 return m_axes[axisIndex].get();
962}
963
973void MatrixWorkspace::replaceAxis(const std::size_t &axisIndex, std::unique_ptr<Axis> newAxis) {
974 // First check that axisIndex is in range
975 if (axisIndex >= m_axes.size()) {
976 throw Kernel::Exception::IndexError(axisIndex, m_axes.size(), "Value of axisIndex is invalid for this workspace");
977 }
978 // If we're OK, then delete the old axis and set the pointer to the new one
979 m_axes[axisIndex] = std::move(newAxis);
980}
981
987 if (!this->isCommonBins()) {
988 return false;
989 }
990
991 if (this->getNumberHistograms() == 0) {
992 return false;
993 }
994
995 const auto &x0 = this->x(0);
996 if (x0.size() < 2) {
997 return false;
998 }
999
1000 // guard against all axis elements being equal
1001 if (x0[1] == x0[0]) {
1002 return false;
1003 }
1004
1005 double diff = x0[1] / x0[0];
1006 if (!std::isfinite(diff)) {
1007 return false;
1008 }
1009 // ignore final bin, since it may be a different size
1010 for (size_t i = 1; i < x0.size() - 2; ++i) {
1011 if (std::isfinite(x0[i + 1]) && std::isfinite(x0[i])) {
1012 if (std::abs(x0[i + 1] / x0[i] - diff) > EPSILON) {
1013 return false;
1014 }
1015 } else {
1016 return false;
1017 }
1018 }
1019 return true;
1020}
1021
1026size_t MatrixWorkspace::numberOfAxis() const { return m_axes.size(); }
1027
1029void MatrixWorkspace::setYUnit(const std::string &newUnit) { m_YUnit = newUnit; }
1030
1036std::string MatrixWorkspace::YUnitLabel(bool useLatex /* = false */) const {
1037 std::string retVal;
1038 if (!m_YUnitLabel.empty()) {
1039 retVal = m_YUnitLabel;
1040 } else {
1041 retVal = m_YUnit;
1042 if (this->isDistribution()) {
1043 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
1044 }
1045 }
1046 if (useLatex) {
1047 retVal = replacePerWithLatex(retVal);
1048 }
1049 return retVal;
1050}
1051
1053void MatrixWorkspace::setYUnitLabel(const std::string &newLabel) { m_YUnitLabel = newLabel; }
1054
1060 return getSpectrum(0).yMode() == HistogramData::Histogram::YMode::Frequencies;
1061}
1062
1066 if (isDistribution() == newValue)
1067 return;
1068 HistogramData::Histogram::YMode ymode =
1069 newValue ? HistogramData::Histogram::YMode::Frequencies : HistogramData::Histogram::YMode::Counts;
1070 for (size_t i = 0; i < getNumberHistograms(); ++i)
1071 getSpectrum(i).setYMode(ymode);
1072}
1073
1079 // all spectra *should* have the same behavior
1080 return isHistogramDataByIndex(0);
1081}
1082
1088bool MatrixWorkspace::isHistogramDataByIndex(const std::size_t index) const {
1089 bool isHist = (x(index).size() != y(index).size());
1090
1091 // TODOHIST temporary sanity check
1092 if (isHist) {
1093 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::BinEdges) {
1094 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1095 "Histogram::Xmode is not BinEdges");
1096 }
1097 } else {
1098 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::Points) {
1099 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1100 "Histogram::Xmode is not Points");
1101 }
1102 }
1103 return isHist;
1104}
1105
1111 std::lock_guard<std::mutex> lock{m_isCommonBinsMutex};
1112 const bool isFlagValid{m_isCommonBinsFlagValid.exchange(true)};
1113 if (isFlagValid) {
1114 return m_isCommonBinsFlag;
1115 }
1116 m_isCommonBinsFlag = true;
1117 const size_t numHist = this->getNumberHistograms();
1118 // there being only one or zero histograms is accepted as not being an error
1119 if (numHist <= 1) {
1120 return m_isCommonBinsFlag;
1121 }
1122
1123 // First check if the x-axis shares a common ptr.
1124 const HistogramData::HistogramX *first = &x(0);
1125 for (size_t i = 1; i < numHist; ++i) {
1126 if (&x(i) != first) {
1127 m_isCommonBinsFlag = false;
1128 break;
1129 }
1130 }
1131
1132 // If true, we may return here.
1133 if (m_isCommonBinsFlag) {
1134 return m_isCommonBinsFlag;
1135 }
1136
1137 m_isCommonBinsFlag = true;
1138 // Check that that size of each histogram is identical.
1139 const size_t numBins = x(0).size();
1140 for (size_t i = 1; i < numHist; ++i) {
1141 if (x(i).size() != numBins) {
1142 m_isCommonBinsFlag = false;
1143 return m_isCommonBinsFlag;
1144 }
1145 }
1146
1147 const auto &x0 = x(0);
1148 // Check that the values of each histogram are identical.
1150 for (int i = 1; i < static_cast<int>(numHist); ++i) {
1151 if (m_isCommonBinsFlag) {
1152 const auto specIndex = static_cast<std::size_t>(i);
1153 const auto &xi = x(specIndex);
1154 for (size_t j = 0; j < numBins; ++j) {
1155 const double a = x0[j];
1156 const double b = xi[j];
1157 // Check for NaN and infinity before comparing for equality
1158 if (std::isfinite(a) && std::isfinite(b)) {
1159 if (std::abs(a - b) > EPSILON) {
1160 m_isCommonBinsFlag = false;
1161 break;
1162 }
1163 // Otherwise we check that both are NaN or both are infinity
1164 } else if ((std::isnan(a) != std::isnan(b)) || (std::isinf(a) != std::isinf(b))) {
1165 m_isCommonBinsFlag = false;
1166 break;
1167 }
1168 }
1169 }
1170 }
1171 return m_isCommonBinsFlag;
1172}
1173
1179 if (!this->isCommonBins())
1180 return false;
1181
1182 const HistogramData::HistogramX bins = x(0);
1183
1184 for (size_t i = 0; i < bins.size(); ++i) {
1185 if (std::trunc(bins[i]) != bins[i])
1186 return false;
1187 }
1188 return true;
1189}
1190
1205void MatrixWorkspace::maskBin(const size_t &workspaceIndex, const size_t &binIndex, const double &weight) {
1206 // First check the workspaceIndex is valid
1207 if (workspaceIndex >= this->getNumberHistograms())
1208 throw Kernel::Exception::IndexError(workspaceIndex, this->getNumberHistograms(),
1209 "MatrixWorkspace::maskBin,workspaceIndex");
1210 // Then check the bin index
1211 if (binIndex >= y(workspaceIndex).size())
1212 throw Kernel::Exception::IndexError(binIndex, y(workspaceIndex).size(), "MatrixWorkspace::maskBin,binIndex");
1213
1214 // this function is marked parallel critical
1215 flagMasked(workspaceIndex, binIndex, weight);
1216
1217 // this is the actual result of the masking that most algorithms and plotting
1218 // implementations will see, the bin mask flags defined above are used by only
1219 // some algorithms
1220 // If the weight is 0, nothing more needs to be done after flagMasked above
1221 // (i.e. NaN and Inf will also stay intact)
1222 // If the weight is not 0, NaN and Inf values are set to 0,
1223 // whereas other values are scaled by (1 - weight)
1224 if (weight != 0.) {
1225 double &yData = this->mutableY(workspaceIndex)[binIndex];
1226 (std::isnan(yData) || std::isinf(yData)) ? yData = 0. : yData *= (1 - weight);
1227 double &eData = this->mutableE(workspaceIndex)[binIndex];
1228 (std::isnan(eData) || std::isinf(eData)) ? eData = 0. : eData *= (1 - weight);
1229 }
1230}
1231
1240void MatrixWorkspace::flagMasked(const size_t &index, const size_t &binIndex, const double &weight) {
1241 // Writing to m_masks is not thread-safe, so put in some protection
1243 // First get a reference to the list for this spectrum (or create a new
1244 // list)
1245 MaskList &binList = m_masks[index];
1246 binList[binIndex] = weight;
1247 }
1248}
1249
1254bool MatrixWorkspace::hasMaskedBins(const size_t &workspaceIndex) const {
1255 // First check the workspaceIndex is valid. Return false if it isn't (decided
1256 // against throwing here).
1257 if (workspaceIndex >= this->getNumberHistograms())
1258 return false;
1259 return m_masks.find(workspaceIndex) != m_masks.end();
1260}
1261
1265bool MatrixWorkspace::hasAnyMaskedBins() const { return !m_masks.empty(); }
1266
1273const MatrixWorkspace::MaskList &MatrixWorkspace::maskedBins(const size_t &workspaceIndex) const {
1274 auto it = m_masks.find(workspaceIndex);
1275 // Throw if there are no masked bins for this spectrum. The caller should
1276 // check first using hasMaskedBins!
1277 if (it == m_masks.end()) {
1278 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1279 }
1280
1281 return it->second;
1282}
1283
1284std::vector<size_t> MatrixWorkspace::maskedBinsIndices(const size_t &workspaceIndex) const {
1285 auto it = m_masks.find(workspaceIndex);
1286 // Throw if there are no masked bins for this spectrum. The caller should
1287 // check first using hasMaskedBins!
1288 if (it == m_masks.end()) {
1289 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1290 }
1291
1292 auto maskedBinsList = it->second;
1293 std::vector<size_t> maskedIds;
1294 maskedIds.reserve(maskedBinsList.size());
1295
1296 std::transform(maskedBinsList.begin(), maskedBinsList.end(), std::back_inserter(maskedIds),
1297 [](const auto &mb) { return mb.first; });
1298 return maskedIds;
1299}
1300
1306void MatrixWorkspace::setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins) {
1307 m_masks[workspaceIndex] = maskedBins;
1308}
1309
1315void MatrixWorkspace::setUnmaskedBins(const size_t workspaceIndex) { m_masks.erase(workspaceIndex); }
1316
1326void MatrixWorkspace::setMonitorWorkspace(const std::shared_ptr<MatrixWorkspace> &monitorWS) {
1327 if (monitorWS.get() == this) {
1328 throw std::runtime_error("To avoid memory leak, monitor workspace"
1329 " can not be the same workspace as the host workspace");
1330 }
1331 m_monitorWorkspace = monitorWS;
1332}
1333
1336std::shared_ptr<MatrixWorkspace> MatrixWorkspace::monitorWorkspace() const { return m_monitorWorkspace; }
1337
1342 const size_t runMemSize = run().getMemorySize();
1343 if (this->isRaggedWorkspace()) {
1344 const auto numHist = this->getNumberHistograms();
1345 size_t total{0};
1346 for (size_t i = 0; i < numHist; ++i) {
1347 total += this->getSpectrum(i).getMemorySize();
1348 }
1349 return total + runMemSize;
1350 } else {
1351 // 3 doubles per histogram bin.
1352 return 3 * size() * sizeof(double) + runMemSize;
1353 }
1354}
1355
1360 size_t total = 0;
1361 auto lastX = this->refX(0);
1362 for (size_t wi = 0; wi < getNumberHistograms(); wi++) {
1363 auto X = this->refX(wi);
1364 // If the pointers are the same
1365 if (!(X == lastX) || wi == 0)
1366 total += (*X).size() * sizeof(double);
1367 }
1368 return total;
1369}
1370
1379Types::Core::DateAndTime MatrixWorkspace::getFirstPulseTime() const { return this->run().getFirstPulseTime(); }
1380
1389Types::Core::DateAndTime MatrixWorkspace::getLastPulseTime() const { return this->run().getLastPulseTime(); }
1390
1399std::size_t MatrixWorkspace::yIndexOfX(const double xValue, const std::size_t &index,
1400 [[maybe_unused]] const double tolerance) const {
1401 if (index >= getNumberHistograms())
1402 throw std::out_of_range("MatrixWorkspace::yIndexOfX - Index out of range.");
1403
1404 const auto &xValues = this->x(index);
1405 const bool ascendingOrder = xValues.front() < xValues.back();
1406 const auto minX = ascendingOrder ? xValues.front() : xValues.back();
1407 const auto maxX = ascendingOrder ? xValues.back() : xValues.front();
1408
1410 if (xValue < minX || xValue > maxX)
1411 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1412 "the range of the min and max bin edges.");
1413
1414 return binIndexOfValue(xValues, xValue, ascendingOrder);
1415 } else {
1416 if (xValue < minX - tolerance || xValue > maxX + tolerance)
1417 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1418 "range for this point data.");
1419
1420 return xIndexOfValue(xValues, xValue, tolerance);
1421 }
1422}
1423
1431std::size_t MatrixWorkspace::binIndexOfValue(HistogramData::HistogramX const &xValues, const double xValue,
1432 const bool ascendingOrder) const {
1433 std::size_t hops;
1434 if (ascendingOrder) {
1435 auto lowerIter = std::lower_bound(xValues.cbegin(), xValues.cend(), xValue);
1436
1437 // If we are pointing at the first value then we want to be in the first bin
1438 if (lowerIter == xValues.cbegin())
1439 ++lowerIter;
1440
1441 hops = std::distance(xValues.cbegin(), lowerIter);
1442 } else {
1443 auto lowerIter = std::lower_bound(xValues.crbegin(), xValues.crend(), xValue);
1444
1445 if (lowerIter == xValues.crbegin())
1446 ++lowerIter;
1447
1448 hops = xValues.size() - std::distance(xValues.crbegin(), lowerIter);
1449 }
1450 // The bin index is offset by one from the number of hops between iterators as
1451 // they start at zero (for a histogram workspace)
1452 return hops - 1;
1453}
1454
1463std::size_t MatrixWorkspace::xIndexOfValue(const HistogramData::HistogramX &xValues, const double xValue,
1464 const double tolerance) const {
1465 auto const iter = std::find_if(xValues.cbegin(), xValues.cend(), [&xValue, &tolerance](double const &value) {
1466 return std::abs(xValue - value) <= tolerance;
1467 });
1468 if (iter != xValues.cend())
1469 return std::distance(xValues.cbegin(), iter);
1470 else
1471 throw std::invalid_argument("MatrixWorkspace::yIndexOfX - the X value provided could not be found "
1472 "in the workspace containing point data.");
1473}
1474
1475uint64_t MatrixWorkspace::getNPoints() const { return static_cast<uint64_t>(this->size()); }
1476
1477//================================= FOR MDGEOMETRY
1478//====================================================
1479
1480size_t MatrixWorkspace::getNumDims() const { return 2; }
1481
1482std::string MatrixWorkspace::getDimensionIdFromAxis(const int &axisIndex) const {
1483 std::string id;
1484 if (0 == axisIndex) {
1485 id = xDimensionId;
1486 } else if (1 == axisIndex) {
1487 id = yDimensionId;
1488 } else {
1489 throw std::invalid_argument("Cannot have an index for a MatrixWorkspace "
1490 "axis that is not == 0 or == 1");
1491 }
1492 return id;
1493}
1494
1495//===============================================================================
1497public:
1498 MWDimension(const Axis *axis, std::string dimensionId)
1499 : m_axis(*axis), m_dimensionId(std::move(dimensionId)),
1500 m_haveEdges(dynamic_cast<const BinEdgeAxis *>(&m_axis) != nullptr),
1501 m_frame(std::make_unique<Geometry::GeneralFrame>(m_axis.unit()->label(), m_axis.unit()->label())) {}
1502
1504 std::string getName() const override {
1505 const auto &unit = m_axis.unit();
1506 if (unit && unit->unitID() != "Empty")
1507 return unit->caption();
1508 else
1509 return m_axis.title();
1510 }
1511
1513 const Kernel::UnitLabel getUnits() const override { return m_axis.unit()->label(); }
1514
1518 const std::string &getDimensionId() const override { return m_dimensionId; }
1519
1521 bool getIsIntegrated() const override { return m_axis.length() == 1; }
1522
1524 coord_t getMinimum() const override { return coord_t(m_axis.getMin()); }
1525
1527 coord_t getMaximum() const override { return coord_t(m_axis.getMax()); }
1528
1531 size_t getNBins() const override {
1532 if (m_haveEdges)
1533 return m_axis.length() - 1;
1534 else
1535 return m_axis.length();
1536 }
1537
1539 size_t getNBoundaries() const override { return m_axis.length(); }
1540
1542 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1543 throw std::runtime_error("Not implemented");
1544 }
1545
1547 coord_t getX(size_t ind) const override { return coord_t(m_axis(ind)); }
1548
1554 coord_t getBinWidth() const override {
1555 size_t nsteps = (m_haveEdges) ? this->getNBins() : this->getNBins() - 1;
1556 return (getMaximum() - getMinimum()) / static_cast<coord_t>(nsteps);
1557 }
1558
1559 // Dimensions must be xml serializable.
1560 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1561
1562 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1563 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1564
1565private:
1566 const Axis &m_axis;
1567 const std::string m_dimensionId;
1568 const bool m_haveEdges;
1570};
1571
1572//===============================================================================
1577public:
1578 MWXDimension(const MatrixWorkspace *ws, std::string dimensionId)
1579 : m_ws(ws), m_X(ws->readX(0)), m_dimensionId(std::move(dimensionId)),
1580 m_frame(std::make_unique<Geometry::GeneralFrame>(m_ws->getAxis(0)->unit()->label(),
1581 m_ws->getAxis(0)->unit()->label())) {}
1582
1584 std::string getName() const override {
1585 const auto *axis = m_ws->getAxis(0);
1586 const auto &unit = axis->unit();
1587 if (unit && unit->unitID() != "Empty")
1588 return unit->caption();
1589 else
1590 return axis->title();
1591 }
1592
1594 const Kernel::UnitLabel getUnits() const override { return m_ws->getAxis(0)->unit()->label(); }
1595
1599 const std::string &getDimensionId() const override { return m_dimensionId; }
1600
1602 bool getIsIntegrated() const override { return m_X.size() == 1; }
1603
1605 coord_t getMinimum() const override { return coord_t(m_X.front()); }
1606
1608 coord_t getMaximum() const override { return coord_t(m_X.back()); }
1609
1612 size_t getNBins() const override { return (m_ws->isHistogramData()) ? m_X.size() - 1 : m_X.size(); }
1613
1615 size_t getNBoundaries() const override { return m_X.size(); }
1616
1618 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1619 throw std::runtime_error("Not implemented");
1620 }
1621
1623 coord_t getX(size_t ind) const override { return coord_t(m_X[ind]); }
1624
1625 // Dimensions must be xml serializable.
1626 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1627 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1628 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1629
1630private:
1636 const std::string m_dimensionId;
1639};
1640
1641std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimension(size_t index) const {
1642 if (index == 0) {
1643 return std::make_shared<MWXDimension>(this, xDimensionId);
1644 } else if (index == 1) {
1645 Axis *yAxis = this->getAxis(1);
1646 return std::make_shared<MWDimension>(yAxis, yDimensionId);
1647 } else
1648 throw std::invalid_argument("MatrixWorkspace only has 2 dimensions.");
1649}
1650
1651std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimensionWithId(std::string id) const {
1652 int nAxes = this->axes();
1653 std::shared_ptr<IMDDimension> dim;
1654 for (int i = 0; i < nAxes; i++) {
1655 const std::string knownId = getDimensionIdFromAxis(i);
1656 if (knownId == id) {
1657 dim = std::make_shared<MWDimension>(this->getAxis(i), id);
1658 break;
1659 }
1660 }
1661
1662 if (nullptr == dim) {
1663 std::string message = "Cannot find id : " + id;
1664 throw std::overflow_error(message);
1665 }
1666 return dim;
1667}
1668
1676std::vector<std::unique_ptr<IMDIterator>>
1678 // Find the right number of cores to use
1679 size_t numCores = suggestedNumCores;
1680 if (!this->threadSafe())
1681 numCores = 1;
1682 size_t numElements = this->getNumberHistograms();
1683 if (numCores > numElements)
1684 numCores = numElements;
1685 if (numCores < 1)
1686 numCores = 1;
1687
1688 // Create one iterator per core, splitting evenly amongst spectra
1689 std::vector<std::unique_ptr<IMDIterator>> out;
1690 for (size_t i = 0; i < numCores; i++) {
1691 size_t begin = (i * numElements) / numCores;
1692 size_t end = ((i + 1) * numElements) / numCores;
1693 if (end > numElements)
1694 end = numElements;
1695 out.emplace_back(std::make_unique<MatrixWorkspaceMDIterator>(this, function, begin, end));
1696 }
1697 return out;
1698}
1699
1717
1725 const Mantid::API::MDNormalization &normalization) const {
1726 if (this->axes() != 2)
1727 throw std::invalid_argument("MatrixWorkspace::getSignalAtCoord() - "
1728 "Workspace can only have 2 axes, found " +
1729 std::to_string(this->axes()));
1730
1731 // First, find the workspace index
1732 Axis const *ax1 = this->getAxis(1);
1733 size_t wi(-1);
1734 try {
1735 wi = ax1->indexOfValue(coords[1]);
1736 } catch (std::out_of_range &) {
1737 return std::numeric_limits<double>::quiet_NaN();
1738 }
1739
1740 const size_t nhist = this->getNumberHistograms();
1741 const auto &yVals = this->y(wi);
1742 double yBinSize(1.0); // only applies for volume normalization & numeric axis
1743 if (normalization == VolumeNormalization && ax1->isNumeric()) {
1744 size_t uVI = 0; // unused vertical index.
1745 double currentVertical = ax1->operator()(wi, uVI);
1746 if (wi + 1 == nhist && nhist > 1) // On the boundary, look back to get diff
1747 {
1748 yBinSize = currentVertical - ax1->operator()(wi - 1, uVI);
1749 } else {
1750 yBinSize = ax1->operator()(wi + 1, uVI) - currentVertical;
1751 }
1752 }
1753
1754 if (wi < nhist) {
1755 const auto &xVals = x(wi);
1756 size_t i;
1757 try {
1758 coord_t xCoord = coords[0];
1759 if (isHistogramData())
1760 i = Kernel::VectorHelper::indexOfValueFromEdges(xVals.rawData(), xCoord);
1761 else
1762 i = Kernel::VectorHelper::indexOfValueFromCenters(xVals.rawData(), xCoord);
1763 } catch (std::out_of_range &) {
1764 return std::numeric_limits<double>::quiet_NaN();
1765 }
1766
1767 double yVal = yVals[i];
1768 // What is our normalization factor?
1769 switch (normalization) {
1770 case NoNormalization:
1771 return yVal;
1772 case VolumeNormalization: {
1773 // Divide the signal by the area
1774 auto volume = yBinSize * (xVals[i + 1] - xVals[i]);
1775 if (volume == 0.0) {
1776 return std::numeric_limits<double>::quiet_NaN();
1777 }
1778 return yVal / volume;
1779 }
1781 // Not yet implemented, may not make sense
1782 return yVal;
1783 }
1784 // This won't happen
1785 return yVal;
1786 } else {
1787 return std::numeric_limits<double>::quiet_NaN();
1788 }
1789}
1790
1799 const Mantid::API::MDNormalization &normalization) const {
1800 return getSignalAtCoord(coords, normalization);
1801}
1802
1803/*
1804MDMasking for a Matrix Workspace has not been implemented.
1805@param :
1806*/
1807void MatrixWorkspace::setMDMasking(std::unique_ptr<Mantid::Geometry::MDImplicitFunction> /*maskingRegion*/) {
1808 throw std::runtime_error("MatrixWorkspace::setMDMasking has no implementation");
1809}
1810
1811/*
1812Clear MDMasking for a Matrix Workspace has not been implemented.
1813*/
1815 throw std::runtime_error("MatrixWorkspace::clearMDMasking has no implementation");
1816}
1817
1824
1825// Check if this class has an oriented lattice on a sample object
1827
1839 size_t start, size_t stop, size_t width, size_t indexStart,
1840 size_t indexEnd) const {
1841 // width must be provided (for now)
1842 if (width == 0) {
1843 throw std::runtime_error("Cannot create image with width 0");
1844 }
1845
1846 size_t nHist = getNumberHistograms();
1847 // use all spectra by default
1848 if (stop == 0) {
1849 stop = nHist;
1850 }
1851
1852 // check start and stop
1853 if (stop < start) {
1854 throw std::runtime_error("Cannot create image for an empty data set.");
1855 }
1856
1857 if (start >= nHist) {
1858 throw std::runtime_error("Cannot create image: start index is out of range");
1859 }
1860
1861 if (stop >= nHist) {
1862 throw std::runtime_error("Cannot create image: stop index is out of range");
1863 }
1864
1865 // calculate image geometry
1866 size_t dataSize = stop - start + 1;
1867 size_t height = dataSize / width;
1868
1869 // and check that the data fits exactly into this geometry
1870 if (height * width != dataSize) {
1871 throw std::runtime_error("Cannot create image: the data set cannot form a rectangle.");
1872 }
1873
1874 size_t nBins = blocksize();
1875 bool isHisto = isHistogramData();
1876
1877 // default indexEnd is the last index of the X vector
1878 if (indexEnd == 0) {
1879 indexEnd = nBins;
1880 if (!isHisto && indexEnd > 0)
1881 --indexEnd;
1882 }
1883
1884 // check the x-range indices
1885 if (indexEnd < indexStart) {
1886 throw std::runtime_error("Cannot create image for an empty data set.");
1887 }
1888
1889 if (indexStart >= nBins || indexEnd > nBins || (!isHisto && indexEnd == nBins)) {
1890 throw std::runtime_error("Cannot create image: integration interval is out of range.");
1891 }
1892
1893 // initialize the image
1894 auto image = std::make_shared<MantidImage>(height);
1895 if (!isHisto)
1896 ++indexEnd;
1897
1898 // deal separately with single-binned workspaces: no integration is required
1899 if (isHisto && indexEnd == indexStart + 1) {
1901 for (int i = 0; i < static_cast<int>(height); ++i) {
1902 auto &row = (*image)[i];
1903 row.resize(width);
1904 size_t spec = start + static_cast<size_t>(i) * width;
1905 for (size_t j = 0; j < width; ++j, ++spec) {
1906 row[j] = (this->*read)(spec)[indexStart];
1907 }
1908 }
1909 } else {
1910 // each image pixel is integrated over the x-range [indexStart,indexEnd)
1912 for (int i = 0; i < static_cast<int>(height); ++i) {
1913 auto &row = (*image)[i];
1914 row.resize(width);
1915 size_t spec = start + static_cast<size_t>(i) * width;
1916 for (size_t j = 0; j < width; ++j, ++spec) {
1917 auto &V = (this->*read)(spec);
1918 row[j] = std::accumulate(V.begin() + indexStart, V.begin() + indexEnd, 0.0);
1919 }
1920 }
1921 }
1922
1923 return image;
1924}
1925
1926std::pair<int64_t, int64_t> MatrixWorkspace::findY(double value, const std::pair<int64_t, int64_t> &idx) const {
1927 std::pair<int64_t, int64_t> out(-1, -1);
1928 const int64_t numHists = static_cast<int64_t>(this->getNumberHistograms());
1929 if (std::isnan(value)) {
1930 for (int64_t i = idx.first; i < numHists; ++i) {
1931 const auto &Y = this->y(i);
1932 if (auto it = std::find_if(std::next(Y.begin(), idx.second), Y.end(), [](double v) { return std::isnan(v); });
1933 it != Y.end()) {
1934 out = {i, std::distance(Y.begin(), it)};
1935 break;
1936 }
1937 }
1938 } else {
1939 for (int64_t i = idx.first; i < numHists; ++i) {
1940 const auto &Y = this->y(i);
1941 if (auto it = std::find(std::next(Y.begin(), idx.second), Y.end(), value); it != Y.end()) {
1942 out = {i, std::distance(Y.begin(), it)};
1943 break;
1944 }
1945 }
1946 }
1947 return out;
1948}
1949
1956std::pair<size_t, size_t> MatrixWorkspace::getImageStartEndXIndices(size_t i, double startX, double endX) const {
1957 if (startX == EMPTY_DBL())
1958 startX = x(i).front();
1959 auto pStart = getXIndex(i, startX, true);
1960 if (pStart.second != 0.0) {
1961 throw std::runtime_error("Start X value is required to be on bin boundary.");
1962 }
1963 if (endX == EMPTY_DBL())
1964 endX = x(i).back();
1965 auto pEnd = getXIndex(i, endX, false, pStart.first);
1966 if (pEnd.second != 0.0) {
1967 throw std::runtime_error("End X value is required to be on bin boundary.");
1968 }
1969 return std::make_pair(pStart.first, pEnd.first);
1970}
1971
1980MantidImage_sptr MatrixWorkspace::getImageY(size_t start, size_t stop, size_t width, double startX, double endX) const {
1981 auto p = getImageStartEndXIndices(0, startX, endX);
1982 return getImage(&MatrixWorkspace::readY, start, stop, width, p.first, p.second);
1983}
1984
1993MantidImage_sptr MatrixWorkspace::getImageE(size_t start, size_t stop, size_t width, double startX, double endX) const {
1994 auto p = getImageStartEndXIndices(0, startX, endX);
1995 return getImage(&MatrixWorkspace::readE, start, stop, width, p.first, p.second);
1996}
1997
2010std::pair<size_t, double> MatrixWorkspace::getXIndex(size_t i, double x, bool isLeft, size_t start) const {
2011 auto &X = this->x(i);
2012 auto nx = X.size();
2013
2014 // if start out of range - search failed
2015 if (start >= nx)
2016 return std::make_pair(nx, 0.0);
2017 if (start > 0 && start == nx - 1) {
2018 // starting with the last index is allowed for right boundary search
2019 if (!isLeft)
2020 return std::make_pair(start, 0.0);
2021 return std::make_pair(nx, 0.0);
2022 }
2023
2024 // consider point data with single value
2025 if (nx == 1) {
2026 assert(start == 0);
2027 if (isLeft)
2028 return x <= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2029 return x >= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2030 }
2031
2032 // left boundaries below start value map to the start value
2033 if (x <= X[start]) {
2034 return isLeft ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2035 }
2036 // right boundary search returns last x value for all values above it
2037 if (x >= X.back()) {
2038 return !isLeft ? std::make_pair(nx - 1, 0.0) : std::make_pair(nx, 0.0);
2039 }
2040
2041 // general case: find the boundary index and bin fraction
2042 auto end = X.end();
2043 for (auto ix = X.begin() + start + 1; ix != end; ++ix) {
2044 if (*ix >= x) {
2045 auto index = static_cast<size_t>(std::distance(X.begin(), ix));
2046 if (isLeft)
2047 --index;
2048 return std::make_pair(index, std::abs((X[index] - x) / (*ix - *(ix - 1))));
2049 }
2050 }
2051 // I don't think we can ever get here
2052 return std::make_pair(nx, 0.0);
2053}
2054
2063void MatrixWorkspace::setImage(MantidVec &(MatrixWorkspace::*dataVec)(const std::size_t), const MantidImage &image,
2064 size_t start, [[maybe_unused]] bool parallelExecution) {
2065
2066 if (image.empty())
2067 return;
2068 if (image[0].empty())
2069 return;
2070
2071 if (blocksize() != 1) {
2072 throw std::runtime_error("Cannot set image: a single bin workspace is expected.");
2073 }
2074
2075 size_t height = image.size();
2076 size_t width = image.front().size();
2077 size_t dataSize = width * height;
2078
2079 if (start + dataSize > getNumberHistograms()) {
2080 throw std::runtime_error("Cannot set image: image is bigger than workspace.");
2081 }
2082
2083 PARALLEL_FOR_IF(parallelExecution)
2084 for (int i = 0; i < static_cast<int>(height); ++i) {
2085 auto &row = image[i];
2086 if (row.size() != width) {
2087 throw std::runtime_error("Canot set image: image is corrupted.");
2088 }
2089 size_t spec = start + static_cast<size_t>(i) * width;
2090 auto rowEnd = row.end();
2091 for (auto pixel = row.begin(); pixel != rowEnd; ++pixel, ++spec) {
2092 (this->*dataVec)(spec)[0] = *pixel;
2093 }
2094 }
2095}
2096
2103void MatrixWorkspace::setImageY(const MantidImage &image, size_t start, bool parallelExecution) {
2104 setImage(&MatrixWorkspace::dataY, image, start, parallelExecution);
2105}
2106
2113void MatrixWorkspace::setImageE(const MantidImage &image, size_t start, bool parallelExecution) {
2114 setImage(&MatrixWorkspace::dataE, image, start, parallelExecution);
2115}
2116
2118
2126 setDetectorGrouping(index, getSpectrum(index).getDetectorIDs());
2127}
2128
2130 const auto &detInfo = detectorInfo();
2131 size_t numberOfDetectors{detInfo.size()};
2132 if (numberOfDetectors == 0) {
2133 // Default to empty spectrum definitions if there is no instrument.
2134 m_indexInfo->setSpectrumDefinitions(std::vector<SpectrumDefinition>(m_indexInfo->size()));
2135 return;
2136 }
2137 size_t numberOfSpectra = numberOfDetectors * detInfo.scanCount();
2138 if (numberOfSpectra != m_indexInfo->globalSize())
2139 throw std::invalid_argument("MatrixWorkspace: IndexInfo does not contain spectrum definitions so "
2140 "building a 1:1 mapping from spectra to detectors was attempted, but "
2141 "the number of spectra in the workspace is not equal to the number of "
2142 "detectors in the instrument.");
2143 std::vector<SpectrumDefinition> specDefs(m_indexInfo->size());
2144 if (!detInfo.isScanning() && (numberOfSpectra == m_indexInfo->size())) {
2145 for (size_t i = 0; i < numberOfSpectra; ++i)
2146 specDefs[i].add(i);
2147 } else {
2148 size_t specIndex = 0;
2149 size_t globalSpecIndex = 0;
2150 for (size_t detIndex = 0; detIndex < detInfo.size(); ++detIndex) {
2151 for (size_t time = 0; time < detInfo.scanCount(); ++time) {
2152 if (m_indexInfo->isOnThisPartition(Indexing::GlobalSpectrumIndex(globalSpecIndex++)))
2153 specDefs[specIndex++].add(detIndex, time);
2154 }
2155 }
2156 }
2157 m_indexInfo->setSpectrumDefinitions(std::move(specDefs));
2158}
2159
2161 const auto &detInfo = detectorInfo();
2162 const auto detInfo_scanCount = detInfo.scanCount(); // cache value outside of the loop
2163 // Use size() directly; avoid detectorIDs()
2164 const auto allDetIDs_size = detInfo.size();
2165 const auto &specDefs = m_indexInfo->spectrumDefinitions();
2166 const auto indexInfoSize = static_cast<int64_t>(m_indexInfo->size());
2167 enum class ErrorCode { None, InvalidDetIndex, InvalidTimeIndex };
2168 std::atomic<ErrorCode> errorValue(ErrorCode::None);
2169#pragma omp parallel for
2170 for (int64_t i = 0; i < indexInfoSize; ++i) {
2171 auto &spec = getSpectrum(i);
2172 // Prevent setting flags that require spectrum definition updates
2173 spec.setMatrixWorkspace(nullptr, i);
2174 spec.setSpectrumNo(static_cast<specnum_t>(m_indexInfo->spectrumNumber(i)));
2175 std::set<detid_t> detIDs;
2176 for (const auto &index : (*specDefs)[i]) {
2177 const size_t detIndex = index.first;
2178 if (detIndex >= allDetIDs_size) {
2179 errorValue = ErrorCode::InvalidDetIndex;
2180 } else if (index.second >= detInfo_scanCount) { // timeIndex is second
2181 errorValue = ErrorCode::InvalidTimeIndex;
2182 } else {
2183 detIDs.insert(detInfo.detid(detIndex));
2184 }
2185 }
2186 spec.setDetectorIDs(std::move(detIDs));
2187 }
2188 switch (errorValue) {
2189 case ErrorCode::InvalidDetIndex:
2190 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2191 "detector index, i.e., the spectrum definition does not match "
2192 "the instrument in the workspace.");
2193 case ErrorCode::InvalidTimeIndex:
2194 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2195 "time index for a detector, i.e., the spectrum definition does "
2196 "not match the instrument in the workspace.");
2197 case ErrorCode::None:; // nothing to do
2198 }
2199}
2200
2201} // namespace Mantid::API
2202
2204namespace Mantid::Kernel {
2205
2206template <>
2208IPropertyManager::getValue<Mantid::API::MatrixWorkspace_sptr>(const std::string &name) const {
2209 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2210 if (prop) {
2211 return *prop;
2212 } else {
2213 std::string message =
2214 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<MatrixWorkspace>.";
2215 throw std::runtime_error(message);
2216 }
2217}
2218
2219template <>
2221IPropertyManager::getValue<Mantid::API::MatrixWorkspace_const_sptr>(const std::string &name) const {
2222 auto const *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2223 if (prop) {
2224 return prop->operator()();
2225 } else {
2226 std::string message =
2227 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<MatrixWorkspace>.";
2228 throw std::runtime_error(message);
2229 }
2230}
2231
2232} // namespace Mantid::Kernel
2233
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 size_t getMemorySize() const =0
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:90
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.
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.
virtual bool isRaggedWorkspace() const =0
Returns true if the workspace is ragged (has differently sized spectra).
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
std::string YUnitLabel(bool useLatex=false) const
Returns a caption for the units of the data in the workspace.
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:179
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.