Mantid
Loading...
Searching...
No Matches
NexusClasses.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
11#include <memory>
12#include <utility>
13
14namespace Mantid::NeXus {
15
16std::vector<std::string> NXAttributes::names() const {
17 std::vector<std::string> out;
18 out.reserve(m_values.size());
19 std::transform(m_values.cbegin(), m_values.cend(), std::back_inserter(out),
20 [](const auto &value) { return value.first; });
21 return out;
22}
23
24std::vector<std::string> NXAttributes::values() const {
25 std::vector<std::string> out;
26 out.reserve(m_values.size());
27 std::transform(m_values.cbegin(), m_values.cend(), std::back_inserter(out),
28 [](const auto &value) { return value.second; });
29 return out;
30}
31
37std::string NXAttributes::operator()(const std::string &name) const {
38 auto it = m_values.find(name);
39 if (it == m_values.end())
40 return "";
41 return it->second;
42}
43
48void NXAttributes::set(const std::string &name, const std::string &value) { m_values[name] = value; }
49
54void NXAttributes::set(const std::string &name, double value) {
55 std::ostringstream ostr;
56 ostr << value;
57 m_values[name] = ostr.str();
58}
59
60//---------------------------------------------------------
61// NXObject methods
62//---------------------------------------------------------
63
70NXObject::NXObject(const NXhandle fileID, const NXClass *parent, const std::string &name)
71 : m_fileID(fileID), m_open(false) {
72 if (parent && !name.empty()) {
73 m_path = parent->path() + "/" + name;
74 }
75}
76
77std::string NXObject::name() const {
78 size_t i = m_path.find_last_of('/');
79 if (i == std::string::npos)
80 return m_path;
81 else
82 return m_path.substr(i + 1, m_path.size() - i - 1);
83}
84
88 NXname pName;
89 int iLength, iType;
90#ifndef NEXUS43
91 int rank;
92 int dims[4];
93#endif
94 std::vector<char> buff(128);
95
96#ifdef NEXUS43
97 while (NXgetnextattr(m_fileID, pName, &iLength, &iType) != NX_EOD) {
98#else
99 while (NXgetnextattra(m_fileID, pName, &rank, dims, &iType) != NX_EOD) {
100#endif
101#ifndef NEXUS43
102 if (rank > 1) { // mantid only supports single value attributes
103 throw std::runtime_error("Encountered attribute with multi-dimensional array value");
104 }
105 iLength = dims[0]; // to clarify things
106 if (iType != NX_CHAR && iLength != 1) {
107 throw std::runtime_error("Encountered attribute with array value");
108 }
109#endif
110
111 switch (iType) {
112 case NX_CHAR: {
113 if (iLength >= 0 && (unsigned)iLength > buff.size()) {
114 buff.resize(iLength);
115 }
116 int nz = iLength + 1;
117 NXgetattr(m_fileID, pName, buff.data(), &nz, &iType);
118 attributes.set(pName, buff.data());
119 break;
120 }
121 case NX_INT16: {
122 short int value;
123 NXgetattr(m_fileID, pName, &value, &iLength, &iType);
124 sprintf(buff.data(), "%i", value);
125 attributes.set(pName, buff.data());
126 break;
127 }
128 case NX_INT32: {
129 int value;
130 NXgetattr(m_fileID, pName, &value, &iLength, &iType);
131 sprintf(buff.data(), "%i", value);
132 attributes.set(pName, buff.data());
133 break;
134 }
135 case NX_UINT16: {
136 short unsigned int value;
137 NXgetattr(m_fileID, pName, &value, &iLength, &iType);
138 sprintf(buff.data(), "%u", value);
139 attributes.set(pName, buff.data());
140 break;
141 }
142 }
143 };
144}
145//---------------------------------------------------------
146// NXClass methods
147//---------------------------------------------------------
148
149NXClass::NXClass(const NXClass &parent, const std::string &name) : NXObject(parent.m_fileID, &parent, name) { clear(); }
150
152 NXClassInfo res;
153 char nxname[NX_MAXNAMELEN], nxclass[NX_MAXNAMELEN];
154 res.stat = NXgetnextentry(m_fileID, nxname, nxclass, &res.datatype);
155 if (res) // Check if previous call was successful
156 {
157 res.nxname = nxname;
158 res.nxclass = nxclass;
159 }
160 return res;
161}
162
164 clear();
165 NXClassInfo info;
166 while ((info = getNextEntry())) {
167 if (info.nxclass == "SDS") {
168 NXInfo data_info;
169 NXopendata(m_fileID, info.nxname.c_str());
170 data_info.stat = NXgetinfo(m_fileID, &data_info.rank, data_info.dims, &data_info.type);
171 NXclosedata(m_fileID);
172 data_info.nxname = info.nxname;
173 m_datasets->emplace_back(data_info);
174 } else if (info.nxclass.substr(0, 2) == "NX" || info.nxclass.substr(0, 2) == "IX") {
175 m_groups->emplace_back(info);
176 }
177 }
178 reset();
179}
180
181bool NXClass::isValid(const std::string &path) const {
182 if (NXopengrouppath(m_fileID, path.c_str()) == NX_OK) {
183 NXclosegroup(m_fileID);
184 return true;
185 } else
186 return false;
187}
188
190 if (NX_ERROR == NXopengrouppath(m_fileID, m_path.c_str())) {
191
192 throw std::runtime_error("Cannot open group " + name() + " of class " + NX_class() + " (trying to open path " +
193 m_path + ")");
194 }
195 //}
196 m_open = true;
197 readAllInfo();
198}
199
210bool NXClass::openLocal(const std::string &nxclass) {
211 std::string className = nxclass.empty() ? NX_class() : nxclass;
212 if (NX_ERROR == NXopengroup(m_fileID, name().c_str(), className.c_str())) {
213 // It would be nice if this worked
214 // if (NX_ERROR == NXopengrouppath(m_fileID,m_path.c_str()))
215 //{
216 // throw std::runtime_error("Cannot open group "+m_path+" of class
217 // "+NX_class());
218 //}
219 return false;
220 }
221 m_open = true;
222 readAllInfo();
223 return true;
224}
225
227 if (NX_ERROR == NXclosegroup(m_fileID)) {
228 throw std::runtime_error("Cannot close group " + name() + " of class " + NX_class() + " (trying to close path " +
229 m_path + ")");
230 }
231 m_open = false;
232}
233
234void NXClass::reset() { NXinitgroupdir(m_fileID); }
235
237 m_groups.reset(new std::vector<NXClassInfo>);
238 m_datasets.reset(new std::vector<NXInfo>);
239}
240
241std::string NXClass::getString(const std::string &name) const {
242 NXChar buff = openNXChar(name);
243 try {
244 buff.load();
245 return std::string(buff(), buff.dim0());
246 } catch (std::runtime_error &) {
247 // deals with reading uninitialized/empty data
248 return std::string();
249 }
250}
251
252double NXClass::getDouble(const std::string &name) const {
253 NXDouble number = openNXDouble(name);
254 number.load();
255 return *number();
256}
257
258float NXClass::getFloat(const std::string &name) const {
259 NXFloat number = openNXFloat(name);
260 number.load();
261 return *number();
262}
263
264int NXClass::getInt(const std::string &name) const {
265 NXInt number = openNXInt(name);
266 number.load();
267 return *number();
268}
273bool NXClass::containsGroup(const std::string &query) const {
274 std::vector<NXClassInfo>::const_iterator end = m_groups->end();
275 for (std::vector<NXClassInfo>::const_iterator i = m_groups->begin(); i != end; ++i) {
276 if (i->nxname == query) {
277 return true;
278 }
279 }
280 return false;
281}
282
288NXInfo NXClass::getDataSetInfo(const std::string &name) const {
289 NXInfo info;
290 for (std::vector<NXInfo>::const_iterator it = datasets().begin(); it != datasets().end(); ++it) {
291 if (it->nxname == name)
292 return *it;
293 }
294 info.stat = NX_ERROR;
295 return info;
296}
297
301bool NXClass::containsDataSet(const std::string &query) const { return getDataSetInfo(query).stat != NX_ERROR; }
302
303//---------------------------------------------------------
304// NXNote methods
305//---------------------------------------------------------
306
307std::string NXNote::author() {
308 if (!m_author_ok) {
309 NXChar aut = openNXChar("author");
310 aut.load();
311 m_author = std::string(aut(), aut.dim0());
312 m_author_ok = true;
313 }
314 return m_author;
315}
316
317std::vector<std::string> &NXNote::data() {
318 if (!m_data_ok) {
319 int rank;
320 int dims[4];
321 int type;
322 NXopendata(m_fileID, "data");
323 NXgetinfo(m_fileID, &rank, dims, &type);
324 int n = dims[0];
325 auto buffer = new char[n];
326 NXstatus stat = NXgetdata(m_fileID, buffer);
327 NXclosedata(m_fileID);
328 m_data.clear();
329 if (stat == NX_ERROR) {
330 delete[] buffer;
331 return m_data;
332 }
333 std::istringstream istr(std::string(buffer, n));
334 delete[] buffer;
335
336 std::string line;
337 while (getline(istr, line)) {
338 m_data.emplace_back(line);
339 }
340
341 m_data_ok = true;
342 }
343 return m_data;
344}
345
346std::string NXNote::description() {
347 if (!m_description_ok) {
348 NXChar str = openNXChar("description");
349 str.load();
350 m_description = std::string(str(), str.dim0());
351 m_description_ok = true;
352 }
353 return m_description;
354}
355
356std::vector<char> &NXBinary::binary() {
357 if (!m_data_ok) {
358 int rank;
359 int dims[4];
360 int type;
361 NXopendata(m_fileID, "data");
362 NXgetinfo(m_fileID, &rank, dims, &type);
363 int n = dims[0];
364 m_binary.resize(n);
365 NXstatus stat = NXgetdata(m_fileID, &m_binary[0]);
366 (void)stat; // Avoid unused variable compiler warning
367 NXclosedata(m_fileID);
368 }
369 return m_binary;
370}
371
372//---------------------------------------------------------
373// NXRoot methods
374//---------------------------------------------------------
375
379NXRoot::NXRoot(std::string fname) : m_filename(std::move(fname)) {
380 // Open NeXus file
381 NXstatus stat = NXopen(m_filename.c_str(), NXACC_READ, &m_fileID);
382 if (stat == NX_ERROR) {
383 std::cout << "NXRoot: Error loading " << m_filename;
384 throw Kernel::Exception::FileError("Unable to open File:", m_filename);
385 }
386 readAllInfo();
387}
388
394NXRoot::NXRoot(std::string fname, const std::string &entry) : m_filename(std::move(fname)) {
395 (void)entry;
396 // Open NeXus file
397 NXstatus stat = NXopen(m_filename.c_str(), NXACC_CREATE5, &m_fileID);
398 if (stat == NX_ERROR) {
399 throw Kernel::Exception::FileError("Unable to open File:", m_filename);
400 }
401}
402
403NXRoot::~NXRoot() { NXclose(&m_fileID); }
404
405bool NXRoot::isStandard() const { return true; }
406
411 if (groups().empty()) {
412 throw std::runtime_error("NeXus file has no entries");
413 }
414 for (std::vector<NXClassInfo>::const_iterator grp = groups().begin(); grp != groups().end(); ++grp) {
415 if (grp->nxclass == "NXentry") {
416 return openEntry(grp->nxname);
417 }
418 }
419 throw std::runtime_error("NeXus file has no entries");
420}
421
422//---------------------------------------------------------
423// NXDataSet methods
424//---------------------------------------------------------
425
431NXDataSet::NXDataSet(const NXClass &parent, const std::string &name) : NXObject(parent.m_fileID, &parent, name) {
432 size_t i = name.find_last_of('/');
433 if (i == std::string::npos)
435 else if (name.empty() || i == name.size() - 1)
436 throw std::runtime_error("Improper dataset name " + name);
437 else
438 m_info.nxname = name.substr(i + 1);
439}
440
441// Opens the data set. Does not read in any data. Call load(...) to load the
442// data
444 size_t i = m_path.find_last_of('/');
445 if (i == std::string::npos || i == 0)
446 return; // we are in the root group, assume it is open
447 std::string group_path = m_path.substr(0, i);
448 if (NX_ERROR == NXopenpath(m_fileID, group_path.c_str())) {
449 throw std::runtime_error("Cannot open dataset " + m_path);
450 }
451 if (NXopendata(m_fileID, name().c_str()) != NX_OK) {
452 throw std::runtime_error("Error opening data in group \"" + name() + "\"");
453 }
454
455 if (NXgetinfo(m_fileID, &m_info.rank, m_info.dims, &m_info.type) != NX_OK) {
456 throw std::runtime_error("Error retrieving information for " + name() + " group");
457 }
458
460 NXclosedata(m_fileID);
461}
462
464 if (NXopendata(m_fileID, name().c_str()) != NX_OK) {
465 throw std::runtime_error("Error opening data in group \"" + name() + "\"");
466 }
467 if (NXgetinfo(m_fileID, &m_info.rank, m_info.dims, &m_info.type) != NX_OK) {
468 throw std::runtime_error("Error retrieving information for " + name() + " group");
469 }
471 NXclosedata(m_fileID);
472}
473
479int NXDataSet::dim0() const {
480 if (m_info.rank == 0) {
481 throw std::out_of_range("NXDataSet::dim0() - Requested dimension greater than rank.");
482 }
483 return m_info.dims[0];
484}
485
491int NXDataSet::dim1() const {
492 if (m_info.rank < 2) {
493 throw std::out_of_range("NXDataSet::dim1() - Requested dimension greater than rank.");
494 }
495 return m_info.dims[1];
496}
497
503int NXDataSet::dim2() const {
504 if (m_info.rank < 3) {
505 throw std::out_of_range("NXDataSet::dim2() - Requested dimension greater than rank.");
506 }
507 return m_info.dims[2];
508}
509
515int NXDataSet::dim3() const {
516 if (m_info.rank < 4) {
517 throw std::out_of_range("NXDataSet::dim3() - Requested dimension greater than rank.");
518 }
519 return m_info.dims[3];
520}
521
526void NXDataSet::getData(void *data) {
527 NXopendata(m_fileID, name().c_str());
528 if (NXgetdata(m_fileID, data) != NX_OK)
529 throw std::runtime_error("Cannot read data from NeXus file");
530 NXclosedata(m_fileID);
531}
532
544void NXDataSet::getSlab(void *data, int start[], int size[]) {
545 NXopendata(m_fileID, name().c_str());
546 if (NXgetslab(m_fileID, data, start, size) != NX_OK)
547 throw std::runtime_error("Cannot read data slab from NeXus file");
548 NXclosedata(m_fileID);
549}
550
551//---------------------------------------------------------
552// NXData methods
553//---------------------------------------------------------
554
555NXData::NXData(const NXClass &parent, const std::string &name) : NXMainClass(parent, name) {}
556
557//---------------------------------------------------------
558// NXLog methods
559//---------------------------------------------------------
560
565 NXInfo vinfo = getDataSetInfo("time");
566 if (vinfo.stat == NX_ERROR) {
568 } else {
569 return createTimeSeries();
570 }
571}
572
577 const std::string valAttr("value");
578 NXInfo vinfo = getDataSetInfo(valAttr);
579 Kernel::Property *prop;
580 int nxType = vinfo.type;
581 if (nxType == NX_FLOAT64) {
582 prop = new Kernel::PropertyWithValue<double>(name(), getDouble(valAttr));
583 } else if (nxType == NX_INT32) {
584 prop = new Kernel::PropertyWithValue<int>(name(), getInt(valAttr));
585 } else if (nxType == NX_CHAR) {
587 } else if (nxType == NX_UINT8) {
588 NXDataSetTyped<unsigned char> value(*this, valAttr);
589 value.load();
590 bool state = value[0] != 0;
591 prop = new Kernel::PropertyWithValue<bool>(name(), state);
592 } else {
593 prop = nullptr;
594 }
595
596 return prop;
597}
598
609Kernel::Property *NXLog::createTimeSeries(const std::string &start_time, const std::string &new_name) {
610 const std::string &logName = new_name.empty() ? name() : new_name;
611 NXInfo vinfo = getDataSetInfo("time");
612 if (vinfo.type == NX_FLOAT64) {
613 NXDouble times(*this, "time");
614 times.openLocal();
615 times.load();
616 std::string units = times.attributes("units");
617 if (units == "minutes") {
618 using std::placeholders::_1;
619 std::transform(times(), times() + times.dim0(), times(), std::bind(std::multiplies<double>(), _1, 60));
620 } else if (!units.empty() && units.substr(0, 6) != "second") {
621 return nullptr;
622 }
623 return parseTimeSeries(logName, times, start_time);
624 } else if (vinfo.type == NX_FLOAT32) {
625 NXFloat times(*this, "time");
626 times.openLocal();
627 times.load();
628 std::string units = times.attributes("units");
629 if (units == "minutes") {
630 std::for_each(times(), times() + times.dim0(), [](float &val) { val *= 60.0f; });
631 } else if (!units.empty() && units.substr(0, 6) != "second") {
632 return nullptr;
633 }
634 return parseTimeSeries(logName, times, start_time);
635 }
636
637 return nullptr;
638}
639
640} // namespace Mantid::NeXus
double value
The value of the point.
Definition: FitMW.cpp:51
Records the filename and the description of failure.
Definition: Exception.h:98
The concrete, templated class for properties.
Base class for properties.
Definition: Property.h:94
std::map< std::string, std::string > m_values
the list of attributes
Definition: NexusClasses.h:84
std::string operator()(const std::string &name) const
returns the value of attribute with name name
std::vector< std::string > values() const
Returns the list of attribute values.
std::vector< std::string > names() const
Returns the list of attribute names.
void set(const std::string &name, const std::string &value)
set the attribute's value
std::vector< char > m_binary
content
Definition: NexusClasses.h:766
std::vector< char > & binary()
Return the binary data associated with the note.
The base class for a Nexus class (group).
Definition: NexusClasses.h:487
int getInt(const std::string &name) const
Returns a int.
bool openLocal(const std::string &nxclass="")
Opens this NXClass using NXopengroup.
NXClassInfo getNextEntry()
Returns the class information about the next entry (class or dataset) in this class.
std::vector< NXInfo > & datasets() const
Returns a list of all datasets in this NXClass.
Definition: NexusClasses.h:593
void open()
Opens this NXClass using NXopengrouppath. Can be slow (or is slow)
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
Definition: NexusClasses.h:546
NXDouble openNXDouble(const std::string &name) const
Creates and opens a double dataset.
Definition: NexusClasses.h:556
void reset()
Creates a new object in the NeXus file at path path.
void close()
Close this class.
std::shared_ptr< std::vector< NXClassInfo > > m_groups
Holds info about the child NXClasses.
Definition: NexusClasses.h:616
NXClass()
Pricate constructor.
Definition: NexusClasses.h:622
std::string NX_class() const override
The NX class identifier.
Definition: NexusClasses.h:498
void readAllInfo()
Fills in m_groups and m_datasets.
bool containsGroup(const std::string &query) const
Returns whether an individual group (or group) is present.
std::vector< NXClassInfo > & groups() const
Returns a list of all classes (or groups) in this NXClass.
Definition: NexusClasses.h:589
void clear()
Deletes content of m_groups and m_datasets.
bool containsDataSet(const std::string &query) const
Returns whether an individual dataset is present.
NXInfo getDataSetInfo(const std::string &name) const
Returns NXInfo for a dataset.
std::shared_ptr< std::vector< NXInfo > > m_datasets
Holds info about the datasets in this NXClass.
Definition: NexusClasses.h:617
float getFloat(const std::string &name) const
Returns a float.
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
Definition: NexusClasses.h:551
bool isValid(const std::string &path) const
Check if a path exists relative to the current class path.
NXChar openNXChar(const std::string &name) const
Creates and opens a char dataset.
Definition: NexusClasses.h:561
double getDouble(const std::string &name) const
Returns a double.
std::string getString(const std::string &name) const
Returns a string.
Templated class implementation of NXDataSet.
Definition: NexusClasses.h:203
void load(const int blocksize=1, int i=-1, int j=-1, int k=-1, int l=-1) override
Implementation of the virtual NXDataSet::load(...) method.
Definition: NexusClasses.h:289
int dim2() const
Returns the number of elements along the third dimension.
void getData(void *data)
Wrapper to the NXgetdata.
int dim0() const
Returns the number of elements along the first dimension.
void open()
Opens the data set.
std::string name() const
Returns the name of the data set.
Definition: NexusClasses.h:159
void getSlab(void *data, int start[], int size[])
Wrapper to the NXgetslab.
int dim3() const
Returns the number of elements along the fourth dimension.
NXInfo m_info
Holds the data info.
Definition: NexusClasses.h:194
void openLocal()
Opens datasets faster but the parent group must be already open.
int dim1() const
Returns the number of elements along the second dimension.
NXData(const NXClass &parent, const std::string &name)
Constructor.
Implements NXentry Nexus class.
Definition: NexusClasses.h:898
Kernel::Property * createSingleValueProperty()
Creates a single value property of the log.
Kernel::Property * createTimeSeries(const std::string &start_time="", const std::string &new_name="")
Creates a TimeSeriesProperty and returns a pointer to it.
Kernel::Property * parseTimeSeries(const std::string &logName, const TYPE &times, const std::string &time0="")
Parse a time series.
Definition: NexusClasses.h:649
Kernel::Property * createProperty()
Creates a property wrapper around the log.
Main class is the one that can contain auxiliary classes.
Definition: NexusClasses.h:773
bool m_data_ok
data loaded indicator
Definition: NexusClasses.h:748
std::string m_author
author
Definition: NexusClasses.h:744
std::vector< std::string > & data()
Returns the note's content.
std::string description()
Returns the description string.
std::string author()
Returns the note's author.
bool m_author_ok
author loaded indicator
Definition: NexusClasses.h:747
bool m_description_ok
description loaded indicator
Definition: NexusClasses.h:749
std::string m_description
description
Definition: NexusClasses.h:746
std::vector< std::string > m_data
content
Definition: NexusClasses.h:745
The base abstract class for NeXus classes and data sets.
Definition: NexusClasses.h:93
NXhandle m_fileID
Nexus file id.
Definition: NexusClasses.h:113
std::string name() const
Returns the name of the object.
std::string m_path
Keeps the absolute path to the object.
Definition: NexusClasses.h:116
friend class NXDataSet
a friend class declaration
Definition: NexusClasses.h:94
void getAttributes()
Reads in attributes.
bool m_open
Set to true if the object has been open.
Definition: NexusClasses.h:117
NXObject()
Private default constructor.
Definition: NexusClasses.h:119
std::string path() const
Returns the absolute path to the object.
Definition: NexusClasses.h:107
friend class NXRoot
a friend class declaration
Definition: NexusClasses.h:96
NXAttributes attributes
Attributes.
Definition: NexusClasses.h:111
const std::string m_filename
The file name.
Definition: NexusClasses.h:943
~NXRoot() override
Destructor.
bool isStandard() const
True if complies with our understanding of the www.nexusformat.org definition.
NXEntry openFirstEntry()
Open the first NXentry in the file.
NXEntry openEntry(const std::string &name)
Opens an entry – a topmost Nexus class.
Definition: NexusClasses.h:939
STL namespace.
Information about a Nexus class.
Definition: NexusClasses.h:53
std::string nxclass
NX class of the object or "SDS" if a dataset.
Definition: NexusClasses.h:56
std::string nxname
name of the object
Definition: NexusClasses.h:55
int datatype
NX data type if a dataset, e.g.
Definition: NexusClasses.h:57
C++ implementation of NeXus classes.
Definition: NexusClasses.h:41
NXstatus stat
return status
Definition: NexusClasses.h:47
int rank
number of dimensions of the data
Definition: NexusClasses.h:44
int type
type of the data, e.g. NX_CHAR, NX_FLOAT32, see napi.h
Definition: NexusClasses.h:46
int dims[4]
sizes along each dimension
Definition: NexusClasses.h:45
std::string nxname
name of the object
Definition: NexusClasses.h:43