Mantid
Loading...
Searching...
No Matches
NexusClasses.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/DllConfig.h"
10#include "MantidNexus/NexusFile.h"
11
12#include <algorithm>
13#include <array>
14#include <boost/container/vector.hpp>
15#include <iostream>
16#include <map>
17#include <memory>
18#include <numeric>
19#include <sstream>
20#include <string>
21#include <vector>
22
23namespace Mantid {
24namespace Nexus {
25
32typedef std::array<dimsize_t, 4> NXDimArray;
33
37struct NXInfo {
38 NXInfo() : nxname(), rank(0), dims(), type(NXnumtype::BAD), allGood(false) {}
39 NXInfo(Info const &info, std::string const &name);
40 std::string nxname;
41 std::size_t rank;
44 bool allGood;
45 operator bool() { return allGood; }
46};
47
50 NXClassInfo(Entry e) : nxname(e.first), nxclass(e.second), datatype(NXnumtype::BAD), allGood(true) {}
52 std::string nxname;
53 std::string nxclass;
55 bool allGood;
56 operator bool() { return allGood; }
57};
58
59/*
60 * LoadNexusProcessed and SaveNexusProcessed need to share some attributes, put them at namespace level here
61 */
62
65
69class MANTID_NEXUS_DLL NXAttributes {
70public:
71 std::size_t n() const { return m_values.size(); }
72 std::vector<std::string> names() const;
73 std::vector<std::string> values() const;
74 std::string operator()(const std::string &name) const;
75 void set(const std::string &name, const std::string &value);
76 template <typename T> void set(const std::string &name, T value);
77private:
78 std::map<std::string, std::string> m_values;
79};
80
81// Forward declaration
82class NXClass;
83
88class MANTID_NEXUS_DLL NXObject {
89 friend class NXDataSet;
90 friend class NXClass;
91 friend class NXRoot;
92public:
93 // Constructor
94 NXObject(File *fileID, NXClass const *parent, std::string const &name);
95 NXObject(std::shared_ptr<File> const &fileID, NXClass const *parent, std::string const &name);
96 virtual ~NXObject() = default;
98 virtual std::string NX_class() const = 0;
99 // True if complies with our understanding of the www.nexusformat.org
100 // definition.
101 // virtual bool isStandard()const = 0;
103 NexusAddress const &address() const { return m_address; }
105 std::string name() const;
107 std::shared_ptr<File> m_fileID;
108
109protected:
111 bool m_open;
112private:
113 NXObject();
114};
115
128class MANTID_NEXUS_DLL NXDataSet : public NXObject {
129public:
130 // Constructor
131 NXDataSet(NXClass const &parent, std::string const &name);
133 std::string NX_class() const override { return "SDS"; }
135 void open();
137 void openLocal();
139 std::size_t rank() const { return m_info.rank; }
141 dimsize_t dims(std::size_t i) const { return i < 4 ? m_info.dims[i] : 0; }
143 dimsize_t dim0() const;
145 dimsize_t dim1() const;
147 dimsize_t dim2() const;
149 dimsize_t dim3() const;
151 std::string name() const { return m_info.nxname; } // cppcheck-suppress returnByReference
153 NXnumtype type() const { return m_info.type; }
156
157protected:
164 template <typename NumT> void getData(NumT *data) {
165 m_fileID->openData(name());
166 m_fileID->getData(data);
167 m_fileID->closeData();
168 }
169
180 template <typename NumT> void getSlab(NumT *data, DimVector const &start, DimVector const &size) {
181 m_fileID->openData(name());
182 m_fileID->getSlab(data, start, size);
183 m_fileID->closeData();
184 }
185
187
188private:
189 void getAttributes();
190};
191
192template <typename T>
193using container_T = std::conditional_t<std::is_same<T, bool>{}, boost::container::vector<bool>, std::vector<T>>;
194
198template <class T> class NXDataSetTyped : public NXDataSet {
199
200public:
207 NXDataSetTyped(NXClass const &parent, std::string const &name) : NXDataSet(parent, name), m_size(0UL) {}
214 const T *operator()() const {
215 if (m_data.empty())
216 throw std::runtime_error("Attempt to read uninitialized data from " + address());
217 return m_data.data();
218 }
219
221 if (m_data.empty())
222 throw std::runtime_error("Attempt to read uninitialized data from " + address());
223 return m_data.data();
224 }
225
234 const T &operator[](std::size_t i) const {
235 if (m_data.empty())
236 throw std::runtime_error("Attempt to read uninitialized data from " + address());
237 if (i >= m_size)
238 rangeError();
239 return m_data[i];
240 }
241
242 T &operator[](std::size_t i) { return const_cast<T &>(static_cast<const NXDataSetTyped &>(*this)[i]); }
252 const T &operator()(std::size_t i, std::size_t j) const { return this->operator[](i * dim1() + j); }
253 T &operator()(std::size_t i, std::size_t j) {
254 return const_cast<T &>(static_cast<const NXDataSetTyped &>(*this)(i, j));
255 }
265 const T &operator()(std::size_t i, std::size_t j, std::size_t k) const {
266 return this->operator[]((i * dim1() + j) * dim2() + k);
267 }
268 T &operator()(std::size_t i, std::size_t j, std::size_t k) {
269 return const_cast<T &>(static_cast<const NXDataSetTyped &>(*this)(i, j, k));
270 }
271
275 std::size_t size() const { return m_size; }
276
278 void load() {
279 const auto rank_local = this->rank();
280 if (rank_local > 4) {
281 throw std::runtime_error("Cannot load dataset of rank greater than 4");
282 }
283 // determine total size in memory and allocate it
284 std::size_t num_ele = std::accumulate(this->m_info.dims.cbegin(), this->m_info.dims.cbegin() + rank_local,
285 static_cast<std::size_t>(1), std::multiplies<std::size_t>());
286 if constexpr (std::is_same_v<T, char>) {
287 // For char type we need to add one for the null terminator
288 num_ele += 1;
289 }
290 this->alloc(static_cast<std::size_t>(num_ele));
291
292 // do the actual load
293 getData(m_data.data());
294
295 if constexpr (std::is_same_v<T, char>) {
296 // For char type we need to add a null terminator
297 m_data.push_back('\0');
298 }
299 }
300
301 void load(dimsize_t const blocksize, dimsize_t const i) {
302 if (rank() > 4) {
303 throw std::runtime_error("Cannot load dataset of rank greater than 4");
304 }
305 dimsize_t n = 0;
306 DimVector datastart, datasize;
307 if (rank() == 4) {
308 if (i >= dim0())
309 rangeError();
310 n = dim1() * dim2() * dim3();
311 datastart = {i, 0, 0, 0};
312 datasize = {1, dim1(), dim2(), dim2()};
313 } else if (rank() == 3) {
314 if (i >= dim0())
315 rangeError();
316 n = dim1() * dim2();
317 datastart = {i, 0, 0};
318 datasize = {1, dim1(), dim2()};
319 } else if (rank() == 2) {
320 if (i >= dim0())
321 rangeError();
322 dimsize_t m = blocksize;
323 if (i + m > dim0())
324 m = dim0() - i;
325 n = dim1() * m;
326 datastart = {i, 0};
327 datasize = {m, dim1()};
328 } else if (rank() == 1) {
329 if (i >= dim0())
330 rangeError();
331 n = 1 * blocksize;
332 datastart = {i};
333 datasize = {blocksize};
334 }
335 alloc(n);
336 getSlab(m_data.data(), datastart, datasize);
337 }
338
351 void load(dimsize_t const blocksize, dimsize_t const i, dimsize_t const j) {
352 if (rank() > 4) {
353 throw std::runtime_error("Cannot load dataset of rank greater than 4");
354 }
355 dimsize_t n = 0;
356 DimVector datastart, datasize;
357 if (rank() == 4) {
358 if (i >= dim0() || j >= dim1())
359 rangeError();
360 n = dim2() * dim3();
361 datastart = {i, j, 0, 0};
362 datasize = {1, 1, dim2(), dim2()};
363 } else if (rank() == 3) {
364 if (i >= dim0() || j >= dim1())
365 rangeError();
366 dimsize_t m = blocksize;
367 if (j + m > dim1())
368 m = dim1() - j;
369 n = dim2() * m;
370 datastart = {i, j, 0};
371 datasize = {1, m, dim2()};
372 } else if (rank() == 2) {
373 if (i >= dim0() || j >= dim1())
374 rangeError();
375 n = 1;
376 datastart = {i, j};
377 datasize = {1, 1};
378 } else if (rank() == 1) {
379 if (i >= dim0())
380 rangeError();
381 n = 1 * blocksize;
382 datastart = {i};
383 datasize = {blocksize};
384 }
385 alloc(n);
386 getSlab(m_data.data(), datastart, datasize);
387 }
388
389private:
395 void alloc(dimsize_t new_size) {
396 if (new_size == 0) {
397 throw std::runtime_error("Attempt to load from an empty dataset " + address());
398 }
399 try {
400 if (new_size != m_size) {
401 m_data.resize(new_size);
402 m_size = new_size;
403 }
404 } catch (...) {
405 std::ostringstream ostr;
406 ostr << "Cannot allocate " << new_size * sizeof(T) << " bytes of memory to load the data";
407 throw std::runtime_error(ostr.str());
408 }
409 }
411 void rangeError() const { throw std::range_error("Nexus dataset range error"); }
412 // We cannot use an STL vector due to the dreaded std::vector<bool>
414 std::size_t m_size;
415};
416
431
432//-------------------- classes --------------------------//
433
442class MANTID_NEXUS_DLL NXClass : public NXObject {
443 friend class NXRoot;
444
445public:
452 NXClass(NXClass const &parent, std::string const &name);
454 std::string NX_class() const override { return "NXClass"; }
455
461 bool isValid(const std::string &address) const;
469 template <class NX> NX openNXClass(const std::string &name) const {
470 NX nxc(*this, name);
471 nxc.open();
472 return nxc;
473 }
474
481 NXClass openNXGroup(const std::string &name) const { return openNXClass<NXClass>(name); }
482
490 template <class T> NXDataSetTyped<T> openNXDataSet(const std::string &name) const {
491 NXDataSetTyped<T> data(*this, name);
492 data.open();
493 return data;
494 }
495
501 NXInt openNXInt(const std::string &name) const { return openNXDataSet<int32_t>(name); }
507 NXFloat openNXFloat(const std::string &name) const { return openNXDataSet<float>(name); }
513 NXDouble openNXDouble(const std::string &name) const { return openNXDataSet<double>(name); }
519 NXChar openNXChar(const std::string &name) const { return openNXDataSet<char>(name); }
525 NXUInt64 openNXSize(const std::string &name) const { return openNXDataSet<uint64_t>(name); }
532 std::string getString(const std::string &name) const;
538 double getDouble(const std::string &name) const;
544 float getFloat(const std::string &name) const;
550 int32_t getInt(const std::string &name) const;
551
553 std::vector<NXClassInfo> &groups() const { return *m_groups; }
555 bool containsGroup(const std::string &query) const;
557 std::vector<NXInfo> &datasets() const { return *m_datasets; }
563 NXInfo getDataSetInfo(const std::string &name) const;
565 bool containsDataSet(const std::string &query) const;
567 void close();
569 void open();
576 bool openLocal(const std::string &nxclass = "");
577
578protected:
579 std::shared_ptr<std::vector<NXClassInfo>> m_groups;
580 std::shared_ptr<std::vector<NXInfo>> m_datasets;
581 void readAllInfo();
582 void clear();
583private:
585 NXClass() : NXObject() { clear(); }
586};
587
588//-------------------- main classes -------------------------------//
589
592class MANTID_NEXUS_DLL NXData : public NXClass {
593public:
599 NXData(const NXClass &parent, const std::string &name);
601 std::string NX_class() const override { return "NXdata"; }
603 template <typename T> NXDataSetTyped<T> openData() {
604 for (std::vector<NXInfo>::const_iterator it = datasets().begin(); it != datasets().end(); ++it) {
605 NXDataSet dset(*this, it->nxname);
606 dset.open();
607 if (dset.attributes("signal") == "1") {
608 return openNXDataSet<T>(it->nxname);
609 }
610 }
611 // You failed to find the signal.
612 // So try to just open the "data" entry directly
613 return openNXDataSet<T>("data");
614 }
616 NXDouble openDoubleData() { return openData<double>(); }
618 NXFloat openFloatData() { return openData<float>(); }
620 NXInt openIntData() { return openData<int32_t>(); }
621};
622
624class MANTID_NEXUS_DLL NXDetector : public NXClass {
625public:
631 NXDetector(const NXClass &parent, const std::string &name) : NXClass(parent, name) {}
633 std::string NX_class() const override { return "NXdetector"; }
635 NXFloat openDistance() { return openNXFloat("distance"); }
637 NXFloat openAzimuthalAngle() { return openNXFloat("azimuthal_angle"); }
639 NXFloat openPolarAngle() { return openNXFloat("polar_angle"); }
640};
641
643class MANTID_NEXUS_DLL NXInstrument : public NXClass {
644public:
650 NXInstrument(const NXClass &parent, const std::string &name) : NXClass(parent, name) {}
652 std::string NX_class() const override { return "NXinstrument"; }
657 NXDetector openNXDetector(const std::string &name) { return openNXClass<NXDetector>(name); }
658};
659
661class MANTID_NEXUS_DLL NXEntry : public NXClass {
662public:
669 NXEntry(const NXClass &parent, const std::string &name) : NXClass(parent, name) {}
671 std::string NX_class() const override { return "NXentry"; }
677 NXData openNXData(const std::string &name) const { return openNXClass<NXData>(name); }
683 NXInstrument openNXInstrument(const std::string &name) const { return openNXClass<NXInstrument>(name); }
684};
685
687class MANTID_NEXUS_DLL NXRoot : public NXClass {
688public:
689 // Constructor
690 NXRoot(std::string fname);
691 // Constructor
692 NXRoot(std::string fname, const std::string &entry);
694 ~NXRoot() override;
696 std::string NX_class() const override { return "NXroot"; }
699 bool isStandard() const;
705 NXEntry openEntry(const std::string &name) { return openNXClass<NXEntry>(name); }
706 NXEntry openFirstEntry();
707
708private:
709 const std::string m_filename;
710};
711
712} // namespace Nexus
713} // namespace Mantid
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
std::map< std::string, std::string > m_values
the list of attributes
std::size_t n() const
number of attributes
The base class for a Nexus class (group).
NXClass()
Private constructor.
std::vector< NXInfo > & datasets() const
Returns a list of all datasets in this NXClass.
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
std::vector< NXClassInfo > & groups() const
Returns a list of all classes (or groups) in this NXClass.
NXClass openNXGroup(const std::string &name) const
Creates and opens an arbitrary (non-standard) class (group).
std::shared_ptr< std::vector< NXClassInfo > > m_groups
Holds info about the child NXClasses.
NXChar openNXChar(const std::string &name) const
Creates and opens a char dataset.
std::shared_ptr< std::vector< NXInfo > > m_datasets
Holds info about the datasets in this NXClass.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
NX openNXClass(const std::string &name) const
Templated method for creating derived NX classes.
NXUInt64 openNXSize(const std::string &name) const
Creates and opens a size_t dataset.
NXDouble openNXDouble(const std::string &name) const
Creates and opens a double dataset.
std::string NX_class() const override
The NX class identifier.
NXDataSetTyped< T > openNXDataSet(const std::string &name) const
Templated method for creating datasets.
Templated class implementation of NXDataSet.
const T & operator()(std::size_t i, std::size_t j, std::size_t k) const
Returns a value assuming the data is a tree-dimensional array.
const T & operator[](std::size_t i) const
Returns the i-th value in the internal buffer.
std::size_t m_size
The buffer size.
void load(dimsize_t const blocksize, dimsize_t const i, dimsize_t const j)
Implementation of the virtual NXDataSet::load(...) method.
T & operator()(std::size_t i, std::size_t j)
container_T< T > m_data
The data buffer.
const T & operator()(std::size_t i, std::size_t j) const
Returns a value assuming the data is a two-dimensional array.
T & operator()(std::size_t i, std::size_t j, std::size_t k)
NXDataSetTyped(NXClass const &parent, std::string const &name)
Constructor.
void rangeError() const
A shortcut to "throw std::range_error("Nexus dataset range error");".
void load(dimsize_t const blocksize, dimsize_t const i)
void alloc(dimsize_t new_size)
Allocates memory for the data buffer.
T & operator[](std::size_t i)
const T * operator()() const
Returns a pointer to the internal data buffer.
void load()
Read all of the datablock in.
container_T< T > & vecBuffer()
Returns a the internal buffer.
std::size_t size() const
Returns the size of the data buffer.
Abstract base class for a Nexus data set.
void getData(NumT *data)
Wrapper to the NXgetdata.
dimsize_t dim0() const
Returns the number of elements along the first dimension.
NXAttributes attributes
Attributes.
NXnumtype type() const
Returns the Nexus type of the data. The types are defined in NexusFile_fwd.h.
dimsize_t dim3() const
Returns the number of elements along the fourth dimension.
NXInfo m_info
Holds the data info.
dimsize_t dims(std::size_t i) const
Returns the number of elements along i-th dimension.
dimsize_t dim2() const
Returns the number of elements along the third dimension.
void getSlab(NumT *data, DimVector const &start, DimVector const &size)
Wrapper to the NXgetslab.
std::string NX_class() const override
NX class name. Returns "SDS".
void open()
Opens the data set. Does not read in any data. Call load(...) to load the data.
std::size_t rank() const
Returns the rank (number of dimensions) of the data. The maximum is 4.
dimsize_t dim1() const
Returns the number of elements along the second dimension.
std::string name() const
Returns the name of the data set.
Implements NXdata Nexus class.
NXDataSetTyped< T > openData()
Opens the dataset within this NXData with signal=1 attribute.
NXDouble openDoubleData()
Opens data of double type.
std::string NX_class() const override
Nexus class id.
NXInt openIntData()
Opens data of int type.
NXFloat openFloatData()
Opens data of float type.
Implements NXdetector Nexus class.
NXFloat openPolarAngle()
Opens the dataset containing pixel polar angles.
std::string NX_class() const override
Nexus class id.
NXFloat openDistance()
Opens the dataset containing pixel distances.
NXFloat openAzimuthalAngle()
Opens the dataset containing pixel azimuthal angles.
NXDetector(const NXClass &parent, const std::string &name)
Constructor.
Implements NXentry Nexus class.
std::string NX_class() const override
Nexus class id.
NXEntry(const NXClass &parent, const std::string &name)
Constructor.
NXData openNXData(const std::string &name) const
Opens a NXData.
NXInstrument openNXInstrument(const std::string &name) const
Opens a NXInstrument.
Implements NXinstrument Nexus class.
NXInstrument(const NXClass &parent, const std::string &name)
Constructor.
std::string NX_class() const override
Nexus class id.
NXDetector openNXDetector(const std::string &name)
Opens a NXDetector.
The base abstract class for Nexus classes and data sets.
virtual std::string NX_class() const =0
Return the NX class name for a class (HDF group) or "SDS" for a data set;.
NexusAddress const & address() const
Returns the absolute address to the object.
virtual ~NXObject()=default
std::shared_ptr< File > m_fileID
Nexus file id.
NexusAddress m_address
Keeps the absolute address to the object.
bool m_open
Set to true if the object has been open.
Implements NXroot Nexus class.
const std::string m_filename
The file name.
std::string NX_class() const override
Return the NX class for a class (HDF group) or "SDS" for a data set;.
NXEntry openEntry(const std::string &name)
Opens an entry – a topmost Nexus class.
This simple class encapsulates some methods for working with paths inside a Nexus file.
The primitive types published by this API.
NXDataSetTyped< int32_t > NXUInt32
The integer dataset type.
NXDataSetTyped< int64_t > NXInt64
The integer dataset type.
const int g_processed_blocksize
Default block size for reading and writing processed files.
std::conditional_t< std::is_same< T, bool >{}, boost::container::vector< bool >, std::vector< T > > container_T
NXDataSetTyped< char > NXChar
The char dataset type.
std::array< dimsize_t, 4 > NXDimArray
C++ implementation of Nexus classes.
std::vector< dimsize_t > DimVector
std::pair< std::string, std::string > Entry
NXDataSetTyped< uint64_t > NXUInt64
The integer dataset type.
Helper class which provides the Collimation Length for SANS instruments.
This structure holds the type and dimensions of a primative field/array.
Information about a Nexus class.
bool allGood
return status
std::string nxclass
NX class of the object or "SDS" if a dataset.
std::string nxname
name of the object
NXnumtype datatype
NX data type if a dataset, e.g. NX_CHAR, FLOAT32; see NexusFile_fwd.h.
Structure for keeping information about a Nexus data set, such as the dimensions and the type.
bool allGood
return status
std::size_t rank
number of dimensions of the data
std::string nxname
name of the object
NXDimArray dims
sizes along each dimension
NXnumtype type
type of the data, e.g. NX_CHAR, FLOAT32; see NexusFile_fwd.h