Mantid
Loading...
Searching...
No Matches
NexusLoader.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2025 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
10#include <ranges>
11
13
15
16NexusLoader::NexusLoader(const bool is_time_filtered, const std::vector<PulseROI> &pulse_indices,
17 const std::vector<std::pair<int, PulseROI>> &target_to_pulse_indices)
18 : m_is_time_filtered(is_time_filtered), m_pulse_indices(pulse_indices),
19 m_target_to_pulse_indices(target_to_pulse_indices) {}
20
21void NexusLoader::loadData(H5::DataSet &SDS, std::unique_ptr<std::vector<uint32_t>> &data,
22 const std::vector<size_t> &offsets, const std::vector<size_t> &slabsizes) {
23 loadDataInternal(SDS, data, offsets, slabsizes);
24}
25
26void NexusLoader::loadData(H5::DataSet &SDS, std::unique_ptr<std::vector<float>> &data,
27 const std::vector<size_t> &offsets, const std::vector<size_t> &slabsizes) {
28 loadDataInternal(SDS, data, offsets, slabsizes);
29}
30
31template <typename Type>
32void NexusLoader::loadDataInternal(H5::DataSet &SDS, std::unique_ptr<std::vector<Type>> &data,
33 const std::vector<size_t> &offsets, const std::vector<size_t> &slabsizes) const {
34 // assumes that data is the same type as the dataset
35 H5::DataSpace filespace = SDS.getSpace();
36
37 const auto length_actual = static_cast<size_t>(filespace.getSelectNpoints());
38
39 const hsize_t rankedoffset[1] = {static_cast<hsize_t>(offsets[0])};
40 const hsize_t rankedextent[1] = {static_cast<hsize_t>(slabsizes[0])};
41
42 size_t total_size = slabsizes[0];
43
44 // only select hyperslab if not loading all the data
45 if (rankedextent[0] < length_actual) {
46 // set the first hyperslab with H5S_SELECT_SET
47 filespace.selectHyperslab(H5S_SELECT_SET, rankedextent, rankedoffset);
48
49 // If more slabs, select them with H5S_SELECT_OR to include in the read.
50 // This allows reading non-contiguous data.
51 for (size_t i = 1; i < offsets.size(); ++i) {
52 const hsize_t offset[1] = {static_cast<hsize_t>(offsets[i])};
53 const hsize_t extent[1] = {static_cast<hsize_t>(slabsizes[i])};
54 filespace.selectHyperslab(H5S_SELECT_OR, extent, offset);
55 total_size += slabsizes[i];
56 }
57 }
58
59 // create a memory space for the data to read into, total size is all the slabs combined
60 const hsize_t total_rankedextent[1] = {static_cast<hsize_t>(total_size)};
61 H5::DataSpace memspace(1, total_rankedextent);
62
63 // do the actual read
64 const H5::DataType dataType = SDS.getDataType();
65
66 std::size_t dataSize = filespace.getSelectNpoints();
67 data->resize(dataSize);
68 SDS.read(data->data(), dataType, memspace, filespace);
69}
70
71std::stack<EventROI> NexusLoader::getEventIndexRanges(H5::Group &event_group, const uint64_t number_events,
72 std::unique_ptr<std::vector<uint64_t>> *event_index_out) const {
73 // This will return a stack of pairs, where each pair is the start and stop index of the event ranges
74 std::stack<EventROI> ranges;
76 // TODO this should be made smarter to only read the necessary range
77 std::unique_ptr<std::vector<uint64_t>> event_index = std::make_unique<std::vector<uint64_t>>();
78 this->loadEventIndex(event_group, event_index);
79
80 // add backwards so that the first range is on top
81 for (const auto &pair : m_pulse_indices | std::views::reverse) {
82 uint64_t start_event = event_index->at(pair.first);
83 uint64_t stop_event =
84 (pair.second == std::numeric_limits<size_t>::max()) ? number_events : event_index->at(pair.second);
85 if (start_event < stop_event)
86 ranges.emplace(start_event, stop_event);
87 }
88
89 // If caller wants the event_index data, transfer it
90 if (event_index_out) {
91 *event_index_out = std::move(event_index);
92 }
93 } else {
94 constexpr uint64_t START_DEFAULT = 0;
95 ranges.emplace(START_DEFAULT, number_events);
96 }
97 return ranges;
98}
99
100std::stack<std::pair<int, EventROI>> NexusLoader::getEventIndexSplitRanges(H5::Group &event_group,
101 const uint64_t number_events) {
102 // This will return a stack of pairs, where each pair is the start and stop index of the event ranges with a mapping
103 // to target, taking intersection with m_pulse_indices
104 std::stack<std::pair<int, EventROI>> ranges;
105 // TODO this should be made smarter to only read the necessary range
106 std::unique_ptr<std::vector<uint64_t>> event_index = std::make_unique<std::vector<uint64_t>>();
107 this->loadEventIndex(event_group, event_index);
108
109 // add backwards so that the first range is on top
110 for (const auto &pair : m_target_to_pulse_indices | std::views::reverse) {
111 uint64_t start_event = event_index->at(pair.second.first);
112 uint64_t stop_event = (pair.second.second == std::numeric_limits<size_t>::max())
113 ? number_events
114 : event_index->at(pair.second.second);
115 if (start_event < stop_event)
116 ranges.emplace(pair.first, EventROI(start_event, stop_event));
117 }
118
119 return ranges;
120}
121
122void NexusLoader::loadEventIndex(H5::Group &event_group, std::unique_ptr<std::vector<uint64_t>> &data) const {
123 auto event_index_sds = event_group.openDataSet(NxsFieldNames::INDEX_ID);
124 std::vector<size_t> offsets = {0};
125 std::vector<size_t> slabsizes = {static_cast<size_t>(event_index_sds.getSpace().getSelectNpoints())};
126 loadDataInternal(event_index_sds, data, offsets, slabsizes);
127}
128template void NexusLoader::loadDataInternal<uint64_t>(H5::DataSet &SDS, std::unique_ptr<std::vector<uint64_t>> &data,
129 const std::vector<size_t> &offsets,
130 const std::vector<size_t> &slabsizes) const;
131
132} // namespace Mantid::DataHandling::AlignAndFocusPowderSlim
uint64_t hsize_t
void loadDataInternal(H5::DataSet &SDS, std::unique_ptr< std::vector< Type > > &data, const std::vector< size_t > &offsets, const std::vector< size_t > &slabsizes) const
virtual std::stack< EventROI > getEventIndexRanges(H5::Group &event_group, const uint64_t number_events, std::unique_ptr< std::vector< uint64_t > > *event_index=nullptr) const
void loadEventIndex(H5::Group &event_group, std::unique_ptr< std::vector< uint64_t > > &data) const
NexusLoader(const bool is_time_filtered, const std::vector< PulseROI > &pulse_indices, const std::vector< std::pair< int, PulseROI > > &target_to_pulse_indices={})
std::stack< std::pair< int, EventROI > > getEventIndexSplitRanges(H5::Group &event_group, const uint64_t number_events)
std::vector< std::pair< int, PulseROI > > m_target_to_pulse_indices
Definition NexusLoader.h:49
virtual void loadData(H5::DataSet &SDS, std::unique_ptr< std::vector< uint32_t > > &data, const std::vector< size_t > &offsets, const std::vector< size_t > &slabsizes)
std::pair< uint64_t, uint64_t > EventROI
Definition NexusLoader.h:26