Mantid
Loading...
Searching...
No Matches
LoadSassena.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 +
9#include "MantidAPI/Axis.h"
18#include "MantidKernel/Unit.h"
20
21#include <hdf5_hl.h>
22
23#include <utility>
24
25namespace Mantid::DataHandling {
26
28
29
35int LoadSassena::confidence(Kernel::NexusDescriptor &descriptor) const {
36 if (descriptor.hasRootAttr("sassena_version") || descriptor.pathExists("/qvectors")) {
37 return 99;
38 }
39 return 0;
40}
41
50void LoadSassena::registerWorkspace(const API::WorkspaceGroup_sptr &gws, const std::string &wsName,
51 const DataObjects::Workspace2D_sptr &ws, const std::string &description) {
52 UNUSED_ARG(description);
53 API::AnalysisDataService::Instance().add(wsName, ws);
54 gws->addWorkspace(ws);
55}
56
64herr_t LoadSassena::dataSetInfo(const hid_t &h5file, const std::string &setName, hsize_t *dims) const {
65 H5T_class_t class_id;
66 size_t type_size;
67 herr_t errorcode = H5LTget_dataset_info(h5file, setName.c_str(), dims, &class_id, &type_size);
68 if (errorcode < 0) {
69 g_log.error("Unable to read " + setName + " dataset info");
70 }
71 return errorcode;
72}
73
80herr_t LoadSassena::dataSetDouble(const hid_t &h5file, const std::string &setName, std::vector<double> &buf) {
81 herr_t errorcode = H5LTread_dataset_double(h5file, setName.c_str(), buf.data());
82 if (errorcode < 0) {
83 this->g_log.error("Cannot read " + setName + " dataset");
84 }
85 return errorcode;
86}
87
88/* Helper object and function to sort modulus of Q-vectors
89 */
90using mypair = std::pair<double, int>;
91bool compare(const mypair &left, const mypair &right) { return left.first < right.first; }
103HistogramData::Points LoadSassena::loadQvectors(const hid_t &h5file, const API::WorkspaceGroup_sptr &gws,
104 std::vector<int> &sorting_indexes) {
105
106 // store the modulus of the vector
107 std::vector<double> qvmod;
108
109 const std::string gwsName = this->getPropertyValue("OutputWorkspace");
110 const std::string setName("qvectors");
111
112 hsize_t dims[3];
113 if (dataSetInfo(h5file, setName, dims) < 0) {
114 throw Kernel::Exception::FileError("Unable to read " + setName + " dataset info:", m_filename);
115 }
116 auto nq = static_cast<int>(dims[0]); // number of q-vectors
117 std::vector<double> buf(nq * 3);
118
119 herr_t errorcode = this->dataSetDouble(h5file, "qvectors", buf);
120 if (errorcode < 0) {
121 this->g_log.error("LoadSassena::loadQvectors cannot proceed");
122 qvmod.resize(0);
123 return HistogramData::Points(std::move(qvmod));
124 }
125
126 qvmod.reserve(nq);
127 for (auto curr = buf.cbegin(); curr != buf.cend(); curr += 3) {
128 qvmod.emplace_back(sqrt(curr[0] * curr[0] + curr[1] * curr[1] + curr[2] * curr[2]));
129 }
130
131 if (getProperty("SortByQVectors")) {
132 std::vector<mypair> qvmodpair;
133 qvmodpair.reserve(nq);
134 for (int iq = 0; iq < nq; iq++)
135 qvmodpair.emplace_back(qvmod[iq], iq);
136 std::sort(qvmodpair.begin(), qvmodpair.end(), compare);
137 for (int iq = 0; iq < nq; iq++)
138 sorting_indexes.emplace_back(qvmodpair[iq].second);
139 std::sort(qvmod.begin(), qvmod.end());
140 } else
141 for (int iq = 0; iq < nq; iq++)
142 sorting_indexes.emplace_back(iq);
143
144 DataObjects::Workspace2D_sptr ws = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
145 API::WorkspaceFactory::Instance().create("Workspace2D", nq, 3, 3));
146 std::string wsName = gwsName + std::string("_") + setName;
147 ws->setTitle(wsName);
148
149 for (int iq = 0; iq < nq; iq++) {
150 auto &Y = ws->mutableY(iq);
151 auto curr = std::next(buf.cbegin(), 3 * sorting_indexes[iq]);
152 Y.assign(curr, std::next(curr, 3));
153 }
154
155 ws->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("MomentumTransfer"); // Set the Units
156
157 this->registerWorkspace(gws, wsName, ws, "X-axis: origin of Q-vectors; Y-axis: tip of Q-vectors");
158 return HistogramData::Points(std::move(qvmod));
159}
160
172void LoadSassena::loadFQ(const hid_t &h5file, const API::WorkspaceGroup_sptr &gws, const std::string &setName,
173 const HistogramData::Points &qvmod, const std::vector<int> &sorting_indexes) {
174
175 auto nq = static_cast<int>(qvmod.size()); // number of q-vectors
176 std::vector<double> buf(nq * 2);
177 herr_t errorcode = this->dataSetDouble(h5file, setName, buf);
178 if (errorcode < 0) {
179 this->g_log.error("LoadSassena::loadFQ cannot proceed");
180 return;
181 }
182
183 const std::string gwsName = this->getPropertyValue("OutputWorkspace");
184
185 DataObjects::Workspace2D_sptr ws = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
186 API::WorkspaceFactory::Instance().create("Workspace2D", 2, nq, nq));
187 const std::string wsName = gwsName + std::string("_") + setName;
188 ws->setTitle(wsName);
189
190 auto &re = ws->mutableY(0); // store the real part
191 ws->setPoints(0, qvmod); // X-axis values are the modulus of the q vector
192 auto &im = ws->mutableY(1); // store the imaginary part
193 ws->setPoints(1, qvmod);
194
195 for (int iq = 0; iq < nq; ++iq) {
196 auto curr = std::next(buf.cbegin(), 2 * sorting_indexes[iq]);
197 re[iq] = *curr;
198 im[iq] = *std::next(curr);
199 }
200
201 // Set the Units
202 ws->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("MomentumTransfer");
203
204 this->registerWorkspace(gws, wsName, ws, "X-axis: Q-vector modulus; Y-axis: intermediate structure factor");
205}
206
220void LoadSassena::loadFQT(const hid_t &h5file, const API::WorkspaceGroup_sptr &gws, const std::string &setName,
221 const HistogramData::Points &qvmod, const std::vector<int> &sorting_indexes) {
222
223 hsize_t dims[3];
224 if (dataSetInfo(h5file, setName, dims) < 0) {
225 this->g_log.error("Unable to read " + setName + " dataset info");
226 this->g_log.error("LoadSassena::loadFQT cannot proceed");
227 return;
228 }
229 auto nnt = static_cast<int>(dims[1]); // number of non-negative time points
230 int nt = 2 * nnt - 1; // number of time points
231
232 auto nq = static_cast<int>(qvmod.size()); // number of q-vectors
233 std::vector<double> buf(nq * nnt * 2);
234 herr_t errorcode = this->dataSetDouble(h5file, setName, buf);
235 if (errorcode < 0) {
236 this->g_log.error("LoadSassena::loadFQT cannot proceed");
237 return;
238 }
239
240 const std::string gwsName = this->getPropertyValue("OutputWorkspace");
241 const double dt = getProperty("TimeUnit"); // time unit increment, in picoseconds;
242 DataObjects::Workspace2D_sptr wsRe = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
243 API::WorkspaceFactory::Instance().create("Workspace2D", nq, nt, nt));
244 const std::string wsReName = gwsName + std::string("_") + setName + std::string(".Re");
245 wsRe->setTitle(wsReName);
246
247 DataObjects::Workspace2D_sptr wsIm = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
248 API::WorkspaceFactory::Instance().create("Workspace2D", nq, nt, nt));
249 const std::string wsImName = gwsName + std::string("_") + setName + std::string(".Im");
250 wsIm->setTitle(wsImName);
251
252 int origin = nnt - 1;
253 for (int iq = 0; iq < nq; iq++) {
254 auto &reX = wsRe->mutableX(iq);
255 auto &imX = wsIm->mutableX(iq);
256 auto &reY = wsRe->mutableY(iq);
257 auto &imY = wsIm->mutableY(iq);
258 const int index = sorting_indexes[iq];
259 auto curr = std::next(buf.cbegin(), index * nnt * 2);
260 for (int it = 0; it < nnt; it++) {
261 reX[origin + it] = it * dt; // time point for the real part
262 reY[origin + it] = *curr; // real part of the intermediate structure factor
263 reX[origin - it] = -it * dt; // symmetric negative time
264 reY[origin - it] = *curr; // symmetric value for the negative time
265 ++curr;
266 imX[origin + it] = it * dt;
267 imY[origin + it] = *curr;
268 imX[origin - it] = -it * dt;
269 imY[origin - it] = -(*curr); // antisymmetric value for negative times
270 ++curr;
271 }
272 }
273
274 // Set the Time unit for the X-axis
275 wsRe->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("Label");
276 auto unitPtr = std::dynamic_pointer_cast<Kernel::Units::Label>(wsRe->getAxis(0)->unit());
277 unitPtr->setLabel("Time", "picoseconds");
278
279 wsIm->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("Label");
280 unitPtr = std::dynamic_pointer_cast<Kernel::Units::Label>(wsIm->getAxis(0)->unit());
281 unitPtr->setLabel("Time", "picoseconds");
282
283 // Create a numeric axis to replace the default vertical one
284 auto verticalAxisRe = std::make_unique<API::NumericAxis>(nq);
285 auto verticalAxisIm = std::make_unique<API::NumericAxis>(nq);
286 auto verticalAxisReRaw = verticalAxisRe.get();
287 auto verticalAxisImRaw = verticalAxisIm.get();
288 wsRe->replaceAxis(1, std::move(verticalAxisRe));
289 wsIm->replaceAxis(1, std::move(verticalAxisIm));
290
291 // Now set the axis values
292 for (int i = 0; i < nq; ++i) {
293 verticalAxisReRaw->setValue(i, qvmod[i]);
294 verticalAxisImRaw->setValue(i, qvmod[i]);
295 }
296
297 // Set the axis units
298 verticalAxisReRaw->unit() = Kernel::UnitFactory::Instance().create("MomentumTransfer");
299 verticalAxisReRaw->title() = "|Q|";
300 verticalAxisImRaw->unit() = Kernel::UnitFactory::Instance().create("MomentumTransfer");
301 verticalAxisImRaw->title() = "|Q|";
302
303 // Set the X axis title (for conversion to MD)
304 wsRe->getAxis(0)->title() = "Energy transfer";
305 wsIm->getAxis(0)->title() = "Energy transfer";
306
307 // Register the workspaces
308 registerWorkspace(gws, wsReName, wsRe, "X-axis: time; Y-axis: real part of intermediate structure factor");
309 registerWorkspace(gws, wsImName, wsIm, "X-axis: time; Y-axis: imaginary part of intermediate structure factor");
310}
311
318 // Declare the Filename algorithm property. Mandatory. Sets the path to the
319 // file to load.
320 const std::vector<std::string> exts{".h5", ".hd5"};
321 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load, exts), "A Sassena file");
322 // Declare the OutputWorkspace property
324 std::make_unique<API::WorkspaceProperty<API::Workspace>>("OutputWorkspace", "", Kernel::Direction::Output),
325 "The name of the group workspace to be created.");
327 "The Time unit in between data points, in picoseconds. "
328 "Default is 1.0 picosec.");
329 declareProperty(std::make_unique<Kernel::PropertyWithValue<bool>>("SortByQVectors", true, Kernel::Direction::Input),
330 "Sort structure factors by increasing momentum transfer?");
331}
332
337 // auto
338 // gws=std::dynamic_pointer_cast<API::WorkspaceGroup>(getProperty("OutputWorkspace"));
339 // API::WorkspaceGroup_sptr gws=getProperty("OutputWorkspace");
340 API::Workspace_sptr ows = getProperty("OutputWorkspace");
341
342 API::WorkspaceGroup_sptr gws = std::dynamic_pointer_cast<API::WorkspaceGroup>(ows);
343 if (gws && API::AnalysisDataService::Instance().doesExist(gws->getName())) {
344 // gws->deepRemoveAll(); // remove workspace members
345 API::AnalysisDataService::Instance().deepRemoveGroup(gws->getName());
346 } else {
347 gws = std::make_shared<API::WorkspaceGroup>();
348 setProperty("OutputWorkspace", std::dynamic_pointer_cast<API::Workspace>(gws));
349 }
350
351 // populate m_validSets
352 int nvalidSets = 4;
353 const char *validSets[] = {"fq", "fq0", "fq2", "fqt"};
354 for (int iSet = 0; iSet < nvalidSets; iSet++)
355 this->m_validSets.emplace_back(validSets[iSet]);
356
357 // open the HDF5 file for reading
358 m_filename = this->getPropertyValue("Filename");
359 hid_t h5file = H5Fopen(m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
360 if (h5file < 0) {
361 this->g_log.error("Cannot open " + m_filename);
362 throw Kernel::Exception::FileError("Unable to open:", m_filename);
363 }
364
365 // find out the sassena version used
366 char cversion[16];
367 if (H5LTget_attribute_string(h5file, "/", "sassena_version", cversion) < 0) {
368 this->g_log.error("Unable to read Sassena version");
369 }
370 // const std::string version(cversion);
371 // determine which loader protocol to use based on the version
372 // to be done at a later time, maybe implement a Version class
373
374 // Block to read the Q-vectors
375 std::vector<int> sorting_indexes;
376 const auto qvmod = this->loadQvectors(h5file, gws, sorting_indexes);
377 if (qvmod.empty()) {
378 this->g_log.error("No Q-vectors read. Unable to proceed");
379 H5Fclose(h5file);
380 return;
381 }
382
383 // iterate over the valid sets
384 std::string setName;
385 for (std::vector<std::string>::const_iterator it = this->m_validSets.begin(); it != this->m_validSets.end(); ++it) {
386 setName = *it;
387 if (H5Lexists(h5file, setName.c_str(), H5P_DEFAULT)) {
388 if (setName == "fq" || setName == "fq0" || setName == "fq2")
389 this->loadFQ(h5file, gws, setName, qvmod, sorting_indexes);
390 else if (setName == "fqt")
391 this->loadFQT(h5file, gws, setName, qvmod, sorting_indexes);
392 } else
393 this->g_log.information("Dataset " + setName + " not present in file");
394 } // end of iterate over the valid sets
395
396 H5Fclose(h5file);
397} // end of LoadSassena::exec()
398
399} // namespace Mantid::DataHandling
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
double left
Definition: LineProfile.cpp:80
double right
Definition: LineProfile.cpp:81
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
A property class for workspaces.
Load Sassena Output files.
Definition: LoadSassena.h:45
void loadFQT(const hid_t &h5file, const API::WorkspaceGroup_sptr &gws, const std::string &setName, const HistogramData::Points &qvmod, const std::vector< int > &sorting_indexes)
Load time-dependent structure factor.
std::string m_filename
name and path of input file
Definition: LoadSassena.h:89
HistogramData::Points loadQvectors(const hid_t &h5file, const API::WorkspaceGroup_sptr &gws, std::vector< int > &sorting_indexes)
Load qvectors dataset, calculate modulus of vectors.
std::vector< std::string > m_validSets
valid datasets
Definition: LoadSassena.h:87
void init() override
Initialization code.
void exec() override
Execution code.
void loadFQ(const hid_t &h5file, const API::WorkspaceGroup_sptr &gws, const std::string &setName, const HistogramData::Points &qvmod, const std::vector< int > &sorting_indexes)
Load structure factor asa function of q-vector modulus.
void registerWorkspace(const API::WorkspaceGroup_sptr &gws, const std::string &wsName, const DataObjects::Workspace2D_sptr &ws, const std::string &description)
Add a workspace to the group and register in the analysis data service.
Definition: LoadSassena.cpp:50
herr_t dataSetInfo(const hid_t &h5file, const std::string &setName, hsize_t *dims) const
Read info about one HDF5 dataset, log if error.
Definition: LoadSassena.cpp:64
herr_t dataSetDouble(const hid_t &h5file, const std::string &setName, std::vector< double > &buf)
Read dataset data to a buffer ot type double.
Definition: LoadSassena.cpp:80
Records the filename and the description of failure.
Definition: Exception.h:98
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::pair< double, int > mypair
Definition: LoadSassena.cpp:90
bool compare(const mypair &left, const mypair &right)
Definition: LoadSassena.cpp:91
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54