26#include <boost/math/special_functions/round.hpp>
27#include <boost/math/tools/minima.hpp>
29#include <Poco/AutoPtr.h>
30#include <Poco/TemporaryFile.h>
31#include <Poco/Util/PropertyFileConfiguration.h>
45constexpr size_t HORIZONTAL_TUBES = 16;
46constexpr size_t VERTICAL_TUBES = 35;
47constexpr size_t DETECTOR_TUBES = HORIZONTAL_TUBES + VERTICAL_TUBES;
51constexpr size_t HISTO_BINS_Y_DENUMERATOR = 16;
52constexpr size_t PIXELS_PER_TUBE =
HISTO_BINS_Y / HISTO_BINS_Y_DENUMERATOR;
54constexpr size_t BM_HISTOGRAMS =
HISTO_BINS_X * PIXELS_PER_TUBE;
55constexpr size_t HISTOGRAMS = BM_HISTOGRAMS + PIXELS_PER_TUBE;
56constexpr size_t BEAM_MONITOR_BINS = 100;
57constexpr size_t PSEUDO_BM_TUBE = 55;
59constexpr size_t BM_HALF_WINDOW = 5;
69constexpr char SelectDetectorTubesStr[] =
"SelectDetectorTubes";
70constexpr char SelectDatasetStr[] =
"SelectDataset";
71constexpr char OverrideDopplerFreqStr[] =
"OverrideDopplerFrequency";
72constexpr char OverrideDopplerPhaseStr[] =
"OverrideDopplerPhase";
75constexpr char RawDopplerTimeStr[] =
"LoadAsRawDopplerTime";
76constexpr char IncludePseudoBMStr[] =
"IncludeBeamMonitor";
77constexpr char CalibrateDopplerPhaseStr[] =
"CalibrateDopplerPhase";
78constexpr char PathToBinaryStr[] =
"BinaryEventPath";
81using TimeLimits = std::pair<double, double>;
83template <
typename Type>
88 p->addValue(time,
value);
96template <
typename Type>
97Type GetNeXusValue(
const Nexus::NXEntry &entry,
const std::string &address,
const Type &defval, int32_t
index) {
102 return dataSet()[
index];
103 }
catch (std::runtime_error &) {
109double GetNeXusValue<double>(
const Nexus::NXEntry &entry,
const std::string &address,
const double &defval,
115 return dataSet()[
index];
116 }
catch (std::runtime_error &) {
121std::string GetNeXusValue<std::string>(
const Nexus::NXEntry &entry,
const std::string &address,
122 const std::string &defval, int32_t ) {
125 return entry.getString(address);
126 }
catch (std::runtime_error &) {
132void MapNeXusToProperty(
const Nexus::NXEntry &entry,
const std::string &address,
const T &defval,
133 API::LogManager &logManager,
const std::string &
name,
const T &factor, int32_t
index) {
135 T
value = GetNeXusValue<T>(entry, address, defval,
index);
136 logManager.addProperty<T>(
name,
value * factor);
141void MapNeXusToProperty<std::string>(Nexus::NXEntry
const &entry,
const std::string &address,
const std::string &defval,
142 API::LogManager &logManager,
const std::string &
name,
143 const std::string & , int32_t
index) {
145 std::string
const value = GetNeXusValue<std::string>(entry, address, defval,
index);
146 logManager.addProperty<std::string>(
name,
value);
150void MapNeXusToSeries(Nexus::NXEntry &entry,
const std::string &address,
const T &defval, API::LogManager &logManager,
151 const std::string &time,
const std::string &
name,
const T &factor, int32_t
index) {
153 auto value = GetNeXusValue<T>(entry, address, defval,
index);
154 AddSinglePointTimeSeriesProperty<T>(logManager, time,
name,
value * factor);
160template <
typename T,
typename F>
void mapRangeToIndex(
const std::string &line, std::vector<T> &result,
const F &fn) {
162 std::stringstream ss(line);
165 while (std::getline(ss, item,
',')) {
166 auto k = item.find(
'-');
169 if (k != std::string::npos) {
170 p0 = boost::lexical_cast<size_t>(item.substr(0, k));
171 p1 = boost::lexical_cast<size_t>(item.substr(k + 1, item.size() - k - 1));
173 p0 = boost::lexical_cast<size_t>(item);
177 if (p1 < result.size() && p0 <= p1) {
179 result[p0++] = fn(
index);
182 }
else if (p0 < result.size() && p1 < p0) {
184 result[p0] = fn(
index);
188 throw std::invalid_argument(
"invalid range specification");
194template <
typename F>
double invert(
double y,
const F &f,
double x0 = 0.0,
const double eps = 1e-16) {
196 double e0 = f(x0) -
y;
198 double x1 = x0 + eps;
199 double e1 = f(x1) -
y;
201 while (
fabs(e0) > eps && loop-- > 0) {
202 double x = (x1 * e0 - x0 * e1) / (e0 - e1);
219using TofData = std::tuple<double, double>;
227 const std::vector<double> &
m_L2;
229 inline double L1(
double t)
const {
return m_L0 +
m_A * sin(
m_w * t +
m_phi); }
231 inline double v1(
double t)
const {
return m_v2 -
m_A *
m_w * cos(m_w * t + m_phi); }
234 ConvertTOF(
double Amp,
double freq,
double phase,
double L1,
double v2,
const std::vector<double> &L2)
237 TofData directTOF(
size_t detID,
double tobs)
const {
240 auto tn = [=](
double t) {
return t + (L1(t) +
m_L2[detID]) / v1(t); };
242 double tsec = tobs * 1.0e-6;
243 double t0 = tsec - (
m_L0 +
m_L2[detID]) / m_v2;
244 double tinv = invert(tsec, tn, t0);
245 double tof = (
m_L0 +
m_L2[detID]) / v1(tinv);
247 return TofData(tinv * 1.0e6, tof * 1.0e6);
250 TofData analysedTOF(
size_t detID,
double tobs)
const {
252 auto tn = [=](
double t) {
return t + L1(t) / v1(t) +
m_L2[detID] /
m_v2; };
254 double tsec = tobs * 1.0e-6;
255 double t0 = tsec - (
m_L0 +
m_L2[detID]) / m_v2;
256 double t = invert(tsec, tn, t0);
259 return TofData(t * 1.0e6, tof * 1.0e6);
264double maskedMean(
const std::vector<double> &
vec,
const std::vector<bool> &mask) {
265 if (
vec.size() == 0 ||
vec.size() != mask.size())
266 throw std::runtime_error(
"masked mean of empty or mismatched vectors");
269 for (
size_t i = 0; i !=
vec.size(); i++) {
276 throw std::runtime_error(
"mean of empty vector");
277 return sum /
static_cast<double>(
count);
281double maskedStdev(
const std::vector<double> &
vec,
const std::vector<bool> &mask) {
283 auto avg = maskedMean(
vec, mask);
286 for (
size_t i = 0; i !=
vec.size(); i++) {
289 sum += (
vec[i] - avg) * (
vec[i] - avg);
292 return std::sqrt(sum /
static_cast<double>(
count));
304std::vector<double> runningAverage(
const std::vector<size_t> &data,
size_t halfWindow) {
305 const auto N = data.size();
306 const size_t totalWindow = 2 * halfWindow + 1;
311 size_t startIndex = N - halfWindow;
312 for (
size_t i = 0; i < totalWindow; i++) {
313 size_t ix = (startIndex + i) % N;
319 std::vector<double> filtered(N, 0);
320 for (
size_t i = 0; i < N; i++) {
322 filtered[i] =
static_cast<double>(sum) /
static_cast<double>(totalWindow);
324 sum -= data[startIndex];
325 sum += data[(startIndex + totalWindow) % N];
326 startIndex = (startIndex + 1) % N;
337 explicit FileLoader(
const char *filename) :
_ifs(filename,
std::ios::binary |
std::ios::in) {
339 throw std::runtime_error(
"unable to open file");
346 bool read(
char *s, std::streamsize
n) {
return static_cast<bool>(
_ifs.read(s,
n)); }
348 size_t size() {
return _size; }
352 size_t selected_position() {
return _ifs.tellg(); }
395 EventProcessor(
const std::vector<bool> &roi,
const std::vector<size_t> &mapIndex,
const size_t stride,
396 const double framePeriod,
const double gatePeriod, TimeLimits timeBoundary, TimeLimits directLimits,
397 TimeLimits analysedLimits,
bool includeBM)
421 return static_cast<int64_t
>(start * 1.0e3);
424 void addEvent(
size_t x,
size_t p,
double tdop,
double taux) {
431 auto y =
static_cast<size_t>(p / HISTO_BINS_Y_DENUMERATOR);
435 size_t id = BM_HISTOGRAMS +
y;
454 xid = xid + DETECTOR_TUBES;
459 if (
id >=
m_roi.size())
485 EventCounter(
const std::vector<bool> &roi,
const std::vector<size_t> &mapIndex,
const size_t stride,
486 const double framePeriod,
const double gatePeriod,
const TimeLimits &timeBoundary,
487 const TimeLimits &directLimits,
const TimeLimits &analysedLimits, std::vector<size_t> &eventCounts,
489 :
EventProcessor(roi, mapIndex, stride, framePeriod, gatePeriod, timeBoundary, directLimits, analysedLimits,
519 if (
x < DETECTOR_TUBES)
520 std::tie(pulse, tof) =
m_convertTOF.analysedTOF(
id, tobs);
522 std::tie(pulse, tof) =
m_convertTOF.directTOF(
id, tobs);
523 offset +=
static_cast<int64_t
>(pulse * 1e3);
531 auto ev = Types::Event::TofEvent(tof, Types::Core::DateAndTime(offset));
539 auto ev = Types::Event::TofEvent(tobs, Types::Core::DateAndTime(offset));
549 EventAssigner(
const std::vector<bool> &roi,
const std::vector<size_t> &mapIndex,
const size_t stride,
550 const double framePeriod,
const double gatePeriod,
const TimeLimits &timeBoundary,
551 const TimeLimits &directLimits,
const TimeLimits &analysedLimits, ConvertTOF &convert,
552 std::vector<EventVector_pt> &eventVectors, int64_t startTime,
bool saveAsTOF,
bool includeBM)
553 :
EventProcessor(roi, mapIndex, stride, framePeriod, gatePeriod, timeBoundary, directLimits, analysedLimits,
563 size_t numBins()
const {
return BEAM_MONITOR_BINS; }
567template <
typename EP>
570 using namespace ANSTO;
574 FileLoader loader(eventFile.c_str());
579 ReadEventFile(loader, eventProcessor, progTracker, 100,
false);
589 std::vector<std::string> exts;
595 exts.emplace_back(
".hdf");
597 exts.emplace_back(
".tar");
599 "The input filename of the stored data");
602 Base::declareProperty(PathToBinaryStr,
"",
603 "Relative or absolute path to the compressed binary\n"
604 "event file linked to the HDF file, eg /storage/data/");
609 exts.emplace_back(
".xml");
611 "The input filename of the mask data");
613 Base::declareProperty(SelectDetectorTubesStr,
"",
614 "Comma separated range of detectors tubes to be loaded,\n"
617 Base::declareProperty(
621 Base::declareProperty(SelectDatasetStr, 0,
"Select the index for the dataset to be loaded.");
624 Base::declareProperty(OverrideDopplerFreqStr,
EMPTY_DBL(),
"Override the Doppler frequency, in Hertz.");
626 Base::declareProperty(OverrideDopplerPhaseStr,
EMPTY_DBL(),
"Override the Doppler phase, in degrees.");
628 Base::declareProperty(CalibrateDopplerPhaseStr,
false,
629 "Calibrate the Doppler phase prior to TOF conversion,\n"
630 "ignored if imported as Doppler time or phase entered");
632 Base::declareProperty(RawDopplerTimeStr,
false,
633 "Import file as observed time relative the Doppler\n"
634 "drive, in microsecs.");
636 Base::declareProperty(IncludePseudoBMStr,
false,
"Include the individual beam monitor events as spectra.");
639 "Only include events after the provided start time, in "
640 "seconds (relative to the start of the run).");
643 "Only include events before the provided stop time, in "
644 "seconds (relative to the start of the run).");
646 std::string grpOptional =
"Filters";
655 m_localWorkspace = std::make_shared<DataObjects::EventWorkspace>();
656 m_localWorkspace->initialize(HISTOGRAMS, 2, 1);
659 m_localWorkspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"TOF");
660 m_localWorkspace->setYUnit(
"Counts");
663 m_localWorkspace->setTitle(title);
674template <
typename FD>
void LoadEMU<FD>::exec(
const std::string &hdfFile,
const std::string &eventFile) {
676 namespace fs = std::filesystem;
680 fs::path p = hdfFile;
681 for (; !p.extension().empty();)
683 std::string title = p.generic_string();
690 logManager.
addProperty(SelectDatasetStr, m_datasetIndex);
691 loadParameters(hdfFile, logManager);
692 prog.
doReport(
"creating instrument");
697 std::string maskfile = Base::getPropertyValue(
MaskStr);
698 std::string seltubes = Base::getPropertyValue(SelectDetectorTubesStr);
699 logManager.
addProperty(SelectDetectorTubesStr, seltubes);
702 std::vector<bool> roi = createRoiVector(seltubes, maskfile);
704 if (Base::isEmpty(timeMaxBoundary))
705 timeMaxBoundary = std::numeric_limits<double>::infinity();
709 auto instr = m_localWorkspace->getInstrument();
710 auto iparam = [&instr](
const std::string &tag) {
return instr->getNumberParameter(tag)[0]; };
716 double sampleAnalyser = iparam(
"SampleAnalyser");
717 auto endID =
static_cast<detid_t>(DETECTOR_TUBES * PIXELS_PER_TUBE);
718 for (
detid_t detID = 0; detID < endID; ++detID)
719 updateNeutronicPostions(detID, sampleAnalyser);
723 std::string dmapStr = instr->getParameterAsString(
"DetectorMap");
724 std::vector<size_t> detMapIndex = std::vector<size_t>(DETECTOR_TUBES, 0);
725 mapRangeToIndex(dmapStr, detMapIndex, [](
size_t n) {
return n; });
730 loadDetectorL2Values();
731 loadDopplerParameters(logManager);
732 double v2 = iparam(
"AnalysedV2");
733 double framePeriod = 1.0e6 / m_dopplerFreq;
734 double sourceSample = iparam(
"SourceSample");
735 ConvertTOF convertTOF(m_dopplerAmpl * m_dopplerRun, m_dopplerFreq, m_dopplerPhase, sourceSample, v2, m_detectorL2);
743 size_t numberHistograms = m_localWorkspace->getNumberHistograms();
744 std::vector<EventVector_pt> eventVectors(numberHistograms,
nullptr);
745 std::vector<size_t> eventCounts(numberHistograms, 0);
751 TimeLimits directLimits(1000.0 * iparam(
"DirectTauxMin"), 1000.0 * iparam(
"DirectTauxMax"));
752 TimeLimits analysedLimits(1000.0 * iparam(
"AnalysedTauxMin"), 1000.0 * iparam(
"AnalysedTauxMax"));
758 bool includeBM = Base::getProperty(IncludePseudoBMStr);
759 EMU::EventCounter eventCounter(roi, detMapIndex, PIXELS_PER_TUBE, framePeriod, gatePeriod, timeBoundary, directLimits,
760 analysedLimits, eventCounts, includeBM);
761 EMU::loadEvents(prog,
"loading neutron counts", eventFile, eventCounter);
763 prepareEventStorage(progTracker, eventCounts, eventVectors);
768 Types::Core::DateAndTime startTime(m_startRun);
769 auto start_nanosec = startTime.totalNanoseconds();
770 bool saveAsTOF = !Base::getProperty(RawDopplerTimeStr);
771 bool loadAsTOF = !m_calibrateDoppler && saveAsTOF;
772 EMU::EventAssigner eventAssigner(roi, detMapIndex, PIXELS_PER_TUBE, framePeriod, gatePeriod, timeBoundary,
773 directLimits, analysedLimits, convertTOF, eventVectors, start_nanosec, loadAsTOF,
775 EMU::loadEvents(prog,
"loading neutron events (TOF)", eventFile, eventAssigner);
778 auto filteredBM = runningAverage(eventAssigner.
beamMonitorCounts(), BM_HALF_WINDOW);
779 auto res = std::minmax_element(filteredBM.begin(), filteredBM.end());
780 auto ratePerSec =
static_cast<double>(eventAssigner.
numBins()) / eventCounter.
duration();
781 auto minBM = *res.first * ratePerSec;
782 auto maxBM = *res.second * ratePerSec;
783 AddSinglePointTimeSeriesProperty<double>(logManager, m_startRun,
"BeamMonitorBkgRate", minBM);
784 AddSinglePointTimeSeriesProperty<double>(logManager, m_startRun,
"BeamMonitorRate", maxBM);
785 AddSinglePointTimeSeriesProperty<int>(logManager, m_startRun,
"MonitorCounts",
786 static_cast<int>(eventAssigner.
bmCounts()));
790 auto minTOF = eventAssigner.
tofMin();
791 auto maxTOF = eventAssigner.
tofMax();
792 if (m_calibrateDoppler) {
793 calibrateDopplerPhase(eventCounts, eventVectors);
795 dopplerTimeToTOF(eventVectors, minTOF, maxTOF);
798 AddSinglePointTimeSeriesProperty<double>(logManager, m_startRun,
"DopplerPhase", m_dopplerPhase);
801 m_localWorkspace->setAllX(HistogramData::BinEdges{std::max(0.0, floor(minTOF)), maxTOF + 1});
802 setupDetectorMasks(roi);
805 auto frame_count = eventCounter.
numFrames();
806 AddSinglePointTimeSeriesProperty<int>(logManager, m_startRun,
"frame_count",
static_cast<int>(frame_count));
809 auto scan_period =
static_cast<double>(frame_count + 1) / m_dopplerFreq;
810 AddSinglePointTimeSeriesProperty<double>(logManager, m_startRun,
"ScanPeriod", scan_period);
812 std::string filename = Base::getPropertyValue(
FilenameStr);
815 Types::Core::time_duration duration =
816 boost::posix_time::microseconds(
static_cast<boost::int64_t
>(eventCounter.
duration() * 1.0e6));
817 Types::Core::DateAndTime endTime(startTime + duration);
818 logManager.
addProperty(
"end_time", endTime.toISO8601String());
822 loadEnvironParameters(hdfFile, logManager);
824 Base::setProperty(
"OutputWorkspace", m_localWorkspace);
831 size_t maskedBins = std::count_if(roi.begin(), roi.end(), [](
bool v) { return !v; });
833 if (maskedBins > 0) {
835 std::vector<size_t> maskIndexList(maskedBins);
836 size_t maskIndex = 0;
838 for (
size_t i = 0; i != roi.size(); i++)
840 maskIndexList[maskIndex++] = i;
842 auto maskingAlg = Base::createChildAlgorithm(
"MaskDetectors");
843 maskingAlg->setProperty(
"Workspace", m_localWorkspace);
844 maskingAlg->setProperty(
"WorkspaceIndexList", maskIndexList);
845 maskingAlg->executeAsChildAlg();
851template <
typename FD>
853 std::vector<EventVector_pt> &eventVectors) {
855 size_t numberHistograms = eventCounts.size();
856 for (
size_t i = 0; i != numberHistograms; ++i) {
860 eventList.
reserve(eventCounts[i]);
875 auto instr = m_localWorkspace->getInstrument();
880 m_dopplerFreq = Base::getProperty(OverrideDopplerFreqStr);
881 if (Base::isEmpty(m_dopplerFreq)) {
883 m_dopplerFreq = 0.5 * doppVel / (M_PI * m_dopplerAmpl);
885 AddSinglePointTimeSeriesProperty<double>(logm, m_startRun,
"DopplerFrequency", m_dopplerFreq);
887 m_dopplerPhase = Base::getProperty(OverrideDopplerPhaseStr);
888 m_calibrateDoppler = Base::getProperty(CalibrateDopplerPhaseStr) && Base::isEmpty(m_dopplerPhase);
889 if (Base::isEmpty(m_dopplerPhase)) {
891 double doppThreshold = instr->getNumberParameter(
"DopplerReferenceThreshold")[0];
892 double doppDelay = instr->getNumberParameter(
"DopplerReferenceDelay")[0];
893 m_dopplerPhase = 180.0 - asin(0.001 * doppThreshold / m_dopplerAmpl) * 180.0 / M_PI + doppDelay * m_dopplerFreq;
897 int32_t calPhase = (m_calibrateDoppler ? 1 : 0);
903template <
typename FD>
905 const std::vector<EventVector_pt> &eventVectors) {
908 auto instr = m_localWorkspace->getInstrument();
909 double v2 = instr->getNumberParameter(
"AnalysedV2")[0];
910 double l1 = instr->getNumberParameter(
"SourceSample")[0];
913 auto startID =
static_cast<size_t>(HORIZONTAL_TUBES * PIXELS_PER_TUBE);
914 auto endID =
static_cast<size_t>(DETECTOR_TUBES * PIXELS_PER_TUBE);
915 size_t numEvents = std::accumulate(eventCounts.begin() + startID, eventCounts.begin() + endID,
size_t{0});
917 throw std::runtime_error(
"no analysed events for phase calibration");
921 constexpr size_t NHIST = 100;
922 std::vector<int> histogram(NHIST + 1, 0);
925 auto costFn = [&,
this](
double phase) {
926 ConvertTOF convTOF(m_dopplerAmpl * m_dopplerRun, m_dopplerFreq, phase, l1, v2, m_detectorL2);
931 for (
size_t i = startID; i < endID; i++) {
932 for (
auto const &
x : *eventVectors[i]) {
933 std::tie(pulse, tof) = convTOF.analysedTOF(i,
x.tof());
934 auto tof1 = 1e-6 * tof - m_detectorL2[i] / v2;
935 nVel[ix++] = l1 / tof1;
940 auto ixlim = std::minmax_element(nVel.begin(), nVel.end());
941 auto vmin = nVel[ixlim.first - nVel.begin()];
942 auto vmax = nVel[ixlim.second - nVel.begin()];
944 std::fill(histogram.begin(), histogram.end(), 0);
945 auto delta = (vmax - vmin) / NHIST;
948 auto j =
static_cast<size_t>(std::floor((v - vmin) /
delta));
950 if (histogram[j] > maxHist)
951 maxHist = histogram[j];
956 auto minLevel =
static_cast<int>(maxHist / 4);
958 nCnd[i] = (histogram[nMap[i]] >= minLevel ? true :
false);
962 auto cost = maskedStdev(nVel, nCnd);
968 int bits = std::numeric_limits<double>::digits;
969 boost::uintmax_t itn = 30;
970 using boost::math::tools::brent_find_minima;
971 auto minPhase = m_dopplerPhase - 5.0;
972 auto maxPhase = m_dopplerPhase + 5.0;
973 auto r = brent_find_minima(costFn, minPhase, maxPhase, bits, itn);
974 m_dopplerPhase = r.first;
979template <
typename FD>
983 auto const instr = m_localWorkspace->getInstrument();
984 double v2 = instr->getNumberParameter(
"AnalysedV2")[0];
985 double l1 = instr->getNumberParameter(
"SourceSample")[0];
986 ConvertTOF convTOF(m_dopplerAmpl * m_dopplerRun, m_dopplerFreq, m_dopplerPhase, l1, v2, m_detectorL2);
991 auto directID =
static_cast<size_t>(DETECTOR_TUBES * PIXELS_PER_TUBE);
992 for (
size_t id = 0;
id < eventVectors.size();
id++) {
993 for (
auto &
x : *eventVectors[id]) {
996 std::tie(pulse, tof) = convTOF.analysedTOF(
id,
x.tof());
998 std::tie(pulse, tof) = convTOF.directTOF(
id,
x.tof());
1001 int64_t pulseTime =
x.pulseTime().totalNanoseconds();
1002 pulseTime +=
static_cast<int64_t
>(pulse * 1000);
1003 x = Types::Event::TofEvent(tof, Types::Core::DateAndTime(pulseTime));
1006 minTOF = maxTOF =
x.tof();
1009 minTOF = std::min(minTOF,
x.tof());
1010 maxTOF = std::max(maxTOF,
x.tof());
1019 m_detectorL2 = std::vector<double>(HISTOGRAMS);
1020 const auto &detectorInfo = m_localWorkspace->detectorInfo();
1021 auto detIDs = detectorInfo.detectorIDs();
1022 for (
const auto detID : detIDs) {
1023 auto ix = detectorInfo.indexOf(detID);
1024 double l2 = detectorInfo.l2(ix);
1025 m_detectorL2[detID] =
l2;
1034 auto &compInfo = m_localWorkspace->mutableComponentInfo();
1037 auto component = instrument->getDetector(detID);
1038 double rho, theta, phi;
1042 double scale = -(2 * sampleAnalyser +
rho) /
rho;
1045 const auto componentIndex = compInfo.indexOf(component->getComponentID());
1046 compInfo.setPosition(componentIndex,
position);
1047 }
catch (
const std::runtime_error &) {
1054template <
typename FD>
1057 std::vector<bool> result(HISTOGRAMS,
true);
1060 if (!selected.empty()) {
1062 mapRangeToIndex(selected, tubes, [](
size_t) {
return true; });
1064 if (tubes[i] ==
false) {
1065 for (
size_t j = 0; j < PIXELS_PER_TUBE; j++) {
1066 result[i * PIXELS_PER_TUBE + j] =
false;
1072 if (maskfile.length() == 0)
1075 std::ifstream input(maskfile.c_str());
1077 throw std::invalid_argument(
"invalid mask file");
1080 while (std::getline(input, line)) {
1081 auto i0 = line.find(
"<detids>");
1082 auto iN = line.find(
"</detids>");
1084 if ((i0 != std::string::npos) && (iN != std::string::npos) && (i0 < iN)) {
1085 line = line.substr(i0 + 8, iN - i0 - 8);
1086 mapRangeToIndex(line, result, [](
size_t) {
return false; });
1099 MapNeXusToProperty<std::string>(entry,
"sample/name",
"unknown", logm,
"SampleName",
"", 0);
1100 MapNeXusToProperty<std::string>(entry,
"sample/description",
"unknown", logm,
"SampleDescription",
"", 0);
1103 Types::Core::DateAndTime startTime(GetNeXusValue<std::string>(entry,
"start_time",
"2000-01-01T00:00:00", 0));
1104 if (m_datasetIndex > 0) {
1105 auto baseTime = GetNeXusValue<int32_t>(entry,
"instrument/detector/start_time", 0, 0);
1106 auto nthTime = GetNeXusValue<int32_t>(entry,
"instrument/detector/start_time", 0, m_datasetIndex);
1108 Types::Core::time_duration duration =
1109 boost::posix_time::microseconds(
static_cast<boost::int64_t
>((nthTime - baseTime) * 1.0e6));
1110 Types::Core::DateAndTime startDataset(startTime + duration);
1111 m_startRun = startDataset.toISO8601String();
1113 m_startRun = startTime.toISO8601String();
1117 MapNeXusToSeries<double>(entry,
"instrument/doppler/ctrl/amplitude", 75.0, logm, m_startRun,
"DopplerAmplitude",
1118 0.001, m_datasetIndex);
1119 MapNeXusToSeries<double>(entry,
"instrument/doppler/ctrl/velocity", 4.7, logm, m_startRun,
"DopplerVelocity", 1,
1121 MapNeXusToSeries<int>(entry,
"instrument/doppler/ctrl/run_cmd", 1, logm, m_startRun,
"DopplerRun", 1, m_datasetIndex);
1123 MapNeXusToSeries<double>(entry,
"instrument/chpr/background/actspeed", 1272.8, logm, m_startRun,
1124 "BackgroundChopperFrequency", 1.0 / 60, 0);
1125 MapNeXusToSeries<double>(entry,
"instrument/chpr/graphite/actspeed", 2545.6, logm, m_startRun,
1126 "GraphiteChopperFrequency", 1.0 / 60, 0);
1128 MapNeXusToSeries<double>(entry,
"instrument/hztubegap", 0.02, logm, m_startRun,
"horizontal_tubes_gap", 1.0, 0);
1130 MapNeXusToSeries<double>(entry,
"instrument/source/power", 20.0, logm, m_startRun,
"ReactorPower", 1.0,
1133 MapNeXusToProperty<double>(entry,
"instrument/doppler/tosource", 2.035, logm,
"SourceSample", 1.0, 0);
1146 for (
const auto &tag : tags) {
1147 MapNeXusToSeries<double>(entry,
"data/" + tag, 0.0, logm, time_str,
"env_" + tag, 1.0, m_datasetIndex);
1155 auto loadInstrumentAlg = Base::createChildAlgorithm(
"LoadInstrument");
1156 loadInstrumentAlg->setProperty(
"Workspace", m_localWorkspace);
1157 loadInstrumentAlg->setPropertyValue(
"InstrumentName",
"EMUau");
1159 loadInstrumentAlg->executeAsChildAlg();
1182const std::string
LoadEMUHdf::summary()
const {
return "Loads an EMU Hdf and linked event file into a workspace."; }
1190 if (descriptor.
isEntry(
"/entry1/site_name") && descriptor.
isEntry(
"/entry1/instrument/doppler/ctrl/velocity") &&
1191 descriptor.
isEntry(
"/entry1/instrument/doppler/ctrl/amplitude") &&
1192 descriptor.
isEntry(
"/entry1/instrument/detector/daq_dirname") &&
1193 descriptor.
isEntry(
"/entry1/instrument/detector/dataset_number") &&
1194 descriptor.
isEntry(
"/entry1/data/hmm_total_t_ds0") && descriptor.
isEntry(
"/entry1/data/hmm_total_t_ds1") &&
1195 descriptor.
isEntry(
"/entry1/data/hmm_total_xt_ds0") && descriptor.
isEntry(
"/entry1/data/hmm_total_xt_ds1")) {
1211 namespace fs = std::filesystem;
1216 if (evtPath.empty())
1220 if (evtPath.rfind(
"./") == 0 || evtPath.rfind(
"../") == 0) {
1221 fs::path hp(hdfFile);
1222 evtPath = fs::canonical(hp.parent_path() / evtPath).string();
1231 if (fs::is_directory(evtPath)) {
1234 auto eventDir = GetNeXusValue<std::string>(entry,
"instrument/detector/daq_dirname",
"./", 0);
1235 auto dataset = GetNeXusValue<int32_t>(entry,
"instrument/detector/dataset_number", 0,
m_datasetIndex);
1237 g_log.
warning(
"Negative dataset index recorded in HDF, reset to zero!");
1244 fs::path filePath = fs::absolute(fs::path(evtPath) / eventDir / (
"DATASET_" +
std::to_string(dataset)) /
"EOS.bin");
1245 if (!fs::is_regular_file(filePath)) {
1246 filePath = fs::absolute(fs::path(hdfFile).replace_extension(
".bin"));
1248 evtPath = filePath.generic_string();
1252 if (!fs::is_regular_file(evtPath)) {
1253 std::string msg =
"Check path, cannot open binary event file: " + evtPath;
1254 throw std::runtime_error(msg);
1275 return "Loads an EMU tar file, containing the Hdf and event file, into a "
1289 size_t hdfFiles = 0;
1290 size_t binFiles = 0;
1291 const std::vector<std::string> &subFiles = file.
files();
1292 for (
const auto &subFile : subFiles) {
1293 auto len = subFile.length();
1294 if ((len > 4) && (subFile.find_first_of(
"\\/", 0, 2) == std::string::npos)) {
1295 if ((subFile.rfind(
".hdf") == len - 4) && (subFile.compare(0, 3,
"EMU") == 0))
1297 else if (subFile.rfind(
".bin") == len - 4)
1302 return (hdfFiles == 1) && (binFiles == 1) ? 50 : 0;
1317 if (!tarFile.
good())
1318 throw std::invalid_argument(
"invalid EMU tar file");
1325 const std::vector<std::string> &files = tarFile.
files();
1326 auto selectFile = [&](
const std::string &ext) {
1327 auto itf = std::find_if(files.cbegin(), files.cend(),
1328 [&ext](
const std::string &file) { return file.rfind(ext) == file.length() - 4; });
1329 if (itf == files.end())
1330 throw std::runtime_error(
"missing tar file data");
1332 tarFile.
select(itf->c_str());
1334 auto extractFile = [&](Poco::TemporaryFile &tfile) {
1335 std::shared_ptr<FILE> handle(fopen(tfile.path().c_str(),
"wb"), fclose);
1340 while (0 != (bytesRead = tarFile.
read(buffer,
sizeof(buffer))))
1341 fwrite(buffer, bytesRead, 1, handle.get());
1348 Poco::TemporaryFile hdfFile;
1349 extractFile(hdfFile);
1353 Poco::TemporaryFile eventFile;
1354 extractFile(eventFile);
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
const std::vector< double > & m_L2
std::vector< T > const * vec
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
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 void init()=0
Virtual method - must be overridden by concrete algorithm.
virtual void exec()=0
Virtual method - must be overridden by concrete algorithm.
@ 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.
void setSpectrumNo(specnum_t num)
Sets the spectrum number of this spectrum.
This class contains the information about the log entries.
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
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.
void doReport(const std::string &msg="") override
Actually do the reporting, without changing the loop counter.
A property class for workspaces.
helper class to keep track of progress
void update(int64_t position)
size_t read(void *dst, size_t size)
bool select(const char *file)
const std::vector< std::string > & files() const
std::vector< EventVector_pt > & m_eventVectors
const std::vector< size_t > & beamMonitorCounts() const
EventAssigner(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const size_t stride, const double framePeriod, const double gatePeriod, const TimeLimits &timeBoundary, const TimeLimits &directLimits, const TimeLimits &analysedLimits, ConvertTOF &convert, std::vector< EventVector_pt > &eventVectors, int64_t startTime, bool saveAsTOF, bool includeBM)
void addEventImpl(size_t id, size_t x, size_t, double tobs) override
std::vector< size_t > m_bmCounts
void addPseudoBMEventImpl(size_t id, double tobs) override
const ConvertTOF & m_convertTOF
EventCounter(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const size_t stride, const double framePeriod, const double gatePeriod, const TimeLimits &timeBoundary, const TimeLimits &directLimits, const TimeLimits &analysedLimits, std::vector< size_t > &eventCounts, bool includeBM)
void addEventImpl(size_t id, size_t, size_t, double) override
void addPseudoBMEventImpl(size_t id, double) override
std::vector< size_t > & m_eventCounts
const double m_framePeriod
const std::vector< bool > & m_roi
const TimeLimits m_directTaux
void addEvent(size_t x, size_t p, double tdop, double taux)
const std::vector< size_t > & m_mapIndex
virtual void addEventImpl(size_t id, size_t x, size_t y, double tof)=0
const double m_gatePeriod
int64_t frameStart() const
EventProcessor(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const size_t stride, const double framePeriod, const double gatePeriod, TimeLimits timeBoundary, TimeLimits directLimits, TimeLimits analysedLimits, bool includeBM)
virtual void addPseudoBMEventImpl(size_t id, double tobs)=0
const TimeLimits m_analysedTaux
const TimeLimits m_timeBoundary
LoadEMUHdf : Loads an ANSTO EMU Hdf and linked event file into a workspace.
const std::vector< std::string > seeAlso() const override
Similar algorithms.
void exec() override
Execute the algorithm.
int version() const override
Algorithm's version for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
const std::string name() const override
Algorithms name for identification.
const std::string category() const override
Algorithm's category for identification.
void init() override
Initialise the algorithm and declare the properties for the nexus descriptor.
int confidence(Nexus::NexusDescriptor &descriptor) const override
Return the confidence as an integer value that this algorithm can load the file descriptor.
LoadEMUTar : Loads a merged ANSTO EMU Hdf and event file into a workspace.
int version() const override
Algorithm's version for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
const std::string name() const override
Algorithms name for identification.
int confidence(Kernel::FileDescriptor &descriptor) const override
Return the confidence as an integer value that this algorithm can load the file descriptor.
const std::string category() const override
Algorithm's category for identification.
void exec() override
Execute the algorithm.
const std::vector< std::string > seeAlso() const override
Similar algorithms.
void init() override
Initialise the algorithm and declare the standard properties for the general file descriptor.
void prepareEventStorage(ANSTO::ProgressTracker &prog, const std::vector< size_t > &eventCounts, std::vector< EventVector_pt > &eventVectors)
Allocate space for the event storage in eventVectors after the eventCounts have been determined.
void calibrateDopplerPhase(const std::vector< size_t > &eventCounts, const std::vector< EventVector_pt > &eventVectors)
Calibrate the doppler phase based on the analysed events using the eventCounts and eventVectors.
std::vector< bool > createRoiVector(const std::string &seltubes, const std::string &maskfile)
Region of interest is defined by the selected detectors and the maskfile.
void loadInstrument()
Load the instrument definition.
void loadParameters(const std::string &hdfFile, API::LogManager &logm)
Load parameters from input hdfFile and save to the log manager, logm.
void loadDetectorL2Values()
Recovers the L2 neutronic distance for each detector.
void setupDetectorMasks(const std::vector< bool > &roi)
Set up the detector masks to the region of interest roi.
void updateNeutronicPostions(detid_t detID, double sampleAnalyser)
Update the neutronic position for the detID using the distance from the source and the sample to anal...
void loadDopplerParameters(API::LogManager &logm)
Get the Doppler parameters and record to the log manager, logm.
void createWorkspace(const std::string &title)
Creates an event workspace and sets the title.
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,...
void dopplerTimeToTOF(const std::vector< EventVector_pt > &eventVectors, double &minTOF, double &maxTOF)
Convert the doppler time to TOF for all the events in eventVectors and time of flight range as minTOF...
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.
Defines a wrapper around an open file.
const std::string & filename() const
Access the filename.
const std::string & extension() const
Access the file extension.
void warning(const std::string &msg)
Logs at warning level.
OptionalBool : Tri-state bool.
A specialised Property class for holding a series of time-value pairs.
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
NXDataSetTyped< T > openNXDataSet(const std::string &name) const
Templated method for creating datasets.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
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.
std::shared_ptr< T > createWorkspace(InitArgs... args)
Kernel::Logger g_log("ExperimentInfo")
static logger object
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 ®exFilter)
extract datasets from a group that match a regex filter
void loadEvents(API::Progress &prog, const char *progMsg, const std::string &eventFile, EP &eventProcessor)
static char const *const FilenameStr
static const size_t HISTO_BINS_X
static const size_t HISTO_BINS_Y
static const size_t Progress_LoadBinFile
void AddSinglePointTimeSeriesProperty(API::LogManager &logManager, const std::string &time, const std::string &name, const TYPE value)
static char const *const MaskStr
static char const *const FilterByTimeStartStr
static const size_t Progress_Total
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.
static char const *const FilterByTimeStopStr
static const size_t Progress_ReserveMemory
DLLExport void getEventsFrom(EventList &el, std::vector< Types::Event::TofEvent > *&events)
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
NXDataSetTyped< float > NXFloat
The float dataset type.
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.