Skip to content

Commit 74464d1

Browse files
Fix bug with detector-ids that do not increase in a component
This affects VULCAN from 2021 on when loading a single bank of data. Since the detector ids do not increase with components, there was an implicit assumption that was being violated.
1 parent 0aacae3 commit 74464d1

File tree

2 files changed

+58
-20
lines changed

2 files changed

+58
-20
lines changed

Framework/DataHandling/src/LoadEventNexusIndexSetup.cpp

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,41 @@ namespace Mantid::DataHandling {
2525

2626
namespace {
2727
void 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).
2837
std::vector<Indexing::SpectrumNumber> spectrumNumbers;
29-
// Temporary spectrum number in `filtered` was detector ID, now translate
30-
// to spectrum number, starting at 1. Note that we use detIDs and not
31-
// DetectorInfo for translation since we need to match the unfiltered
32-
// spectrum numbers, which are based on skipping monitors (which would be
33-
// included in DetectorInfo).
34-
for (int32_t i = 0; i < static_cast<int32_t>(detIDs.size()); ++i) {
35-
if (filtered.spectrumNumber(spectrumNumbers.size()) == detIDs[i])
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) {
3644
spectrumNumbers.emplace_back(i + 1);
37-
if (filtered.size() == spectrumNumbers.size())
38-
break;
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());
3961
}
62+
4063
filtered.setSpectrumNumbers(std::move(spectrumNumbers));
4164
}
4265
} // namespace
@@ -48,24 +71,22 @@ LoadEventNexusIndexSetup::LoadEventNexusIndexSetup(MatrixWorkspace_const_sptr in
4871
std::pair<int32_t, int32_t> LoadEventNexusIndexSetup::eventIDLimits() const { return {m_min, m_max}; }
4972

5073
IndexInfo LoadEventNexusIndexSetup::makeIndexInfo() {
51-
// The default 1:1 will suffice but exclude the monitors as they are always in
52-
// a separate workspace
53-
auto detIDs = m_instrumentWorkspace->getInstrument()->getDetectorIDs(true);
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);
5476
const auto &detectorInfo = m_instrumentWorkspace->detectorInfo();
5577
std::vector<SpectrumDefinition> specDefs;
5678
specDefs.reserve(detIDs.size());
5779
std::transform(detIDs.cbegin(), detIDs.cend(), std::back_inserter(specDefs),
5880
[&detectorInfo](const auto detID) { return SpectrumDefinition(detectorInfo.indexOf(detID)); });
59-
// We need to filter based on detector IDs, but use IndexInfo for filtering
60-
// for a unified filtering mechanism. Thus we set detector IDs as (temporary)
61-
// spectrum numbers.
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.
6283
IndexInfo indexInfo(std::vector<SpectrumNumber>(detIDs.begin(), detIDs.end()));
6384
indexInfo.setSpectrumDefinitions(specDefs);
6485

6586
auto filtered = filterIndexInfo(indexInfo);
6687

67-
// Spectrum numbers are continuous and start at 1. If there is a filter,
68-
// spectrum numbers are set up to be consistent with the unfiltered case.
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.
6990
if (filtered.size() == indexInfo.size()) {
7091
filtered.setSpectrumNumbers(1, static_cast<int32_t>(filtered.size()));
7192
} else {
@@ -96,9 +117,8 @@ IndexInfo LoadEventNexusIndexSetup::makeIndexInfo(const std::vector<std::string>
96117
}
97118
if (dets.empty())
98119
throw std::runtime_error("Could not find the bank named '" + bankName +
99-
"' as a component assembly in the instrument "
100-
"tree; or it did not contain any detectors. Try "
101-
"unchecking SingleBankPixelsOnly.");
120+
"' as a component assembly in the instrument tree; or it did not contain any detectors. "
121+
"Try unchecking SingleBankPixelsOnly.");
102122
}
103123
Indexing::IndexInfo indexInfo(std::move(spectrumNumbers));
104124
indexInfo.setSpectrumDefinitions(std::move(spectrumDefinitions));

Framework/DataHandling/test/LoadEventNexusIndexSetupTest.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,24 @@ class LoadEventNexusIndexSetupTest : public CxxTest::TestSuite {
190190
TS_ASSERT_EQUALS(specDefs->at(1), SpectrumDefinition(3));
191191
}
192192

193+
/* compare this test body with test_makeIndexInfo_from_bank. The main difference is that the instrument components are
194+
* specifed backwards. This is consistent with VULCAN IDF */
195+
void test_makeIndexInfo_from_bank_backwards() {
196+
LoadEventNexusIndexSetup indexSetup(m_ws, EMPTY_INT(), EMPTY_INT(), {});
197+
const auto indexInfo = indexSetup.makeIndexInfo({"det-12", "det-2"}); // intentionally backwards
198+
TS_ASSERT_EQUALS(indexSetup.eventIDLimits().first, EMPTY_INT());
199+
TS_ASSERT_EQUALS(indexSetup.eventIDLimits().second, EMPTY_INT());
200+
TS_ASSERT_EQUALS(indexInfo.size(), 2);
201+
// these match the spectrum numbers of the full instrument
202+
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), SpectrumNumber(2));
203+
TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), SpectrumNumber(4));
204+
// this may actually be wrong, but it appears as though the order of the spectrum definitions match the way they
205+
// were requested while the spectrum numbers (just above) are always in increasing order
206+
const auto specDefs = indexInfo.spectrumDefinitions();
207+
TS_ASSERT_EQUALS(specDefs->at(0), SpectrumDefinition(3));
208+
TS_ASSERT_EQUALS(specDefs->at(1), SpectrumDefinition(1));
209+
}
210+
193211
void test_makeIndexInfo_from_bank_filter_ignored() {
194212
LoadEventNexusIndexSetup indexSetup(m_ws, 12, EMPTY_INT(), {1});
195213
// This variant ignores any filter in the index/workspace setup phase,

0 commit comments

Comments
 (0)