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
170 // top level file information
171 Nexus::File file(m_filename);
172
173 // open the correct entry
174 using string_map_t = std::map<std::string, std::string>;
175 string_map_t entries = file.getEntries();
176
177 if (m_top_entry_name.empty()) {
178 const auto it = std::find_if(entries.cbegin(), entries.cend(), [](const auto &entry) {
179 return ((entry.first == "entry" || entry.first == "raw_data_1") && entry.second == "NXentry");
180 });
181 if (it != entries.cend()) {
182 file.openGroup(it->first, it->second);
183 m_top_entry_name = it->first;
184 }
185 } else {
186 if (!keyExists(m_top_entry_name, entries)) {
187 throw std::invalid_argument(m_filename + " does not contain an entry named " + m_top_entry_name);
188 }
189 file.openGroup(m_top_entry_name, "NXentry"); // Open as will need to be
190 // open for subsequent operations
191 }
192 prog1.report();
193
194 size_t numPeriods = 0;
195 m_monitor_count = getMonitorInfo(file, numPeriods);
196 // Fix the detector numbers if the defaults above are not correct
197 // fixUDets(detector_numbers, file, spectra_numbers, m_monitor_count);
198 // a temporary place to put the spectra/detector numbers
199 // this gets the ids from the "isis_vms_compat" group
200 fixUDets(file);
201
202 if (numPeriods > 0) {
205 }
206
207 // Nothing to do
208 if (0 == m_monitor_count) {
209 // previous version just used to return, but that
210 // threw an error when the OutputWorkspace property was not set.
211 // and the error message was confusing.
212 // This has changed to throw a specific error.
213 throw std::invalid_argument(m_filename + " does not contain any monitors");
214 }
215
216 // only used if using event monitors
217 // EventWorkspace_sptr eventWS;
218 // Create the output workspace
219 std::vector<bool> loadMonitorFlags;
220 bool useEventMon = createOutputWorkspace(loadMonitorFlags);
221
222 API::Progress prog3(this, 0.6, 1.0, m_monitor_count);
223
224 // cache address to entry for later
225 const std::string entryAddress = file.getAddress();
226
227 // TODO-NEXT: load event monitor if it is required to do so
228 // load histogram monitor if it is required to do so
229 // Require a tuple: monitorNames[i], loadAsEvent[i], loadAsHistogram[i]
230 for (std::size_t ws_index = 0; ws_index < m_monitor_count; ++ws_index) {
231 // already know spectrum and detector numbers
232 g_log.debug() << "monIndex = " << m_monitorInfo[ws_index].detNum << '\n';
233 g_log.debug() << "spectrumNo = " << m_monitorInfo[ws_index].specNum << '\n';
234 m_workspace->getSpectrum(ws_index).setSpectrumNo(m_monitorInfo[ws_index].specNum);
235 m_workspace->getSpectrum(ws_index).setDetectorID(m_monitorInfo[ws_index].detNum);
236
237 // Don't actually read all of the monitors
238 g_log.information() << "Loading " << m_monitorInfo[ws_index].name;
239 if (loadMonitorFlags[ws_index]) {
240 g_log.information() << "\n";
241 file.openGroup(m_monitorInfo[ws_index].name, "NXmonitor");
242 if (useEventMon) {
243 // load as an event monitor
244 readEventMonitorEntry(file, ws_index);
245 } else {
246 // load as a histogram monitor
247 readHistoMonitorEntry(file, ws_index, numPeriods);
248 }
249 file.closeGroup(); // NXmonitor
250 } else {
251 g_log.information() << " is skipped.\n";
252 }
253
254 prog3.report();
255 }
256
257 if (useEventMon) // set the x-range to be the range for min/max events
258 {
259 EventWorkspace_sptr eventWS = std::dynamic_pointer_cast<EventWorkspace>(m_workspace);
260 double xmin, xmax;
261 eventWS->getEventXMinMax(xmin, xmax);
262
263 if (xmin > xmax) {
264 xmin = 0;
265 xmax = 1;
266 if (eventWS->getNumberEvents() == 0) {
267 g_log.warning("No events loading. Resetting time-of-flight range 0 to 1");
268 } else {
269 g_log.warning("time-of-flight range of events are unusual. Resetting time-of-flight range 0 to 1");
270 }
271 } else {
272 // move out by one just like LoadEventNexus
273 xmin = xmin - 1;
274 xmax = xmax + 1;
275 }
276
277 auto axis = HistogramData::BinEdges{xmin, xmax};
278 eventWS->setAllX(axis); // Set the binning axis using this.
279
280 // a certain generation of ISIS files modify the time-of-flight
281 const std::string currentAddress = file.getAddress();
282
284 adjustTimeOfFlightISISLegacy(file, eventWS, m_top_entry_name, "NXmonitor");
285 }
286
287 file.openAddress(currentAddress); // reset to where it was earlier
288 }
289
290 // Check for and ISIS compat block to get the detector IDs for the loaded
291 // spectrum numbers
292 // @todo: Find out if there is a better (i.e. more generic) way to do this
293 try {
294 g_log.debug() << "Load Sample data isis\n";
295 loadSampleDataISIScompatibilityInfo(file, m_workspace);
296 } catch (Nexus::Exception const &) {
297 }
298
299 // Need to get the instrument name from the file
300 std::string instrumentName;
301 file.openAddress(entryAddress); // reset address in case of unusual behavior
302 file.openGroup("instrument", "NXinstrument");
303 try {
304 file.openData("name");
305 instrumentName = file.getStrData();
306 // Now let's close the file as we don't need it anymore to load the
307 // instrument.
308 file.closeData();
309 file.closeGroup(); // Close the NXentry
310 file.close();
311
312 } catch (std::runtime_error &) // no correct instrument definition (old ISIS
313 // file, fall back to isis_vms_compat)
314 {
315 file.closeGroup(); // Close the instrument NXentry
317 file.close();
318 }
319
320 g_log.debug() << "Instrument name read from NeXus file is " << instrumentName << '\n';
321
322 m_workspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
323 m_workspace->setYUnit("Counts");
324
325 // Load the logs
327
328 // Old SNS files don't have this
329 try {
330 // The run_start will be loaded from the pulse times.
331 Types::Core::DateAndTime run_start(0, 0);
332 run_start = m_workspace->getFirstPulseTime();
333 m_workspace->mutableRun().addProperty("run_start", run_start.toISO8601String(), true);
334 } catch (...) {
335 // Old files have the start_time defined, so all SHOULD be good.
336 // The start_time, however, has been known to be wrong in old files.
337 }
338 // Load the instrument
340
341 // Load the meta data, but don't stop on errors
342 g_log.debug() << "Loading metadata\n";
343 try {
344 LoadEventNexus::loadEntryMetadata<API::MatrixWorkspace_sptr>(m_filename, m_workspace, m_top_entry_name);
345 } catch (std::exception &e) {
346 g_log.warning() << "Error while loading meta data: " << e.what() << '\n';
347 }
348
349 // add filename
350 m_workspace->mutableRun().addProperty("Filename", m_filename);
351
352 if ((numPeriods > 0) && (!useEventMon)) {
354 } else {
355 this->setProperty("OutputWorkspace", m_workspace);
356 }
357}
358
359//------------------------------------------------------------------------------
366void LoadNexusMonitors2::fixUDets(Nexus::File &file) {
367 const size_t nmonitors = m_monitorInfo.size();
368 boost::scoped_array<detid_t> det_ids(new detid_t[nmonitors]);
369 boost::scoped_array<specnum_t> spec_ids(new specnum_t[nmonitors]);
370 // convert the monitor info into two arrays for resorting
371 for (size_t i = 0; i < nmonitors; ++i) {
372 spec_ids[i] = m_monitorInfo[i].specNum;
373 det_ids[i] = m_monitorInfo[i].detNum;
374 }
375
376 try {
377 file.openGroup("isis_vms_compat", "IXvms");
378 } catch (Nexus::Exception const &) {
379 return;
380 }
381 // UDET
382 file.openData("UDET");
383 std::vector<int32_t> udet;
384 file.getData(udet);
385 file.closeData();
386 // SPEC
387 file.openData("SPEC");
388 std::vector<int32_t> spec;
389 file.getData(spec);
390 file.closeData();
391
392 // This is a little complicated: Each value in the spec_id array is a value
393 // found in the
394 // SPEC block of isis_vms_compat. The index that this value is found at then
395 // corresponds
396 // to the index within the UDET block that holds the detector ID
397 std::vector<int32_t>::const_iterator beg = spec.begin();
398 for (size_t mon_index = 0; mon_index < nmonitors; ++mon_index) {
399 std::vector<int32_t>::const_iterator itr = std::find(spec.begin(), spec.end(), spec_ids[mon_index]);
400 if (itr == spec.end()) {
401 det_ids[mon_index] = -1;
402 continue;
403 }
404 std::vector<int32_t>::difference_type udet_index = std::distance(beg, itr);
405 det_ids[mon_index] = udet[udet_index];
406 }
407 file.closeGroup();
408
409 // copy the information back into the monitorinfo
410 for (size_t i = 0; i < nmonitors; ++i) {
411 m_monitorInfo[i].specNum = spec_ids[i];
412 m_monitorInfo[i].detNum = det_ids[i];
413 }
414}
415
416void LoadNexusMonitors2::runLoadLogs(const std::string &filename, const API::MatrixWorkspace_sptr &localWorkspace) {
417 // get the properties for which logs to use
418 const std::vector<std::string> allow_list = getProperty(PropertyNames::LOGS_ALLOW);
419 const std::vector<std::string> block_list = getProperty(PropertyNames::LOGS_BLOCK);
420
421 // do the actual work
422 auto loadLogs = createChildAlgorithm("LoadNexusLogs");
423
424 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
425 try {
426 g_log.information() << "Loading logs from NeXus file...\n";
427 loadLogs->setPropertyValue("Filename", filename);
428 loadLogs->setProperty<API::MatrixWorkspace_sptr>("Workspace", localWorkspace);
429 // copy properties for which logs to use/not use
430 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_ALLOW, allow_list);
431 loadLogs->setProperty<std::vector<std::string>>(PropertyNames::LOGS_BLOCK, block_list);
432 loadLogs->execute();
433 } catch (...) {
434 g_log.error() << "Error while loading Logs from Nexus. Some sample logs "
435 "may be missing.\n";
436 }
437}
438
439//------------------------------------------------------------------------------
446bool LoadNexusMonitors2::canOpenAsNeXus(const std::string &fname) {
447 bool res = true;
448 std::unique_ptr<Nexus::File> filePointer;
449 try {
450 filePointer = std::make_unique<Nexus::File>(fname);
451 filePointer->getEntries();
452 } catch (Nexus::Exception const &e) {
453 g_log.error() << "Failed to open as a NeXus file: '" << fname << "', error description: " << e.what() << '\n';
454 res = false;
455 }
456 return res;
457}
458
459//------------------------------------------------------------------------------
467 // Y array should be divisible by the number of periods
468 if (m_multiPeriodCounts[0].size() % numPeriods != 0) {
469 g_log.warning() << "Attempted to split multiperiod histogram workspace with " << m_multiPeriodCounts[0].size()
470 << "data entries, into " << numPeriods
471 << "periods."
472 " Aborted.\n";
473 return;
474 }
475
476 size_t yLength = m_multiPeriodCounts[0].size() / numPeriods;
477 size_t xLength = yLength + 1;
478 size_t numSpectra = m_workspace->getNumberHistograms();
479 API::ISISRunLogs monLogCreator(m_workspace->run());
480
481 BinEdges edges = m_multiPeriodBinEdges[0];
482 std::vector<API::MatrixWorkspace_sptr> outputWorkspaces;
483 outputWorkspaces.reserve(numPeriods);
484
485 for (size_t i = 0; i < numPeriods; i++) {
486 // create the period workspace
488 API::WorkspaceFactory::Instance().create(m_workspace, numSpectra, xLength, yLength);
489
490 auto offset = yLength * i;
491
492 for (size_t wsIndex = 0; wsIndex < numSpectra; wsIndex++) {
493 auto inYBegin = m_multiPeriodCounts[wsIndex].cbegin() + offset;
494
495 wsPeriod->setHistogram(wsIndex, edges, Counts(inYBegin, inYBegin + yLength));
496 }
497 // add period logs
498 monLogCreator.addStatusLog(wsPeriod->mutableRun());
499 monLogCreator.addPeriodLogs(static_cast<int>(i + 1), wsPeriod->mutableRun());
500
501 outputWorkspaces.push_back(std::move(wsPeriod));
502 }
503
504 // set output workspace to either single period ws, or group ws.
505 if (outputWorkspaces.size() > 1) {
507 for (const auto &ws : outputWorkspaces) {
508 wsGroup->addWorkspace(ws);
509 }
510 this->setProperty("OutputWorkspace", wsGroup);
511 } else if (outputWorkspaces.size() == 1) {
512 this->setProperty("OutputWorkspace", outputWorkspaces[0]);
513 } else {
514 g_log.error() << "No period workspaces generated to output.";
515 }
516}
517
518size_t LoadNexusMonitors2::getMonitorInfo(Nexus::File &file, size_t &numPeriods) {
519 // should already be open to the correct NXentry
520
521 m_monitorInfo.clear();
522
523 using string_map_t = std::map<std::string, std::string>;
524
525 // Now we want to go through and find the monitors
526 string_map_t entries = file.getEntries();
527 numPeriods = 0;
528 // we want to sort monitors by monitor_number if they are present
529
530 API::Progress prog2(this, 0.2, 0.6, entries.size());
531
532 string_map_t::const_iterator it = entries.begin();
533 for (; it != entries.end(); ++it) {
534 std::string entry_name(it->first);
535 std::string entry_class(it->second);
536 if ((entry_class == "NXmonitor")) {
537 MonitorInfo info;
538
539 // check for event/histogram monitor
540 // -> This will prefer event monitors over histogram
541 // if they are found in the same group.
542 file.openGroup(entry_name, "NXmonitor");
543 info.name = entry_name;
544 info.hasEvent = isEventMonitor(file);
545 info.hasHisto = isHistoMonitor(file);
546
547 // get the detector number
548 string_map_t inner_entries = file.getEntries(); // get list of entries
549 if (inner_entries.find("monitor_number") != inner_entries.end()) {
550 // get monitor number from field in file
551 const auto detNum = Nexus::IOHelper::readNexusValue<int64_t>(file, "monitor_number");
552 if (detNum > std::numeric_limits<detid_t>::max()) {
553 throw std::runtime_error("Monitor number too larger to represent");
554 }
555 info.detNum = static_cast<detid_t>(detNum);
556 } else {
557 // default creates it from monitor name
558 std::filesystem::path monPath(entry_name);
559 std::string monitorName = monPath.stem().string();
560
561 // check for monitor name - in our case will be of the form either
562 // monitor1
563 // or monitor_1
564 std::string::size_type loc = monitorName.rfind('_');
565 if (loc == std::string::npos) {
566 loc = monitorName.rfind('r');
567 }
568
569 info.detNum = -1 * boost::lexical_cast<int>(monitorName.substr(loc + 1)); // SNS default
570 }
571
572 // get the spectrum number
573 if (inner_entries.find("spectrum_index") != inner_entries.end()) {
574 file.openData("spectrum_index");
575 file.getData(&info.specNum);
576 file.closeData();
577 } else {
578 // default is to match the detector number
579 info.specNum = std::abs(info.detNum);
580 }
581
582 if (info.hasHisto && (numPeriods == 0) && (inner_entries.find("period_index") != inner_entries.end())) {
583 MantidVec period_data;
584 file.openData("period_index");
585 file.getDataCoerce(period_data);
586 file.closeData();
587 numPeriods = period_data.size();
588 }
589
590 file.closeGroup(); // close NXmonitor
591 m_monitorInfo.emplace_back(info);
592 }
593 prog2.report();
594 }
595
596 // sort based on the absolute value of the monitor number
597 // this takes care of the fact that SNS monitors have negative numbers
598 std::sort(m_monitorInfo.begin(), m_monitorInfo.end(), [](const MonitorInfo &left, const MonitorInfo &right) {
599 return std::abs(left.detNum) < std::abs(right.detNum);
600 });
601
602 return m_monitorInfo.size();
603}
604
605bool LoadNexusMonitors2::createOutputWorkspace(std::vector<bool> &loadMonitorFlags) {
606 loadMonitorFlags.clear();
607
608 size_t numEventMon =
609 std::count_if(m_monitorInfo.begin(), m_monitorInfo.end(), [](const MonitorInfo &info) { return info.hasEvent; });
610 size_t numHistoMon =
611 std::count_if(m_monitorInfo.begin(), m_monitorInfo.end(), [](const MonitorInfo &info) { return info.hasHisto; });
612
613 bool useEventMon; // which type of workspace to create/is created
614 const std::string loadType = getProperty("LoadOnly");
615 if (loadType == LOAD_EVENTS) {
616 useEventMon = true;
617 if (numEventMon == 0) { // make sure there are some
618 throw std::runtime_error("Loading event data. Trying to load event data but failed to "
619 "find event monitors. This file may be corrupted or it may not be "
620 "supported");
621 }
622 } else if (loadType == LOAD_HISTO) {
623 useEventMon = false;
624 if (numHistoMon == 0) { // make sure there are some
625 throw std::runtime_error("Not loading event data. Trying to load histogram data but failed to "
626 "find monitors with histogram data or could not interpret the data. "
627 "This file may be corrupted or it may not be supported");
628 }
629 } else { // only other option is to go with the default
630 if (numEventMon > 0 && numHistoMon > 0) {
631 std::stringstream errmsg;
632 errmsg << "There are " << numHistoMon << " histogram monitors and " << numEventMon
633 << " event monitors. Loading Histogram by default. "
634 << "Use \"LoadOnly\" or \"MonitorLoadOnly\" to specify which to "
635 "load.";
636 m_log.warning(errmsg.str());
637 useEventMon = false;
638 } else {
639 // more than one event monitor means use that since both can't be nonzero
640 useEventMon = (numEventMon > 0);
641 }
642 }
643
644 // set up the flags to load monitor
645 if (useEventMon) {
646 // load event
647 for (size_t i_mon = 0; i_mon < m_monitor_count; ++i_mon) {
648 loadMonitorFlags.emplace_back(m_monitorInfo[i_mon].hasEvent);
649 }
650 } else {
651 // load histogram
652 for (size_t i_mon = 0; i_mon < m_monitor_count; ++i_mon) {
653 loadMonitorFlags.emplace_back(m_monitorInfo[i_mon].hasHisto);
654 }
655 }
656
657 // create workspace
658 if (useEventMon) {
659 // Use event monitors and create event workspace
660
661 // only used if using event monitors
663 eventWS->initialize(m_monitorInfo.size(), 1, 1);
664
665 // Set the units
666 eventWS->getAxis(0)->unit() = Mantid::Kernel::UnitFactory::Instance().create("TOF");
667 eventWS->setYUnit("Counts");
668 m_workspace = eventWS;
669 } else { // only other option is histograms
670 // Use histogram monitors and event monitors' histogram data.
671 // And thus create a Workspace2D.
672
673 m_workspace = API::WorkspaceFactory::Instance().create("Workspace2D", m_monitorInfo.size(), 2, 1);
674 }
675
676 return useEventMon;
677}
678
679void LoadNexusMonitors2::readEventMonitorEntry(Nexus::File &file, size_t ws_index) {
680 // setup local variables
681 EventWorkspace_sptr eventWS = std::dynamic_pointer_cast<EventWorkspace>(m_workspace);
682 std::string tof_units, event_time_zero_units;
683
684 // read in the data
685 auto event_index = Nexus::IOHelper::readNexusVector<uint64_t>(file, "event_index");
686
687 file.openData("event_time_offset"); // time of flight
688 MantidVec time_of_flight = Nexus::IOHelper::readNexusVector<double>(file);
689 file.getAttr("units", tof_units);
690 Kernel::Units::timeConversionVector(time_of_flight, tof_units, "microseconds");
691 file.closeData();
692
693 // warn the user if no events were found
694 if (time_of_flight.empty()) {
695 g_log.error() << "No events found in \"" << m_monitorInfo[ws_index].name << "\"\n";
696 return; // early
697 }
698
699 file.openData("event_time_zero"); // pulse time
700 MantidVec seconds = Nexus::IOHelper::readNexusVector<double>(file);
701 file.getAttr("units", event_time_zero_units);
702 Kernel::Units::timeConversionVector(seconds, event_time_zero_units, "seconds");
703 Mantid::Types::Core::DateAndTime pulsetime_offset;
704 {
705 std::string startTime;
706 file.getAttr("offset", startTime);
707 pulsetime_offset = createFromSanitizedISO8601(startTime);
708 }
709 file.closeData();
710
711 // load up the event list
712 DataObjects::EventList &event_list = eventWS->getSpectrum(ws_index);
713
714 Mantid::Types::Core::DateAndTime pulsetime;
715 Mantid::Types::Core::DateAndTime lastpulsetime(0);
716 std::size_t numEvents = time_of_flight.size();
717 bool pulsetimesincreasing = true;
718 size_t pulse_index(0);
719 size_t numPulses = seconds.size();
720 for (std::size_t j = 0; j < numEvents; ++j) {
721 while (!((j >= event_index[pulse_index]) && (j < event_index[pulse_index + 1]))) {
722 pulse_index += 1;
723 if (pulse_index > (numPulses + 1))
724 break;
725 }
726 if (pulse_index >= (numPulses))
727 pulse_index = numPulses - 1; // fix it
728 pulsetime = pulsetime_offset + seconds[pulse_index];
729 if (pulsetime < lastpulsetime)
730 pulsetimesincreasing = false;
731 lastpulsetime = pulsetime;
732 event_list.addEventQuickly(Types::Event::TofEvent(time_of_flight[j], pulsetime));
733 }
734 if (pulsetimesincreasing)
736}
737
738void LoadNexusMonitors2::readHistoMonitorEntry(Nexus::File &file, size_t ws_index, size_t numPeriods) {
739 // Now, actually retrieve the necessary data
740 file.openData("data");
741 MantidVec data;
742 file.getDataCoerce(data);
743 file.closeData();
744
745 // Get the TOF axis
746 file.openData("time_of_flight");
747 MantidVec tof;
748 file.getDataCoerce(tof);
749 file.closeData();
750
751 if (numPeriods > 0) {
752 m_multiPeriodBinEdges[ws_index] = std::move(tof);
753 m_multiPeriodCounts[ws_index] = std::move(data);
754 } else {
755 m_workspace->setHistogram(ws_index, Histogram(BinEdges(std::move(tof)), Counts(std::move(data))));
756 }
757}
758
759} // 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
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.
void adjustTimeOfFlightISISLegacy(Nexus::File &file, T localWorkspace, const std::string &entry_name, const std::string &classType)
ISIS specific method for dealing with wide events.
MANTID_DATAHANDLING_DLL bool doPerformISISEventShift(Nexus::File &file, std::string &topEntryName)
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
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