25#include "MantidIndexing/IndexInfo.h"
42using Mantid::Types::Core::DateAndTime;
51using namespace Kernel;
52using namespace DateAndTimeHelpers;
53using namespace Geometry;
55using namespace DataObjects;
56using Types::Core::DateAndTime;
60const std::string NULL_STR(
"NULL");
69bool exists(::NeXus::File &file,
const std::string &name) {
70 const auto entries = file.getEntries();
71 return exists(entries, name);
74bool exists(
const std::map<std::string, std::string> &entries,
const std::string &name) {
75 return entries.find(name) != entries.end();
82 : filter_tof_min(0), filter_tof_max(0), m_specMin(0), m_specMax(0), longest_tof(0), shortest_tof(0), bad_tofs(0),
83 discarded_events(0), compressTolerance(0), m_instrument_loaded_correctly(false), loadlogs(false),
84 event_id_is_spec(false) {}
96 const std::map<std::string, std::set<std::string>> &allEntries = descriptor.
getAllEntries();
97 if (allEntries.count(
"NXevent_data") == 1) {
98 if (descriptor.
isEntry(
"/entry",
"NXentry") || descriptor.
isEntry(
"/raw_data_1",
"NXentry")) {
110 const std::vector<std::string> exts{
".nxs.h5",
".nxs",
"_event.nxs"};
112 "The name of the Event NeXus file to read, including its full or "
114 "The file name is typically of the form INST_####_event.nxs (N.B. case "
115 "sensitive if running on Linux).");
118 "The name of the output EventWorkspace or WorkspaceGroup in which to "
119 "load the EventNexus file.");
122 "Optional: Name of the NXentry to load if it's not the default.");
125 "Optional: To exclude events that do not fall within a range "
126 "of times-of-flight. "
127 "This is the minimum accepted value in microseconds. Keep "
128 "blank to load all events.");
131 "Optional: To exclude events that do not fall within a range "
132 "of times-of-flight. "
133 "This is the maximum accepted value in microseconds. Keep "
134 "blank to load all events.");
137 "Optional: To only include events after the provided start "
138 "time, in seconds (relative to the start of the run).");
141 "Optional: To only include events before the provided stop "
142 "time, in seconds (relative to the start of the run).");
144 std::string grp1 =
"Filter Events";
151 "Optional: To only include events from one bank. Any bank "
152 "whose name does not match the given string will have no "
156 "Optional: Only applies if you specified a single bank to "
157 "load with BankName. "
158 "Only pixels in the specified bank will be created if true; "
159 "all of the instrument's pixels will be created otherwise.");
162 std::string grp2 =
"Loading a Single Bank";
167 "Pre-count the number of events in each pixel before allocating memory "
168 "(optional, default True). "
169 "This can significantly reduce memory use and memory fragmentation; it "
170 "may also speed up loading.");
173 "Run CompressEvents while loading (optional, leave blank or "
174 "negative to not do). "
175 "This specified the tolerance to use (in microseconds) when "
178 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
179 mustBePositive->setLower(1);
181 "If loading the file by sections ('chunks'), this is the "
182 "section number of this execution of the algorithm.");
184 "If loading the file by sections ('chunks'), this is the "
185 "total number of sections.");
191 std::string grp3 =
"Reduce Memory Use";
198 "Load the monitors from the file (optional, default False).");
200 std::vector<std::string> options{
"",
"Events",
"Histogram"};
201 declareProperty(
"MonitorsLoadOnly",
"", std::make_shared<Kernel::StringListValidator>(options),
202 "If multiple repesentations exist, which one to load. "
203 "Default is to load the one that is present.");
206 "Optional: To exclude events from monitors that do not fall "
207 "within a range of times-of-flight. "
208 "This is the minimum accepted value in microseconds.");
211 "Optional: To exclude events from monitors that do not fall "
212 "within a range of times-of-flight. "
213 "This is the maximum accepted value in microseconds.");
216 "Optional: To only include events from monitors after the "
217 "provided start time, in seconds (relative to the start of "
221 "Optional: To only include events from monitors before the "
222 "provided stop time, in seconds (relative to the start of "
226 auto asEventsIsOn = [] {
227 std::unique_ptr<IPropertySettings> prop = std::make_unique<VisibleWhenProperty>(
"LoadMonitors",
IS_EQUAL_TO,
"1");
235 std::string grp4 =
"Monitors";
246 "A comma-separated list of individual spectra to read.");
249 "If true, only the meta data and sample logs will be loaded.");
252 "Load only the Sample/DAS logs from the file (default True).");
255 "Load all the logs from the nxs, without checking or processing them; if checked, LoadLogs will be "
256 "ignored; use with caution");
258 std::vector<std::string> loadType{
"Default"};
261 loadType.emplace_back(
"Multiprocess (experimental)");
264#ifdef MPI_EXPERIMENTAL
265 loadType.emplace_back(
"MPI");
268 auto loadTypeValidator = std::make_shared<StringListValidator>(loadType);
270 "Set type of loader. 2 options {Default, Multiproceess},"
271 "'Multiprocess' should work faster for big files and it is "
272 "experimental, available only in Linux");
275 "Reads the embedded Instrument XML from the NeXus file "
276 "(optional, default True). ");
279 "The number of bins intially defined. Use Rebin to change "
280 "the binning later. If there is no data loaded, or you "
281 "select meta data only you will only get 1 bin.");
286 "If specified, only these logs will be loaded from the file (each "
287 "separated by a space).");
290 "If specified, these logs will NOT be loaded from the file (each "
291 "separated by a space).");
298 std::string nxentryProperty =
getProperty(
"NXentryName");
299 if (!nxentryProperty.empty()) {
306 const auto entry =
m_file->getNextEntry();
307 if (entry.second ==
"NXentry") {
308 if ((entry.first ==
"entry") || (entry.first ==
"raw_data_1")) {
312 }
else if (entry.first == NULL_STR && entry.second == NULL_STR) {
313 g_log.
error() <<
"Unable to determine name of top level NXentry - assuming "
319 }
catch (
const std::exception &) {
320 g_log.
error() <<
"Unable to determine name of top level NXentry - assuming "
329 (
m_ws->run().getLogData(
"pause")->size() > 1)) {
330 g_log.
notice(
"Filtering out events when the run was marked as paused. "
331 "Set the loadeventnexus.keeppausedevents configuration "
332 "property to override this.");
335 filter->setProperty(
"InputWorkspace",
workspace);
336 filter->setProperty(
"OutputWorkspace",
workspace);
337 filter->setProperty(
"LogName",
"pause");
339 filter->setProperty(
"MinimumValue", 0.0);
340 filter->setProperty(
"MaximumValue", 0.0);
341 filter->setProperty(
"LogBoundary",
"Left");
352 using std::placeholders::_1;
353 auto func = std::bind(&LoadEventNexus::filterDuringPause<MatrixWorkspace_sptr>,
this, _1);
364 Mantid::Types::Core::DateAndTime &stopTime) {
370 filterByTime->setProperty(
"AbsoluteStartTime", startTime.toISO8601String());
371 filterByTime->setProperty(
"AbsoluteStopTime", stopTime.toISO8601String());
379 Mantid::Types::Core::DateAndTime &startTime,
380 Mantid::Types::Core::DateAndTime &stopTime) {
382 using std::placeholders::_1;
383 auto func = std::bind(&LoadEventNexus::filterEventsByTime<EventWorkspace_sptr>,
this, _1, startTime, stopTime);
401 bool load_monitors = this->
getProperty(
"LoadMonitors");
413 Progress prog(
this, 0.0, 0.3, reports);
416 m_ws = std::make_shared<EventWorkspaceCollection>();
423 <<
" events were encountered coming from pixels which "
424 "are not in the Instrument Definition File."
425 "These events were discarded.\n";
443 prog.
report(
"Loading monitors");
449 file.openData(
"event_time_zero");
450 std::string isooffset;
455 if (!file.hasAttr(
"offset")) {
456 offset = DateAndTime(
"1970-01-01T00:00:00Z");
457 logger.
warning(
"In firstLastPulseTimes: no ISO8601 offset attribute "
458 "provided for event_time_zero, using UNIX epoch instead");
460 file.getAttr(
"offset", isooffset);
461 offset = DateAndTime(isooffset);
464 if (file.hasAttr(
"units"))
465 file.getAttr(
"units", units);
467 auto pulse_times = Mantid::NeXus::NeXusIOHelper::readNexusVector<double>(file,
"event_time_zero");
470 if (pulse_times.empty()) {
471 throw std::invalid_argument(
"Cannot find run start; event_time_zero contains no pulse times");
475 return std::make_pair(DateAndTime(pulse_times.front() * conv, 0.0) + offset.totalNanoseconds(),
476 DateAndTime(pulse_times.back() * conv, 0.0) + offset.totalNanoseconds());
491std::size_t
numEvents(::NeXus::File &file,
bool &hasTotalCounts,
bool &oldNeXusFileNames,
const std::string &prefix,
494 if (hasTotalCounts) {
495 hasTotalCounts =
false;
496 if (descriptor.
isEntry(prefix +
"/total_counts")) {
498 file.openData(
"total_counts");
499 auto info = file.getInfo();
501 if (info.type == ::NeXus::UINT64) {
503 file.readData(
"total_counts", eventCount);
504 hasTotalCounts =
true;
507 }
catch (::NeXus::Exception &) {
514 if (oldNeXusFileNames)
515 file.openData(
"event_pixel_id");
517 file.openData(
"event_id");
518 }
catch (::NeXus::Exception &) {
521 file.openData(
"event_pixel_id");
522 oldNeXusFileNames =
true;
523 }
catch (::NeXus::Exception &) {
529 size_t numEvents =
static_cast<std::size_t
>(file.getInfo().dims[0]);
548std::shared_ptr<BankPulseTimes>
550 bool returnpulsetimes,
int &nPeriods,
555 std::shared_ptr<BankPulseTimes> out;
562 loadLogs->setPropertyValue(
"Filename", nexusfilename);
565 loadLogs->setPropertyValue(
"NXentryName", alg.
getPropertyValue(
"NXentryName"));
571 const Run &run = localWorkspace->run();
580 std::unique_ptr<TimeSeriesProperty<int>> tempPeriodLog(
dynamic_cast<TimeSeriesProperty<int> *
>(temp->clone()));
585 std::vector<Types::Core::DateAndTime> temp;
586 if (localWorkspace->run().hasProperty(
"proton_charge")) {
592 if (returnpulsetimes)
593 out = std::make_shared<BankPulseTimes>(temp);
597 if (temp[0] < Types::Core::DateAndTime(
"1991-01-01T00:00:00"))
599 "sample log with invalid pulse time!\n";
601 Types::Core::DateAndTime run_start = localWorkspace->getFirstPulseTime();
606 localWorkspace->mutableRun().addProperty(
"run_start", run_start.toISO8601String(),
true);
608 localWorkspace->mutableRun().addProperty(
"run_start", run.
getProperty(
"start_time")->
value(),
true);
611 "not be able to filter by time.\n";
617 localWorkspace->mutableRun().setGoniometer(gm,
true);
618 }
catch (std::runtime_error &) {
625 alg.
getLogger().
error() <<
"Error while loading Logs from SNS Nexus. Some "
626 "sample logs may be missing."
650 const std::string &nexusfilename, T localWorkspace,
API::Algorithm &alg,
bool returnpulsetimes,
int &nPeriods,
652 const std::vector<std::string> &block_list) {
656 std::shared_ptr<BankPulseTimes> out;
663 loadLogs->setPropertyValue(
"Filename", nexusfilename);
665 loadLogs->setProperty<std::vector<std::string>>(
"AllowList", allow_list);
666 loadLogs->setProperty<std::vector<std::string>>(
"BlockList", block_list);
669 loadLogs->setPropertyValue(
"NXentryName", alg.
getPropertyValue(
"NXentryName"));
675 const Run &run = localWorkspace->run();
684 std::unique_ptr<TimeSeriesProperty<int>> tempPeriodLog(
dynamic_cast<TimeSeriesProperty<int> *
>(temp->clone()));
689 std::vector<Types::Core::DateAndTime> temp;
690 if (localWorkspace->run().hasProperty(
"proton_charge")) {
696 if (returnpulsetimes)
697 out = std::make_shared<BankPulseTimes>(temp);
701 if (temp[0] < Types::Core::DateAndTime(
"1991-01-01T00:00:00"))
703 "sample log with invalid pulse time!\n";
705 Types::Core::DateAndTime run_start = localWorkspace->getFirstPulseTime();
710 localWorkspace->mutableRun().addProperty(
"run_start", run_start.toISO8601String(),
true);
713 "not be able to filter by time.\n";
719 localWorkspace->mutableRun().setGoniometer(gm,
true);
720 }
catch (std::runtime_error &) {
727 alg.
getLogger().
error() <<
"Error while loading Logs from SNS Nexus. Some "
728 "sample logs may be missing."
749 const int &nPeriods,
const std::string &nexusfilename) {
750 const auto valuesAsVector = tempPeriodLog->valuesAsVector();
751 const auto nPeriodsInLog = *std::max_element(valuesAsVector.begin(), valuesAsVector.end());
754 if (nPeriodsInLog == 0 && nPeriods == 1) {
757 const std::vector<int> newValues(tempPeriodLog->realSize(), 1);
758 const auto times = tempPeriodLog->timesAsVector();
760 }
else if (nPeriodsInLog != nPeriods) {
766 const auto msg =
"File " + nexusfilename +
767 " has been corrupted. The log framelog/period_log/value "
769 std::to_string(nPeriodsInLog) +
" periods, but periods/number contains " +
770 std::to_string(nPeriods) +
". This file should be manually inspected and corrected.";
774 periodLog = std::make_unique<const TimeSeriesProperty<int>>(*tempPeriodLog);
775 tempPeriodLog.reset();
794std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs<EventWorkspaceCollection_sptr>(
797 auto ws = localWorkspace->getSingleHeldWorkspace();
798 auto ret = runLoadNexusLogs<MatrixWorkspace_sptr>(nexusfilename, ws, alg, returnpulsetimes, nPeriods, periodLog);
819std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs<EventWorkspaceCollection_sptr>(
822 const std::vector<std::string> &allow_list,
const std::vector<std::string> &block_list) {
823 auto ws = localWorkspace->getSingleHeldWorkspace();
824 auto ret = runLoadNexusLogs<MatrixWorkspace_sptr>(nexusfilename, ws, alg, returnpulsetimes, nPeriods, periodLog,
825 allow_list, block_list);
849 std::vector<std::string> allow_list =
getProperty(
"AllowList");
850 std::vector<std::string> block_list =
getProperty(
"BlockList");
853 DateAndTime run_start(0, 0);
854 bool takeTimesFromEvents =
false;
858 auto periodLog = std::make_unique<const TimeSeriesProperty<int>>(
"period_log");
866 if (allow_list.empty() && block_list.empty()) {
868 runLoadNexusLogs<EventWorkspaceCollection_sptr>(
m_filename,
m_ws, *
this,
true, nPeriods, periodLog);
871 periodLog, allow_list, block_list);
875 run_start =
m_ws->getFirstPulseTime();
883 takeTimesFromEvents =
true;
889 NXstatus nxStat = NXopen(
m_filename.c_str(), NXACC_READ, &nxHandle);
891 if (nxStat != NX_ERROR) {
898 <<
"Reading the start time directly from /" <<
m_top_entry_name <<
"/start_time\n";
906 m_ws->mutableRun().addProperty(
"run_start", run_start.toISO8601String(),
true);
909 const std::shared_ptr<NexusHDF5Descriptor> descriptor =
getFileInfo();
916 }
catch (std::runtime_error &e) {
918 g_log.
error() <<
"Error loading metadata: " << e.what() <<
'\n';
921 m_ws->setNPeriods(
static_cast<size_t>(nPeriods),
926 std::vector<DateAndTime> temp;
932 prog->
report(
"Loading instrument");
941 throw std::runtime_error(
"Instrument was not initialized correctly! "
942 "Loading cannot continue.");
953 vector<string> bankNames;
954 vector<std::size_t> bankNumEvents;
955 std::string classType = monitors ?
"NXmonitor" :
"NXevent_data";
957 bool oldNeXusFileNames(
false);
958 bool haveWeights =
false;
959 auto firstPulseT = DateAndTime::maximum();
961 const std::map<std::string, std::set<std::string>> &allEntries = descriptor->getAllEntries();
963 auto itClassEntries = allEntries.find(classType);
965 if (itClassEntries != allEntries.end()) {
967 const std::set<std::string> &classEntries = itClassEntries->second;
971 for (
const std::string &classEntry : classEntries) {
973 if (std::regex_match(classEntry, groups, classRegex)) {
974 const std::string entry_name(groups[2].str());
977 if (entry_name ==
"bank_error_events" || entry_name ==
"bank_unmapped_events")
980 m_file->openGroup(entry_name, classType);
984 bool hasTotalCounts =
true;
985 std::size_t num =
numEvents(*
m_file, hasTotalCounts, oldNeXusFileNames, prefix, *descriptor);
986 bankNames.emplace_back(entry_name);
987 bankNumEvents.emplace_back(num);
989 if (takeTimesFromEvents && num > 0) {
995 firstPulseT = std::min(firstPulseT, localFirstLast.first);
999 const std::string absoluteEventWeightName = prefix +
"/event_weight";
1000 haveWeights = descriptor->isEntry(absoluteEventWeightName);
1006 if (takeTimesFromEvents)
1007 run_start = firstPulseT;
1021 double filter_time_start_sec, filter_time_stop_sec;
1022 filter_time_start_sec =
getProperty(
"FilterByTimeStart");
1023 filter_time_stop_sec =
getProperty(
"FilterByTimeStop");
1026 bool is_time_filtered =
false;
1033 if (filter_time_start_sec !=
EMPTY_DBL()) {
1035 is_time_filtered =
true;
1038 if (filter_time_stop_sec !=
EMPTY_DBL()) {
1040 is_time_filtered =
true;
1045 std::string msg =
"Your ";
1048 msg +=
"filter for time's Stop value is smaller than the Start value.";
1049 throw std::invalid_argument(msg);
1055 auto axis = HistogramData::BinEdges{1,
static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1 - 1};
1057 m_ws->setAllX(axis);
1064 std::vector<std::string> someBanks =
getProperty(
"BankName");
1065 const bool SingleBankPixelsOnly =
getProperty(
"SingleBankPixelsOnly");
1066 if ((!someBanks.empty()) && (!monitors)) {
1067 std::vector<std::string> eventedBanks;
1068 eventedBanks.reserve(someBanks.size());
1069 std::transform(someBanks.cbegin(), someBanks.cend(), std::back_inserter(eventedBanks),
1070 [](
const auto &bank) { return bank +
"_events"; });
1073 const auto invalidBank =
1074 std::find_if(eventedBanks.cbegin(), eventedBanks.cend(), [&bankNames](
const auto &someBank) {
1075 return std::none_of(bankNames.cbegin(), bankNames.cend(),
1076 [&someBank](const auto &name) { return name == someBank; });
1078 if (invalidBank != eventedBanks.cend()) {
1079 throw std::invalid_argument(
"No entry named '" + *invalidBank +
"' was found in the .NXS file.");
1083 bankNames.assign(eventedBanks.cbegin(), eventedBanks.cend());
1086 bankNumEvents.assign(someBanks.size(), 1);
1088 if (!SingleBankPixelsOnly)
1092 prog->report(
"Initializing all pixels");
1095 if (m_ws->getInstrument()->hasParameter(
"remove-unused-banks")) {
1096 std::vector<double> instrumentUnused = m_ws->getInstrument()->getNumberParameter(
"remove-unused-banks",
true);
1097 if (!instrumentUnused.empty()) {
1098 const auto unused =
static_cast<int>(instrumentUnused.front());
1100 deleteBanks(m_ws, bankNames);
1104 createSpectraMapping(m_filename, monitors, someBanks);
1108 for (
size_t i = 0; i < m_ws->getNumberHistograms(); i++)
1112 shortest_tof =
static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1;
1116 auto loaderType = defineLoaderType(haveWeights, oldNeXusFileNames, classType);
1117 if (loaderType != LoaderType::DEFAULT) {
1118 auto ws = m_ws->getSingleHeldWorkspace();
1120 if (loaderType == LoaderType::MPI) {
1127 }
catch (
const std::runtime_error &) {
1128 g_log.
warning() <<
"MPI event loader failed, falling back to default loader.\n";
1132 struct ExceptionOutput {
1133 static void out(
decltype(g_log) &log,
const std::exception &except,
int level = 0) {
1134 log.warning() << std::string(level,
' ') <<
"exception: " << except.what() <<
'\n';
1136 std::rethrow_if_nested(except);
1137 }
catch (
const std::exception &e) {
1138 ExceptionOutput::out(log, e, level + 1);
1146 getProperty(
"Precount"));
1151 }
catch (
const std::exception &e) {
1152 ExceptionOutput::out(
g_log, e);
1153 g_log.
warning() <<
"\nMultiprocess event loader failed, falling back "
1154 "to default loader.\n";
1158 safeOpenFile(m_filename);
1161 bool precount = getProperty(
"Precount");
1162 int chunk = getProperty(
"ChunkNumber");
1163 int totalChunks = getProperty(
"TotalChunks");
1165 classType, bankNumEvents, oldNeXusFileNames, precount, chunk, totalChunks);
1169 const std::size_t eventsLoaded = m_ws->getNumberEvents();
1171 <<
". Shortest TOF: " << shortest_tof <<
" microsec; longest TOF: " << longest_tof
1174 if (shortest_tof < 0)
1175 g_log.
warning() <<
"The shortest TOF was negative! At least 1 event has an "
1176 "invalid time-of-flight.\n";
1179 <<
" events with TOF > 2e8. This "
1180 "may indicate errors in the raw "
1184 if (m_ws->getInstrument()->hasParameter(
"T0")) {
1185 std::vector<double> instrumentT0 = m_ws->getInstrument()->getNumberParameter(
"T0",
true);
1186 if (!instrumentT0.empty()) {
1187 const double mT0 = instrumentT0.front();
1189 auto numHistograms =
static_cast<int64_t
>(m_ws->getNumberHistograms());
1191 for (int64_t i = 0; i < numHistograms; ++i) {
1194 m_ws->getSpectrum(i).addTof(mT0);
1199 API::Run &run = m_ws->mutableRun();
1200 run.addProperty<
double>(
"T0", mT0,
true);
1205 if (eventsLoaded > 0) {
1206 int nBins = getProperty(
"NumberOfBins");
1207 auto binEdgesVec = std::vector<double>(nBins + 1);
1208 binEdgesVec[0] = shortest_tof - 1;
1209 binEdgesVec[nBins] = longest_tof + 1;
1210 double binStep = (binEdgesVec[nBins] - binEdgesVec[0]) / nBins;
1211 for (
int binIndex = 1; binIndex < nBins; binIndex++) {
1212 binEdgesVec[binIndex] = binEdgesVec[0] + (binStep * binIndex);
1214 m_ws->setAllX(HistogramData::BinEdges{binEdgesVec});
1216 m_ws->setAllX(HistogramData::BinEdges{0.0, 1.0});
1221 if (is_time_filtered) {
1224 filterEventsByTime(m_ws, filter_time_start, filter_time_stop);
1240bool LoadEventNexus::runLoadIDFFromNexus<EventWorkspaceCollection_sptr>(
const std::string &nexusfilename,
1242 const std::string &top_entry_name,
1244 auto ws = localWorkspace->getSingleHeldWorkspace();
1245 auto hasLoaded = runLoadIDFFromNexus<MatrixWorkspace_sptr>(nexusfilename, ws, top_entry_name, alg);
1246 localWorkspace->setInstrument(ws->getInstrument());
1255 std::string instrumentName;
1257 hFile.openGroup(
"isis_vms_compat",
"IXvms");
1258 }
catch (std::runtime_error &) {
1259 return instrumentName;
1262 hFile.openData(
"NAME");
1263 }
catch (std::runtime_error &) {
1265 return instrumentName;
1268 instrumentName = hFile.getStrData();
1272 return instrumentName;
1289bool LoadEventNexus::runLoadInstrument<EventWorkspaceCollection_sptr>(
const std::string &nexusfilename,
1291 const std::string &top_entry_name,
Algorithm *alg,
1293 auto ws = localWorkspace->getSingleHeldWorkspace();
1294 auto hasLoaded = runLoadInstrument<MatrixWorkspace_sptr>(nexusfilename, ws, top_entry_name, alg, descriptor);
1295 localWorkspace->setInstrument(ws->getInstrument());
1306 const std::vector<std::string> &bankNames) {
1309 std::vector<std::shared_ptr<RectangularDetector>> detList;
1310 for (
int i = 0; i < inst->nelements(); i++) {
1311 std::shared_ptr<RectangularDetector> det;
1312 std::shared_ptr<ICompAssembly> assem;
1313 std::shared_ptr<ICompAssembly> assem2;
1315 det = std::dynamic_pointer_cast<RectangularDetector>((*inst)[i]);
1317 detList.emplace_back(det);
1322 assem = std::dynamic_pointer_cast<ICompAssembly>((*inst)[i]);
1324 for (
int j = 0; j < assem->nelements(); j++) {
1325 det = std::dynamic_pointer_cast<RectangularDetector>((*assem)[j]);
1327 detList.emplace_back(det);
1333 assem2 = std::dynamic_pointer_cast<ICompAssembly>((*assem)[j]);
1335 for (
int k = 0; k < assem2->nelements(); k++) {
1336 det = std::dynamic_pointer_cast<RectangularDetector>((*assem2)[k]);
1338 detList.emplace_back(det);
1347 if (detList.empty())
1349 for (
auto &det : detList) {
1351 std::string det_name = det->getName();
1352 for (
auto &bankName : bankNames) {
1353 size_t pos = bankName.find(
"_events");
1354 if (det_name == bankName.substr(0, pos))
1360 std::shared_ptr<const IComponent> parent = inst->getComponentByName(det_name);
1361 std::vector<Geometry::IComponent_const_sptr> children;
1362 std::shared_ptr<const Geometry::ICompAssembly> asmb =
1363 std::dynamic_pointer_cast<const Geometry::ICompAssembly>(parent);
1364 asmb->getChildren(children,
false);
1365 for (
auto &col : children) {
1366 std::shared_ptr<const Geometry::ICompAssembly> asmb2 =
1367 std::dynamic_pointer_cast<const Geometry::ICompAssembly>(col);
1368 std::vector<Geometry::IComponent_const_sptr> grandchildren;
1369 asmb2->getChildren(grandchildren,
false);
1371 for (
auto &row : grandchildren) {
1374 inst->removeDetector(
d);
1377 auto *comp =
dynamic_cast<IComponent *
>(det.get());
1392 const std::vector<std::string> &bankNames) {
1395 if (!monitorsOnly && !bankNames.empty()) {
1397 g_log.
warning() <<
"Spectrum min/max/list selection ignored when "
1398 "`SingleBankPixelsOnly` is enabled\n";
1400 g_log.
debug() <<
"Populated spectra map for select banks\n";
1403 g_log.
debug() <<
"Loading only monitor spectra from " << nxsfile <<
"\n";
1405 g_log.
debug() <<
"Loading only detector spectra from " << nxsfile <<
"\n";
1409 g_log.
debug() <<
"No custom spectra mapping found, continuing with default "
1410 "1:1 mapping of spectrum:detectorID\n";
1412 g_log.
debug() <<
"Populated 1:1 spectra map for the whole instrument \n";
1424 std::string mon_wsname = this->
getProperty(
"OutputWorkspace");
1425 mon_wsname.append(
"_monitors");
1429 loadMonitors->setPropertyValue(
"Filename",
m_filename);
1430 g_log.
information() <<
"New workspace name for monitors: " << mon_wsname <<
'\n';
1431 loadMonitors->setPropertyValue(
"OutputWorkspace", mon_wsname);
1432 loadMonitors->setPropertyValue(
"LoadOnly", this->
getProperty(
"MonitorsLoadOnly"));
1433 loadMonitors->setPropertyValue(
"NXentryName", this->
getProperty(
"NXentryName"));
1434 loadMonitors->execute();
1435 Workspace_sptr monsOut = loadMonitors->getProperty(
"OutputWorkspace");
1439 "Monitors from the Event NeXus file");
1446 m_ws->setMonitorWorkspace(mons);
1453 for (
int i = 0; i < monsGrp->getNumberOfEntries(); i++) {
1454 std::stringstream ssWsName;
1455 ssWsName << mon_wsname <<
"_" << i + 1;
1456 std::stringstream ssPropName;
1457 ssPropName <<
"MonitorWorkspace"
1461 "Monitors from the Event NeXus file");
1462 this->
setProperty(ssPropName.str(), monsGrp->getItem(i));
1478std::unique_ptr<std::pair<std::vector<int32_t>, std::vector<int32_t>>>
1480 const std::string vms_str =
"/isis_vms_compat";
1482 g_log.
debug() <<
"Attempting to load custom spectra mapping from '" << entry_name << vms_str <<
"'.\n";
1483 m_file->openPath(
"/" + entry_name + vms_str);
1484 }
catch (::NeXus::Exception &) {
1506 m_file->openData(
"UDET");
1507 std::vector<int32_t> udet;
1511 m_file->openData(
"SPEC");
1512 std::vector<int32_t> spec;
1523 const size_t ndets(udet.size());
1524 if (ndets != spec.size()) {
1525 std::ostringstream os;
1526 os <<
"UDET/SPEC list size mismatch. UDET=" << udet.size() <<
", SPEC=" << spec.size() <<
"\n";
1527 throw std::runtime_error(os.str());
1531 return std::make_unique<std::pair<std::vector<int32_t>, std::vector<int32_t>>>(std::move(spec), std::move(udet));
1541 std::string prefix(
"Filter");
1554 std::string msg(
"You must specify both min & max or neither TOF filters");
1556 msg =
" for the monitors.";
1557 throw std::invalid_argument(msg);
1579 file.openGroup(
"isis_vms_compat",
"IXvms");
1580 }
catch (::NeXus::Exception &) {
1587 std::vector<int32_t> spb;
1588 std::vector<float> rspb;
1589 file.readData(
"SPB", spb);
1590 file.readData(
"RSPB", rspb);
1596 }
catch (::NeXus::Exception &ex) {
1598 std::stringstream s;
1599 s <<
"Wrong definition found in isis_vms_compat :> " << ex.what();
1601 throw std::runtime_error(s.str());
1616 }
catch (std::runtime_error &e) {
1617 throw std::runtime_error(
"Severe failure when trying to open NeXus file: " + std::string(e.what()));
1621 throw std::runtime_error(
"An unexpected failure happened, unable to "
1622 "initialize file object when trying to open NeXus "
1631 const std::string &classType)
const {
1633 if (propVal ==
"Default")
1636 bool noParallelConstrictions =
true;
1637 noParallelConstrictions &= !(
m_ws->nPeriods() != 1);
1638 noParallelConstrictions &= !haveWeights;
1639 noParallelConstrictions &= !oldNeXusFileNames;
1641 noParallelConstrictions &= !((
filter_time_start != Types::Core::DateAndTime::minimum() ||
1643 noParallelConstrictions &= !((!
isDefault(
"CompressTolerance") || !
isDefault(
"SpectrumMin") ||
1645 noParallelConstrictions &= !(classType !=
"NXevent_data");
1647 if (!noParallelConstrictions)
1649#ifndef MPI_EXPERIMENTAL
1656Parallel::ExecutionMode
1658 static_cast<void>(storageModes);
1659 return Parallel::ExecutionMode::Distributed;
IPeaksWorkspace_sptr workspace
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
#define DECLARE_NEXUS_HDF5_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_HDF5_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM mac...
Base class from which all concrete algorithm classes should be derived.
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.
bool isDefault(const std::string &name) const
const Parallel::Communicator & communicator() const
Returns a const reference to the (MPI) communicator of the algorithm.
Kernel::Logger & getLogger() const
Returns a reference to the logger.
void filterByTime(const Types::Core::DateAndTime &, const Types::Core::DateAndTime &) override
@ Load
allowed here which will be passed to the algorithm
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.
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
virtual const std::shared_ptr< Mantid::Kernel::NexusHDF5Descriptor > getFileInfo() const noexcept
Required to pass m_fileInfo to static functions Keeping it shared_ptr to match setFileInfo signature ...
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) override
Create a Child Algorithm.
Helper class for reporting progress from algorithms.
void doReport(const std::string &msg="") override
Actually do the reporting, without changing the loop counter.
This class stores information regarding an experimental run as a series of log entries.
A property class for workspaces.
static void load(LoadEventNexus *alg, EventWorkspaceCollection &ws, bool haveWeights, bool event_id_is_spec, std::vector< std::string > bankNames, const std::vector< int > &periodLog, const std::string &classType, std::vector< std::size_t > bankNumEvents, const bool oldNeXusFileNames, const bool precount, const int chunk, const int totalChunks)
EventWorkspaceCollection : Collection of EventWorspaces to give backward-forward compatibility around...
void setGeometryFlag(const int flag)
void setWidth(const float flag)
void setHeight(const float flag)
void setThickness(const float flag)
Custom exception extending std::invalid_argument Thrown when nperiods does not match period_log Custo...
Helper for LoadEventNexus dealing with setting up indices (spectrum numbers an detector ID mapping) f...
Indexing::IndexInfo makeIndexInfo()
std::pair< int32_t, int32_t > eventIDLimits() const
LoadEventNexus::LoaderType defineLoaderType(const bool haveWeights, const bool oldNeXusFileNames, const std::string &classType) const
The parallel loader currently has no support for a series of special cases, as indicated by the retur...
void createSpectraMapping(const std::string &nxsfile, const bool monitorsOnly, const std::vector< std::string > &bankNames=std::vector< std::string >())
Create the required spectra mapping.
Mantid::Types::Core::DateAndTime filter_time_start
Filter by start time.
double filter_tof_max
Filter by a maximum time-of-flight.
void safeOpenFile(const std::string &fname)
to open the nexus file with specific exception handling/message
void execLoader() override
Execution code.
bool loadlogs
Do we load the sample logs?
bool event_id_is_spec
True if the event_id is spectrum no not pixel ID.
static void checkForCorruptedPeriods(std::unique_ptr< Kernel::TimeSeriesProperty< int > > tempPeriodLog, std::unique_ptr< const Kernel::TimeSeriesProperty< int > > &periodLog, const int &nPeriods, const std::string &nexusfilename)
Check for corrupted period logs If data is historical (1 periods, period is labelled 0) then change p...
size_t discarded_events
A count of events discarded because they came from a pixel that's not in the IDF.
T filterEventsByTime(T workspace, Mantid::Types::Core::DateAndTime &startTime, Mantid::Types::Core::DateAndTime &stopTime)
Filter the events by pulse time - no in place version so have to return workspace.
int confidence(Kernel::NexusHDF5Descriptor &descriptor) const override
Return the confidence with with this algorithm can load the file.
Mantid::Types::Core::DateAndTime filter_time_stop
Filter by stop time.
void init() override
Intialisation code.
int32_t m_specMax
Maximum spectrum to load.
void deleteBanks(const EventWorkspaceCollection_sptr &workspace, const std::vector< std::string > &bankNames)
Deletes banks for a workspace given the bank names.
double compressTolerance
Tolerance for CompressEvents; use -1 to mean don't compress.
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 std::shared_ptr< BankPulseTimes > runLoadNexusLogs(const std::string &nexusfilename, T localWorkspace, Algorithm &alg, bool returnpulsetimes, int &nPeriods, std::unique_ptr< const Kernel::TimeSeriesProperty< int > > &periodLog)
Load the log from the nexus file.
Parallel::ExecutionMode getParallelExecutionMode(const std::map< std::string, Parallel::StorageMode > &storageModes) const override
Get correct execution mode based on input storage modes for an MPI run.
void runLoadMonitors()
Load the Monitors from the NeXus file into a workspace.
static void loadSampleDataISIScompatibility(::NeXus::File &file, EventWorkspaceCollection &WS)
Load information of the sample.
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...
std::unique_ptr<::NeXus::File > m_file
void filterDuringPause(T workspace)
std::unique_ptr< std::pair< std::vector< int32_t >, std::vector< int32_t > > > loadISISVMSSpectraMapping(const std::string &entry_name)
Load a spectra mapping from the given file.
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.
std::shared_ptr< EventWorkspaceCollection > m_ws
The workspace being filled out.
void loadEvents(API::Progress *const prog, const bool monitors)
Load events from the file.
LoadEventNexus()
Empty default constructor.
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.
void setTopEntryName()
Set the top entry field name.
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 setTimeFilters(const bool monitors)
Set the filters on TOF.
static void loadMPI(DataObjects::EventWorkspace &ws, const std::string &filename, const std::string &groupName, const std::vector< std::string > &bankNames, const bool eventIDIsSpectrumNumber)
Load events from given banks into given EventWorkspace using MPI.
static void loadMultiProcess(DataObjects::EventWorkspace &ws, const std::string &filename, const std::string &groupName, const std::vector< std::string > &bankNames, const bool eventIDIsSpectrumNumber, const bool precalcEvents)
Load events from given banks into given EventWorkspace using boost::interprocess.
This class represents a detector - i.e.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
void makeUniversalGoniometer()
Make a default universal goniometer with phi,chi,omega angles according to SNS convention.
base class for Geometric IComponent
Support for a property that holds an array of values.
Exception for when an item is not found in a collection.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
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.
void notice(const std::string &msg)
Logs at notice 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.
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.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-path entry exists for a particular groupClass in a Nexus dataset.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
The concrete, templated class for properties.
virtual std::string value() const =0
Returns the value of the property as a string.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
A specialised Property class for holding a series of time-value pairs.
std::vector< Types::Core::DateAndTime > timesAsVector() const override
Return the time series's times as a vector<DateAndTime>
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void addNexusFieldsToWsRun(NXhandle nxfileID, API::Run &runDetails, const std::string &entryName="", bool useFullPath=false)
Add properties from a nexus file to the workspace run.
std::pair< DateAndTime, DateAndTime > firstLastPulseTimes(::NeXus::File &file, Kernel::Logger &logger)
bool exists(::NeXus::File &file, const std::string &name)
Based on the current group in the file, does the named sub-entry exist?
std::shared_ptr< EventWorkspaceCollection > EventWorkspaceCollection_sptr
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< Instrument > Instrument_sptr
Shared pointer to an instrument object.
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...
MANTID_KERNEL_DLL double timeConversionValue(const std::string &input_unit, const std::string &output_unit)
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.