18#include "MantidLegacyNexus/NeXusException.hpp"
19#include "MantidLegacyNexus/NeXusFile.hpp"
20#include "MantidLegacyNexus/NexusClasses.h"
24const std::array<std::string, 5> SUPPORTED_INSTRUMENTS = {{
"IN4",
"IN5",
"IN6",
"PANTHER",
"SHARP"}};
29const std::string NXINSTRUMENT(
"NXinstrument");
30const std::string SDS(
"SDS");
31const std::string EMPTY_STR(
"");
37using namespace Kernel;
39using namespace HistogramData;
43namespace LegacyLoadHelper {
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; });
64LegacyNexus::NXInt getIntDataset(
const LegacyNexus::NXEntry &entry,
const std::string &groupName) {
65 auto dataGroup = entry.openNXData(groupName);
66 return dataGroup.openIntData();
75LegacyNexus::NXDouble getDoubleDataset(
const LegacyNexus::NXEntry &entry,
const std::string &groupName) {
76 auto dataGroup = entry.openNXData(groupName);
77 return dataGroup.openDoubleData();
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;
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)];
107 int loadOrder[3] = {0, 1, 2};
110 HistogramData::Points histoPoints;
111 HistogramData::BinEdges binEdges;
113 histoPoints = HistogramData::Points(xAxis);
115 binEdges = HistogramData::BinEdges(xAxis);
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) {
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()) {
128 currentSpectrum -= nSkipped;
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]]);
135 const HistogramData::Counts counts(spectrum.begin(), spectrum.end());
136 const HistogramData::CountVariances countVariances(spectrum.begin(), spectrum.end());
138 ws->setCounts(currentSpectrum, counts);
139 ws->setCountVariances(currentSpectrum, countVariances);
140 ws->setPoints(currentSpectrum, histoPoints);
142 ws->setHistogram(currentSpectrum, binEdges, counts);
144 const specnum_t detectorID = customDetectorIDs ? detectorIDs[currentSpectrum] : currentSpectrum;
145 ws->getSpectrum(currentSpectrum).setSpectrumNo(detectorID);
150template <
typename NumericType>
152 const std::string &property_name,
API::Run &runDetails) {
154 legacyhelperlog.warning() <<
"Property " << property_name
155 <<
" was set twice. Please check the Nexus file and your inputs.";
161 if (filehandle.hasAttr(
"units"))
162 filehandle.getAttr(
"units", units);
165 std::vector<NumericType> data_vec;
166 data_vec.reserve(nxinfo.dims.front());
167 filehandle.getDataCoerce(data_vec);
170 const auto dim1size = data_vec.size();
173 runDetails.
addProperty(property_name, data_vec.front());
175 runDetails.
addProperty(property_name, data_vec.front(), units);
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")) {
204 filehandle.openData(nxname);
205 const auto nxinfo = filehandle.getInfo();
206 const auto rank = nxinfo.dims.size();
209 bool read_property = (rank == 1);
210 switch (nxinfo.type) {
211 case (LegacyNexus::NXnumtype::CHAR):
213 case (LegacyNexus::NXnumtype::FLOAT32):
214 case (LegacyNexus::NXnumtype::FLOAT64):
216 read_property = (nxinfo.dims[0] <= 9);
218 case (LegacyNexus::NXnumtype::INT16):
219 case (LegacyNexus::NXnumtype::INT32):
220 case (LegacyNexus::NXnumtype::UINT16):
222 read_property = (nxinfo.dims.front() == 1);
225 read_property =
false;
230 const std::string property_name = (parent_name.empty() ? nxname : parent_name +
"." + nxname);
232 switch (nxinfo.type) {
233 case (LegacyNexus::NXnumtype::CHAR): {
234 std::string property_value = filehandle.getStrData();
235 if (property_name.ends_with(
"_time")) {
241 runDetails.
addProperty(property_name, property_value);
244 runDetails.
addProperty(property_name, property_value);
246 legacyhelperlog.warning()
247 <<
"Property " << property_name <<
" was set twice. Please check the Nexus file and your inputs.\n";
252 case (LegacyNexus::NXnumtype::FLOAT32):
253 case (LegacyNexus::NXnumtype::FLOAT64):
254 addNumericProperty<double>(filehandle, nxinfo, property_name, runDetails);
256 case (LegacyNexus::NXnumtype::INT16):
257 case (LegacyNexus::NXnumtype::INT32):
258 case (LegacyNexus::NXnumtype::UINT16):
259 addNumericProperty<int>(filehandle, nxinfo, property_name, runDetails);
262 std::stringstream msg;
263 msg <<
"Encountered unknown type: " <<
static_cast<int>(nxinfo.type);
264 throw std::runtime_error(msg.str());
268 filehandle.closeData();
271 if ((nxclass !=
"ILL_data_scan_vars") && (nxclass !=
"NXill_data_scan_vars")) {
273 filehandle.openGroup(nxname, nxclass);
276 recurseAndAddNexusFieldsToWsRun(filehandle, runDetails, nxname, nxclass, level + 1);
278 filehandle.closeGroup();
291void addNexusFieldsToWsRun(LegacyNexus::File &filehandle,
API::Run &runDetails) {
295 std::string entryNameActual(
"");
297 const auto entryNameAndClass = filehandle.getNextEntry();
298 entryNameActual = entryNameAndClass.first;
299 }
catch (
const LegacyNexus::Exception &) {
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();
324 if ((descriptor.
pathExists(
"/entry0/wavelength") && descriptor.
pathExists(
"/entry0/experiment_identifier") &&
327 && !descriptor.
pathExists(
"/entry0/instrument/VirtualChopper")
329 && !descriptor.
pathExists(
"/entry0/instrument/Tx"))
330 || (descriptor.
pathExists(
"/entry0/data_scan") &&
331 descriptor.
pathExists(
"/entry0/instrument/Detector"))
346 "File path of the Data file to load");
349 "The name to use for the output workspace");
362 LegacyNexus::NXRoot dataRoot(filenameData);
363 LegacyNexus::NXEntry dataFirstEntry = dataRoot.openFirstEntry();
364 m_isScan = dataFirstEntry.containsGroup(
"data_scan");
397 std::vector<std::string> monitorList;
402 monitorList.push_back(
"data_scan/scanned_variables/data");
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");
425 throw std::runtime_error(
"Cannot set the instrument name from the Nexus file!");
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);
437 if (firstEntry.containsGroup(
"monitor"))
439 else if (firstEntry.containsGroup(
"monitor1"))
442 std::string message(
"Cannot find monitor[1] in the Nexus file!");
443 throw std::runtime_error(message);
458 const std::string dataName =
m_isScan ?
"data_scan/detector_data/data" :
"data";
469 size_t numberOfTubesInRosace = 0;
472 numberOfTubesInRosace +=
static_cast<size_t>(dataRosace.dim0());
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");
498 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create(
"Wavelength");
513 LegacyNexus::NXClass monitorEntry = entry.openNXGroup(
m_monitorName);
515 if (monitorEntry.containsDataSet(
"time_of_flight")) {
517 LegacyNexus::NXFloat time_of_flight_data = entry.openNXFloat(
m_monitorName +
"/time_of_flight");
518 time_of_flight_data.load();
545 LegacyNexus::File nxfileID(filename, LegacyNexus::NXACC_READ);
547 }
catch (
const LegacyNexus::Exception &) {
548 g_log.
debug() <<
"convertNexusToProperties: Error loading " << filename;
553 g_log.
debug() <<
"End parsing properties from : " << filename <<
'\n';
572 runDetails.
addProperty(
"Facility", std::string(
"ILL"));
580 double n_pulses = -1;
581 double fermiChopperSpeed = -1;
588 if (std::abs(bkgChopper1Speed - bkgChopper2Speed) > 1) {
589 throw std::invalid_argument(
"Background choppers 1 and 2 have different speeds");
592 n_pulses = fermiChopperSpeed / bkgChopper1Speed / 4;
597 n_pulses = fermiChopperSpeed / suppressorSpeed;
602 const double pulseInterval = 60.0 / (2 * fermiChopperSpeed) * n_pulses;
603 runDetails.
addProperty<
double>(
"pulse_interval", pulseInterval);
617 LegacyNexus::NXInt scannedAxis = entry.openNXInt(
"data_scan/scanned_variables/variables_names/axis");
619 int scannedVarId = 0;
621 if (scannedAxis[
index] == 1) {
622 scannedVarId =
index;
632 LegacyNexus::NXClass moni = entry.openNXGroup(
m_monitorName);
633 if (moni.containsDataSet(
"time_of_flight")) {
641 xAxis[i] =
static_cast<double>(i);
664 g_log.
debug() <<
"Loading data into the workspace...\n";
671 std::vector<int> detectorIDs =
m_localWorkspace->getInstrument()->getDetectorIDs(
false);
681 g_log.
debug() <<
"Loading data into the workspace: IN4 Rosace!\n";
687 spec += dataRosace.dim0();
690 for (
const auto &monitorName : monitorList) {
691 detectorIDs[spec] =
static_cast<int>(spec) + 1;
711 const std::vector<int> detectorIDs =
m_localWorkspace->getInstrument()->getDetectorIDs(
false);
712 const std::tuple<int, int, int> dimOrder{1, 2, 0};
716 const std::vector<int> monitorIDs =
m_localWorkspace->getInstrument()->getMonitors();
717 const auto spectrumNo = data.dim1() * data.dim2();
723 const auto counts = monitorData(3,
index);
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.
@ 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...
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.
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.
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
std::string m_instrumentAddress
Name of the instrument address.
void init() override
Initialises the algorithm.
size_t m_numberOfPixelsPerTube
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.
double m_timeOfFlightDelay
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.
LoadILLTOF2()
Constructor.
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.
std::string m_monitorName
void addAllNexusFieldsAsProperties(const std::string &filename)
Goes through all the fields of the NeXus file and adds them as parameters in the workspace.
size_t m_numberOfChannels
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.
size_t m_numberOfMonitors
void exec() override
Executes the algorithm.
size_t m_numberOfHistograms
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.
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.
void debug(const std::string &msg)
Logs at debug level.
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.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.