Mantid
Loading...
Searching...
No Matches
LoadHelper.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 * Helper file to gather common routines to the Loaders
9 * */
10
17
18#include <nexus/napi.h>
19
20#include <boost/algorithm/string/predicate.hpp> //assert(boost::algorithm::ends_with("mystring", "ing"));
21
22namespace Mantid {
23
24namespace {
26Kernel::Logger g_log("LoadHelper");
27} // namespace
28
29namespace DataHandling {
30using namespace Kernel;
31using namespace API;
32
38 std::string insNamePath;
39 std::vector<Mantid::NeXus::NXClassInfo> v = firstEntry.groups();
40 for (auto it = v.begin(); it < v.end(); it++) {
41 if (it->nxclass == "NXinstrument") {
42 insNamePath = it->nxname;
43 break;
44 }
45 }
46 return insNamePath;
47}
48
49std::string LoadHelper::getStringFromNexusPath(const Mantid::NeXus::NXEntry &firstEntry, const std::string &nexusPath) {
50 return firstEntry.getString(nexusPath);
51}
52
53double LoadHelper::getDoubleFromNexusPath(const Mantid::NeXus::NXEntry &firstEntry, const std::string &nexusPath) {
54 return firstEntry.getFloat(nexusPath);
55}
56
62 const std::string &nexusPath) {
63
64 Mantid::NeXus::NXFloat timeBinningNexus = firstEntry.openNXFloat(nexusPath);
65 timeBinningNexus.load();
66
67 size_t numberOfBins = static_cast<size_t>(timeBinningNexus.dim0()) + 1; // boundaries
68
69 float *timeBinning_p = &timeBinningNexus[0];
70 std::vector<double> timeBinning(numberOfBins);
71 std::copy(timeBinning_p, timeBinning_p + timeBinningNexus.dim0(), std::begin(timeBinning));
72 // calculate the extra bin at the end
73 timeBinning[numberOfBins - 1] = timeBinning[numberOfBins - 2] + timeBinning[1] - timeBinning[0];
74
75 return timeBinning;
76}
82double LoadHelper::calculateEnergy(double wavelength) {
84 (2 * PhysicalConstants::NeutronMass * wavelength * wavelength * 1e-20) / PhysicalConstants::meV;
85 return e;
86}
87
94double LoadHelper::calculateTOF(double distance, double wavelength) {
95 if (wavelength <= 0) {
96 throw std::runtime_error("Wavelenght is <= 0");
97 }
98
99 double velocity = PhysicalConstants::h / (PhysicalConstants::NeutronMass * wavelength * 1e-10); // m/s
100
101 return distance / velocity;
102}
103
104/*
105 * Get instrument property as double
106 * @s - input property name
107 *
108 */
110 std::vector<std::string> prop = workspace->getInstrument()->getStringParameter(s);
111 if (prop.empty()) {
112 return EMPTY_DBL();
113 } else {
114 return boost::lexical_cast<double>(prop[0]);
115 }
116}
117
131void LoadHelper::addNexusFieldsToWsRun(NXhandle nxfileID, API::Run &runDetails, const std::string &entryName,
132 bool useFullPath) {
133 std::string emptyStr; // needed for first call
134 int datatype;
135 char nxname[NX_MAXNAMELEN], nxclass[NX_MAXNAMELEN];
136 if (!entryName.empty()) {
137 strcpy(nxname, entryName.c_str());
138 }
139
140 // As a workaround against some "not so good" old ILL nexus files
141 // (ILLIN5_Vana_095893.nxs for example)
142 // by default we begin the parse on the first entry (entry0),
143 // or from a chosen entryName. This allow to avoid the
144 // bogus entries that follows.
145
146 NXstatus getnextentry_status = NXgetnextentry(nxfileID, nxname, nxclass, &datatype);
147 if (getnextentry_status == NX_OK) {
148 if ((NXopengroup(nxfileID, nxname, nxclass)) == NX_OK) {
149 recurseAndAddNexusFieldsToWsRun(nxfileID, runDetails, emptyStr, emptyStr, 1 /* level */, useFullPath);
150 NXclosegroup(nxfileID);
151 }
152 }
153}
154
168void LoadHelper::recurseAndAddNexusFieldsToWsRun(NXhandle nxfileID, API::Run &runDetails, std::string &parent_name,
169 std::string &parent_class, int level, bool useFullPath) {
170 // Classes
171 NXstatus getnextentry_status;
172 int datatype;
174 char nxname[NX_MAXNAMELEN], nxclass[NX_MAXNAMELEN];
175 nxname[0] = '0';
176 nxclass[0] = '0';
177
178 bool has_entry = true; // follows getnextentry_status
179 while (has_entry) {
180 getnextentry_status = NXgetnextentry(nxfileID, nxname, nxclass, &datatype);
181
182 if (getnextentry_status == NX_OK) {
183 NXstatus opengroup_status;
184 NXstatus opendata_status;
185 NXstatus getinfo_status;
186
187 std::string property_name = (parent_name.empty() ? nxname : parent_name + "." + nxname);
188 if ((opengroup_status = NXopengroup(nxfileID, nxname, nxclass)) == NX_OK) {
189 if (std::string(nxclass) != "ILL_data_scan_vars" && std::string(nxclass) != "NXill_data_scan_vars") {
190 // Go down to one level, if the group is known to nexus
191 std::string p_nxname = useFullPath ? property_name : nxname; // current names can be useful for next level
192 std::string p_nxclass(nxclass);
193
194 recurseAndAddNexusFieldsToWsRun(nxfileID, runDetails, p_nxname, p_nxclass, level + 1, useFullPath);
195 }
196
197 NXclosegroup(nxfileID);
198 } // if(NXopengroup
199 else if ((opendata_status = NXopendata(nxfileID, nxname)) == NX_OK) {
200 if (parent_class != "NXData" && parent_class != "NXMonitor" &&
201 std::string(nxname) != "data") { // create a property
202 int rank = 0;
203 int dims[4] = {0, 0, 0, 0};
204 int type;
205
206 // Get the value
207 if ((getinfo_status = NXgetinfo(nxfileID, &rank, dims, &type)) == NX_OK) {
208 // Note, we choose to only build properties on small float arrays
209 // filter logic is below
210 bool build_small_float_array = false; // default
211 bool read_property = true;
212
213 if ((type == NX_FLOAT32) || (type == NX_FLOAT64)) {
214 if ((rank == 1) && (dims[0] <= 9)) {
215 build_small_float_array = true;
216 } else {
217 read_property = false;
218 }
219 } else if (type != NX_CHAR) {
220 if ((rank > 1) || (dims[0] > 1) || (dims[1] > 1) || (dims[2] > 1) || (dims[3] > 1)) {
221 read_property = false;
222 }
223 } else {
224 if ((rank > 1) || (dims[1] > 1) || (dims[2] > 1) || (dims[3] > 1)) {
225 read_property = false;
226 }
227 }
228
229 if (read_property) {
230
231 void *dataBuffer;
232 NXmalloc(&dataBuffer, rank, dims, type);
233
234 if (NXgetdata(nxfileID, dataBuffer) == NX_OK) {
235
236 if (type == NX_CHAR) {
237 std::string property_value(reinterpret_cast<const char *>(dataBuffer));
238 if (boost::algorithm::ends_with(property_name, "_time")) {
239 // That's a time value! Convert to Mantid standard
240 property_value = dateTimeInIsoFormat(property_value);
241 if (runDetails.hasProperty(property_name))
242 runDetails.getProperty(property_name)->setValue(property_value);
243 else
244 runDetails.addProperty(property_name, property_value);
245 } else {
246 if (!runDetails.hasProperty(property_name)) {
247 runDetails.addProperty(property_name, property_value);
248 } else {
249 g_log.warning() << "Property " << property_name
250 << " was set twice. Please check the Nexus file and your inputs." << std::endl;
251 }
252 }
253
254 } else if ((type == NX_FLOAT32) || (type == NX_FLOAT64) || (type == NX_INT16) || (type == NX_INT32) ||
255 (type == NX_UINT16)) {
256
257 // Look for "units"
258 NXstatus units_status;
259 char units_sbuf[NX_MAXNAMELEN];
260 int units_len = NX_MAXNAMELEN;
261 int units_type = NX_CHAR;
262
263 char unitsAttrName[] = "units";
264 units_status = NXgetattr(nxfileID, unitsAttrName, units_sbuf, &units_len, &units_type);
265 if ((type == NX_FLOAT32) || (type == NX_FLOAT64)) {
266 // Mantid numerical properties are double only.
267 double property_double_value = 0.0;
268
269 // Simple case, one value
270 if (dims[0] == 1) {
271 if (type == NX_FLOAT32) {
272 property_double_value = *(reinterpret_cast<float *>(dataBuffer));
273 } else if (type == NX_FLOAT64) {
274 property_double_value = *(reinterpret_cast<double *>(dataBuffer));
275 }
276 if (!runDetails.hasProperty(property_name)) {
277
278 if (units_status != NX_ERROR)
279 runDetails.addProperty(property_name, property_double_value, std::string(units_sbuf));
280 else
281 runDetails.addProperty(property_name, property_double_value);
282 } else {
283 g_log.warning() << "Property " << property_name
284 << " was set twice. Please check the Nexus file and your inputs." << std::endl;
285 }
286 } else if (build_small_float_array) {
287 // An array, converted to "name_index", with index < 10
288 // (see
289 // test above)
290 for (int dim_index = 0; dim_index < dims[0]; dim_index++) {
291 if (type == NX_FLOAT32) {
292 property_double_value = (reinterpret_cast<float *>(dataBuffer))[dim_index];
293 } else if (type == NX_FLOAT64) {
294 property_double_value = (reinterpret_cast<double *>(dataBuffer))[dim_index];
295 }
296 std::string indexed_property_name =
297 property_name + std::string("_") + std::to_string(dim_index);
298
299 if (!runDetails.hasProperty(indexed_property_name)) {
300 if (units_status != NX_ERROR)
301 runDetails.addProperty(indexed_property_name, property_double_value,
302 std::string(units_sbuf));
303 else
304 runDetails.addProperty(indexed_property_name, property_double_value);
305 } else {
306 g_log.warning()
307 << "Property " << property_name
308 << " was set twice. Please check the Nexus file and your inputs." << std::endl;
309 }
310 }
311 }
312
313 } else {
314 // int case
315 int property_int_value = 0;
316 if (type == NX_INT16) {
317 property_int_value = *(reinterpret_cast<short int *>(dataBuffer));
318 } else if (type == NX_INT32) {
319 property_int_value = *(reinterpret_cast<int *>(dataBuffer));
320 } else if (type == NX_UINT16) {
321 property_int_value = *(reinterpret_cast<short unsigned int *>(dataBuffer));
322 }
323
324 if (!runDetails.hasProperty(property_name)) {
325 if (units_status != NX_ERROR)
326 runDetails.addProperty(property_name, property_int_value, std::string(units_sbuf));
327 else
328 runDetails.addProperty(property_name, property_int_value);
329 } else {
330 g_log.warning() << "Property " << property_name
331 << " was set twice. Please check the Nexus file and your inputs." << std::endl;
332 }
333
334 } // if (type==...
335 }
336 }
337 NXfree(&dataBuffer);
338 dataBuffer = nullptr;
339 }
340
341 } // if NXgetinfo OK
342 } // if (parent_class == "NXData" || parent_class == "NXMonitor") else
343
344 NXclosedata(nxfileID);
345 }
346 } else if (getnextentry_status == NX_EOD) {
347 has_entry = false; // end of loop
348 } else {
349 has_entry = false; // end of loop
350 }
351
352 } // while
353
354} // recurseAndAddNexusFieldsToWsRun
355
362void LoadHelper::dumpNexusAttributes(NXhandle nxfileID) {
363 // Attributes
364 NXname pName;
365 int iLength, iType;
366#ifndef NEXUS43
367 int rank;
368 int dims[4];
369#endif
370 std::vector<char> buff(128);
371
372#ifdef NEXUS43
373 while (NXgetnextattr(nxfileID, pName, &iLength, &iType) != NX_EOD) {
374#else
375 while (NXgetnextattra(nxfileID, pName, &rank, dims, &iType) != NX_EOD) {
376 if (rank > 1) { // mantid only supports single value attributes
377 throw std::runtime_error("Encountered attribute with multi-dimensional array value");
378 }
379 iLength = dims[0]; // to clarify things
380 if (iType != NX_CHAR && iLength != 1) {
381 throw std::runtime_error("Encountered attribute with array value");
382 }
383#endif
384
385 switch (iType) {
386 case NX_CHAR: {
387 if (iLength > static_cast<int>(buff.size())) {
388 buff.resize(iLength);
389 }
390 int nz = iLength + 1;
391 NXgetattr(nxfileID, pName, buff.data(), &nz, &iType);
392 break;
393 }
394 case NX_INT16: {
395 short int value;
396 NXgetattr(nxfileID, pName, &value, &iLength, &iType);
397 break;
398 }
399 case NX_INT32: {
400 int value;
401 NXgetattr(nxfileID, pName, &value, &iLength, &iType);
402 break;
403 }
404 case NX_UINT16: {
405 short unsigned int value;
406 NXgetattr(nxfileID, pName, &value, &iLength, &iType);
407 break;
408 }
409 } // switch
410 } // while
411}
421std::string LoadHelper::dateTimeInIsoFormat(const std::string &dateToParse) {
422 namespace bt = boost::posix_time;
423 try {
424 // Try to convert to a boost date as an iso string. If it works, we are already in ISO and no conversion is
425 // requiered.
426 bt::from_iso_extended_string(dateToParse);
427 return dateToParse;
428
429 } catch (...) {
430 }
431 // parsing format
432 const std::locale format = std::locale(std::locale::classic(), new bt::time_input_facet("%d-%b-%y %H:%M:%S"));
433
434 bt::ptime pt;
435 std::istringstream is(dateToParse);
436 is.imbue(format);
437 is >> pt;
438
439 if (pt != bt::ptime()) {
440 // Converts to ISO
441 std::string s = bt::to_iso_extended_string(pt);
442 return s;
443 } else {
444 return "";
445 }
446}
447
454void LoadHelper::moveComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName,
455 const V3D &newPos) {
456 Geometry::IComponent_const_sptr component = ws->getInstrument()->getComponentByName(componentName);
457 if (!component) {
458 throw std::invalid_argument("Instrument component " + componentName + " not found");
459 }
460 auto &componentInfo = ws->mutableComponentInfo();
461 const auto componentIndex = componentInfo.indexOf(component->getComponentID());
462 componentInfo.setPosition(componentIndex, newPos);
463}
464
472void LoadHelper::rotateComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName,
473 const Kernel::Quat &rot) {
474 Geometry::IComponent_const_sptr component = ws->getInstrument()->getComponentByName(componentName);
475 if (!component) {
476 throw std::invalid_argument("Instrument component " + componentName + " not found");
477 }
478 auto &componentInfo = ws->mutableComponentInfo();
479 const auto componentIndex = componentInfo.indexOf(component->getComponentID());
480 componentInfo.setRotation(componentIndex, rot);
481}
482
489V3D LoadHelper::getComponentPosition(const API::MatrixWorkspace_sptr &ws, const std::string &componentName) {
490 Geometry::IComponent_const_sptr component = ws->getInstrument()->getComponentByName(componentName);
491 if (!component) {
492 throw std::invalid_argument("Instrument component " + componentName + " not found");
493 }
494 V3D pos = component->getPos();
495 return pos;
496}
497
498} // namespace DataHandling
499} // namespace Mantid
double value
The value of the point.
Definition: FitMW.cpp:51
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Definition: LogManager.cpp:265
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
Definition: LogManager.cpp:404
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition: LogManager.h:79
This class stores information regarding an experimental run as a series of log entries.
Definition: Run.h:38
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
virtual std::string setValue(const std::string &)=0
Set the value of the property via a string.
Class for quaternions.
Definition: Quat.h:39
Class for 3D vectors.
Definition: V3D.h:34
std::vector< NXClassInfo > & groups() const
Returns a list of all classes (or groups) in this NXClass.
Definition: NexusClasses.h:589
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
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 dim0() const
Returns the number of elements along the first dimension.
Implements NXentry Nexus class.
Definition: NexusClasses.h:898
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
double getInstrumentProperty(const API::MatrixWorkspace_sptr &, const std::string &)
Definition: LoadHelper.cpp:109
double calculateEnergy(double)
Calculate Neutron Energy from wavelength: .
Definition: LoadHelper.cpp:82
void recurseAndAddNexusFieldsToWsRun(NXhandle nxfileID, API::Run &runDetails, std::string &parent_name, std::string &parent_class, int level, bool useFullPath)
Recursively add properties from a nexus file to the workspace run.
Definition: LoadHelper.cpp:168
void rotateComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName, const Kernel::Quat &rot)
LoadHelper::rotateComponent.
Definition: LoadHelper.cpp:472
std::string getStringFromNexusPath(const Mantid::NeXus::NXEntry &, const std::string &)
Definition: LoadHelper.cpp:49
std::vector< double > getTimeBinningFromNexusPath(const Mantid::NeXus::NXEntry &, const std::string &)
Gets the time binning from a Nexus float array Adds an extra bin at the end.
Definition: LoadHelper.cpp:61
void addNexusFieldsToWsRun(NXhandle nxfileID, API::Run &runDetails, const std::string &entryName="", bool useFullPath=false)
Add properties from a nexus file to the workspace run.
Definition: LoadHelper.cpp:131
double getDoubleFromNexusPath(const Mantid::NeXus::NXEntry &, const std::string &)
Definition: LoadHelper.cpp:53
std::string findInstrumentNexusPath(const Mantid::NeXus::NXEntry &)
Finds the path for the instrument name in the nexus file Usually of the form: entry0/<NXinstrument cl...
Definition: LoadHelper.cpp:37
void moveComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName, const Kernel::V3D &newPos)
LoadHelper::moveComponent.
Definition: LoadHelper.cpp:454
void dumpNexusAttributes(NXhandle nxfileID)
Show attributes attached to the current Nexus entry.
Definition: LoadHelper.cpp:362
double calculateTOF(double, double)
Calculate TOF from distance.
Definition: LoadHelper.cpp:94
std::string dateTimeInIsoFormat(const std::string &)
Parses the date as formatted at the ILL: 29-Jun-12 11:27:26 and converts it to the ISO format used in...
Definition: LoadHelper.cpp:421
Kernel::V3D getComponentPosition(const API::MatrixWorkspace_sptr &ws, const std::string &componentName)
LoadHelper::getComponentPosition.
Definition: LoadHelper.cpp:489
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition: IComponent.h:161
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
static constexpr double meV
1 meV in Joules.
Helper class which provides the Collimation Length for SANS instruments.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
std::string to_string(const wide_integer< Bits, Signed > &n)