23#include <boost/lexical_cast.hpp>
37using Mantid::HistogramData::BinEdges;
38using Mantid::HistogramData::Counts;
39using Mantid::HistogramData::Histogram;
51 file.openGroup(
"isis_vms_compat",
"IXvms");
59 std::vector<int32_t> spb;
60 std::vector<float> rspb;
61 file.readData(
"SPB", spb);
62 file.readData(
"RSPB", rspb);
64 WS->mutableSample().setGeometryFlag(spb[2]);
65 WS->mutableSample().setThickness(rspb[3]);
66 WS->mutableSample().setHeight(rspb[4]);
67 WS->mutableSample().setWidth(rspb[5]);
71 s <<
"Wrong definition found in isis_vms_compat :> " << ex.what();
73 throw std::runtime_error(s.str());
79const std::string LOAD_EVENTS(
"Events");
80const std::string LOAD_HISTO(
"Histogram");
83const std::string LOGS_ALLOW(
"AllowList");
84const std::string LOGS_BLOCK(
"BlockList");
88bool keyExists(std::string
const &key, std::map<std::string, std::string>
const &entries) {
89 return entries.find(key) != entries.cend();
94bool isHistoMonitor(Nexus::File
const &monitorFileHandle) {
95 const auto fields = monitorFileHandle.getEntries();
96 return keyExists(
"data", fields) && keyExists(
"time_of_flight", fields);
99std::size_t sizeOfUnopenedSDS(Nexus::File &file,
const std::string &fieldName) {
100 file.openData(fieldName);
101 auto size =
static_cast<std::size_t
>(file.getInfo().dims[0]);
106bool eventIdNotEmptyIfExists(Nexus::File &file, std::map<std::string, std::string>
const &fields) {
107 if (keyExists(
"event_id", fields))
108 return sizeOfUnopenedSDS(file,
"event_id") > 1;
115bool isEventMonitor(Nexus::File &file) {
116 const auto fields = file.getEntries();
117 return keyExists(
"event_index", fields) && keyExists(
"event_time_offset", fields) &&
118 keyExists(
"event_time_zero", fields) && eventIdNotEmptyIfExists(file, fields);
125 const std::vector<std::string> exts{
".nxs.h5",
".nxs"};
127 "The name (including its full or relative path) of the NeXus file to "
128 "attempt to load. The file extension must either be .nxs, .NXS, or .nxs.h5");
132 "The name of the output workspace in which to load the NeXus monitors.");
135 "Optional: Name of the NXentry to load if it's not the default.");
137 std::vector<std::string> options{
"", LOAD_EVENTS, LOAD_HISTO};
138 declareProperty(
"LoadOnly",
"", std::make_shared<Kernel::StringListValidator>(options),
139 "If multiple repesentations exist, which one to load. "
140 "Default is to load the one that is present, and Histogram "
141 "if both are present.");
145 "If specified, only these logs will be loaded from the file (each "
146 "separated by a comma).");
149 "If specified, these logs will NOT be loaded from the file (each "
150 "separated by a comma).");
165 throw std::runtime_error(
"Failed to recognize this file as a NeXus file, cannot continue.");
177 using string_map_t = std::map<std::string, std::string>;
178 string_map_t entries = file.getEntries();
181 const auto it = std::find_if(entries.cbegin(), entries.cend(), [](
const auto &entry) {
182 return ((entry.first ==
"entry" || entry.first ==
"raw_data_1") && entry.second ==
"NXentry");
184 if (it != entries.cend()) {
185 file.openGroup(it->first, it->second);
197 size_t numPeriods = 0;
205 if (numPeriods > 0) {
216 throw std::invalid_argument(
m_filename +
" does not contain any monitors");
222 std::vector<bool> loadMonitorFlags;
228 const std::string entryAddress = file.getAddress();
233 for (std::size_t ws_index = 0; ws_index <
m_monitor_count; ++ws_index) {
242 if (loadMonitorFlags[ws_index]) {
264 eventWS->getEventXMinMax(xmin, xmax);
269 if (eventWS->getNumberEvents() == 0) {
270 g_log.
warning(
"No events loading. Resetting time-of-flight range 0 to 1");
272 g_log.
warning(
"time-of-flight range of events are unusual. Resetting time-of-flight range 0 to 1");
280 auto axis = HistogramData::BinEdges{xmin, xmax};
281 eventWS->setAllX(axis);
284 const std::string currentAddress = file.getAddress();
286 file.openAddress(currentAddress);
294 loadSampleDataISIScompatibilityInfo(file,
m_workspace);
299 std::string instrumentName;
300 file.openAddress(entryAddress);
301 file.openGroup(
"instrument",
"NXinstrument");
303 file.openData(
"name");
304 instrumentName = file.getStrData();
311 }
catch (std::runtime_error &)
319 g_log.
debug() <<
"Instrument name read from NeXus file is " << instrumentName <<
'\n';
321 m_workspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"TOF");
330 Types::Core::DateAndTime run_start(0, 0);
332 m_workspace->mutableRun().addProperty(
"run_start", run_start.toISO8601String(),
true);
344 }
catch (std::exception &e) {
345 g_log.
warning() <<
"Error while loading meta data: " << e.what() <<
'\n';
351 if ((numPeriods > 0) && (!useEventMon)) {
367 boost::scoped_array<detid_t> det_ids(
new detid_t[nmonitors]);
368 boost::scoped_array<specnum_t> spec_ids(
new specnum_t[nmonitors]);
370 for (
size_t i = 0; i < nmonitors; ++i) {
376 file.openGroup(
"isis_vms_compat",
"IXvms");
381 file.openData(
"UDET");
382 std::vector<int32_t> udet;
386 file.openData(
"SPEC");
387 std::vector<int32_t> spec;
396 std::vector<int32_t>::const_iterator beg = spec.begin();
397 for (
size_t mon_index = 0; mon_index < nmonitors; ++mon_index) {
398 std::vector<int32_t>::const_iterator itr = std::find(spec.begin(), spec.end(), spec_ids[mon_index]);
399 if (itr == spec.end()) {
400 det_ids[mon_index] = -1;
403 std::vector<int32_t>::difference_type udet_index = std::distance(beg, itr);
404 det_ids[mon_index] = udet[udet_index];
409 for (
size_t i = 0; i < nmonitors; ++i) {
417 const std::vector<std::string> allow_list =
getProperty(PropertyNames::LOGS_ALLOW);
418 const std::vector<std::string> block_list =
getProperty(PropertyNames::LOGS_BLOCK);
426 loadLogs->setPropertyValue(
"Filename", filename);
429 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_ALLOW, allow_list);
430 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_BLOCK, block_list);
433 g_log.
error() <<
"Error while loading Logs from Nexus. Some sample logs "
447 std::unique_ptr<Nexus::File> filePointer;
449 filePointer = std::make_unique<Nexus::File>(fname);
450 filePointer->getEntries();
452 g_log.
error() <<
"Failed to open as a NeXus file: '" << fname <<
"', error description: " << e.what() <<
'\n';
469 <<
"data entries, into " << numPeriods
476 size_t xLength = yLength + 1;
477 size_t numSpectra =
m_workspace->getNumberHistograms();
481 std::vector<API::MatrixWorkspace_sptr> outputWorkspaces;
482 outputWorkspaces.reserve(numPeriods);
484 for (
size_t i = 0; i < numPeriods; i++) {
489 auto offset = yLength * i;
491 for (
size_t wsIndex = 0; wsIndex < numSpectra; wsIndex++) {
494 wsPeriod->setHistogram(wsIndex, edges, Counts(inYBegin, inYBegin + yLength));
498 monLogCreator.
addPeriodLogs(
static_cast<int>(i + 1), wsPeriod->mutableRun());
500 outputWorkspaces.push_back(std::move(wsPeriod));
504 if (outputWorkspaces.size() > 1) {
506 for (
const auto &ws : outputWorkspaces) {
507 wsGroup->addWorkspace(ws);
510 }
else if (outputWorkspaces.size() == 1) {
511 this->
setProperty(
"OutputWorkspace", outputWorkspaces[0]);
513 g_log.
error() <<
"No period workspaces generated to output.";
522 using string_map_t = std::map<std::string, std::string>;
525 string_map_t entries = file.getEntries();
531 string_map_t::const_iterator it = entries.begin();
532 for (; it != entries.end(); ++it) {
533 std::string entry_name(it->first);
534 std::string entry_class(it->second);
535 if ((entry_class ==
"NXmonitor")) {
541 file.openGroup(entry_name,
"NXmonitor");
542 info.
name = entry_name;
543 info.
hasEvent = isEventMonitor(file);
544 info.
hasHisto = isHistoMonitor(file);
547 string_map_t inner_entries = file.getEntries();
548 if (inner_entries.find(
"monitor_number") != inner_entries.end()) {
550 const auto detNum = Nexus::IOHelper::readNexusValue<int64_t>(file,
"monitor_number");
551 if (detNum > std::numeric_limits<detid_t>::max()) {
552 throw std::runtime_error(
"Monitor number too larger to represent");
557 std::filesystem::path monPath(entry_name);
558 std::string monitorName = monPath.stem().string();
563 std::string::size_type loc = monitorName.rfind(
'_');
564 if (loc == std::string::npos) {
565 loc = monitorName.rfind(
'r');
568 info.
detNum = -1 * boost::lexical_cast<int>(monitorName.substr(loc + 1));
572 if (inner_entries.find(
"spectrum_index") != inner_entries.end()) {
573 file.openData(
"spectrum_index");
581 if (info.
hasHisto && (numPeriods == 0) && (inner_entries.find(
"period_index") != inner_entries.end())) {
583 file.openData(
"period_index");
584 file.getDataCoerce(period_data);
586 numPeriods = period_data.size();
598 return std::abs(left.detNum) < std::abs(right.detNum);
605 loadMonitorFlags.clear();
613 const std::string loadType =
getProperty(
"LoadOnly");
614 if (loadType == LOAD_EVENTS) {
616 if (numEventMon == 0) {
617 throw std::runtime_error(
"Loading event data. Trying to load event data but failed to "
618 "find event monitors. This file may be corrupted or it may not be "
621 }
else if (loadType == LOAD_HISTO) {
623 if (numHistoMon == 0) {
624 throw std::runtime_error(
"Not loading event data. Trying to load histogram data but failed to "
625 "find monitors with histogram data or could not interpret the data. "
626 "This file may be corrupted or it may not be supported");
629 if (numEventMon > 0 && numHistoMon > 0) {
630 std::stringstream errmsg;
631 errmsg <<
"There are " << numHistoMon <<
" histogram monitors and " << numEventMon
632 <<
" event monitors. Loading Histogram by default. "
633 <<
"Use \"LoadOnly\" or \"MonitorLoadOnly\" to specify which to "
639 useEventMon = (numEventMon > 0);
647 loadMonitorFlags.emplace_back(
m_monitorInfo[i_mon].hasEvent);
652 loadMonitorFlags.emplace_back(
m_monitorInfo[i_mon].hasHisto);
665 eventWS->getAxis(0)->unit() = Mantid::Kernel::UnitFactory::Instance().create(
"TOF");
666 eventWS->setYUnit(
"Counts");
681 std::string tof_units, event_time_zero_units;
684 auto event_index = Nexus::IOHelper::readNexusVector<uint64_t>(file,
"event_index");
686 file.openData(
"event_time_offset");
687 MantidVec time_of_flight = Nexus::IOHelper::readNexusVector<double>(file);
688 file.getAttr(
"units", tof_units);
693 if (time_of_flight.empty()) {
698 file.openData(
"event_time_zero");
699 MantidVec seconds = Nexus::IOHelper::readNexusVector<double>(file);
700 file.getAttr(
"units", event_time_zero_units);
702 Mantid::Types::Core::DateAndTime pulsetime_offset;
704 std::string startTime;
705 file.getAttr(
"offset", startTime);
713 Mantid::Types::Core::DateAndTime pulsetime;
714 Mantid::Types::Core::DateAndTime lastpulsetime(0);
715 std::size_t
numEvents = time_of_flight.size();
716 bool pulsetimesincreasing =
true;
717 size_t pulse_index(0);
718 size_t numPulses = seconds.size();
719 for (std::size_t j = 0; j <
numEvents; ++j) {
720 while (!((j >= event_index[pulse_index]) && (j < event_index[pulse_index + 1]))) {
722 if (pulse_index > (numPulses + 1))
725 if (pulse_index >= (numPulses))
726 pulse_index = numPulses - 1;
727 pulsetime = pulsetime_offset + seconds[pulse_index];
728 if (pulsetime < lastpulsetime)
729 pulsetimesincreasing =
false;
730 lastpulsetime = pulsetime;
731 event_list.
addEventQuickly(Types::Event::TofEvent(time_of_flight[j], pulsetime));
733 if (pulsetimesincreasing)
739 file.openData(
"data");
741 file.getDataCoerce(data);
745 file.openData(
"time_of_flight");
747 file.getDataCoerce(tof);
750 if (numPeriods > 0) {
754 m_workspace->setHistogram(ws_index, Histogram(BinEdges(std::move(tof)), Counts(std::move(data))));
#define DECLARE_ALGORITHM(classname)
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.
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 m_log
Logger for this algorithm.
@ Load
allowed here which will be passed to the algorithm
Defines a class to aid in creating ISIS specific run logs for periods, status etc.
void addStatusLog(API::Run &exptRun)
Adds the status log to the this run.
void addPeriodLogs(const int period, API::Run &exptRun)
Adds period related logs.
Helper class for reporting progress from algorithms.
Class to hold a set of workspaces.
A property class for workspaces.
static bool loadInstrument(const std::string &nexusfilename, T localWorkspace, const std::string &top_entry_name, Algorithm *alg, const Nexus::NexusDescriptor *descriptor=nullptr)
Load instrument from Nexus file if possible, else from IDF spacified by Nexus file.
static std::string readInstrumentFromISIS_VMSCompat(Nexus::File &hFile)
method used to return instrument name for some old ISIS files where it is not written properly within...
size_t m_monitor_count
Number of monitors.
void runLoadLogs(const std::string &filename, const API::MatrixWorkspace_sptr &localWorkspace)
Load the logs.
bool createOutputWorkspace(std::vector< bool > &loadMonitorFlags)
void readHistoMonitorEntry(Nexus::File &file, size_t ws_index, size_t numPeriods)
void splitMutiPeriodHistrogramData(const size_t numPeriods)
split multi period histogram workspace into a workspace group
std::vector< LoadNexusMonitorsAlg::MonitorInfo > m_monitorInfo
void init() override
Initialise algorithm.
std::string m_filename
The name and path of the input file.
void readEventMonitorEntry(Nexus::File &file, size_t ws_index)
std::vector< HistogramData::BinEdges > m_multiPeriodBinEdges
std::string m_top_entry_name
name of top level NXentry to use
void fixUDets(Nexus::File &file)
Fix the detector numbers if the defaults are not correct.
const std::string name() const override
Algorithm's name for identification.
size_t getMonitorInfo(Nexus::File &file, size_t &numPeriods)
API::MatrixWorkspace_sptr m_workspace
The workspace being filled out.
void exec() override
Execute algorithm.
bool canOpenAsNeXus(const std::string &fname)
is it possible to open the file?
std::vector< HistogramData::Counts > m_multiPeriodCounts
void setSortOrder(const EventSortType order) const
Manually set the event list sort order value.
void addEventQuickly(const Types::Event::TofEvent &event)
Append an event to the histogram, without clearing the cache, to make it faster.
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
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.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
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...
Class that provides for a standard Nexus exception.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void adjustTimeOfFlightISISLegacy(Nexus::File &file, T localWorkspace, const std::string &entry_name, const std::string &classType, const Nexus::NexusDescriptor *descriptor=nullptr)
ISIS specific method for dealing with wide events.
std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const Nexus::NexusDescriptor &descriptor)
Get the number of events in the currently opened group.
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
MANTID_KERNEL_DLL Types::Core::DateAndTime createFromSanitizedISO8601(const std::string &date)
Creates a DateAndTime object from a date string even if the string does not exactly conform to ISO860...
void timeConversionVector(std::vector< T > &vec, const std::string &input_unit, const std::string &output_unit)
int32_t detid_t
Typedef for a detector ID.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
int32_t specnum_t
Typedef for a spectrum Number.
detid_t detNum
monitorName
std::string name
name of the group in the nexus file - TODO was
Describes the direction (within an algorithm) of a Property.
@ Input
An input workspace.
@ Output
An output workspace.