13#include "MantidDataHandling/DllConfig.h"
30#include "MantidNexus/NexusFile.h"
33#include <boost/lexical_cast.hpp>
34#include <boost/scoped_array.hpp>
45namespace DataHandling {
60bool exists(
const std::map<std::string, std::string> &entries,
const std::string &
name);
81 const std::string
name()
const override {
return "LoadEventNexus"; };
84 const std::string
summary()
const override {
85 return "Loads an Event NeXus file and stores as an "
86 "EventWorkspace. Optionally, you can filter out events falling "
87 "outside a range of times-of-flight and/or a time interval.";
91 int version()
const override {
return 1; };
92 const std::vector<std::string>
seeAlso()
const override {
93 return {
"LoadISISNexus",
"LoadEventAndCompress",
"LoadEventAsWorkspace2D"};
97 const std::string
category()
const override {
return "DataHandling\\Nexus"; }
101 template <
typename T>
102 static std::shared_ptr<BankPulseTimes>
103 runLoadNexusLogs(
const std::string &nexusfilename, T localWorkspace,
Algorithm &alg,
bool returnpulsetimes,
106 template <
typename T>
107 static std::shared_ptr<BankPulseTimes>
108 runLoadNexusLogs(
const std::string &nexusfilename, T localWorkspace,
Algorithm &alg,
bool returnpulsetimes,
110 const std::vector<std::string> &allow_list,
const std::vector<std::string> &block_list);
114 const int &nPeriods,
const std::string &nexusfilename, std::string &status);
116 template <
typename T>
117 static void loadEntryMetadata(
const std::string &nexusfilename, T WS,
const std::string &entry_name);
120 template <
typename T>
121 static bool loadInstrument(
const std::string &nexusfilename, T localWorkspace,
const std::string &top_entry_name,
125 template <
typename T>
126 static bool runLoadIDFFromNexus(
const std::string &nexusfilename, T localWorkspace,
const std::string &top_entry_name,
130 template <
typename T>
131 static bool runLoadInstrument(
const std::string &nexusfilename, T localWorkspace,
const std::string &top_entry_name,
138 static std::string readInstrumentFromISIS_VMSCompat(Nexus::File &hFile);
145 std::shared_ptr<EventWorkspaceCollection>
m_ws;
164 bool m_is_time_filtered{
false};
166 bool filter_bad_pulses{
false};
196 void init()
override;
199 void exec()
override;
201 std::map<std::string, std::string> validateInputs()
override;
206 void createSpectraMapping(
const std::string &nxsfile,
const bool monitorsOnly,
207 const std::vector<std::string> &bankNames = std::vector<std::string>());
209 void runLoadMonitors();
211 void setTimeFilters(
const bool monitors);
212 template <
typename T>
213 T filterEventsByTime(T
workspace, Mantid::Types::Core::DateAndTime &startTime,
214 Mantid::Types::Core::DateAndTime &stopTime);
217 std::unique_ptr<std::pair<std::vector<int32_t>, std::vector<int32_t>>>
218 loadISISVMSSpectraMapping(
const std::string &entry_name);
220 template <
typename T>
void filterDuringPause(T
workspace);
223 void setTopEntryName();
226 void safeOpenFile(
const std::string &fname);
274 file.openData(binsName);
276 std::vector<float> tofsFile;
277 file.getData(tofsFile);
282 if (end_wi <= start_wi) {
283 end_wi = localWorkspace->getNumberHistograms();
290 for (
size_t wi = start_wi; wi < end_wi; ++wi) {
292 if (event_list.
empty())
296 auto tofsEventList = event_list.
getTofs();
298 size_t n = tofsFile.size();
300 auto ev = tofsEventList.begin();
301 auto ev_end = tofsEventList.end();
302 for (
size_t i = 1; i <
n; ++i) {
303 double right = double(tofsFile[i]);
305 if ((ev != ev_end) && (
right < *ev)) {
310 while ((ev != ev_end) && (*ev <
right)) {
316 double left = double(tofsFile[i - 1]);
318 std::uniform_real_distribution<double> flat(
left,
right);
319 std::vector<double> random_numbers(
m);
320 std::generate(random_numbers.begin(), random_numbers.end(), [&flat, &rng]() { return flat(rng); });
321 std::sort(random_numbers.begin(), random_numbers.end());
322 auto it = random_numbers.begin();
323 for (
auto ev1 = ev -
m; ev1 != ev; ++ev1, ++it) {
329 event_list.
setTofs(tofsEventList);
349 const std::string &classType) {
352 file.openAddress(
"/");
353 file.openGroup(entry_name,
"NXentry");
355 using string_map_t = std::map<std::string, std::string>;
356 string_map_t entries = file.getEntries();
358 if (classType ==
"NXmonitor") {
359 std::vector<std::string> bankNames;
360 for (string_map_t::const_iterator it = entries.begin(); it != entries.end(); ++it) {
361 const std::string entry_class(it->second);
362 if (entry_class == classType) {
363 const std::string entryName(it->first);
364 bankNames.emplace_back(entryName);
367 for (
size_t i = 0; i < bankNames.size(); ++i) {
368 const std::string &mon = bankNames[i];
369 file.openGroup(mon, classType);
370 entries = file.getEntries();
371 if (entries.find(
"event_time_bins") == entries.end()) {
389 file.openGroup(
"detector_1_events",
"NXevent_data");
390 entries = file.getEntries();
391 for (string_map_t::const_iterator it = entries.begin(); it != entries.end(); ++it) {
392 if (it->first ==
"time_of_flight" || it->first ==
"event_time_bins") {
401 file.openGroup(
"instrument",
"NXinstrument");
402 file.openGroup(
"dae",
"IXdae");
403 entries = file.getEntries();
404 size_t time_channels_number = 0;
405 for (string_map_t::const_iterator it = entries.begin(); it != entries.end(); ++it) {
408 if (it->first.size() > 14 && it->first.substr(0, 14) ==
"time_channels_") {
409 size_t n = boost::lexical_cast<size_t>(it->first.substr(14));
410 if (
n > time_channels_number) {
411 time_channels_number =
n;
415 if (time_channels_number > 0)
417 file.openGroup(
"time_channels_" +
std::to_string(time_channels_number),
"IXtime_channels");
418 entries = file.getEntries();
419 for (string_map_t::const_iterator it = entries.begin(); it != entries.end(); ++it) {
420 if (it->first ==
"time_of_flight" || it->first ==
"event_time_bins") {
448 const std::string &top_entry_name,
Algorithm *alg,
450 std::string instrument;
451 std::string instFilename;
458 instFilename = nexusfilename;
461 Nexus::File nxfile(nexusfilename);
463 nxfile.openGroup(top_entry_name,
"NXentry");
465 nxfile.openGroup(
"instrument",
"NXinstrument");
467 nxfile.openData(
"name");
468 instrument = nxfile.getStrData();
469 alg->
getLogger().
debug() <<
"Instrument name read from NeXus file is " << instrument <<
'\n';
474 if (instrument.empty()) {
476 size_t n = nexusfilename.rfind(
'/');
477 if (
n != std::string::npos) {
478 std::string temp = nexusfilename.substr(
n + 1, nexusfilename.size() -
n - 1);
480 if (
n != std::string::npos &&
n > 0) {
481 instrument = temp.substr(0,
n);
486 if (instrument ==
"POWGEN3")
487 instrument =
"POWGEN";
488 if (instrument ==
"NOM")
489 instrument =
"NOMAD";
491 if (instrument.empty())
492 throw std::runtime_error(
"Could not find the instrument name in the NXS "
493 "file or using the filename. Cannot load "
501 if (instFilename.empty()) {
506 if (instFilename.empty()) {
507 std::filesystem::path directory(Kernel::ConfigService::Instance().getInstrumentDirectory());
508 std::filesystem::path file(instrument +
"_Definition.xml");
509 std::filesystem::path fullPath = directory / file;
510 instFilename = fullPath.string();
519 bool executionSuccessful(
true);
521 loadInst->setPropertyValue(
"Filename", instFilename);
522 loadInst->setPropertyValue(
"InstrumentName", instrument);
529 localWorkspace->populateInstrumentParameters();
530 }
catch (std::invalid_argument &e) {
531 alg->
getLogger().
information() <<
"Invalid argument to LoadInstrument Child Algorithm : " << e.what() <<
'\n';
532 executionSuccessful =
false;
533 }
catch (std::runtime_error &e) {
536 executionSuccessful =
false;
540 if (!executionSuccessful) {
541 alg->
getLogger().
error() <<
"Error loading Instrument definition file\n";
547 const auto &
pmap = localWorkspace->constInstrumentParameters();
548 if (!
pmap.contains(localWorkspace->getInstrument()->getComponentID(),
"det-pos-source"))
549 return executionSuccessful;
551 std::shared_ptr<Geometry::Parameter> updateDets =
552 pmap.get(localWorkspace->getInstrument()->getComponentID(),
"det-pos-source");
553 std::string
value = updateDets->value<std::string>();
554 if (
value.substr(0, 8) ==
"datafile") {
557 updateInst->setPropertyValue(
"Filename", nexusfilename);
558 if (
value ==
"datafile-ignore-phi") {
559 updateInst->setProperty(
"IgnorePhi",
true);
561 "positions in the data file except for the "
564 alg->
getLogger().
information(
"Detector positions in IDF updated with positions in the data file");
568 updateInst->execute();
571 return executionSuccessful;
579 Nexus::File file(nexusfilename);
580 file.openGroup(entry_name,
"NXentry");
583 if (file.hasData(
"/" + entry_name +
"/title")) {
584 file.openData(
"title");
586 std::string title = file.getStrData();
594 if (file.hasData(
"/" + entry_name +
"/notes")) {
595 file.openData(
"notes");
597 std::string notes = file.getStrData();
599 WS->mutableRun().addProperty(
"file_notes", notes,
true);
605 if (file.hasData(
"/" + entry_name +
"/run_number")) {
606 file.openData(
"run_number");
609 run = file.getStrData();
610 }
else if (file.isDataInt()) {
612 std::vector<int>
value;
618 WS->mutableRun().addProperty(
"run_number", run,
true);
624 if (file.hasData(
"/" + entry_name +
"/experiment_identifier")) {
625 file.openData(
"experiment_identifier");
628 expId = file.getStrData();
630 if (!expId.empty()) {
631 WS->mutableRun().addProperty(
"experiment_identifier", expId,
true);
638 if (file.hasGroup(
"/" + entry_name +
"/sample",
"NXsample")) {
639 file.openGroup(
"sample",
"NXsample");
641 if (file.hasData(
"/" + entry_name +
"/sample/name")) {
642 file.openData(
"name");
643 const auto info = file.getInfo();
644 std::string sampleName;
646 if (info.dims.size() == 1) {
647 sampleName = file.getStrData();
649 const int64_t total_length = std::accumulate(info.dims.begin(), info.dims.end(),
static_cast<int64_t
>(1),
650 std::multiplies<int64_t>());
651 boost::scoped_array<char> val_array(
new char[total_length]);
652 file.getData(val_array.get());
653 sampleName = std::string(val_array.get(), total_length);
657 if (!sampleName.empty()) {
658 WS->mutableSample().setName(sampleName);
668 if (file.hasData(
"/" + entry_name +
"/duration")) {
669 file.openData(
"duration");
670 std::vector<double> duration;
671 file.getDataCoerce(duration);
672 if (duration.size() == 1) {
675 if (file.hasAttr(
"units")) {
676 file.getAttr<std::string>(
"units", units);
680 WS->mutableRun().addProperty(
"duration", duration[0], units,
true);
704 const std::string &top_entry_name,
Algorithm *alg,
707 bool loadNexusInstrumentXML =
true;
709 loadNexusInstrumentXML = alg->
getProperty(
"LoadNexusInstrumentXML");
711 bool foundInstrument =
false;
712 if (loadNexusInstrumentXML)
713 foundInstrument = runLoadIDFFromNexus<T>(nexusfilename, localWorkspace, top_entry_name, alg);
714 if (!foundInstrument)
715 foundInstrument = runLoadInstrument<T>(nexusfilename, std::move(localWorkspace), top_entry_name, alg, descriptor);
716 return foundInstrument;
731 const std::string &top_entry_name,
Algorithm *alg) {
734 Nexus::File nxsfile(nexusfilename);
735 nxsfile.openAddress(top_entry_name +
"/instrument/instrument_xml");
737 alg->
getLogger().
information(
"No instrument XML definition found in " + nexusfilename +
" at " + top_entry_name +
746 loadInst->setPropertyValue(
"Filename", nexusfilename);
748 loadInst->setPropertyValue(
"InstrumentParentPath", top_entry_name);
750 }
catch (std::invalid_argument &) {
751 alg->
getLogger().
error(
"Invalid argument to LoadIDFFromNexus Child Algorithm ");
752 }
catch (std::runtime_error &) {
753 alg->
getLogger().
debug(
"No instrument definition found by LoadIDFFromNexus in " + nexusfilename +
" at " +
754 top_entry_name +
"/instrument");
757 if (!loadInst->isExecuted())
759 return loadInst->isExecuted();
double value
The value of the point.
IPeaksWorkspace_sptr workspace
Base class from which all concrete algorithm classes should be derived.
bool existsProperty(const std::string &name) const override
Checks whether the named property is already in the list of managed property.
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 & getLogger() const
Returns a reference to the logger.
Defines an interface to an algorithm that loads a file so that it can take part in the automatic sele...
static std::string getInstrumentFilename(const std::string &instrumentName, const std::string &date="")
Get the IDF using the instrument name and date.
Helper class for reporting progress from algorithms.
EventWorkspaceCollection : Collection of EventWorspaces to give backward-forward compatibility around...
Custom exception extending std::invalid_argument Thrown when nperiods does not match period_log Custo...
InvalidLogPeriods(const std::string &msg)
std::shared_ptr< Mantid::Kernel::TimeROI > bad_pulses_timeroi
double longest_tof
Limits found to tof.
Mantid::Types::Core::DateAndTime filter_time_start
Filter by start time.
double filter_tof_max
Filter by a maximum time-of-flight.
bool loadlogs
Do we load the sample logs?
bool event_id_is_spec
True if the event_id is spectrum no not pixel ID.
size_t discarded_events
A count of events discarded because they came from a pixel that's not in the IDF.
Mantid::Types::Core::DateAndTime filter_time_stop
Filter by stop time.
static bool runLoadInstrument(const std::string &nexusfilename, T localWorkspace, const std::string &top_entry_name, Algorithm *alg, const Nexus::NexusDescriptor *descriptor=nullptr)
Load instrument from IDF file specified by Nexus file.
const std::string summary() const override
Summary of algorithms purpose.
int32_t m_specMax
Maximum spectrum to load.
double compressTolerance
Tolerance for CompressEvents; use -1 to mean don't compress.
const std::string category() const override
Category.
std::string m_filename
The name and path of the input file.
std::shared_ptr< BankPulseTimes > m_allBanksPulseTimes
Pulse times for ALL banks, taken from proton_charge log.
static void loadEntryMetadata(const std::string &nexusfilename, T WS, const std::string &entry_name)
Load the run number and other meta data from the given bank.
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.
const std::vector< std::string > seeAlso() const override
Function to return all of the seeAlso (these are not validated) algorithms related to this algorithm....
double shortest_tof
Limits found to tof.
std::mutex m_tofMutex
Mutex protecting tof limits.
bool filter_tof_range
Tof range is being filtered.
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...
DataObjects::EventWorkspace_sptr createEmptyEventWorkspace()
const std::string name() const override
function to return a name of the algorithm, must be overridden in all algorithms
std::unique_ptr< Nexus::File > m_file
std::shared_ptr< EventWorkspaceCollection > m_ws
The workspace being filled out.
static bool runLoadIDFFromNexus(const std::string &nexusfilename, T localWorkspace, const std::string &top_entry_name, Algorithm *alg)
Load instrument for Nexus file.
bool m_instrument_loaded_correctly
Was the instrument loaded?
size_t bad_tofs
Count of all the "bad" tofs found.
int32_t m_specMin
Minimum spectrum to load.
int version() const override
Version.
double filter_tof_min
Filter by a minimum time-of-flight.
std::string m_top_entry_name
name of top level NXentry to use
void setTofs(const MantidVec &tofs) override
Set a list of TOFs to the current event list.
void sortTof() const
Sort events by TOF in one thread.
bool empty() const
Much like stl containers, returns true if there is nothing in the event list.
void getTofs(std::vector< double > &tofs) const override
Fill a vector with the list of TOFs.
Exception for when an item is not found in a collection.
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void information(const std::string &msg)
Logs at information level.
OptionalBool : Tri-state bool.
A specialised Property class for holding a series of time-value pairs.
Class that provides for a standard Nexus exception.
const std::map< std::string, std::set< std::string > > & getAllEntries() const noexcept
Returns a const reference of the internal map holding all entries in the Nexus HDF5 file.
static unsigned short constexpr CHAR
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
bool isNexus(const std::string &filename)
Determine if the Geometry file type is Nexus.
void makeTimeOfFlightDataFuzzy(Nexus::File &file, T localWorkspace, const std::string &binsName, size_t start_wi=0, size_t end_wi=0)
Load the time of flight data.
std::shared_ptr< EventWorkspaceCollection > EventWorkspaceCollection_sptr
bool exists(Nexus::File &file, const std::string &name)
void loadEvents(API::Progress &prog, const char *progMsg, EP &eventProcessor, const Nexus::NXEntry &entry, uint64_t start_nsec, uint64_t end_nsec)
void adjustTimeOfFlightISISLegacy(Nexus::File &file, T localWorkspace, const std::string &entry_name, const std::string &classType)
ISIS specific method for dealing with wide events.
MANTID_DATAHANDLING_DLL bool doPerformISISEventShift(Nexus::File &file, std::string &topEntryName)
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
Helper class which provides the Collimation Length for SANS instruments.
Generate a tableworkspace to store the calibration results.
std::string to_string(const wide_integer< Bits, Signed > &n)