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"
25#include "MantidKernel/MDUnit.h"
30
31#include "MantidParallel/Collectives.h"
32#include "MantidParallel/Communicator.h"
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
44using Mantid::Types::Core::DateAndTime;
45
46namespace {
48auto accumulate_if_finite = [](const double accumulator, const double newValue) {
49 if (std::isfinite(newValue)) {
50 return accumulator + newValue;
51 } else {
52 return accumulator;
53 }
54};
55} // namespace
56
57namespace Mantid::API {
58using std::size_t;
59using namespace Geometry;
60using Kernel::V3D;
61
62namespace {
64Kernel::Logger g_log("MatrixWorkspace");
65constexpr const double EPSILON{1.0e-9};
66
75std::string appendUnitDenominatorUsingPer(std::string yLabel, const MatrixWorkspace &workspace, bool useLatex) {
76 if (useLatex) {
77 std::string xLabel = workspace.getAxis(0)->unit()->label().latex();
78 if (!xLabel.empty())
79 yLabel += " per $" + workspace.getAxis(0)->unit()->label().latex() + "$";
80 } else {
81 std::string xLabel = workspace.getAxis(0)->unit()->label().ascii();
82 if (!xLabel.empty())
83 yLabel += " per " + workspace.getAxis(0)->unit()->label().ascii();
84 }
85 return yLabel;
86}
87
94std::string replacePerWithLatex(std::string yLabel) {
95 std::vector<std::string> splitVec;
96 boost::split_regex(splitVec, yLabel, boost::regex(" per "));
97 if (splitVec.size() > 1) {
98 yLabel = splitVec[0];
99 splitVec.erase(splitVec.begin());
100 std::string unitString = boost::algorithm::join(splitVec, " ");
101 if (!yLabel.empty())
102 yLabel += " ";
103 yLabel += "(" + unitString + ")$^{-1}$";
104 }
105 return yLabel;
106}
107
108} // namespace
109const std::string MatrixWorkspace::xDimensionId = "xDimension";
110const std::string MatrixWorkspace::yDimensionId = "yDimension";
111
113MatrixWorkspace::MatrixWorkspace(const Parallel::StorageMode storageMode)
114 : IMDWorkspace(storageMode), ExperimentInfo(), m_axes(), m_isInitialized(false), m_YUnit(), m_YUnitLabel(),
115 m_masks() {}
116
118 : IMDWorkspace(other), ExperimentInfo(other), m_indexInfo(std::make_unique<Indexing::IndexInfo>(other.indexInfo())),
119 m_isInitialized(other.m_isInitialized), m_YUnit(other.m_YUnit), m_YUnitLabel(other.m_YUnitLabel),
120 m_isCommonBinsFlag(other.m_isCommonBinsFlag), m_masks(other.m_masks), m_indexInfoNeedsUpdate(false) {
121 m_axes.resize(other.m_axes.size());
122 for (size_t i = 0; i < m_axes.size(); ++i)
123 m_axes[i] = std::unique_ptr<Axis>(other.m_axes[i]->clone(this));
124 m_isCommonBinsFlagValid.store(other.m_isCommonBinsFlagValid.load());
125 // TODO: Do we need to init m_monitorWorkspace?
126}
127
129// RJT, 3/10/07: The Analysis Data Service needs to be able to delete
130// workspaces, so I moved this from protected to public.
132
138const Indexing::IndexInfo &MatrixWorkspace::indexInfo() const {
139 std::lock_guard<std::mutex> lock(m_indexInfoMutex);
140 // Individual SpectrumDefinitions in SpectrumInfo may have changed. Due to a
141 // copy-on-write mechanism the definitions stored in IndexInfo may then be out
142 // of sync (definitions in SpectrumInfo have been updated).
143 m_indexInfo->setSpectrumDefinitions(spectrumInfo().sharedSpectrumDefinitions());
144 // If spectrum numbers are set in ISpectrum this flag will be true. However,
145 // for MPI builds we will forbid changing spectrum numbers in this way, so we
146 // should never enter this branch. Thus it is sufficient to set only the local
147 // spectrum numbers here.
149 std::vector<Indexing::SpectrumNumber> spectrumNumbers;
150 for (size_t i = 0; i < getNumberHistograms(); ++i)
151 spectrumNumbers.emplace_back(getSpectrum(i).getSpectrumNo());
152 m_indexInfo->setSpectrumNumbers(std::move(spectrumNumbers));
154 }
155 return *m_indexInfo;
156}
157
161void MatrixWorkspace::setIndexInfo(const Indexing::IndexInfo &indexInfo) {
162 if (indexInfo.storageMode() != storageMode())
163 throw std::invalid_argument("MatrixWorkspace::setIndexInfo: "
164 "Parallel::StorageMode in IndexInfo does not "
165 "match storage mode in workspace");
166
167 // Comparing the *local* size of the indexInfo.
168 if (indexInfo.size() != getNumberHistograms())
169 throw std::invalid_argument("MatrixWorkspace::setIndexInfo: IndexInfo size "
170 "does not match number of histograms in "
171 "workspace");
172
173 m_indexInfo = std::make_unique<Indexing::IndexInfo>(indexInfo);
175 if (!m_indexInfo->spectrumDefinitions())
177 // Fails if spectrum definitions contain invalid indices.
179 // This sets the SpectrumDefinitions for the SpectrumInfo, which may seem
180 // counterintuitive at first -- why would setting IndexInfo modify internals
181 // of SpectrumInfo? However, logically it would not make sense to assign
182 // SpectrumDefinitions in an assignment of SpectrumInfo: Changing
183 // SpectrumDefinitions requires also changes at a higher level of a workspace
184 // (in particular the histograms, which would need to be regrouped as well).
185 // Thus, assignment of SpectrumInfo should just check for compatible
186 // SpectrumDefinitions and assign other data (such as per-spectrum masking
187 // flags, which do not exist yet). Furthermore, since currently detector
188 // groupings are still stored in ISpectrum (in addition to the
189 // SpectrumDefinitions in SpectrumInfo), an assigment of SpectrumDefinitions
190 // in SpectrumInfo would lead to inconsistent workspaces. SpectrumDefinitions
191 // are thus assigned by IndexInfo, which acts at a highler level and is
192 // typically used at construction time of a workspace, i.e., there is no data
193 // in histograms yet which would need to be regrouped.
194 setSpectrumDefinitions(m_indexInfo->spectrumDefinitions());
195}
196
198void MatrixWorkspace::setIndexInfoWithoutISpectrumUpdate(const Indexing::IndexInfo &indexInfo) {
199 // Workspace is already initialized (m_isInitialized == true), but this is
200 // called by initializedFromParent which is some sort of second-stage
201 // initialization, so there is no check for storage mode compatibility here,
202 // in contrast to what setIndexInfo() does.
203 setStorageMode(indexInfo.storageMode());
204 // Comparing the *local* size of the indexInfo.
205 if (indexInfo.size() != getNumberHistograms())
206 throw std::invalid_argument("MatrixWorkspace::setIndexInfo: IndexInfo size "
207 "does not match number of histograms in "
208 "workspace");
211 setSpectrumDefinitions(m_indexInfo->spectrumDefinitions());
212}
213
215const std::string MatrixWorkspace::toString() const {
216 std::ostringstream os;
217 os << id() << "\n"
218 << "Title: " << getTitle() << "\n"
219 << "Histograms: " << getNumberHistograms() << "\n"
220 << "Bins: ";
221
222 try {
223 os << blocksize() << "\n";
224 } catch (std::length_error &) {
225 os << "variable\n"; // TODO shouldn't use try/catch
226 }
227
228 if (isHistogramData())
229 os << "Histogram\n";
230 else
231 os << "Data points\n";
232
233 os << "X axis: ";
234 if (axes() > 0) {
235 Axis *ax = getAxis(0);
236 if (ax && ax->unit())
237 os << ax->unit()->caption() << " / " << ax->unit()->label().ascii();
238 else
239 os << "Not set";
240 } else {
241 os << "N/A";
242 }
243 os << "\n"
244 << "Y axis: " << YUnitLabel() << "\n";
245
246 os << "Distribution: " << (isDistribution() ? "True" : "False") << "\n";
247
249 return os.str();
250}
251
262void MatrixWorkspace::initialize(const std::size_t &NVectors, const std::size_t &XLength, const std::size_t &YLength) {
263 // Check validity of arguments
264 if (NVectors == 0 || XLength == 0 || YLength == 0) {
265 throw std::out_of_range("All arguments to init must be positive and non-zero");
266 }
267
268 // Bypass the initialization if the workspace has already been initialized.
269 if (m_isInitialized)
270 return;
271
273 m_indexInfo = std::make_unique<Indexing::IndexInfo>(NVectors);
274
275 // Invoke init() method of the derived class inside a try/catch clause
276 try {
277 this->init(NVectors, XLength, YLength);
278 } catch (std::runtime_error &) {
279 throw;
280 }
281
282 // Indicate that this workspace has been initialized to prevent duplicate
283 // attempts.
284 m_isInitialized = true;
285}
286
287void MatrixWorkspace::initialize(const std::size_t &NVectors, const HistogramData::Histogram &histogram) {
288 Indexing::IndexInfo indices(NVectors);
289 // Empty SpectrumDefinitions to indicate no default mapping to detectors.
290 indices.setSpectrumDefinitions(std::vector<SpectrumDefinition>(NVectors));
291 return initialize(indices, histogram);
292}
293
294void MatrixWorkspace::initialize(const Indexing::IndexInfo &indexInfo, const HistogramData::Histogram &histogram) {
295 // Check validity of arguments
296 if (indexInfo.size() == 0 || histogram.x().empty()) {
297 throw std::out_of_range("All arguments to init must be positive and non-zero");
298 }
299
300 // Bypass the initialization if the workspace has already been initialized.
301 if (m_isInitialized)
302 return;
303 setStorageMode(indexInfo.storageMode());
307
308 // Indicate that this workspace has been initialized to prevent duplicate
309 // attempts.
310 m_isInitialized = true;
311}
312
313//---------------------------------------------------------------------------------------
318void MatrixWorkspace::setTitle(const std::string &t) {
320
321 // A MatrixWorkspace contains uniquely one Run object, hence for this
322 // workspace
323 // keep the Run object run_title property the same as the workspace title
324 Run &run = mutableRun();
325 run.addProperty("run_title", t, true);
326}
327
332const std::string MatrixWorkspace::getTitle() const {
333 if (run().hasProperty("run_title")) {
334 std::string title = run().getProperty("run_title")->value();
335 return title;
336 } else
337 return Workspace::getTitle();
338}
339
341 for (size_t j = 0; j < getNumberHistograms(); ++j) {
342 auto &spec = getSpectrum(j);
343 try {
344 if (map.indexIsSpecNumber())
345 spec.setDetectorIDs(map.getDetectorIDsForSpectrumNo(spec.getSpectrumNo()));
346 else
347 spec.setDetectorIDs(map.getDetectorIDsForSpectrumIndex(j));
348 } catch (std::out_of_range &e) {
349 // Get here if the spectrum number is not in the map.
350 spec.clearDetectorIDs();
351 g_log.debug(e.what());
352 g_log.debug() << "Spectrum number " << spec.getSpectrumNo() << " not in map.\n";
353 }
354 }
355}
356
366void MatrixWorkspace::rebuildSpectraMapping(const bool includeMonitors, const specnum_t specNumOffset) {
367 if (sptr_instrument->nelements() == 0) {
368 return;
369 }
370
371 std::vector<detid_t> pixelIDs = this->getInstrument()->getDetectorIDs(!includeMonitors);
372
373 try {
374 size_t index = 0;
375 std::vector<detid_t>::const_iterator iend = pixelIDs.end();
376 for (std::vector<detid_t>::const_iterator it = pixelIDs.begin(); it != iend; ++it) {
377 // The detector ID
378 const detid_t detId = *it;
379 const auto specNo = specnum_t(index + specNumOffset);
380
381 if (index < this->getNumberHistograms()) {
382 auto &spec = getSpectrum(index);
383 spec.setSpectrumNo(specNo);
384 spec.setDetectorID(detId);
385 }
386
387 index++;
388 }
389
390 } catch (std::runtime_error &) {
391 throw;
392 }
393}
394
400 auto *ax = dynamic_cast<SpectraAxis *>(this->m_axes[1].get());
401 if (!ax)
402 throw std::runtime_error("MatrixWorkspace::getSpectrumToWorkspaceIndexMap: "
403 "axis[1] is not a SpectraAxis, so I cannot "
404 "generate a map.");
405 try {
406 return ax->getSpectraIndexMap();
407 } catch (std::runtime_error &) {
408 g_log.error() << "MatrixWorkspace::getSpectrumToWorkspaceIndexMap: no elements!";
409 throw;
410 }
411}
412
422 auto *ax = dynamic_cast<SpectraAxis *>(this->m_axes[1].get());
423 if (!ax)
424 throw std::runtime_error("MatrixWorkspace::getSpectrumToWorkspaceIndexMap: "
425 "axis[1] is not a SpectraAxis, so I cannot "
426 "generate a map.");
427
428 // Find the min/max spectra IDs
429 specnum_t min = std::numeric_limits<specnum_t>::max(); // So that any number
430 // will be less than this
431 specnum_t max = -std::numeric_limits<specnum_t>::max(); // So that any number
432 // will be greater than
433 // this
434 size_t length = ax->length();
435 for (size_t i = 0; i < length; i++) {
436 specnum_t spec = ax->spectraNo(i);
437 if (spec < min)
438 min = spec;
439 if (spec > max)
440 max = spec;
441 }
442
443 // Offset so that the "min" value goes to index 0
444 offset = -min;
445
446 // Size correctly
447 std::vector<size_t> out(max - min + 1, 0);
448
449 // Make the vector
450 for (size_t i = 0; i < length; i++) {
451 specnum_t spec = ax->spectraNo(i);
452 out[spec + offset] = i;
453 }
454
455 return out;
456}
457
462 bool retVal = false;
463
464 // Loop through the workspace index
465 for (size_t workspaceIndex = 0; workspaceIndex < this->getNumberHistograms(); workspaceIndex++) {
466 auto detList = getSpectrum(workspaceIndex).getDetectorIDs();
467 if (detList.size() > 1) {
468 retVal = true;
469 break;
470 }
471 }
472 return retVal;
473}
474
489 bool ignoreIfNoValidDets) const {
490 detid2index_map map;
491 const auto &specInfo = spectrumInfo();
492
493 // Loop through the workspace index
494 for (size_t workspaceIndex = 0; workspaceIndex < this->getNumberHistograms(); ++workspaceIndex) {
495 // Workspaces can contain invalid detector IDs. hasDetectors will silently ignore them until this is fixed.
496 if (ignoreIfNoValidDets && !specInfo.hasDetectors(workspaceIndex)) {
497 continue;
498 }
499 auto detList = getSpectrum(workspaceIndex).getDetectorIDs();
500
501 if (throwIfMultipleDets) {
502 if (detList.size() > 1) {
503 throw std::runtime_error("MatrixWorkspace::getDetectorIDToWorkspaceIndexMap(): more than 1 "
504 "detector for one histogram! I cannot generate a map of detector "
505 "ID to workspace index.");
506 }
507
508 // Set the KEY to the detector ID and the VALUE to the workspace index.
509 if (detList.size() == 1)
510 map[*detList.begin()] = workspaceIndex;
511 } else {
512 // Allow multiple detectors per workspace index
513 for (auto det : detList)
514 map[det] = workspaceIndex;
515 }
516
517 // Ignore if the detector list is empty.
518 }
519
520 return map;
521}
522
536 bool throwIfMultipleDets) const {
537 // Make a correct initial size
538 std::vector<size_t> out;
539 detid_t minId = 0;
540 detid_t maxId = 0;
541 this->getInstrument()->getMinMaxDetectorIDs(minId, maxId);
542 offset = -minId;
543 const int outSize = maxId - minId + 1;
544 // Allocate at once
545 out.resize(outSize, std::numeric_limits<size_t>::max());
546
547 for (size_t workspaceIndex = 0; workspaceIndex < getNumberHistograms(); ++workspaceIndex) {
548 // Get the list of detectors from the WS index
549 const auto &detList = this->getSpectrum(workspaceIndex).getDetectorIDs();
550
551 if (throwIfMultipleDets && (detList.size() > 1))
552 throw std::runtime_error("MatrixWorkspace::getDetectorIDToWorkspaceIndexVector(): more than 1 "
553 "detector for one histogram! I cannot generate a map of detector ID "
554 "to workspace index.");
555
556 // Allow multiple detectors per workspace index, or,
557 // If only one is allowed, then this has thrown already
558 for (auto det : detList) {
559 int index = det + offset;
560 if (index < 0 || index >= outSize) {
561 g_log.debug() << "MatrixWorkspace::getDetectorIDToWorkspaceIndexVector("
562 "): detector ID found ("
563 << det << " at workspace index " << workspaceIndex << ") is invalid.\n";
564 } else
565 // Save it at that point.
566 out[index] = workspaceIndex;
567 }
568
569 } // (for each workspace index)
570 return out;
571}
572
579std::vector<size_t> MatrixWorkspace::getIndicesFromSpectra(const std::vector<specnum_t> &spectraList) const {
580 // Clear the output index list
581 std::vector<size_t> indexList;
582 indexList.reserve(this->getNumberHistograms());
583
584 auto iter = spectraList.cbegin();
585 while (iter != spectraList.cend()) {
586 for (size_t i = 0; i < this->getNumberHistograms(); ++i) {
587 if (this->getSpectrum(i).getSpectrumNo() == *iter) {
588 indexList.emplace_back(i);
589 break;
590 }
591 }
592 ++iter;
593 }
594 return indexList;
595}
596
604 for (size_t i = 0; i < this->getNumberHistograms(); ++i) {
605 if (this->getSpectrum(i).getSpectrumNo() == specNo)
606 return i;
607 }
608 throw std::runtime_error("Could not find spectrum number in any spectrum.");
609}
610
622std::vector<size_t> MatrixWorkspace::getIndicesFromDetectorIDs(const std::vector<detid_t> &detIdList) const {
623 if (m_indexInfo->size() != m_indexInfo->globalSize())
624 throw std::runtime_error("MatrixWorkspace: Using getIndicesFromDetectorIDs "
625 "in a parallel run is most likely incorrect. "
626 "Aborting.");
627
628 std::map<detid_t, std::set<size_t>> detectorIDtoWSIndices;
629 for (size_t i = 0; i < getNumberHistograms(); ++i) {
630 auto detIDs = getSpectrum(i).getDetectorIDs();
631 for (auto detID : detIDs) {
632 detectorIDtoWSIndices[detID].insert(i);
633 }
634 }
635
636 std::vector<size_t> indexList;
637 indexList.reserve(detIdList.size());
638 for (const auto detId : detIdList) {
639 auto wsIndices = detectorIDtoWSIndices.find(detId);
640 if (wsIndices != detectorIDtoWSIndices.end()) {
641 std::copy(wsIndices->second.cbegin(), wsIndices->second.cend(), std::back_inserter(indexList));
642 }
643 }
644 return indexList;
645}
646
654std::vector<specnum_t> MatrixWorkspace::getSpectraFromDetectorIDs(const std::vector<detid_t> &detIdList) const {
655 std::vector<specnum_t> spectraList;
656
657 // Try every detector in the list
658 for (auto detId : detIdList) {
659 bool foundDet = false;
660 specnum_t foundSpecNum = 0;
661
662 // Go through every histogram
663 for (size_t i = 0; i < this->getNumberHistograms(); i++) {
664 if (this->getSpectrum(i).hasDetectorID(detId)) {
665 foundDet = true;
666 foundSpecNum = this->getSpectrum(i).getSpectrumNo();
667 break;
668 }
669 }
670
671 if (foundDet)
672 spectraList.emplace_back(foundSpecNum);
673 } // for each detector ID in the list
674 return spectraList;
675}
676
678 double xmin;
679 double xmax;
680 this->getXMinMax(xmin, xmax); // delegate to the proper code
681 return xmin;
682}
683
685 double xmin;
686 double xmax;
687 this->getXMinMax(xmin, xmax); // delegate to the proper code
688 return xmax;
689}
690
691void MatrixWorkspace::getXMinMax(double &xmin, double &xmax) const {
692 // set to crazy values to start
693 xmin = std::numeric_limits<double>::max();
694 xmax = -1.0 * xmin;
695 size_t numberOfSpectra = this->getNumberHistograms();
696
697 // determine the data range
698 for (size_t workspaceIndex = 0; workspaceIndex < numberOfSpectra; workspaceIndex++) {
699 const auto &dataX = this->x(workspaceIndex);
700 const double xfront = dataX.front();
701 const double xback = dataX.back();
702 if (std::isfinite(xfront) && std::isfinite(xback)) {
703 if (xfront < xmin)
704 xmin = xfront;
705 if (xback > xmax)
706 xmax = xback;
707 }
708 }
709 if (m_indexInfo->size() != m_indexInfo->globalSize()) {
710 auto &comm = m_indexInfo->communicator();
711 std::vector<double> extrema(comm.size());
712 Parallel::all_gather(comm, xmin, extrema);
713 xmin = *std::min_element(extrema.begin(), extrema.end());
714 Parallel::all_gather(comm, xmax, extrema);
715 xmax = *std::max_element(extrema.begin(), extrema.end());
716 }
717}
718
732void MatrixWorkspace::getIntegratedSpectra(std::vector<double> &out, const double minX, const double maxX,
733 const bool entireRange) const {
734 out.resize(this->getNumberHistograms(), 0.0);
735
736 // offset for histogram data, because the x axis is not the same size for histogram and point data.
737 const size_t histogramOffset = this->isHistogramData() ? 1 : 0;
738
739 // Run in parallel if the implementation is threadsafe
741 for (int wksp_index = 0; wksp_index < static_cast<int>(this->getNumberHistograms()); wksp_index++) {
742 // Get Handle to data
743 const Mantid::MantidVec &x = this->readX(wksp_index);
744 const auto &y = this->y(wksp_index);
745 // If it is a 1D workspace, no need to integrate
746 if ((x.size() <= 1 + histogramOffset) && (!y.empty())) {
747 out[wksp_index] = y[0];
748 } else {
749 // Iterators for limits - whole range by default
750 Mantid::MantidVec::const_iterator lowit, highit;
751 lowit = x.begin();
752 highit = x.end() - histogramOffset;
753
754 // But maybe we don't want the entire range?
755 if (!entireRange) {
756 // If the first element is lower that the xmin then search for new lowit
757 if ((*lowit) < minX)
758 lowit = std::lower_bound(x.begin(), x.end(), minX);
759 // If the last element is higher that the xmax then search for new highit
760 if (*(highit - 1 + histogramOffset) > maxX)
761 highit = std::upper_bound(lowit, x.end(), maxX);
762 }
763
764 // Get the range for the y vector
765 Mantid::MantidVec::difference_type distmin = std::distance(x.begin(), lowit);
766 Mantid::MantidVec::difference_type distmax = std::distance(x.begin(), highit);
767 double sum(0.0);
768 if (distmin <= distmax) {
769 // Integrate
770 sum = std::accumulate(y.begin() + distmin, y.begin() + distmax, 0.0, accumulate_if_finite);
771 }
772 // Save it in the vector
773 out[wksp_index] = sum;
774 }
775 }
776}
777
788 const auto &dets = getSpectrum(workspaceIndex).getDetectorIDs();
789 Instrument_const_sptr localInstrument = getInstrument();
790 if (!localInstrument) {
791 g_log.debug() << "No instrument defined.\n";
792 throw Kernel::Exception::NotFoundError("Instrument not found", "");
793 }
794
795 const size_t ndets = dets.size();
796 if (ndets == 1) {
797 // If only 1 detector for the spectrum number, just return it
798 return localInstrument->getDetector(*dets.begin());
799 } else if (ndets == 0) {
800 throw Kernel::Exception::NotFoundError("MatrixWorkspace::getDetector(): No "
801 "detectors for this workspace "
802 "index.",
803 "");
804 }
805 // Else need to construct a DetectorGroup and return that
806 auto dets_ptr = localInstrument->getDetectors(dets);
807 return std::make_shared<Geometry::DetectorGroup>(dets_ptr);
808}
809
818
820 Geometry::IComponent_const_sptr source = instrument->getSource();
821 Geometry::IComponent_const_sptr sample = instrument->getSample();
822 if (source == nullptr || sample == nullptr) {
824 "Instrument not sufficiently defined: failed to get source and/or "
825 "sample");
826 }
827
828 const Kernel::V3D samplePos = sample->getPos();
829 const Kernel::V3D beamLine = samplePos - source->getPos();
830
831 if (beamLine.nullVector()) {
832 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
833 }
834 // Get the instrument up axis.
835 const V3D &thetaSignAxis = instrument->getReferenceFrame()->vecThetaSign();
836 return det.getSignedTwoTheta(samplePos, beamLine, thetaSignAxis);
837}
838
847 Instrument_const_sptr instrument = this->getInstrument();
848 Geometry::IComponent_const_sptr source = instrument->getSource();
849 Geometry::IComponent_const_sptr sample = instrument->getSample();
850 if (source == nullptr || sample == nullptr) {
852 "Instrument not sufficiently defined: failed to get source and/or "
853 "sample");
854 }
855
856 const Kernel::V3D samplePos = sample->getPos();
857 const Kernel::V3D beamLine = samplePos - source->getPos();
858
859 if (beamLine.nullVector()) {
860 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
861 }
862 return det.getTwoTheta(samplePos, beamLine);
863}
864
866int MatrixWorkspace::axes() const { return static_cast<int>(m_axes.size()); }
867
874Axis *MatrixWorkspace::getAxis(const std::size_t &axisIndex) const {
875 if (axisIndex >= m_axes.size()) {
876 throw Kernel::Exception::IndexError(axisIndex, m_axes.size(), "Argument to getAxis is invalid for this workspace");
877 }
878
879 return m_axes[axisIndex].get();
880}
881
891void MatrixWorkspace::replaceAxis(const std::size_t &axisIndex, std::unique_ptr<Axis> newAxis) {
892 // First check that axisIndex is in range
893 if (axisIndex >= m_axes.size()) {
894 throw Kernel::Exception::IndexError(axisIndex, m_axes.size(), "Value of axisIndex is invalid for this workspace");
895 }
896 // If we're OK, then delete the old axis and set the pointer to the new one
897 m_axes[axisIndex] = std::move(newAxis);
898}
899
905 if (!this->isCommonBins()) {
906 return false;
907 }
908
909 if (this->getNumberHistograms() == 0) {
910 return false;
911 }
912
913 const auto &x0 = this->x(0);
914 if (x0.size() < 2) {
915 return false;
916 }
917
918 // guard against all axis elements being equal
919 if (x0[1] == x0[0]) {
920 return false;
921 }
922
923 double diff = x0[1] / x0[0];
924 if (!std::isfinite(diff)) {
925 return false;
926 }
927 // ignore final bin, since it may be a different size
928 for (size_t i = 1; i < x0.size() - 2; ++i) {
929 if (std::isfinite(x0[i + 1]) && std::isfinite(x0[i])) {
930 if (std::abs(x0[i + 1] / x0[i] - diff) > EPSILON) {
931 return false;
932 }
933 } else {
934 return false;
935 }
936 }
937 return true;
938}
939
944size_t MatrixWorkspace::numberOfAxis() const { return m_axes.size(); }
945
947std::string MatrixWorkspace::YUnit() const { return m_YUnit; }
948
950void MatrixWorkspace::setYUnit(const std::string &newUnit) { m_YUnit = newUnit; }
951
958std::string MatrixWorkspace::YUnitLabel(bool useLatex /* = false */, bool plotAsDistribution /* = false */) const {
959 std::string retVal;
960 if (!m_YUnitLabel.empty()) {
961 retVal = m_YUnitLabel;
962 // If a custom label has been set and we are dividing by bin width when
963 // plotting (i.e. plotAsDistribution = true and the workspace is not a
964 // distribution), we must append the x-unit as a divisor. We assume the
965 // custom label contains the correct units for the data.
966 if (plotAsDistribution && !this->isDistribution())
967 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
968 } else {
969 retVal = m_YUnit;
970 // If no custom label is set and the workspace is a distribution we need to
971 // append the divisor's unit to the label. If the workspace is not a
972 // distribution, but we are plotting it as a distribution, we must append
973 // the divisor's unit.
974 if (plotAsDistribution || this->isDistribution())
975 retVal = appendUnitDenominatorUsingPer(retVal, *this, useLatex);
976 }
977 if (useLatex)
978 retVal = replacePerWithLatex(retVal);
979 return retVal;
980}
981
983void MatrixWorkspace::setYUnitLabel(const std::string &newLabel) { m_YUnitLabel = newLabel; }
984
990 return getSpectrum(0).yMode() == HistogramData::Histogram::YMode::Frequencies;
991}
992
997 if (isDistribution() == newValue)
998 return;
999 HistogramData::Histogram::YMode ymode =
1000 newValue ? HistogramData::Histogram::YMode::Frequencies : HistogramData::Histogram::YMode::Counts;
1001 for (size_t i = 0; i < getNumberHistograms(); ++i)
1002 getSpectrum(i).setYMode(ymode);
1003}
1004
1010 // all spectra *should* have the same behavior
1011 return isHistogramDataByIndex(0);
1012}
1013
1019bool MatrixWorkspace::isHistogramDataByIndex(const std::size_t index) const {
1020 bool isHist = (x(index).size() != y(index).size());
1021
1022 // TODOHIST temporary sanity check
1023 if (isHist) {
1024 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::BinEdges) {
1025 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1026 "Histogram::Xmode is not BinEdges");
1027 }
1028 } else {
1029 if (getSpectrum(index).histogram().xMode() != HistogramData::Histogram::XMode::Points) {
1030 throw std::logic_error("In MatrixWorkspace::isHistogramData(): "
1031 "Histogram::Xmode is not Points");
1032 }
1033 }
1034 return isHist;
1035}
1036
1042 std::lock_guard<std::mutex> lock{m_isCommonBinsMutex};
1043 const bool isFlagValid{m_isCommonBinsFlagValid.exchange(true)};
1044 if (isFlagValid) {
1045 return m_isCommonBinsFlag;
1046 }
1047 m_isCommonBinsFlag = true;
1048 const size_t numHist = this->getNumberHistograms();
1049 // there being only one or zero histograms is accepted as not being an error
1050 if (numHist <= 1) {
1051 return m_isCommonBinsFlag;
1052 }
1053
1054 // First check if the x-axis shares a common ptr.
1055 const HistogramData::HistogramX *first = &x(0);
1056 for (size_t i = 1; i < numHist; ++i) {
1057 if (&x(i) != first) {
1058 m_isCommonBinsFlag = false;
1059 break;
1060 }
1061 }
1062
1063 // If true, we may return here.
1064 if (m_isCommonBinsFlag) {
1065 return m_isCommonBinsFlag;
1066 }
1067
1068 m_isCommonBinsFlag = true;
1069 // Check that that size of each histogram is identical.
1070 const size_t numBins = x(0).size();
1071 for (size_t i = 1; i < numHist; ++i) {
1072 if (x(i).size() != numBins) {
1073 m_isCommonBinsFlag = false;
1074 break;
1075 }
1076 }
1077
1078 // Check that the values of each histogram are identical.
1079 if (m_isCommonBinsFlag) {
1080 const size_t lastSpec = numHist - 1;
1081 for (size_t i = 0; i < lastSpec; ++i) {
1082 const auto &xi = x(i);
1083 const auto &xip1 = x(i + 1);
1084 for (size_t j = 0; j < numBins; ++j) {
1085 const double a = xi[j];
1086 const double b = xip1[j];
1087 // Check for NaN and infinity before comparing for equality
1088 if (std::isfinite(a) && std::isfinite(b)) {
1089 if (std::abs(a - b) > EPSILON) {
1090 m_isCommonBinsFlag = false;
1091 break;
1092 }
1093 // Otherwise we check that both are NaN or both are infinity
1094 } else if ((std::isnan(a) != std::isnan(b)) || (std::isinf(a) != std::isinf(b))) {
1095 m_isCommonBinsFlag = false;
1096 break;
1097 }
1098 }
1099 }
1100 }
1101 return m_isCommonBinsFlag;
1102}
1103
1109 if (!this->isCommonBins())
1110 return false;
1111
1112 const HistogramData::HistogramX bins = x(0);
1113
1114 for (size_t i = 0; i < bins.size(); ++i) {
1115 if (std::trunc(bins[i]) != bins[i])
1116 return false;
1117 }
1118 return true;
1119}
1120
1135void MatrixWorkspace::maskBin(const size_t &workspaceIndex, const size_t &binIndex, const double &weight) {
1136 // First check the workspaceIndex is valid
1137 if (workspaceIndex >= this->getNumberHistograms())
1138 throw Kernel::Exception::IndexError(workspaceIndex, this->getNumberHistograms(),
1139 "MatrixWorkspace::maskBin,workspaceIndex");
1140 // Then check the bin index
1141 if (binIndex >= y(workspaceIndex).size())
1142 throw Kernel::Exception::IndexError(binIndex, y(workspaceIndex).size(), "MatrixWorkspace::maskBin,binIndex");
1143
1144 // this function is marked parallel critical
1145 flagMasked(workspaceIndex, binIndex, weight);
1146
1147 // this is the actual result of the masking that most algorithms and plotting
1148 // implementations will see, the bin mask flags defined above are used by only
1149 // some algorithms
1150 // If the weight is 0, nothing more needs to be done after flagMasked above
1151 // (i.e. NaN and Inf will also stay intact)
1152 // If the weight is not 0, NaN and Inf values are set to 0,
1153 // whereas other values are scaled by (1 - weight)
1154 if (weight != 0.) {
1155 double &y = this->mutableY(workspaceIndex)[binIndex];
1156 (std::isnan(y) || std::isinf(y)) ? y = 0. : y *= (1 - weight);
1157 double &e = this->mutableE(workspaceIndex)[binIndex];
1158 (std::isnan(e) || std::isinf(e)) ? e = 0. : e *= (1 - weight);
1159 }
1160}
1161
1170void MatrixWorkspace::flagMasked(const size_t &index, const size_t &binIndex, const double &weight) {
1171 // Writing to m_masks is not thread-safe, so put in some protection
1173 // First get a reference to the list for this spectrum (or create a new
1174 // list)
1175 MaskList &binList = m_masks[index];
1176 binList[binIndex] = weight;
1177 }
1178}
1179
1184bool MatrixWorkspace::hasMaskedBins(const size_t &workspaceIndex) const {
1185 // First check the workspaceIndex is valid. Return false if it isn't (decided
1186 // against throwing here).
1187 if (workspaceIndex >= this->getNumberHistograms())
1188 return false;
1189 return m_masks.find(workspaceIndex) != m_masks.end();
1190}
1191
1195bool MatrixWorkspace::hasAnyMaskedBins() const { return !m_masks.empty(); }
1196
1203const MatrixWorkspace::MaskList &MatrixWorkspace::maskedBins(const size_t &workspaceIndex) const {
1204 auto it = m_masks.find(workspaceIndex);
1205 // Throw if there are no masked bins for this spectrum. The caller should
1206 // check first using hasMaskedBins!
1207 if (it == m_masks.end()) {
1208 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1209 }
1210
1211 return it->second;
1212}
1213
1214std::vector<size_t> MatrixWorkspace::maskedBinsIndices(const size_t &workspaceIndex) const {
1215 auto it = m_masks.find(workspaceIndex);
1216 // Throw if there are no masked bins for this spectrum. The caller should
1217 // check first using hasMaskedBins!
1218 if (it == m_masks.end()) {
1219 throw Kernel::Exception::IndexError(workspaceIndex, 0, "MatrixWorkspace::maskedBins");
1220 }
1221
1222 auto maskedBins = it->second;
1223 std::vector<size_t> maskedIds;
1224 maskedIds.reserve(maskedBins.size());
1225
1226 std::transform(maskedBins.begin(), maskedBins.end(), std::back_inserter(maskedIds),
1227 [](const auto &mb) { return mb.first; });
1228 return maskedIds;
1229}
1230
1236void MatrixWorkspace::setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins) {
1237 m_masks[workspaceIndex] = maskedBins;
1238}
1239
1245void MatrixWorkspace::setUnmaskedBins(const size_t workspaceIndex) { m_masks.erase(workspaceIndex); }
1246
1256void MatrixWorkspace::setMonitorWorkspace(const std::shared_ptr<MatrixWorkspace> &monitorWS) {
1257 if (monitorWS.get() == this) {
1258 throw std::runtime_error("To avoid memory leak, monitor workspace"
1259 " can not be the same workspace as the host workspace");
1260 }
1261 m_monitorWorkspace = monitorWS;
1262}
1263
1266std::shared_ptr<MatrixWorkspace> MatrixWorkspace::monitorWorkspace() const { return m_monitorWorkspace; }
1267
1272 // 3 doubles per histogram bin.
1273 return 3 * size() * sizeof(double) + run().getMemorySize();
1274}
1275
1280 size_t total = 0;
1281 auto lastX = this->refX(0);
1282 for (size_t wi = 0; wi < getNumberHistograms(); wi++) {
1283 auto X = this->refX(wi);
1284 // If the pointers are the same
1285 if (!(X == lastX) || wi == 0)
1286 total += (*X).size() * sizeof(double);
1287 }
1288 return total;
1289}
1290
1302Types::Core::DateAndTime MatrixWorkspace::getFirstPulseTime() const {
1303 TimeSeriesProperty<double> *log = this->run().getTimeSeriesProperty<double>("proton_charge");
1304
1305 DateAndTime startDate = log->firstTime();
1306 DateAndTime reference("1991-01-01T00:00:00");
1307
1308 int i = 0;
1309 // Find the first pulse after 1991
1310 while (startDate < reference && i < 100) {
1311 i++;
1312 startDate = log->nthTime(i);
1313 }
1314
1315 // Return as DateAndTime.
1316 return startDate;
1317}
1318
1327Types::Core::DateAndTime MatrixWorkspace::getLastPulseTime() const {
1328 TimeSeriesProperty<double> *log = this->run().getTimeSeriesProperty<double>("proton_charge");
1329 return log->lastTime();
1330}
1331
1340std::size_t MatrixWorkspace::yIndexOfX(const double xValue, const std::size_t &index,
1341 [[maybe_unused]] const double tolerance) const {
1342 if (index >= getNumberHistograms())
1343 throw std::out_of_range("MatrixWorkspace::yIndexOfX - Index out of range.");
1344
1345 const auto &xValues = this->x(index);
1346 const bool ascendingOrder = xValues.front() < xValues.back();
1347 const auto minX = ascendingOrder ? xValues.front() : xValues.back();
1348 const auto maxX = ascendingOrder ? xValues.back() : xValues.front();
1349
1351 if (xValue < minX || xValue > maxX)
1352 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1353 "the range of the min and max bin edges.");
1354
1355 return binIndexOfValue(xValues, xValue, ascendingOrder);
1356 } else {
1357 if (xValue < minX - tolerance || xValue > maxX + tolerance)
1358 throw std::out_of_range("MatrixWorkspace::yIndexOfX - X value is out of "
1359 "range for this point data.");
1360
1361 return xIndexOfValue(xValues, xValue, tolerance);
1362 }
1363}
1364
1372std::size_t MatrixWorkspace::binIndexOfValue(HistogramData::HistogramX const &xValues, const double xValue,
1373 const bool ascendingOrder) const {
1374 std::size_t hops;
1375 if (ascendingOrder) {
1376 auto lowerIter = std::lower_bound(xValues.cbegin(), xValues.cend(), xValue);
1377
1378 // If we are pointing at the first value then we want to be in the first bin
1379 if (lowerIter == xValues.cbegin())
1380 ++lowerIter;
1381
1382 hops = std::distance(xValues.cbegin(), lowerIter);
1383 } else {
1384 auto lowerIter = std::lower_bound(xValues.crbegin(), xValues.crend(), xValue);
1385
1386 if (lowerIter == xValues.crbegin())
1387 ++lowerIter;
1388
1389 hops = xValues.size() - std::distance(xValues.crbegin(), lowerIter);
1390 }
1391 // The bin index is offset by one from the number of hops between iterators as
1392 // they start at zero (for a histogram workspace)
1393 return hops - 1;
1394}
1395
1404std::size_t MatrixWorkspace::xIndexOfValue(const HistogramData::HistogramX &xValues, const double xValue,
1405 const double tolerance) const {
1406 auto const iter = std::find_if(xValues.cbegin(), xValues.cend(), [&xValue, &tolerance](double const &value) {
1407 return std::abs(xValue - value) <= tolerance;
1408 });
1409 if (iter != xValues.cend())
1410 return std::distance(xValues.cbegin(), iter);
1411 else
1412 throw std::invalid_argument("MatrixWorkspace::yIndexOfX - the X value provided could not be found "
1413 "in the workspace containing point data.");
1414}
1415
1416uint64_t MatrixWorkspace::getNPoints() const { return static_cast<uint64_t>(this->size()); }
1417
1418//================================= FOR MDGEOMETRY
1419//====================================================
1420
1421size_t MatrixWorkspace::getNumDims() const { return 2; }
1422
1423std::string MatrixWorkspace::getDimensionIdFromAxis(const int &axisIndex) const {
1424 std::string id;
1425 if (0 == axisIndex) {
1426 id = xDimensionId;
1427 } else if (1 == axisIndex) {
1428 id = yDimensionId;
1429 } else {
1430 throw std::invalid_argument("Cannot have an index for a MatrixWorkspace "
1431 "axis that is not == 0 or == 1");
1432 }
1433 return id;
1434}
1435
1436//===============================================================================
1438public:
1439 MWDimension(const Axis *axis, std::string dimensionId)
1440 : m_axis(*axis), m_dimensionId(std::move(dimensionId)),
1441 m_haveEdges(dynamic_cast<const BinEdgeAxis *>(&m_axis) != nullptr),
1442 m_frame(std::make_unique<Geometry::GeneralFrame>(m_axis.unit()->label(), m_axis.unit()->label())) {}
1443
1445 std::string getName() const override {
1446 const auto &unit = m_axis.unit();
1447 if (unit && unit->unitID() != "Empty")
1448 return unit->caption();
1449 else
1450 return m_axis.title();
1451 }
1452
1454 const Kernel::UnitLabel getUnits() const override { return m_axis.unit()->label(); }
1455
1459 const std::string &getDimensionId() const override { return m_dimensionId; }
1460
1462 bool getIsIntegrated() const override { return m_axis.length() == 1; }
1463
1465 coord_t getMinimum() const override { return coord_t(m_axis.getMin()); }
1466
1468 coord_t getMaximum() const override { return coord_t(m_axis.getMax()); }
1469
1472 size_t getNBins() const override {
1473 if (m_haveEdges)
1474 return m_axis.length() - 1;
1475 else
1476 return m_axis.length();
1477 }
1478
1480 size_t getNBoundaries() const override { return m_axis.length(); }
1481
1483 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1484 throw std::runtime_error("Not implemented");
1485 }
1486
1488 coord_t getX(size_t ind) const override { return coord_t(m_axis(ind)); }
1489
1495 coord_t getBinWidth() const override {
1496 size_t nsteps = (m_haveEdges) ? this->getNBins() : this->getNBins() - 1;
1497 return (getMaximum() - getMinimum()) / static_cast<coord_t>(nsteps);
1498 }
1499
1500 // Dimensions must be xml serializable.
1501 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1502
1503 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1504 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1505
1506private:
1507 const Axis &m_axis;
1508 const std::string m_dimensionId;
1509 const bool m_haveEdges;
1511};
1512
1513//===============================================================================
1518public:
1519 MWXDimension(const MatrixWorkspace *ws, std::string dimensionId)
1520 : m_ws(ws), m_X(ws->readX(0)), m_dimensionId(std::move(dimensionId)),
1521 m_frame(std::make_unique<Geometry::GeneralFrame>(m_ws->getAxis(0)->unit()->label(),
1522 m_ws->getAxis(0)->unit()->label())) {}
1523
1525 std::string getName() const override {
1526 const auto *axis = m_ws->getAxis(0);
1527 const auto &unit = axis->unit();
1528 if (unit && unit->unitID() != "Empty")
1529 return unit->caption();
1530 else
1531 return axis->title();
1532 }
1533
1535 const Kernel::UnitLabel getUnits() const override { return m_ws->getAxis(0)->unit()->label(); }
1536
1540 const std::string &getDimensionId() const override { return m_dimensionId; }
1541
1543 bool getIsIntegrated() const override { return m_X.size() == 1; }
1544
1546 coord_t getMinimum() const override { return coord_t(m_X.front()); }
1547
1549 coord_t getMaximum() const override { return coord_t(m_X.back()); }
1550
1553 size_t getNBins() const override { return (m_ws->isHistogramData()) ? m_X.size() - 1 : m_X.size(); }
1554
1556 size_t getNBoundaries() const override { return m_X.size(); }
1557
1559 void setRange(size_t /*nBins*/, coord_t /*min*/, coord_t /*max*/) override {
1560 throw std::runtime_error("Not implemented");
1561 }
1562
1564 coord_t getX(size_t ind) const override { return coord_t(m_X[ind]); }
1565
1566 // Dimensions must be xml serializable.
1567 std::string toXMLString() const override { throw std::runtime_error("Not implemented"); }
1568 const Kernel::MDUnit &getMDUnits() const override { return m_frame->getMDUnit(); }
1569 const Geometry::MDFrame &getMDFrame() const override { return *m_frame; }
1570
1571private:
1577 const std::string m_dimensionId;
1580};
1581
1582std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimension(size_t index) const {
1583 if (index == 0) {
1584 return std::make_shared<MWXDimension>(this, xDimensionId);
1585 } else if (index == 1) {
1586 Axis *yAxis = this->getAxis(1);
1587 return std::make_shared<MWDimension>(yAxis, yDimensionId);
1588 } else
1589 throw std::invalid_argument("MatrixWorkspace only has 2 dimensions.");
1590}
1591
1592std::shared_ptr<const Mantid::Geometry::IMDDimension> MatrixWorkspace::getDimensionWithId(std::string id) const {
1593 int nAxes = this->axes();
1594 std::shared_ptr<IMDDimension> dim;
1595 for (int i = 0; i < nAxes; i++) {
1596 const std::string knownId = getDimensionIdFromAxis(i);
1597 if (knownId == id) {
1598 dim = std::make_shared<MWDimension>(this->getAxis(i), id);
1599 break;
1600 }
1601 }
1602
1603 if (nullptr == dim) {
1604 std::string message = "Cannot find id : " + id;
1605 throw std::overflow_error(message);
1606 }
1607 return dim;
1608}
1609
1617std::vector<std::unique_ptr<IMDIterator>>
1619 // Find the right number of cores to use
1620 size_t numCores = suggestedNumCores;
1621 if (!this->threadSafe())
1622 numCores = 1;
1623 size_t numElements = this->getNumberHistograms();
1624 if (numCores > numElements)
1625 numCores = numElements;
1626 if (numCores < 1)
1627 numCores = 1;
1628
1629 // Create one iterator per core, splitting evenly amongst spectra
1630 std::vector<std::unique_ptr<IMDIterator>> out;
1631 for (size_t i = 0; i < numCores; i++) {
1632 size_t begin = (i * numElements) / numCores;
1633 size_t end = ((i + 1) * numElements) / numCores;
1634 if (end > numElements)
1635 end = numElements;
1636 out.emplace_back(std::make_unique<MatrixWorkspaceMDIterator>(this, function, begin, end));
1637 }
1638 return out;
1639}
1640
1656 return IMDWorkspace::getLinePlot(start, end, normalize);
1657}
1658
1666 const Mantid::API::MDNormalization &normalization) const {
1667 if (this->axes() != 2)
1668 throw std::invalid_argument("MatrixWorkspace::getSignalAtCoord() - "
1669 "Workspace can only have 2 axes, found " +
1670 std::to_string(this->axes()));
1671
1672 coord_t xCoord = coords[0];
1673 coord_t yCoord = coords[1];
1674 // First, find the workspace index
1675 Axis *ax1 = this->getAxis(1);
1676 size_t wi(-1);
1677 try {
1678 wi = ax1->indexOfValue(yCoord);
1679 } catch (std::out_of_range &) {
1680 return std::numeric_limits<double>::quiet_NaN();
1681 }
1682
1683 const size_t nhist = this->getNumberHistograms();
1684 const auto &yVals = this->y(wi);
1685 double yBinSize(1.0); // only applies for volume normalization & numeric axis
1686 if (normalization == VolumeNormalization && ax1->isNumeric()) {
1687 size_t uVI = 0; // unused vertical index.
1688 double currentVertical = ax1->operator()(wi, uVI);
1689 if (wi + 1 == nhist && nhist > 1) // On the boundary, look back to get diff
1690 {
1691 yBinSize = currentVertical - ax1->operator()(wi - 1, uVI);
1692 } else {
1693 yBinSize = ax1->operator()(wi + 1, uVI) - currentVertical;
1694 }
1695 }
1696
1697 if (wi < nhist) {
1698 const auto &xVals = x(wi);
1699 size_t i;
1700 try {
1701 if (isHistogramData())
1702 i = Kernel::VectorHelper::indexOfValueFromEdges(xVals.rawData(), xCoord);
1703 else
1704 i = Kernel::VectorHelper::indexOfValueFromCenters(xVals.rawData(), xCoord);
1705 } catch (std::out_of_range &) {
1706 return std::numeric_limits<double>::quiet_NaN();
1707 }
1708
1709 double y = yVals[i];
1710 // What is our normalization factor?
1711 switch (normalization) {
1712 case NoNormalization:
1713 return y;
1714 case VolumeNormalization: {
1715 // Divide the signal by the area
1716 auto volume = yBinSize * (xVals[i + 1] - xVals[i]);
1717 if (volume == 0.0) {
1718 return std::numeric_limits<double>::quiet_NaN();
1719 }
1720 return y / volume;
1721 }
1723 // Not yet implemented, may not make sense
1724 return y;
1725 }
1726 // This won't happen
1727 return y;
1728 } else {
1729 return std::numeric_limits<double>::quiet_NaN();
1730 }
1731}
1732
1741 const Mantid::API::MDNormalization &normalization) const {
1742 return getSignalAtCoord(coords, normalization);
1743}
1744
1745/*
1746MDMasking for a Matrix Workspace has not been implemented.
1747@param :
1748*/
1749void MatrixWorkspace::setMDMasking(std::unique_ptr<Mantid::Geometry::MDImplicitFunction> /*maskingRegion*/) {
1750 throw std::runtime_error("MatrixWorkspace::setMDMasking has no implementation");
1751}
1752
1753/*
1754Clear MDMasking for a Matrix Workspace has not been implemented.
1755*/
1757 throw std::runtime_error("MatrixWorkspace::clearMDMasking has no implementation");
1758}
1759
1764 return Mantid::Kernel::None;
1765}
1766
1767// Check if this class has an oriented lattice on a sample object
1769
1781 size_t start, size_t stop, size_t width, size_t indexStart,
1782 size_t indexEnd) const {
1783 // width must be provided (for now)
1784 if (width == 0) {
1785 throw std::runtime_error("Cannot create image with width 0");
1786 }
1787
1788 size_t nHist = getNumberHistograms();
1789 // use all spectra by default
1790 if (stop == 0) {
1791 stop = nHist;
1792 }
1793
1794 // check start and stop
1795 if (stop < start) {
1796 throw std::runtime_error("Cannot create image for an empty data set.");
1797 }
1798
1799 if (start >= nHist) {
1800 throw std::runtime_error("Cannot create image: start index is out of range");
1801 }
1802
1803 if (stop >= nHist) {
1804 throw std::runtime_error("Cannot create image: stop index is out of range");
1805 }
1806
1807 // calculate image geometry
1808 size_t dataSize = stop - start + 1;
1809 size_t height = dataSize / width;
1810
1811 // and check that the data fits exactly into this geometry
1812 if (height * width != dataSize) {
1813 throw std::runtime_error("Cannot create image: the data set cannot form a rectangle.");
1814 }
1815
1816 size_t nBins = blocksize();
1817 bool isHisto = isHistogramData();
1818
1819 // default indexEnd is the last index of the X vector
1820 if (indexEnd == 0) {
1821 indexEnd = nBins;
1822 if (!isHisto && indexEnd > 0)
1823 --indexEnd;
1824 }
1825
1826 // check the x-range indices
1827 if (indexEnd < indexStart) {
1828 throw std::runtime_error("Cannot create image for an empty data set.");
1829 }
1830
1831 if (indexStart >= nBins || indexEnd > nBins || (!isHisto && indexEnd == nBins)) {
1832 throw std::runtime_error("Cannot create image: integration interval is out of range.");
1833 }
1834
1835 // initialize the image
1836 auto image = std::make_shared<MantidImage>(height);
1837 if (!isHisto)
1838 ++indexEnd;
1839
1840 // deal separately with single-binned workspaces: no integration is required
1841 if (isHisto && indexEnd == indexStart + 1) {
1843 for (int i = 0; i < static_cast<int>(height); ++i) {
1844 auto &row = (*image)[i];
1845 row.resize(width);
1846 size_t spec = start + static_cast<size_t>(i) * width;
1847 for (size_t j = 0; j < width; ++j, ++spec) {
1848 row[j] = (this->*read)(spec)[indexStart];
1849 }
1850 }
1851 } else {
1852 // each image pixel is integrated over the x-range [indexStart,indexEnd)
1854 for (int i = 0; i < static_cast<int>(height); ++i) {
1855 auto &row = (*image)[i];
1856 row.resize(width);
1857 size_t spec = start + static_cast<size_t>(i) * width;
1858 for (size_t j = 0; j < width; ++j, ++spec) {
1859 auto &V = (this->*read)(spec);
1860 row[j] = std::accumulate(V.begin() + indexStart, V.begin() + indexEnd, 0.0);
1861 }
1862 }
1863 }
1864
1865 return image;
1866}
1867
1868std::pair<int64_t, int64_t> MatrixWorkspace::findY(double value, const std::pair<int64_t, int64_t> &idx) const {
1869 std::pair<int64_t, int64_t> out(-1, -1);
1870 const int64_t numHists = static_cast<int64_t>(this->getNumberHistograms());
1871 if (std::isnan(value)) {
1872 for (int64_t i = idx.first; i < numHists; ++i) {
1873 const auto &Y = this->y(i);
1874 if (auto it = std::find_if(std::next(Y.begin(), idx.second), Y.end(), [](double v) { return std::isnan(v); });
1875 it != Y.end()) {
1876 out = {i, std::distance(Y.begin(), it)};
1877 break;
1878 }
1879 }
1880 } else {
1881 for (int64_t i = idx.first; i < numHists; ++i) {
1882 const auto &Y = this->y(i);
1883 if (auto it = std::find(std::next(Y.begin(), idx.second), Y.end(), value); it != Y.end()) {
1884 out = {i, std::distance(Y.begin(), it)};
1885 break;
1886 }
1887 }
1888 }
1889 return out;
1890}
1891
1898std::pair<size_t, size_t> MatrixWorkspace::getImageStartEndXIndices(size_t i, double startX, double endX) const {
1899 if (startX == EMPTY_DBL())
1900 startX = x(i).front();
1901 auto pStart = getXIndex(i, startX, true);
1902 if (pStart.second != 0.0) {
1903 throw std::runtime_error("Start X value is required to be on bin boundary.");
1904 }
1905 if (endX == EMPTY_DBL())
1906 endX = x(i).back();
1907 auto pEnd = getXIndex(i, endX, false, pStart.first);
1908 if (pEnd.second != 0.0) {
1909 throw std::runtime_error("End X value is required to be on bin boundary.");
1910 }
1911 return std::make_pair(pStart.first, pEnd.first);
1912}
1913
1922MantidImage_sptr MatrixWorkspace::getImageY(size_t start, size_t stop, size_t width, double startX, double endX) const {
1923 auto p = getImageStartEndXIndices(0, startX, endX);
1924 return getImage(&MatrixWorkspace::readY, start, stop, width, p.first, p.second);
1925}
1926
1935MantidImage_sptr MatrixWorkspace::getImageE(size_t start, size_t stop, size_t width, double startX, double endX) const {
1936 auto p = getImageStartEndXIndices(0, startX, endX);
1937 return getImage(&MatrixWorkspace::readE, start, stop, width, p.first, p.second);
1938}
1939
1952std::pair<size_t, double> MatrixWorkspace::getXIndex(size_t i, double x, bool isLeft, size_t start) const {
1953 auto &X = this->x(i);
1954 auto nx = X.size();
1955
1956 // if start out of range - search failed
1957 if (start >= nx)
1958 return std::make_pair(nx, 0.0);
1959 if (start > 0 && start == nx - 1) {
1960 // starting with the last index is allowed for right boundary search
1961 if (!isLeft)
1962 return std::make_pair(start, 0.0);
1963 return std::make_pair(nx, 0.0);
1964 }
1965
1966 // consider point data with single value
1967 if (nx == 1) {
1968 assert(start == 0);
1969 if (isLeft)
1970 return x <= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
1971 return x >= X[start] ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
1972 }
1973
1974 // left boundaries below start value map to the start value
1975 if (x <= X[start]) {
1976 return isLeft ? std::make_pair(start, 0.0) : std::make_pair(nx, 0.0);
1977 }
1978 // right boundary search returns last x value for all values above it
1979 if (x >= X.back()) {
1980 return !isLeft ? std::make_pair(nx - 1, 0.0) : std::make_pair(nx, 0.0);
1981 }
1982
1983 // general case: find the boundary index and bin fraction
1984 auto end = X.end();
1985 for (auto ix = X.begin() + start + 1; ix != end; ++ix) {
1986 if (*ix >= x) {
1987 auto index = static_cast<size_t>(std::distance(X.begin(), ix));
1988 if (isLeft)
1989 --index;
1990 return std::make_pair(index, fabs((X[index] - x) / (*ix - *(ix - 1))));
1991 }
1992 }
1993 // I don't think we can ever get here
1994 return std::make_pair(nx, 0.0);
1995}
1996
2005void MatrixWorkspace::setImage(MantidVec &(MatrixWorkspace::*dataVec)(const std::size_t), const MantidImage &image,
2006 size_t start, [[maybe_unused]] bool parallelExecution) {
2007
2008 if (image.empty())
2009 return;
2010 if (image[0].empty())
2011 return;
2012
2013 if (blocksize() != 1) {
2014 throw std::runtime_error("Cannot set image: a single bin workspace is expected.");
2015 }
2016
2017 size_t height = image.size();
2018 size_t width = image.front().size();
2019 size_t dataSize = width * height;
2020
2021 if (start + dataSize > getNumberHistograms()) {
2022 throw std::runtime_error("Cannot set image: image is bigger than workspace.");
2023 }
2024
2025 PARALLEL_FOR_IF(parallelExecution)
2026 for (int i = 0; i < static_cast<int>(height); ++i) {
2027 auto &row = image[i];
2028 if (row.size() != width) {
2029 throw std::runtime_error("Canot set image: image is corrupted.");
2030 }
2031 size_t spec = start + static_cast<size_t>(i) * width;
2032 auto rowEnd = row.end();
2033 for (auto pixel = row.begin(); pixel != rowEnd; ++pixel, ++spec) {
2034 (this->*dataVec)(spec)[0] = *pixel;
2035 }
2036 }
2037}
2038
2045void MatrixWorkspace::setImageY(const MantidImage &image, size_t start, bool parallelExecution) {
2046 setImage(&MatrixWorkspace::dataY, image, start, parallelExecution);
2047}
2048
2055void MatrixWorkspace::setImageE(const MantidImage &image, size_t start, bool parallelExecution) {
2056 setImage(&MatrixWorkspace::dataE, image, start, parallelExecution);
2057}
2058
2060 if (m_isInitialized && storageMode() == Parallel::StorageMode::Distributed && m_indexInfo->communicator().size() > 1)
2061 throw std::logic_error("Setting spectrum numbers in MatrixWorkspace via "
2062 "ISpectrum::setSpectrumNo is not possible in MPI "
2063 "runs for distributed workspaces. Use IndexInfo.");
2065}
2066
2074 setDetectorGrouping(index, getSpectrum(index).getDetectorIDs());
2075}
2076
2078 const auto &detInfo = detectorInfo();
2079 size_t numberOfDetectors{detInfo.size()};
2080 if (numberOfDetectors == 0) {
2081 // Default to empty spectrum definitions if there is no instrument.
2082 m_indexInfo->setSpectrumDefinitions(std::vector<SpectrumDefinition>(m_indexInfo->size()));
2083 return;
2084 }
2085 size_t numberOfSpectra = numberOfDetectors * detInfo.scanCount();
2086 if (numberOfSpectra != m_indexInfo->globalSize())
2087 throw std::invalid_argument("MatrixWorkspace: IndexInfo does not contain spectrum definitions so "
2088 "building a 1:1 mapping from spectra to detectors was attempted, but "
2089 "the number of spectra in the workspace is not equal to the number of "
2090 "detectors in the instrument.");
2091 std::vector<SpectrumDefinition> specDefs(m_indexInfo->size());
2092 if (!detInfo.isScanning() && (numberOfSpectra == m_indexInfo->size())) {
2093 for (size_t i = 0; i < numberOfSpectra; ++i)
2094 specDefs[i].add(i);
2095 } else {
2096 size_t specIndex = 0;
2097 size_t globalSpecIndex = 0;
2098 for (size_t detIndex = 0; detIndex < detInfo.size(); ++detIndex) {
2099 for (size_t time = 0; time < detInfo.scanCount(); ++time) {
2100 if (m_indexInfo->isOnThisPartition(Indexing::GlobalSpectrumIndex(globalSpecIndex++)))
2101 specDefs[specIndex++].add(detIndex, time);
2102 }
2103 }
2104 }
2105 m_indexInfo->setSpectrumDefinitions(std::move(specDefs));
2106}
2107
2109 const auto &detInfo = detectorInfo();
2110 const auto &allDetIDs = detInfo.detectorIDs();
2111 const auto &specDefs = m_indexInfo->spectrumDefinitions();
2112 const auto size = static_cast<int64_t>(m_indexInfo->size());
2113 enum class ErrorCode { None, InvalidDetIndex, InvalidTimeIndex };
2114 std::atomic<ErrorCode> errorValue(ErrorCode::None);
2115#pragma omp parallel for
2116 for (int64_t i = 0; i < size; ++i) {
2117 auto &spec = getSpectrum(i);
2118 // Prevent setting flags that require spectrum definition updates
2119 spec.setMatrixWorkspace(nullptr, i);
2120 spec.setSpectrumNo(static_cast<specnum_t>(m_indexInfo->spectrumNumber(i)));
2121 std::set<detid_t> detIDs;
2122 for (const auto &index : (*specDefs)[i]) {
2123 const size_t detIndex = index.first;
2124 const size_t timeIndex = index.second;
2125 if (detIndex >= allDetIDs.size()) {
2126 errorValue = ErrorCode::InvalidDetIndex;
2127 } else if (timeIndex >= detInfo.scanCount()) {
2128 errorValue = ErrorCode::InvalidTimeIndex;
2129 } else {
2130 detIDs.insert(allDetIDs[detIndex]);
2131 }
2132 }
2133 spec.setDetectorIDs(std::move(detIDs));
2134 }
2135 switch (errorValue) {
2136 case ErrorCode::InvalidDetIndex:
2137 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2138 "detector index, i.e., the spectrum definition does not match "
2139 "the instrument in the workspace.");
2140 case ErrorCode::InvalidTimeIndex:
2141 throw std::invalid_argument("MatrixWorkspace: SpectrumDefinition contains an out-of-range "
2142 "time index for a detector, i.e., the spectrum definition does "
2143 "not match the instrument in the workspace.");
2144 case ErrorCode::None:; // nothing to do
2145 }
2146}
2147
2148} // namespace Mantid::API
2149
2151namespace Mantid::Kernel {
2152
2153template <>
2155IPropertyManager::getValue<Mantid::API::MatrixWorkspace_sptr>(const std::string &name) const {
2156 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2157 if (prop) {
2158 return *prop;
2159 } else {
2160 std::string message =
2161 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<MatrixWorkspace>.";
2162 throw std::runtime_error(message);
2163 }
2164}
2165
2166template <>
2168IPropertyManager::getValue<Mantid::API::MatrixWorkspace_const_sptr>(const std::string &name) const {
2169 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::MatrixWorkspace_sptr> *>(getPointerToProperty(name));
2170 if (prop) {
2171 return prop->operator()();
2172 } else {
2173 std::string message =
2174 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<MatrixWorkspace>.";
2175 throw std::runtime_error(message);
2176 }
2177}
2178
2179} // namespace Mantid::Kernel
2180
double value
The value of the point.
Definition: FitMW.cpp:51
double height
Definition: GetAllEi.cpp:155
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
const double EPSILON(1.0E-10)
#define fabs(x)
Definition: Matrix.cpp:22
#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.
Definition: IMDWorkspace.h:40
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:105
specnum_t getSpectrumNo() const
Definition: ISpectrum.cpp:123
bool hasDetectorID(const detid_t detID) const
Return true if the given detector ID is in the list for this ISpectrum.
Definition: ISpectrum.cpp:109
virtual HistogramData::Histogram histogram() const
Returns the Histogram associated with this spectrum.
Definition: ISpectrum.h:95
void setYMode(HistogramData::Histogram::YMode ymode)
Definition: ISpectrum.h:106
const std::set< detid_t > & getDetectorIDs() const
Get a const reference to the detector IDs set.
Definition: ISpectrum.cpp:113
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
Definition: LogManager.cpp:404
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition: LogManager.h:79
Kernel::TimeSeriesProperty< T > * getTimeSeriesProperty(const std::string &name) const
Returns a property as a time series property.
Definition: LogManager.cpp:308
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.
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.
const HistogramData::HistogramE & e(const size_t index) const
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 MantidVec & dataX(const std::size_t index)
Deprecated, use mutableX() instead. Returns the x data.
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.
MatrixWorkspace(const MatrixWorkspace &other)
Protected copy constructor. May be used by childs for cloning.
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::shared_ptr< MatrixWorkspace > monitorWorkspace() const
Returns a pointer to the internal monitor workspace.
LinePlot getLinePlot(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize) const override
Generate a line plot through the matrix workspace.
std::vector< size_t > maskedBinsIndices(const size_t &workspaceIndex) const
virtual bool isIntegerBins() const
Returns true if the workspace has common, integer X bins.
HistogramData::Histogram histogram(const size_t index) const
Returns the Histogram at the given workspace index.
std::vector< size_t > getIndicesFromDetectorIDs(const std::vector< detid_t > &detIdList) const
Converts a list of detector IDs to the corresponding workspace indices.
const std::string getTitle() const override
Gets MatrixWorkspace title (same as Run object run_title property)
void setDistribution(bool newValue)
Set the flag for whether the Y-values are dimensioned.
size_t getMemorySize() const override
Get the footprint in memory in bytes.
const Indexing::IndexInfo & indexInfo() const
Returns a const reference to the IndexInfo object of the workspace.
virtual void getIntegratedSpectra(std::vector< double > &out, const double minX, const double maxX, const bool entireRange) const
Return a vector with the integrated counts for all spectra withing the given range.
uint64_t getNPoints() const override
Gets the number of points available on the workspace.
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.
size_t getNumDims() const override
virtual double getXMax() const
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.
bool m_isCommonBinsFlag
Flag indicating whether the data has common bins.
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.
void replaceAxis(const std::size_t &axisIndex, std::unique_ptr< Axis > newAxis)
Replaces one of the workspace's axes with the new one provided.
std::string YUnit() const
Returns the units of the data in the workspace.
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.
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:38
size_t getMemorySize() const override
Return an approximate memory size for the object in bytes.
Definition: Run.cpp:316
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:67
Parallel::StorageMode storageMode() const
Returns the storage mode (used for MPI runs)
Definition: Workspace.cpp:82
virtual void setTitle(const std::string &)
Set the title of the workspace.
Definition: Workspace.cpp:28
void setStorageMode(Parallel::StorageMode mode)
Sets the storage mode (used for MPI runs)
Definition: Workspace.cpp:85
virtual const std::string getTitle() const
Get the workspace title.
Definition: Workspace.cpp:46
GeneralFrame : Any MDFrame that isn't related to momemtum transfer.
Definition: GeneralFrame.h:21
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...
Definition: IMDDimension.h:39
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
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
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.
Types::Core::DateAndTime firstTime() const
Returns the first time regardless of filter.
Types::Core::DateAndTime lastTime() const
Returns the last time.
Types::Core::DateAndTime nthTime(int n) const
Returns n-th time. NOTE: Complexity is order(n)! regardless of filter.
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:241
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:161
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:341
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.
Definition: SpectrumInfo.h:21
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
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:16
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
Holds X, Y, E for a line plot.
Definition: IMDWorkspace.h:48