Mantid
Loading...
Searching...
No Matches
LoadILLTOF2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2019 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
9#include "MantidAPI/Axis.h"
13#include "MantidAPI/Run.h"
19
20#include <boost/algorithm/string/predicate.hpp>
21
22namespace {
24const std::array<std::string, 5> SUPPORTED_INSTRUMENTS = {{"IN4", "IN5", "IN6", "PANTHER", "SHARP"}};
25} // namespace
26
27namespace Mantid::DataHandling {
28
29using namespace Kernel;
30using namespace API;
31using namespace NeXus;
32using namespace HistogramData;
33
35
36
44int LoadILLTOF2::confidence(Kernel::NexusDescriptor &descriptor) const {
45
46 // fields existent only at the ILL
47 if (descriptor.pathExists("/entry0/wavelength") && descriptor.pathExists("/entry0/experiment_identifier") &&
48 descriptor.pathExists("/entry0/mode") && !descriptor.pathExists("/entry0/dataSD") // This one is for
49 // LoadILLIndirect
50 && !descriptor.pathExists("/entry0/instrument/VirtualChopper") // This one is for
51 // LoadILLReflectometry
52 && !descriptor.pathExists("/entry0/data_scan") // This one is handled by LoadILLDiffraction
53 && !descriptor.pathExists("/entry0/instrument/Tx") // This eliminates SALSA data
54 ) {
55 return 80;
56 } else {
57 return 0;
58 }
59}
60
62
67 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
68 "File path of the Data file to load");
69
70 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
71 "The name to use for the output workspace");
72 declareProperty("ConvertToTOF", false, "Convert the bin edges to time-of-flight", Direction::Input);
73}
74
79 // Retrieve filename
80 const std::string filenameData = getPropertyValue("Filename");
81 bool convertToTOF = getProperty("convertToTOF");
82
83 // open the root node
84 NeXus::NXRoot dataRoot(filenameData);
85 NXEntry dataFirstEntry = dataRoot.openFirstEntry();
86
87 loadInstrumentDetails(dataFirstEntry);
88 loadTimeDetails(dataFirstEntry);
89
90 const auto monitors = getMonitorInfo(dataFirstEntry);
91
92 initWorkSpace(dataFirstEntry, monitors);
93
96
97 runLoadInstrument(); // just to get IDF contents
98
99 loadDataIntoTheWorkSpace(dataFirstEntry, monitors, convertToTOF);
100
103
104 // load the instrument from the IDF if it exists
106
107 // Set the output workspace property
108 setProperty("OutputWorkspace", m_localWorkspace);
109}
110
118std::vector<std::vector<int>> LoadILLTOF2::getMonitorInfo(const NeXus::NXEntry &firstEntry) {
119
120 std::vector<std::vector<int>> monitorList;
121
122 for (std::vector<NXClassInfo>::const_iterator it = firstEntry.groups().begin(); it != firstEntry.groups().end();
123 ++it) {
124
125 if (it->nxclass == "NXmonitor" || boost::starts_with(it->nxname, "monitor")) {
126
127 g_log.debug() << "Load monitor data from " + it->nxname;
128
129 NXData dataGroup = firstEntry.openNXData(it->nxname + "/data");
130 NXInt data = dataGroup.openIntData();
131 // load the counts from the file into memory
132 data.load();
133
134 std::vector<int> thisMonitor(data(), data() + data.size());
135 monitorList.emplace_back(thisMonitor);
136 }
137 }
138 return monitorList;
139}
140
147
149
150 if (m_instrumentPath.empty()) {
151 throw std::runtime_error("Cannot set the instrument name from the Nexus file!");
152 }
153
155
156 if (std::find(SUPPORTED_INSTRUMENTS.begin(), SUPPORTED_INSTRUMENTS.end(), m_instrumentName) ==
157 SUPPORTED_INSTRUMENTS.end()) {
158 std::string message = "The instrument " + m_instrumentName + " is not valid for this loader!";
159 throw std::runtime_error(message);
160 }
161
162 // Monitor can be monitor (IN5, PANTHER) or monitor1 (IN6)
163 if (firstEntry.containsGroup("monitor"))
164 m_monitorName = "monitor";
165 else if (firstEntry.containsGroup("monitor1"))
166 m_monitorName = "monitor1";
167 else {
168 std::string message("Cannot find monitor[1] in the Nexus file!");
169 throw std::runtime_error(message);
170 }
171
172 g_log.debug() << "Instrument name set to: " + m_instrumentName << '\n';
173}
174
182void LoadILLTOF2::initWorkSpace(NeXus::NXEntry &entry, const std::vector<std::vector<int>> &monitors) {
183
184 // read in the data
185 NXData dataGroup = entry.openNXData("data");
186 NXInt data = dataGroup.openIntData();
187
188 m_numberOfTubes = static_cast<size_t>(data.dim0());
189 m_numberOfPixelsPerTube = static_cast<size_t>(data.dim1());
190 m_numberOfChannels = static_cast<size_t>(data.dim2());
191 const size_t numberOfMonitors = monitors.size();
192
196 size_t numberOfTubesInRosace = 0;
197 if (m_instrumentName == "IN4") {
198 NXData dataGroupRosace = entry.openNXData("instrument/Detector_Rosace/data");
199 NXInt dataRosace = dataGroupRosace.openIntData();
200 numberOfTubesInRosace += static_cast<size_t>(dataRosace.dim0());
201 }
202
203 // dim0 * m_numberOfPixelsPerTube is the total number of detectors
205
206 g_log.debug() << "NumberOfTubes: " << m_numberOfTubes << '\n';
207 g_log.debug() << "NumberOfPixelsPerTube: " << m_numberOfPixelsPerTube << '\n';
208 g_log.debug() << "NumberOfChannels: " << m_numberOfChannels << '\n';
209
210 // Now create the output workspace
211 // total number of spectra + number of monitors,
212 // bin boundaries = m_numberOfChannels + 1
213 // Z/time dimension
214 m_localWorkspace = WorkspaceFactory::Instance().create("Workspace2D", m_numberOfHistograms + numberOfMonitors,
216
217 NXClass monitor = entry.openNXGroup(m_monitorName);
218 if (monitor.containsDataSet("time_of_flight")) {
219 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
220 m_localWorkspace->setYUnitLabel("Counts");
221 } else {
222 g_log.debug("PANTHER diffraction mode");
223 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
224 m_localWorkspace->setYUnitLabel("Counts");
225 }
226}
227
234
235 m_wavelength = entry.getFloat("wavelength");
236
237 NeXus::NXClass monitorEntry = entry.openNXGroup(m_monitorName);
238
239 if (monitorEntry.containsDataSet("time_of_flight")) {
240
241 NXFloat time_of_flight_data = entry.openNXFloat(m_monitorName + "/time_of_flight");
242 time_of_flight_data.load();
243
244 // The entry "monitor/time_of_flight", has 3 fields:
245 // channel width , number of channels, Time of flight delay
246 m_channelWidth = time_of_flight_data[0];
247 m_timeOfFlightDelay = time_of_flight_data[2];
248
249 g_log.debug("Nexus Data:");
250 g_log.debug() << " ChannelWidth: " << m_channelWidth << '\n';
251 g_log.debug() << " TimeOfFlightDelay: " << m_timeOfFlightDelay << '\n';
252 g_log.debug() << " Wavelength: " << m_wavelength << '\n';
253 } // the other case is the diffraction mode for PANTHER, where nothing is
254 // needed here
255}
256
263void LoadILLTOF2::addAllNexusFieldsAsProperties(const std::string &filename) {
264
265 API::Run &runDetails = m_localWorkspace->mutableRun();
266
267 // Open NeXus file
268 NXhandle nxfileID;
269 NXstatus stat = NXopen(filename.c_str(), NXACC_READ, &nxfileID);
270
271 g_log.debug() << "Starting parsing properties from : " << filename << '\n';
272 if (stat == NX_ERROR) {
273 g_log.debug() << "convertNexusToProperties: Error loading " << filename;
274 throw Kernel::Exception::FileError("Unable to open File:", filename);
275 }
276 LoadHelper::addNexusFieldsToWsRun(nxfileID, runDetails);
277 NXclose(&nxfileID);
278 runDetails.addProperty("run_list", runDetails.getPropertyValueAsType<int>("run_number"));
279 g_log.debug() << "End parsing properties from : " << filename << '\n';
280}
281
287
288 API::Run &runDetails = m_localWorkspace->mutableRun();
289 const double ei = LoadHelper::calculateEnergy(m_wavelength);
290 runDetails.addProperty<double>("Ei", ei, true); // overwrite
291}
292
297 API::Run &runDetails = m_localWorkspace->mutableRun();
298 runDetails.addProperty("Facility", std::string("ILL"));
299}
300
305 API::Run &runDetails = m_localWorkspace->mutableRun();
306 double n_pulses = -1;
307 double fermiChopperSpeed = -1;
308
309 if (m_instrumentName == "IN4") {
310 fermiChopperSpeed = runDetails.getPropertyAsSingleValue("FC.rotation_speed");
311 const double bkgChopper1Speed = runDetails.getPropertyAsSingleValue("BC1.rotation_speed");
312 const double bkgChopper2Speed = runDetails.getPropertyAsSingleValue("BC2.rotation_speed");
313
314 if (std::abs(bkgChopper1Speed - bkgChopper2Speed) > 1) {
315 throw std::invalid_argument("Background choppers 1 and 2 have different speeds");
316 }
317
318 n_pulses = fermiChopperSpeed / bkgChopper1Speed / 4;
319 } else if (m_instrumentName == "IN6") {
320 fermiChopperSpeed = runDetails.getPropertyAsSingleValue("Fermi.rotation_speed");
321 const double suppressorSpeed = runDetails.getPropertyAsSingleValue("Suppressor.rotation_speed");
322
323 n_pulses = fermiChopperSpeed / suppressorSpeed;
324 } else {
325 return;
326 }
327
328 const double pulseInterval = 60.0 / (2 * fermiChopperSpeed) * n_pulses;
329 runDetails.addProperty<double>("pulse_interval", pulseInterval);
330}
331
340void LoadILLTOF2::loadDataIntoTheWorkSpace(NeXus::NXEntry &entry, const std::vector<std::vector<int>> &monitors,
341 bool convertToTOF) {
342
343 g_log.debug() << "Loading data into the workspace...\n";
344 // read in the data
345 NXData dataGroup = entry.openNXData("data");
346 NXInt data = dataGroup.openIntData();
347 // load the counts from the file into memory
348 data.load();
349
350 NXClass moni = entry.openNXGroup(m_monitorName);
351
352 // Put tof in an array
353 auto &X0 = m_localWorkspace->mutableX(0);
354 if (moni.containsDataSet("time_of_flight")) {
355 if (convertToTOF) {
356 for (size_t i = 0; i < m_numberOfChannels + 1; ++i) {
357 X0[i] = m_timeOfFlightDelay + m_channelWidth * static_cast<double>(i) +
358 m_channelWidth / 2; // to make sure the bin centre is positive
359 }
360 } else {
361 for (size_t i = 0; i < m_numberOfChannels + 1; ++i) {
362 X0[i] = static_cast<double>(i); // just take the channel index
363 }
364 }
365 } else {
366 // Diffraction PANTHER
367 X0[0] = m_wavelength * 0.9;
368 X0[1] = m_wavelength * 1.1;
369 }
370 // The binning for monitors is considered the same as for detectors
371 size_t spec = 0;
372
373 auto const &instrument = m_localWorkspace->getInstrument();
374
375 const std::vector<detid_t> detectorIDs = instrument->getDetectorIDs(true);
376
378
379 loadSpectra(spec, m_numberOfTubes, detectorIDs, data, progress);
380
381 g_log.debug() << "Loading detector data into the workspace: DONE!\n";
382
386 if (m_instrumentName == "IN4") {
387 g_log.debug() << "Loading data into the workspace: IN4 Rosace!\n";
388 // read in the data
389 NXData dataGroupRosace = entry.openNXData("instrument/Detector_Rosace/data");
390 NXInt dataRosace = dataGroupRosace.openIntData();
391 auto numberOfTubes = static_cast<size_t>(dataRosace.dim0());
392 // load the counts from the file into memory
393 dataRosace.load();
394
395 Progress progressRosace(this, 0.0, 1.0, numberOfTubes * m_numberOfPixelsPerTube);
396
397 loadSpectra(spec, numberOfTubes, detectorIDs, dataRosace, progressRosace);
398 }
399
400 const auto monitorIDs = instrument->getMonitors();
401
402 for (size_t i = 0; i < monitors.size(); ++i) {
403 const auto &monitor = monitors[i];
404 m_localWorkspace->setHistogram(spec, m_localWorkspace->binEdges(0), Counts(monitor.begin(), monitor.end()));
405 m_localWorkspace->getSpectrum(spec).setDetectorID(monitorIDs[i]);
406 spec++;
407 }
408}
409
420void LoadILLTOF2::loadSpectra(size_t &spec, const size_t numberOfTubes, const std::vector<detid_t> &detectorIDs,
421 const NXInt &data, Progress &progress) {
423 for (int i = 0; i < static_cast<int>(numberOfTubes); ++i) {
424 for (size_t j = 0; j < m_numberOfPixelsPerTube; ++j) {
425 const int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
426 const size_t currentSpectrum = spec + i * m_numberOfPixelsPerTube + j;
427 m_localWorkspace->setHistogram(currentSpectrum, m_localWorkspace->binEdges(0),
428 Counts(data_p, data_p + m_numberOfChannels));
429 m_localWorkspace->getSpectrum(currentSpectrum).setDetectorID(detectorIDs[currentSpectrum]);
430 progress.report();
431 }
432 }
433 spec += numberOfTubes * m_numberOfPixelsPerTube;
434}
435
440
441 auto loadInst = createChildAlgorithm("LoadInstrument");
442
443 loadInst->setPropertyValue("InstrumentName", m_instrumentName);
444 loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", m_localWorkspace);
445 loadInst->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(false));
446 loadInst->execute();
447}
448
449} // namespace Mantid::DataHandling
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#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.
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
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.
Definition: Algorithm.cpp:842
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
Defines an interface to an algorithm that loads a file so that it can take part in the automatic sele...
Definition: IFileLoader.h:19
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition: LogManager.h:79
double getPropertyAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic=Kernel::Math::Mean) const
Returns a property as a single double value from its name.
Definition: LogManager.cpp:349
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
Definition: LogManager.cpp:332
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:38
A property class for workspaces.
Loads an ILL IN4/5/6/Panther NeXus file into a Mantid workspace.
Definition: LoadILLTOF2.h:20
API::MatrixWorkspace_sptr m_localWorkspace
Definition: LoadILLTOF2.h:63
void loadTimeDetails(const NeXus::NXEntry &entry)
Load the time details from the nexus file.
void init() override
Initialises the algorithm.
Definition: LoadILLTOF2.cpp:66
void addEnergyToRun()
Calculates the incident energy from the wavelength and adds it as sample log 'Ei'.
void initWorkSpace(NeXus::NXEntry &entry, const std::vector< std::vector< int > > &)
Creates the workspace and initialises member variables with the corresponding values.
void loadInstrumentDetails(const NeXus::NXEntry &)
Sets the instrument name along with its path in the nexus file.
std::string m_instrumentPath
Name of the instrument path.
Definition: LoadILLTOF2.h:66
std::vector< std::vector< int > > getMonitorInfo(const NeXus::NXEntry &firstEntry)
Loads Monitor data into an vector of monitor data.
void loadDataIntoTheWorkSpace(NeXus::NXEntry &entry, const std::vector< std::vector< int > > &, bool convertToTOF)
Loads all the spectra into the workspace, including that from the monitor.
std::string m_instrumentName
Name of the instrument.
Definition: LoadILLTOF2.h:65
void addAllNexusFieldsAsProperties(const std::string &filename)
Goes through all the fields of the NeXus file and adds them as parameters in the workspace.
void loadSpectra(size_t &spec, const size_t numberOfTubes, const std::vector< Mantid::detid_t > &detectorIDs, const NeXus::NXInt &data, Mantid::API::Progress &progress)
Loops over all the pixels and loads the correct spectra.
void addPulseInterval()
Calculates and adds the pulse intervals for the run.
void addFacility()
Adds facility info to the sample logs.
void exec() override
Executes the algorithm.
Definition: LoadILLTOF2.cpp:78
void runLoadInstrument()
Runs LoadInstrument to attach the instrument to the workspace.
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 debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
OptionalBool : Tri-state bool.
Definition: OptionalBool.h:25
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).
Definition: NexusClasses.h:487
NXClass openNXGroup(const std::string &name) const
Creates and opens an arbitrary (non-standard) class (group).
Definition: NexusClasses.h:529
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
bool containsDataSet(const std::string &query) const
Returns whether an individual dataset is present.
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
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 size() const
Returns the size of the data buffer.
Definition: NexusClasses.h:267
int dim2() const
Returns the number of elements along the third dimension.
int dim0() const
Returns the number of elements along the first dimension.
int dim1() const
Returns the number of elements along the second dimension.
Implements NXdata Nexus class.
Definition: NexusClasses.h:795
NXInt openIntData()
Opens data of int type.
Definition: NexusClasses.h:828
Implements NXentry Nexus class.
Definition: NexusClasses.h:898
NXData openNXData(const std::string &name) const
Opens a NXData.
Definition: NexusClasses.h:912
Implements NXroot Nexus class.
Definition: NexusClasses.h:922
NXEntry openFirstEntry()
Open the first NXentry in the file.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
double calculateEnergy(double)
Calculate Neutron Energy from wavelength: .
Definition: LoadHelper.cpp:82
std::string getStringFromNexusPath(const Mantid::NeXus::NXEntry &, const std::string &)
Definition: LoadHelper.cpp:49
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
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
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
Definition: MultiThreaded.h:22
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54