Mantid
Loading...
Searching...
No Matches
LoadMLZ.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 +
8#include "MantidAPI/Axis.h"
11#include "MantidAPI/Progress.h"
13#include "MantidAPI/Sample.h"
24
25#include <algorithm>
26#include <cmath>
27#include <limits>
28#include <vector>
29
30namespace Mantid::DataHandling {
31
32using namespace Kernel;
33using namespace API;
34using namespace Nexus;
35using HistogramData::BinEdges;
36using HistogramData::Counts;
37
38// Register the algorithm into the AlgorithmFactory
40
41
44 : m_numberOfTubes{0}, m_numberOfPixelsPerTube{0}, m_numberOfChannels{0}, m_numberOfHistograms{0},
45 m_monitorElasticPeakPosition{0}, m_wavelength{0.0}, m_channelWidth{0.0}, m_timeOfFlightDelay{0.0},
46 m_monitorCounts{0}, m_chopper_speed{0.0}, m_chopper_ratio{0}, m_l1{0.0}, m_l2{0.0}, m_t1{0.0},
47 m_supportedInstruments{"TOFTOF", "DNS"} {}
48
50const std::string LoadMLZ::name() const { return "LoadMLZ"; }
51
53int LoadMLZ::version() const { return 1; }
54
56const std::string LoadMLZ::category() const { return "DataHandling\\Nexus"; }
57
61 const std::vector<std::string> exts{".nxs", ".hdf", ".hd5"};
62 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, exts),
63 "File path of the Data file to load");
64
65 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
66 "The name to use for the output workspace");
67}
68
72 // Retrieve filename
73 std::string filenameData = getPropertyValue("Filename");
74
75 // open the root node
76 Nexus::NXRoot dataRoot(filenameData);
77 NXEntry dataFirstEntry = dataRoot.openFirstEntry();
78
79 loadInstrumentDetails(dataFirstEntry);
80 loadTimeDetails(dataFirstEntry);
81
82 initWorkspace(dataFirstEntry);
83
84 // load the instrument from the IDF
87
88 loadDataIntoTheWorkSpace(dataFirstEntry);
89 loadRunDetails(dataFirstEntry); // must run after runLoadInstrument
90 loadExperimentDetails(dataFirstEntry);
91 maskDetectors(dataFirstEntry);
92
93 setProperty("OutputWorkspace", m_localWorkspace);
94}
95
103 // fields existent only at the MLZ
104 if (descriptor.isEntry("/Scan/wavelength") && descriptor.isEntry("/Scan/title") && descriptor.isEntry("/Scan/mode")) {
105 return 80;
106 } else {
107 return 0;
108 }
109}
110
115 // address to the pixel_mask
116 std::string pmaddress = "instrument/detector/pixel_mask";
117
118 Nexus::NXInt pmdata = entry.openNXInt(pmaddress);
119 // load the counts from the file into memory
120 pmdata.load();
121 g_log.debug() << "PMdata size: " << pmdata.size() << '\n';
122 std::vector<int> masked_detectors(pmdata(), pmdata() + pmdata.size());
123
124 g_log.debug() << "Number of masked detectors: " << masked_detectors.size() << '\n';
125
126 auto &detInfo = m_localWorkspace->mutableDetectorInfo();
127 std::vector<size_t> indicesToMask;
128 for (auto masked_detector : masked_detectors) {
129 g_log.debug() << "List of masked detectors: ";
130 g_log.debug() << masked_detector;
131 g_log.debug() << ", ";
132 try {
133 indicesToMask.emplace_back(detInfo.indexOf(masked_detector));
134 } catch (std::out_of_range &) {
135 g_log.warning() << "Invalid detector ID " << masked_detector << ". Found while running LoadMLZ\n";
136 }
137 }
138 g_log.debug() << '\n';
139
140 for (const auto index : indicesToMask)
141 detInfo.setMasked(index, true);
142}
143
148
150
151 if (m_instrumentAddress.empty()) {
152 throw std::runtime_error("Cannot set the instrument name from the Nexus file!");
153 }
154
156
157 if (std::find(m_supportedInstruments.begin(), m_supportedInstruments.end(), m_instrumentName) ==
159 std::string message = "The instrument " + m_instrumentName + " is not valid for this loader!";
160 throw std::runtime_error(message);
161 }
162
163 g_log.debug() << "Instrument name set to: " + m_instrumentName << '\n';
164}
165
173void LoadMLZ::initWorkspace(const Nexus::NXEntry &entry) //, const std::vector<std::vector<int> >&monitors)
174{
175 // read in the data
176 NXData dataGroup = entry.openNXData("data");
177 NXInt data = dataGroup.openIntData();
178
179 m_numberOfTubes = static_cast<size_t>(data.dim0());
180 m_numberOfPixelsPerTube = static_cast<size_t>(data.dim1());
181 m_numberOfChannels = static_cast<size_t>(data.dim2());
183
184 g_log.debug() << "NumberOfTubes: " << m_numberOfTubes << '\n';
185 g_log.debug() << "NumberOfPixelsPerTube: " << m_numberOfPixelsPerTube << '\n';
186 g_log.debug() << "NumberOfChannels: " << m_numberOfChannels << '\n';
187
188 // Now create the output workspace
191 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
192 m_localWorkspace->setYUnitLabel("Counts");
193}
194
200 // Read data from IDF: distance source-sample and distance sample-detectors
201 m_l1 = m_localWorkspace->spectrumInfo().l1();
202 m_l2 = m_localWorkspace->spectrumInfo().l2(1);
203
204 g_log.debug() << "L1: " << m_l1 << ", L2: " << m_l2 << '\n';
205}
206
212
213 m_wavelength = entry.getFloat("wavelength");
214
215 // Monitor can be monitor or Monitor
216 std::string monitorName;
217 if (entry.containsGroup("monitor"))
218 monitorName = "monitor";
219 else if (entry.containsGroup("Monitor"))
220 monitorName = "Monitor";
221 else {
222 std::string message("Cannot find monitor/Monitor in the Nexus file!");
223 g_log.error(message);
224 throw std::runtime_error(message);
225 }
226
227 m_monitorCounts = entry.getInt(monitorName + "/integral");
228
229 m_monitorElasticPeakPosition = entry.getInt(monitorName + "/elastic_peak");
230
231 NXFloat time_of_flight_data = entry.openNXFloat(monitorName + "/time_of_flight");
232 time_of_flight_data.load();
233
234 // The entry "monitor/time_of_flight", has 3 fields:
235 // channel width [microseconds], number of channels, Time of flight delay
236 m_channelWidth = time_of_flight_data[0] * 50.e-3;
237 m_timeOfFlightDelay = time_of_flight_data[2] * 50.e-3;
238
239 g_log.debug("Nexus Data:");
240 g_log.debug() << " MonitorCounts: " << m_monitorCounts << '\n';
241 g_log.debug() << " ChannelWidth (microseconds): " << m_channelWidth << '\n';
242 g_log.debug() << " Wavelength (angstroems): " << m_wavelength << '\n';
243 g_log.debug() << " ElasticPeakPosition: " << m_monitorElasticPeakPosition << '\n';
244 g_log.debug() << " TimeOfFlightDelay (microseconds): " << m_timeOfFlightDelay << '\n';
245
246 m_chopper_speed = entry.getFloat("instrument/chopper/rotation_speed");
247
248 m_chopper_ratio = entry.getInt("instrument/chopper/ratio");
249
250 g_log.debug() << " ChopperSpeed: " << m_chopper_speed << '\n';
251 g_log.debug() << " ChopperRatio: " << m_chopper_ratio << '\n';
252}
253
262
263 API::Run &runDetails = m_localWorkspace->mutableRun();
264
265 std::string runNum = entry.getString("entry_identifier"); // run_number");
266 std::string run_num = boost::lexical_cast<std::string>(runNum);
267 runDetails.addProperty("run_number", run_num);
268
269 std::string start_time = entry.getString("start_time");
270 runDetails.addProperty("run_start", start_time);
271
272 std::string end_time = entry.getString("end_time");
273 runDetails.addProperty("run_end", end_time);
274
275 runDetails.addProperty("wavelength", m_wavelength, "Angstrom", true);
276
278 runDetails.addProperty<double>("Ei", ei, "meV", true); // overwrite
279
280 int duration = entry.getInt("duration");
281 runDetails.addProperty("duration", duration, "Seconds", true);
282
283 std::string mode = entry.getString("mode");
284 runDetails.addProperty("mode", mode);
285
286 std::string title = entry.getString("title");
287 m_localWorkspace->setTitle(title);
288
289 // Check if temperature is defined
290 NXClass sample = entry.openNXGroup("sample");
291 if (sample.containsDataSet("temperature")) {
292 double temperature = entry.getFloat("sample/temperature");
293 runDetails.addProperty("temperature", temperature, "K", true);
294 }
295
296 runDetails.addProperty("monitor_counts", static_cast<double>(m_monitorCounts));
297 runDetails.addProperty("chopper_speed", m_chopper_speed);
298 runDetails.addProperty("chopper_ratio", m_chopper_ratio);
299 runDetails.addProperty("channel_width", m_channelWidth, "microseconds", true);
300
301 // Calculate number of full time channels - use to crop workspace - S. Busch's
302 // method
303 double full_channels =
304 floor(30. * m_chopper_ratio / (m_chopper_speed) * 1.e6 / m_channelWidth); // channelWidth in microsec.
305 runDetails.addProperty("full_channels", full_channels);
306
307 // Proposal title
308 std::string proposal_title = entry.getString("proposal");
309 runDetails.addProperty("proposal_title", proposal_title);
310
311 // proposal number
312 std::string proposal_number = entry.getString("proposal_number");
313 runDetails.addProperty("proposal_number", proposal_number);
314
315 // users
316 std::string user_name = entry.getString("user2/name");
317 runDetails.addProperty("experiment_team", user_name);
318
319 runDetails.addProperty("EPP", m_monitorElasticPeakPosition);
320 runDetails.addProperty("TOF1", m_t1, "microseconds", true);
321
322 // set instrument parameter Efixed, catch error, but don't stop
323 try {
324 auto setPar = createChildAlgorithm("SetInstrumentParameter");
325 setPar->setProperty<MatrixWorkspace_sptr>("Workspace", m_localWorkspace);
326 setPar->setProperty("ParameterName", "Efixed");
327 setPar->setProperty("ParameterType", "Number");
328 setPar->setProperty("Value", std::to_string(ei));
329 setPar->execute();
330 } catch (...) {
331 g_log.warning("Cannot set the instrument parameter Efixed.");
332 }
333}
334
343 // TODO: Do the rest
344 // Pick out the geometry information
345
346 std::string description = boost::lexical_cast<std::string>(entry.getFloat("sample/description"));
347
348 m_localWorkspace->mutableSample().setName(description);
349}
350
357 // read in the data
358 NXData dataGroup = entry.openNXData("data");
359 NXInt data = dataGroup.openIntData();
360 data.load();
361
363 g_log.debug() << " t1 (microseconds): " << m_t1 << '\n';
364
365 std::vector<double> detectorTofBins(m_numberOfChannels + 1);
366 for (size_t i = 0; i < m_numberOfChannels + 1; ++i) {
367 detectorTofBins[i] = m_channelWidth * static_cast<double>(static_cast<int>(i)) + m_t1 + m_channelWidth / 2;
368 }
369
370 // Assign calculated bins to first X axis
371 BinEdges edges(std::move(detectorTofBins));
372
374 size_t spec = 0;
375 for (size_t i = 0; i < m_numberOfTubes; ++i) {
376 for (size_t j = 0; j < m_numberOfPixelsPerTube; ++j) {
377 // Assign Y
378 int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
379
380 m_localWorkspace->setHistogram(spec, edges, Counts(data_p, data_p + m_numberOfChannels));
381
382 ++spec;
383 progress.report();
384 }
385 }
386}
387
392 auto loadInst = createChildAlgorithm("LoadInstrument");
393
394 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
395 try {
396 loadInst->setPropertyValue("InstrumentName", m_instrumentName);
397 g_log.debug() << "InstrumentName" << m_instrumentName << '\n';
398 loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", m_localWorkspace);
399 loadInst->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(true));
400 loadInst->execute();
401 } catch (...) {
402 g_log.warning("Cannot load the instrument definition.");
403 }
404}
405
406} // namespace Mantid::DataHandling
std::map< DeltaEMode::Type, std::string > index
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
@ Load
allowed here which will be passed to the algorithm
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:91
Helper class for reporting progress from algorithms.
Definition Progress.h:25
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
A property class for workspaces.
LoadMLZ : Loads MLZ nexus or hdf file into a Mantid workspace.
Definition LoadMLZ.h:22
void loadExperimentDetails(const Nexus::NXEntry &entry)
Load data about the Experiment.
Definition LoadMLZ.cpp:342
std::string m_instrumentAddress
Name of the instrument address.
Definition LoadMLZ.h:59
API::MatrixWorkspace_sptr m_localWorkspace
Definition LoadMLZ.h:56
void exec() override
Execute the algorithm.
Definition LoadMLZ.cpp:71
void loadDataIntoTheWorkSpace(const Nexus::NXEntry &entry)
Loads all the spectra into the workspace, including that from the monitor.
Definition LoadMLZ.cpp:356
int confidence(Nexus::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
Definition LoadMLZ.cpp:102
std::string m_instrumentName
Name of the instrument.
Definition LoadMLZ.h:58
void loadRunDetails(Nexus::NXEntry &entry)
Load information about the run.
Definition LoadMLZ.cpp:261
const std::string name() const override
Algorithm's name for identification.
Definition LoadMLZ.cpp:50
void loadTimeDetails(const Nexus::NXEntry &entry)
Load the time details from the nexus file.
Definition LoadMLZ.cpp:211
int version() const override
Algorithm's version for identification.
Definition LoadMLZ.cpp:53
void initInstrumentSpecific()
Function to do specific instrument stuff.
Definition LoadMLZ.cpp:199
void maskDetectors(const Nexus::NXEntry &entry)
Loads Masked detectors from the /Scan/instrument/Detector/pixel_mask.
Definition LoadMLZ.cpp:114
void initWorkspace(const Nexus::NXEntry &entry)
Creates the workspace and initialises member variables with the corresponding values.
Definition LoadMLZ.cpp:173
void loadInstrumentDetails(const Nexus::NXEntry &)
Set the instrument name along with its address on the nexus file.
Definition LoadMLZ.cpp:147
void init() override
Initialize the algorithm's properties.
Definition LoadMLZ.cpp:60
void runLoadInstrument()
Run the Child Algorithm LoadInstrument.
Definition LoadMLZ.cpp:391
std::vector< std::string > m_supportedInstruments
Definition LoadMLZ.h:81
const std::string category() const override
Algorithm's category for identification.
Definition LoadMLZ.cpp:56
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
OptionalBool : Tri-state bool.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
The base class for a Nexus class (group).
float getFloat(const std::string &name) const
Returns a float.
std::string getString(const std::string &name) const
Returns a string.
bool containsGroup(const std::string &query) const
Returns whether an individual group (or group) is present.
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
NXClass openNXGroup(const std::string &name) const
Creates and opens an arbitrary (non-standard) class (group).
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
bool containsDataSet(const std::string &query) const
Returns whether an individual dataset is present.
int32_t getInt(const std::string &name) const
Returns a int.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
std::size_t size() const
Returns the size of the data buffer.
dimsize_t dim0() const
Returns the number of elements along the first dimension.
dimsize_t dim2() const
Returns the number of elements along the third dimension.
dimsize_t dim1() const
Returns the number of elements along the second dimension.
Implements NXdata Nexus class.
NXInt openIntData()
Opens data of int type.
Implements NXentry Nexus class.
NXData openNXData(const std::string &name) const
Opens a NXData.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
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.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string getStringFromNexusAddress(const Mantid::Nexus::NXEntry &, const std::string &)
double calculateEnergy(double)
Calculate Neutron Energy from wavelength: .
double calculateTOF(double, double)
Calculate TOF from distance.
std::string findInstrumentNexusAddress(const Mantid::Nexus::NXEntry &)
Finds the address for the instrument name in the nexus file Usually of the form: entry0/<NXinstrument...
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.
Definition Property.h:54