Mantid
Loading...
Searching...
No Matches
LoadEventNexusIndexSetup.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 +
7#include <utility>
8
14#include "MantidIndexing/Extract.h"
15#include "MantidIndexing/SpectrumIndexSet.h"
16#include "MantidIndexing/SpectrumNumber.h"
17#include "MantidTypes/SpectrumDefinition.h"
18
19#include <algorithm>
20
21using namespace Mantid::API;
22using namespace Mantid::Indexing;
23
24namespace Mantid::DataHandling {
25
26namespace {
27void setupConsistentSpectrumNumbers(IndexInfo &filtered, const std::vector<detid_t> &detIDs) {
28 // get the filtered information and sort the ids to make the main loop run faster
29 auto spectrumNumbersFiltered = filtered.spectrumNumbers(); // what it is at the beginning
30 if (!std::is_sorted(spectrumNumbersFiltered.cbegin(), spectrumNumbersFiltered.cend())) {
31 std::sort(spectrumNumbersFiltered.begin(), spectrumNumbersFiltered.end());
32 }
33
34 // Temporary spectrum number in `filtered` was detector ID, now translate to spectrum number, starting at 1. Note that
35 // we use detIDs and not DetectorInfo for translation since we need to match the unfiltered spectrum numbers, which
36 // are based on skipping monitors (which would be included in DetectorInfo).
37 std::vector<Indexing::SpectrumNumber> spectrumNumbers;
38 const auto NUM_DETIDS = static_cast<int32_t>(detIDs.size());
39 auto specFilterIter = spectrumNumbersFiltered.cbegin();
40 auto specFilterIterEnd = spectrumNumbersFiltered.cend();
41 for (int32_t i = 0; i < NUM_DETIDS; ++i) {
42 auto specFilterIterTemp = std::find(specFilterIter, specFilterIterEnd, detIDs[i]);
43 if (specFilterIterTemp != specFilterIterEnd) {
44 spectrumNumbers.emplace_back(i + 1);
45
46 // finish early if everything was found
47 if (filtered.size() == spectrumNumbers.size())
48 break;
49
50 // advance to the element after the one found to start next search
51 specFilterIter = std::next(specFilterIterTemp);
52 }
53 }
54
55 // error check the results
56 if (filtered.size() != spectrumNumbers.size()) {
57 std::stringstream msg;
58 msg << "Not all detectors were found in the instrumen. Requested filtered=" << filtered.size()
59 << " found=" << spectrumNumbers.size();
60 throw std::runtime_error(msg.str());
61 }
62
63 filtered.setSpectrumNumbers(std::move(spectrumNumbers));
64}
65} // namespace
66
68 const int32_t max, std::vector<int32_t> range)
69 : m_instrumentWorkspace(std::move(instrumentWorkspace)), m_min(min), m_max(max), m_range(std::move(range)) {}
70
71std::pair<int32_t, int32_t> LoadEventNexusIndexSetup::eventIDLimits() const { return {m_min, m_max}; }
72
74 // The default 1:1 will suffice but exclude the monitors as they are always in a separate workspace
75 const auto detIDs = m_instrumentWorkspace->getInstrument()->getDetectorIDs(true);
76 const auto &detectorInfo = m_instrumentWorkspace->detectorInfo();
77 std::vector<SpectrumDefinition> specDefs;
78 specDefs.reserve(detIDs.size());
79 std::transform(detIDs.cbegin(), detIDs.cend(), std::back_inserter(specDefs),
80 [&detectorInfo](const auto detID) { return SpectrumDefinition(detectorInfo.indexOf(detID)); });
81 // We need to filter based on detector IDs, but use IndexInfo for filtering for a unified filtering mechanism. Thus we
82 // set detector IDs as (temporary) spectrum numbers.
83 IndexInfo indexInfo(std::vector<SpectrumNumber>(detIDs.begin(), detIDs.end()));
84 indexInfo.setSpectrumDefinitions(specDefs);
85
86 auto filtered = filterIndexInfo(indexInfo);
87
88 // Spectrum numbers are continuous and start at 1. If there is a filter, spectrum numbers are set up to be consistent
89 // with the unfiltered case.
90 if (filtered.size() == indexInfo.size()) {
91 filtered.setSpectrumNumbers(1, static_cast<int32_t>(filtered.size()));
92 } else {
93 setupConsistentSpectrumNumbers(filtered, detIDs);
94 }
95
96 return filtered;
97}
98
99IndexInfo LoadEventNexusIndexSetup::makeIndexInfo(const std::vector<std::string> &bankNames) {
100 const auto &componentInfo = m_instrumentWorkspace->componentInfo();
101 const auto &detectorInfo = m_instrumentWorkspace->detectorInfo();
102 std::vector<SpectrumDefinition> spectrumDefinitions;
103 // Temporary spectrum numbers setup up to be detector IDs, used for finding
104 // correct spectrum number to be consistent with unfiltered case.
105 std::vector<SpectrumNumber> spectrumNumbers;
106 const auto &instrument = m_instrumentWorkspace->getInstrument();
107 for (const auto &bankName : bankNames) {
108 const auto &bank = instrument->getComponentByName(bankName);
109 std::vector<size_t> dets;
110 if (bank) {
111 const auto bankIndex = componentInfo.indexOf(bank->getComponentID());
112 dets = componentInfo.detectorsInSubtree(bankIndex);
113 for (const auto detIndex : dets) {
114 spectrumDefinitions.emplace_back(detIndex);
115 spectrumNumbers.emplace_back(detectorInfo.detectorIDs()[detIndex]);
116 }
117 }
118 if (dets.empty())
119 throw std::runtime_error("Could not find the bank named '" + bankName +
120 "' as a component assembly in the instrument tree; or it did not contain any detectors. "
121 "Try unchecking SingleBankPixelsOnly.");
122 }
123 Indexing::IndexInfo indexInfo(std::move(spectrumNumbers));
124 indexInfo.setSpectrumDefinitions(std::move(spectrumDefinitions));
125 setupConsistentSpectrumNumbers(indexInfo, instrument->getDetectorIDs(true));
126 // Filters are ignored when selecting bank names. Reset min/max to avoid
127 // unintended dropping of events in the loader.
128 m_min = EMPTY_INT();
129 m_max = EMPTY_INT();
130 return indexInfo;
131}
132
134 const std::pair<std::vector<int32_t>, std::vector<int32_t>> &spectrumDetectorMapping, const bool monitorsOnly) {
135 const auto &spec = spectrumDetectorMapping.first;
136 const auto &udet = spectrumDetectorMapping.second;
137
138 const std::vector<detid_t> monitors = m_instrumentWorkspace->getInstrument()->getMonitors();
139 const auto &detectorInfo = m_instrumentWorkspace->detectorInfo();
140 if (monitorsOnly) {
141 std::vector<Indexing::SpectrumNumber> spectrumNumbers;
142 std::vector<SpectrumDefinition> spectrumDefinitions;
143 // Find the det_ids in the udet array.
144 for (const auto id : monitors) {
145 // Find the index in the udet array
146 auto it = std::find(udet.begin(), udet.end(), id);
147 if (it != udet.end()) {
148 const specnum_t &specNo = spec[it - udet.begin()];
149 spectrumNumbers.emplace_back(specNo);
150 spectrumDefinitions.emplace_back(detectorInfo.indexOf(id));
151 }
152 }
153 Indexing::IndexInfo indexInfo(spectrumNumbers);
154 indexInfo.setSpectrumDefinitions(std::move(spectrumDefinitions));
155 return indexInfo;
156 } else {
157 SpectrumDetectorMapping mapping(spec, udet, monitors);
158 auto uniqueSpectra = mapping.getSpectrumNumbers();
159 std::vector<SpectrumDefinition> spectrumDefinitions;
160 for (const auto specNo : uniqueSpectra) {
161 spectrumDefinitions.emplace_back();
162 for (const auto detID : mapping.getDetectorIDsForSpectrumNo(specNo)) {
163 try {
164 spectrumDefinitions.back().add(detectorInfo.indexOf(detID));
165 } catch (std::out_of_range &) {
166 // Discarding detector IDs that do not exist in the instrument.
167 }
168 }
169 }
170 Indexing::IndexInfo indexInfo(std::vector<Indexing::SpectrumNumber>(uniqueSpectra.begin(), uniqueSpectra.end()));
171 indexInfo.setSpectrumDefinitions(std::move(spectrumDefinitions));
172 return filterIndexInfo(indexInfo);
173 }
174}
175
181IndexInfo LoadEventNexusIndexSetup::filterIndexInfo(const IndexInfo &indexInfo) {
182 // Check if range [SpectrumMin, SpectrumMax] was supplied
183 if (m_min != EMPTY_INT() || m_max != EMPTY_INT()) {
184 if (m_max == EMPTY_INT())
185 m_max = static_cast<int32_t>(indexInfo.spectrumNumber(indexInfo.size() - 1));
186 if (m_min == EMPTY_INT())
187 m_min = static_cast<int32_t>(indexInfo.spectrumNumber(0));
188 // Avoid adding non-existing indices (can happen if instrument has gaps in
189 // its detector IDs). IndexInfo does the filtering for use.
190 const auto indices = indexInfo.makeIndexSet(static_cast<SpectrumNumber>(m_min), static_cast<SpectrumNumber>(m_max));
191 std::transform(indices.begin(), indices.end(), std::back_inserter(m_range),
192 [indexInfo](const auto index) { return static_cast<int32_t>(indexInfo.spectrumNumber(index)); });
193 }
194 // Check if SpectrumList was supplied (or filled via min/max above)
195 if (!m_range.empty()) {
196 std::sort(m_range.begin(), m_range.end());
197 const auto indices = indexInfo.makeIndexSet(std::vector<SpectrumNumber>(m_range.begin(), m_range.end()));
198 m_min = static_cast<int32_t>(indexInfo.spectrumNumber(*indices.begin()));
199 m_max = static_cast<int32_t>(indexInfo.spectrumNumber(*(indices.end() - 1)));
200 return extract(indexInfo, indices);
201 }
202 return indexInfo;
203}
204
205} // namespace Mantid::DataHandling
std::map< DeltaEMode::Type, std::string > index
specnum_t m_min
specnum_t m_max
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
std::set< specnum_t > getSpectrumNumbers() const
const API::MatrixWorkspace_const_sptr m_instrumentWorkspace
Indexing::IndexInfo filterIndexInfo(const Indexing::IndexInfo &indexInfo)
Filter IndexInfo based on optional spectrum range/list provided.
LoadEventNexusIndexSetup(API::MatrixWorkspace_const_sptr instrumentWorkspace, const int32_t min, const int32_t max, std::vector< int32_t > range)
std::pair< int32_t, int32_t > eventIDLimits() const
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
STL namespace.