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 "MantidIndexing/DllConfig.h"
10#include <algorithm>
11#include <boost/any.hpp>
12#include <cstdint>
13#include <nexus/NeXusFile.hpp>
14#include <numeric>
15#include <string>
16#include <utility>
17
18namespace Mantid {
19namespace NeXus {
20namespace NeXusIOHelper {
21
24
25namespace {
26
28#define RUN_NEXUSIOHELPER_FUNCTION(Narrow, type, func_name, ...) \
29 switch (type) { \
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__); \
34 case ::NeXus::INT8: \
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__); \
50 default: \
51 throw std::runtime_error("NeXusIOHelper: Unknown type in Nexus file"); \
52 }
53
54int64_t vectorVolume(const std::vector<int64_t> &size) {
55 return std::accumulate(size.begin(), size.end(), int64_t{1}, std::multiplies<>());
56}
57
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()) {
62 file.openData(entry);
63 info_and_close.second = true;
64 }
65 info_and_close.first = file.getInfo();
66 return info_and_close;
67}
68
71template <typename T> void callGetData(::NeXus::File &file, std::vector<T> &buf, const bool close_file) {
72 file.getData(buf);
73 if (close_file)
74 file.closeData();
75}
76
78template <typename T> void callGetData(::NeXus::File &file, T &buf, const bool close_file) {
79 file.getData(&buf);
80 if (close_file)
81 file.closeData();
82}
83
85template <typename T>
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);
89 if (close_file)
90 file.closeData();
91}
92
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>) {
99 if (close_file)
100 file.closeData();
101 throw std::runtime_error("Narrowing is forbidden in NeXusIOHelper::readNexusAnyVector");
102 } else if constexpr (std::is_same_v<T, U>) {
103 if (size > 0)
104 callGetData(file, out, close_file);
105 } else {
106 if (size > 0) {
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); });
110 }
111 }
112}
113
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);
119 return vec;
120}
121
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);
128}
129
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>) {
137 if (close_file)
138 file.closeData();
139 throw std::runtime_error("Narrowing is forbidden in NeXusIOHelper::readNexusAnySlab");
140 } else if constexpr (std::is_same_v<T, U>) {
141 if (volume > 0)
142 callGetSlab(file, out, start, size, close_file);
143 } else {
144 if (volume > 0) {
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); });
148 }
149 }
150}
151
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);
159 return vec;
160}
161
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);
170}
171
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>) {
177 if (close_file)
178 file.closeData();
179 throw std::runtime_error("Narrowing is forbidden in NeXusIOHelper::readAnyVariable");
180 } else if constexpr (std::is_same_v<T, U>) {
181 T buf;
182 callGetData(file, buf, close_file);
183 return buf;
184 } else {
185 U buf;
186 callGetData(file, buf, close_file);
187 return static_cast<T>(buf);
188 }
189}
190
191} // end of anonymous namespace
192
197template <typename T, typename Narrow = PreventNarrowing>
198std::vector<T> readNexusVector(::NeXus::File &file, const std::string &entry = "") {
199 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
200 RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnyVector, file,
201 vectorVolume((info_and_close.first).dims), info_and_close.second);
202}
203
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)));
211 RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnyVector, out, file,
212 vectorVolume((info_and_close.first).dims), info_and_close.second);
213}
214
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)));
222 RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnySlab, file, start, size,
223 info_and_close.second);
224}
225
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)));
234 RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnySlab, out, file, start, size,
235 info_and_close.second);
236}
237
238template <typename T, typename Narrow = PreventNarrowing>
239T readNexusValue(::NeXus::File &file, const std::string &entry = "") {
240 const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
241 RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnyVariable, file, info_and_close.second);
242}
243
244} // namespace NeXusIOHelper
245} // namespace NeXus
246} // namespace Mantid
#define RUN_NEXUSIOHELPER_FUNCTION(Narrow, type, func_name,...)
Macro to run a function depending on the type of data in the Nexus file.
Definition: NexusIOHelper.h:28
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.