Mantid
Loading...
Searching...
No Matches
LoadEventNexus.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
9#include "MantidAPI/Axis.h"
14#include "MantidAPI/Run.h"
15#include "MantidAPI/Sample.h"
25#include "MantidIndexing/IndexInfo.h"
32#include "MantidKernel/Timer.h"
36
37#include <H5Cpp.h>
38#include <memory>
39
40#include <regex>
41
42using Mantid::Types::Core::DateAndTime;
43using std::map;
44using std::string;
45using std::vector;
46
47namespace Mantid::DataHandling {
48
50
51using namespace Kernel;
52using namespace DateAndTimeHelpers;
53using namespace Geometry;
54using namespace API;
55using namespace DataObjects;
56using Types::Core::DateAndTime;
57
58namespace {
59// detnotes the end of iteration for NeXus::getNextEntry
60const std::string NULL_STR("NULL");
61} // namespace
62
69bool exists(::NeXus::File &file, const std::string &name) {
70 const auto entries = file.getEntries();
71 return exists(entries, name);
72}
73
74bool exists(const std::map<std::string, std::string> &entries, const std::string &name) {
75 return entries.find(name) != entries.end();
76}
77
78//----------------------------------------------------------------------------------------------
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) {}
85
86//----------------------------------------------------------------------------------------------
94
95 int confidence = 0;
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")) {
99 confidence = 80;
100 }
101 }
102
103 return confidence;
104}
105
106//----------------------------------------------------------------------------------------------
110 const std::vector<std::string> exts{".nxs.h5", ".nxs", "_event.nxs"};
111 this->declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, exts),
112 "The name of the Event NeXus file to read, including its full or "
113 "relative path. "
114 "The file name is typically of the form INST_####_event.nxs (N.B. case "
115 "sensitive if running on Linux).");
116
117 this->declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
118 "The name of the output EventWorkspace or WorkspaceGroup in which to "
119 "load the EventNexus file.");
120
121 declareProperty(std::make_unique<PropertyWithValue<string>>("NXentryName", "", Direction::Input),
122 "Optional: Name of the NXentry to load if it's not the default.");
123
124 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTofMin", EMPTY_DBL(), Direction::Input),
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.");
129
130 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTofMax", EMPTY_DBL(), Direction::Input),
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.");
135
136 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTimeStart", EMPTY_DBL(), Direction::Input),
137 "Optional: To only include events after the provided start "
138 "time, in seconds (relative to the start of the run).");
139
140 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTimeStop", EMPTY_DBL(), Direction::Input),
141 "Optional: To only include events before the provided stop "
142 "time, in seconds (relative to the start of the run).");
143
144 std::string grp1 = "Filter Events";
145 setPropertyGroup("FilterByTofMin", grp1);
146 setPropertyGroup("FilterByTofMax", grp1);
147 setPropertyGroup("FilterByTimeStart", grp1);
148 setPropertyGroup("FilterByTimeStop", grp1);
149
150 declareProperty(std::make_unique<ArrayProperty<string>>("BankName", Direction::Input),
151 "Optional: To only include events from one bank. Any bank "
152 "whose name does not match the given string will have no "
153 "events.");
154
155 declareProperty(std::make_unique<PropertyWithValue<bool>>("SingleBankPixelsOnly", true, Direction::Input),
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.");
160 setPropertySettings("SingleBankPixelsOnly", std::make_unique<VisibleWhenProperty>("BankName", IS_NOT_DEFAULT));
161
162 std::string grp2 = "Loading a Single Bank";
163 setPropertyGroup("BankName", grp2);
164 setPropertyGroup("SingleBankPixelsOnly", grp2);
165
166 declareProperty(std::make_unique<PropertyWithValue<bool>>("Precount", true, Direction::Input),
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.");
171
172 declareProperty(std::make_unique<PropertyWithValue<double>>("CompressTolerance", -1.0, Direction::Input),
173 "Run CompressEvents while loading (optional, leave blank or "
174 "negative to not do). "
175 "This specified the tolerance to use (in microseconds) when "
176 "compressing.");
177
178 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
179 mustBePositive->setLower(1);
180 declareProperty("ChunkNumber", EMPTY_INT(), mustBePositive,
181 "If loading the file by sections ('chunks'), this is the "
182 "section number of this execution of the algorithm.");
183 declareProperty("TotalChunks", EMPTY_INT(), mustBePositive,
184 "If loading the file by sections ('chunks'), this is the "
185 "total number of sections.");
186 // TotalChunks is only meaningful if ChunkNumber is set
187 // Would be nice to be able to restrict ChunkNumber to be <= TotalChunks at
188 // validation
189 setPropertySettings("TotalChunks", std::make_unique<VisibleWhenProperty>("ChunkNumber", IS_NOT_DEFAULT));
190
191 std::string grp3 = "Reduce Memory Use";
192 setPropertyGroup("Precount", grp3);
193 setPropertyGroup("CompressTolerance", grp3);
194 setPropertyGroup("ChunkNumber", grp3);
195 setPropertyGroup("TotalChunks", grp3);
196
197 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadMonitors", false, Direction::Input),
198 "Load the monitors from the file (optional, default False).");
199
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.");
204
205 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTofMin", EMPTY_DBL(), Direction::Input),
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.");
209
210 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTofMax", EMPTY_DBL(), Direction::Input),
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.");
214
215 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTimeStart", EMPTY_DBL(), Direction::Input),
216 "Optional: To only include events from monitors after the "
217 "provided start time, in seconds (relative to the start of "
218 "the run).");
219
220 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTimeStop", EMPTY_DBL(), Direction::Input),
221 "Optional: To only include events from monitors before the "
222 "provided stop time, in seconds (relative to the start of "
223 "the run).");
224
225 setPropertySettings("MonitorsLoadOnly", std::make_unique<VisibleWhenProperty>("LoadMonitors", IS_EQUAL_TO, "1"));
226 auto asEventsIsOn = [] {
227 std::unique_ptr<IPropertySettings> prop = std::make_unique<VisibleWhenProperty>("LoadMonitors", IS_EQUAL_TO, "1");
228 return prop;
229 };
230 setPropertySettings("FilterMonByTofMin", asEventsIsOn());
231 setPropertySettings("FilterMonByTofMax", asEventsIsOn());
232 setPropertySettings("FilterMonByTimeStart", asEventsIsOn());
233 setPropertySettings("FilterMonByTimeStop", asEventsIsOn());
234
235 std::string grp4 = "Monitors";
236 setPropertyGroup("LoadMonitors", grp4);
237 setPropertyGroup("MonitorsLoadOnly", grp4);
238 setPropertyGroup("FilterMonByTofMin", grp4);
239 setPropertyGroup("FilterMonByTofMax", grp4);
240 setPropertyGroup("FilterMonByTimeStart", grp4);
241 setPropertyGroup("FilterMonByTimeStop", grp4);
242
243 declareProperty("SpectrumMin", EMPTY_INT(), mustBePositive, "The number of the first spectrum to read.");
244 declareProperty("SpectrumMax", EMPTY_INT(), mustBePositive, "The number of the last spectrum to read.");
245 declareProperty(std::make_unique<ArrayProperty<int32_t>>("SpectrumList"),
246 "A comma-separated list of individual spectra to read.");
247
248 declareProperty(std::make_unique<PropertyWithValue<bool>>("MetaDataOnly", false, Direction::Input),
249 "If true, only the meta data and sample logs will be loaded.");
250
251 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadLogs", true, Direction::Input),
252 "Load only the Sample/DAS logs from the file (default True).");
253
254 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadAllLogs", false, Direction::Input),
255 "Load all the logs from the nxs, without checking or processing them; if checked, LoadLogs will be "
256 "ignored; use with caution");
257
258 std::vector<std::string> loadType{"Default"};
259
260#ifndef _WIN32
261 loadType.emplace_back("Multiprocess (experimental)");
262#endif // _WIN32
263
264#ifdef MPI_EXPERIMENTAL
265 loadType.emplace_back("MPI");
266#endif // MPI_EXPERIMENTAL
267
268 auto loadTypeValidator = std::make_shared<StringListValidator>(loadType);
269 declareProperty("LoadType", "Default", loadTypeValidator,
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");
273
274 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadNexusInstrumentXML", true, Direction::Input),
275 "Reads the embedded Instrument XML from the NeXus file "
276 "(optional, default True). ");
277
278 declareProperty("NumberOfBins", 500, mustBePositive,
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.");
282
283 // Flexible log loading
284 declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>("AllowList", std::vector<std::string>(),
286 "If specified, only these logs will be loaded from the file (each "
287 "separated by a space).");
288 declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>("BlockList", std::vector<std::string>(),
290 "If specified, these logs will NOT be loaded from the file (each "
291 "separated by a space).");
292}
293
294//----------------------------------------------------------------------------------------------
298 std::string nxentryProperty = getProperty("NXentryName");
299 if (!nxentryProperty.empty()) {
300 m_top_entry_name = nxentryProperty;
301 return;
302 }
303
304 try {
305 while (true) {
306 const auto entry = m_file->getNextEntry();
307 if (entry.second == "NXentry") {
308 if ((entry.first == "entry") || (entry.first == "raw_data_1")) {
309 m_top_entry_name = entry.first;
310 break;
311 }
312 } else if (entry.first == NULL_STR && entry.second == NULL_STR) {
313 g_log.error() << "Unable to determine name of top level NXentry - assuming "
314 "\"entry\".\n";
315 m_top_entry_name = "entry";
316 break;
317 }
318 }
319 } catch (const std::exception &) {
320 g_log.error() << "Unable to determine name of top level NXentry - assuming "
321 "\"entry\".\n";
322 m_top_entry_name = "entry";
323 }
324}
325
326template <typename T> void LoadEventNexus::filterDuringPause(T workspace) {
327 try {
328 if ((!ConfigService::Instance().hasProperty("loadeventnexus.keeppausedevents")) &&
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.");
333
334 auto filter = createChildAlgorithm("FilterByLogValue");
335 filter->setProperty("InputWorkspace", workspace);
336 filter->setProperty("OutputWorkspace", workspace);
337 filter->setProperty("LogName", "pause");
338 // The log value is set to 1 when the run is paused, 0 otherwise.
339 filter->setProperty("MinimumValue", 0.0);
340 filter->setProperty("MaximumValue", 0.0);
341 filter->setProperty("LogBoundary", "Left");
342 filter->execute();
343 }
344 } catch (Exception::NotFoundError &) {
345 // No "pause" log, just carry on
346 }
347}
348
349template <>
350void LoadEventNexus::filterDuringPause<EventWorkspaceCollection_sptr>(EventWorkspaceCollection_sptr workspace) {
351 // We provide a function pointer to the filter method of the object
352 using std::placeholders::_1;
353 auto func = std::bind(&LoadEventNexus::filterDuringPause<MatrixWorkspace_sptr>, this, _1);
354 workspace->applyFilterInPlace(func);
355}
356
357//-----------------------------------------------------------------------------
362template <typename T>
363T LoadEventNexus::filterEventsByTime(T workspace, Mantid::Types::Core::DateAndTime &startTime,
364 Mantid::Types::Core::DateAndTime &stopTime) {
365
366 auto filterByTime = createChildAlgorithm("FilterByTime");
367 g_log.information("Filtering events by time...");
368 filterByTime->setProperty("InputWorkspace", workspace);
369 // sample log already filtered by time so use absolute times to be safe
370 filterByTime->setProperty("AbsoluteStartTime", startTime.toISO8601String());
371 filterByTime->setProperty("AbsoluteStopTime", stopTime.toISO8601String());
372 filterByTime->execute();
373 return filterByTime->getProperty("OutputWorkspace");
374}
375
376template <>
378LoadEventNexus::filterEventsByTime<EventWorkspaceCollection_sptr>(EventWorkspaceCollection_sptr workspace,
379 Mantid::Types::Core::DateAndTime &startTime,
380 Mantid::Types::Core::DateAndTime &stopTime) {
381 // We provide a function pointer to the filter method of the object
382 using std::placeholders::_1;
383 auto func = std::bind(&LoadEventNexus::filterEventsByTime<EventWorkspace_sptr>, this, _1, startTime, stopTime);
384 workspace->applyFilter(func);
385 return workspace;
386}
387
388//------------------------------------------------------------------------------------------------
393 // Retrieve the filename from the properties
394 m_filename = getPropertyValue("Filename");
395
396 compressTolerance = getProperty("CompressTolerance");
397
398 loadlogs = getProperty("LoadLogs");
399
400 // Check to see if the monitors need to be loaded later
401 bool load_monitors = this->getProperty("LoadMonitors");
402
403 // this must make absolutely sure that m_file is a valid (and open)
404 // NeXus::File object
406
408
409 // Initialize progress reporting.
410 int reports = 3;
411 if (load_monitors)
412 reports++;
413 Progress prog(this, 0.0, 0.3, reports);
414
415 // Load the detector events
416 m_ws = std::make_shared<EventWorkspaceCollection>(); // Algorithm currently
417 // relies on an
418 // object-level workspace ptr
419 loadEvents(&prog, false); // Do not load monitor blocks
420
421 if (discarded_events > 0) {
423 << " events were encountered coming from pixels which "
424 "are not in the Instrument Definition File."
425 "These events were discarded.\n";
426 }
427
428 // If the run was paused at any point, filter out those events (SNS only, I
429 // think)
430 filterDuringPause(m_ws->getSingleHeldWorkspace());
431
432 // add filename
433 m_ws->mutableRun().addProperty("Filename", m_filename);
434 // Save output
435 this->setProperty("OutputWorkspace", m_ws->combinedWorkspace());
436
437 // close the file since LoadNexusMonitors will take care of its own file
438 // handle
439 m_file->close();
440
441 // Load the monitors with child algorithm 'LoadNexusMonitors'
442 if (load_monitors) {
443 prog.report("Loading monitors");
444 this->runLoadMonitors();
445 }
446}
447
448std::pair<DateAndTime, DateAndTime> firstLastPulseTimes(::NeXus::File &file, Kernel::Logger &logger) {
449 file.openData("event_time_zero");
450 std::string isooffset; // ISO8601 offset
451 DateAndTime offset;
452 // According to the Nexus standard, if the offset is not present, it implies
453 // the offset is and absolute timestamp, which is relative to the start of
454 // Unix epoch (https://manual.nexusformat.org/classes/base_classes/NXlog.html)
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");
459 } else {
460 file.getAttr("offset", isooffset);
461 offset = DateAndTime(isooffset);
462 }
463 std::string units; // time units
464 if (file.hasAttr("units"))
465 file.getAttr("units", units);
466 // Read in the pulse times
467 auto pulse_times = Mantid::NeXus::NeXusIOHelper::readNexusVector<double>(file, "event_time_zero");
468 // Remember to close the entry
469 file.closeData();
470 if (pulse_times.empty()) {
471 throw std::invalid_argument("Cannot find run start; event_time_zero contains no pulse times");
472 }
473 // Convert to seconds
474 auto conv = Kernel::Units::timeConversionValue(units, "s");
475 return std::make_pair(DateAndTime(pulse_times.front() * conv, 0.0) + offset.totalNanoseconds(),
476 DateAndTime(pulse_times.back() * conv, 0.0) + offset.totalNanoseconds());
477} // namespace DataHandling
478
491std::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix,
492 const NexusHDF5Descriptor &descriptor) {
493 // try getting the value of total_counts
494 if (hasTotalCounts) {
495 hasTotalCounts = false;
496 if (descriptor.isEntry(prefix + "/total_counts")) {
497 try {
498 file.openData("total_counts");
499 auto info = file.getInfo();
500 file.closeData();
501 if (info.type == ::NeXus::UINT64) {
502 uint64_t eventCount;
503 file.readData("total_counts", eventCount);
504 hasTotalCounts = true;
505 return eventCount;
506 }
507 } catch (::NeXus::Exception &) {
508 }
509 }
510 }
511
512 // just get the length of the event pixel ids
513 try {
514 if (oldNeXusFileNames)
515 file.openData("event_pixel_id");
516 else
517 file.openData("event_id");
518 } catch (::NeXus::Exception &) {
519 // Older files (before Nov 5, 2010) used this field.
520 try {
521 file.openData("event_pixel_id");
522 oldNeXusFileNames = true;
523 } catch (::NeXus::Exception &) {
524 // Some groups have neither indicating there are not events here
525 return 0;
526 }
527 }
528
529 size_t numEvents = static_cast<std::size_t>(file.getInfo().dims[0]);
530 file.closeData();
531 return numEvents;
532}
533
547template <typename T>
548std::shared_ptr<BankPulseTimes>
549LoadEventNexus::runLoadNexusLogs(const std::string &nexusfilename, T localWorkspace, API::Algorithm &alg,
550 bool returnpulsetimes, int &nPeriods,
551 std::unique_ptr<const TimeSeriesProperty<int>> &periodLog) {
552 // --------------------- Load DAS Logs -----------------
553 // The pulse times will be empty if not specified in the DAS logs.
554 // BankPulseTimes * out = NULL;
555 std::shared_ptr<BankPulseTimes> out;
556 auto loadLogs = alg.createChildAlgorithm("LoadNexusLogs");
557
558 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
559 try {
560 alg.getLogger().information() << "Loading logs from NeXus file..."
561 << "\n";
562 loadLogs->setPropertyValue("Filename", nexusfilename);
563 loadLogs->setProperty<API::MatrixWorkspace_sptr>("Workspace", localWorkspace);
564 try {
565 loadLogs->setPropertyValue("NXentryName", alg.getPropertyValue("NXentryName"));
566 } catch (...) {
567 }
568
569 loadLogs->execute();
570
571 const Run &run = localWorkspace->run();
572 // Get the number of periods
573 if (run.hasProperty("nperiods")) {
574 nPeriods = run.getPropertyValueAsType<int>("nperiods");
575 }
576 // Get the period log. Map of DateAndTime to Period int values.
577 if (run.hasProperty("period_log")) {
578 auto *temp = run.getProperty("period_log");
579 // Check for corrupted period logs
580 std::unique_ptr<TimeSeriesProperty<int>> tempPeriodLog(dynamic_cast<TimeSeriesProperty<int> *>(temp->clone()));
581 checkForCorruptedPeriods(std::move(tempPeriodLog), periodLog, nPeriods, nexusfilename);
582 }
583
584 // If successful, we can try to load the pulse times
585 std::vector<Types::Core::DateAndTime> temp;
586 if (localWorkspace->run().hasProperty("proton_charge")) {
587 auto *log =
588 dynamic_cast<Kernel::TimeSeriesProperty<double> *>(localWorkspace->mutableRun().getProperty("proton_charge"));
589 if (log)
590 temp = log->timesAsVector();
591 }
592 if (returnpulsetimes)
593 out = std::make_shared<BankPulseTimes>(temp);
594
595 // Use the first pulse as the run_start time.
596 if (!temp.empty()) {
597 if (temp[0] < Types::Core::DateAndTime("1991-01-01T00:00:00"))
598 alg.getLogger().warning() << "Found entries in the proton_charge "
599 "sample log with invalid pulse time!\n";
600
601 Types::Core::DateAndTime run_start = localWorkspace->getFirstPulseTime();
602 // add the start of the run as a ISO8601 date/time string. The start =
603 // first non-zero time.
604 // (this is used in LoadInstrument to find the right instrument file to
605 // use).
606 localWorkspace->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
607 } else if (run.hasProperty("start_time")) {
608 localWorkspace->mutableRun().addProperty("run_start", run.getProperty("start_time")->value(), true);
609 } else {
610 alg.getLogger().warning() << "Empty proton_charge sample log. You will "
611 "not be able to filter by time.\n";
612 }
614 try {
617 localWorkspace->mutableRun().setGoniometer(gm, true);
618 } catch (std::runtime_error &) {
619 }
620 } catch (const InvalidLogPeriods &) {
621 // Rethrow so LoadEventNexus fails.
622 // If we don't, Mantid will crash.
623 throw;
624 } catch (...) {
625 alg.getLogger().error() << "Error while loading Logs from SNS Nexus. Some "
626 "sample logs may be missing."
627 << "\n";
628 return out;
629 }
630 return out;
631}
632
648template <typename T>
649std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs(
650 const std::string &nexusfilename, T localWorkspace, API::Algorithm &alg, bool returnpulsetimes, int &nPeriods,
651 std::unique_ptr<const TimeSeriesProperty<int>> &periodLog, const std::vector<std::string> &allow_list,
652 const std::vector<std::string> &block_list) {
653 // --------------------- Load DAS Logs -----------------
654 // The pulse times will be empty if not specified in the DAS logs.
655 // BankPulseTimes * out = NULL;
656 std::shared_ptr<BankPulseTimes> out;
657 auto loadLogs = alg.createChildAlgorithm("LoadNexusLogs");
658
659 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
660 try {
661 alg.getLogger().information() << "Loading logs from NeXus file..."
662 << "\n";
663 loadLogs->setPropertyValue("Filename", nexusfilename);
664 loadLogs->setProperty<API::MatrixWorkspace_sptr>("Workspace", localWorkspace);
665 loadLogs->setProperty<std::vector<std::string>>("AllowList", allow_list);
666 loadLogs->setProperty<std::vector<std::string>>("BlockList", block_list);
667
668 try {
669 loadLogs->setPropertyValue("NXentryName", alg.getPropertyValue("NXentryName"));
670 } catch (...) {
671 }
672
673 loadLogs->execute();
674
675 const Run &run = localWorkspace->run();
676 // Get the number of periods
677 if (run.hasProperty("nperiods")) {
678 nPeriods = run.getPropertyValueAsType<int>("nperiods");
679 }
680 // Get the period log. Map of DateAndTime to Period int values.
681 if (run.hasProperty("period_log")) {
682 auto *temp = run.getProperty("period_log");
683 // Check for corrupted period logs
684 std::unique_ptr<TimeSeriesProperty<int>> tempPeriodLog(dynamic_cast<TimeSeriesProperty<int> *>(temp->clone()));
685 checkForCorruptedPeriods(std::move(tempPeriodLog), periodLog, nPeriods, nexusfilename);
686 }
687
688 // If successful, we can try to load the pulse times
689 std::vector<Types::Core::DateAndTime> temp;
690 if (localWorkspace->run().hasProperty("proton_charge")) {
691 auto *log =
692 dynamic_cast<Kernel::TimeSeriesProperty<double> *>(localWorkspace->mutableRun().getProperty("proton_charge"));
693 if (log)
694 temp = log->timesAsVector();
695 }
696 if (returnpulsetimes)
697 out = std::make_shared<BankPulseTimes>(temp);
698
699 // Use the first pulse as the run_start time.
700 if (!temp.empty()) {
701 if (temp[0] < Types::Core::DateAndTime("1991-01-01T00:00:00"))
702 alg.getLogger().warning() << "Found entries in the proton_charge "
703 "sample log with invalid pulse time!\n";
704
705 Types::Core::DateAndTime run_start = localWorkspace->getFirstPulseTime();
706 // add the start of the run as a ISO8601 date/time string. The start =
707 // first non-zero time.
708 // (this is used in LoadInstrument to find the right instrument file to
709 // use).
710 localWorkspace->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
711 } else {
712 alg.getLogger().warning() << "Empty proton_charge sample log. You will "
713 "not be able to filter by time.\n";
714 }
716 try {
719 localWorkspace->mutableRun().setGoniometer(gm, true);
720 } catch (std::runtime_error &) {
721 }
722 } catch (const InvalidLogPeriods &) {
723 // Rethrow so LoadEventNexus fails.
724 // If we don't, Mantid will crash.
725 throw;
726 } catch (...) {
727 alg.getLogger().error() << "Error while loading Logs from SNS Nexus. Some "
728 "sample logs may be missing."
729 << "\n";
730 return out;
731 }
732 return out;
733}
734
748 std::unique_ptr<const TimeSeriesProperty<int>> &periodLog,
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());
752
753 // Check for historic files
754 if (nPeriodsInLog == 0 && nPeriods == 1) {
755 // "modernize" the local copy here by making period_log
756 // a vector of 1s
757 const std::vector<int> newValues(tempPeriodLog->realSize(), 1);
758 const auto times = tempPeriodLog->timesAsVector();
759 periodLog.reset(new const TimeSeriesProperty<int>("period_log", times, newValues));
760 } else if (nPeriodsInLog != nPeriods) {
761 // Sanity check here that period_log only contains period numbers up to
762 // nperiods. These values can be different due to instrument noise, and
763 // cause undescriptive crashes if not caught.
764 // We throw here to make it clear
765 // that the file is corrupted and must be manually assessed.
766 const auto msg = "File " + nexusfilename +
767 " has been corrupted. The log framelog/period_log/value "
768 "contains " +
769 std::to_string(nPeriodsInLog) + " periods, but periods/number contains " +
770 std::to_string(nPeriods) + ". This file should be manually inspected and corrected.";
771 throw InvalidLogPeriods(msg);
772 } else {
773 // periodLog should point to a copy of the period logs
774 periodLog = std::make_unique<const TimeSeriesProperty<int>>(*tempPeriodLog);
775 tempPeriodLog.reset();
776 }
777}
778
793template <>
794std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs<EventWorkspaceCollection_sptr>(
795 const std::string &nexusfilename, EventWorkspaceCollection_sptr localWorkspace, API::Algorithm &alg,
796 bool returnpulsetimes, int &nPeriods, std::unique_ptr<const TimeSeriesProperty<int>> &periodLog) {
797 auto ws = localWorkspace->getSingleHeldWorkspace();
798 auto ret = runLoadNexusLogs<MatrixWorkspace_sptr>(nexusfilename, ws, alg, returnpulsetimes, nPeriods, periodLog);
799 return ret;
800}
801
818template <>
819std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs<EventWorkspaceCollection_sptr>(
820 const std::string &nexusfilename, EventWorkspaceCollection_sptr localWorkspace, API::Algorithm &alg,
821 bool returnpulsetimes, int &nPeriods, std::unique_ptr<const TimeSeriesProperty<int>> &periodLog,
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);
826 return ret;
827}
828
829enum class LoadEventNexus::LoaderType { MPI, MULTIPROCESS, DEFAULT };
830
831//-----------------------------------------------------------------------------
842void LoadEventNexus::loadEvents(API::Progress *const prog, const bool monitors) {
843 bool metaDataOnly = getProperty("MetaDataOnly");
844
845 // Get the time filters
846 setTimeFilters(monitors);
847
848 // Get the log filter if provided
849 std::vector<std::string> allow_list = getProperty("AllowList");
850 std::vector<std::string> block_list = getProperty("BlockList");
851
852 // The run_start will be loaded from the pulse times.
853 DateAndTime run_start(0, 0);
854 bool takeTimesFromEvents = false;
855 // Initialize the counter of bad TOFs
856 bad_tofs = 0;
857 int nPeriods = 1;
858 auto periodLog = std::make_unique<const TimeSeriesProperty<int>>("period_log");
859
860 bool loadAllLogs = getProperty("LoadAllLogs");
861
862 if (loadlogs) {
863 if (!loadAllLogs) {
864 prog->doReport("Loading DAS logs");
865
866 if (allow_list.empty() && block_list.empty()) {
868 runLoadNexusLogs<EventWorkspaceCollection_sptr>(m_filename, m_ws, *this, true, nPeriods, periodLog);
869 } else {
870 m_allBanksPulseTimes = runLoadNexusLogs<EventWorkspaceCollection_sptr>(m_filename, m_ws, *this, true, nPeriods,
871 periodLog, allow_list, block_list);
872 }
873
874 try {
875 run_start = m_ws->getFirstPulseTime();
877 /*
878 This is added to (a) support legacy behaviour of continuing to take
879 times from the proto_charge log, but (b) allowing a fall back of
880 getting run start and end from actual pulse times within the
881 NXevent_data group. Note that the latter is better Nexus compliant.
882 */
883 takeTimesFromEvents = true;
884 }
885 } else {
886 prog->doReport("Loading all logs");
887 // Open NeXus file
888 NXhandle nxHandle;
889 NXstatus nxStat = NXopen(m_filename.c_str(), NXACC_READ, &nxHandle);
890
891 if (nxStat != NX_ERROR) {
892 LoadHelper::addNexusFieldsToWsRun(nxHandle, m_ws->mutableRun(), "", true);
893 NXclose(&nxHandle);
894 }
895 }
896 } else {
897 g_log.information() << "Skipping the loading of sample logs!\n"
898 << "Reading the start time directly from /" << m_top_entry_name << "/start_time\n";
899 // start_time is read and set
900 m_file->openPath("/");
901 m_file->openGroup(m_top_entry_name, "NXentry");
902 std::string tmp;
903 m_file->readData("start_time", tmp);
904 m_file->closeGroup();
905 run_start = createFromSanitizedISO8601(tmp);
906 m_ws->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
907 }
908 // set more properties on the workspace
909 const std::shared_ptr<NexusHDF5Descriptor> descriptor = getFileInfo();
910
911 try {
912 // this is a static method that is why it is passing the
913 // file object and the file path
914
915 loadEntryMetadata<EventWorkspaceCollection_sptr>(m_filename, m_ws, m_top_entry_name, *descriptor);
916 } catch (std::runtime_error &e) {
917 // Missing metadata is not a fatal error. Log and go on with your life
918 g_log.error() << "Error loading metadata: " << e.what() << '\n';
919 }
920
921 m_ws->setNPeriods(static_cast<size_t>(nPeriods),
922 periodLog); // This is how many workspaces we are going to make.
923
924 // Make sure you have a non-NULL m_allBanksPulseTimes
925 if (m_allBanksPulseTimes == nullptr) {
926 std::vector<DateAndTime> temp;
927 m_allBanksPulseTimes = std::make_shared<BankPulseTimes>(temp);
928 }
929
930 if (!m_ws->getInstrument() || !m_instrument_loaded_correctly) {
931 // Load the instrument (if not loaded before)
932 prog->report("Loading instrument");
933 // Note that closing an re-opening the file is needed here for loading
934 // instruments directly from the nexus file containing the event data.
935 // This may not be needed in the future if both LoadEventNexus and
936 // LoadInstrument are made to use the same Nexus/HDF5 library
937 m_file->close();
939
941 throw std::runtime_error("Instrument was not initialized correctly! "
942 "Loading cannot continue.");
943 // reopen file
945 }
946
947 // top level file information
948 m_file->openPath("/");
949 // Start with the base entry
950 m_file->openGroup(m_top_entry_name, "NXentry");
951
952 // Now we want to go through all the bankN_event entries
953 vector<string> bankNames;
954 vector<std::size_t> bankNumEvents;
955 std::string classType = monitors ? "NXmonitor" : "NXevent_data";
956 ::NeXus::Info info;
957 bool oldNeXusFileNames(false);
958 bool haveWeights = false;
959 auto firstPulseT = DateAndTime::maximum();
960
961 const std::map<std::string, std::set<std::string>> &allEntries = descriptor->getAllEntries();
962
963 auto itClassEntries = allEntries.find(classType);
964
965 if (itClassEntries != allEntries.end()) {
966
967 const std::set<std::string> &classEntries = itClassEntries->second;
968 const std::regex classRegex("(/" + m_top_entry_name + "/)([^/]*)");
969 std::smatch groups;
970
971 for (const std::string &classEntry : classEntries) {
972
973 if (std::regex_match(classEntry, groups, classRegex)) {
974 const std::string entry_name(groups[2].str());
975
976 // skip entries with junk data
977 if (entry_name == "bank_error_events" || entry_name == "bank_unmapped_events")
978 continue;
979
980 m_file->openGroup(entry_name, classType);
981
982 // get the number of events
983 const std::string prefix = "/" + m_top_entry_name + "/" + entry_name;
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);
988
989 if (takeTimesFromEvents && num > 0) {
990 /* If we are here, we are loading logs, but have failed to establish
991 * the run_start from the proton_charge log. We are going to get this
992 * from our event_time_zero instead
993 */
994 auto localFirstLast = firstLastPulseTimes(*m_file, this->g_log);
995 firstPulseT = std::min(firstPulseT, localFirstLast.first);
996 }
997
998 // Look for weights in simulated file
999 const std::string absoluteEventWeightName = prefix + "/event_weight";
1000 haveWeights = descriptor->isEntry(absoluteEventWeightName);
1001 m_file->closeGroup();
1002 }
1003 }
1004 }
1005
1006 if (takeTimesFromEvents)
1007 run_start = firstPulseT;
1008
1010
1011 // Close the 'top entry' group (raw_data_1 for NexusProcessed, etc.)
1012 m_file->closeGroup();
1013
1014 // Delete the output workspace name if it existed
1015 std::string outName = getPropertyValue("OutputWorkspace");
1016 if (AnalysisDataService::Instance().doesExist(outName))
1017 AnalysisDataService::Instance().remove(outName);
1018
1019 // --------------------------- Time filtering
1020 // ------------------------------------
1021 double filter_time_start_sec, filter_time_stop_sec;
1022 filter_time_start_sec = getProperty("FilterByTimeStart");
1023 filter_time_stop_sec = getProperty("FilterByTimeStop");
1024
1025 // Default to ALL pulse times
1026 bool is_time_filtered = false;
1027 filter_time_start = Types::Core::DateAndTime::minimum();
1028 filter_time_stop = Types::Core::DateAndTime::maximum();
1029
1030 if (m_allBanksPulseTimes->pulseTimes.size() > 0) {
1031 // If not specified, use the limits of doubles. Otherwise, convert from
1032 // seconds to absolute PulseTime
1033 if (filter_time_start_sec != EMPTY_DBL()) {
1034 filter_time_start = run_start + filter_time_start_sec;
1035 is_time_filtered = true;
1036 }
1037
1038 if (filter_time_stop_sec != EMPTY_DBL()) {
1039 filter_time_stop = run_start + filter_time_stop_sec;
1040 is_time_filtered = true;
1041 }
1042
1043 // Silly values?
1045 std::string msg = "Your ";
1046 if (monitors)
1047 msg += "monitor ";
1048 msg += "filter for time's Stop value is smaller than the Start value.";
1049 throw std::invalid_argument(msg);
1050 }
1051 }
1052
1053 if (metaDataOnly) {
1054 // Now, create a default X-vector for histogramming, with just 2 bins.
1055 auto axis = HistogramData::BinEdges{1, static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1 - 1};
1056 // Set the binning axis using this.
1057 m_ws->setAllX(axis);
1058
1059 createSpectraMapping(m_filename, monitors, std::vector<std::string>());
1060 return;
1061 }
1062
1063 // --------- Loading only one bank ? ----------------------------------
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"; });
1071
1072 // check that all of the requested banks are in the file
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; });
1077 });
1078 if (invalidBank != eventedBanks.cend()) {
1079 throw std::invalid_argument("No entry named '" + *invalidBank + "' was found in the .NXS file.");
1080 }
1081
1082 // change the number of banks to load
1083 bankNames.assign(eventedBanks.cbegin(), eventedBanks.cend());
1084
1085 // TODO this equally weights the banks
1086 bankNumEvents.assign(someBanks.size(), 1);
1087
1088 if (!SingleBankPixelsOnly)
1089 someBanks.clear(); // Marker to load all pixels
1090 }
1091
1092 prog->report("Initializing all pixels");
1093
1094 // Remove unused banks if parameter is set
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());
1099 if (unused == 1)
1100 deleteBanks(m_ws, bankNames);
1101 }
1102 }
1103 //----------------- Pad Empty Pixels -------------------------------
1104 createSpectraMapping(m_filename, monitors, someBanks);
1105
1106 // Set all (empty) event lists as sorted by pulse time. That way, calling
1107 // SortEvents will not try to sort these empty lists.
1108 for (size_t i = 0; i < m_ws->getNumberHistograms(); i++)
1109 m_ws->getSpectrum(i).setSortOrder(DataObjects::PULSETIME_SORT);
1110
1111 // Count the limits to time of flight
1112 shortest_tof = static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1;
1113 longest_tof = 0.;
1114
1115 bool loaded{false};
1116 auto loaderType = defineLoaderType(haveWeights, oldNeXusFileNames, classType);
1117 if (loaderType != LoaderType::DEFAULT) {
1118 auto ws = m_ws->getSingleHeldWorkspace();
1119 m_file->close();
1120 if (loaderType == LoaderType::MPI) {
1121 try {
1122 ParallelEventLoader::loadMPI(*ws, m_filename, m_top_entry_name, bankNames, event_id_is_spec);
1123 g_log.information() << "Used MPI ParallelEventLoader.\n";
1124 loaded = true;
1125 shortest_tof = 0.0;
1126 longest_tof = 1e10;
1127 } catch (const std::runtime_error &) {
1128 g_log.warning() << "MPI event loader failed, falling back to default loader.\n";
1129 }
1130 } else {
1131
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';
1135 try {
1136 std::rethrow_if_nested(except);
1137 } catch (const std::exception &e) {
1138 ExceptionOutput::out(log, e, level + 1);
1139 } catch (...) {
1140 }
1141 }
1142 };
1143
1144 try {
1145 ParallelEventLoader::loadMultiProcess(*ws, m_filename, m_top_entry_name, bankNames, event_id_is_spec,
1146 getProperty("Precount"));
1147 g_log.information() << "Used Multiprocess ParallelEventLoader.\n";
1148 loaded = true;
1149 shortest_tof = 0.0;
1150 longest_tof = 1e10;
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";
1155 }
1156 }
1157
1158 safeOpenFile(m_filename);
1159 }
1160 if (!loaded) {
1161 bool precount = getProperty("Precount");
1162 int chunk = getProperty("ChunkNumber");
1163 int totalChunks = getProperty("TotalChunks");
1164 DefaultEventLoader::load(this, *m_ws, haveWeights, event_id_is_spec, bankNames, periodLog->valuesAsVector(),
1165 classType, bankNumEvents, oldNeXusFileNames, precount, chunk, totalChunks);
1166 }
1167
1168 // Info reporting
1169 const std::size_t eventsLoaded = m_ws->getNumberEvents();
1170 g_log.information() << "Read " << eventsLoaded << " events"
1171 << ". Shortest TOF: " << shortest_tof << " microsec; longest TOF: " << longest_tof
1172 << " microsec.\n";
1173
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";
1177 if (bad_tofs > 0)
1178 g_log.warning() << "Found " << bad_tofs
1179 << " events with TOF > 2e8. This "
1180 "may indicate errors in the raw "
1181 "TOF data.\n";
1182
1183 // Use T0 offset from TOPAZ Parameter file if it exists
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();
1188 if (mT0 != 0.0) {
1189 auto numHistograms = static_cast<int64_t>(m_ws->getNumberHistograms());
1191 for (int64_t i = 0; i < numHistograms; ++i) {
1193 // Do the offsetting
1194 m_ws->getSpectrum(i).addTof(mT0);
1196 }
1198 // set T0 in the run parameters
1199 API::Run &run = m_ws->mutableRun();
1200 run.addProperty<double>("T0", mT0, true);
1201 }
1202 }
1203 }
1204 // Now, create a default X-vector for histogramming, with just 2 bins.
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);
1213 }
1214 m_ws->setAllX(HistogramData::BinEdges{binEdgesVec});
1215 } else
1216 m_ws->setAllX(HistogramData::BinEdges{0.0, 1.0});
1217
1218 // if there is time_of_flight load it
1219 adjustTimeOfFlightISISLegacy(*m_file, m_ws, m_top_entry_name, classType, descriptor.get());
1220
1221 if (is_time_filtered) {
1222 // Now filter out the run and events, using the DateAndTime type.
1223 // This will sort both by pulse time
1224 filterEventsByTime(m_ws, filter_time_start, filter_time_stop);
1225 }
1226}
1227
1228//-----------------------------------------------------------------------------
1239template <>
1240bool LoadEventNexus::runLoadIDFFromNexus<EventWorkspaceCollection_sptr>(const std::string &nexusfilename,
1241 EventWorkspaceCollection_sptr localWorkspace,
1242 const std::string &top_entry_name,
1243 Algorithm *alg) {
1244 auto ws = localWorkspace->getSingleHeldWorkspace();
1245 auto hasLoaded = runLoadIDFFromNexus<MatrixWorkspace_sptr>(nexusfilename, ws, top_entry_name, alg);
1246 localWorkspace->setInstrument(ws->getInstrument());
1247 return hasLoaded;
1248}
1249
1254std::string LoadEventNexus::readInstrumentFromISIS_VMSCompat(::NeXus::File &hFile) {
1255 std::string instrumentName;
1256 try {
1257 hFile.openGroup("isis_vms_compat", "IXvms");
1258 } catch (std::runtime_error &) {
1259 return instrumentName;
1260 }
1261 try {
1262 hFile.openData("NAME");
1263 } catch (std::runtime_error &) {
1264 hFile.closeGroup();
1265 return instrumentName;
1266 }
1267
1268 instrumentName = hFile.getStrData();
1269 hFile.closeData();
1270 hFile.closeGroup();
1271
1272 return instrumentName;
1273}
1274
1275//-----------------------------------------------------------------------------
1288template <>
1289bool LoadEventNexus::runLoadInstrument<EventWorkspaceCollection_sptr>(const std::string &nexusfilename,
1290 EventWorkspaceCollection_sptr localWorkspace,
1291 const std::string &top_entry_name, Algorithm *alg,
1292 const Kernel::NexusHDF5Descriptor *descriptor) {
1293 auto ws = localWorkspace->getSingleHeldWorkspace();
1294 auto hasLoaded = runLoadInstrument<MatrixWorkspace_sptr>(nexusfilename, ws, top_entry_name, alg, descriptor);
1295 localWorkspace->setInstrument(ws->getInstrument());
1296 return hasLoaded;
1297}
1298
1299//-----------------------------------------------------------------------------
1306 const std::vector<std::string> &bankNames) {
1307 Instrument_sptr inst = std::const_pointer_cast<Instrument>(workspace->getInstrument()->baseInstrument());
1308 // Build a list of Rectangular Detectors
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;
1314
1315 det = std::dynamic_pointer_cast<RectangularDetector>((*inst)[i]);
1316 if (det) {
1317 detList.emplace_back(det);
1318 } else {
1319 // Also, look in the first sub-level for RectangularDetectors (e.g.
1320 // PG3). We are not doing a full recursive search since that will be
1321 // very long for lots of pixels.
1322 assem = std::dynamic_pointer_cast<ICompAssembly>((*inst)[i]);
1323 if (assem) {
1324 for (int j = 0; j < assem->nelements(); j++) {
1325 det = std::dynamic_pointer_cast<RectangularDetector>((*assem)[j]);
1326 if (det) {
1327 detList.emplace_back(det);
1328
1329 } else {
1330 // Also, look in the second sub-level for RectangularDetectors
1331 // (e.g. PG3). We are not doing a full recursive search since that
1332 // will be very long for lots of pixels.
1333 assem2 = std::dynamic_pointer_cast<ICompAssembly>((*assem)[j]);
1334 if (assem2) {
1335 for (int k = 0; k < assem2->nelements(); k++) {
1336 det = std::dynamic_pointer_cast<RectangularDetector>((*assem2)[k]);
1337 if (det) {
1338 detList.emplace_back(det);
1339 }
1340 }
1341 }
1342 }
1343 }
1344 }
1345 }
1346 }
1347 if (detList.empty())
1348 return;
1349 for (auto &det : detList) {
1350 bool keep = false;
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))
1355 keep = true;
1356 if (keep)
1357 break;
1358 }
1359 if (!keep) {
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);
1370
1371 for (auto &row : grandchildren) {
1372 auto *d = dynamic_cast<Detector *>(const_cast<IComponent *>(row.get()));
1373 if (d)
1374 inst->removeDetector(d);
1375 }
1376 }
1377 auto *comp = dynamic_cast<IComponent *>(det.get());
1378 inst->remove(comp);
1379 }
1380 }
1381}
1382//-----------------------------------------------------------------------------
1391void LoadEventNexus::createSpectraMapping(const std::string &nxsfile, const bool monitorsOnly,
1392 const std::vector<std::string> &bankNames) {
1393 LoadEventNexusIndexSetup indexSetup(m_ws->getSingleHeldWorkspace(), getProperty("SpectrumMin"),
1394 getProperty("SpectrumMax"), getProperty("SpectrumList"), communicator());
1395 if (!monitorsOnly && !bankNames.empty()) {
1396 if (!isDefault("SpectrumMin") || !isDefault("SpectrumMax") || !isDefault("SpectrumList"))
1397 g_log.warning() << "Spectrum min/max/list selection ignored when "
1398 "`SingleBankPixelsOnly` is enabled\n";
1399 m_ws->setIndexInfo(indexSetup.makeIndexInfo(bankNames));
1400 g_log.debug() << "Populated spectra map for select banks\n";
1401 } else if (auto mapping = loadISISVMSSpectraMapping(m_top_entry_name)) {
1402 if (monitorsOnly) {
1403 g_log.debug() << "Loading only monitor spectra from " << nxsfile << "\n";
1404 } else {
1405 g_log.debug() << "Loading only detector spectra from " << nxsfile << "\n";
1406 }
1407 m_ws->setIndexInfo(indexSetup.makeIndexInfo(*mapping, monitorsOnly));
1408 } else {
1409 g_log.debug() << "No custom spectra mapping found, continuing with default "
1410 "1:1 mapping of spectrum:detectorID\n";
1411 m_ws->setIndexInfo(indexSetup.makeIndexInfo());
1412 g_log.debug() << "Populated 1:1 spectra map for the whole instrument \n";
1413 }
1414 std::tie(m_specMin, m_specMax) = indexSetup.eventIDLimits();
1415}
1416
1417//-----------------------------------------------------------------------------
1424 std::string mon_wsname = this->getProperty("OutputWorkspace");
1425 mon_wsname.append("_monitors");
1426
1427 auto loadMonitors = createChildAlgorithm("LoadNexusMonitors");
1428 g_log.information("Loading monitors from NeXus file...");
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");
1436 // create the output workspace property on the fly
1437 this->declareProperty(
1438 std::make_unique<WorkspaceProperty<Workspace>>("MonitorWorkspace", mon_wsname, Direction::Output),
1439 "Monitors from the Event NeXus file");
1440 this->setProperty("MonitorWorkspace", monsOut);
1441
1442 // The output will either be a group workspace or a matrix workspace
1443 MatrixWorkspace_sptr mons = std::dynamic_pointer_cast<MatrixWorkspace>(monsOut);
1444 if (mons) {
1445 // Set the internal monitor workspace pointer as well
1446 m_ws->setMonitorWorkspace(mons);
1447
1448 filterDuringPause(mons);
1449 } else {
1450 WorkspaceGroup_sptr monsGrp = std::dynamic_pointer_cast<WorkspaceGroup>(monsOut);
1451 if (monsGrp) {
1452 // declare a property for each member of the group
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"
1458 << "_" << i + 1;
1459 this->declareProperty(
1460 std::make_unique<WorkspaceProperty<MatrixWorkspace>>(ssPropName.str(), ssWsName.str(), Direction::Output),
1461 "Monitors from the Event NeXus file");
1462 this->setProperty(ssPropName.str(), monsGrp->getItem(i));
1463 }
1464 }
1465 }
1466}
1467
1468//
1478std::unique_ptr<std::pair<std::vector<int32_t>, std::vector<int32_t>>>
1479LoadEventNexus::loadISISVMSSpectraMapping(const std::string &entry_name) {
1480 const std::string vms_str = "/isis_vms_compat";
1481 try {
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 &) {
1485 return nullptr; // Doesn't exist
1486 }
1487
1488 // The ISIS spectrum mapping is defined by 2 arrays in isis_vms_compat
1489 // block:
1490 // UDET - An array of detector IDs
1491 // SPEC - An array of spectrum numbers
1492 // There sizes must match. Hardware allows more than one detector ID to be
1493 // mapped to a single spectrum
1494 // and this is encoded in the SPEC/UDET arrays by repeating the spectrum
1495 // number in the array
1496 // for each mapped detector, e.g.
1497 //
1498 // 1 1001
1499 // 1 1002
1500 // 2 2001
1501 // 3 3001
1502 //
1503 // defines 3 spectra, where the first spectrum contains 2 detectors
1504
1505 // UDET
1506 m_file->openData("UDET");
1507 std::vector<int32_t> udet;
1508 m_file->getData(udet);
1509 m_file->closeData();
1510 // SPEC
1511 m_file->openData("SPEC");
1512 std::vector<int32_t> spec;
1513 m_file->getData(spec);
1514 m_file->closeData();
1515 // Go up/back. this assumes one level for entry name and a second level
1516 // for /isis_vms_compat, typically: /raw_data_1/isis_vms_compat
1517 m_file->closeGroup();
1518 m_file->closeGroup();
1519
1520 // The spec array will contain a spectrum number for each udet but the
1521 // spectrum number
1522 // may be the same for more that one detector
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());
1528 }
1529 // If mapping loaded the event ID is the spectrum number and not det ID
1530 this->event_id_is_spec = true;
1531 return std::make_unique<std::pair<std::vector<int32_t>, std::vector<int32_t>>>(std::move(spec), std::move(udet));
1532}
1533
1539void LoadEventNexus::setTimeFilters(const bool monitors) {
1540 // Get the limits to the filter
1541 std::string prefix("Filter");
1542 if (monitors)
1543 prefix += "Mon";
1544
1545 filter_tof_min = getProperty(prefix + "ByTofMin");
1546 filter_tof_max = getProperty(prefix + "ByTofMax");
1547 if ((filter_tof_min == EMPTY_DBL()) && (filter_tof_max == EMPTY_DBL())) {
1548 // Nothing specified. Include everything
1549 filter_tof_min = -1e20;
1550 filter_tof_max = +1e20;
1551 } else if ((filter_tof_min != EMPTY_DBL()) && (filter_tof_max != EMPTY_DBL())) {
1552 // Both specified. Keep these values
1553 } else {
1554 std::string msg("You must specify both min & max or neither TOF filters");
1555 if (monitors)
1556 msg = " for the monitors.";
1557 throw std::invalid_argument(msg);
1558 }
1559}
1560
1561//-----------------------------------------------------------------------------
1562
1578 try {
1579 file.openGroup("isis_vms_compat", "IXvms");
1580 } catch (::NeXus::Exception &) {
1581 // No problem, it just means that this entry does not exist
1582 return;
1583 }
1584
1585 // read the data
1586 try {
1587 std::vector<int32_t> spb;
1588 std::vector<float> rspb;
1589 file.readData("SPB", spb);
1590 file.readData("RSPB", rspb);
1591
1592 WS.setGeometryFlag(spb[2]); // the flag is in the third value
1593 WS.setThickness(rspb[3]);
1594 WS.setHeight(rspb[4]);
1595 WS.setWidth(rspb[5]);
1596 } catch (::NeXus::Exception &ex) {
1597 // it means that the data was not as expected, report the problem
1598 std::stringstream s;
1599 s << "Wrong definition found in isis_vms_compat :> " << ex.what();
1600 file.closeGroup();
1601 throw std::runtime_error(s.str());
1602 }
1603
1604 file.closeGroup();
1605}
1606
1613void LoadEventNexus::safeOpenFile(const std::string &fname) {
1614 try {
1615 m_file = std::make_unique<::NeXus::File>(m_filename, NXACC_READ);
1616 } catch (std::runtime_error &e) {
1617 throw std::runtime_error("Severe failure when trying to open NeXus file: " + std::string(e.what()));
1618 }
1619 // make sure that by no means we could dereference NULL later on
1620 if (!m_file) {
1621 throw std::runtime_error("An unexpected failure happened, unable to "
1622 "initialize file object when trying to open NeXus "
1623 "file: " +
1624 fname);
1625 }
1626}
1627
1630LoadEventNexus::LoaderType LoadEventNexus::defineLoaderType(const bool haveWeights, const bool oldNeXusFileNames,
1631 const std::string &classType) const {
1632 auto propVal = getPropertyValue("LoadType");
1633 if (propVal == "Default")
1634 return LoaderType::DEFAULT;
1635
1636 bool noParallelConstrictions = true;
1637 noParallelConstrictions &= !(m_ws->nPeriods() != 1);
1638 noParallelConstrictions &= !haveWeights;
1639 noParallelConstrictions &= !oldNeXusFileNames;
1640 noParallelConstrictions &= !(filter_tof_min != -1e20 || filter_tof_max != 1e20);
1641 noParallelConstrictions &= !((filter_time_start != Types::Core::DateAndTime::minimum() ||
1642 filter_time_stop != Types::Core::DateAndTime::maximum()));
1643 noParallelConstrictions &= !((!isDefault("CompressTolerance") || !isDefault("SpectrumMin") ||
1644 !isDefault("SpectrumMax") || !isDefault("SpectrumList") || !isDefault("ChunkNumber")));
1645 noParallelConstrictions &= !(classType != "NXevent_data");
1646
1647 if (!noParallelConstrictions)
1648 return LoaderType::DEFAULT;
1649#ifndef MPI_EXPERIMENTAL
1651#else
1652 return propVal == "MPI" ? LoaderType::MPI : LoaderType::MULTIPROCESS;
1653#endif
1654}
1655
1656Parallel::ExecutionMode
1657LoadEventNexus::getParallelExecutionMode(const std::map<std::string, Parallel::StorageMode> &storageModes) const {
1658 static_cast<void>(storageModes);
1659 return Parallel::ExecutionMode::Distributed;
1660}
1661} // namespace Mantid::DataHandling
gsl_vector * tmp
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
#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...
Definition: MultiThreaded.h:94
#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.
Definition: Algorithm.h:85
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
bool isDefault(const std::string &name) const
Definition: Algorithm.cpp:2084
const Parallel::Communicator & communicator() const
Returns a const reference to the (MPI) communicator of the algorithm.
Definition: Algorithm.cpp:1870
Kernel::Logger & getLogger() const
Returns a reference to the logger.
Definition: Algorithm.cpp:1660
void filterByTime(const Types::Core::DateAndTime &, const Types::Core::DateAndTime &) override
Definition: Algorithm.h:365
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Definition: LogManager.cpp:265
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
Definition: LogManager.cpp:404
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
Definition: LogManager.cpp:332
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.
Definition: Progress.h:25
void doReport(const std::string &msg="") override
Actually do the reporting, without changing the loop counter.
Definition: Progress.cpp:70
This class stores information regarding an experimental run as a series of log entries.
Definition: Run.h:38
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...
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...
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
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.
Definition: Detector.h:30
Class to represent a particular goniometer setting, which is described by the rotation matrix.
Definition: Goniometer.h:55
void makeUniversalGoniometer()
Make a default universal goniometer with phi,chi,omega angles according to SNS convention.
Definition: Goniometer.cpp:271
base class for Geometric IComponent
Definition: IComponent.h:51
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
Exception for when an item is not found in a collection.
Definition: Exception.h:145
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.
Definition: Logger.h:52
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
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.
Definition: ProgressBase.h:51
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
Definition: Workspace_fwd.h:20
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.
Definition: LoadHelper.cpp:131
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)
Definition: Unit.cpp:1435
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.
Definition: MultiThreaded.h:22
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54