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"
24#include "MantidIndexing/IndexInfo.h"
32#include "MantidKernel/Timer.h"
36#include "MantidNexus/NexusFile.h"
38
39#include <H5Cpp.h>
40#include <boost/format.hpp>
41#include <memory>
42
43#include <regex>
44
45using Mantid::Types::Core::DateAndTime;
46using std::map;
47using std::string;
48using std::vector;
49
50namespace Mantid::DataHandling {
51
53
54using namespace Kernel;
55using namespace DateAndTimeHelpers;
56using namespace Geometry;
57using namespace API;
58using namespace DataObjects;
59using Types::Core::DateAndTime;
60
61namespace {
62const std::vector<std::string> binningModeNames{"Default", "Linear", "Logarithmic"};
63enum class BinningMode { DEFAULT, LINEAR, LOGARITHMIC, enum_count };
65
66const std::string LOG_CHARGE_NAME("proton_charge");
67
68namespace PropertyNames {
69const std::string COMPRESS_TOL("CompressTolerance");
70const std::string COMPRESS_MODE("CompressBinningMode");
71const std::string BAD_PULSES_CUTOFF("FilterBadPulsesLowerCutoff");
72} // namespace PropertyNames
73} // namespace
74
75bool doPerformISISEventShift(Nexus::File &file, std::string &topEntryName) {
76 std::string detectorEventsAddr = std::format("/{}/detector_1_events", topEntryName);
77 if (!file.hasAddress(detectorEventsAddr)) { // not an isis file
78 return false;
79 }
80
81 const std::string eventTimeShiftAddr(detectorEventsAddr + "/event_time_offset_shift");
82 if (file.hasAddress(eventTimeShiftAddr)) { // almost certainly an isis file
83 std::string eventShiftType;
84 file.readData(eventTimeShiftAddr, eventShiftType);
85 return !(eventShiftType == "random"); // event correction already applied
86 }
87
88 const std::string programNameAddr = std::format("/{}/program_name", topEntryName);
89 if (file.hasAddress(programNameAddr)) { // check for ISIS control program
90 std::string program_name;
91 file.readData(programNameAddr, program_name);
92 if (program_name == "ISISICP.EXE") {
93 return true;
94 }
95 }
96 return false;
97}
98
99//----------------------------------------------------------------------------------------------
103 : filter_tof_min(0), filter_tof_max(0), m_specMin(0), m_specMax(0), longest_tof(0), shortest_tof(0), bad_tofs(0),
104 discarded_events(0), compressEvents(false), m_instrument_loaded_correctly(false), loadlogs(false),
105 event_id_is_spec(false) {
107}
108
109//----------------------------------------------------------------------------------------------
117 int confidence = 0;
118 if (descriptor.classTypeExists("NXevent_data")) {
119 if (descriptor.isEntry("/entry", "NXentry") || descriptor.isEntry("/raw_data_1", "NXentry")) {
120 confidence = 80;
121 }
122 }
123
124 return confidence;
125}
126
127//----------------------------------------------------------------------------------------------
131 const std::vector<std::string> exts{".nxs.h5", ".nxs", "_event.nxs"};
132 this->declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, exts),
133 "The name of the Event NeXus file to read, including its full or "
134 "relative path. "
135 "The file name is typically of the form INST_####_event.nxs (N.B. case "
136 "sensitive if running on Linux).");
137
138 this->declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
139 "The name of the output EventWorkspace or WorkspaceGroup in which to "
140 "load the EventNexus file.");
141
142 declareProperty(std::make_unique<PropertyWithValue<string>>("NXentryName", "", Direction::Input),
143 "Optional: Name of the NXentry to load if it's not the default.");
144
145 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTofMin", EMPTY_DBL(), Direction::Input),
146 "Optional: To exclude events that do not fall within a range "
147 "of times-of-flight. "
148 "This is the minimum accepted value in microseconds. Keep "
149 "blank to load all events.");
150
151 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTofMax", EMPTY_DBL(), Direction::Input),
152 "Optional: To exclude events that do not fall within a range "
153 "of times-of-flight. "
154 "This is the maximum accepted value in microseconds. Keep "
155 "blank to load all events.");
156
157 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTimeStart", EMPTY_DBL(), Direction::Input),
158 "Optional: To only include events after the provided start "
159 "time, in seconds (relative to the start of the run).");
160
161 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTimeStop", EMPTY_DBL(), Direction::Input),
162 "Optional: To only include events before the provided stop "
163 "time, in seconds (relative to the start of the run).");
164
166 std::make_unique<PropertyWithValue<double>>(PropertyNames::BAD_PULSES_CUTOFF, EMPTY_DBL(), Direction::Input),
167 "Optional: To filter bad pulses set the Lower Cutoff percentage to use.");
168
169 std::string grp1 = "Filter Events";
170 setPropertyGroup("FilterByTofMin", grp1);
171 setPropertyGroup("FilterByTofMax", grp1);
172 setPropertyGroup("FilterByTimeStart", grp1);
173 setPropertyGroup("FilterByTimeStop", grp1);
174 setPropertyGroup("FilterBadPulsesLowerCutoff", grp1);
175
176 declareProperty(std::make_unique<ArrayProperty<string>>("BankName", Direction::Input),
177 "Optional: To only include events from one bank. Any bank "
178 "whose name does not match the given string will have no "
179 "events.");
180
181 declareProperty(std::make_unique<PropertyWithValue<bool>>("SingleBankPixelsOnly", true, Direction::Input),
182 "Optional: Only applies if you specified a single bank to "
183 "load with BankName. "
184 "Only pixels in the specified bank will be created if true; "
185 "all of the instrument's pixels will be created otherwise.");
186 setPropertySettings("SingleBankPixelsOnly", std::make_unique<VisibleWhenProperty>("BankName", IS_NOT_DEFAULT));
187
188 std::string grp2 = "Loading a Single Bank";
189 setPropertyGroup("BankName", grp2);
190 setPropertyGroup("SingleBankPixelsOnly", grp2);
191
192 declareProperty(std::make_unique<PropertyWithValue<bool>>("Precount", true, Direction::Input),
193 "Pre-count the number of events in each pixel before allocating memory "
194 "(optional, default True). "
195 "This can significantly reduce memory use and memory fragmentation; it "
196 "may also speed up loading.");
197
199 std::make_unique<PropertyWithValue<double>>(PropertyNames::COMPRESS_TOL, EMPTY_DBL(), Direction::Input),
200 "CompressEvents while loading (optional, default: off). "
201 "This specified the tolerance to use (in microseconds) when compressing where positive is linear tolerance, "
202 "negative is logorithmic tolerance, and zero indicates that time-of-flight must be identical to compress.");
204 PropertyNames::COMPRESS_MODE, binningModeNames[size_t(BinningMode::DEFAULT)],
205 std::make_shared<Mantid::Kernel::StringListValidator>(binningModeNames),
206 "Optional. "
207 "Binning behavior can be specified in the usual way through sign of binwidth and other properties ('Default'); "
208 "or can be set to one of the allowed binning modes. "
209 "This will override all other specification or default behavior.");
210
211 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
212 mustBePositive->setLower(1);
213 declareProperty("ChunkNumber", EMPTY_INT(), mustBePositive,
214 "If loading the file by sections ('chunks'), this is the "
215 "section number of this execution of the algorithm.");
216 declareProperty("TotalChunks", EMPTY_INT(), mustBePositive,
217 "If loading the file by sections ('chunks'), this is the "
218 "total number of sections.");
219 // TotalChunks is only meaningful if ChunkNumber is set
220 // Would be nice to be able to restrict ChunkNumber to be <= TotalChunks at
221 // validation
222 setPropertySettings("TotalChunks", std::make_unique<VisibleWhenProperty>("ChunkNumber", IS_NOT_DEFAULT));
223
224 std::string grp3 = "Reduce Memory Use";
225 setPropertyGroup("Precount", grp3);
226 setPropertyGroup(PropertyNames::COMPRESS_TOL, grp3);
227 setPropertyGroup(PropertyNames::COMPRESS_MODE, grp3);
228 setPropertyGroup("ChunkNumber", grp3);
229 setPropertyGroup("TotalChunks", grp3);
230
231 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadMonitors", false, Direction::Input),
232 "Load the monitors from the file (optional, default False).");
233
234 std::vector<std::string> options{"", "Events", "Histogram"};
235 declareProperty("MonitorsLoadOnly", "", std::make_shared<Kernel::StringListValidator>(options),
236 "If multiple repesentations exist, which one to load. "
237 "Default is to load the one that is present.");
238
239 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTofMin", EMPTY_DBL(), Direction::Input),
240 "Optional: To exclude events from monitors that do not fall "
241 "within a range of times-of-flight. "
242 "This is the minimum accepted value in microseconds.");
243
244 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTofMax", EMPTY_DBL(), Direction::Input),
245 "Optional: To exclude events from monitors that do not fall "
246 "within a range of times-of-flight. "
247 "This is the maximum accepted value in microseconds.");
248
249 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTimeStart", EMPTY_DBL(), Direction::Input),
250 "Optional: To only include events from monitors after the "
251 "provided start time, in seconds (relative to the start of "
252 "the run).");
253
254 declareProperty(std::make_unique<PropertyWithValue<double>>("FilterMonByTimeStop", EMPTY_DBL(), Direction::Input),
255 "Optional: To only include events from monitors before the "
256 "provided stop time, in seconds (relative to the start of "
257 "the run).");
258
259 setPropertySettings("MonitorsLoadOnly", std::make_unique<VisibleWhenProperty>("LoadMonitors", IS_EQUAL_TO, "1"));
260 auto asEventsIsOn = [] {
261 std::unique_ptr<IPropertySettings> prop = std::make_unique<VisibleWhenProperty>("LoadMonitors", IS_EQUAL_TO, "1");
262 return prop;
263 };
264 setPropertySettings("FilterMonByTofMin", asEventsIsOn());
265 setPropertySettings("FilterMonByTofMax", asEventsIsOn());
266 setPropertySettings("FilterMonByTimeStart", asEventsIsOn());
267 setPropertySettings("FilterMonByTimeStop", asEventsIsOn());
268
269 std::string grp4 = "Monitors";
270 setPropertyGroup("LoadMonitors", grp4);
271 setPropertyGroup("MonitorsLoadOnly", grp4);
272 setPropertyGroup("FilterMonByTofMin", grp4);
273 setPropertyGroup("FilterMonByTofMax", grp4);
274 setPropertyGroup("FilterMonByTimeStart", grp4);
275 setPropertyGroup("FilterMonByTimeStop", grp4);
276
277 declareProperty("SpectrumMin", EMPTY_INT(), mustBePositive, "The number of the first spectrum to read.");
278 declareProperty("SpectrumMax", EMPTY_INT(), mustBePositive, "The number of the last spectrum to read.");
279 declareProperty(std::make_unique<ArrayProperty<int32_t>>("SpectrumList"),
280 "A comma-separated list of individual spectra to read.");
281
282 declareProperty(std::make_unique<PropertyWithValue<bool>>("MetaDataOnly", false, Direction::Input),
283 "If true, only the meta data and sample logs will be loaded.");
284
285 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadLogs", true, Direction::Input),
286 "Load only the Sample/DAS logs from the file (default True).");
287
288 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadAllLogs", false, Direction::Input),
289 "Load all the logs from the nxs, without checking or processing them; if checked, LoadLogs will be "
290 "ignored; use with caution");
291
292 std::vector<std::string> loadType{"Default", "Multiprocess (experimental)"};
293 auto loadTypeValidator = std::make_shared<StringListValidator>(loadType);
295 "LoadType", "Default", loadTypeValidator,
296 "Deprecated feature. This option has no effect on algorithm behavior and will be removed in a future release.");
297
298 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadNexusInstrumentXML", true, Direction::Input),
299 "Reads the embedded Instrument XML from the NeXus file "
300 "(optional, default True). ");
301
302 declareProperty("NumberOfBins", 500, mustBePositive,
303 "The number of bins intially defined. Use Rebin to change "
304 "the binning later. If there is no data loaded, or you "
305 "select meta data only you will only get 1 bin.");
306
307 // Flexible log loading
308 declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>("AllowList", std::vector<std::string>(),
310 "If specified, only these logs will be loaded from the file (each "
311 "separated by a space).");
312 declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>("BlockList", std::vector<std::string>(),
314 "If specified, these logs will NOT be loaded from the file (each "
315 "separated by a space).");
316}
317
318std::map<std::string, std::string> LoadEventNexus::validateInputs() {
319
320 // Warn deprecated experimental feature, but do not throw error
321 if (!isDefault("LoadType")) {
322 g_log.warning() << "The experimental multiprocess loader has been discontinued. The default loader will be used "
323 "instead. Please remove use of this property from all scripts.";
324 }
325 setProperty("LoadType", "Default");
326
327 std::map<std::string, std::string> result;
328
329 if (!isDefault(PropertyNames::BAD_PULSES_CUTOFF)) {
330 const double cutoff = getProperty(PropertyNames::BAD_PULSES_CUTOFF);
331 if (cutoff < 0 || cutoff > 100)
332 result[PropertyNames::BAD_PULSES_CUTOFF] = "Must be empty or between 0 and 100";
333 }
334
335 return result;
336}
337
338//----------------------------------------------------------------------------------------------
342 std::string nxentryProperty = getProperty("NXentryName");
343 if (!nxentryProperty.empty()) {
344 m_top_entry_name = nxentryProperty;
345 return;
346 }
347
348 std::string firstGoodEntry("");
349 std::set<std::string> goodEntries{"entry", "raw_data_1"};
350 auto allEntries = m_file->getEntries();
351 for (std::string goodEntry : goodEntries) {
352 if (allEntries.count(goodEntry) != 0 && allEntries[goodEntry] != "SDS") {
353 firstGoodEntry = std::move(goodEntry);
354 break;
355 }
356 }
357 m_top_entry_name = std::move(firstGoodEntry);
358 if (m_top_entry_name.empty()) {
359 g_log.error() << "Unable to determine name of top level NXentry - assuming \"entry\".\n";
360 m_top_entry_name = "entry";
361 }
362}
363
364template <typename T> void LoadEventNexus::filterDuringPause(T workspace) {
365 try {
366 if ((!ConfigService::Instance().hasProperty("loadeventnexus.keeppausedevents")) &&
367 (m_ws->run().getLogData("pause")->size() > 1)) {
368 g_log.notice("Filtering out events when the run was marked as paused. "
369 "Set the loadeventnexus.keeppausedevents configuration "
370 "property to override this.");
371
372 auto filter = createChildAlgorithm("FilterByLogValue");
373 filter->setProperty("InputWorkspace", workspace);
374 filter->setProperty("OutputWorkspace", workspace);
375 filter->setProperty("LogName", "pause");
376 // The log value is set to 1 when the run is paused, 0 otherwise.
377 filter->setProperty("MinimumValue", 0.0);
378 filter->setProperty("MaximumValue", 0.0);
379 filter->setProperty("LogBoundary", "Left");
380 filter->execute();
381 }
382 } catch (Exception::NotFoundError &) {
383 // No "pause" log, just carry on
384 }
385}
386
387template <>
388void LoadEventNexus::filterDuringPause<EventWorkspaceCollection_sptr>(EventWorkspaceCollection_sptr workspace) {
389 // We provide a function pointer to the filter method of the object
390 using std::placeholders::_1;
391 auto func = std::bind(&LoadEventNexus::filterDuringPause<MatrixWorkspace_sptr>, this, _1);
392 workspace->applyFilterInPlace(func);
393}
394
395//-----------------------------------------------------------------------------
400template <typename T>
401T LoadEventNexus::filterEventsByTime(T workspace, Mantid::Types::Core::DateAndTime &startTime,
402 Mantid::Types::Core::DateAndTime &stopTime) {
403 auto filterByTime = createChildAlgorithm("FilterByTime");
404 g_log.information("Filtering events by time...");
405 filterByTime->setProperty("InputWorkspace", workspace);
406 // sample log already filtered by time so use absolute times to be safe
407 filterByTime->setProperty("AbsoluteStartTime", startTime.toISO8601String());
408 filterByTime->setProperty("AbsoluteStopTime", stopTime.toISO8601String());
409 filterByTime->execute();
410 return filterByTime->getProperty("OutputWorkspace");
411}
412
413template <>
415LoadEventNexus::filterEventsByTime<EventWorkspaceCollection_sptr>(EventWorkspaceCollection_sptr workspace,
416 Mantid::Types::Core::DateAndTime &startTime,
417 Mantid::Types::Core::DateAndTime &stopTime) {
418 // We provide a function pointer to the filter method of the object
419 using std::placeholders::_1;
420 auto func = std::bind(&LoadEventNexus::filterEventsByTime<EventWorkspace_sptr>, this, _1, startTime, stopTime);
421 workspace->applyFilter(func);
422 return workspace;
423}
424
425//------------------------------------------------------------------------------------------------
430 // Retrieve the filename from the properties
431 m_filename = getPropertyValue("Filename");
432
433 compressEvents = !isDefault(PropertyNames::COMPRESS_TOL);
434 compressTolerance = getProperty(PropertyNames::COMPRESS_TOL);
435 if (compressEvents) {
436 BINMODE mode = getPropertyValue(PropertyNames::COMPRESS_MODE);
437 if (mode == BinningMode::LINEAR)
439 else if (mode == BinningMode::LOGARITHMIC)
440 compressTolerance = -1. * std::fabs(compressTolerance);
441 }
442
443 loadlogs = getProperty("LoadLogs");
444
445 // Check to see if the monitors need to be loaded later
446 bool load_monitors = this->getProperty("LoadMonitors");
447
448 // this must make absolutely sure that m_file is a valid (and open)
449 // Nexus::File object
451
453
454 // Initialize progress reporting.
455 int reports = 3;
456 if (load_monitors)
457 reports++;
458 Progress prog(this, 0.0, 0.3, reports);
459
460 // Load the detector events
461 m_ws = std::make_shared<EventWorkspaceCollection>(); // Algorithm currently
462 // relies on an
463
464 // object-level workspace ptr
465 loadEvents(&prog, false); // Do not load monitor blocks
466
467 if (discarded_events > 0) {
469 << " events were encountered coming from pixels which "
470 "are not in the Instrument Definition File."
471 "These events were discarded.\n";
472 }
473
474 // If the run was paused at any point, filter out those events (SNS only, I
475 // think)
476 filterDuringPause(m_ws->getSingleHeldWorkspace());
477
478 // add filename
479 m_ws->mutableRun().addProperty("Filename", m_filename);
480 // Save output
481 this->setProperty("OutputWorkspace", m_ws->combinedWorkspace());
482
483 // close the file since LoadNexusMonitors will take care of its own file
484 // handle
485 m_file->close();
486
487 // Load the monitors with child algorithm 'LoadNexusMonitors'
488 if (load_monitors) {
489 prog.report("Loading monitors");
490 this->runLoadMonitors();
491 }
492}
493
494std::pair<DateAndTime, DateAndTime> firstLastPulseTimes(Nexus::File &file, Kernel::Logger &logger) {
495 file.openData("event_time_zero");
496 DateAndTime offset;
497 // According to the Nexus standard, if the offset is not present, it implies
498 // the offset is and absolute timestamp, which is relative to the start of
499 // Unix epoch (https://manual.nexusformat.org/classes/base_classes/NXlog.html)
500 if (!file.hasAttr("offset")) {
501 offset = DateAndTime("1970-01-01T00:00:00Z");
502 logger.warning("In firstLastPulseTimes: no ISO8601 offset attribute "
503 "provided for event_time_zero, using UNIX epoch instead");
504 } else {
505 std::string isooffset; // ISO8601 offset
506 file.getAttr("offset", isooffset);
507 offset = DateAndTime(isooffset);
508 }
509 std::string units; // time units
510 if (file.hasAttr("units"))
511 file.getAttr("units", units);
512 // Read in the pulse times
513 auto pulse_times = Nexus::IOHelper::readNexusVector<double>(file, "event_time_zero");
514 // Remember to close the entry
515 file.closeData();
516 if (pulse_times.empty()) {
517 throw std::invalid_argument("Cannot find run start; event_time_zero contains no pulse times");
518 }
519 // Convert to seconds
520 auto conv = Kernel::Units::timeConversionValue(units, "s");
521 return std::make_pair(DateAndTime(pulse_times.front() * conv, 0.0) + offset.totalNanoseconds(),
522 DateAndTime(pulse_times.back() * conv, 0.0) + offset.totalNanoseconds());
523} // namespace DataHandling
524
536std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix) {
537 // try getting the value of total_counts
538 if (hasTotalCounts) {
539 hasTotalCounts = false;
540 if (file.hasData(prefix + "/total_counts")) {
541 try {
542 file.openData("total_counts");
543 auto info = file.getInfo();
544 file.closeData();
545 if (info.type == NXnumtype::UINT64) {
546 uint64_t eventCount;
547 file.readData("total_counts", eventCount);
548 hasTotalCounts = true;
549 return eventCount;
550 }
551 } catch (Nexus::Exception const &) {
552 }
553 }
554 }
555
556 // just get the length of the event pixel ids
557 try {
558 if (oldNeXusFileNames)
559 file.openData("event_pixel_id");
560 else
561 file.openData("event_id");
562 } catch (Nexus::Exception const &) {
563 // Older files (before Nov 5, 2010) used this field.
564 try {
565 file.openData("event_pixel_id");
566 oldNeXusFileNames = true;
567 } catch (Nexus::Exception const &) {
568 // Some groups have neither indicating there are not events here
569 return 0;
570 }
571 }
572
573 size_t numEvents = static_cast<std::size_t>(file.getInfo().dims[0]);
574 file.closeData();
575 return numEvents;
576}
577
591template <typename T>
592std::shared_ptr<BankPulseTimes>
593LoadEventNexus::runLoadNexusLogs(const std::string &nexusfilename, T localWorkspace, API::Algorithm &alg,
594 bool returnpulsetimes, int &nPeriods,
595 std::unique_ptr<const TimeSeriesProperty<int>> &periodLog) {
596 // --------------------- Load DAS Logs -----------------
597 // The pulse times will be empty if not specified in the DAS logs.
598 // BankPulseTimes * out = NULL;
599 std::shared_ptr<BankPulseTimes> out;
600 auto loadLogs = alg.createChildAlgorithm("LoadNexusLogs");
601
602 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
603 try {
604 alg.getLogger().information() << "Loading logs from NeXus file..."
605 << "\n";
606 loadLogs->setPropertyValue("Filename", nexusfilename);
607 loadLogs->setProperty<API::MatrixWorkspace_sptr>("Workspace", localWorkspace);
608 try {
609 loadLogs->setPropertyValue("NXentryName", alg.getPropertyValue("NXentryName"));
610 } catch (...) {
611 }
612
613 loadLogs->execute();
614
615 const Run &run = localWorkspace->run();
616 // Get the number of periods
617 if (run.hasProperty("nperiods")) {
618 nPeriods = run.getPropertyValueAsType<int>("nperiods");
619 }
620 // Get the period log. Map of DateAndTime to Period int values.
621 if (run.hasProperty("period_log")) {
622 const auto *temp = run.getProperty("period_log");
623 // Check for corrupted period logs
624 std::string status = "";
625 std::unique_ptr<TimeSeriesProperty<int>> tempPeriodLog(dynamic_cast<TimeSeriesProperty<int> *>(temp->clone()));
626 nPeriods = checkForCorruptedPeriods(std::move(tempPeriodLog), periodLog, nPeriods, nexusfilename, status);
627 if (!status.empty())
628 alg.getLogger().warning(status);
629 }
630
631 // If successful, we can try to load the pulse times
632 std::vector<Types::Core::DateAndTime> temp;
633 if (localWorkspace->run().hasProperty("proton_charge")) {
634 const auto *log =
635 dynamic_cast<Kernel::TimeSeriesProperty<double> *>(localWorkspace->mutableRun().getProperty("proton_charge"));
636 if (log)
637 temp = log->timesAsVector();
638 }
639 if (returnpulsetimes)
640 out = std::make_shared<BankPulseTimes>(temp);
641
642 // Use the first pulse as the run_start time.
643 if (!temp.empty()) {
644 if (temp[0] < Types::Core::DateAndTime("1991-01-01T00:00:00"))
645 alg.getLogger().warning() << "Found entries in the proton_charge "
646 "sample log with invalid pulse time!\n";
647
648 Types::Core::DateAndTime run_start = localWorkspace->getFirstPulseTime();
649 // add the start of the run as a ISO8601 date/time string. The start =
650 // first non-zero time.
651 // (this is used in LoadInstrument to find the right instrument file to
652 // use).
653 localWorkspace->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
654 } else if (run.hasProperty("start_time")) {
655 localWorkspace->mutableRun().addProperty("run_start", run.getProperty("start_time")->value(), true);
656 } else {
657 alg.getLogger().warning() << "Empty proton_charge sample log. You will "
658 "not be able to filter by time.\n";
659 }
661 try {
664 localWorkspace->mutableRun().setGoniometer(gm, true);
665 } catch (std::runtime_error &) {
666 }
667 } catch (const InvalidLogPeriods &) {
668 // Rethrow so LoadEventNexus fails.
669 // If we don't, Mantid will crash.
670 throw;
671 } catch (...) {
672 alg.getLogger().error() << "Error while loading Logs from SNS Nexus. Some "
673 "sample logs may be missing."
674 << "\n";
675 return out;
676 }
677 return out;
678}
679
695template <typename T>
696std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs(
697 const std::string &nexusfilename, T localWorkspace, API::Algorithm &alg, bool returnpulsetimes, int &nPeriods,
698 std::unique_ptr<const TimeSeriesProperty<int>> &periodLog, const std::vector<std::string> &allow_list,
699 const std::vector<std::string> &block_list) {
700 // --------------------- Load DAS Logs -----------------
701 // The pulse times will be empty if not specified in the DAS logs.
702 // BankPulseTimes * out = NULL;
703 std::shared_ptr<BankPulseTimes> out;
704 auto loadLogs = alg.createChildAlgorithm("LoadNexusLogs");
705
706 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
707 try {
708 alg.getLogger().information() << "Loading logs from NeXus file..."
709 << "\n";
710 loadLogs->setPropertyValue("Filename", nexusfilename);
711 loadLogs->setProperty<API::MatrixWorkspace_sptr>("Workspace", localWorkspace);
712 loadLogs->setProperty<std::vector<std::string>>("AllowList", allow_list);
713 loadLogs->setProperty<std::vector<std::string>>("BlockList", block_list);
714
715 try {
716 loadLogs->setPropertyValue("NXentryName", alg.getPropertyValue("NXentryName"));
717 } catch (...) {
718 }
719
720 loadLogs->execute();
721
722 const Run &run = localWorkspace->run();
723 // Get the number of periods
724 if (run.hasProperty("nperiods")) {
725 nPeriods = run.getPropertyValueAsType<int>("nperiods");
726 }
727 // Get the period log. Map of DateAndTime to Period int values.
728 if (run.hasProperty("period_log")) {
729 auto *temp = run.getProperty("period_log");
730 std::string status = "";
731 // Check for corrupted period logs
732 std::unique_ptr<TimeSeriesProperty<int>> tempPeriodLog(dynamic_cast<TimeSeriesProperty<int> *>(temp->clone()));
733 nPeriods = checkForCorruptedPeriods(std::move(tempPeriodLog), periodLog, nPeriods, nexusfilename, status);
734 if (!status.empty())
735 alg.getLogger().warning(status);
736 }
737
738 // If successful, we can try to load the pulse times
739 std::vector<Types::Core::DateAndTime> temp;
740 if (localWorkspace->run().hasProperty("proton_charge")) {
741 auto *log =
742 dynamic_cast<Kernel::TimeSeriesProperty<double> *>(localWorkspace->mutableRun().getProperty("proton_charge"));
743 if (log)
744 temp = log->timesAsVector();
745 }
746 if (returnpulsetimes)
747 out = std::make_shared<BankPulseTimes>(temp);
748
749 // Use the first pulse as the run_start time.
750 if (!temp.empty()) {
751 if (temp[0] < Types::Core::DateAndTime("1991-01-01T00:00:00"))
752 alg.getLogger().warning() << "Found entries in the proton_charge "
753 "sample log with invalid pulse time!\n";
754
755 Types::Core::DateAndTime run_start = localWorkspace->getFirstPulseTime();
756 // add the start of the run as a ISO8601 date/time string. The start =
757 // first non-zero time.
758 // (this is used in LoadInstrument to find the right instrument file to
759 // use).
760 localWorkspace->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
761 } else {
762 alg.getLogger().warning() << "Empty proton_charge sample log. You will "
763 "not be able to filter by time.\n";
764 }
766 try {
769 localWorkspace->mutableRun().setGoniometer(gm, true);
770 } catch (std::runtime_error &) {
771 }
772 } catch (const InvalidLogPeriods &) {
773 // Rethrow so LoadEventNexus fails.
774 // If we don't, Mantid will crash.
775 throw;
776 } catch (...) {
777 alg.getLogger().error() << "Error while loading Logs from SNS Nexus. Some "
778 "sample logs may be missing."
779 << "\n";
780 return out;
781 }
782 return out;
783}
784
800 std::unique_ptr<const TimeSeriesProperty<int>> &periodLog,
801 const int &nPeriods, const std::string &nexusfilename,
802 std::string &status) {
803 const auto valuesAsVector = tempPeriodLog->valuesAsVector();
804 const auto nPeriodsInLog = *std::max_element(valuesAsVector.begin(), valuesAsVector.end());
805 int numberOfValidPeriods = nPeriodsInLog;
806 status = "";
807
808 // Check for historic files
809 if (nPeriodsInLog == 0 && nPeriods == 1) {
810 // "modernize" the local copy here by making period_log
811 // a vector of 1s
812 const std::vector<int> newValues(tempPeriodLog->realSize(), 1);
813 const auto times = tempPeriodLog->timesAsVector();
814 periodLog.reset(new const TimeSeriesProperty<int>("period_log", times, newValues));
815 numberOfValidPeriods = 1;
816 } else if (nPeriodsInLog < nPeriods) {
817 status = boost::str(
818 boost::format(
819 "The number of periods specified in the file (%1%) is greater than the maximum period in the data (%2%).") %
820 nPeriods % nPeriodsInLog);
821 } else if (nPeriodsInLog > nPeriods) {
822 // Sanity check here that period_log only contains period numbers up to
823 // nperiods. These values can be different due to instrument noise, and
824 // cause undescriptive crashes if not caught.
825 // We throw here to make it clear
826 // that the file is corrupted and must be manually assessed.
827 const auto msg = "File " + nexusfilename +
828 " has been corrupted. The log framelog/period_log/value "
829 "contains " +
830 std::to_string(nPeriodsInLog) + " periods, but periods/number contains " +
831 std::to_string(nPeriods) + ". This file should be manually inspected and corrected.";
832 throw InvalidLogPeriods(msg);
833 } else {
834 // periodLog should point to a copy of the period logs
835 periodLog = std::make_unique<const TimeSeriesProperty<int>>(*tempPeriodLog);
836 tempPeriodLog.reset();
837 }
838 return numberOfValidPeriods;
839}
840
855template <>
856std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs<EventWorkspaceCollection_sptr>(
857 const std::string &nexusfilename, EventWorkspaceCollection_sptr localWorkspace, API::Algorithm &alg,
858 bool returnpulsetimes, int &nPeriods, std::unique_ptr<const TimeSeriesProperty<int>> &periodLog) {
859 auto ws = localWorkspace->getSingleHeldWorkspace();
860 auto ret = runLoadNexusLogs<MatrixWorkspace_sptr>(nexusfilename, ws, alg, returnpulsetimes, nPeriods, periodLog);
861 return ret;
862}
863
880template <>
881std::shared_ptr<BankPulseTimes> LoadEventNexus::runLoadNexusLogs<EventWorkspaceCollection_sptr>(
882 const std::string &nexusfilename, EventWorkspaceCollection_sptr localWorkspace, API::Algorithm &alg,
883 bool returnpulsetimes, int &nPeriods, std::unique_ptr<const TimeSeriesProperty<int>> &periodLog,
884 const std::vector<std::string> &allow_list, const std::vector<std::string> &block_list) {
885 auto ws = localWorkspace->getSingleHeldWorkspace();
886 auto ret = runLoadNexusLogs<MatrixWorkspace_sptr>(nexusfilename, ws, alg, returnpulsetimes, nPeriods, periodLog,
887 allow_list, block_list);
888 return ret;
889}
890
891//-----------------------------------------------------------------------------
900void LoadEventNexus::loadEvents(API::Progress *const prog, const bool monitors) {
901 bool metaDataOnly = getProperty("MetaDataOnly");
902
903 // Get the time filters
904 setTimeFilters(monitors);
905
906 // Get the log filter if provided
907 std::vector<std::string> allow_list = getProperty("AllowList"); // if not empty, only these logs will be loaded
908 std::vector<std::string> block_list = getProperty("BlockList"); // if not empty, these logs won't be loaded
909
910 // The run_start will be loaded from the pulse times.
911 DateAndTime run_start(0, 0);
912 bool takeTimesFromEvents = false;
913 // Initialize the counter of bad TOFs
914 bad_tofs = 0;
915 int nPeriods = 1;
916 auto periodLog = std::make_unique<const TimeSeriesProperty<int>>("period_log");
917
918 bool loadAllLogs = getProperty("LoadAllLogs"); // load all logs, not just DAS logs.
919
920 if (loadlogs) {
921 if (!loadAllLogs) {
922 prog->doReport("Loading DAS logs");
923
924 if (allow_list.empty() && block_list.empty()) {
926 runLoadNexusLogs<EventWorkspaceCollection_sptr>(m_filename, m_ws, *this, true, nPeriods, periodLog);
927 } else {
928 m_allBanksPulseTimes = runLoadNexusLogs<EventWorkspaceCollection_sptr>(m_filename, m_ws, *this, true, nPeriods,
929 periodLog, allow_list, block_list);
930 }
931
932 try {
933 run_start = m_ws->getFirstPulseTime();
935 /*
936 This is added to (a) support legacy behaviour of continuing to take
937 times from the proto_charge log, but (b) allowing a fall back of
938 getting run start and end from actual pulse times within the
939 NXevent_data group. Note that the latter is better Nexus compliant.
940 */
941 takeTimesFromEvents = true;
942 }
943 } else {
944 prog->doReport("Loading all logs");
945 try {
946 // Open NeXus file
947 Nexus::File nxHandle(m_filename, NXaccess::READ);
948 LoadHelper::addNexusFieldsToWsRun(nxHandle, m_ws->mutableRun(), "", true);
949 } catch (Nexus::Exception const &e) {
950 g_log.debug() << "Failed to open nexus file \"" << m_filename << "\" in read mode: " << e.what() << "\n";
951 }
952 }
953 } else {
954 g_log.information() << "Skipping the loading of sample logs!\n"
955 << "Reading the start time directly from /" << m_top_entry_name << "/start_time\n";
956 // start_time is read and set
957 m_file->openAddress("/");
958 m_file->openGroup(m_top_entry_name, "NXentry");
959 std::string tmp;
960 m_file->readData("start_time", tmp);
961 m_file->closeGroup();
962 run_start = createFromSanitizedISO8601(tmp);
963 m_ws->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
964 }
965
966 // set more properties on the workspace
967 Nexus::NexusDescriptor const &descriptor = m_file->getFileDescriptor();
968 try {
969 // this is a static method that is why it is passing the
970 // file object and the file path
971
972 loadEntryMetadata<EventWorkspaceCollection_sptr>(m_filename, m_ws, m_top_entry_name);
973 } catch (std::runtime_error &e) {
974 // Missing metadata is not a fatal error. Log and go on with your life
975 g_log.error() << "Error loading metadata: " << e.what() << '\n';
976 }
977
978 m_ws->setNPeriods(static_cast<size_t>(nPeriods),
979 periodLog); // This is how many workspaces we are going to make.
980
981 // Make sure you have a non-NULL m_allBanksPulseTimes
982 if (m_allBanksPulseTimes == nullptr) {
983 std::vector<DateAndTime> temp;
984 m_allBanksPulseTimes = std::make_shared<BankPulseTimes>(temp);
985 }
986
987 if (!m_ws->getInstrument() || !m_instrument_loaded_correctly) {
988 // Load the instrument (if not loaded before)
989 prog->report("Loading instrument");
990 // Note that closing an re-opening the file is needed here for loading
991 // instruments directly from the nexus file containing the event data.
992 // This may not be needed in the future if both LoadEventNexus and
993 // LoadInstrument are made to use the same Nexus/HDF5 library
994 m_file->close();
996
998 throw std::runtime_error("Instrument was not initialized correctly! Loading cannot continue.");
999 // reopen file
1001 }
1002
1003 // top level file information
1004 m_file->openAddress("/");
1005 // Start with the base entry
1006 m_file->openGroup(m_top_entry_name, "NXentry");
1007
1008 // Now we want to go through all the bankN_event entries
1009 vector<string> bankNames;
1010 vector<std::size_t> bankNumEvents;
1011 std::string classType = monitors ? "NXmonitor" : "NXevent_data";
1012 bool oldNeXusFileNames(false);
1013 bool haveWeights = false;
1014 auto firstPulseT = DateAndTime::maximum();
1015 if (m_file->classTypeExists(classType)) {
1016 std::map<std::string, std::string> entries = m_file->getEntries();
1017 for (auto entry : entries) {
1018 if (entry.second != classType) {
1019 continue;
1020 }
1021
1022 // skip entries with junk data
1023 if (entry.first == "bank_error_events" || entry.first == "bank_unmapped_events")
1024 continue;
1025
1026 m_file->openGroup(entry.first, classType);
1027 // get the number of events
1028 const std::string prefix = "/" + m_top_entry_name + "/" + entry.first;
1029 bool hasTotalCounts = true;
1030 std::size_t num = numEvents(*m_file, hasTotalCounts, oldNeXusFileNames, prefix);
1031 bankNames.emplace_back(entry.first);
1032 bankNumEvents.emplace_back(num);
1033 if (takeTimesFromEvents && num > 0) {
1034 /* If we are here, we are loading logs, but have failed to establish
1035 * the run_start from the proton_charge log. We are going to get this
1036 * from our event_time_zero instead
1037 */
1038 auto localFirstLast = firstLastPulseTimes(*m_file, this->g_log);
1039 firstPulseT = std::min(firstPulseT, localFirstLast.first);
1040 }
1041 // Look for weights in simulated file
1042 const std::string absoluteEventWeightName = prefix + "/event_weight";
1043 haveWeights = m_file->hasAddress(absoluteEventWeightName);
1044 m_file->closeGroup();
1045 }
1046 }
1047 if (takeTimesFromEvents)
1048 run_start = firstPulseT;
1049
1051
1052 // Close the 'top entry' group (raw_data_1 for NexusProcessed, etc.)
1053 m_file->closeGroup();
1054
1055 // Delete the output workspace name if it existed
1056 std::string outName = getPropertyValue("OutputWorkspace");
1057 if (AnalysisDataService::Instance().doesExist(outName))
1058 AnalysisDataService::Instance().remove(outName);
1059
1060 // --------------------------- Time filtering
1061 // ------------------------------------
1062 double filter_time_start_sec, filter_time_stop_sec;
1063 filter_time_start_sec = getProperty("FilterByTimeStart");
1064 filter_time_stop_sec = getProperty("FilterByTimeStop");
1065
1066 // Default to ALL pulse times
1067 filter_time_start = Types::Core::DateAndTime::minimum();
1068 filter_time_stop = Types::Core::DateAndTime::maximum();
1069
1070 if (m_allBanksPulseTimes->numberOfPulses() > 0) {
1071 // If not specified, use the limits of doubles. Otherwise, convert from
1072 // seconds to absolute PulseTime
1073 if (filter_time_start_sec != EMPTY_DBL()) {
1074 filter_time_start = run_start + filter_time_start_sec;
1075 m_is_time_filtered = true;
1076 }
1077
1078 if (filter_time_stop_sec != EMPTY_DBL()) {
1079 filter_time_stop = run_start + filter_time_stop_sec;
1080 m_is_time_filtered = true;
1081 }
1082
1083 // Silly values?
1085 std::string msg = "Your ";
1086 if (monitors)
1087 msg += "monitor ";
1088 msg += "filter for time's Stop value is smaller than the Start value.";
1089 throw std::invalid_argument(msg);
1090 }
1091 }
1092
1093 // setup filter bad pulses
1094 filter_bad_pulses = !isDefault(PropertyNames::BAD_PULSES_CUTOFF);
1095
1096 if (filter_bad_pulses) {
1097 double min_pcharge, max_pcharge;
1098 std::tie(min_pcharge, max_pcharge, std::ignore) =
1099 m_ws->run().getBadPulseRange(LOG_CHARGE_NAME, getProperty(PropertyNames::BAD_PULSES_CUTOFF));
1100
1101 const auto *pcharge_log =
1102 dynamic_cast<Kernel::TimeSeriesProperty<double> *>(m_ws->run().getLogData(LOG_CHARGE_NAME));
1103 bad_pulses_timeroi = std::make_shared<TimeROI>(
1104 pcharge_log->makeFilterByValue(min_pcharge, max_pcharge, false, TimeInterval(0, 1), 0., true));
1105 }
1106
1107 if (metaDataOnly) {
1108 // Now, create a default X-vector for histogramming, with just 2 bins.
1109 auto axis = HistogramData::BinEdges{1, static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1 - 1};
1110 // Set the binning axis using this.
1111 m_ws->setAllX(axis);
1112
1113 createSpectraMapping(m_filename, monitors, std::vector<std::string>());
1114 return;
1115 }
1116
1117 // --------- Loading only one bank ? ----------------------------------
1118 std::vector<std::string> someBanks = getProperty("BankName");
1119 const bool SingleBankPixelsOnly = getProperty("SingleBankPixelsOnly");
1120 if ((!someBanks.empty()) && (!monitors)) {
1121 std::vector<std::string> eventedBanks;
1122 eventedBanks.reserve(someBanks.size());
1123 std::transform(someBanks.cbegin(), someBanks.cend(), std::back_inserter(eventedBanks),
1124 [](const auto &bank) { return bank + "_events"; });
1125
1126 // check that all of the requested banks are in the file
1127 const auto invalidBank =
1128 std::find_if(eventedBanks.cbegin(), eventedBanks.cend(), [&bankNames](const auto &someBank) {
1129 return std::none_of(bankNames.cbegin(), bankNames.cend(),
1130 [&someBank](const auto &name) { return name == someBank; });
1131 });
1132 if (invalidBank != eventedBanks.cend()) {
1133 throw std::invalid_argument("No entry named '" + *invalidBank + "' was found in the .NXS file.");
1134 }
1135
1136 // change the number of banks to load
1137 bankNames.assign(eventedBanks.cbegin(), eventedBanks.cend());
1138
1139 // TODO this equally weights the banks
1140 bankNumEvents.assign(someBanks.size(), 1);
1141
1142 if (!SingleBankPixelsOnly)
1143 someBanks.clear(); // Marker to load all pixels
1144 }
1145
1146 prog->report("Initializing all pixels");
1147
1148 // Remove unused banks if parameter is set
1149 if (m_ws->getInstrument()->hasParameter("remove-unused-banks")) {
1150 std::vector<double> instrumentUnused = m_ws->getInstrument()->getNumberParameter("remove-unused-banks", true);
1151 if (!instrumentUnused.empty()) {
1152 const auto unused = static_cast<int>(instrumentUnused.front());
1153 if (unused == 1)
1154 deleteBanks(m_ws, bankNames);
1155 }
1156 }
1157 //----------------- Pad Empty Pixels -------------------------------
1158 createSpectraMapping(m_filename, monitors, someBanks);
1159
1160 // Set all (empty) event lists as sorted by pulse time. That way, calling
1161 // SortEvents will not try to sort these empty lists.
1162 for (size_t i = 0; i < m_ws->getNumberHistograms(); i++)
1163 m_ws->getSpectrum(i).setSortOrder(DataObjects::PULSETIME_SORT);
1164
1165 // Count the limits to time of flight
1166 shortest_tof = static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1;
1167 longest_tof = 0.;
1168
1169 bool precount = getProperty("Precount");
1170 int chunk = getProperty("ChunkNumber");
1171 int totalChunks = getProperty("TotalChunks");
1172 const auto startTime = std::chrono::high_resolution_clock::now();
1173 DefaultEventLoader::load(this, *m_ws, haveWeights, event_id_is_spec, bankNames, periodLog->valuesAsVector(),
1174 classType, bankNumEvents, oldNeXusFileNames, precount, chunk, totalChunks);
1175 addTimer("loadEvents", startTime, std::chrono::high_resolution_clock::now());
1176
1177 // Info reporting
1178 const std::size_t eventsLoaded = m_ws->getNumberEvents();
1179 g_log.information() << "Read " << eventsLoaded << " events"
1180 << ". Shortest TOF: " << shortest_tof << " microsec; longest TOF: " << longest_tof
1181 << " microsec.\n";
1182
1183 if (shortest_tof < 0)
1184 g_log.warning() << "The shortest TOF was negative! At least 1 event has an "
1185 "invalid time-of-flight.\n";
1186 if (bad_tofs > 0)
1187 g_log.warning() << "Found " << bad_tofs
1188 << " events with TOF > 2e8. This "
1189 "may indicate errors in the raw "
1190 "TOF data.\n";
1191
1192 // Use T0 offset from TOPAZ Parameter file if it exists
1193 if (m_ws->getInstrument()->hasParameter("T0")) {
1194 std::vector<double> instrumentT0 = m_ws->getInstrument()->getNumberParameter("T0", true);
1195 if (!instrumentT0.empty()) {
1196 const double mT0 = instrumentT0.front();
1197 if (mT0 != 0.0) {
1198 auto numHistograms = static_cast<int64_t>(m_ws->getNumberHistograms());
1200 for (int64_t i = 0; i < numHistograms; ++i) {
1202 // Do the offsetting
1203 m_ws->getSpectrum(i).addTof(mT0);
1205 }
1207 // set T0 in the run parameters
1208 API::Run &run = m_ws->mutableRun();
1209 run.addProperty<double>("T0", mT0, true);
1210 }
1211 }
1212 }
1213 // Now, create a default X-vector for histogramming, with just 2 bins.
1214 if (eventsLoaded > 0) {
1215 int nBins = getProperty("NumberOfBins");
1216 auto binEdgesVec = std::vector<double>(nBins + 1);
1217 binEdgesVec[0] = shortest_tof; // left edge is inclusive
1218 binEdgesVec[nBins] = longest_tof + 1; // right edge is exclusive
1219 double binStep = (binEdgesVec[nBins] - binEdgesVec[0]) / nBins;
1220 for (int binIndex = 1; binIndex < nBins; binIndex++) {
1221 binEdgesVec[binIndex] = binEdgesVec[0] + (binStep * binIndex);
1222 }
1223 m_ws->setAllX(HistogramData::BinEdges{binEdgesVec});
1224 } else
1225 m_ws->setAllX(HistogramData::BinEdges{0.0, 1.0});
1226
1227 // if there is time_of_flight load it
1228 if (doPerformISISEventShift(*m_file, m_top_entry_name)) {
1229 adjustTimeOfFlightISISLegacy(*m_file, m_ws, m_top_entry_name, classType);
1230 }
1231
1232 if (m_is_time_filtered) {
1233 // events were filtered during read
1234 // filter the logs the same way FilterByTime does
1235 TimeROI timeroi(filter_time_start, filter_time_stop);
1236 if (filter_bad_pulses)
1237 timeroi.update_intersection(*bad_pulses_timeroi);
1238 m_ws->mutableRun().setTimeROI(timeroi);
1239 m_ws->mutableRun().removeDataOutsideTimeROI();
1240 } else if (filter_bad_pulses) {
1241 m_ws->mutableRun().setTimeROI(*bad_pulses_timeroi);
1242 m_ws->mutableRun().removeDataOutsideTimeROI();
1243 }
1244}
1245
1246//-----------------------------------------------------------------------------
1257template <>
1258bool LoadEventNexus::runLoadIDFFromNexus<EventWorkspaceCollection_sptr>(const std::string &nexusfilename,
1259 EventWorkspaceCollection_sptr localWorkspace,
1260 const std::string &top_entry_name,
1261 Algorithm *alg) {
1262 auto ws = localWorkspace->getSingleHeldWorkspace();
1263 auto hasLoaded = runLoadIDFFromNexus<MatrixWorkspace_sptr>(nexusfilename, ws, top_entry_name, alg);
1264 localWorkspace->setInstrument(ws->getInstrument());
1265 return hasLoaded;
1266}
1267
1273 std::string instrumentName;
1274 try {
1275 hFile.openGroup("isis_vms_compat", "IXvms");
1276 } catch (std::runtime_error &) {
1277 return instrumentName;
1278 }
1279 try {
1280 hFile.openData("NAME");
1281 } catch (std::runtime_error &) {
1282 hFile.closeGroup();
1283 return instrumentName;
1284 }
1285
1286 instrumentName = hFile.getStrData();
1287 hFile.closeData();
1288 hFile.closeGroup();
1289
1290 return instrumentName;
1291}
1292
1293//-----------------------------------------------------------------------------
1306template <>
1307bool LoadEventNexus::runLoadInstrument<EventWorkspaceCollection_sptr>(const std::string &nexusfilename,
1308 EventWorkspaceCollection_sptr localWorkspace,
1309 const std::string &top_entry_name, Algorithm *alg,
1310 const Nexus::NexusDescriptor *descriptor) {
1311 auto ws = localWorkspace->getSingleHeldWorkspace();
1312 auto hasLoaded = runLoadInstrument<MatrixWorkspace_sptr>(nexusfilename, ws, top_entry_name, alg, descriptor);
1313 localWorkspace->setInstrument(ws->getInstrument());
1314 return hasLoaded;
1315}
1316
1317//-----------------------------------------------------------------------------
1324 const std::vector<std::string> &bankNames) {
1325 Instrument_sptr inst = std::const_pointer_cast<Instrument>(workspace->getInstrument()->baseInstrument());
1326 // Build a list of Rectangular Detectors
1327 std::vector<std::shared_ptr<RectangularDetector>> detList;
1328 for (int i = 0; i < inst->nelements(); i++) {
1329 std::shared_ptr<RectangularDetector> det;
1330 std::shared_ptr<ICompAssembly> assem;
1331 std::shared_ptr<ICompAssembly> assem2;
1332
1333 det = std::dynamic_pointer_cast<RectangularDetector>((*inst)[i]);
1334 if (det) {
1335 detList.emplace_back(det);
1336 } else {
1337 // Also, look in the first sub-level for RectangularDetectors (e.g.
1338 // PG3). We are not doing a full recursive search since that will be
1339 // very long for lots of pixels.
1340 assem = std::dynamic_pointer_cast<ICompAssembly>((*inst)[i]);
1341 if (assem) {
1342 for (int j = 0; j < assem->nelements(); j++) {
1343 det = std::dynamic_pointer_cast<RectangularDetector>((*assem)[j]);
1344 if (det) {
1345 detList.emplace_back(det);
1346
1347 } else {
1348 // Also, look in the second sub-level for RectangularDetectors
1349 // (e.g. PG3). We are not doing a full recursive search since that
1350 // will be very long for lots of pixels.
1351 assem2 = std::dynamic_pointer_cast<ICompAssembly>((*assem)[j]);
1352 if (assem2) {
1353 for (int k = 0; k < assem2->nelements(); k++) {
1354 det = std::dynamic_pointer_cast<RectangularDetector>((*assem2)[k]);
1355 if (det) {
1356 detList.emplace_back(det);
1357 }
1358 }
1359 }
1360 }
1361 }
1362 }
1363 }
1364 }
1365 if (detList.empty())
1366 return;
1367 for (auto &det : detList) {
1368 bool keep = false;
1369 std::string det_name = det->getName();
1370 for (const auto &bankName : bankNames) {
1371 size_t pos = bankName.find("_events");
1372 if (det_name == bankName.substr(0, pos))
1373 keep = true;
1374 if (keep)
1375 break;
1376 }
1377 if (!keep) {
1378 std::shared_ptr<const IComponent> parent = inst->getComponentByName(det_name);
1379 std::vector<Geometry::IComponent_const_sptr> children;
1380 std::shared_ptr<const Geometry::ICompAssembly> asmb =
1381 std::dynamic_pointer_cast<const Geometry::ICompAssembly>(parent);
1382 asmb->getChildren(children, false);
1383 for (auto &col : children) {
1384 std::shared_ptr<const Geometry::ICompAssembly> asmb2 =
1385 std::dynamic_pointer_cast<const Geometry::ICompAssembly>(col);
1386 std::vector<Geometry::IComponent_const_sptr> grandchildren;
1387 asmb2->getChildren(grandchildren, false);
1388
1389 for (auto &row : grandchildren) {
1390 auto *d = dynamic_cast<Detector *>(const_cast<IComponent *>(row.get()));
1391 if (d)
1392 inst->removeDetector(d);
1393 }
1394 }
1395 auto *comp = dynamic_cast<IComponent *>(det.get());
1396 inst->remove(comp);
1397 }
1398 }
1399}
1400//-----------------------------------------------------------------------------
1409void LoadEventNexus::createSpectraMapping(const std::string &nxsfile, const bool monitorsOnly,
1410 const std::vector<std::string> &bankNames) {
1411 LoadEventNexusIndexSetup indexSetup(m_ws->getSingleHeldWorkspace(), getProperty("SpectrumMin"),
1412 getProperty("SpectrumMax"), getProperty("SpectrumList"));
1413 if (!monitorsOnly && !bankNames.empty()) {
1414 if (!isDefault("SpectrumMin") || !isDefault("SpectrumMax") || !isDefault("SpectrumList"))
1415 g_log.warning() << "Spectrum min/max/list selection ignored when "
1416 "`SingleBankPixelsOnly` is enabled\n";
1417 m_ws->setIndexInfo(indexSetup.makeIndexInfo(bankNames));
1418 g_log.debug() << "Populated spectra map for select banks\n";
1419 } else if (auto mapping = loadISISVMSSpectraMapping(m_top_entry_name)) {
1420 if (monitorsOnly) {
1421 g_log.debug() << "Loading only monitor spectra from " << nxsfile << "\n";
1422 } else {
1423 g_log.debug() << "Loading only detector spectra from " << nxsfile << "\n";
1424 }
1425 m_ws->setIndexInfo(indexSetup.makeIndexInfo(*mapping, monitorsOnly));
1426 } else {
1427 g_log.debug() << "No custom spectra mapping found, continuing with default "
1428 "1:1 mapping of spectrum:detectorID\n";
1429 m_ws->setIndexInfo(indexSetup.makeIndexInfo());
1430 g_log.debug() << "Populated 1:1 spectra map for the whole instrument \n";
1431 }
1432 std::tie(m_specMin, m_specMax) = indexSetup.eventIDLimits();
1433}
1434
1435//-----------------------------------------------------------------------------
1442 std::string mon_wsname = this->getProperty("OutputWorkspace");
1443 mon_wsname.append("_monitors");
1444
1445 auto loadMonitors = createChildAlgorithm("LoadNexusMonitors");
1446 g_log.information("Loading monitors from NeXus file...");
1447 loadMonitors->setPropertyValue("Filename", m_filename);
1448 g_log.information() << "New workspace name for monitors: " << mon_wsname << '\n';
1449 loadMonitors->setPropertyValue("OutputWorkspace", mon_wsname);
1450 loadMonitors->setPropertyValue("LoadOnly", this->getProperty("MonitorsLoadOnly"));
1451 loadMonitors->setPropertyValue("NXentryName", this->getProperty("NXentryName"));
1452 loadMonitors->execute();
1453 Workspace_sptr monsOut = loadMonitors->getProperty("OutputWorkspace");
1454 // create the output workspace property on the fly
1455 this->declareProperty(
1456 std::make_unique<WorkspaceProperty<Workspace>>("MonitorWorkspace", mon_wsname, Direction::Output),
1457 "Monitors from the Event NeXus file");
1458 this->setProperty("MonitorWorkspace", monsOut);
1459
1460 // The output will either be a group workspace or a matrix workspace
1461 MatrixWorkspace_sptr mons = std::dynamic_pointer_cast<MatrixWorkspace>(monsOut);
1462 if (mons) {
1463 // Set the internal monitor workspace pointer as well
1464 m_ws->setMonitorWorkspace(mons);
1465
1466 filterDuringPause(mons);
1467 } else {
1468 WorkspaceGroup_sptr monsGrp = std::dynamic_pointer_cast<WorkspaceGroup>(monsOut);
1469 if (monsGrp) {
1470 // declare a property for each member of the group
1471 for (int i = 0; i < monsGrp->getNumberOfEntries(); i++) {
1472 std::stringstream ssWsName;
1473 ssWsName << mon_wsname << "_" << i + 1;
1474 std::stringstream ssPropName;
1475 ssPropName << "MonitorWorkspace"
1476 << "_" << i + 1;
1477 this->declareProperty(
1478 std::make_unique<WorkspaceProperty<MatrixWorkspace>>(ssPropName.str(), ssWsName.str(), Direction::Output),
1479 "Monitors from the Event NeXus file");
1480 this->setProperty(ssPropName.str(), monsGrp->getItem(i));
1481 }
1482 }
1483 }
1484}
1485
1486//
1496std::unique_ptr<std::pair<std::vector<int32_t>, std::vector<int32_t>>>
1497LoadEventNexus::loadISISVMSSpectraMapping(const std::string &entry_name) {
1498 const std::string vms_str = "/isis_vms_compat";
1499 try {
1500 g_log.debug() << "Attempting to load custom spectra mapping from '" << entry_name << vms_str << "'.\n";
1501 m_file->openAddress("/" + entry_name + vms_str);
1502 } catch (Nexus::Exception const &) {
1503 return nullptr; // Doesn't exist
1504 }
1505
1506 // The ISIS spectrum mapping is defined by 2 arrays in isis_vms_compat
1507 // block:
1508 // UDET - An array of detector IDs
1509 // SPEC - An array of spectrum numbers
1510 // There sizes must match. Hardware allows more than one detector ID to be
1511 // mapped to a single spectrum
1512 // and this is encoded in the SPEC/UDET arrays by repeating the spectrum
1513 // number in the array
1514 // for each mapped detector, e.g.
1515 //
1516 // 1 1001
1517 // 1 1002
1518 // 2 2001
1519 // 3 3001
1520 //
1521 // defines 3 spectra, where the first spectrum contains 2 detectors
1522
1523 // UDET
1524 m_file->openData("UDET");
1525 std::vector<int32_t> udet;
1526 m_file->getData(udet);
1527 m_file->closeData();
1528 // SPEC
1529 m_file->openData("SPEC");
1530 std::vector<int32_t> spec;
1531 m_file->getData(spec);
1532 m_file->closeData();
1533 // Go up/back. this assumes one level for entry name and a second level
1534 // for /isis_vms_compat, typically: /raw_data_1/isis_vms_compat
1535 m_file->closeGroup();
1536 m_file->closeGroup();
1537
1538 // The spec array will contain a spectrum number for each udet but the
1539 // spectrum number
1540 // may be the same for more that one detector
1541 const size_t ndets(udet.size());
1542 if (ndets != spec.size()) {
1543 std::ostringstream os;
1544 os << "UDET/SPEC list size mismatch. UDET=" << udet.size() << ", SPEC=" << spec.size() << "\n";
1545 throw std::runtime_error(os.str());
1546 }
1547 // If mapping loaded the event ID is the spectrum number and not det ID
1548 this->event_id_is_spec = true;
1549 return std::make_unique<std::pair<std::vector<int32_t>, std::vector<int32_t>>>(std::move(spec), std::move(udet));
1550}
1551
1557void LoadEventNexus::setTimeFilters(const bool monitors) {
1558 // Get the limits to the filter
1559 std::string prefix("Filter");
1560 if (monitors)
1561 prefix += "Mon";
1562
1563 filter_tof_min = getProperty(prefix + "ByTofMin");
1564 filter_tof_max = getProperty(prefix + "ByTofMax");
1565 if ((filter_tof_min == EMPTY_DBL()) && (filter_tof_max == EMPTY_DBL())) {
1566 // Nothing specified. Include everything
1567 filter_tof_range = false;
1568 } else if ((filter_tof_min != EMPTY_DBL()) && (filter_tof_max != EMPTY_DBL())) {
1569 // Both specified. Keep these values
1570 filter_tof_range = true;
1571 } else {
1572 std::string msg("You must specify both min & max or neither TOF filters");
1573 if (monitors)
1574 msg = " for the monitors.";
1575 throw std::invalid_argument(msg);
1576 }
1577}
1578
1579//-----------------------------------------------------------------------------
1580
1596 try {
1597 file.openGroup("isis_vms_compat", "IXvms");
1598 } catch (Nexus::Exception const &) {
1599 // No problem, it just means that this entry does not exist
1600 return;
1601 }
1602
1603 // read the data
1604 try {
1605 std::vector<int32_t> spb;
1606 std::vector<float> rspb;
1607 file.readData("SPB", spb);
1608 file.readData("RSPB", rspb);
1609
1610 WS.setGeometryFlag(spb[2]); // the flag is in the third value
1611 WS.setThickness(rspb[3]);
1612 WS.setHeight(rspb[4]);
1613 WS.setWidth(rspb[5]);
1614 } catch (Nexus::Exception const &ex) {
1615 // it means that the data was not as expected, report the problem
1616 std::stringstream s;
1617 s << "Wrong definition found in isis_vms_compat :> " << ex.what();
1618 file.closeGroup();
1619 throw std::runtime_error(s.str());
1620 }
1621
1622 file.closeGroup();
1623}
1624
1631void LoadEventNexus::safeOpenFile(const std::string &fname) {
1632 try {
1633 m_file = std::make_unique<Nexus::File>(m_filename, NXaccess::READ);
1634 } catch (std::runtime_error &e) {
1635 throw std::runtime_error("Severe failure when trying to open NeXus file: " + std::string(e.what()));
1636 }
1637 // make sure that by no means we could dereference NULL later on
1638 if (!m_file) {
1639 throw std::runtime_error("An unexpected failure happened, unable to "
1640 "initialize file object when trying to open NeXus "
1641 "file: " +
1642 fname);
1643 }
1644}
1645} // namespace Mantid::DataHandling
gsl_vector * tmp
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_LAZY_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_LAZY_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:76
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
bool isDefault(const std::string &name) const
Kernel::Logger & getLogger() const
Returns a reference to the logger.
@ 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.
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:35
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
bool m_is_time_filtered
if wall-clock filtering was requested
static int checkForCorruptedPeriods(std::unique_ptr< Kernel::TimeSeriesProperty< int > > tempPeriodLog, std::unique_ptr< const Kernel::TimeSeriesProperty< int > > &periodLog, const int &nPeriods, const std::string &nexusfilename, std::string &status)
Check for corrupted period logs If data is historical (1 periods, period is labelled 0) then change p...
std::shared_ptr< Mantid::Kernel::TimeROI > bad_pulses_timeroi
void createSpectraMapping(const std::string &nxsfile, const bool monitorsOnly, const std::vector< std::string > &bankNames=std::vector< std::string >())
Create the required spectra mapping.
static void loadSampleDataISIScompatibility(Nexus::File &file, EventWorkspaceCollection &WS)
Load information of the sample.
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
bool loadlogs
Do we load the sample logs?
bool event_id_is_spec
True if the event_id is spectrum no not pixel ID.
size_t discarded_events
A count of events discarded because they came from a pixel that's not in the IDF.
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.
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
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 exec() override
Execution code.
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.
static bool loadInstrument(const std::string &nexusfilename, T localWorkspace, const std::string &top_entry_name, Algorithm *alg, const Nexus::NexusDescriptor *descriptor=nullptr)
Load instrument from Nexus file if possible, else from IDF spacified by Nexus file.
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Return the confidence with with this algorithm can load the file.
void runLoadMonitors()
Load the Monitors from the NeXus file into a 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.
bool filter_tof_range
Tof range is being filtered.
static std::string readInstrumentFromISIS_VMSCompat(Nexus::File &hFile)
method used to return instrument name for some old ISIS files where it is not written properly within...
std::unique_ptr< Nexus::File > m_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.
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.
base class for Geometric IComponent
Definition IComponent.h:53
Support for a property that holds an array of values.
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 const > settings)
Add a PropertySettings instance to the chain of settings for a given property.
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:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
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.
Represents a time interval.
Definition DateAndTime.h:25
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>
Class that provides for a standard Nexus exception.
bool isEntry(std::string const &entryName, std::string const &groupClass) const
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
bool classTypeExists(std::string const &classType) const
Query if a given type exists somewhere in the file.
static unsigned short constexpr UINT64
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(Nexus::File &filehandle, API::Run &runDetails, const std::string &entryName="", bool useFullAddress=false)
Add properties from a nexus file to the workspace run.
std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix)
Get the number of events in the currently opened group.
std::shared_ptr< EventWorkspaceCollection > EventWorkspaceCollection_sptr
std::pair< DateAndTime, DateAndTime > firstLastPulseTimes(Nexus::File &file, Kernel::Logger &logger)
void adjustTimeOfFlightISISLegacy(Nexus::File &file, T localWorkspace, const std::string &entry_name, const std::string &classType)
ISIS specific method for dealing with wide events.
MANTID_DATAHANDLING_DLL bool doPerformISISEventShift(Nexus::File &file, std::string &topEntryName)
std::shared_ptr< 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:1430
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.
const std::string BINMODE("BinningMode")
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
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