diff --git a/Framework/DataHandling/src/ParallelEventLoader.cpp b/Framework/DataHandling/src/ParallelEventLoader.cpp index 0b178aaa5539fca1b4c4d415bf088370a3b0ca3b..88dfd283cd528e95fa1380aba14518d9aef506db 100644 --- a/Framework/DataHandling/src/ParallelEventLoader.cpp +++ b/Framework/DataHandling/src/ParallelEventLoader.cpp @@ -1,61 +1,44 @@ #include "MantidDataHandling/ParallelEventLoader.h" #include "MantidDataObjects/EventWorkspace.h" -#include "MantidGeometry/Instrument.h" -#include "MantidGeometry/Instrument/ComponentInfo.h" #include "MantidGeometry/Instrument/DetectorInfo.h" #include "MantidParallel/IO/EventLoader.h" +#include "MantidTypes/SpectrumDefinition.h" #include "MantidTypes/Event/TofEvent.h" namespace Mantid { namespace DataHandling { std::vector<int32_t> bankOffsets(const API::ExperimentInfo &ws, + const std::string &filename, + const std::string &groupName, const std::vector<std::string> &bankNames) { - const auto instrument = ws.getInstrument(); - const auto &compInfo = ws.componentInfo(); + // Build detector ID to spectrum index map. Used only in LoadEventNexus so we + // know there is a 1:1 mapping, omitting monitors. const auto &detInfo = ws.detectorInfo(); const auto &detIDs = detInfo.detectorIDs(); + std::unordered_map<detid_t, int32_t> map; + int32_t spectrumIndex{0}; // *global* index + for (size_t i = 0; i < detInfo.size(); ++i) + if (!detInfo.isMonitor(i)) + map[detIDs[i]] = spectrumIndex++; - // Monitors are not loaded by LoadEventNexus, so we have to exclude them when - // computing an offset based on detector IDs. Currently this is computed in a - // naive way and works only if all monitors have IDs smaller than any - // detector. - int32_t monitorOffset{0}; - bool sawDetector{false}; - for (size_t i = 0; i < detInfo.size(); ++i) { - if (detInfo.isMonitor(i)) { - if (sawDetector) - throw std::runtime_error("Monitors are not corresponding to the first " - "detector IDs in the instrument. This is " - "currently not supported by " - "ParallelEventLoader"); - ++monitorOffset; - } else { - sawDetector = true; - } - } - + // Load any event ID and determine offset from it. This is always a detector + // ID since the parallel loader is disabled otherwise. It is assumed that + // detector IDs within a bank are contiguous. std::vector<int32_t> bankOffsets; - for (const auto &bankName : bankNames) { - // Removing "_events" from bankName - auto bank = - instrument->getComponentByName(bankName.substr(0, bankName.size() - 7)); - if (bank) { - const auto &detectors = - compInfo.detectorsInSubtree(compInfo.indexOf(bank->getComponentID())); - const size_t detIndex = detectors.front(); - bankOffsets.push_back(detIDs[detIndex] - static_cast<int32_t>(detIndex) + - monitorOffset); - if ((detIDs[detectors.back()] - detIDs[detectors.front()]) != - static_cast<int32_t>(detectors.size()) - 1) - throw std::runtime_error("Detector ID range in bank is not contiguous. " - "Cannot use ParallelEventLoader."); - } else { - throw std::runtime_error( - "ParallelEventLoader: Bank " + bankName + - " not found. Cannot determine detector ID offset."); - } + for (const auto &eventId : Parallel::IO::EventLoader::anyEventIdFromBanks( + filename, groupName, bankNames)) { + // The offset is the difference between the event ID and the spectrum index + // and can then be used to translate from the former to the latter by simple + // subtraction. + // If no eventId could be read for a bank it implies that there are no + // events, so any offset will do since it is unused. Set to 0. + if (eventId) + bankOffsets.emplace_back(*eventId - map.at(*eventId)); + else + bankOffsets.emplace_back(0); } + return bankOffsets; } @@ -68,9 +51,9 @@ void ParallelEventLoader::load(DataObjects::EventWorkspace &ws, for (size_t i = 0; i < size; ++i) DataObjects::getEventsFrom(ws.getSpectrum(i), eventLists[i]); - Parallel::IO::EventLoader::load(filename, groupName, bankNames, - bankOffsets(ws, bankNames), - std::move(eventLists)); + Parallel::IO::EventLoader::load( + filename, groupName, bankNames, + bankOffsets(ws, filename, groupName, bankNames), std::move(eventLists)); } } // namespace DataHandling diff --git a/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h b/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h index b7089fcef38a52fc9f1999ca100deebbbdfeec27..aea1261e50015f43416bf8f00a4c919f8da9e5b2 100644 --- a/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h +++ b/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h @@ -5,6 +5,8 @@ #include <string> #include <vector> +#include <boost/optional.hpp> + #include "MantidParallel/DllConfig.h" namespace Mantid { @@ -44,6 +46,9 @@ namespace IO { Code Documentation is available at: <http://doxygen.mantidproject.org> */ namespace EventLoader { +MANTID_PARALLEL_DLL std::vector<boost::optional<int32_t>> +anyEventIdFromBanks(const std::string &filename, const std::string &groupName, + const std::vector<std::string> &bankNames); MANTID_PARALLEL_DLL void load(const std::string &filename, const std::string &groupName, const std::vector<std::string> &bankNames, diff --git a/Framework/Parallel/src/IO/EventLoader.cpp b/Framework/Parallel/src/IO/EventLoader.cpp index cad71a49b21c12fad0cf5dfd0eb03d69aafbb48e..19e6d3c851d3af08b60dfe2dca7763853773c55a 100644 --- a/Framework/Parallel/src/IO/EventLoader.cpp +++ b/Framework/Parallel/src/IO/EventLoader.cpp @@ -1,5 +1,6 @@ #include "MantidParallel/IO/EventLoader.h" #include "MantidParallel/IO/EventLoaderHelpers.h" +#include "MantidParallel/IO/NXEventDataLoader.h" #include <H5Cpp.h> @@ -8,6 +9,24 @@ namespace Parallel { namespace IO { namespace EventLoader { +std::vector<boost::optional<int32_t>> +anyEventIdFromBanks(const std::string &filename, const std::string &groupName, + const std::vector<std::string> &bankNames) { + std::vector<boost::optional<int32_t>> eventIds(bankNames.size()); + H5::H5File file(filename, H5F_ACC_RDONLY); + H5::Group group = file.openGroup(groupName); + for (size_t i = 0; i < bankNames.size(); ++i) { + try { + int32_t eventId; + detail::read<int32_t>(&eventId, group, bankNames[i] + "/event_id", 0, 1); + eventIds[i] = eventId; + } catch (const std::out_of_range &) { + // No event in file, keep eventIds uninitialized for this bank. + } + } + return eventIds; +} + void load(const std::string &filename, const std::string &groupName, const std::vector<std::string> &bankNames, const std::vector<int32_t> &bankOffsets,