9#include "MantidIndexing/DllConfig.h"
11#include <boost/any.hpp>
13#include <nexus/NeXusFile.hpp>
20namespace NeXusIOHelper {
28#define RUN_NEXUSIOHELPER_FUNCTION(Narrow, type, func_name, ...) \
30 case ::NeXus::FLOAT32: \
31 return func_name<T, float, Narrow>(__VA_ARGS__); \
32 case ::NeXus::FLOAT64: \
33 return func_name<T, double, Narrow>(__VA_ARGS__); \
35 return func_name<T, int8_t, Narrow>(__VA_ARGS__); \
36 case ::NeXus::UINT8: \
37 return func_name<T, uint8_t, Narrow>(__VA_ARGS__); \
38 case ::NeXus::INT16: \
39 return func_name<T, int16_t, Narrow>(__VA_ARGS__); \
40 case ::NeXus::UINT16: \
41 return func_name<T, uint16_t, Narrow>(__VA_ARGS__); \
42 case ::NeXus::INT32: \
43 return func_name<T, int32_t, Narrow>(__VA_ARGS__); \
44 case ::NeXus::UINT32: \
45 return func_name<T, uint32_t, Narrow>(__VA_ARGS__); \
46 case ::NeXus::INT64: \
47 return func_name<T, int64_t, Narrow>(__VA_ARGS__); \
48 case ::NeXus::UINT64: \
49 return func_name<T, uint64_t, Narrow>(__VA_ARGS__); \
51 throw std::runtime_error("NeXusIOHelper: Unknown type in Nexus file"); \
54int64_t vectorVolume(
const std::vector<int64_t> &size) {
55 return std::accumulate(size.begin(), size.end(), int64_t{1}, std::multiplies<>());
58std::pair<::NeXus::Info, bool> checkIfOpenAndGetInfo(::NeXus::File &file,
const std::string &&entry) {
59 std::pair<::NeXus::Info, bool> info_and_close;
60 info_and_close.second =
false;
61 if (!file.isDataSetOpen()) {
63 info_and_close.second =
true;
65 info_and_close.first = file.getInfo();
66 return info_and_close;
71template <
typename T>
void callGetData(::NeXus::File &file, std::vector<T> &buf,
const bool close_file) {
78template <
typename T>
void callGetData(::NeXus::File &file, T &buf,
const bool close_file) {
86void callGetSlab(::NeXus::File &file, std::vector<T> &buf,
const std::vector<int64_t> &start,
87 const std::vector<int64_t> &size,
const bool close_file) {
88 file.getSlab(buf.data(), start, size);
96template <
typename T,
typename U,
typename Narrow>
97void doReadNexusAnyVector(std::vector<T> &out, ::NeXus::File &file,
const size_t size,
const bool close_file) {
98 if constexpr (
sizeof(T) <
sizeof(U) && !std::is_same_v<Narrow, AllowNarrowing>) {
101 throw std::runtime_error(
"Narrowing is forbidden in NeXusIOHelper::readNexusAnyVector");
102 }
else if constexpr (std::is_same_v<T, U>) {
104 callGetData(file, out, close_file);
107 std::vector<U> buf(size);
108 callGetData(file, buf, close_file);
109 std::transform(buf.begin(), buf.end(), out.begin(), [](U a) -> T { return static_cast<T>(a); });
115template <
typename T,
typename U,
typename Narrow>
116std::vector<T> readNexusAnyVector(::NeXus::File &file,
const size_t size,
const bool close_file) {
117 std::vector<T> vec(size);
118 doReadNexusAnyVector<T, U, Narrow>(vec, file, size, close_file);
123template <
typename T,
typename U,
typename Narrow>
124void readNexusAnyVector(std::vector<T> &out, ::NeXus::File &file,
const size_t size,
const bool close_file) {
125 if (out.size() < size)
126 throw std::runtime_error(
"The output buffer is too small in NeXusIOHelper::readNexusAnyVector");
127 doReadNexusAnyVector<T, U, Narrow>(out, file, size, close_file);
133template <
typename T,
typename U,
typename Narrow>
134void doReadNexusAnySlab(std::vector<T> &out, ::NeXus::File &file,
const std::vector<int64_t> &start,
135 const std::vector<int64_t> &size,
const int64_t volume,
const bool close_file) {
136 if constexpr (
sizeof(T) <
sizeof(U) && !std::is_same_v<Narrow, AllowNarrowing>) {
139 throw std::runtime_error(
"Narrowing is forbidden in NeXusIOHelper::readNexusAnySlab");
140 }
else if constexpr (std::is_same_v<T, U>) {
142 callGetSlab(file, out, start, size, close_file);
145 std::vector<U> buf(volume);
146 callGetSlab(file, buf, start, size, close_file);
147 std::transform(buf.begin(), buf.end(), out.begin(), [](U a) -> T { return static_cast<T>(a); });
153template <
typename T,
typename U,
typename Narrow>
154std::vector<T> readNexusAnySlab(::NeXus::File &file,
const std::vector<int64_t> &start,
155 const std::vector<int64_t> &size,
const bool close_file) {
156 const auto volume = vectorVolume(size);
157 std::vector<T> vec(volume);
158 doReadNexusAnySlab<T, U, Narrow>(vec, file, start, size, volume, close_file);
163template <
typename T,
typename U,
typename Narrow>
164void readNexusAnySlab(std::vector<T> &out, ::NeXus::File &file,
const std::vector<int64_t> &start,
165 const std::vector<int64_t> &size,
const bool close_file) {
166 const auto volume = vectorVolume(size);
167 if (out.size() <
static_cast<size_t>(volume))
168 throw std::runtime_error(
"The output buffer is too small in NeXusIOHelper::readNexusAnySlab");
169 doReadNexusAnySlab<T, U, Narrow>(out, file, start, size, volume, close_file);
175template <
typename T,
typename U,
typename Narrow> T readNexusAnyVariable(::NeXus::File &file,
const bool close_file) {
176 if constexpr (
sizeof(T) <
sizeof(U) && !std::is_same_v<Narrow, AllowNarrowing>) {
179 throw std::runtime_error(
"Narrowing is forbidden in NeXusIOHelper::readAnyVariable");
180 }
else if constexpr (std::is_same_v<T, U>) {
182 callGetData(file, buf, close_file);
186 callGetData(file, buf, close_file);
187 return static_cast<T
>(buf);
197template <
typename T,
typename Narrow = PreventNarrowing>
199 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
201 vectorVolume((info_and_close.first).dims), info_and_close.second);
208template <
typename T,
typename Narrow = PreventNarrowing>
209void readNexusVector(std::vector<T> &out, ::NeXus::File &file,
const std::string &entry =
"") {
210 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
212 vectorVolume((info_and_close.first).dims), info_and_close.second);
218template <
typename T,
typename Narrow = PreventNarrowing>
219std::vector<T>
readNexusSlab(::NeXus::File &file,
const std::string &entry,
const std::vector<int64_t> &start,
220 const std::vector<int64_t> &size) {
221 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
223 info_and_close.second);
230template <
typename T,
typename Narrow = PreventNarrowing>
231void readNexusSlab(std::vector<T> &out, ::NeXus::File &file,
const std::string &entry,
232 const std::vector<int64_t> &start,
const std::vector<int64_t> &size) {
233 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
235 info_and_close.second);
238template <
typename T,
typename Narrow = PreventNarrowing>
240 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
#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 > readNexusSlab(::NeXus::File &file, const std::string &entry, const std::vector< int64_t > &start, const std::vector< int64_t > &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="")
Helper class which provides the Collimation Length for SANS instruments.