Mantid
Loading...
Searching...
No Matches
LoadNexusMonitors2.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"
12#include "MantidAPI/Sample.h"
19#include "MantidKernel/Unit.h"
22
23#include <boost/lexical_cast.hpp>
24
25#include <algorithm>
26#include <cmath>
27#include <filesystem>
28#include <map>
29#include <vector>
30
37using Mantid::HistogramData::BinEdges;
38using Mantid::HistogramData::Counts;
39using Mantid::HistogramData::Histogram;
42
43namespace Mantid::DataHandling {
44
45// Register the algorithm into the AlgorithmFactory
47
48namespace {
49void loadSampleDataISIScompatibilityInfo(Nexus::File &file, Mantid::API::MatrixWorkspace_sptr const &WS) {
50 try {
51 file.openGroup("isis_vms_compat", "IXvms");
52 } catch (Nexus::Exception const &) {
53 // No problem, it just means that this entry does not exist
54 return;
55 }
56
57 // read the data
58 try {
59 std::vector<int32_t> spb;
60 std::vector<float> rspb;
61 file.readData("SPB", spb);
62 file.readData("RSPB", rspb);
63
64 WS->mutableSample().setGeometryFlag(spb[2]); // the flag is in the third value
65 WS->mutableSample().setThickness(rspb[3]);
66 WS->mutableSample().setHeight(rspb[4]);
67 WS->mutableSample().setWidth(rspb[5]);
68 } catch (Nexus::Exception const &ex) {
69 // it means that the data was not as expected, report the problem
70 std::stringstream s;
71 s << "Wrong definition found in isis_vms_compat :> " << ex.what();
72 file.closeGroup();
73 throw std::runtime_error(s.str());
74 }
75
76 file.closeGroup();
77}
78
79const std::string LOAD_EVENTS("Events");
80const std::string LOAD_HISTO("Histogram");
81
82namespace PropertyNames {
83const std::string LOGS_ALLOW("AllowList");
84const std::string LOGS_BLOCK("BlockList");
85} // namespace PropertyNames
86
87// collection of static methods to inspect monitors to determine type
88bool keyExists(std::string const &key, std::map<std::string, std::string> const &entries) {
89 return entries.find(key) != entries.cend();
90}
91
92// returns true if all of the entries necessary for a histogram exist monitor in
93// the currently open group
94bool isHistoMonitor(Nexus::File const &monitorFileHandle) {
95 const auto fields = monitorFileHandle.getEntries();
96 return keyExists("data", fields) && keyExists("time_of_flight", fields);
97}
98
99std::size_t sizeOfUnopenedSDS(Nexus::File &file, const std::string &fieldName) {
100 file.openData(fieldName);
101 auto size = static_cast<std::size_t>(file.getInfo().dims[0]);
102 file.closeData();
103 return size;
104}
105
106bool eventIdNotEmptyIfExists(Nexus::File &file, std::map<std::string, std::string> const &fields) {
107 if (keyExists("event_id", fields))
108 return sizeOfUnopenedSDS(file, "event_id") > 1;
109 else
110 return true;
111}
112
113// returns true if all of the entries necessary for an event monitor exist in
114// the currently open group
115bool isEventMonitor(Nexus::File &file) {
116 const auto fields = file.getEntries();
117 return keyExists("event_index", fields) && keyExists("event_time_offset", fields) &&
118 keyExists("event_time_zero", fields) && eventIdNotEmptyIfExists(file, fields);
119}
120} // anonymous namespace
121
122//------------------------------------------------------------------------------
125 const std::vector<std::string> exts{".nxs.h5", ".nxs"};
126 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load, exts),
127 "The name (including its full or relative path) of the NeXus file to "
128 "attempt to load. The file extension must either be .nxs, .NXS, or .nxs.h5");
129
131 std::make_unique<API::WorkspaceProperty<API::Workspace>>("OutputWorkspace", "", Kernel::Direction::Output),
132 "The name of the output workspace in which to load the NeXus monitors.");
133
135 "Optional: Name of the NXentry to load if it's not the default.");
136
137 std::vector<std::string> options{"", LOAD_EVENTS, LOAD_HISTO};
138 declareProperty("LoadOnly", "", std::make_shared<Kernel::StringListValidator>(options),
139 "If multiple repesentations exist, which one to load. "
140 "Default is to load the one that is present, and Histogram "
141 "if both are present.");
142
143 declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>(
144 PropertyNames::LOGS_ALLOW, std::vector<std::string>(), Direction::Input),
145 "If specified, only these logs will be loaded from the file (each "
146 "separated by a comma).");
147 declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>(
148 PropertyNames::LOGS_BLOCK, std::vector<std::string>(), Direction::Input),
149 "If specified, these logs will NOT be loaded from the file (each "
150 "separated by a comma).");
151}
152
153//------------------------------------------------------------------------------
159 // Retrieve the filename from the properties
160 m_filename = this->getPropertyValue("Filename");
161
162 API::Progress prog1(this, 0.0, 0.2, 2);
163
165 throw std::runtime_error("Failed to recognize this file as a NeXus file, cannot continue.");
166 }
167
168 m_top_entry_name = this->getPropertyValue("NXentryName");
169 // must be done here before the Nexus::File, HDF5 files can't have 2
170 // simultaneous handlers
172
173 // top level file information
174 Nexus::File file(m_filename);
175
176 // open the correct entry
177 using string_map_t = std::map<std::string, std::string>;
178 string_map_t entries = file.getEntries();
179
180 if (m_top_entry_name.empty()) {
181 const auto it = std::find_if(entries.cbegin(), entries.cend(), [](const auto &entry) {
182 return ((entry.first == "entry" || entry.first == "raw_data_1") && entry.second == "NXentry");
183 });
184 if (it != entries.cend()) {
185 file.openGroup(it->first, it->second);
186 m_top_entry_name = it->first;
187 }
188 } else {
189 if (!keyExists(m_top_entry_name, entries)) {
190 throw std::invalid_argument(m_filename + " does not contain an entry named " + m_top_entry_name);
191 }
192 file.openGroup(m_top_entry_name, "NXentry"); // Open as will need to be
193 // open for subsequent operations
194 }
195 prog1.report();
196
197 size_t numPeriods = 0;
198 m_monitor_count = getMonitorInfo(file, numPeriods);
199 // Fix the detector numbers if the defaults above are not correct
200 // fixUDets(detector_numbers, file, spectra_numbers, m_monitor_count);
201 // a temporary place to put the spectra/detector numbers
202 // this gets the ids from the "isis_vms_compat" group
203 fixUDets(file);
204
205 if (numPeriods > 0) {
208 }
209
210 // Nothing to do
211 if (0 == m_monitor_count) {
212 // previous version just used to return, but that
213 // threw an error when the OutputWorkspace property was not set.
214 // and the error message was confusing.
215 // This has changed to throw a specific error.
216 throw std::invalid_argument(m_filename + " does not contain any monitors");
217 }
218
219 // only used if using event monitors
220 // EventWorkspace_sptr eventWS;
221 // Create the output workspace
222 std::vector<bool> loadMonitorFlags;
223 bool useEventMon = createOutputWorkspace(loadMonitorFlags);
224
225 API::Progress prog3(this, 0.6, 1.0, m_monitor_count);
226
227 // cache address to entry for later
228 const std::string entryAddress = file.getAddress();
229
230 // TODO-NEXT: load event monitor if it is required to do so
231 // load histogram monitor if it is required to do so
232 // Require a tuple: monitorNames[i], loadAsEvent[i], loadAsHistogram[i]
233 for (std::size_t ws_index = 0; ws_index < m_monitor_count; ++ws_index) {
234 // already know spectrum and detector numbers
235 g_log.debug() << "monIndex = " << m_monitorInfo[ws_index].detNum << '\n';
236 g_log.debug() << "spectrumNo = " << m_monitorInfo[ws_index].specNum << '\n';
237 m_workspace->getSpectrum(ws_index).setSpectrumNo(m_monitorInfo[ws_index].specNum);
238 m_workspace->getSpectrum(ws_index).setDetectorID(m_monitorInfo[ws_index].detNum);
239
240 // Don't actually read all of the monitors
241 g_log.information() << "Loading " << m_monitorInfo[ws_index].name;
242 if (loadMonitorFlags[ws_index]) {
243 g_log.information() << "\n";
244 file.openGroup(m_monitorInfo[ws_index].name, "NXmonitor");
245 if (useEventMon) {
246 // load as an event monitor
247 readEventMonitorEntry(file, ws_index);
248 } else {
249 // load as a histogram monitor
250 readHistoMonitorEntry(file, ws_index, numPeriods);
251 }
252 file.closeGroup(); // NXmonitor
253 } else {
254 g_log.information() << " is skipped.\n";
255 }
256
257 prog3.report();
258 }
259
260 if (useEventMon) // set the x-range to be the range for min/max events
261 {
262 EventWorkspace_sptr eventWS = std::dynamic_pointer_cast<EventWorkspace>(m_workspace);
263 double xmin, xmax;
264 eventWS->getEventXMinMax(xmin, xmax);
265
266 if (xmin > xmax) {
267 xmin = 0;
268 xmax = 1;
269 if (eventWS->getNumberEvents() == 0) {
270 g_log.warning("No events loading. Resetting time-of-flight range 0 to 1");
271 } else {
272 g_log.warning("time-of-flight range of events are unusual. Resetting time-of-flight range 0 to 1");
273 }
274 } else {
275 // move out by one just like LoadEventNexus
276 xmin = xmin - 1;
277 xmax = xmax + 1;
278 }
279
280 auto axis = HistogramData::BinEdges{xmin, xmax};
281 eventWS->setAllX(axis); // Set the binning axis using this.
282
283 // a certain generation of ISIS files modify the time-of-flight
284 const std::string currentAddress = file.getAddress();
285 adjustTimeOfFlightISISLegacy(file, eventWS, m_top_entry_name, "NXmonitor");
286 file.openAddress(currentAddress); // reset to where it was earlier
287 }
288
289 // Check for and ISIS compat block to get the detector IDs for the loaded
290 // spectrum numbers
291 // @todo: Find out if there is a better (i.e. more generic) way to do this
292 try {
293 g_log.debug() << "Load Sample data isis\n";
294 loadSampleDataISIScompatibilityInfo(file, m_workspace);
295 } catch (Nexus::Exception const &) {
296 }
297
298 // Need to get the instrument name from the file
299 std::string instrumentName;
300 file.openAddress(entryAddress); // reset address in case of unusual behavior
301 file.openGroup("instrument", "NXinstrument");
302 try {
303 file.openData("name");
304 instrumentName = file.getStrData();
305 // Now let's close the file as we don't need it anymore to load the
306 // instrument.
307 file.closeData();
308 file.closeGroup(); // Close the NXentry
309 file.close();
310
311 } catch (std::runtime_error &) // no correct instrument definition (old ISIS
312 // file, fall back to isis_vms_compat)
313 {
314 file.closeGroup(); // Close the instrument NXentry
316 file.close();
317 }
318
319 g_log.debug() << "Instrument name read from NeXus file is " << instrumentName << '\n';
320
321 m_workspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
322 m_workspace->setYUnit("Counts");
323
324 // Load the logs
326
327 // Old SNS files don't have this
328 try {
329 // The run_start will be loaded from the pulse times.
330 Types::Core::DateAndTime run_start(0, 0);
331 run_start = m_workspace->getFirstPulseTime();
332 m_workspace->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
333 } catch (...) {
334 // Old files have the start_time defined, so all SHOULD be good.
335 // The start_time, however, has been known to be wrong in old files.
336 }
337 // Load the instrument
339
340 // Load the meta data, but don't stop on errors
341 g_log.debug() << "Loading metadata\n";
342 try {
343 LoadEventNexus::loadEntryMetadata<API::MatrixWorkspace_sptr>(m_filename, m_workspace, m_top_entry_name, descriptor);
344 } catch (std::exception &e) {
345 g_log.warning() << "Error while loading meta data: " << e.what() << '\n';
346 }
347
348 // add filename
349 m_workspace->mutableRun().addProperty("Filename", m_filename);
350
351 if ((numPeriods > 0) && (!useEventMon)) {
353 } else {
354 this->setProperty("OutputWorkspace", m_workspace);
355 }
356}
357
358//------------------------------------------------------------------------------
365void LoadNexusMonitors2::fixUDets(Nexus::File &file) {
366 const size_t nmonitors = m_monitorInfo.size();
367 boost::scoped_array<detid_t> det_ids(new detid_t[nmonitors]);
368 boost::scoped_array<specnum_t> spec_ids(new specnum_t[nmonitors]);
369 // convert the monitor info into two arrays for resorting
370 for (size_t i = 0; i < nmonitors; ++i) {
371 spec_ids[i] = m_monitorInfo[i].specNum;
372 det_ids[i] = m_monitorInfo[i].detNum;
373 }
374
375 try {
376 file.openGroup("isis_vms_compat", "IXvms");
377 } catch (Nexus::Exception const &) {
378 return;
379 }
380 // UDET
381 file.openData("UDET");
382 std::vector<int32_t> udet;
383 file.getData(udet);
384 file.closeData();
385 // SPEC
386 file.openData("SPEC");
387 std::vector<int32_t> spec;
388 file.getData(spec);
389 file.closeData();
390
391 // This is a little complicated: Each value in the spec_id array is a value
392 // found in the
393 // SPEC block of isis_vms_compat. The index that this value is found at then
394 // corresponds
395 // to the index within the UDET block that holds the detector ID
396 std::vector<int32_t>::const_iterator beg = spec.begin();
397 for (size_t mon_index = 0; mon_index < nmonitors; ++mon_index) {
398 std::vector<int32_t>::const_iterator itr = std::find(spec.begin(), spec.end(), spec_ids[mon_index]);
399 if (itr == spec.end()) {
400 det_ids[mon_index] = -1;
401 continue;
402 }
403 std::vector<int32_t>::difference_type udet_index = std::distance(beg, itr);
404 det_ids[mon_index] = udet[udet_index];
405 }
406 file.closeGroup();
407
408 // copy the information back into the monitorinfo
409 for (size_t i = 0; i < nmonitors; ++i) {
410 m_monitorInfo[i].specNum = spec_ids[i];
411 m_monitorInfo[i].detNum = det_ids[i];
412 }
413}
414
415void LoadNexusMonitors2::runLoadLogs(const std::string &filename, const API::MatrixWorkspace_sptr &localWorkspace) {
416 // get the properties for which logs to use
417 const std::vector<std::string> allow_list = getProperty(PropertyNames::LOGS_ALLOW);
418 const std::vector<std::string> block_list = getProperty(PropertyNames::LOGS_BLOCK);
419
420 // do the actual work
421 auto loadLogs = createChildAlgorithm("LoadNexusLogs");
422
423 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
424 try {
425 g_log.information() << "Loading logs from NeXus file...\n";
426 loadLogs->setPropertyValue("Filename", filename);
427 loadLogs->setProperty<API::MatrixWorkspace_sptr>("Workspace", localWorkspace);
428 // copy properties for which logs to use/not use
429 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_ALLOW, allow_list);
430 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_BLOCK, block_list);
431 loadLogs->execute();
432 } catch (...) {
433 g_log.error() << "Error while loading Logs from Nexus. Some sample logs "
434 "may be missing.\n";
435 }
436}
437
438//------------------------------------------------------------------------------
445bool LoadNexusMonitors2::canOpenAsNeXus(const std::string &fname) {
446 bool res = true;
447 std::unique_ptr<Nexus::File> filePointer;
448 try {
449 filePointer = std::make_unique<Nexus::File>(fname);
450 filePointer->getEntries();
451 } catch (Nexus::Exception const &e) {
452 g_log.error() << "Failed to open as a NeXus file: '" << fname << "', error description: " << e.what() << '\n';
453 res = false;
454 }
455 return res;
456}
457
458//------------------------------------------------------------------------------
466 // Y array should be divisible by the number of periods
467 if (m_multiPeriodCounts[0].size() % numPeriods != 0) {
468 g_log.warning() << "Attempted to split multiperiod histogram workspace with " << m_multiPeriodCounts[0].size()
469 << "data entries, into " << numPeriods
470 << "periods."
471 " Aborted.\n";
472 return;
473 }
474
475 size_t yLength = m_multiPeriodCounts[0].size() / numPeriods;
476 size_t xLength = yLength + 1;
477 size_t numSpectra = m_workspace->getNumberHistograms();
478 API::ISISRunLogs monLogCreator(m_workspace->run());
479
480 BinEdges edges = m_multiPeriodBinEdges[0];
481 std::vector<API::MatrixWorkspace_sptr> outputWorkspaces;
482 outputWorkspaces.reserve(numPeriods);
483
484 for (size_t i = 0; i < numPeriods; i++) {
485 // create the period workspace
487 API::WorkspaceFactory::Instance().create(m_workspace, numSpectra, xLength, yLength);
488
489 auto offset = yLength * i;
490
491 for (size_t wsIndex = 0; wsIndex < numSpectra; wsIndex++) {
492 auto inYBegin = m_multiPeriodCounts[wsIndex].cbegin() + offset;
493
494 wsPeriod->setHistogram(wsIndex, edges, Counts(inYBegin, inYBegin + yLength));
495 }
496 // add period logs
497 monLogCreator.addStatusLog(wsPeriod->mutableRun());
498 monLogCreator.addPeriodLogs(static_cast<int>(i + 1), wsPeriod->mutableRun());
499
500 outputWorkspaces.push_back(std::move(wsPeriod));
501 }
502
503 // set output workspace to either single period ws, or group ws.
504 if (outputWorkspaces.size() > 1) {
506 for (const auto &ws : outputWorkspaces) {
507 wsGroup->addWorkspace(ws);
508 }
509 this->setProperty("OutputWorkspace", wsGroup);
510 } else if (outputWorkspaces.size() == 1) {
511 this->setProperty("OutputWorkspace", outputWorkspaces[0]);
512 } else {
513 g_log.error() << "No period workspaces generated to output.";
514 }
515}
516
517size_t LoadNexusMonitors2::getMonitorInfo(Nexus::File &file, size_t &numPeriods) {
518 // should already be open to the correct NXentry
519
520 m_monitorInfo.clear();
521
522 using string_map_t = std::map<std::string, std::string>;
523
524 // Now we want to go through and find the monitors
525 string_map_t entries = file.getEntries();
526 numPeriods = 0;
527 // we want to sort monitors by monitor_number if they are present
528
529 API::Progress prog2(this, 0.2, 0.6, entries.size());
530
531 string_map_t::const_iterator it = entries.begin();
532 for (; it != entries.end(); ++it) {
533 std::string entry_name(it->first);
534 std::string entry_class(it->second);
535 if ((entry_class == "NXmonitor")) {
536 MonitorInfo info;
537
538 // check for event/histogram monitor
539 // -> This will prefer event monitors over histogram
540 // if they are found in the same group.
541 file.openGroup(entry_name, "NXmonitor");
542 info.name = entry_name;
543 info.hasEvent = isEventMonitor(file);
544 info.hasHisto = isHistoMonitor(file);
545
546 // get the detector number
547 string_map_t inner_entries = file.getEntries(); // get list of entries
548 if (inner_entries.find("monitor_number") != inner_entries.end()) {
549 // get monitor number from field in file
550 const auto detNum = Nexus::IOHelper::readNexusValue<int64_t>(file, "monitor_number");
551 if (detNum > std::numeric_limits<detid_t>::max()) {
552 throw std::runtime_error("Monitor number too larger to represent");
553 }
554 info.detNum = static_cast<detid_t>(detNum);
555 } else {
556 // default creates it from monitor name
557 std::filesystem::path monPath(entry_name);
558 std::string monitorName = monPath.stem().string();
559
560 // check for monitor name - in our case will be of the form either
561 // monitor1
562 // or monitor_1
563 std::string::size_type loc = monitorName.rfind('_');
564 if (loc == std::string::npos) {
565 loc = monitorName.rfind('r');
566 }
567
568 info.detNum = -1 * boost::lexical_cast<int>(monitorName.substr(loc + 1)); // SNS default
569 }
570
571 // get the spectrum number
572 if (inner_entries.find("spectrum_index") != inner_entries.end()) {
573 file.openData("spectrum_index");
574 file.getData(&info.specNum);
575 file.closeData();
576 } else {
577 // default is to match the detector number
578 info.specNum = std::abs(info.detNum);
579 }
580
581 if (info.hasHisto && (numPeriods == 0) && (inner_entries.find("period_index") != inner_entries.end())) {
582 MantidVec period_data;
583 file.openData("period_index");
584 file.getDataCoerce(period_data);
585 file.closeData();
586 numPeriods = period_data.size();
587 }
588
589 file.closeGroup(); // close NXmonitor
590 m_monitorInfo.emplace_back(info);
591 }
592 prog2.report();
593 }
594
595 // sort based on the absolute value of the monitor number
596 // this takes care of the fact that SNS monitors have negative numbers
597 std::sort(m_monitorInfo.begin(), m_monitorInfo.end(), [](const MonitorInfo &left, const MonitorInfo &right) {
598 return std::abs(left.detNum) < std::abs(right.detNum);
599 });
600
601 return m_monitorInfo.size();
602}
603
604bool LoadNexusMonitors2::createOutputWorkspace(std::vector<bool> &loadMonitorFlags) {
605 loadMonitorFlags.clear();
606
607 size_t numEventMon =
608 std::count_if(m_monitorInfo.begin(), m_monitorInfo.end(), [](const MonitorInfo &info) { return info.hasEvent; });
609 size_t numHistoMon =
610 std::count_if(m_monitorInfo.begin(), m_monitorInfo.end(), [](const MonitorInfo &info) { return info.hasHisto; });
611
612 bool useEventMon; // which type of workspace to create/is created
613 const std::string loadType = getProperty("LoadOnly");
614 if (loadType == LOAD_EVENTS) {
615 useEventMon = true;
616 if (numEventMon == 0) { // make sure there are some
617 throw std::runtime_error("Loading event data. Trying to load event data but failed to "
618 "find event monitors. This file may be corrupted or it may not be "
619 "supported");
620 }
621 } else if (loadType == LOAD_HISTO) {
622 useEventMon = false;
623 if (numHistoMon == 0) { // make sure there are some
624 throw std::runtime_error("Not loading event data. Trying to load histogram data but failed to "
625 "find monitors with histogram data or could not interpret the data. "
626 "This file may be corrupted or it may not be supported");
627 }
628 } else { // only other option is to go with the default
629 if (numEventMon > 0 && numHistoMon > 0) {
630 std::stringstream errmsg;
631 errmsg << "There are " << numHistoMon << " histogram monitors and " << numEventMon
632 << " event monitors. Loading Histogram by default. "
633 << "Use \"LoadOnly\" or \"MonitorLoadOnly\" to specify which to "
634 "load.";
635 m_log.warning(errmsg.str());
636 useEventMon = false;
637 } else {
638 // more than one event monitor means use that since both can't be nonzero
639 useEventMon = (numEventMon > 0);
640 }
641 }
642
643 // set up the flags to load monitor
644 if (useEventMon) {
645 // load event
646 for (size_t i_mon = 0; i_mon < m_monitor_count; ++i_mon) {
647 loadMonitorFlags.emplace_back(m_monitorInfo[i_mon].hasEvent);
648 }
649 } else {
650 // load histogram
651 for (size_t i_mon = 0; i_mon < m_monitor_count; ++i_mon) {
652 loadMonitorFlags.emplace_back(m_monitorInfo[i_mon].hasHisto);
653 }
654 }
655
656 // create workspace
657 if (useEventMon) {
658 // Use event monitors and create event workspace
659
660 // only used if using event monitors
662 eventWS->initialize(m_monitorInfo.size(), 1, 1);
663
664 // Set the units
665 eventWS->getAxis(0)->unit() = Mantid::Kernel::UnitFactory::Instance().create("TOF");
666 eventWS->setYUnit("Counts");
667 m_workspace = eventWS;
668 } else { // only other option is histograms
669 // Use histogram monitors and event monitors' histogram data.
670 // And thus create a Workspace2D.
671
672 m_workspace = API::WorkspaceFactory::Instance().create("Workspace2D", m_monitorInfo.size(), 2, 1);
673 }
674
675 return useEventMon;
676}
677
678void LoadNexusMonitors2::readEventMonitorEntry(Nexus::File &file, size_t ws_index) {
679 // setup local variables
680 EventWorkspace_sptr eventWS = std::dynamic_pointer_cast<EventWorkspace>(m_workspace);
681 std::string tof_units, event_time_zero_units;
682
683 // read in the data
684 auto event_index = Nexus::IOHelper::readNexusVector<uint64_t>(file, "event_index");
685
686 file.openData("event_time_offset"); // time of flight
687 MantidVec time_of_flight = Nexus::IOHelper::readNexusVector<double>(file);
688 file.getAttr("units", tof_units);
689 Kernel::Units::timeConversionVector(time_of_flight, tof_units, "microseconds");
690 file.closeData();
691
692 // warn the user if no events were found
693 if (time_of_flight.empty()) {
694 g_log.error() << "No events found in \"" << m_monitorInfo[ws_index].name << "\"\n";
695 return; // early
696 }
697
698 file.openData("event_time_zero"); // pulse time
699 MantidVec seconds = Nexus::IOHelper::readNexusVector<double>(file);
700 file.getAttr("units", event_time_zero_units);
701 Kernel::Units::timeConversionVector(seconds, event_time_zero_units, "seconds");
702 Mantid::Types::Core::DateAndTime pulsetime_offset;
703 {
704 std::string startTime;
705 file.getAttr("offset", startTime);
706 pulsetime_offset = createFromSanitizedISO8601(startTime);
707 }
708 file.closeData();
709
710 // load up the event list
711 DataObjects::EventList &event_list = eventWS->getSpectrum(ws_index);
712
713 Mantid::Types::Core::DateAndTime pulsetime;
714 Mantid::Types::Core::DateAndTime lastpulsetime(0);
715 std::size_t numEvents = time_of_flight.size();
716 bool pulsetimesincreasing = true;
717 size_t pulse_index(0);
718 size_t numPulses = seconds.size();
719 for (std::size_t j = 0; j < numEvents; ++j) {
720 while (!((j >= event_index[pulse_index]) && (j < event_index[pulse_index + 1]))) {
721 pulse_index += 1;
722 if (pulse_index > (numPulses + 1))
723 break;
724 }
725 if (pulse_index >= (numPulses))
726 pulse_index = numPulses - 1; // fix it
727 pulsetime = pulsetime_offset + seconds[pulse_index];
728 if (pulsetime < lastpulsetime)
729 pulsetimesincreasing = false;
730 lastpulsetime = pulsetime;
731 event_list.addEventQuickly(Types::Event::TofEvent(time_of_flight[j], pulsetime));
732 }
733 if (pulsetimesincreasing)
735}
736
737void LoadNexusMonitors2::readHistoMonitorEntry(Nexus::File &file, size_t ws_index, size_t numPeriods) {
738 // Now, actually retrieve the necessary data
739 file.openData("data");
740 MantidVec data;
741 file.getDataCoerce(data);
742 file.closeData();
743
744 // Get the TOF axis
745 file.openData("time_of_flight");
746 MantidVec tof;
747 file.getDataCoerce(tof);
748 file.closeData();
749
750 if (numPeriods > 0) {
751 m_multiPeriodBinEdges[ws_index] = std::move(tof);
752 m_multiPeriodCounts[ws_index] = std::move(data);
753 } else {
754 m_workspace->setHistogram(ws_index, Histogram(BinEdges(std::move(tof)), Counts(std::move(data))));
755 }
756}
757
758} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double left
double right
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
Kernel::Logger m_log
Logger for this algorithm.
Definition Algorithm.h:421
@ Load
allowed here which will be passed to the algorithm
Defines a class to aid in creating ISIS specific run logs for periods, status etc.
Definition ISISRunLogs.h:28
void addStatusLog(API::Run &exptRun)
Adds the status log to the this run.
void addPeriodLogs(const int period, API::Run &exptRun)
Adds period related logs.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
Class to hold a set of workspaces.
A property class for workspaces.
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.
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...
void runLoadLogs(const std::string &filename, const API::MatrixWorkspace_sptr &localWorkspace)
Load the logs.
bool createOutputWorkspace(std::vector< bool > &loadMonitorFlags)
void readHistoMonitorEntry(Nexus::File &file, size_t ws_index, size_t numPeriods)
void splitMutiPeriodHistrogramData(const size_t numPeriods)
split multi period histogram workspace into a workspace group
std::vector< LoadNexusMonitorsAlg::MonitorInfo > m_monitorInfo
void init() override
Initialise algorithm.
std::string m_filename
The name and path of the input file.
void readEventMonitorEntry(Nexus::File &file, size_t ws_index)
std::vector< HistogramData::BinEdges > m_multiPeriodBinEdges
std::string m_top_entry_name
name of top level NXentry to use
void fixUDets(Nexus::File &file)
Fix the detector numbers if the defaults are not correct.
const std::string name() const override
Algorithm's name for identification.
size_t getMonitorInfo(Nexus::File &file, size_t &numPeriods)
API::MatrixWorkspace_sptr m_workspace
The workspace being filled out.
void exec() override
Execute algorithm.
bool canOpenAsNeXus(const std::string &fname)
is it possible to open the file?
std::vector< HistogramData::Counts > m_multiPeriodCounts
A class for holding :
Definition EventList.h:57
void setSortOrder(const EventSortType order) const
Manually set the event list sort order value.
void addEventQuickly(const Types::Event::TofEvent &event)
Append an event to the histogram, without clearing the cache, to make it faster.
Definition EventList.h:105
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class that provides for a standard Nexus exception.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void adjustTimeOfFlightISISLegacy(Nexus::File &file, T localWorkspace, const std::string &entry_name, const std::string &classType, const Nexus::NexusDescriptor *descriptor=nullptr)
ISIS specific method for dealing with wide events.
std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const Nexus::NexusDescriptor &descriptor)
Get the number of events in the currently opened group.
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
MANTID_KERNEL_DLL Types::Core::DateAndTime createFromSanitizedISO8601(const std::string &date)
Creates a DateAndTime object from a date string even if the string does not exactly conform to ISO860...
void timeConversionVector(std::vector< T > &vec, const std::string &input_unit, const std::string &output_unit)
Definition Unit.h:661
int32_t detid_t
Typedef for a detector ID.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
std::string name
name of the group in the nexus file - TODO was
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54