Mantid
Loading...
Searching...
No Matches
NexusIOHelper.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2007 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#pragma once
8
9#include "MantidNexus/NexusFile.h"
10
11#include <algorithm>
12#include <boost/any.hpp>
13#include <cstdint>
14#include <numeric>
15#include <string>
16#include <utility>
17
19
20enum class Narrowing : bool { Allow = true, Prevent = false };
21
22namespace {
23
25#define RUN_NEXUSIOHELPER_FUNCTION(narrow, type, func_name, ...) \
26 switch (type) { \
27 case NXnumtype::FLOAT32: \
28 return func_name<T, float, narrow>(__VA_ARGS__); \
29 case NXnumtype::FLOAT64: \
30 return func_name<T, double, narrow>(__VA_ARGS__); \
31 case NXnumtype::INT8: \
32 return func_name<T, int8_t, narrow>(__VA_ARGS__); \
33 case NXnumtype::UINT8: \
34 return func_name<T, uint8_t, narrow>(__VA_ARGS__); \
35 case NXnumtype::INT16: \
36 return func_name<T, int16_t, narrow>(__VA_ARGS__); \
37 case NXnumtype::UINT16: \
38 return func_name<T, uint16_t, narrow>(__VA_ARGS__); \
39 case NXnumtype::INT32: \
40 return func_name<T, int32_t, narrow>(__VA_ARGS__); \
41 case NXnumtype::UINT32: \
42 return func_name<T, uint32_t, narrow>(__VA_ARGS__); \
43 case NXnumtype::INT64: \
44 return func_name<T, int64_t, narrow>(__VA_ARGS__); \
45 case NXnumtype::UINT64: \
46 return func_name<T, uint64_t, narrow>(__VA_ARGS__); \
47 default: \
48 std::string msg = "NexusIOHelper: Unknown type " + std::to_string((int)type) + " in Nexus file"; \
49 throw std::runtime_error(msg); \
50 }
51
52int64_t vectorVolume(const Nexus::DimVector &size) {
53 return std::accumulate(size.cbegin(), size.cend(), int64_t{1}, std::multiplies<>());
54}
55
56std::pair<Nexus::Info, bool> checkIfOpenAndGetInfo(Nexus::File &file, const std::string &&entry) {
57 std::pair<Nexus::Info, bool> info_and_close;
58 info_and_close.second = false;
59 if (!file.isDataSetOpen()) {
60 file.openData(entry);
61 info_and_close.second = true;
62 }
63 info_and_close.first = file.getInfo();
64 return info_and_close;
65}
66
70template <typename T, typename U, Narrowing narrow>
71void doReadNexusAnyVector(std::vector<T> &out, Nexus::File &file, const size_t size, const bool close_data) {
72 if constexpr (sizeof(T) < sizeof(U) && narrow == Narrowing::Prevent) {
73 if (close_data)
74 file.closeData();
75 throw std::runtime_error("Narrowing is forbidden in NexusIOHelper::readNexusAnyVector");
76 } else if constexpr (std::is_same_v<T, U>) {
77 if (size > 0) {
78 file.getData(out);
79 }
80 } else {
81 if (size > 0) {
82 std::vector<U> buf(size);
83 file.getData(buf);
84 std::transform(buf.cbegin(), buf.cend(), out.begin(), [](U a) -> T { return static_cast<T>(a); });
85 }
86 }
87 if (close_data) {
88 file.closeData();
89 }
90}
91
93template <typename T, typename U, Narrowing narrow>
94std::vector<T> readNexusAnyVector(Nexus::File &file, const size_t size, const bool close_data) {
95 std::vector<T> vec(size);
96 doReadNexusAnyVector<T, U, narrow>(vec, file, size, close_data);
97 return vec;
98}
99
101template <typename T, typename U, Narrowing narrow>
102void readNexusAnyVector(std::vector<T> &out, Nexus::File &file, const size_t size, const bool close_data) {
103 if (out.size() < size)
104 throw std::runtime_error("The output buffer is too small in NexusIOHelper::readNexusAnyVector");
105 doReadNexusAnyVector<T, U, narrow>(out, file, size, close_data);
106}
107
111template <typename T, typename U, Narrowing narrow>
112void doReadNexusAnySlab(std::vector<T> &out, Nexus::File &file, const Nexus::DimVector &start,
113 const Nexus::DimVector &size, const int64_t volume, const bool close_data) {
114 if constexpr (sizeof(T) < sizeof(U) && narrow == Narrowing::Prevent) {
115 if (close_data)
116 file.closeData();
117 throw std::runtime_error("Narrowing is forbidden in NexusIOHelper::readNexusAnySlab");
118 } else if constexpr (std::is_same_v<T, U>) {
119 if (volume > 0) {
120 file.getSlab(out.data(), start, size);
121 }
122 } else {
123 if (volume > 0) {
124 std::vector<U> buf(volume);
125 file.getSlab(buf.data(), start, size);
126 std::transform(buf.cbegin(), buf.cend(), out.begin(), [](U a) -> T { return static_cast<T>(a); });
127 }
128 }
129 if (volume > 0 && close_data) {
130 file.closeData();
131 }
132}
133
135template <typename T, typename U, Narrowing narrow>
136std::vector<T> readNexusAnySlab(Nexus::File &file, const Nexus::DimVector &start, const Nexus::DimVector &size,
137 const bool close_data) {
138 const auto volume = vectorVolume(size);
139 std::vector<T> vec(volume);
140 doReadNexusAnySlab<T, U, narrow>(vec, file, start, size, volume, close_data);
141 return vec;
142}
143
145template <typename T, typename U, Narrowing narrow>
146void readNexusAnySlab(std::vector<T> &out, Nexus::File &file, const Nexus::DimVector &start,
147 const Nexus::DimVector &size, const bool close_data) {
148 const auto volume = vectorVolume(size);
149 if (out.size() < static_cast<size_t>(volume))
150 throw std::runtime_error("The output buffer is too small in NexusIOHelper::readNexusAnySlab");
151 doReadNexusAnySlab<T, U, narrow>(out, file, start, size, volume, close_data);
152}
153
157template <typename T, typename U, Narrowing narrow> T readNexusAnyVariable(Nexus::File &file, const bool close_data) {
158 T buf;
159 if constexpr (sizeof(T) < sizeof(U) && narrow == Narrowing::Prevent) {
160 if (close_data)
161 file.closeData();
162 throw std::runtime_error("Narrowing is forbidden in NexusIOHelper::readAnyVariable");
163 } else if constexpr (std::is_same_v<T, U>) {
164 file.getData(&buf);
165 } else {
166 U bufu;
167 file.getData<U>(&bufu);
168 buf = std::move(static_cast<T>(bufu));
169 }
170 if (close_data) {
171 file.closeData();
172 }
173 return buf;
174}
175
176} // end of anonymous namespace
177
182template <typename T, Narrowing narrow = Narrowing::Prevent>
183std::vector<T> readNexusVector(Nexus::File &file, const std::string &entry = "") {
184 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
185 RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnyVector, file,
186 vectorVolume((info_and_close.first).dims), info_and_close.second);
187}
188
193template <typename T, Narrowing narrow = Narrowing::Prevent>
194void readNexusVector(std::vector<T> &out, Nexus::File &file, const std::string &entry = "") {
195 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
196 RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnyVector, out, file,
197 vectorVolume((info_and_close.first).dims), info_and_close.second);
198}
199
203template <typename T, Narrowing narrow = Narrowing::Prevent>
204std::vector<T> readNexusSlab(Nexus::File &file, const std::string &entry, DimVector const &start,
205 DimVector const &size) {
206 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
207 RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnySlab, file, start, size,
208 info_and_close.second);
209}
210
215template <typename T, Narrowing narrow = Narrowing::Prevent>
216void readNexusSlab(std::vector<T> &out, Nexus::File &file, const std::string &entry, DimVector const &start,
217 DimVector const &size) {
218 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
219 RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnySlab, out, file, start, size,
220 info_and_close.second);
221}
222
223template <typename T, Narrowing narrow = Narrowing::Prevent>
224T readNexusValue(Nexus::File &file, const std::string &entry = "") {
225 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
226 RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnyVariable, file, info_and_close.second);
227}
228
229} // namespace Mantid::Nexus::IOHelper
#define RUN_NEXUSIOHELPER_FUNCTION(narrow, type, func_name,...)
Macro to run a function depending on the type of data in the Nexus file.
std::vector< T > const * vec
std::vector< T > readNexusSlab(Nexus::File &file, const std::string &entry, DimVector const &start, DimVector const &size)
Opens the data group if needed, finds the data type, and calls readNexusAnySlab via the RUN_NEXUSIOHE...
std::vector< T > readNexusVector(Nexus::File &file, const std::string &entry="")
Opens the data group if needed, finds the data type, computes the data size, and calls readNexusAnyVe...
T readNexusValue(Nexus::File &file, const std::string &entry="")
std::vector< dimsize_t > DimVector