25#include <boost/lexical_cast.hpp>
38using Mantid::HistogramData::BinEdges;
39using Mantid::HistogramData::Counts;
40using Mantid::HistogramData::Histogram;
52 file.openGroup(
"isis_vms_compat",
"IXvms");
53 }
catch (::NeXus::Exception &) {
60 std::vector<int32_t> spb;
61 std::vector<float> rspb;
62 file.readData(
"SPB", spb);
63 file.readData(
"RSPB", rspb);
65 WS->mutableSample().setGeometryFlag(spb[2]);
66 WS->mutableSample().setThickness(rspb[3]);
67 WS->mutableSample().setHeight(rspb[4]);
68 WS->mutableSample().setWidth(rspb[5]);
69 }
catch (::NeXus::Exception &ex) {
72 s <<
"Wrong definition found in isis_vms_compat :> " << ex.what();
74 throw std::runtime_error(s.str());
80const std::string LOAD_EVENTS(
"Events");
81const std::string LOAD_HISTO(
"Histogram");
84const std::string LOGS_ALLOW(
"AllowList");
85const std::string LOGS_BLOCK(
"BlockList");
89bool keyExists(std::string
const &key, std::map<std::string, std::string>
const &entries) {
90 return entries.find(key) != entries.cend();
95bool isHistoMonitor(::NeXus::File &monitorFileHandle) {
96 const auto fields = monitorFileHandle.getEntries();
97 return keyExists(
"data", fields) && keyExists(
"time_of_flight", fields);
100std::size_t sizeOfUnopenedSDS(::NeXus::File &file,
const std::string &fieldName) {
101 file.openData(fieldName);
102 auto size =
static_cast<std::size_t
>(file.getInfo().dims[0]);
107bool eventIdNotEmptyIfExists(::NeXus::File &file, std::map<std::string, std::string>
const &fields) {
108 if (keyExists(
"event_id", fields))
109 return sizeOfUnopenedSDS(file,
"event_id") > 1;
116bool isEventMonitor(::NeXus::File &file) {
117 const auto fields = file.getEntries();
118 return keyExists(
"event_index", fields) && keyExists(
"event_time_offset", fields) &&
119 keyExists(
"event_time_zero", fields) && eventIdNotEmptyIfExists(file, fields);
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 or .NXS");
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::const_iterator it;
179 string_map_t entries = file.getEntries();
182 for (it = entries.begin(); it != entries.end(); ++it) {
183 if (((it->first ==
"entry") || (it->first ==
"raw_data_1")) && (it->second ==
"NXentry")) {
184 file.openGroup(it->first, it->second);
198 size_t numPeriods = 0;
206 if (numPeriods > 1) {
217 throw std::invalid_argument(
m_filename +
" does not contain any monitors");
223 std::vector<bool> loadMonitorFlags;
231 for (std::size_t ws_index = 0; ws_index <
m_monitor_count; ++ws_index) {
240 if (loadMonitorFlags[ws_index]) {
262 eventWS->getEventXMinMax(xmin, xmax);
264 auto axis = HistogramData::BinEdges{xmin - 1, xmax + 1};
265 eventWS->setAllX(axis);
268 const std::string currentPath = file.getPath();
270 file.openPath(currentPath);
278 loadSampleDataISIScompatibilityInfo(file,
m_workspace);
279 }
catch (::NeXus::Exception &) {
283 std::string instrumentName;
284 file.openGroup(
"instrument",
"NXinstrument");
286 file.openData(
"name");
287 instrumentName = file.getStrData();
294 }
catch (std::runtime_error &)
302 g_log.
debug() <<
"Instrument name read from NeXus file is " << instrumentName <<
'\n';
313 Types::Core::DateAndTime run_start(0, 0);
315 m_workspace->mutableRun().addProperty(
"run_start", run_start.toISO8601String(),
true);
327 }
catch (std::exception &e) {
328 g_log.
warning() <<
"Error while loading meta data: " << e.what() <<
'\n';
335 if ((numPeriods > 1) && (!useEventMon)) {
351 boost::scoped_array<detid_t> det_ids(
new detid_t[nmonitors]);
352 boost::scoped_array<specnum_t> spec_ids(
new specnum_t[nmonitors]);
354 for (
size_t i = 0; i < nmonitors; ++i) {
360 file.openGroup(
"isis_vms_compat",
"IXvms");
361 }
catch (::NeXus::Exception &) {
365 file.openData(
"UDET");
366 std::vector<int32_t> udet;
370 file.openData(
"SPEC");
371 std::vector<int32_t> spec;
380 std::vector<int32_t>::const_iterator beg = spec.begin();
381 for (
size_t mon_index = 0; mon_index < nmonitors; ++mon_index) {
382 std::vector<int32_t>::const_iterator itr = std::find(spec.begin(), spec.end(), spec_ids[mon_index]);
383 if (itr == spec.end()) {
384 det_ids[mon_index] = -1;
387 std::vector<int32_t>::difference_type udet_index = std::distance(beg, itr);
388 det_ids[mon_index] = udet[udet_index];
393 for (
size_t i = 0; i < nmonitors; ++i) {
401 const std::vector<std::string> allow_list =
getProperty(PropertyNames::LOGS_ALLOW);
402 const std::vector<std::string> block_list =
getProperty(PropertyNames::LOGS_BLOCK);
410 loadLogs->setPropertyValue(
"Filename", filename);
413 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_ALLOW, allow_list);
414 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_BLOCK, block_list);
417 g_log.
error() <<
"Error while loading Logs from Nexus. Some sample logs "
431 std::unique_ptr<::NeXus::File> filePointer;
433 filePointer = std::make_unique<::NeXus::File>(fname);
435 filePointer->getEntries();
436 }
catch (::NeXus::Exception &e) {
437 g_log.
error() <<
"Failed to open as a NeXus file: '" << fname <<
"', error description: " << e.what() <<
'\n';
453 if (numPeriods < 2) {
454 g_log.
warning() <<
"Attempted to split multiperiod histogram workspace with " << numPeriods
455 <<
"periods, aborted.\n";
462 <<
"data entries, into " << numPeriods
470 size_t xLength = yLength + 1;
471 size_t numSpectra =
m_workspace->getNumberHistograms();
476 for (
size_t i = 0; i < numPeriods; i++) {
481 auto offset = yLength * i;
483 for (
size_t wsIndex = 0; wsIndex < numSpectra; wsIndex++) {
486 wsPeriod->setHistogram(wsIndex, edges, Counts(inYBegin, inYBegin + yLength));
490 monLogCreator.
addPeriodLogs(
static_cast<int>(i + 1), wsPeriod->mutableRun());
493 wsGroup->addWorkspace(wsPeriod);
505 using string_map_t = std::map<std::string, std::string>;
508 string_map_t entries = file.getEntries();
514 string_map_t::const_iterator it = entries.begin();
515 for (; it != entries.end(); ++it) {
516 std::string entry_name(it->first);
517 std::string entry_class(it->second);
518 if ((entry_class ==
"NXmonitor")) {
524 file.openGroup(entry_name,
"NXmonitor");
525 info.
name = entry_name;
526 info.
hasEvent = isEventMonitor(file);
527 info.
hasHisto = isHistoMonitor(file);
530 string_map_t inner_entries = file.getEntries();
531 if (inner_entries.find(
"monitor_number") != inner_entries.end()) {
533 const auto detNum = NeXus::NeXusIOHelper::readNexusValue<int64_t>(file,
"monitor_number");
534 if (detNum > std::numeric_limits<detid_t>::max()) {
535 throw std::runtime_error(
"Monitor number too larger to represent");
540 Poco::Path monPath(entry_name);
541 std::string monitorName = monPath.getBaseName();
546 std::string::size_type loc = monitorName.rfind(
'_');
547 if (loc == std::string::npos) {
548 loc = monitorName.rfind(
'r');
551 info.
detNum = -1 * boost::lexical_cast<int>(monitorName.substr(loc + 1));
555 if (inner_entries.find(
"spectrum_index") != inner_entries.end()) {
556 file.openData(
"spectrum_index");
564 if (info.
hasHisto && (numPeriods == 0) && (inner_entries.find(
"period_index") != inner_entries.end())) {
566 file.openData(
"period_index");
567 file.getDataCoerce(period_data);
569 numPeriods = period_data.size();
581 return std::abs(left.detNum) < std::abs(right.detNum);
588 loadMonitorFlags.clear();
596 const std::string loadType =
getProperty(
"LoadOnly");
597 if (loadType == LOAD_EVENTS) {
599 if (numEventMon == 0) {
600 throw std::runtime_error(
"Loading event data. Trying to load event data but failed to "
601 "find event monitors. This file may be corrupted or it may not be "
604 }
else if (loadType == LOAD_HISTO) {
606 if (numHistoMon == 0) {
607 throw std::runtime_error(
"Not loading event data. Trying to load histogram data but failed to "
608 "find monitors with histogram data or could not interpret the data. "
609 "This file may be corrupted or it may not be supported");
612 if (numEventMon > 0 && numHistoMon > 0) {
613 std::stringstream errmsg;
614 errmsg <<
"There are " << numHistoMon <<
" histogram monitors and " << numEventMon
615 <<
" event monitors. Loading Histogram by default. "
616 <<
"Use \"LoadOnly\" or \"MonitorLoadOnly\" to specify which to "
622 useEventMon = (numEventMon > 0);
630 loadMonitorFlags.emplace_back(
m_monitorInfo[i_mon].hasEvent);
635 loadMonitorFlags.emplace_back(
m_monitorInfo[i_mon].hasHisto);
649 eventWS->setYUnit(
"Counts");
664 std::string tof_units, event_time_zero_units;
667 auto event_index = NeXus::NeXusIOHelper::readNexusVector<uint64_t>(file,
"event_index");
669 file.openData(
"event_time_offset");
670 MantidVec time_of_flight = NeXus::NeXusIOHelper::readNexusVector<double>(file);
671 file.getAttr(
"units", tof_units);
675 file.openData(
"event_time_zero");
676 MantidVec seconds = NeXus::NeXusIOHelper::readNexusVector<double>(file);
677 file.getAttr(
"units", event_time_zero_units);
679 Mantid::Types::Core::DateAndTime pulsetime_offset;
681 std::string startTime;
682 file.getAttr(
"offset", startTime);
690 Mantid::Types::Core::DateAndTime pulsetime(0);
691 Mantid::Types::Core::DateAndTime lastpulsetime(0);
692 std::size_t
numEvents = time_of_flight.size();
693 bool pulsetimesincreasing =
true;
694 size_t pulse_index(0);
695 size_t numPulses = seconds.size();
696 for (std::size_t j = 0; j <
numEvents; ++j) {
697 while (!((j >= event_index[pulse_index]) && (j < event_index[pulse_index + 1]))) {
699 if (pulse_index > (numPulses + 1))
702 if (pulse_index >= (numPulses))
703 pulse_index = numPulses - 1;
704 pulsetime = pulsetime_offset + seconds[pulse_index];
705 if (pulsetime < lastpulsetime)
706 pulsetimesincreasing =
false;
707 lastpulsetime = pulsetime;
708 event_list.
addEventQuickly(Types::Event::TofEvent(time_of_flight[j], pulsetime));
710 if (pulsetimesincreasing)
716 file.openData(
"data");
718 file.getDataCoerce(data);
722 file.openData(
"time_of_flight");
724 file.getDataCoerce(tof);
727 if (numPeriods > 1) {
731 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
Helper class for reporting progress from algorithms.
Class to hold a set of workspaces.
A property class for workspaces.
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.
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...
static bool loadInstrument(const std::string &nexusfilename, T localWorkspace, const std::string &top_entry_name, Algorithm *alg, const Kernel::NexusHDF5Descriptor *descriptor=nullptr)
Load instrument from Nexus file if possible, else from IDF spacified by Nexus file.
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 splitMutiPeriodHistrogramData(const size_t numPeriods)
split multi period histogram workspace into a workspace group
std::vector< LoadNexusMonitorsAlg::MonitorInfo > m_monitorInfo
size_t getMonitorInfo(NeXus::File &file, size_t &numPeriods)
void init() override
Initialise algorithm.
std::string m_filename
The name and path of the input file.
std::vector< HistogramData::BinEdges > m_multiPeriodBinEdges
std::string m_top_entry_name
name of top level NXentry to use
void readHistoMonitorEntry(NeXus::File &file, size_t ws_index, size_t numPeriods)
const std::string name() const override
Algorithm's name for identification.
API::MatrixWorkspace_sptr m_workspace
The workspace being filled out.
void fixUDets(::NeXus::File &file)
Fix the detector numbers if the defaults are not correct.
void exec() override
Execute algorithm.
void readEventMonitorEntry(NeXus::File &file, size_t ws_index)
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...
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
std::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const NexusHDF5Descriptor &descriptor)
Get the number of events in the currently opened group.
void adjustTimeOfFlightISISLegacy(::NeXus::File &file, T localWorkspace, const std::string &entry_name, const std::string &classType, const Kernel::NexusHDF5Descriptor *descriptor=nullptr)
ISIS specific method for dealing with wide events.
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.