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
1037std::string MatrixWorkspace::YUnitLabel(bool useLatex /* = false */, bool plotAsDistribution /* = false */) const {
1038 std::string retVal;
1039 if (!m_YUnitLabel.empty()) {
1040 retVal = m_YUnitLabel;
1041 // If a custom label has been set and we are dividing by bin width when
1042 // plotting (i.e. plotAsDistribution = true and the workspace is not a
1043 // distribution), we must append the x-unit as a divisor. We assume the
1044 // custom label contains the correct units for the data.
1045 if (plotAsDistribution && !this->isDistribution())
1046 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
1047 } else {
1048 retVal = m_YUnit;
1049 // If no custom label is set and the workspace is a distribution we need to
1050 // append the divisor's unit to the label. If the workspace is not a
1051 // distribution, but we are plotting it as a distribution, we must append
1052 // the divisor's unit.
1053 if (plotAsDistribution || this->isDistribution())
1054 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
1055 }
1056 if (useLatex)
1057 retVal = replacePerWithLatex(retVal);
1058 return retVal;
1059}
1060
1062void MatrixWorkspace::setYUnitLabel(const std::string &newLabel) { m_YUnitLabel = newLabel; }
1063
1069 return getSpectrum(0).yMode() == HistogramData::Histogram::YMode::Frequencies;
1070}
1071
1075 if (isDistribution() == newValue)
1076 return;
1077 HistogramData::Histogram::YMode ymode =
1078 newValue ? HistogramData::Histogram::YMode::Frequencies : HistogramData::Histogram::YMode::Counts;
1079 for (size_t i = 0; i < getNumberHistograms(); ++i)
1080 getSpectrum(i).setYMode(ymode);
1081}
1082
1088 // all spectra *should* have the same behavior
1089 return isHistogramDataByIndex(0);
1090}
1091
1097bool MatrixWorkspace::isHistogramDataByIndex(const std::size_t index) const {
1098 bool isHist = (x(index).size() != y(index).size());
1099
1100 // TODOHIST temporary sanity check
1101 if (isHist) {
1102 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::BinEdges) {
1103 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1104 "Histogram::Xmode is not BinEdges");
1105 }
1106 } else {
1107 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::Points) {
1108 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1109 "Histogram::Xmode is not Points");
1110 }
1111 }
1112 return isHist;
1113}
1114
1120 std::lock_guard<std::mutex> lock{m_isCommonBinsMutex};
1121 const bool isFlagValid{m_isCommonBinsFlagValid.exchange(true)};
1122 if (isFlagValid) {
1123 return m_isCommonBinsFlag;
1124 }
1125 m_isCommonBinsFlag = true;
1126 const size_t numHist = this->getNumberHistograms();
1127 // there being only one or zero histograms is accepted as not being an error
1128 if (numHist <= 1) {
1129 return m_isCommonBinsFlag;
1130 }
1131
1132 // First check if the x-axis shares a common ptr.
1133 const HistogramData::HistogramX *first = &x(0);
1134 for (size_t i = 1; i < numHist; ++i) {
1135 if (&x(i) != first) {
1136 m_isCommonBinsFlag = false;
1137 break;
1138 }
1139 }
1140
1141 // If true, we may return here.
1142 if (m_isCommonBinsFlag) {
1143 return m_isCommonBinsFlag;
1144 }
1145
1146 m_isCommonBinsFlag = true;
1147 // Check that that size of each histogram is identical.
1148 const size_t numBins = x(0).size();
1149 for (size_t i = 1; i < numHist; ++i) {
1150 if (x(i).size() != numBins) {
1151 m_isCommonBinsFlag = false;
1152 return m_isCommonBinsFlag;
1153 }
1154 }
1155
1156 const auto &x0 = x(0);
1157 // Check that the values of each histogram are identical.
1159 for (int i = 1; i < static_cast<int>(numHist); ++i) {
1160 if (m_isCommonBinsFlag) {
1161 const auto specIndex = static_cast<std::size_t>(i);
1162 const auto &xi = x(specIndex);
1163 for (size_t j = 0; j < numBins; ++j) {
1164 const double a = x0[j];
1165 const double b = xi[j];
1166 // Check for NaN and infinity before comparing for equality
1167 if (std::isfinite(a) && std::isfinite(b)) {
1168 if (std::abs(a - b) > EPSILON) {
1169 m_isCommonBinsFlag = false;
1170 break;
1171 }
1172 // Otherwise we check that both are NaN or both are infinity
1173 } else if ((std::isnan(a) != std::isnan(b)) || (std::isinf(a) != std::isinf(b))) {
1174 m_isCommonBinsFlag = false;
1175 break;
1176 }
1177 }
1178 }
1179 }
1180 return m_isCommonBinsFlag;
1181}
1182
1188 if (!this->isCommonBins())
1189 return false;
1190
1191 const HistogramData::HistogramX bins = x(0);
1192
1193 for (size_t i = 0; i < bins.size(); ++i) {
1194 if (std::trunc(bins[i]) != bins[i])
1195 return false;
1196 }
1197 return true;
1198}
1199
1214void MatrixWorkspace::maskBin(const size_t &workspaceIndex, const size_t &binIndex, const double &weight) {
1215 // First check the workspaceIndex is valid
1216 if (workspaceIndex >= this->getNumberHistograms())
1217 throw Kernel::Exception::IndexError(workspaceIndex, this->getNumberHistograms(),
1218 "MatrixWorkspace::maskBin,workspaceIndex");
1219 // Then check the bin index
1220 if (binIndex >= y(workspaceIndex).size())
1221 throw Kernel::Exception::IndexError(binIndex, y(workspaceIndex).size(), "MatrixWorkspace::maskBin,binIndex");
1222
1223 // this function is marked parallel critical
1224 flagMasked(workspaceIndex, binIndex, weight);
1225
1226 // this is the actual result of the masking that most algorithms and plotting
1227 // implementations will see, the bin mask flags defined above are used by only
1228 // some algorithms
1229 // If the weight is 0, nothing more needs to be done after flagMasked above
1230 // (i.e. NaN and Inf will also stay intact)
1231 // If the weight is not 0, NaN and Inf values are set to 0,
1232 // whereas other values are scaled by (1 - weight)
1233 if (weight != 0.) {
1234 double &yData = this->mutableY(workspaceIndex)[binIndex];
1235 (std::isnan(yData) || std::isinf(yData)) ? yData = 0. : yData *= (1 - weight);
1236 double &eData = this->mutableE(workspaceIndex)[binIndex];
1237 (std::isnan(eData) || std::isinf(eData)) ? eData = 0. : eData *= (1 - weight);
1238 }
1239}
1240
1249void MatrixWorkspace::flagMasked(const size_t &index, const size_t &binIndex, const double &weight) {
1250 // Writing to m_masks is not thread-safe, so put in some protection
1252 // First get a reference to the list for this spectrum (or create a new
1253 // list)
1254 MaskList &binList = m_masks[index];
1255 binList[binIndex] = weight;
1256 }
1257}
1258
1263bool MatrixWorkspace::hasMaskedBins(const size_t &workspaceIndex) const {
1264 // First check the workspaceIndex is valid. Return false if it isn't (decided
1265 // against throwing here).
1266 if (workspaceIndex >= this->getNumberHistograms())
1267 return false;
1268 return m_masks.find(workspaceIndex) != m_masks.end();
1269}
1270
1274bool MatrixWorkspace::hasAnyMaskedBins() const { return !m_masks.empty(); }
1275
1282const MatrixWorkspace::MaskList &MatrixWorkspace::maskedBins(const size_t &workspaceIndex) const {
1283 auto it = m_masks.find(workspaceIndex);
1284 // Throw if there are no masked bins for this spectrum. The caller should
1285 // check first using hasMaskedBins!
1286 if (it == m_masks.end()) {
1287 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1288 }
1289
1290 return it->second;
1291}
1292
1293std::vector<size_t> MatrixWorkspace::maskedBinsIndices(const size_t &workspaceIndex) const {
1294 auto it = m_masks.find(workspaceIndex);
1295 // Throw if there are no masked bins for this spectrum. The caller should
1296 // check first using hasMaskedBins!
1297 if (it == m_masks.end()) {
1298 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1299 }
1300
1301 auto maskedBinsList = it->second;
1302 std::vector<size_t> maskedIds;
1303 maskedIds.reserve(maskedBinsList.size());
1304
1305 std::transform(maskedBinsList.begin(), maskedBinsList.end(), std::back_inserter(maskedIds),
1306 [](const auto &mb) { return mb.first; });
1307 return maskedIds;
1308}
1309
1315void MatrixWorkspace::setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins) {
1316 m_masks[workspaceIndex] = maskedBins;
1317}
1318
1324void MatrixWorkspace::setUnmaskedBins(const size_t workspaceIndex) { m_masks.erase(workspaceIndex); }
1325
1335void MatrixWorkspace::setMonitorWorkspace(const std::shared_ptr<MatrixWorkspace> &monitorWS) {
1336 if (monitorWS.get() == this) {
1337 throw std::runtime_error("To avoid memory leak, monitor workspace"
1338 " can not be the same workspace as the host workspace");
1339 }
1340 m_monitorWorkspace = monitorWS;
1341}
1342
1345std::shared_ptr<MatrixWorkspace> MatrixWorkspace::monitorWorkspace() const { return m_monitorWorkspace; }
1346
1351 const size_t runMemSize = run().getMemorySize();
1352 if (this->isRaggedWorkspace()) {
1353 const auto numHist = this->getNumberHistograms();
1354 size_t total{0};
1355 for (size_t i = 0; i < numHist; ++i) {
1356 total += this->getSpectrum(i).getMemorySize();
1357 }
1358 return total + runMemSize;
1359 } else {
1360 // 3 doubles per histogram bin.
1361 return 3 * size() * sizeof(double) + runMemSize;
1362 }
1363}
1364
1369 size_t total = 0;
1370 auto lastX = this->refX(0);
1371 for (size_t wi = 0; wi < getNumberHistograms(); wi++) {
1372 auto X = this->refX(wi);
1373 // If the pointers are the same
1374 if (!(X == lastX) || wi == 0)
1375 total += (*X).size() * sizeof(double);
1376 }
1377 return total;
1378}
1379
1388Types::Core::DateAndTime MatrixWorkspace::getFirstPulseTime() const { return this->run().getFirstPulseTime(); }
1389
1398Types::Core::DateAndTime MatrixWorkspace::getLastPulseTime() const { return this->run().getLastPulseTime(); }
1399
1408std::size_t MatrixWorkspace::yIndexOfX(const double xValue, const std::size_t &index,
1409 [[maybe_unused]] const double tolerance) const {
1410 if (index >= getNumberHistograms())
1411 throw std::out_of_range("MatrixWorkspace::yIndexOfX - Index out of range.");
1412
1413 const auto &xValues = this->x(index);
1414 const bool ascendingOrder = xValues.front() < xValues.back();
1415 const auto minX = ascendingOrder ? xValues.front() : xValues.back();
1416 const auto maxX = ascendingOrder ? xValues.back() : xValues.front();
1417
1419 if (xValue < minX || xValue > maxX)
1420 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1421 "the range of the min and max bin edges.");
1422
1423 return binIndexOfValue(xValues, xValue, ascendingOrder);
1424 } else {
1425 if (xValue < minX - tolerance || xValue > maxX + tolerance)
1426 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1427 "range for this point data.");
1428
1429 return xIndexOfValue(xValues, xValue, tolerance);
1430 }
1431}
1432
1440std::size_t MatrixWorkspace::binIndexOfValue(HistogramData::HistogramX const &xValues, const double xValue,
1441 const bool ascendingOrder) const {
1442 std::size_t hops;
1443 if (ascendingOrder) {
1444 auto lowerIter = std::lower_bound(xValues.cbegin(), xValues.cend(), xValue);
1445
1446 // If we are pointing at the first value then we want to be in the first bin
1447 if (lowerIter == xValues.cbegin())
1448 ++lowerIter;
1449
1450 hops = std::distance(xValues.cbegin(), lowerIter);
1451 } else {
1452 auto lowerIter = std::lower_bound(xValues.crbegin(), xValues.crend(), xValue);
1453
1454 if (lowerIter == xValues.crbegin())
1455 ++lowerIter;
1456
1457 hops = xValues.size() - std::distance(xValues.crbegin(), lowerIter);
1458 }
1459 // The bin index is offset by one from the number of hops between iterators as
1460 // they start at zero (for a histogram workspace)
1461 return hops - 1;
1462}
1463
1472std::size_t MatrixWorkspace::xIndexOfValue(const HistogramData::HistogramX &xValues, const double xValue,
1473 const double tolerance) const {
1474 auto const iter = std::find_if(xValues.cbegin(), xValues.cend(), [&xValue, &tolerance](double const &value) {
1475 return std::abs(xValue - value) <= tolerance;
1476 });
1477 if (iter != xValues.cend())
1478 return std::distance(xValues.cbegin(), iter);
1479 else
1480 throw std::invalid_argument("MatrixWorkspace::yIndexOfX - the X value provided could not be found "
1481 "in the workspace containing point data.");
1482}
1483
1484uint64_t MatrixWorkspace::getNPoints() const { return static_cast<uint64_t>(this->size()); }
1485
1486//================================= FOR MDGEOMETRY
1487//====================================================
1488
1489size_t MatrixWorkspace::getNumDims() const { return 2; }
1490
1491std::string MatrixWorkspace::getDimensionIdFromAxis(const int &axisIndex) const {
1492 std::string id;
1493 if (0 == axisIndex) {
1494 id = xDimensionId;
1495 } else if (1 == axisIndex) {
1496 id = yDimensionId;
1497 } else {
1498 throw std::invalid_argument("Cannot have an index for a MatrixWorkspace "
1499 "axis that is not == 0 or == 1");
1500 }
1501 return id;
1502}
1503
1504//===============================================================================
1506public:
1507 MWDimension(const Axis *axis, std::string dimensionId)
1508 : m_axis(*axis), m_dimensionId(std::move(dimensionId)),
1509 m_haveEdges(dynamic_cast<const BinEdgeAxis *>(&m_axis) != nullptr),
1510 m_frame(std::make_unique<Geometry::GeneralFrame>(m_axis.unit()->label(), m_axis.unit()->label())) {}
1511
1513 std::string getName() const override {
1514 const auto &unit = m_axis.unit();
1515 if (unit && unit->unitID() != "Empty")
1516 return unit->caption();
1517 else
1518 return m_axis.title();
1519 }
1520
1522 const Kernel::UnitLabel getUnits() const override { return m_axis.unit()->label(); }
1523
1527 const std::string &getDimensionId() const override { return m_dimensionId; }
1528
1530 bool getIsIntegrated() const override { return m_axis.length() == 1; }
1531
1533 coord_t getMinimum() const override { return coord_t(m_axis.getMin()); }
1534
1536 coord_t getMaximum() const override { return coord_t(m_axis.getMax()); }
1537
1540 size_t getNBins() const override {
1541 if (m_haveEdges)
1542 return m_axis.length() - 1;
1543 else
1544 return m_axis.length();
1545 }
1546
1548 size_t getNBoundaries() const override { return m_axis.length(); }
1549
1551 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1552 throw std::runtime_error("Not implemented");
1553 }
1554
1556 coord_t getX(size_t ind) const override { return coord_t(m_axis(ind)); }
1557
1563 coord_t getBinWidth() const override {
1564 size_t nsteps = (m_haveEdges) ? this->getNBins() : this->getNBins() - 1;
1565 return (getMaximum() - getMinimum()) / static_cast<coord_t>(nsteps);
1566 }
1567
1568 // Dimensions must be xml serializable.
1569 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1570
1571 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1572 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1573
1574private:
1575 const Axis &m_axis;
1576 const std::string m_dimensionId;
1577 const bool m_haveEdges;
1579};
1580
1581//===============================================================================
1586public:
1587 MWXDimension(const MatrixWorkspace *ws, std::string dimensionId)
1588 : m_ws(ws), m_X(ws->readX(0)), m_dimensionId(std::move(dimensionId)),
1589 m_frame(std::make_unique<Geometry::GeneralFrame>(m_ws->getAxis(0)->unit()->label(),
1590 m_ws->getAxis(0)->unit()->label())) {}
1591
1593 std::string getName() const override {
1594 const auto *axis = m_ws->getAxis(0);
1595 const auto &unit = axis->unit();
1596 if (unit && unit->unitID() != "Empty")
1597 return unit->caption();
1598 else
1599 return axis->title();
1600 }
1601
1603 const Kernel::UnitLabel getUnits() const override { return m_ws->getAxis(0)->unit()->label(); }
1604
1608 const std::string &getDimensionId() const override { return m_dimensionId; }
1609
1611 bool getIsIntegrated() const override { return m_X.size() == 1; }
1612
1614 coord_t getMinimum() const override { return coord_t(m_X.front()); }
1615
1617 coord_t getMaximum() const override { return coord_t(m_X.back()); }
1618
1621 size_t getNBins() const override { return (m_ws->isHistogramData()) ? m_X.size() - 1 : m_X.size(); }
1622
1624 size_t getNBoundaries() const override { return m_X.size(); }
1625
1627 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1628 throw std::runtime_error("Not implemented");
1629 }
1630
1632 coord_t getX(size_t ind) const override { return coord_t(m_X[ind]); }
1633
1634 // Dimensions must be xml serializable.
1635 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1636 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1637 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1638
1639private:
1645 const std::string m_dimensionId;
1648};
1649
1650std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimension(size_t index) const {
1651 if (index == 0) {
1652 return std::make_shared<MWXDimension>(this, xDimensionId);
1653 } else if (index == 1) {
1654 Axis *yAxis = this->getAxis(1);
1655 return std::make_shared<MWDimension>(yAxis, yDimensionId);
1656 } else
1657 throw std::invalid_argument("MatrixWorkspace only has 2 dimensions.");
1658}
1659
1660std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimensionWithId(std::string id) const {
1661 int nAxes = this->axes();
1662 std::shared_ptr<IMDDimension> dim;
1663 for (int i = 0; i < nAxes; i++) {
1664 const std::string knownId = getDimensionIdFromAxis(i);
1665 if (knownId == id) {
1666 dim = std::make_shared<MWDimension>(this->getAxis(i), id);
1667 break;
1668 }
1669 }
1670
1671 if (nullptr == dim) {
1672 std::string message = "Cannot find id : " + id;
1673 throw std::overflow_error(message);
1674 }
1675 return dim;
1676}
1677
1685std::vector<std::unique_ptr<IMDIterator>>
1687 // Find the right number of cores to use
1688 size_t numCores = suggestedNumCores;
1689 if (!this->threadSafe())
1690 numCores = 1;
1691 size_t numElements = this->getNumberHistograms();
1692 if (numCores > numElements)
1693 numCores = numElements;
1694 if (numCores < 1)
1695 numCores = 1;
1696
1697 // Create one iterator per core, splitting evenly amongst spectra
1698 std::vector<std::unique_ptr<IMDIterator>> out;
1699 for (size_t i = 0; i < numCores; i++) {
1700 size_t begin = (i * numElements) / numCores;
1701 size_t end = ((i + 1) * numElements) / numCores;
1702 if (end > numElements)
1703 end = numElements;
1704 out.emplace_back(std::make_unique<MatrixWorkspaceMDIterator>(this, function, begin, end));
1705 }
1706 return out;
1707}
1708
1726
1734 const Mantid::API::MDNormalization &normalization) const {
1735 if (this->axes() != 2)
1736 throw std::invalid_argument("MatrixWorkspace::getSignalAtCoord() - "
1737 "Workspace can only have 2 axes, found " +
1738 std::to_string(this->axes()));
1739
1740 // First, find the workspace index
1741 Axis const *ax1 = this->getAxis(1);
1742 size_t wi(-1);
1743 try {
1744 wi = ax1->indexOfValue(coords[1]);
1745 } catch (std::out_of_range &) {
1746 return std::numeric_limits<double>::quiet_NaN();
1747 }
1748
1749 const size_t nhist = this->getNumberHistograms();
1750 const auto &yVals = this->y(wi);
1751 double yBinSize(1.0); // only applies for volume normalization & numeric axis
1752 if (normalization == VolumeNormalization && ax1->isNumeric()) {
1753 size_t uVI = 0; // unused vertical index.
1754 double currentVertical = ax1->operator()(wi, uVI);
1755 if (wi + 1 == nhist && nhist > 1) // On the boundary, look back to get diff
1756 {
1757 yBinSize = currentVertical - ax1->operator()(wi - 1, uVI);
1758 } else {
1759 yBinSize = ax1->operator()(wi + 1, uVI) - currentVertical;
1760 }
1761 }
1762
1763 if (wi < nhist) {
1764 const auto &xVals = x(wi);
1765 size_t i;
1766 try {
1767 coord_t xCoord = coords[0];
1768 if (isHistogramData())
1769 i = Kernel::VectorHelper::indexOfValueFromEdges(xVals.rawData(), xCoord);
1770 else
1771 i = Kernel::VectorHelper::indexOfValueFromCenters(xVals.rawData(), xCoord);
1772 } catch (std::out_of_range &) {
1773 return std::numeric_limits<double>::quiet_NaN();
1774 }
1775
1776 double yVal = yVals[i];
1777 // What is our normalization factor?
1778 switch (normalization) {
1779 case NoNormalization:
1780 return yVal;
1781 case VolumeNormalization: {
1782 // Divide the signal by the area
1783 auto volume = yBinSize * (xVals[i + 1] - xVals[i]);
1784 if (volume == 0.0) {
1785 return std::numeric_limits<double>::quiet_NaN();
1786 }
1787 return yVal / volume;
1788 }
1790 // Not yet implemented, may not make sense
1791 return yVal;
1792 }
1793 // This won't happen
1794 return yVal;
1795 } else {
1796 return std::numeric_limits<double>::quiet_NaN();
1797 }
1798}
1799
1808 const Mantid::API::MDNormalization &normalization) const {
1809 return getSignalAtCoord(coords, normalization);
1810}
1811
1812/*
1813MDMasking for a Matrix Workspace has not been implemented.
1814@param :
1815*/
1816void MatrixWorkspace::setMDMasking(std::unique_ptr<Mantid::Geometry::MDImplicitFunction> /*maskingRegion*/) {
1817 throw std::runtime_error("MatrixWorkspace::setMDMasking has no implementation");
1818}
1819
1820/*
1821Clear MDMasking for a Matrix Workspace has not been implemented.
1822*/
1824 throw std::runtime_error("MatrixWorkspace::clearMDMasking has no implementation");
1825}
1826
1833
1834// Check if this class has an oriented lattice on a sample object
1836
1848 size_t start, size_t stop, size_t width, size_t indexStart,
1849 size_t indexEnd) const {
1850 // width must be provided (for now)
1851 if (width == 0) {
1852 throw std::runtime_error("Cannot create image with width 0");
1853 }
1854
1855 size_t nHist = getNumberHistograms();
1856 // use all spectra by default
1857 if (stop == 0) {
1858 stop = nHist;
1859 }
1860
1861 // check start and stop
1862 if (stop < start) {
1863 throw std::runtime_error("Cannot create image for an empty data set.");
1864 }
1865
1866 if (start >= nHist) {
1867 throw std::runtime_error("Cannot create image: start index is out of range");
1868 }
1869
1870 if (stop >= nHist) {
1871 throw std::runtime_error("Cannot create image: stop index is out of range");
1872 }
1873
1874 // calculate image geometry
1875 size_t dataSize = stop - start + 1;
1876 size_t height = dataSize / width;
1877
1878 // and check that the data fits exactly into this geometry
1879 if (height * width != dataSize) {
1880 throw std::runtime_error("Cannot create image: the data set cannot form a rectangle.");
1881 }
1882
1883 size_t nBins = blocksize();
1884 bool isHisto = isHistogramData();
1885
1886 // default indexEnd is the last index of the X vector
1887 if (indexEnd == 0) {
1888 indexEnd = nBins;
1889 if (!isHisto && indexEnd > 0)
1890 --indexEnd;
1891 }
1892
1893 // check the x-range indices
1894 if (indexEnd < indexStart) {
1895 throw std::runtime_error("Cannot create image for an empty data set.");
1896 }
1897
1898 if (indexStart >= nBins || indexEnd > nBins || (!isHisto && indexEnd == nBins)) {
1899 throw std::runtime_error("Cannot create image: integration interval is out of range.");
1900 }
1901
1902 // initialize the image
1903 auto image = std::make_shared<MantidImage>(height);
1904 if (!isHisto)
1905 ++indexEnd;
1906
1907 // deal separately with single-binned workspaces: no integration is required
1908 if (isHisto && indexEnd == indexStart + 1) {
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 row[j] = (this->*read)(spec)[indexStart];
1916 }
1917 }
1918 } else {
1919 // each image pixel is integrated over the x-range [indexStart,indexEnd)
1921 for (int i = 0; i < static_cast<int>(height); ++i) {
1922 auto &row = (*image)[i];
1923 row.resize(width);
1924 size_t spec = start + static_cast<size_t>(i) * width;
1925 for (size_t j = 0; j < width; ++j, ++spec) {
1926 auto &V = (this->*read)(spec);
1927 row[j] = std::accumulate(V.begin() + indexStart, V.begin() + indexEnd, 0.0);
1928 }
1929 }
1930 }
1931
1932 return image;
1933}
1934
1935std::pair<int64_t, int64_t> MatrixWorkspace::findY(double value, const std::pair<int64_t, int64_t> &idx) const {
1936 std::pair<int64_t, int64_t> out(-1, -1);
1937 const int64_t numHists = static_cast<int64_t>(this->getNumberHistograms());
1938 if (std::isnan(value)) {
1939 for (int64_t i = idx.first; i < numHists; ++i) {
1940 const auto &Y = this->y(i);
1941 if (auto it = std::find_if(std::next(Y.begin(), idx.second), Y.end(), [](double v) { return std::isnan(v); });
1942 it != Y.end()) {
1943 out = {i, std::distance(Y.begin(), it)};
1944 break;
1945 }
1946 }
1947 } else {
1948 for (int64_t i = idx.first; i < numHists; ++i) {
1949 const auto &Y = this->y(i);
1950 if (auto it = std::find(std::next(Y.begin(), idx.second), Y.end(), value); it != Y.end()) {
1951 out = {i, std::distance(Y.begin(), it)};
1952 break;
1953 }
1954 }
1955 }
1956 return out;
1957}
1958
1965std::pair<size_t, size_t> MatrixWorkspace::getImageStartEndXIndices(size_t i, double startX, double endX) const {
1966 if (startX == EMPTY_DBL())
1967 startX = x(i).front();
1968 auto pStart = getXIndex(i, startX, true);
1969 if (pStart.second != 0.0) {
1970 throw std::runtime_error("Start X value is required to be on bin boundary.");
1971 }
1972 if (endX == EMPTY_DBL())
1973 endX = x(i).back();
1974 auto pEnd = getXIndex(i, endX, false, pStart.first);
1975 if (pEnd.second != 0.0) {
1976 throw std::runtime_error("End X value is required to be on bin boundary.");
1977 }
1978 return std::make_pair(pStart.first, pEnd.first);
1979}
1980
1989MantidImage_sptr MatrixWorkspace::getImageY(size_t start, size_t stop, size_t width, double startX, double endX) const {
1990 auto p = getImageStartEndXIndices(0, startX, endX);
1991 return getImage(&MatrixWorkspace::readY, start, stop, width, p.first, p.second);
1992}
1993
2002MantidImage_sptr MatrixWorkspace::getImageE(size_t start, size_t stop, size_t width, double startX, double endX) const {
2003 auto p = getImageStartEndXIndices(0, startX, endX);
2004 return getImage(&MatrixWorkspace::readE, start, stop, width, p.first, p.second);
2005}
2006
2019std::pair<size_t, double> MatrixWorkspace::getXIndex(size_t i, double x, bool isLeft, size_t start) const {
2020 auto &X = this->x(i);
2021 auto nx = X.size();
2022
2023 // if start out of range - search failed
2024 if (start >= nx)
2025 return std::make_pair(nx, 0.0);
2026 if (start > 0 && start == nx - 1) {
2027 // starting with the last index is allowed for right boundary search
2028 if (!isLeft)
2029 return std::make_pair(start, 0.0);
2030 return std::make_pair(nx, 0.0);
2031 }
2032
2033 // consider point data with single value
2034 if (nx == 1) {
2035 assert(start == 0);
2036 if (isLeft)
2037 return x <= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2038 return x >= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2039 }
2040
2041 // left boundaries below start value map to the start value
2042 if (x <= X[start]) {
2043 return isLeft ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
2044 }
2045 // right boundary search returns last x value for all values above it
2046 if (x >= X.back()) {
2047 return !isLeft ? std::make_pair(nx - 1, 0.0) : std::make_pair(nx, 0.0);
2048 }
2049
2050 // general case: find the boundary index and bin fraction
2051 auto end = X.end();
2052 for (auto ix = X.begin() + start + 1; ix != end; ++ix) {
2053 if (*ix >= x) {
2054 auto index = static_cast<size_t>(std::distance(X.begin(), ix));
2055 if (isLeft)
2056 --index;
2057 return std::make_pair(index, std::abs((X[index] - x) / (*ix - *(ix - 1))));
2058 }
2059 }
2060 // I don't think we can ever get here
2061 return std::make_pair(nx, 0.0);
2062}
2063
2072void MatrixWorkspace::setImage(MantidVec &(MatrixWorkspace::*dataVec)(const std::size_t), const MantidImage &image,
2073 size_t start, [[maybe_unused]] bool parallelExecution) {
2074
2075 if (image.empty())
2076 return;
2077 if (image[0].empty())
2078 return;
2079
2080 if (blocksize() != 1) {
2081 throw std::runtime_error("Cannot set image: a single bin workspace is expected.");
2082 }
2083
2084 size_t height = image.size();
2085 size_t width = image.front().size();
2086 size_t dataSize = width * height;
2087
2088 if (start + dataSize > getNumberHistograms()) {
2089 throw std::runtime_error("Cannot set image: image is bigger than workspace.");
2090 }
2091
2092 PARALLEL_FOR_IF(parallelExecution)
2093 for (int i = 0; i < static_cast<int>(height); ++i) {
2094 auto &row = image[i];
2095 if (row.size() != width) {
2096 throw std::runtime_error("Canot set image: image is corrupted.");
2097 }
2098 size_t spec = start + static_cast<size_t>(i) * width;
2099 auto rowEnd = row.end();
2100 for (auto pixel = row.begin(); pixel != rowEnd; ++pixel, ++spec) {
2101 (this->*dataVec)(spec)[0] = *pixel;
2102 }
2103 }
2104}
2105
2112void MatrixWorkspace::setImageY(const MantidImage &image, size_t start, bool parallelExecution) {
2113 setImage(&MatrixWorkspace::dataY, image, start, parallelExecution);
2114}
2115
2122void MatrixWorkspace::setImageE(const MantidImage &image, size_t start, bool parallelExecution) {
2123 setImage(&MatrixWorkspace::dataE, image, start, parallelExecution);
2124}
2125
2127
2135 setDetectorGrouping(index, getSpectrum(index).getDetectorIDs());
2136}
2137
2139 const auto &detInfo = detectorInfo();
2140 size_t numberOfDetectors{detInfo.size()};
2141 if (numberOfDetectors == 0) {
2142 // Default to empty spectrum definitions if there is no instrument.
2143 m_indexInfo->setSpectrumDefinitions(std::vector<SpectrumDefinition>(m_indexInfo->size()));
2144 return;
2145 }
2146 size_t numberOfSpectra = numberOfDetectors * detInfo.scanCount();
2147 if (numberOfSpectra != m_indexInfo->globalSize())
2148 throw std::invalid_argument("MatrixWorkspace: IndexInfo does not contain spectrum definitions so "
2149 "building a 1:1 mapping from spectra to detectors was attempted, but "
2150 "the number of spectra in the workspace is not equal to the number of "
2151 "detectors in the instrument.");
2152 std::vector<SpectrumDefinition> specDefs(m_indexInfo->size());
2153 if (!detInfo.isScanning() && (numberOfSpectra == m_indexInfo->size())) {
2154 for (size_t i = 0; i < numberOfSpectra; ++i)
2155 specDefs[i].add(i);
2156 } else {
2157 size_t specIndex = 0;
2158 size_t globalSpecIndex = 0;
2159 for (size_t detIndex = 0; detIndex < detInfo.size(); ++detIndex) {
2160 for (size_t time = 0; time < detInfo.scanCount(); ++time) {
2161 if (m_indexInfo->isOnThisPartition(Indexing::GlobalSpectrumIndex(globalSpecIndex++)))
2162 specDefs[specIndex++].add(detIndex, time);
2163 }
2164 }
2165 }
2166 m_indexInfo->setSpectrumDefinitions(std::move(specDefs));
2167}
2168
2170 const auto &detInfo = detectorInfo();
2171 const auto detInfo_scanCount = detInfo.scanCount(); // cache value outside of the loop
2172 const auto &allDetIDs = detInfo.detectorIDs();
2173 const auto allDetIDs_size = allDetIDs.size(); // cache value outside of the loop
2174 const auto &specDefs = m_indexInfo->spectrumDefinitions();
2175 const auto indexInfoSize = static_cast<int64_t>(m_indexInfo->size());
2176 enum class ErrorCode { None, InvalidDetIndex, InvalidTimeIndex };
2177 std::atomic<ErrorCode> errorValue(ErrorCode::None);
2178#pragma omp parallel for
2179 for (int64_t i = 0; i < indexInfoSize; ++i) {
2180 auto &spec = getSpectrum(i);
2181 // Prevent setting flags that require spectrum definition updates
2182 spec.setMatrixWorkspace(nullptr, i);
2183 spec.setSpectrumNo(static_cast<specnum_t>(m_indexInfo->spectrumNumber(i)));
2184 std::set<detid_t> detIDs;
2185 for (const auto &index : (*specDefs)[i]) {
2186 const size_t detIndex = index.first;
2187 if (detIndex >= allDetIDs_size) {
2188 errorValue = ErrorCode::InvalidDetIndex;
2189 } else if (index.second >= detInfo_scanCount) { // timeIndex is second
2190 errorValue = ErrorCode::InvalidTimeIndex;
2191 } else {
2192 detIDs.insert(allDetIDs[detIndex]);
2193 }
2194 }
2195 spec.setDetectorIDs(std::move(detIDs));
2196 }
2197 switch (errorValue) {
2198 case ErrorCode::InvalidDetIndex:
2199 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2200 "detector index, i.e., the spectrum definition does not match "
2201 "the instrument in the workspace.");
2202 case ErrorCode::InvalidTimeIndex:
2203 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2204 "time index for a detector, i.e., the spectrum definition does "
2205 "not match the instrument in the workspace.");
2206 case ErrorCode::None:; // nothing to do
2207 }
2208}
2209
2210} // namespace Mantid::API
2211
2213namespace Mantid::Kernel {
2214
2215template <>
2217IPropertyManager::getValue<Mantid::API::MatrixWorkspace_sptr>(const std::string &name) const {
2218 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2219 if (prop) {
2220 return *prop;
2221 } else {
2222 std::string message =
2223 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<MatrixWorkspace>.";
2224 throw std::runtime_error(message);
2225 }
2226}
2227
2228template <>
2230IPropertyManager::getValue<Mantid::API::MatrixWorkspace_const_sptr>(const std::string &name) const {
2231 auto const *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2232 if (prop) {
2233 return prop->operator()();
2234 } else {
2235 std::string message =
2236 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<MatrixWorkspace>.";
2237 throw std::runtime_error(message);
2238 }
2239}
2240
2241} // namespace Mantid::Kernel
2242
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.
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.
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
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.