Mantid
Loading...
Searching...
No Matches
PropertyNexus.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 +
14#include "MantidNexus/NexusFile.h"
15
16// PropertyWithValue implementation
18
19#include <boost/algorithm/string/split.hpp>
20
21#include <memory>
22
23using namespace Mantid::Kernel;
24
25#ifdef _WIN32
26#pragma warning(push)
27#pragma warning(disable : 4805)
28#endif
29
31
32namespace {
33//----------------------------------------------------------------------------------------------
41template <typename NumT>
42std::unique_ptr<Property> makeProperty(Nexus::File *file, const std::string &name,
43 const std::vector<Types::Core::DateAndTime> &times) {
44 std::vector<NumT> values;
45 file->getData(values);
46 if (times.empty()) {
47 if (values.size() == 1) {
48 return std::make_unique<PropertyWithValue<NumT>>(name, values[0]);
49 } else {
50 return std::make_unique<ArrayProperty<NumT>>(name, std::move(values));
51 }
52 } else {
53 auto prop = std::make_unique<TimeSeriesProperty<NumT>>(name);
54 prop->addValues(times, values);
55 return std::unique_ptr<Property>(std::move(prop));
56 }
57}
58
66std::unique_ptr<Property> makeTimeSeriesBoolProperty(Nexus::File *file, const std::string &name,
67 const std::vector<Types::Core::DateAndTime> &times) {
68 std::vector<uint8_t> savedValues;
69 file->getData(savedValues);
70 const size_t nvals = savedValues.size();
71 std::vector<bool> realValues(nvals);
72 for (size_t i = 0; i < nvals; ++i) {
73 realValues[i] = (savedValues[i] != 0);
74 }
75 auto prop = std::make_unique<TimeSeriesProperty<bool>>(name);
76 prop->addValues(times, realValues);
77 return std::unique_ptr<Property>(std::move(prop));
78}
79
81std::unique_ptr<Property> makeStringProperty(Nexus::File *file, const std::string &name,
82 const std::vector<Types::Core::DateAndTime> &times) {
83 if (times.empty()) {
84 std::string bigString = file->getStrData();
85 return std::make_unique<PropertyWithValue<std::string>>(name, bigString);
86 } else {
87 if (file->getInfo().dims.size() != 2)
88 throw std::runtime_error("NXlog loading failed on field " + name + ". Expected rank 2.");
89 int64_t numStrings = file->getInfo().dims[0];
90 int64_t span = file->getInfo().dims[1];
91 auto data = std::make_unique<char[]>(numStrings * span);
92 file->getData(data.get());
93 std::vector<std::string> values;
94 values.reserve(static_cast<size_t>(numStrings));
95 for (int64_t i = 0; i < numStrings; i++)
96 values.emplace_back(data.get() + i * span);
97
98 auto prop = std::make_unique<TimeSeriesProperty<std::string>>(name);
99 prop->addValues(times, values);
100 return std::unique_ptr<Property>(std::move(prop));
101 }
102}
106void getTimeAndStart(Nexus::File *file, std::vector<double> &timeSec, std::string &startStr) {
107 file->openData("time");
108 file->getData(timeSec);
109 // Optionally get a start
110 try {
111 file->getAttr("start", startStr);
112 } catch (Nexus::Exception const &) {
113 }
114 file->closeData();
115}
116
126std::unique_ptr<Property> loadPropertyCommon(Nexus::File *file, const std::string &group,
127 const std::vector<double> &timeSec, std::string &startStr) {
128 std::vector<Types::Core::DateAndTime> times;
129 if (!timeSec.empty()) {
130 // Use a default start time
131 if (startStr.empty())
132 startStr = "2000-01-01T00:00:00";
133 // Convert time in seconds to DateAndTime
134 Types::Core::DateAndTime start(startStr);
135 times.reserve(timeSec.size());
136 std::transform(timeSec.cbegin(), timeSec.cend(), std::back_inserter(times),
137 [&start](const auto &time) { return start + time; });
138 }
139
140 file->openData("value");
141 std::unique_ptr<Property> retVal = nullptr;
142 switch (file->getInfo().type) {
144 retVal = makeProperty<float>(file, group, times);
145 break;
147 retVal = makeProperty<double>(file, group, times);
148 break;
149 case NXnumtype::INT32:
150 retVal = makeProperty<int32_t>(file, group, times);
151 break;
153 retVal = makeProperty<uint32_t>(file, group, times);
154 break;
155 case NXnumtype::INT64:
156 retVal = makeProperty<int64_t>(file, group, times);
157 break;
159 retVal = makeProperty<uint64_t>(file, group, times);
160 break;
161 case NXnumtype::CHAR:
162 retVal = makeStringProperty(file, group, times);
163 break;
164 case NXnumtype::UINT8: {
165 // Check the type at the group level. Boolean stored as UINT8
166 file->closeData();
167 const bool typeIsBool = file->hasAttr("boolean");
168 file->openData("value");
169
170 if (typeIsBool)
171 retVal = makeTimeSeriesBoolProperty(file, group, times);
172 break;
173 }
174 case NXnumtype::INT8:
175 case NXnumtype::INT16:
177 retVal = nullptr;
178 break;
179 case NXnumtype::BAD:
180 throw std::runtime_error("Invalid data type found.");
181 break;
182 }
183
184 // verifying that the attribute exists makes this very slow in NeXus v4.4.3
185 // because of the change in how nxgetnextattr is implemented
186 std::string unitsStr;
187 try {
188 file->getAttr("units", unitsStr);
189 } catch (Nexus::Exception const &) {
190 // let it drop on the floor
191 }
192
193 file->closeData();
194 file->closeGroup();
195 // add units
196 if (retVal)
197 retVal->setUnits(unitsStr);
198 return retVal;
199}
200
201} // namespace
202//----------------------------------------------------------------------------------------------
203
204std::unique_ptr<Property> loadProperty(Nexus::File *file, const std::string &group,
205 const Mantid::Nexus::NexusDescriptor &fileInfo, const std::string &prefix) {
206 file->openGroup(group, "NXlog");
207
208 // Times in second offsets
209 std::vector<double> timeSec;
210 std::string startStr;
211
212 // Check if the "time" field is present
213 if (fileInfo.isEntry(prefix + "/" + group + "/time")) {
214 getTimeAndStart(file, timeSec, startStr);
215 }
216
217 return loadPropertyCommon(file, group, timeSec, startStr);
218}
219
220//----------------------------------------------------------------------------------------------
228std::unique_ptr<Property> loadProperty(Nexus::File *file, const std::string &group) {
229 file->openGroup(group, "NXlog");
230
231 // Times in second offsets
232 std::vector<double> timeSec;
233 std::string startStr;
234
235 // Get the entries so that you can check if the "time" field is present
236 std::map<std::string, std::string> entries = file->getEntries();
237 if (entries.find("time") != entries.end()) {
238 getTimeAndStart(file, timeSec, startStr);
239 }
240
241 return loadPropertyCommon(file, group, timeSec, startStr);
242}
243
244#ifdef _WIN32
245#pragma warning(pop)
246#endif
247
248} // namespace Mantid::Kernel::PropertyNexus
std::string name
Definition Run.cpp:60
Class that provides for a standard Nexus exception.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
static unsigned short constexpr UINT16
static unsigned short constexpr UINT64
static unsigned short constexpr INT8
static unsigned short constexpr INT64
static unsigned short constexpr INT16
static unsigned short constexpr UINT32
static unsigned short constexpr CHAR
static unsigned short constexpr UINT8
static unsigned short constexpr INT32
static unsigned short constexpr FLOAT32
static unsigned short constexpr BAD
static unsigned short constexpr FLOAT64
Namespace with helper methods for loading and saving Property's (logs) to NXS files.
DLLExport std::unique_ptr< Property > loadProperty(Nexus::File *file, const std::string &group, const Nexus::NexusDescriptor &fileInfo, const std::string &prefix)
Opens a NXlog group in a nexus file and creates the correct Property object from it.