32using namespace Kernel;
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;
52constexpr char MaskStr[] =
"Mask";
53constexpr char SelectDetectorTubesStr[] =
"SelectDetectorTubes";
54constexpr char SelectDatasetStr[] =
"SelectDataset";
57constexpr char PathToBinaryStr[] =
"BinaryEventPath";
58constexpr char TOFBiasStr[] =
"TimeOfFlightBias";
59constexpr char CalibrateTOFStr[] =
"CalibrateTOFBias";
60constexpr char LambdaOnTwoStr[] =
"LambdaOnTwoMode";
63using TimeLimits = std::pair<double, double>;
65template <
typename Type>
69 auto p =
new Kernel::TimeSeriesProperty<Type>(
name);
70 p->addValue(time,
value);
73 logManager.addProperty(p);
78template <
typename Type>
79Type GetNeXusValue(
const Nexus::NXEntry &entry,
const std::string &address,
const Type &defval, int32_t
index) {
81 Nexus::NXDataSetTyped<Type> dataSet = entry.openNXDataSet<Type>(address);
84 return dataSet()[
index];
85 }
catch (std::runtime_error &) {
92double GetNeXusValue<double>(
const Nexus::NXEntry &entry,
const std::string &address,
const double &defval,
98 return dataSet()[
index];
99 }
catch (std::runtime_error &) {
105std::string GetNeXusValue<std::string>(
const Nexus::NXEntry &entry,
const std::string &address,
106 const std::string &defval, int32_t ) {
109 return entry.getString(address);
110 }
catch (std::runtime_error &) {
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) {
119 T
value = GetNeXusValue<T>(entry, address, defval,
index);
120 logManager.addProperty<T>(
name,
value * factor);
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 & , int32_t
index) {
129 std::string
value = GetNeXusValue<std::string>(entry, address, defval,
index);
130 logManager.addProperty<std::string>(
name,
value);
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,
138 auto value = GetNeXusValue<T>(entry, address, defval,
index);
139 AddSinglePointTimeSeriesProperty<T>(logManager, time,
name,
value * factor);
145template <
typename T,
typename F>
void mapRangeToIndex(
const std::string &line, std::vector<T> &result,
const F &fn) {
147 std::stringstream ss(line);
150 while (std::getline(ss, item,
',')) {
151 auto const k = item.find(
'-');
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));
158 p0 = boost::lexical_cast<size_t>(item);
162 if (p1 < result.size() && p0 <= p1) {
164 result[p0++] = fn(
index);
167 }
else if (p0 < result.size() && p1 < p0) {
169 result[p0] = fn(
index);
173 throw std::invalid_argument(
"invalid range specification");
183 explicit FileLoader(
const char *filename) :
_ifs(filename,
std::ios::binary |
std::ios::in) {
185 throw std::runtime_error(
"unable to open file");
192 bool read(
char *s, std::streamsize
n) {
return static_cast<bool>(
_ifs.read(s,
n)); }
194 size_t size()
const {
return _size; }
198 size_t selected_position() {
return _ifs.tellg(); }
219 m_M = (
static_cast<double>(N) / (maxVal - minVal));
225 inline double ival(
double val)
const {
return m_M * val +
m_B; }
227 inline double xval(
double ix)
const {
return (ix -
m_B) /
m_M; }
229 inline void add(
double val) {
230 auto ix =
static_cast<size_t>(std::floor(
ival(val)));
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)
295 return static_cast<int64_t
>(start * 1.0e3);
304 void addEvent(
size_t x,
size_t p,
double tof,
double ) {
311 auto y =
static_cast<size_t>(p / HISTO_BINS_Y_DENUMERATOR);
320 size_t id = xid < DETECTOR_TUBES ? PIXELS_PER_TUBE * xid +
y : DETECTOR_SPECTRA + xid;
321 if (
id >=
m_roi.size())
350 const std::vector<double> &
m_L2;
356 double deltaT = 1.0e6 * (
m_L1 +
m_L2[id]) /
m_V0 - tobs;
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)
376 for (
size_t i = 0; i < hvec.size(); i++) {
377 if (hvec[i] >= minLevel) {
378 auto ix =
static_cast<double>(i);
384 return (
count > 0 ? sum /
static_cast<double>(
count) : 0.0);
414 auto ev = Types::Event::TofEvent(tof, Types::Core::DateAndTime(offset));
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)
430template <
typename EP>
433 using namespace ANSTO;
437 FileLoader loader(eventFile.c_str());
442 ReadEventFile(loader, eventProcessor, progTracker, 100,
false);
451 std::vector<std::string> exts;
456 exts.emplace_back(
".hdf");
458 "The input filename of the stored data");
461 "Relative or absolute path to the compressed binary\n"
462 "event file linked to the HDF file, eg /storage/data/");
466 exts.emplace_back(
".xml");
468 "The input filename of the mask data");
471 "Comma separated range of detectors tubes to be loaded,\n"
477 declareProperty(SelectDatasetStr, 0,
"Select the index for the dataset to be loaded.");
479 declareProperty(TOFBiasStr, 0.0,
"Time of flight correction in micro-sec.");
481 declareProperty(CalibrateTOFStr,
false,
"Calibrate the TOF correction from the elastic pulse.");
483 declareProperty(LambdaOnTwoStr,
false,
"Instrument is operating in Lambda on Two mode.");
486 "Only include events after the provided start time, in "
487 "seconds (relative to the start of the run).");
490 "Only include events before the provided stop time, in "
491 "seconds (relative to the start of the run).");
493 std::string grpOptional =
"Filters";
506 m_localWorkspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"TOF");
521void LoadPLN::exec(
const std::string &hdfFile,
const std::string &eventFile) {
523 namespace fs = std::filesystem;
527 fs::path p = hdfFile;
528 for (; !p.extension().empty();)
530 std::string title = p.generic_string();
538 prog.
doReport(
"creating instrument");
544 logManager.
addProperty(SelectDetectorTubesStr, seltubes);
550 timeMaxBoundary = std::numeric_limits<double>::infinity();
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; });
562 std::vector<EventVector_pt> eventVectors(numberHistograms,
nullptr);
563 std::vector<size_t> eventCounts(numberHistograms, 0);
567 double framePeriod = 1.0e6 / masterRpm;
571 double gatePeriod = (std::round(masterRpm / slaveRpm) == 1.0 ? 0.5 * framePeriod : framePeriod);
572 AddSinglePointTimeSeriesProperty<double>(logManager,
m_startRun,
"GatePeriod", gatePeriod);
575 size_t hdfCounts =
static_cast<size_t>(logManager.
getTimeSeriesProperty<
int>(
"TotalCounts")->firstValue());
577 double sourceSample =
fabs(instr->getSource()->getPos().Z());
580 double sampleTime = 1.0e6 * sourceSample / velocity;
581 PLN::EventCounter eventCounter(roi, detMapIndex, framePeriod, gatePeriod, timeBoundary, eventCounts, sourceSample,
583 PLN::loadEvents(prog,
"loading neutron counts", eventFile, eventCounter);
597 Types::Core::DateAndTime startTime(
m_startRun);
598 auto const start_nanosec = startTime.totalNanoseconds();
599 bool const calibrateTOF =
getProperty(CalibrateTOFStr);
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);
612 auto minTOF = eventAssigner.
tofMin();
613 auto maxTOF = eventAssigner.
tofMax();
616 m_localWorkspace->setAllX(HistogramData::BinEdges{std::max(0.0, floor(minTOF)), maxTOF + 1});
620 auto frame_count =
static_cast<int>(eventCounter.
numFrames());
621 AddSinglePointTimeSeriesProperty<int>(logManager,
m_startRun,
"frame_count", frame_count);
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());
644 auto detIDs = detectorInfo.detectorIDs();
645 for (
const auto detID : detIDs) {
646 auto ix = detectorInfo.indexOf(detID);
647 double l2 = detectorInfo.l2(ix);
656 size_t maskedBins = 0;
657 for (
size_t i = 0; i != roi.size(); i++)
661 if (maskedBins > 0) {
663 std::vector<size_t> maskIndexList(maskedBins);
664 size_t maskIndex = 0;
666 for (
size_t i = 0; i != roi.size(); i++)
668 maskIndexList[maskIndex++] = i;
672 maskingAlg->setProperty(
"WorkspaceIndexList", maskIndexList);
673 maskingAlg->executeAsChildAlg();
680 std::vector<EventVector_pt> &eventVectors) {
682 size_t numberHistograms = eventCounts.size();
683 for (
size_t i = 0; i != numberHistograms; ++i) {
687 eventList.
reserve(eventCounts[i]);
703 std::vector<bool> result(HISTOGRAMS,
true);
706 if (!selected.empty()) {
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;
716 for (
size_t i = 0; i < MONITORS; i++) {
717 result[DETECTOR_SPECTRA + i] = tubes[DETECTOR_TUBES + i];
721 if (maskfile.length() == 0)
724 std::ifstream input(maskfile.c_str());
726 throw std::invalid_argument(
"invalid mask file");
729 while (std::getline(input, line)) {
730 auto i0 = line.find(
"<detids>");
731 auto iN = line.find(
"</detids>");
733 if ((i0 != std::string::npos) && (iN != std::string::npos) && (i0 < iN)) {
734 line = line.substr(i0 + 8, iN - i0 - 8);
735 mapRangeToIndex(line, result, [](
size_t) {
return false; });
748 MapNeXusToProperty<std::string>(entry,
"sample/name",
"unknown", logm,
"SampleName",
"", 0);
749 MapNeXusToProperty<std::string>(entry,
"sample/description",
"unknown", logm,
"SampleDescription",
"", 0);
752 Types::Core::DateAndTime startTime(GetNeXusValue<std::string>(entry,
"start_time",
"2000-01-01T00:00:00", 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);
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);
769 bool const lambdaOnTwoMode =
getProperty(LambdaOnTwoStr);
770 double lambdaFactor = (lambdaOnTwoMode ? 0.5 : 1.0);
771 logm.
addProperty(
"LambdaOnTwoMode", (lambdaOnTwoMode ? 1 : 0));
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",
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,
797 for (
const auto &tag : tags) {
798 MapNeXusToSeries<double>(entry,
"data/" + tag, 0.0, logm, time_str,
"env_" + tag, 1.0,
m_datasetIndex);
808 loadInstrumentAlg->setPropertyValue(
"InstrumentName",
"PELICAN");
810 loadInstrumentAlg->executeAsChildAlg();
825const std::string
LoadPLN::summary()
const {
return "Loads a PLN Hdf and linked event file into a workspace."; }
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")) {
850 namespace fs = std::filesystem;
859 if (evtPath.rfind(
"./") == 0 || evtPath.rfind(
"../") == 0) {
860 fs::path hp(hdfFile);
861 evtPath = fs::canonical(hp.parent_path() / evtPath).string();
870 if (fs::is_directory(evtPath)) {
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);
876 std::string message(
"Negative dataset index recorded in HDF, reset to zero!");
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)) {
893 fs::path hp = hdfFile;
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();
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);
910 exec(hdfFile, evtPath);
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define DECLARE_NEXUS_LAZY_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_LAZY_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM mac...
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.
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.
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)
LoadPLN : Loads an ANSTO PLN Hdf and linked event file into a workspace.
std::vector< double > m_detectorL2
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
const std::vector< std::string > seeAlso() const override
Similar algorithms.
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.
int version() const override
Algorithm's version for identification.
void setupDetectorMasks(const std::vector< bool > &roi)
Set up the detector masks to the region of interest roi.
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,...
DataObjects::EventWorkspace_sptr m_localWorkspace
void init() override
Initialise the algorithm and declare the properties for the nexus descriptor.
void createWorkspace(const std::string &title)
Creates an event workspace and sets the title.
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 loadInstrument()
Load the instrument definition.
std::vector< bool > createRoiVector(const std::string &seltubes, const std::string &maskfile)
Region of interest is defined by the selected detectors and the maskfile.
const std::string name() const override
Algorithms name for identification.
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Return the confidence as an integer value that this algorithm can load the file descriptor.
void exec() override
Execute the algorithm.
const std::string category() const override
Algorithm's category for identification.
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)
std::vector< EventVector_pt > & m_eventVectors
void addEventImpl(size_t id, size_t, size_t, double tobs) override
std::vector< size_t > & m_eventCounts
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)
void addEventImpl(size_t id, size_t, size_t, double tobs) override
const std::vector< double > & m_L2
const std::vector< bool > & m_roi
void addEvent(size_t x, size_t p, double tof, double)
const std::vector< size_t > & m_mapIndex
size_t availableEvents() const
const double m_framePeriod
const TimeLimits m_timeBoundary
virtual void addEventImpl(size_t id, size_t x, size_t y, double tof)=0
int64_t frameStart() const
const double m_gatePeriod
size_t processedEvents() const
EventProcessor(const std::vector< bool > &roi, const std::vector< size_t > &mapIndex, const double framePeriod, const double gatePeriod, const TimeLimits &timeBoundary, size_t maxEvents)
double ival(double val) const
std::vector< size_t > m_hist
double xval(double ix) const
SimpleHist(size_t N, double minVal, double maxVal)
const std::vector< size_t > & histogram() const
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.
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.
std::string const & extension() const noexcept
Access the file extension.
bool isEntry(std::string const &entryName, std::string const &groupClass) const
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
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 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
static char const *const FilterByTimeStopStr
static const size_t Progress_ReserveMemory
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.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.