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 <sstream>
19#include <string>
20#include <vector>
21
22namespace Mantid {
23namespace Nexus {
24
31typedef std::array<dimsize_t, 4> NXDimArray;
32
36struct NXInfo {
37 NXInfo() : nxname(), rank(0), dims(), type(NXnumtype::BAD), allGood(false) {}
38 NXInfo(Info const &info, std::string const &name);
39 std::string nxname;
40 std::size_t rank;
43 bool allGood;
44 operator bool() { return allGood; }
45};
46
49 NXClassInfo(Entry e) : nxname(e.first), nxclass(e.second), datatype(NXnumtype::BAD), allGood(true) {}
51 std::string nxname;
52 std::string nxclass;
54 bool allGood;
55 operator bool() { return allGood; }
56};
57
58/*
59 * LoadNexusProcessed and SaveNexusProcessed need to share some attributes, put them at namespace level here
60 */
61
64
68class MANTID_NEXUS_DLL NXAttributes {
69public:
70 std::size_t n() const { return m_values.size(); }
71 std::vector<std::string> names() const;
72 std::vector<std::string> values() const;
73 std::string operator()(const std::string &name) const;
74 void set(const std::string &name, const std::string &value);
75 template <typename T> void set(const std::string &name, T value);
76private:
77 std::map<std::string, std::string> m_values;
78};
79
80// Forward declaration
81class NXClass;
82
87class MANTID_NEXUS_DLL NXObject {
88 friend class NXDataSet;
89 friend class NXClass;
90 friend class NXRoot;
91public:
92 // Constructor
93 NXObject(File *fileID, NXClass const *parent, std::string const &name);
94 NXObject(std::shared_ptr<File> const &fileID, NXClass const *parent, std::string const &name);
95 virtual ~NXObject() = default;
97 virtual std::string NX_class() const = 0;
98 // True if complies with our understanding of the www.nexusformat.org
99 // definition.
100 // virtual bool isStandard()const = 0;
102 NexusAddress const &address() const { return m_address; }
104 std::string name() const;
106 std::shared_ptr<File> m_fileID;
107
108protected:
110 bool m_open;
111private:
112 NXObject();
113};
114
127class MANTID_NEXUS_DLL NXDataSet : public NXObject {
128public:
129 // Constructor
130 NXDataSet(NXClass const &parent, std::string const &name);
132 std::string NX_class() const override { return "SDS"; }
134 void open();
136 void openLocal();
138 std::size_t rank() const { return m_info.rank; }
140 dimsize_t dims(std::size_t i) const { return i < 4 ? m_info.dims[i] : 0; }
142 dimsize_t dim0() const;
144 dimsize_t dim1() const;
146 dimsize_t dim2() const;
148 dimsize_t dim3() const;
150 std::string name() const { return m_info.nxname; } // cppcheck-suppress returnByReference
152 NXnumtype type() const { return m_info.type; }
155
156protected:
163 template <typename NumT> void getData(NumT *data) {
164 m_fileID->openData(name());
165 m_fileID->getData(data);
166 m_fileID->closeData();
167 }
168
179 template <typename NumT> void getSlab(NumT *data, DimVector const &start, DimVector const &size) {
180 m_fileID->openData(name());
181 m_fileID->getSlab(data, start, size);
182 m_fileID->closeData();
183 }
184
185private:
187 void getAttributes();
188};
189
190template <typename T>
191using container_T = std::conditional_t<std::is_same<T, bool>{}, boost::container::vector<bool>, std::vector<T>>;
192
196template <class T> class NXDataSetTyped : public NXDataSet {
197
198public:
205 NXDataSetTyped(NXClass const &parent, std::string const &name) : NXDataSet(parent, name), m_size(0UL) {}
212 const T *operator()() const {
213 if (m_data.empty())
214 throw std::runtime_error("Attempt to read uninitialized data from " + address());
215 return m_data.data();
216 }
217
219 if (m_data.empty())
220 throw std::runtime_error("Attempt to read uninitialized data from " + address());
221 return m_data.data();
222 }
223
232 const T &operator[](std::size_t i) const {
233 if (m_data.empty())
234 throw std::runtime_error("Attempt to read uninitialized data from " + address());
235 if (i >= m_size)
236 rangeError();
237 return m_data[i];
238 }
239
240 T &operator[](std::size_t i) { return const_cast<T &>(static_cast<const NXDataSetTyped &>(*this)[i]); }
250 const T &operator()(std::size_t i, std::size_t j) const { return this->operator[](i * dim1() + j); }
251 T &operator()(std::size_t i, std::size_t j) {
252 return const_cast<T &>(static_cast<const NXDataSetTyped &>(*this)(i, j));
253 }
263 const T &operator()(std::size_t i, std::size_t j, std::size_t k) const {
264 return this->operator[]((i * dim1() + j) * dim2() + k);
265 }
266 T &operator()(std::size_t i, std::size_t j, std::size_t k) {
267 return const_cast<T &>(static_cast<const NXDataSetTyped &>(*this)(i, j, k));
268 }
269
273 std::size_t size() const { return m_size; }
274
276 void load() {
277 const auto rank_local = this->rank();
278 if (rank_local > 4) {
279 throw std::runtime_error("Cannot load dataset of rank greater than 4");
280 }
281 // determine total size in memory and allocate it
282 auto num_ele = this->dim0();
283 if (rank_local > 1) {
284 num_ele *= this->dim1();
285 if (rank_local > 2) {
286 num_ele *= this->dim2();
287 if (rank_local > 3) {
288 num_ele *= this->dim3();
289 }
290 }
291 }
292 if constexpr (std::is_same_v<T, char>) {
293 // For char type we need to add one for the null terminator
294 num_ele += 1;
295 }
296 this->alloc(static_cast<std::size_t>(num_ele));
297
298 // do the actual load
299 getData(m_data.data());
300
301 if constexpr (std::is_same_v<T, char>) {
302 // For char type we need to add a null terminator
303 m_data.push_back('\0');
304 }
305 }
306
307 void load(dimsize_t const blocksize, dimsize_t const i) {
308 if (rank() > 4) {
309 throw std::runtime_error("Cannot load dataset of rank greater than 4");
310 }
311 dimsize_t n = 0;
312 DimVector datastart, datasize;
313 if (rank() == 4) {
314 if (i >= dim0())
315 rangeError();
316 n = dim1() * dim2() * dim3();
317 datastart = {i, 0, 0, 0};
318 datasize = {1, dim1(), dim2(), dim2()};
319 } else if (rank() == 3) {
320 if (i >= dim0())
321 rangeError();
322 n = dim1() * dim2();
323 datastart = {i, 0, 0};
324 datasize = {1, dim1(), dim2()};
325 } else if (rank() == 2) {
326 if (i >= dim0())
327 rangeError();
328 dimsize_t m = blocksize;
329 if (i + m > dim0())
330 m = dim0() - i;
331 n = dim1() * m;
332 datastart = {i, 0};
333 datasize = {m, dim1()};
334 } else if (rank() == 1) {
335 if (i >= dim0())
336 rangeError();
337 n = 1 * blocksize;
338 datastart = {i};
339 datasize = {blocksize};
340 }
341 alloc(n);
342 getSlab(m_data.data(), datastart, datasize);
343 }
344
357 void load(dimsize_t const blocksize, dimsize_t const i, dimsize_t const j) {
358 if (rank() > 4) {
359 throw std::runtime_error("Cannot load dataset of rank greater than 4");
360 }
361 dimsize_t n = 0;
362 DimVector datastart, datasize;
363 if (rank() == 4) {
364 if (i >= dim0() || j >= dim1())
365 rangeError();
366 n = dim2() * dim3();
367 datastart = {i, j, 0, 0};
368 datasize = {1, 1, dim2(), dim2()};
369 } else if (rank() == 3) {
370 if (i >= dim0() || j >= dim1())
371 rangeError();
372 dimsize_t m = blocksize;
373 if (j + m > dim1())
374 m = dim1() - j;
375 n = dim2() * m;
376 datastart = {i, j, 0};
377 datasize = {1, m, dim2()};
378 } else if (rank() == 2) {
379 if (i >= dim0() || j >= dim1())
380 rangeError();
381 n = 1;
382 datastart = {i, j};
383 datasize = {1, 1};
384 } else if (rank() == 1) {
385 if (i >= dim0())
386 rangeError();
387 n = 1 * blocksize;
388 datastart = {i};
389 datasize = {blocksize};
390 }
391 alloc(n);
392 getSlab(m_data.data(), datastart, datasize);
393 }
394
395private:
401 void alloc(dimsize_t new_size) {
402 if (new_size == 0) {
403 throw std::runtime_error("Attempt to load from an empty dataset " + address());
404 }
405 try {
406 if (new_size != m_size) {
407 m_data.resize(new_size);
408 m_size = new_size;
409 }
410 } catch (...) {
411 std::ostringstream ostr;
412 ostr << "Cannot allocate " << new_size * sizeof(T) << " bytes of memory to load the data";
413 throw std::runtime_error(ostr.str());
414 }
415 }
417 void rangeError() const { throw std::range_error("Nexus dataset range error"); }
418 // We cannot use an STL vector due to the dreaded std::vector<bool>
420 std::size_t m_size;
421};
422
437
438//-------------------- classes --------------------------//
439
448class MANTID_NEXUS_DLL NXClass : public NXObject {
449 friend class NXRoot;
450
451public:
458 NXClass(NXClass const &parent, std::string const &name);
460 std::string NX_class() const override { return "NXClass"; }
461
467 bool isValid(const std::string &address) const;
475 template <class NX> NX openNXClass(const std::string &name) const {
476 NX nxc(*this, name);
477 nxc.open();
478 return nxc;
479 }
480
487 NXClass openNXGroup(const std::string &name) const { return openNXClass<NXClass>(name); }
488
496 template <class T> NXDataSetTyped<T> openNXDataSet(const std::string &name) const {
497 NXDataSetTyped<T> data(*this, name);
498 data.open();
499 return data;
500 }
501
507 NXInt openNXInt(const std::string &name) const { return openNXDataSet<int32_t>(name); }
513 NXFloat openNXFloat(const std::string &name) const { return openNXDataSet<float>(name); }
519 NXDouble openNXDouble(const std::string &name) const { return openNXDataSet<double>(name); }
525 NXChar openNXChar(const std::string &name) const { return openNXDataSet<char>(name); }
531 NXUInt64 openNXSize(const std::string &name) const { return openNXDataSet<uint64_t>(name); }
538 std::string getString(const std::string &name) const;
544 double getDouble(const std::string &name) const;
550 float getFloat(const std::string &name) const;
556 int32_t getInt(const std::string &name) const;
557
559 std::vector<NXClassInfo> &groups() const { return *m_groups; }
561 bool containsGroup(const std::string &query) const;
563 std::vector<NXInfo> &datasets() const { return *m_datasets; }
569 NXInfo getDataSetInfo(const std::string &name) const;
571 bool containsDataSet(const std::string &query) const;
573 void close();
575 void open();
582 bool openLocal(const std::string &nxclass = "");
583
584protected:
585 std::shared_ptr<std::vector<NXClassInfo>> m_groups;
586 std::shared_ptr<std::vector<NXInfo>> m_datasets;
587 void readAllInfo();
588 void clear();
589private:
591 NXClass() : NXObject() { clear(); }
592};
593
594//-------------------- main classes -------------------------------//
595
598class MANTID_NEXUS_DLL NXData : public NXClass {
599public:
605 NXData(const NXClass &parent, const std::string &name);
607 std::string NX_class() const override { return "NXdata"; }
609 template <typename T> NXDataSetTyped<T> openData() {
610 for (std::vector<NXInfo>::const_iterator it = datasets().begin(); it != datasets().end(); ++it) {
611 NXDataSet dset(*this, it->nxname);
612 dset.open();
613 if (dset.attributes("signal") == "1") {
614 return openNXDataSet<T>(it->nxname);
615 }
616 }
617 // You failed to find the signal.
618 // So try to just open the "data" entry directly
619 return openNXDataSet<T>("data");
620 }
622 NXDouble openDoubleData() { return openData<double>(); }
624 NXFloat openFloatData() { return openData<float>(); }
626 NXInt openIntData() { return openData<int32_t>(); }
627};
628
630class MANTID_NEXUS_DLL NXDetector : public NXClass {
631public:
637 NXDetector(const NXClass &parent, const std::string &name) : NXClass(parent, name) {}
639 std::string NX_class() const override { return "NXdetector"; }
641 NXFloat openDistance() { return openNXFloat("distance"); }
643 NXFloat openAzimuthalAngle() { return openNXFloat("azimuthal_angle"); }
645 NXFloat openPolarAngle() { return openNXFloat("polar_angle"); }
646};
647
649class MANTID_NEXUS_DLL NXInstrument : public NXClass {
650public:
656 NXInstrument(const NXClass &parent, const std::string &name) : NXClass(parent, name) {}
658 std::string NX_class() const override { return "NXinstrument"; }
663 NXDetector openNXDetector(const std::string &name) { return openNXClass<NXDetector>(name); }
664};
665
667class MANTID_NEXUS_DLL NXEntry : public NXClass {
668public:
675 NXEntry(const NXClass &parent, const std::string &name) : NXClass(parent, name) {}
677 std::string NX_class() const override { return "NXentry"; }
683 NXData openNXData(const std::string &name) const { return openNXClass<NXData>(name); }
689 NXInstrument openNXInstrument(const std::string &name) const { return openNXClass<NXInstrument>(name); }
690};
691
693class MANTID_NEXUS_DLL NXRoot : public NXClass {
694public:
695 // Constructor
696 NXRoot(std::string fname);
697 // Constructor
698 NXRoot(std::string fname, const std::string &entry);
700 ~NXRoot() override;
702 std::string NX_class() const override { return "NXroot"; }
705 bool isStandard() const;
711 NXEntry openEntry(const std::string &name) { return openNXClass<NXEntry>(name); }
712 NXEntry openFirstEntry();
713
714private:
715 const std::string m_filename;
716};
717
718} // namespace Nexus
719} // 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