Mantid
Loading...
Searching...
No Matches
LoadPLN.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 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 +
7
9#include "MantidAPI/Axis.h"
13#include "MantidAPI/Run.h"
23
24#include <algorithm>
25#include <cmath>
26#include <filesystem>
27#include <fstream>
28#include <utility>
29
30namespace Mantid::DataHandling {
31
32using namespace Kernel;
33
34namespace {
35
36// number of physical detectors
37constexpr size_t MONITORS = 8;
38constexpr size_t DETECTOR_TUBES = 200;
39constexpr size_t HISTO_BINS_X = DETECTOR_TUBES + MONITORS;
40constexpr size_t HISTO_BINS_Y_DENUMERATOR = 16;
41constexpr size_t PIXELS_PER_TUBE = 1024 / HISTO_BINS_Y_DENUMERATOR;
42constexpr size_t DETECTOR_SPECTRA = DETECTOR_TUBES * PIXELS_PER_TUBE;
43constexpr size_t HISTOGRAMS = DETECTOR_SPECTRA + MONITORS;
44
45// File loading progress boundaries
46constexpr size_t Progress_LoadBinFile = 48;
47constexpr size_t Progress_ReserveMemory = 4;
49
50// Algorithm parameter names
51constexpr char FilenameStr[] = "Filename";
52constexpr char MaskStr[] = "Mask";
53constexpr char SelectDetectorTubesStr[] = "SelectDetectorTubes";
54constexpr char SelectDatasetStr[] = "SelectDataset";
55constexpr char FilterByTimeStartStr[] = "FilterByTimeStart";
56constexpr char FilterByTimeStopStr[] = "FilterByTimeStop";
57constexpr char PathToBinaryStr[] = "BinaryEventPath";
58constexpr char TOFBiasStr[] = "TimeOfFlightBias";
59constexpr char CalibrateTOFStr[] = "CalibrateTOFBias";
60constexpr char LambdaOnTwoStr[] = "LambdaOnTwoMode";
61
62// Common pairing of limits
63using TimeLimits = std::pair<double, double>;
64
65template <typename Type>
66void AddSinglePointTimeSeriesProperty(API::LogManager &logManager, const std::string &time, const std::string &name,
67 const Type value) {
68 // create time series property and add single value
69 auto p = new Kernel::TimeSeriesProperty<Type>(name);
70 p->addValue(time, value);
71
72 // add to log manager
73 logManager.addProperty(p);
74}
75
76// Utility functions for loading values with defaults
77// Single value properties only support int, double, string and bool
78template <typename Type>
79Type GetNeXusValue(const Nexus::NXEntry &entry, const std::string &address, const Type &defval, int32_t index) {
80 try {
81 Nexus::NXDataSetTyped<Type> dataSet = entry.openNXDataSet<Type>(address);
82 dataSet.load();
83
84 return dataSet()[index];
85 } catch (std::runtime_error &) {
86 return defval;
87 }
88}
89
90// string and double are special cases
91template <>
92double GetNeXusValue<double>(const Nexus::NXEntry &entry, const std::string &address, const double &defval,
93 int32_t index) {
94 try {
95 Nexus::NXFloat dataSet = entry.openNXDataSet<float>(address);
96 dataSet.load();
97
98 return dataSet()[index];
99 } catch (std::runtime_error &) {
100 return defval;
101 }
102}
103
104template <>
105std::string GetNeXusValue<std::string>(const Nexus::NXEntry &entry, const std::string &address,
106 const std::string &defval, int32_t /*unused*/) {
107
108 try {
109 return entry.getString(address);
110 } catch (std::runtime_error &) {
111 return defval;
112 }
113}
114
115template <typename T>
116void MapNeXusToProperty(const Nexus::NXEntry &entry, const std::string &address, const T &defval,
117 API::LogManager &logManager, const std::string &name, const T &factor, int32_t index) {
118
119 T value = GetNeXusValue<T>(entry, address, defval, index);
120 logManager.addProperty<T>(name, value * factor);
121}
122
123// string is a special case
124template <>
125void MapNeXusToProperty<std::string>(const Nexus::NXEntry &entry, const std::string &address, const std::string &defval,
126 API::LogManager &logManager, const std::string &name,
127 const std::string & /*unused*/, int32_t index) {
128
129 std::string value = GetNeXusValue<std::string>(entry, address, defval, index);
130 logManager.addProperty<std::string>(name, value);
131}
132
133template <typename T>
134void MapNeXusToSeries(const Nexus::NXEntry &entry, const std::string &address, const T &defval,
135 API::LogManager &logManager, const std::string &time, const std::string &name, const T &factor,
136 int32_t index) {
137
138 auto value = GetNeXusValue<T>(entry, address, defval, index);
139 AddSinglePointTimeSeriesProperty<T>(logManager, time, name, value * factor);
140}
141
142// map the comma separated range of indexes to the vector via a lambda function
143// throws an exception if it is outside the vector range
144//
145template <typename T, typename F> void mapRangeToIndex(const std::string &line, std::vector<T> &result, const F &fn) {
146
147 std::stringstream ss(line);
148 std::string item;
149 size_t index = 0;
150 while (std::getline(ss, item, ',')) {
151 auto const k = item.find('-');
152
153 size_t p0, p1;
154 if (k != std::string::npos) {
155 p0 = boost::lexical_cast<size_t>(item.substr(0, k));
156 p1 = boost::lexical_cast<size_t>(item.substr(k + 1, item.size() - k - 1));
157 } else {
158 p0 = boost::lexical_cast<size_t>(item);
159 p1 = p0;
160 }
161
162 if (p1 < result.size() && p0 <= p1) {
163 while (p0 <= p1) {
164 result[p0++] = fn(index);
165 index++;
166 }
167 } else if (p0 < result.size() && p1 < p0) {
168 do {
169 result[p0] = fn(index);
170 index++;
171 } while (p1 < p0--);
172 } else
173 throw std::invalid_argument("invalid range specification");
174 }
175}
176
177// Simple reader that is compatible with the ASNTO event file loader
178class FileLoader {
179 std::ifstream _ifs;
180 size_t _size;
181
182public:
183 explicit FileLoader(const char *filename) : _ifs(filename, std::ios::binary | std::ios::in) {
184 if (!_ifs.is_open() || _ifs.fail())
185 throw std::runtime_error("unable to open file");
186
187 _ifs.seekg(0, _ifs.end);
188 _size = _ifs.tellg();
189 _ifs.seekg(0, _ifs.beg);
190 }
191
192 bool read(char *s, std::streamsize n) { return static_cast<bool>(_ifs.read(s, n)); }
193
194 size_t size() const { return _size; }
195
196 size_t position() { return _ifs.tellg(); }
197
198 size_t selected_position() { return _ifs.tellg(); }
199};
200
201} // anonymous namespace
202
203namespace PLN {
204
205//
206// In the future the ANSTO helper and event file loader will be generalized to
207// handle the instruments consistently.
208
209// Simple 1D histogram class
211 std::vector<size_t> m_hist;
212 double m_M;
213 double m_B;
214 size_t m_peak;
215 size_t m_count;
216
217public:
218 SimpleHist(size_t N, double minVal, double maxVal) : m_hist(N, 0) {
219 m_M = (static_cast<double>(N) / (maxVal - minVal));
220 m_B = -m_M * minVal;
221 m_peak = 0;
222 m_count = 0;
223 }
224
225 inline double ival(double val) const { return m_M * val + m_B; }
226
227 inline double xval(double ix) const { return (ix - m_B) / m_M; }
228
229 inline void add(double val) {
230 auto ix = static_cast<size_t>(std::floor(ival(val)));
231 if (ix < m_hist.size()) {
232 m_hist[ix]++;
233 m_count++;
234 if (m_hist[ix] > m_peak)
235 m_peak = m_hist[ix];
236 }
237 }
238
239 const std::vector<size_t> &histogram() const { return m_hist; }
240
241 inline size_t peak() const { return m_peak; }
242 inline size_t count() const { return m_count; }
243};
244
246protected:
247 // fields
248 const std::vector<bool> &m_roi;
249 const std::vector<size_t> &m_mapIndex;
250 const double m_framePeriod;
251 const double m_gatePeriod;
252
253 // number of frames
254 size_t m_frames;
256
257 // number of events
261
262 // time boundaries
263 const TimeLimits m_timeBoundary; // seconds
264
265 virtual void addEventImpl(size_t id, size_t x, size_t y, double tof) = 0;
266
267public:
268 EventProcessor(const std::vector<bool> &roi, const std::vector<size_t> &mapIndex, const double framePeriod,
269 const double gatePeriod, const TimeLimits &timeBoundary, size_t maxEvents)
270 : m_roi(roi), m_mapIndex(mapIndex), m_framePeriod(framePeriod), m_gatePeriod(gatePeriod), m_frames(0),
272 m_timeBoundary(timeBoundary) {}
273
274 void newFrame() {
276 m_frames++;
277 if (validFrame())
279 }
280 }
281
282 inline bool validFrame() const {
283 double frameTime = m_framePeriod * static_cast<double>(m_frames) * 1.0e-6;
284 return (frameTime >= m_timeBoundary.first && frameTime <= m_timeBoundary.second);
285 }
286
287 double duration() const {
288 // length test in seconds
289 return m_framePeriod * static_cast<double>(m_frames) * 1.0e-6;
290 }
291
292 inline int64_t frameStart() const {
293 // returns time in nanoseconds from start of test
294 auto start = m_framePeriod * static_cast<double>(m_frames);
295 return static_cast<int64_t>(start * 1.0e3);
296 }
297
298 size_t numFrames() const { return m_framesValid; }
299
301
302 size_t processedEvents() const { return m_processedEvents; }
303
304 void addEvent(size_t x, size_t p, double tof, double /*taux*/) {
305
306 // check if in time boundaries
307 if (!validFrame())
308 return;
309
310 // group pixels
311 auto y = static_cast<size_t>(p / HISTO_BINS_Y_DENUMERATOR);
312
313 // determine detector id and check limits
314 if (x >= HISTO_BINS_X || y >= PIXELS_PER_TUBE)
315 return;
316
317 // map the raw detector index to the physical model
318 size_t xid = m_mapIndex[x];
319
320 size_t id = xid < DETECTOR_TUBES ? PIXELS_PER_TUBE * xid + y : DETECTOR_SPECTRA + xid;
321 if (id >= m_roi.size())
322 return;
323
324 // check if neutron is in region of interest
325 if (!m_roi[id])
326 return;
327
328 // finally pass to specific handler
330 // take the modulus of the tof time to account for the
331 // longer background chopper rate
332 double mtof = tof < 0.0 ? fmod(tof + m_gatePeriod, m_gatePeriod) : fmod(tof, m_gatePeriod);
333
334 addEventImpl(id, xid, y, mtof);
336 } else {
338 }
339 }
340};
341
342// The class determines the number of counts linked to the detectors and the
343// tof correction.
345protected:
346 // fields
347 std::vector<size_t> &m_eventCounts;
348 double m_L1;
349 double m_V0;
350 const std::vector<double> &m_L2;
352
353 void addEventImpl(size_t id, size_t /*x*/, size_t /*y*/, double tobs) override {
354 m_eventCounts[id]++;
355 // the maximum occurs at the elastic peak
356 double deltaT = 1.0e6 * (m_L1 + m_L2[id]) / m_V0 - tobs;
357 m_histogram.add(deltaT);
358 }
359
360public:
361 // construction
362 EventCounter(const std::vector<bool> &roi, const std::vector<size_t> &mapIndex, const double framePeriod,
363 const double gatePeriod, const TimeLimits &timeBoundary, std::vector<size_t> &eventCounts,
364 const double L1, const double V0, const std::vector<double> &vecL2, size_t maxEvents)
365 : EventProcessor(roi, mapIndex, framePeriod, gatePeriod, timeBoundary, maxEvents), m_eventCounts(eventCounts),
366 m_L1(L1), m_V0(V0), m_L2(vecL2), m_histogram(5000, -2500.0, 2500.0) {}
367
368 // clips the histogram above 25% and takes the mean of the values
369 double tofCorrection() {
370
371 // determine the points above the 25% threshold
372 auto minLevel = static_cast<size_t>(m_histogram.peak() / 4);
373 auto hvec = m_histogram.histogram();
374 double sum = 0.0;
375 size_t count = 0;
376 for (size_t i = 0; i < hvec.size(); i++) {
377 if (hvec[i] >= minLevel) {
378 auto ix = static_cast<double>(i);
379 sum += static_cast<double>(hvec[i]) * m_histogram.xval(ix + 0.5);
380 count += hvec[i];
381 }
382 }
383
384 return (count > 0 ? sum / static_cast<double>(count) : 0.0);
385 }
386};
387
389protected:
390 // fields
391 std::vector<EventVector_pt> &m_eventVectors;
392 double m_tofMin;
393 double m_tofMax;
394 int64_t m_startTime;
397
398 void addEventImpl(size_t id, size_t /*x*/, size_t /*y*/, double tobs) override {
399
400 // get the absolute time for the start of the frame
401 auto const offset = m_startTime + frameStart();
402
403 // adjust the tof to account for the correction and allocate events
404 // that occur before the sample time as slow events from the previous pulse
405 double tof = tobs + m_tofCorrection - m_sampleTime;
406 if (tof < 0.0)
407 tof = fmod(tof + m_gatePeriod, m_gatePeriod);
408 tof += m_sampleTime;
409 if (m_tofMin > tof)
410 m_tofMin = tof;
411 if (m_tofMax < tof)
412 m_tofMax = tof;
413
414 auto ev = Types::Event::TofEvent(tof, Types::Core::DateAndTime(offset));
415 m_eventVectors[id]->emplace_back(ev);
416 }
417
418public:
419 EventAssigner(const std::vector<bool> &roi, const std::vector<size_t> &mapIndex, const double framePeriod,
420 const double gatePeriod, const TimeLimits &timeBoundary, std::vector<EventVector_pt> &eventVectors,
421 int64_t startTime, double tofCorrection, double sampleTime, size_t maxEvents)
422 : EventProcessor(roi, mapIndex, framePeriod, gatePeriod, timeBoundary, maxEvents), m_eventVectors(eventVectors),
423 m_tofMin(std::numeric_limits<double>::max()), m_tofMax(std::numeric_limits<double>::min()),
424 m_startTime(startTime), m_tofCorrection(tofCorrection), m_sampleTime(sampleTime) {}
425
426 double tofMin() const { return m_tofMin <= m_tofMax ? m_tofMin : 0.0; }
427 double tofMax() const { return m_tofMin <= m_tofMax ? m_tofMax : 0.0; }
428};
429
430template <typename EP>
431void loadEvents(API::Progress &prog, const char *progMsg, const std::string &eventFile, EP &eventProcessor) {
432
433 using namespace ANSTO;
434
435 prog.doReport(progMsg);
436
437 FileLoader loader(eventFile.c_str());
438
439 // for progress notifications
440 ANSTO::ProgressTracker progTracker(prog, progMsg, loader.size(), Progress_LoadBinFile);
441
442 ReadEventFile(loader, eventProcessor, progTracker, 100, false);
443}
444} // namespace PLN
445
449
450 // Specify file extensions which can be associated with a specific file.
451 std::vector<std::string> exts;
452
453 // Declare the Filename algorithm property. Mandatory. Sets the path to the
454 // file to load.
455 exts.clear();
456 exts.emplace_back(".hdf");
457 declareProperty(std::make_unique<API::FileProperty>(FilenameStr, "", API::FileProperty::Load, exts),
458 "The input filename of the stored data");
459
460 declareProperty(PathToBinaryStr, "./", std::make_shared<Kernel::MandatoryValidator<std::string>>(),
461 "Relative or absolute path to the compressed binary\n"
462 "event file linked to the HDF file, eg /storage/data/");
463
464 // mask
465 exts.clear();
466 exts.emplace_back(".xml");
467 declareProperty(std::make_unique<API::FileProperty>(MaskStr, "", API::FileProperty::OptionalLoad, exts),
468 "The input filename of the mask data");
469
470 declareProperty(SelectDetectorTubesStr, "",
471 "Comma separated range of detectors tubes to be loaded,\n"
472 " eg 16,19-45,47");
473
475 std::make_unique<API::WorkspaceProperty<API::IEventWorkspace>>("OutputWorkspace", "", Kernel::Direction::Output));
476
477 declareProperty(SelectDatasetStr, 0, "Select the index for the dataset to be loaded.");
478
479 declareProperty(TOFBiasStr, 0.0, "Time of flight correction in micro-sec.");
480
481 declareProperty(CalibrateTOFStr, false, "Calibrate the TOF correction from the elastic pulse.");
482
483 declareProperty(LambdaOnTwoStr, false, "Instrument is operating in Lambda on Two mode.");
484
486 "Only include events after the provided start time, in "
487 "seconds (relative to the start of the run).");
488
490 "Only include events before the provided stop time, in "
491 "seconds (relative to the start of the run).");
492
493 std::string grpOptional = "Filters";
496}
497
499void LoadPLN::createWorkspace(const std::string &title) {
500
501 // Create the workspace
502 m_localWorkspace = std::make_shared<DataObjects::EventWorkspace>();
503 m_localWorkspace->initialize(HISTOGRAMS, 2, 1);
504
505 // set the units
506 m_localWorkspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
507 m_localWorkspace->setYUnit("Counts");
508
509 // set title
510 m_localWorkspace->setTitle(title);
511}
512
520
521void LoadPLN::exec(const std::string &hdfFile, const std::string &eventFile) {
522
523 namespace fs = std::filesystem;
524
525 // Create workspace
526 // ----------------
527 fs::path p = hdfFile;
528 for (; !p.extension().empty();)
529 p = p.stem();
530 std::string title = p.generic_string();
531 createWorkspace(title);
532 API::LogManager &logManager = m_localWorkspace->mutableRun();
533 API::Progress prog(this, 0.0, 1.0, Progress_Total);
534
535 // Load instrument and workspace properties
536 logManager.addProperty(SelectDatasetStr, m_datasetIndex);
537 loadParameters(hdfFile, logManager);
538 prog.doReport("creating instrument");
540
541 // Get the region of interest and filters and save to log
542 std::string const maskfile = getPropertyValue(MaskStr);
543 std::string const seltubes = getPropertyValue(SelectDetectorTubesStr);
544 logManager.addProperty(SelectDetectorTubesStr, seltubes);
545 logManager.addProperty(MaskStr, maskfile);
546
547 std::vector<bool> roi = createRoiVector(seltubes, maskfile);
548 double timeMaxBoundary = getProperty(FilterByTimeStopStr);
549 if (isEmpty(timeMaxBoundary))
550 timeMaxBoundary = std::numeric_limits<double>::infinity();
551 TimeLimits timeBoundary(getProperty(FilterByTimeStartStr), timeMaxBoundary);
552
553 // get the detector map from raw input to a physical detector
554 auto instr = m_localWorkspace->getInstrument();
555 std::string dmapStr = instr->getParameterAsString("DetectorMap");
556 std::vector<size_t> detMapIndex = std::vector<size_t>(HISTO_BINS_X, 0);
557 mapRangeToIndex(dmapStr, detMapIndex, [](size_t n) { return n; });
558
559 // Load the events file. First count the number of events to reserve
560 // memory and then assign the events to the detectors
561 size_t numberHistograms = m_localWorkspace->getNumberHistograms();
562 std::vector<EventVector_pt> eventVectors(numberHistograms, nullptr);
563 std::vector<size_t> eventCounts(numberHistograms, 0);
564
565 double masterRpm = fabs(logManager.getTimeSeriesProperty<double>("FermiChopperFreq")->firstValue());
566 double slaveRpm = fabs(logManager.getTimeSeriesProperty<double>("OverlapChopperFreq")->firstValue());
567 double framePeriod = 1.0e6 / masterRpm;
568
569 // if fermi chopper freq equals the overlap freq then the gate period is
570 // half the frame period
571 double gatePeriod = (std::round(masterRpm / slaveRpm) == 1.0 ? 0.5 * framePeriod : framePeriod);
572 AddSinglePointTimeSeriesProperty<double>(logManager, m_startRun, "GatePeriod", gatePeriod);
573
574 // count total events per pixel and reserve necessary memory
575 size_t hdfCounts = static_cast<size_t>(logManager.getTimeSeriesProperty<int>("TotalCounts")->firstValue());
577 double sourceSample = fabs(instr->getSource()->getPos().Z());
578 double wavelength = logManager.getTimeSeriesProperty<double>("Wavelength")->firstValue();
579 double velocity = PhysicalConstants::h / (PhysicalConstants::NeutronMass * wavelength * 1e-10);
580 double sampleTime = 1.0e6 * sourceSample / velocity;
581 PLN::EventCounter eventCounter(roi, detMapIndex, framePeriod, gatePeriod, timeBoundary, eventCounts, sourceSample,
582 velocity, m_detectorL2, hdfCounts);
583 PLN::loadEvents(prog, "loading neutron counts", eventFile, eventCounter);
584 ANSTO::ProgressTracker progTracker(prog, "creating neutron event lists", numberHistograms, Progress_ReserveMemory);
585 prepareEventStorage(progTracker, eventCounts, eventVectors);
586
587 // log a message if the number of events in the event file does not match
588 // the total counts in the hdf
589 if (hdfCounts != eventCounter.availableEvents()) {
590 g_log.error("HDF and event counts differ: " + std::to_string(hdfCounts) + ", " +
591 std::to_string(eventCounter.availableEvents()));
592 }
593
594 // now perform the actual event collection and TOF convert if necessary
595 // if a phase calibration is required then load it as raw doppler time
596 // perform the calibration and then convert to TOF
597 Types::Core::DateAndTime startTime(m_startRun);
598 auto const start_nanosec = startTime.totalNanoseconds();
599 bool const calibrateTOF = getProperty(CalibrateTOFStr);
600 double tofCorrection = getProperty(TOFBiasStr);
601 if (calibrateTOF) {
602 tofCorrection = eventCounter.tofCorrection();
603 }
604 logManager.addProperty("CalibrateTOF", (calibrateTOF ? 1 : 0));
605 AddSinglePointTimeSeriesProperty<double>(logManager, m_startRun, "TOFCorrection", tofCorrection);
606 PLN::EventAssigner eventAssigner(roi, detMapIndex, framePeriod, gatePeriod, timeBoundary, eventVectors, start_nanosec,
607 tofCorrection, sampleTime, hdfCounts);
608 PLN::loadEvents(prog, "loading neutron events (TOF)", eventFile, eventAssigner);
609
610 // perform a calibration and then TOF conversion if necessary
611 // and update the tof limits
612 auto minTOF = eventAssigner.tofMin();
613 auto maxTOF = eventAssigner.tofMax();
614
615 // just to make sure the bins hold it all and setup the detector masks
616 m_localWorkspace->setAllX(HistogramData::BinEdges{std::max(0.0, floor(minTOF)), maxTOF + 1});
618
619 // set log values
620 auto frame_count = static_cast<int>(eventCounter.numFrames());
621 AddSinglePointTimeSeriesProperty<int>(logManager, m_startRun, "frame_count", frame_count);
622
623 std::string filename = getPropertyValue(FilenameStr);
624 logManager.addProperty("filename", filename);
625
626 Types::Core::time_duration duration =
627 boost::posix_time::microseconds(static_cast<boost::int64_t>(eventCounter.duration() * 1.0e6));
628 Types::Core::DateAndTime endTime(startTime + duration);
629 logManager.addProperty("start_time", startTime.toISO8601String());
630 logManager.addProperty("end_time", endTime.toISO8601String());
631 logManager.addProperty<double>("dur", eventCounter.duration());
632
633 // Finally add the time-series evironment parameters explicitly
634 loadEnvironParameters(hdfFile, logManager);
635
636 setProperty("OutputWorkspace", m_localWorkspace);
637}
638
641
642 m_detectorL2.resize(HISTOGRAMS, 0.0);
643 const auto &detectorInfo = m_localWorkspace->detectorInfo();
644 auto detIDs = detectorInfo.detectorIDs();
645 for (const auto detID : detIDs) {
646 auto ix = detectorInfo.indexOf(detID);
647 double l2 = detectorInfo.l2(ix);
648 m_detectorL2[detID] = l2;
649 }
650}
651
653void LoadPLN::setupDetectorMasks(const std::vector<bool> &roi) {
654
655 // count total number of masked bins
656 size_t maskedBins = 0;
657 for (size_t i = 0; i != roi.size(); i++)
658 if (!roi[i])
659 maskedBins++;
660
661 if (maskedBins > 0) {
662 // create list of masked bins
663 std::vector<size_t> maskIndexList(maskedBins);
664 size_t maskIndex = 0;
665
666 for (size_t i = 0; i != roi.size(); i++)
667 if (!roi[i])
668 maskIndexList[maskIndex++] = i;
669
670 auto maskingAlg = createChildAlgorithm("MaskDetectors");
671 maskingAlg->setProperty("Workspace", m_localWorkspace);
672 maskingAlg->setProperty("WorkspaceIndexList", maskIndexList);
673 maskingAlg->executeAsChildAlg();
674 }
675}
676
679void LoadPLN::prepareEventStorage(ANSTO::ProgressTracker &progTracker, std::vector<size_t> &eventCounts,
680 std::vector<EventVector_pt> &eventVectors) {
681
682 size_t numberHistograms = eventCounts.size();
683 for (size_t i = 0; i != numberHistograms; ++i) {
684 DataObjects::EventList &eventList = m_localWorkspace->getSpectrum(i);
685
687 eventList.reserve(eventCounts[i]);
688
689 eventList.setDetectorID(static_cast<detid_t>(i));
690 eventList.setSpectrumNo(static_cast<detid_t>(i));
691
692 DataObjects::getEventsFrom(eventList, eventVectors[i]);
693
694 progTracker.update(i);
695 }
696 progTracker.complete();
697}
698
701std::vector<bool> LoadPLN::createRoiVector(const std::string &selected, const std::string &maskfile) {
702
703 std::vector<bool> result(HISTOGRAMS, true);
704
705 // turn off pixels linked to missing tubes
706 if (!selected.empty()) {
707 std::vector<bool> tubes(HISTO_BINS_X, false);
708 mapRangeToIndex(selected, tubes, [](size_t) { return true; });
709 for (size_t i = 0; i < DETECTOR_TUBES; i++) {
710 if (tubes[i] == false) {
711 for (size_t j = 0; j < PIXELS_PER_TUBE; j++) {
712 result[i * PIXELS_PER_TUBE + j] = false;
713 }
714 }
715 }
716 for (size_t i = 0; i < MONITORS; i++) {
717 result[DETECTOR_SPECTRA + i] = tubes[DETECTOR_TUBES + i];
718 }
719 }
720
721 if (maskfile.length() == 0)
722 return result;
723
724 std::ifstream input(maskfile.c_str());
725 if (!input.good())
726 throw std::invalid_argument("invalid mask file");
727
728 std::string line;
729 while (std::getline(input, line)) {
730 auto i0 = line.find("<detids>");
731 auto iN = line.find("</detids>");
732
733 if ((i0 != std::string::npos) && (iN != std::string::npos) && (i0 < iN)) {
734 line = line.substr(i0 + 8, iN - i0 - 8); // 8 = len("<detids>")
735 mapRangeToIndex(line, result, [](size_t) { return false; });
736 }
737 }
738
739 return result;
740}
741
743void LoadPLN::loadParameters(const std::string &hdfFile, API::LogManager &logm) {
744
745 Nexus::NXRoot root(hdfFile);
746 Nexus::NXEntry entry = root.openFirstEntry();
747
748 MapNeXusToProperty<std::string>(entry, "sample/name", "unknown", logm, "SampleName", "", 0);
749 MapNeXusToProperty<std::string>(entry, "sample/description", "unknown", logm, "SampleDescription", "", 0);
750
751 // if dataset index > 0 need to add an offset to the start time
752 Types::Core::DateAndTime startTime(GetNeXusValue<std::string>(entry, "start_time", "2000-01-01T00:00:00", 0));
753 if (m_datasetIndex > 0) {
754 auto baseTime = GetNeXusValue<int32_t>(entry, "instrument/detector/start_time", 0, 0);
755 auto nthTime = GetNeXusValue<int32_t>(entry, "instrument/detector/start_time", 0, m_datasetIndex);
756
757 Types::Core::time_duration duration =
758 boost::posix_time::microseconds((static_cast<int64_t>(nthTime) - static_cast<int64_t>(baseTime)) * 1'000'000);
759 Types::Core::DateAndTime startDataset(startTime + duration);
760 m_startRun = startDataset.toISO8601String();
761 } else {
762 m_startRun = startTime.toISO8601String();
763 }
764
765 // Add support for instrument running in lambda on two mode.
766 // Added as UI option as the available instrument parameters
767 // cannot be reliably interpreted to predict the mode (as
768 // advised by the instrument scientist).
769 bool const lambdaOnTwoMode = getProperty(LambdaOnTwoStr);
770 double lambdaFactor = (lambdaOnTwoMode ? 0.5 : 1.0);
771 logm.addProperty("LambdaOnTwoMode", (lambdaOnTwoMode ? 1 : 0));
772
773 MapNeXusToSeries<double>(entry, "instrument/fermi_chopper/mchs", 0.0, logm, m_startRun, "FermiChopperFreq", 1.0 / 60,
775 MapNeXusToSeries<double>(entry, "instrument/fermi_chopper/schs", 0.0, logm, m_startRun, "OverlapChopperFreq",
776 1.0 / 60, m_datasetIndex);
777 MapNeXusToSeries<double>(entry, "instrument/crystal/wavelength", 0.0, logm, m_startRun, "Wavelength", lambdaFactor,
779 MapNeXusToSeries<double>(entry, "instrument/detector/stth", 0.0, logm, m_startRun, "DetectorTankAngle", 1.0,
781 MapNeXusToSeries<int32_t>(entry, "monitor/bm1_counts", 0, logm, m_startRun, "MonitorCounts", 1, m_datasetIndex);
782 MapNeXusToSeries<int32_t>(entry, "data/total_counts", 0, logm, m_startRun, "TotalCounts", 1, m_datasetIndex);
783 MapNeXusToSeries<double>(entry, "data/tofw", 5.0, logm, m_startRun, "ChannelWidth", 1, m_datasetIndex);
784 MapNeXusToSeries<double>(entry, "sample/mscor", 0.0, logm, m_startRun, "SampleRotation", 1, m_datasetIndex);
785}
786
789void LoadPLN::loadEnvironParameters(const std::string &hdfFile, API::LogManager &logm) {
790
791 Nexus::NXRoot root(hdfFile);
792 Nexus::NXEntry entry = root.openFirstEntry();
793 auto time_str = logm.getPropertyValueAsType<std::string>("end_time");
794
795 // load the environment variables for the dataset loaded
796 auto tags = ANSTO::filterDatasets(entry, "data/", "^[A-Z]{1,3}[0-9]{1,3}[A-Z]{1,3}[0-9]{1,3}$");
797 for (const auto &tag : tags) {
798 MapNeXusToSeries<double>(entry, "data/" + tag, 0.0, logm, time_str, "env_" + tag, 1.0, m_datasetIndex);
799 }
800}
801
804
805 // loads the IDF and parameter file
806 auto loadInstrumentAlg = createChildAlgorithm("LoadInstrument");
807 loadInstrumentAlg->setProperty("Workspace", m_localWorkspace);
808 loadInstrumentAlg->setPropertyValue("InstrumentName", "PELICAN");
809 loadInstrumentAlg->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(false));
810 loadInstrumentAlg->executeAsChildAlg();
811}
812
814int LoadPLN::version() const { return 1; }
815
817const std::vector<std::string> LoadPLN::seeAlso() const { return {"Load", "LoadEMU"}; }
819const std::string LoadPLN::category() const { return "DataHandling\\ANSTO"; }
820
822const std::string LoadPLN::name() const { return "LoadPLN"; }
823
825const std::string LoadPLN::summary() const { return "Loads a PLN Hdf and linked event file into a workspace."; }
826
830 if (descriptor.extension() != ".hdf")
831 return 0;
832
833 if (descriptor.isEntry("/entry1/site_name") && descriptor.isEntry("/entry1/instrument/fermi_chopper") &&
834 descriptor.isEntry("/entry1/instrument/aperture/sh1") &&
835 descriptor.isEntry("/entry1/instrument/ag1010/MEAS/Temperature") &&
836 descriptor.isEntry("/entry1/instrument/detector/daq_dirname") &&
837 descriptor.isEntry("/entry1/instrument/detector/dataset_number") && descriptor.isEntry("/entry1/data/hmm") &&
838 descriptor.isEntry("/entry1/data/time_of_flight") && descriptor.isEntry("/entry1/data/total_counts")) {
839 return 80;
840 } else {
841 return 0;
842 }
843}
844
847// exec() function that works with the two files.
849
850 namespace fs = std::filesystem;
851
852 // Open the hdf file and find the dirname and dataset number
853 std::string hdfFile = getPropertyValue(FilenameStr);
854 std::string evtPath = getPropertyValue(PathToBinaryStr);
855 if (evtPath.empty())
856 evtPath = "./";
857
858 // if relative ./ or ../ then append to the directory for the hdf file
859 if (evtPath.rfind("./") == 0 || evtPath.rfind("../") == 0) {
860 fs::path hp(hdfFile);
861 evtPath = fs::canonical(hp.parent_path() / evtPath).string();
862 }
863
864 // dataset index to be loaded
865 m_datasetIndex = getProperty(SelectDatasetStr);
866
867 // if path provided build the file path from the directory name and dataset
868 // number from the hdf file, however if this is not a valid path then try
869 // the basename with a '.bin' extension
870 if (fs::is_directory(evtPath)) {
871 Nexus::NXRoot root(hdfFile);
872 Nexus::NXEntry entry = root.openFirstEntry();
873 auto eventDir = GetNeXusValue<std::string>(entry, "instrument/detector/daq_dirname", "./", 0);
874 auto dataset = GetNeXusValue<int32_t>(entry, "instrument/detector/dataset_number", 0, m_datasetIndex);
875 if (dataset < 0) {
876 std::string message("Negative dataset index recorded in HDF, reset to zero!");
877 g_log.error(message);
878 dataset = 0;
879 }
880
881 // build the path to the event file using the standard storage convention at ansto:
882 // 'relpath/[daq_dirname]/DATASET_[n]/EOS.bin'
883 // but if the file is missing, try relpath/{source}.bin
884 std::stringstream buffer;
885 buffer << eventDir.c_str() << "/DATASET_" << dataset << "/EOS.bin";
886 fs::path filePath = evtPath;
887 filePath /= buffer.str();
888 filePath = fs::absolute(filePath);
889 std::string nomPath = filePath.generic_string();
890 if (fs::is_regular_file(nomPath)) {
891 evtPath = nomPath;
892 } else {
893 fs::path hp = hdfFile;
894 buffer.str("");
895 buffer.clear();
896 buffer << hp.stem().generic_string().c_str() << ".bin";
897 fs::path path = evtPath;
898 path /= buffer.str();
899 path = fs::absolute(path);
900 evtPath = path.generic_string();
901 }
902 }
903
904 // finally check that the event file exists
905 if (!fs::is_regular_file(evtPath)) {
906 std::string msg = "Check path, cannot open binary event file: " + evtPath;
907 throw std::runtime_error(msg);
908 }
909
910 exec(hdfFile, evtPath);
911}
912
913// register the algorithms into the AlgorithmFactory
915
916} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
double position
Definition GetAllEi.cpp:154
std::map< DeltaEMode::Type, std::string > index
size_t _size
Definition LoadEMU.cpp:334
std::ifstream _ifs
Definition LoadEMU.cpp:333
#define fabs(x)
Definition Matrix.cpp:22
int count
counter
Definition Matrix.cpp:37
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
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
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
void setDetectorID(const detid_t detID)
Clear the list of detector IDs, then add one.
Definition ISpectrum.cpp:84
void setSpectrumNo(specnum_t num)
Sets the spectrum number of this spectrum.
This class contains the information about the log entries.
Definition LogManager.h:44
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:91
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
Kernel::TimeSeriesProperty< T > * getTimeSeriesProperty(const std::string &name) const
Returns a property as a time series property.
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
A property class for workspaces.
helper class to keep track of progress
LoadPLN : Loads an ANSTO PLN Hdf and linked event file into a workspace.
Definition LoadPLN.h:58
std::vector< double > m_detectorL2
Definition LoadPLN.h:101
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
Definition LoadPLN.cpp:825
const std::vector< std::string > seeAlso() const override
Similar algorithms.
Definition LoadPLN.cpp:817
void prepareEventStorage(ANSTO::ProgressTracker &prog, std::vector< size_t > &eventCounts, std::vector< EventVector_pt > &eventVectors)
Allocate space for the event storage in eventVectors after the eventCounts have been determined.
Definition LoadPLN.cpp:679
int version() const override
Algorithm's version for identification.
Definition LoadPLN.cpp:814
void setupDetectorMasks(const std::vector< bool > &roi)
Set up the detector masks to the region of interest roi.
Definition LoadPLN.cpp:653
void loadEnvironParameters(const std::string &hdfFile, API::LogManager &logm)
Load the environment variables from the hdfFile and save as time series to the log manager,...
Definition LoadPLN.cpp:789
DataObjects::EventWorkspace_sptr m_localWorkspace
Definition LoadPLN.h:98
void init() override
Initialise the algorithm and declare the properties for the nexus descriptor.
Definition LoadPLN.cpp:448
void createWorkspace(const std::string &title)
Creates an event workspace and sets the title.
Definition LoadPLN.cpp:499
void loadParameters(const std::string &hdfFile, API::LogManager &logm)
Load parameters from input hdfFile and save to the log manager, logm.
Definition LoadPLN.cpp:743
int confidence(Nexus::NexusDescriptor &descriptor) const override
Return the confidence as an integer value that this algorithm can load the file descriptor.
Definition LoadPLN.cpp:829
void loadDetectorL2Values()
Recovers the L2 neutronic distance for each detector.
Definition LoadPLN.cpp:640
void loadInstrument()
Load the instrument definition.
Definition LoadPLN.cpp:803
std::vector< bool > createRoiVector(const std::string &seltubes, const std::string &maskfile)
Region of interest is defined by the selected detectors and the maskfile.
Definition LoadPLN.cpp:701
const std::string name() const override
Algorithms name for identification.
Definition LoadPLN.cpp:822
void exec() override
Execute the algorithm.
Definition LoadPLN.cpp:848
const std::string category() const override
Algorithm's category for identification.
Definition LoadPLN.cpp:819
EventAssigner(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const double framePeriod, const double gatePeriod, const TimeLimits &timeBoundary, std::vector< EventVector_pt > &eventVectors, int64_t startTime, double tofCorrection, double sampleTime, size_t maxEvents)
Definition LoadPLN.cpp:419
std::vector< EventVector_pt > & m_eventVectors
Definition LoadPLN.cpp:391
void addEventImpl(size_t id, size_t, size_t, double tobs) override
Definition LoadPLN.cpp:398
std::vector< size_t > & m_eventCounts
Definition LoadPLN.cpp:347
EventCounter(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const double framePeriod, const double gatePeriod, const TimeLimits &timeBoundary, std::vector< size_t > &eventCounts, const double L1, const double V0, const std::vector< double > &vecL2, size_t maxEvents)
Definition LoadPLN.cpp:362
void addEventImpl(size_t id, size_t, size_t, double tobs) override
Definition LoadPLN.cpp:353
const std::vector< double > & m_L2
Definition LoadPLN.cpp:350
const std::vector< bool > & m_roi
Definition LoadPLN.cpp:248
void addEvent(size_t x, size_t p, double tof, double)
Definition LoadPLN.cpp:304
const std::vector< size_t > & m_mapIndex
Definition LoadPLN.cpp:249
virtual void addEventImpl(size_t id, size_t x, size_t y, double tof)=0
EventProcessor(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const double framePeriod, const double gatePeriod, const TimeLimits &timeBoundary, size_t maxEvents)
Definition LoadPLN.cpp:268
double ival(double val) const
Definition LoadPLN.cpp:225
double xval(double ix) const
Definition LoadPLN.cpp:227
SimpleHist(size_t N, double minVal, double maxVal)
Definition LoadPLN.cpp:218
const std::vector< size_t > & histogram() const
Definition LoadPLN.cpp:239
A class for holding :
Definition EventList.h:57
void setSortOrder(const EventSortType order) const
Manually set the event list sort order value.
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
Validator to check that a property is not left empty.
OptionalBool : Tri-state bool.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
const std::string & extension() const
Access the file extension.
void ReadEventFile(IReader &loader, IEventHandler &handler, IProgress &progress, int32_t def_clock_scale, bool use_tx_chopper)
std::vector< std::string > filterDatasets(const Nexus::NXEntry &entry, const std::string &groupAddress, const std::string &regexFilter)
extract datasets from a group that match a regex filter
void loadEvents(API::Progress &prog, const char *progMsg, const std::string &eventFile, EP &eventProcessor)
Definition LoadPLN.cpp:431
static char const *const FilenameStr
Definition LoadBBY.cpp:55
static const size_t HISTO_BINS_X
Definition LoadBBY.cpp:48
static const size_t Progress_LoadBinFile
Definition LoadBBY.cpp:51
void AddSinglePointTimeSeriesProperty(API::LogManager &logManager, const std::string &time, const std::string &name, const TYPE value)
Definition LoadBBY.cpp:67
static char const *const MaskStr
Definition LoadBBY.cpp:56
static char const *const FilterByTimeStartStr
Definition LoadBBY.cpp:61
static const size_t Progress_Total
Definition LoadBBY.cpp:53
static char const *const FilterByTimeStopStr
Definition LoadBBY.cpp:62
static const size_t Progress_ReserveMemory
Definition LoadBBY.cpp:52
DLLExport void getEventsFrom(EventList &el, std::vector< Types::Event::TofEvent > *&events)
NXDataSetTyped< float > NXFloat
The float dataset type.
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.
Definition Property.h:54