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_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.
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.
int confidence(Nexus::NexusDescriptor &descriptor) const override
Return the confidence as an integer value that this algorithm can load the file descriptor.
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.
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.
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 ®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.