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"
18#include "MantidLegacyNexus/NeXusException.hpp"
19#include "MantidLegacyNexus/NeXusFile.hpp"
20#include "MantidLegacyNexus/NexusClasses.h"
21
22namespace {
24const std::array<std::string, 5> SUPPORTED_INSTRUMENTS = {{"IN4", "IN5", "IN6", "PANTHER", "SHARP"}};
25
27Mantid::Kernel::Logger legacyhelperlog("LegacyLoadHelper");
28
29const std::string NXINSTRUMENT("NXinstrument");
30const std::string SDS("SDS"); // denotes data field
31const std::string EMPTY_STR("");
32
33} // namespace
34
35namespace Mantid::DataHandling {
36
37using namespace Kernel;
38using namespace API;
39using namespace HistogramData;
40
42
43namespace LegacyLoadHelper { // these methods are copied from LoadHelper
48std::string findInstrumentNexusAddress(const LegacyNexus::NXEntry &firstEntry) {
49 std::string result("");
50 std::vector<LegacyNexus::NXClassInfo> v = firstEntry.groups();
51 const auto it = std::find_if(v.cbegin(), v.cend(), [](const auto &group) { return group.nxclass == NXINSTRUMENT; });
52 if (it != v.cend())
53 result = it->nxname;
54
55 return result;
56}
57
64LegacyNexus::NXInt getIntDataset(const LegacyNexus::NXEntry &entry, const std::string &groupName) {
65 auto dataGroup = entry.openNXData(groupName);
66 return dataGroup.openIntData();
67}
68
75LegacyNexus::NXDouble getDoubleDataset(const LegacyNexus::NXEntry &entry, const std::string &groupName) {
76 auto dataGroup = entry.openNXData(groupName);
77 return dataGroup.openDoubleData();
78}
79
94void fillStaticWorkspace(const API::MatrixWorkspace_sptr &ws, const LegacyNexus::NXInt &data,
95 const std::vector<double> &xAxis, int64_t initialSpectrum = 0, bool pointData = false,
96 const std::vector<int> &detectorIDs = std::vector<int>(),
97 const std::set<int> &acceptedDetectorIDs = std::set<int>(),
98 const std::tuple<short, short, short> &axisOrder = std::tuple<short, short, short>(0, 1, 2)) {
99 const bool customDetectorIDs = detectorIDs.size() != 0;
100 const bool excludeDetectorIDs = acceptedDetectorIDs.size() != 0;
101
102 std::array dims = {data.dim0(), data.dim1(), data.dim2()};
103 const auto nTubes = dims[std::get<0>(axisOrder)];
104 const auto nPixels = dims[std::get<1>(axisOrder)];
105 const auto nChannels = dims[std::get<2>(axisOrder)];
106
107 int loadOrder[3] = {0, 1, 2};
108 LoadHelper::loadingOrder(axisOrder, loadOrder);
109
110 HistogramData::Points histoPoints;
111 HistogramData::BinEdges binEdges;
112 if (pointData)
113 histoPoints = HistogramData::Points(xAxis);
114 else
115 binEdges = HistogramData::BinEdges(xAxis);
116 int nSkipped = 0;
117
118#pragma omp parallel for if (!excludeDetectorIDs && Kernel::threadSafe(*ws))
119 for (specnum_t tube_no = 0; tube_no < static_cast<specnum_t>(nTubes); ++tube_no) {
120 for (specnum_t pixel_no = 0; pixel_no < nPixels; ++pixel_no) {
121 specnum_t currentSpectrum =
122 static_cast<specnum_t>(initialSpectrum) + tube_no * static_cast<specnum_t>(nPixels) + pixel_no;
123 if (excludeDetectorIDs != 0 && std::find(acceptedDetectorIDs.cbegin(), acceptedDetectorIDs.cend(),
124 currentSpectrum) == acceptedDetectorIDs.end()) {
125 nSkipped++;
126 continue;
127 }
128 currentSpectrum -= nSkipped;
129
130 std::vector<int> spectrum(nChannels);
131 for (auto channel_no = 0; channel_no < nChannels; ++channel_no) {
132 const int dataIndices[3] = {tube_no, pixel_no, channel_no};
133 spectrum[channel_no] = data(dataIndices[loadOrder[0]], dataIndices[loadOrder[1]], dataIndices[loadOrder[2]]);
134 }
135 const HistogramData::Counts counts(spectrum.begin(), spectrum.end());
136 const HistogramData::CountVariances countVariances(spectrum.begin(), spectrum.end());
137 if (pointData) {
138 ws->setCounts(currentSpectrum, counts);
139 ws->setCountVariances(currentSpectrum, countVariances);
140 ws->setPoints(currentSpectrum, histoPoints);
141 } else {
142 ws->setHistogram(currentSpectrum, binEdges, counts);
143 }
144 const specnum_t detectorID = customDetectorIDs ? detectorIDs[currentSpectrum] : currentSpectrum;
145 ws->getSpectrum(currentSpectrum).setSpectrumNo(detectorID);
146 }
147 }
148}
149
150template <typename NumericType>
151void addNumericProperty(LegacyNexus::File &filehandle, const LegacyNexus::Info &nxinfo,
152 const std::string &property_name, API::Run &runDetails) {
153 if (!runDetails.hasProperty(property_name)) {
154 legacyhelperlog.warning() << "Property " << property_name
155 << " was set twice. Please check the Nexus file and your inputs.";
156 }
157 // this assumes all values are rank==1
158
159 // Look for "units"
160 std::string units; // empty string
161 if (filehandle.hasAttr("units"))
162 filehandle.getAttr("units", units);
163
164 // read the field
165 std::vector<NumericType> data_vec;
166 data_vec.reserve(nxinfo.dims.front());
167 filehandle.getDataCoerce(data_vec);
168
169 // create the property on the run objects
170 const auto dim1size = data_vec.size();
171 if (dim1size == 1) {
172 if (units.empty())
173 runDetails.addProperty(property_name, data_vec.front());
174 else
175 runDetails.addProperty(property_name, data_vec.front(), units);
176 } else {
177 // create a bunch of little properties
178 for (size_t index = 0; index < dim1size; ++index) {
179 const auto property_name_indexed = property_name + "_" + std::to_string(index);
180 if (units.empty())
181 runDetails.addProperty(property_name_indexed, data_vec[index]);
182 else
183 runDetails.addProperty(property_name_indexed, data_vec[index], units);
184 }
185 }
186}
187
197void recurseAndAddNexusFieldsToWsRun(LegacyNexus::File &filehandle, API::Run &runDetails,
198 const std::string &parent_name, const std::string &parent_class, int level) {
199 for (const auto &entry : filehandle.getEntries()) {
200 const auto nxname = entry.first;
201 const auto nxclass = entry.second;
202 if (nxclass == SDS) {
203 if ((parent_class != "NXData") && parent_class != "NXMonitor" && (nxname != "data")) { // create a property
204 filehandle.openData(nxname);
205 const auto nxinfo = filehandle.getInfo(); // get information about the open data
206 const auto rank = nxinfo.dims.size();
207
208 // Note, we choose to only build properties on small float arrays filter logic is below
209 bool read_property = (rank == 1);
210 switch (nxinfo.type) {
211 case (LegacyNexus::NXnumtype::CHAR):
212 break; // everything is fine
213 case (LegacyNexus::NXnumtype::FLOAT32):
214 case (LegacyNexus::NXnumtype::FLOAT64):
215 // some 1d float arrays may be loaded
216 read_property = (nxinfo.dims[0] <= 9);
217 break;
218 case (LegacyNexus::NXnumtype::INT16):
219 case (LegacyNexus::NXnumtype::INT32):
220 case (LegacyNexus::NXnumtype::UINT16):
221 // only read scalar values for everything else - e.g. integers
222 read_property = (nxinfo.dims.front() == 1);
223 break;
224 default:
225 read_property = false;
226 }
227
228 if (read_property) {
229 // generate a name for the property
230 const std::string property_name = (parent_name.empty() ? nxname : parent_name + "." + nxname);
231
232 switch (nxinfo.type) {
233 case (LegacyNexus::NXnumtype::CHAR): {
234 std::string property_value = filehandle.getStrData();
235 if (property_name.ends_with("_time")) {
236 // That's a time value! Convert to Mantid standard
237 property_value = LoadHelper::dateTimeInIsoFormat(property_value);
238 if (runDetails.hasProperty(property_name))
239 runDetails.getProperty(property_name)->setValue(property_value);
240 else
241 runDetails.addProperty(property_name, property_value);
242 } else {
243 if (!runDetails.hasProperty(property_name)) {
244 runDetails.addProperty(property_name, property_value);
245 } else {
246 legacyhelperlog.warning()
247 << "Property " << property_name << " was set twice. Please check the Nexus file and your inputs.\n";
248 }
249 }
250 break;
251 }
252 case (LegacyNexus::NXnumtype::FLOAT32):
253 case (LegacyNexus::NXnumtype::FLOAT64):
254 addNumericProperty<double>(filehandle, nxinfo, property_name, runDetails);
255 break;
256 case (LegacyNexus::NXnumtype::INT16):
257 case (LegacyNexus::NXnumtype::INT32):
258 case (LegacyNexus::NXnumtype::UINT16):
259 addNumericProperty<int>(filehandle, nxinfo, property_name, runDetails);
260 break;
261 default:
262 std::stringstream msg;
263 msg << "Encountered unknown type: " << static_cast<int>(nxinfo.type);
264 throw std::runtime_error(msg.str());
265 break;
266 }
267 }
268 filehandle.closeData();
269 }
270 } else {
271 if ((nxclass != "ILL_data_scan_vars") && (nxclass != "NXill_data_scan_vars")) {
272 // open the group and recurse down, if the group is known to nexus
273 filehandle.openGroup(nxname, nxclass);
274
275 // current names can be useful for next level
276 recurseAndAddNexusFieldsToWsRun(filehandle, runDetails, nxname, nxclass, level + 1);
277
278 filehandle.closeGroup();
279 }
280 }
281 }
282}
283
291void addNexusFieldsToWsRun(LegacyNexus::File &filehandle, API::Run &runDetails) {
292 // As a workaround against some "not so good" old ILL nexus files (ILLIN5_Vana_095893.nxs for example) by default we
293 // begin the parse on the first entry (entry0), or from a chosen entryName. This allow to avoid the bogus entries that
294 // follows
295 std::string entryNameActual("");
296 try {
297 const auto entryNameAndClass = filehandle.getNextEntry();
298 entryNameActual = entryNameAndClass.first;
299 } catch (const LegacyNexus::Exception &) { /* ignore */
300 }
301
302 // open the group and parse down
303 if (!entryNameActual.empty()) {
304 constexpr int LEVEL_RECURSE{1};
305 filehandle.openGroup(entryNameActual, "NXentry");
306 recurseAndAddNexusFieldsToWsRun(filehandle, runDetails, EMPTY_STR, EMPTY_STR, LEVEL_RECURSE);
307 filehandle.closeGroup();
308 }
309}
310
311} // namespace LegacyLoadHelper
312
322
323 // fields existent only at the ILL
324 if ((descriptor.pathExists("/entry0/wavelength") && descriptor.pathExists("/entry0/experiment_identifier") &&
325 descriptor.pathExists("/entry0/mode") && !descriptor.pathExists("/entry0/dataSD") // This one is for
326 // LoadILLIndirect
327 && !descriptor.pathExists("/entry0/instrument/VirtualChopper") // This one is for
328 // LoadILLReflectometry
329 && !descriptor.pathExists("/entry0/instrument/Tx")) // This eliminates SALSA data
330 || (descriptor.pathExists("/entry0/data_scan") &&
331 descriptor.pathExists("/entry0/instrument/Detector")) // The last one is scan mode of PANTHER and SHARP
332 ) {
333 return 79; // return 79 since LoadILLTOF3 will return 80 if file is hdf5 based
334 } else {
335 return 0;
336 }
337}
338
340
345 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
346 "File path of the Data file to load");
347
348 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
349 "The name to use for the output workspace");
350 declareProperty("ConvertToTOF", false, "Convert the bin edges to time-of-flight", Direction::Input);
351}
352
357 // Retrieve filename
358 const std::string filenameData = getPropertyValue("Filename");
359 bool convertToTOF = getProperty("convertToTOF");
360
361 // open the root node
362 LegacyNexus::NXRoot dataRoot(filenameData);
363 LegacyNexus::NXEntry dataFirstEntry = dataRoot.openFirstEntry();
364 m_isScan = dataFirstEntry.containsGroup("data_scan");
365
366 loadInstrumentDetails(dataFirstEntry);
367 loadTimeDetails(dataFirstEntry);
368
369 const auto monitorList = getMonitorInfo(dataFirstEntry);
370 initWorkspace(dataFirstEntry);
371
372 addAllNexusFieldsAsProperties(filenameData);
373 addFacility();
374 // load the instrument from the IDF if it exists
376
377 if (m_isScan) {
378 fillScanWorkspace(dataFirstEntry, monitorList);
379 } else {
380 fillStaticWorkspace(dataFirstEntry, monitorList, convertToTOF);
381 }
384
385 // Set the output workspace property
386 setProperty("OutputWorkspace", m_localWorkspace);
387}
388
396std::vector<std::string> LoadILLTOF2::getMonitorInfo(const LegacyNexus::NXEntry &firstEntry) {
397 std::vector<std::string> monitorList;
398 if (m_isScan) {
399 // in case of a scan, there is only one monitor and its data are stored per scan step
400 // in "data_scan/scanned_variables/data", if that changes, a search for the "monitor" name
401 // may be required in the "data_scan/scanned_variables/variables_names"
402 monitorList.push_back("data_scan/scanned_variables/data");
403 } else {
404 for (std::vector<LegacyNexus::NXClassInfo>::const_iterator it = firstEntry.groups().begin();
405 it != firstEntry.groups().end(); ++it) {
406 if (it->nxclass == "NXmonitor" || it->nxname.starts_with("monitor")) {
407 monitorList.push_back(it->nxname + "/data");
408 }
409 }
410 }
411 m_numberOfMonitors = monitorList.size();
412 return monitorList;
413}
414
420void LoadILLTOF2::loadInstrumentDetails(const LegacyNexus::NXEntry &firstEntry) {
421
423
424 if (m_instrumentAddress.empty()) {
425 throw std::runtime_error("Cannot set the instrument name from the Nexus file!");
426 }
427
428 m_instrumentName = firstEntry.getString(m_instrumentAddress + "/name");
429
430 if (std::find(SUPPORTED_INSTRUMENTS.begin(), SUPPORTED_INSTRUMENTS.end(), m_instrumentName) ==
431 SUPPORTED_INSTRUMENTS.end()) {
432 std::string message = "The instrument " + m_instrumentName + " is not valid for this loader!";
433 throw std::runtime_error(message);
434 }
435
436 // Monitor can be monitor (IN5, PANTHER) or monitor1 (IN6)
437 if (firstEntry.containsGroup("monitor"))
438 m_monitorName = "monitor";
439 else if (firstEntry.containsGroup("monitor1"))
440 m_monitorName = "monitor1";
441 else {
442 std::string message("Cannot find monitor[1] in the Nexus file!");
443 throw std::runtime_error(message);
444 }
445
446 g_log.debug() << "Instrument name set to: " + m_instrumentName << '\n';
447}
448
455void LoadILLTOF2::initWorkspace(const LegacyNexus::NXEntry &entry) {
456
457 // read in the data
458 const std::string dataName = m_isScan ? "data_scan/detector_data/data" : "data";
459 auto data = LegacyLoadHelper::getIntDataset(entry, dataName);
460
461 // default order is: tubes - pixels - channels, but for scans it is scans - tubes - pixels
462 m_numberOfTubes = static_cast<size_t>(m_isScan ? data.dim1() : data.dim0());
463 m_numberOfPixelsPerTube = static_cast<size_t>(m_isScan ? data.dim2() : data.dim1());
464 m_numberOfChannels = static_cast<size_t>(m_isScan ? data.dim0() : data.dim2());
465
469 size_t numberOfTubesInRosace = 0;
470 if (m_instrumentName == "IN4") {
471 auto dataRosace = LegacyLoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data");
472 numberOfTubesInRosace += static_cast<size_t>(dataRosace.dim0());
473 }
474
475 // dim0 * m_numberOfPixelsPerTube is the total number of detectors
477
478 g_log.debug() << "NumberOfTubes: " << m_numberOfTubes << '\n';
479 g_log.debug() << "NumberOfPixelsPerTube: " << m_numberOfPixelsPerTube << '\n';
480 g_log.debug() << "NumberOfChannels: " << m_numberOfChannels << '\n';
481
482 // Now create the output workspace
483 // total number of spectra + number of monitors,
484 // bin boundaries = m_numberOfChannels + 1 if diffraction or TOF mode, m_numberOfChannels for scans
485 // Z/time dimension
486 const auto numberOfChannels = m_isScan ? m_numberOfChannels : m_numberOfChannels + 1;
488 numberOfChannels, m_numberOfChannels);
489 if (m_isScan) {
490 m_localWorkspace->setYUnitLabel("Counts");
491 } else {
492 LegacyNexus::NXClass monitor = entry.openNXGroup(m_monitorName);
493 if (monitor.containsDataSet("time_of_flight")) {
494 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
495 m_localWorkspace->setYUnitLabel("Counts");
496 } else {
497 g_log.debug("PANTHER diffraction mode");
498 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
499 m_localWorkspace->setYUnitLabel("Counts");
500 }
501 }
502}
503
509void LoadILLTOF2::loadTimeDetails(const LegacyNexus::NXEntry &entry) {
510
511 m_wavelength = entry.getFloat("wavelength");
512
513 LegacyNexus::NXClass monitorEntry = entry.openNXGroup(m_monitorName);
514
515 if (monitorEntry.containsDataSet("time_of_flight")) {
516
517 LegacyNexus::NXFloat time_of_flight_data = entry.openNXFloat(m_monitorName + "/time_of_flight");
518 time_of_flight_data.load();
519
520 // The entry "monitor/time_of_flight", has 3 fields:
521 // channel width , number of channels, Time of flight delay
522 m_channelWidth = time_of_flight_data[0];
523 m_timeOfFlightDelay = time_of_flight_data[2];
524
525 g_log.debug("Nexus Data:");
526 g_log.debug() << " ChannelWidth: " << m_channelWidth << '\n';
527 g_log.debug() << " TimeOfFlightDelay: " << m_timeOfFlightDelay << '\n';
528 g_log.debug() << " Wavelength: " << m_wavelength << '\n';
529 } // the other case is the diffraction mode for PANTHER, where nothing is
530 // needed here
531}
532
539void LoadILLTOF2::addAllNexusFieldsAsProperties(const std::string &filename) {
540
541 API::Run &runDetails = m_localWorkspace->mutableRun();
542
543 // Open NeXus file
544 try {
545 LegacyNexus::File nxfileID(filename, LegacyNexus::NXACC_READ);
546 LegacyLoadHelper::addNexusFieldsToWsRun(nxfileID, runDetails);
547 } catch (const LegacyNexus::Exception &) {
548 g_log.debug() << "convertNexusToProperties: Error loading " << filename;
549 throw Kernel::Exception::FileError("Unable to open File:", filename);
550 }
551
552 runDetails.addProperty("run_list", runDetails.getPropertyValueAsType<int>("run_number"));
553 g_log.debug() << "End parsing properties from : " << filename << '\n';
554}
555
561
562 API::Run &runDetails = m_localWorkspace->mutableRun();
563 const double ei = LoadHelper::calculateEnergy(m_wavelength);
564 runDetails.addProperty<double>("Ei", ei, true); // overwrite
565}
566
571 API::Run &runDetails = m_localWorkspace->mutableRun();
572 runDetails.addProperty("Facility", std::string("ILL"));
573}
574
579 API::Run &runDetails = m_localWorkspace->mutableRun();
580 double n_pulses = -1;
581 double fermiChopperSpeed = -1;
582
583 if (m_instrumentName == "IN4") {
584 fermiChopperSpeed = runDetails.getPropertyAsSingleValue("FC.rotation_speed");
585 const double bkgChopper1Speed = runDetails.getPropertyAsSingleValue("BC1.rotation_speed");
586 const double bkgChopper2Speed = runDetails.getPropertyAsSingleValue("BC2.rotation_speed");
587
588 if (std::abs(bkgChopper1Speed - bkgChopper2Speed) > 1) {
589 throw std::invalid_argument("Background choppers 1 and 2 have different speeds");
590 }
591
592 n_pulses = fermiChopperSpeed / bkgChopper1Speed / 4;
593 } else if (m_instrumentName == "IN6") {
594 fermiChopperSpeed = runDetails.getPropertyAsSingleValue("Fermi.rotation_speed");
595 const double suppressorSpeed = runDetails.getPropertyAsSingleValue("Suppressor.rotation_speed");
596
597 n_pulses = fermiChopperSpeed / suppressorSpeed;
598 } else {
599 return;
600 }
601
602 const double pulseInterval = 60.0 / (2 * fermiChopperSpeed) * n_pulses;
603 runDetails.addProperty<double>("pulse_interval", pulseInterval);
604}
605
612std::vector<double> LoadILLTOF2::prepareAxis(const LegacyNexus::NXEntry &entry, bool convertToTOF) {
613
614 std::vector<double> xAxis(m_localWorkspace->readX(0).size());
615 if (m_isScan) {
616 // read which variable is going to be the axis
617 LegacyNexus::NXInt scannedAxis = entry.openNXInt("data_scan/scanned_variables/variables_names/axis");
618 scannedAxis.load();
619 int scannedVarId = 0;
620 for (int index = 0; index < scannedAxis.dim0(); index++) {
621 if (scannedAxis[index] == 1) {
622 scannedVarId = index;
623 break;
624 }
625 }
626 auto axis = LegacyLoadHelper::getDoubleDataset(entry, "data_scan/scanned_variables/data");
627 axis.load();
628 for (int index = 0; index < axis.dim1(); index++) {
629 xAxis[index] = axis(scannedVarId, index);
630 }
631 } else {
632 LegacyNexus::NXClass moni = entry.openNXGroup(m_monitorName);
633 if (moni.containsDataSet("time_of_flight")) {
634 if (convertToTOF) {
635 for (size_t i = 0; i < m_numberOfChannels + 1; ++i) {
636 xAxis[i] = m_timeOfFlightDelay + m_channelWidth * static_cast<double>(i) +
637 m_channelWidth / 2; // to make sure the bin centre is positive
638 }
639 } else {
640 for (size_t i = 0; i < m_numberOfChannels + 1; ++i) {
641 xAxis[i] = static_cast<double>(i); // just take the channel index
642 }
643 }
644 } else {
645 // Diffraction PANTHER
646 xAxis[0] = m_wavelength * 0.9;
647 xAxis[1] = m_wavelength * 1.1;
648 }
649 }
650 return xAxis;
651}
652
661void LoadILLTOF2::fillStaticWorkspace(const LegacyNexus::NXEntry &entry, const std::vector<std::string> &monitorList,
662 bool convertToTOF) {
663
664 g_log.debug() << "Loading data into the workspace...\n";
665
666 // Prepare X-axis array
667 auto xAxis = prepareAxis(entry, convertToTOF);
668
669 // The binning for monitors is considered the same as for detectors
670 int64_t spec = 0;
671 std::vector<int> detectorIDs = m_localWorkspace->getInstrument()->getDetectorIDs(false);
672
673 auto data = LegacyLoadHelper::getIntDataset(entry, "data");
674 data.load();
675
676 LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, spec, false, detectorIDs);
677 spec = static_cast<int>(m_numberOfTubes * m_numberOfPixelsPerTube);
678
679 // IN4 Rosace detectors are in a different NeXus entry
680 if (m_instrumentName == "IN4") {
681 g_log.debug() << "Loading data into the workspace: IN4 Rosace!\n";
682 // read in the data
683 // load the counts from the file into memory
684 auto dataRosace = LegacyLoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data");
685 dataRosace.load();
686 LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, dataRosace, xAxis, spec, false, detectorIDs);
687 spec += dataRosace.dim0();
688 }
689
690 for (const auto &monitorName : monitorList) {
691 detectorIDs[spec] = static_cast<int>(spec) + 1;
692 auto monitorData = LegacyLoadHelper::getIntDataset(entry, monitorName);
693 monitorData.load();
694 LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, monitorData, xAxis, spec, false, detectorIDs);
695 spec++;
696 }
697}
698
704void LoadILLTOF2::fillScanWorkspace(const LegacyNexus::NXEntry &entry, const std::vector<std::string> &monitorList) {
705 // Prepare X-axis array
706 auto xAxis = prepareAxis(entry, false);
707 auto data = LegacyLoadHelper::getIntDataset(entry, "data_scan/detector_data/data");
708 data.load();
709
710 // Load scan data
711 const std::vector<int> detectorIDs = m_localWorkspace->getInstrument()->getDetectorIDs(false);
712 const std::tuple<int, int, int> dimOrder{1, 2, 0};
713 LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, 0, true, detectorIDs, std::set<int>(), dimOrder);
714
715 // Load monitor data, there is only one monitor
716 const std::vector<int> monitorIDs = m_localWorkspace->getInstrument()->getMonitors();
717 const auto spectrumNo = data.dim1() * data.dim2();
718 auto monitorData = LegacyLoadHelper::getDoubleDataset(entry, monitorList[0]);
719 monitorData.load();
720 for (int index = 0; index < monitorData.dim1(); index++) {
721 // monitor is always the 4th row, if that ever changes, a name search for 'monitor1' would be necessary among
722 // scanned_variables
723 const auto counts = monitorData(3, index);
724 m_localWorkspace->mutableY(spectrumNo)[index] = counts;
725 m_localWorkspace->mutableE(spectrumNo)[index] = sqrt(counts);
726 m_localWorkspace->mutableX(spectrumNo)[index] = xAxis[index];
727 }
728 // finally, we need to set the correct detector ID for the monitor
729 m_localWorkspace->getSpectrum(spectrumNo).setDetectorID(monitorIDs[0]);
730}
731
732} // namespace Mantid::DataHandling
std::map< DeltaEMode::Type, std::string > index
#define DECLARE_LEGACY_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_LEGACY_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM m...
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.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
@ Load
allowed here which will be passed to the algorithm
Defines an interface to an algorithm that loads a file so that it can take part in the automatic sele...
Definition IFileLoader.h:19
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:91
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.
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
A property class for workspaces.
void loadInstrumentDetails(const LegacyNexus::NXEntry &)
Sets the instrument name along with its address in the nexus file.
API::MatrixWorkspace_sptr m_localWorkspace
Definition LoadILLTOF2.h:64
std::string m_instrumentAddress
Name of the instrument address.
Definition LoadILLTOF2.h:67
void init() override
Initialises the algorithm.
void addEnergyToRun()
Calculates the incident energy from the wavelength and adds it as sample log 'Ei'.
void initWorkspace(const LegacyNexus::NXEntry &entry)
Creates the workspace and initialises member variables with the corresponding values.
void loadTimeDetails(const LegacyNexus::NXEntry &entry)
Load the time details from the nexus file.
void fillStaticWorkspace(const LegacyNexus::NXEntry &entry, const std::vector< std::string > &monitorList, bool convertToTOF)
Fills the non-scan measurement data into the workspace, including that from the monitor.
std::vector< std::string > getMonitorInfo(const LegacyNexus::NXEntry &firstEntry)
Finds monitor data names and stores them in a vector.
void fillScanWorkspace(const LegacyNexus::NXEntry &entry, const std::vector< std::string > &monitorList)
Fills scan workspace with data and monitor data counts.
std::string m_instrumentName
Name of the instrument.
Definition LoadILLTOF2.h:66
void addAllNexusFieldsAsProperties(const std::string &filename)
Goes through all the fields of the NeXus file and adds them as parameters in the workspace.
int confidence(Kernel::LegacyNexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
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.
std::vector< double > prepareAxis(const LegacyNexus::NXEntry &entry, bool convertToTOF)
Prepares X axis for the workspace being loaded.
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.
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
bool pathExists(const std::string &path) const
Query if a path exists.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
virtual std::string setValue(const std::string &)=0
Set the value of the property via a string.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string findInstrumentNexusAddress(const LegacyNexus::NXEntry &firstEntry)
Finds the address for the instrument name in the nexus file Usually of the form: entry0/<NXinstrument...
LegacyNexus::NXInt getIntDataset(const LegacyNexus::NXEntry &entry, const std::string &groupName)
Fetches NXInt data from the requested group name in the entry provided.
void addNumericProperty(LegacyNexus::File &filehandle, const LegacyNexus::Info &nxinfo, const std::string &property_name, API::Run &runDetails)
void fillStaticWorkspace(const API::MatrixWorkspace_sptr &ws, const LegacyNexus::NXInt &data, const std::vector< double > &xAxis, int64_t initialSpectrum=0, bool pointData=false, const std::vector< int > &detectorIDs=std::vector< int >(), const std::set< int > &acceptedDetectorIDs=std::set< int >(), const std::tuple< short, short, short > &axisOrder=std::tuple< short, short, short >(0, 1, 2))
Fills workspace with histogram data from provided data structure.
void addNexusFieldsToWsRun(LegacyNexus::File &filehandle, API::Run &runDetails)
Add properties from a nexus file to the workspace run.
LegacyNexus::NXDouble getDoubleDataset(const LegacyNexus::NXEntry &entry, const std::string &groupName)
Fetches NXDouble data from the requested group name in the entry provided.
double calculateEnergy(double)
Calculate Neutron Energy from wavelength: .
void loadingOrder(const std::tuple< short, short, short > &axisOrder, int *dataIndices)
Handles non-standard loading order of the provided data, based on the provided data dimension order.
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...
void loadEmptyInstrument(const API::MatrixWorkspace_sptr &ws, const std::string &instrumentName, const std::string &instrumentAddress="")
Loads empty instrument of chosen name into a provided workspace.
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54