31#include <boost/algorithm/string.hpp>
32#include <boost/algorithm/string/trim.hpp>
33#include <boost/math/special_functions/round.hpp>
35#include <Poco/AutoPtr.h>
36#include <Poco/DOM/AutoPtr.h>
37#include <Poco/DOM/DOMParser.h>
38#include <Poco/DOM/Document.h>
39#include <Poco/DOM/Element.h>
40#include <Poco/DOM/NodeFilter.h>
41#include <Poco/DOM/NodeIterator.h>
42#include <Poco/DOM/NodeList.h>
43#include <Poco/TemporaryFile.h>
44#include <Poco/Util/PropertyFileConfiguration.h>
48using namespace Kernel;
79 {
"end", Anxs::ScanLog::End}, {
"mean", Anxs::ScanLog::Mean}, {
"start", Anxs::ScanLog::Start}};
87 std::vector<uint64_t> times;
88 std::vector<T> values;
90 auto n = Anxs::extractTimedDataSet<T>(entry, path, startTime, endTime, times, values, units);
94 auto meanX = std::accumulate(values.begin(), values.end(), 0.0) /
static_cast<T
>(
n);
96 std::for_each(values.begin(), values.end(), [&](
const double d) { accum += (d - meanX) * (d - meanX); });
97 auto stdX = sqrt(accum /
static_cast<T
>(
n));
98 auto result = std::minmax_element(values.begin(), values.end());
99 log.
debug() <<
"Log parameter " << path <<
": " << meanX <<
" +- " << stdX <<
", " << *result.first <<
" ... "
100 << *result.second <<
", pts " <<
n << std::endl;
102 log.
debug() <<
"Cannot find : " << path << std::endl;
108template <
typename TYPE>
113 p->addValue(time,
value);
119template <
typename EP>
121 uint64_t start_nsec, uint64_t end_nsec) {
123 using namespace ANSTO;
130 const std::string neutronPath{
"instrument/detector_events"};
145 static const std::set<std::string> requiredEntries = {
"/entry1/program_name",
146 "/entry1/experiment/gumtree_version",
147 "/entry1/instrument/detector_events/event_time_zero",
148 "/entry1/instrument/detector_events/event_id",
149 "/entry1/instrument/L1/value",
150 "/entry1/instrument/L2_curtaind/value",
151 "/entry1/instrument/L2_curtainl/value",
152 "/entry1/instrument/L2_curtainr/value",
153 "/entry1/instrument/L2_curtainu/value",
154 "/entry1/instrument/nvs067/lambda/value",
155 "/entry1/instrument/shutters/fast_shutter",
156 "/entry1/scan_dataset/time",
157 "/entry1/scan_dataset/value"};
159 if (std::all_of(requiredEntries.cbegin(), requiredEntries.cend(),
160 [&descriptor](
const std::string &entry) { return descriptor.isEntry(entry); })) {
173 std::vector<std::string> exts;
178 exts.emplace_back(
".nxs");
180 "The input filename of the stored data");
184 exts.emplace_back(
".xml");
186 "The input filename of the mask data");
194 "Optional: To exclude events that do not fall within a range "
195 "of times-of-flight. "
196 "This is the minimum accepted value in microseconds. Keep "
197 "blank to load all events.");
202 "Optional: To exclude events that do not fall within a range "
203 "of times-of-flight. "
204 "This is the maximum accepted value in microseconds. Keep "
205 "blank to load all events.");
210 "Optional: To only include events after the provided start time, in "
211 "seconds (relative to the start of the run).");
216 "Optional: To only include events before the provided stop time, in "
217 "seconds (relative to the start of the run).");
221 std::string grpOptional =
"Filters";
234 if (API::AnalysisDataService::Instance().doesExist(outName))
235 API::AnalysisDataService::Instance().remove(outName);
245 uint64_t startTime, endTime;
250 if (startTime >= endTime) {
252 throw std::runtime_error(
"LoadBBY2: invalid or missing scan time range.");
265 tofMaxBoundary = std::numeric_limits<double>::infinity();
267 timeMaxBoundary = std::numeric_limits<double>::infinity();
270 prog.
doReport(
"creating instrument");
281 std::map<std::string, double> logParams;
282 std::map<std::string, std::string> logStrings;
283 std::map<std::string, std::string> allParams;
284 createInstrument(nxsEntry, startTime, endTime, instrumentInfo, logParams, logStrings, allParams);
287 if (instrumentInfo.
is_tof)
288 eventWS->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"TOF");
290 eventWS->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"Wavelength");
292 eventWS->setYUnit(
"Counts");
296 size_t numberHistograms = eventWS->getNumberHistograms();
298 std::vector<EventVector_pt> eventVectors(numberHistograms,
nullptr);
299 std::vector<size_t> eventCounts(numberHistograms, 0);
307 double period = periodSlave;
308 double shift = -1.0 / 6.0 * periodMaster - periodSlave * phaseSlave / 360.0;
311 Types::Core::DateAndTime startDateTime(instrumentInfo.
start_time);
312 auto startInNanosec = startDateTime.totalNanoseconds();
316 timeMinBoundary, timeMaxBoundary, eventCounts);
318 loadEvents<ANSTO::EventCounter>(prog,
"loading neutron counts", eventCounter, nxsEntry, startTime, endTime);
323 for (
size_t i = 0; i != numberHistograms; ++i) {
327 eventList.
reserve(eventCounts[i]);
338 if (instrumentInfo.
is_tof) {
340 timeMinBoundary, timeMaxBoundary, eventVectors);
342 loadEvents(prog,
"loading neutron events (TOF)", eventAssigner, nxsEntry, startTime, endTime);
345 startInNanosec, tofMinBoundary, tofMaxBoundary, timeMinBoundary,
346 timeMaxBoundary, eventVectors);
348 loadEvents(prog,
"loading neutron events (Wavelength)", eventAssigner, nxsEntry, startTime, endTime);
351 auto getParam = [&allParams](
const std::string &tag,
double defValue) {
353 return std::stod(allParams[tag]);
354 }
catch (
const std::invalid_argument &) {
358 if (instrumentInfo.
is_tof) {
360 eventWS->setAllX(HistogramData::BinEdges{std::max(0.0, floor(eventCounter.
tofMin())), eventCounter.
tofMax() + 1});
362 double lof = getParam(
"wavelength_extn_lo", 0.95);
363 double hif = getParam(
"wavelength_extn_hi", 1.05);
364 eventWS->setAllX(HistogramData::BinEdges{instrumentInfo.
wavelength * lof, instrumentInfo.
wavelength * hif});
368 size_t maskedBins = std::count_if(roi.begin(), roi.end(), [](
bool v) { return !v; });
370 if (maskedBins > 0) {
372 std::vector<size_t> maskIndexList(maskedBins);
373 size_t maskIndex = 0;
375 for (
size_t i = 0; i != roi.size(); i++)
377 maskIndexList[maskIndex++] = i;
380 maskingAlg->setProperty(
"Workspace", eventWS);
381 maskingAlg->setProperty(
"WorkspaceIndexList", maskIndexList);
382 maskingAlg->executeAsChildAlg();
388 auto frame_count =
static_cast<int>(eventCounter.
numFrames());
392 logManager.
addProperty(
"frame_count", frame_count);
397 logManager.
addProperty(
"bm_counts",
static_cast<double>(frame_count) * period /
400 Types::Core::time_duration duration =
401 boost::posix_time::microseconds(
static_cast<boost::int64_t
>(
static_cast<double>(frame_count) * period));
403 Types::Core::DateAndTime start_time(instrumentInfo.
start_time);
404 Types::Core::DateAndTime end_time(start_time + duration);
406 logManager.
addProperty(
"start_time", start_time.toISO8601String());
407 logManager.
addProperty(
"run_start", start_time.toISO8601String());
408 logManager.
addProperty(
"end_time", end_time.toISO8601String());
411 std::string time_str = start_time.toISO8601String();
419 for (
auto &
x : logStrings) {
422 for (
auto &
x : logParams) {
427 loadInstrumentAlg->setProperty(
"Workspace", eventWS);
428 loadInstrumentAlg->setPropertyValue(
"InstrumentName",
"BILBY");
430 loadInstrumentAlg->executeAsChildAlg();
439 if (maskfile.length() == 0)
442 std::ifstream input(maskfile.c_str());
444 throw std::invalid_argument(
"invalid mask file");
447 while (std::getline(input, line)) {
448 auto i0 = line.find(
"<detids>");
449 auto iN = line.find(
"</detids>");
451 if ((i0 != std::string::npos) && (iN != std::string::npos) && (i0 < iN)) {
452 line = line.substr(i0 + 8, iN - i0 - 8);
453 std::stringstream ss(line);
456 while (std::getline(ss, item,
',')) {
457 auto k = item.find(
'-');
460 if (k != std::string::npos) {
461 p0 = boost::lexical_cast<size_t>(item.substr(0, k));
462 p1 = boost::lexical_cast<size_t>(item.substr(k + 1, item.size() - k - 1));
467 p0 = boost::lexical_cast<size_t>(item);
471 if (p0 < result.size()) {
472 if (p1 >= result.size())
473 p1 = result.size() - 1;
476 result[p0++] =
false;
487 std::map<std::string, double> &logParams,
488 std::map<std::string, std::string> &logStrings,
489 std::map<std::string, std::string> &allParams) {
491 std::string idfDirectory = Mantid::Kernel::ConfigService::Instance().getString(
"instrumentDefinition.directory");
494 std::string parameterFilename = idfDirectory +
"BILBY_Parameters.xml";
497 Poco::AutoPtr<Poco::XML::Document> pDoc;
499 pDoc = pParser.parse(parameterFilename);
503 NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
504 Node *pNode = it.nextNode();
506 if (pNode->nodeName() ==
"parameter") {
507 auto pElem =
dynamic_cast<Element *
>(pNode);
508 std::string paramName = pElem->getAttribute(
"name");
509 Poco::AutoPtr<NodeList> nodeList = pElem->childNodes();
510 for (
unsigned long i = 0; i < nodeList->length(); i++) {
511 auto cNode = nodeList->item(i);
512 if (cNode->nodeName() ==
"value") {
513 auto cElem =
dynamic_cast<Poco::XML::Element *
>(cNode);
514 std::string
value = cElem->getAttribute(
"val");
515 allParams[paramName] = std::move(
value);
519 pNode = it.nextNode();
522 auto isNumeric = [](
const std::string &tag) {
524 auto stag = boost::algorithm::trim_copy(tag);
526 auto value = std::stod(stag, &sz);
527 return sz > 0 && stag.size() == sz && std::isfinite(
value);
528 }
catch (
const std::invalid_argument &) {
533 std::string tmpString;
534 double tmpDouble = 0.0f;
535 uint64_t tmpTimestamp = 0;
536 for (
auto &
x : allParams) {
537 if (
x.first.find(
"log_") == 0) {
538 auto logTag = boost::algorithm::trim_copy(
x.first.substr(4));
539 auto line =
x.second;
542 std::vector<std::string> details;
543 boost::split(details, line, boost::is_any_of(
","));
544 if (details.size() < 3) {
545 g_log.
warning() <<
"Invalid format for BILBY parameter " <<
x.first << std::endl;
548 auto hdfTag = boost::algorithm::trim_copy(details[0]);
552 auto updateOk =
false;
553 if (!hdfTag.empty()) {
554 if (isNumeric(details[1])) {
556 bool timeLoaded =
false;
558 auto key = (details.size() < 4) ?
"mean" : boost::algorithm::trim_copy(details[3]);
561 (imap !=
ScanLogMap.end()) ? imap->second : Anxs::ScanLog::Mean;
563 tmpDouble, tmpString);
565 if (baseLoaded || timeLoaded) {
566 auto factor = std::stod(details[1]);
567 logParams[logTag] = factor * tmpDouble;
570 traceStatistics<double>(entry, hdfTag, startTime, endTime,
g_log);
574 logStrings[logTag] = tmpString;
581 auto defValue = boost::algorithm::trim_copy(details[2]);
582 if (!defValue.empty()) {
583 if (isNumeric(defValue))
584 logParams[logTag] = std::stod(defValue);
586 logStrings[logTag] = std::move(defValue);
588 g_log.
warning() <<
"Cannot find hdf parameter " << hdfTag <<
", using default.\n";
591 }
catch (
const std::invalid_argument &) {
592 g_log.
warning() <<
"Invalid format for BILBY parameter " <<
x.first << std::endl;
596 }
catch (std::exception &ex) {
597 g_log.
warning() <<
"Failed to load instrument with error: " << ex.what()
598 <<
". The current facility may not be fully "
605 InstrumentInfo &instrumentInfo, std::map<std::string, double> &logParams,
606 std::map<std::string, std::string> &logStrings,
607 std::map<std::string, std::string> &allParams) {
611 instrumentInfo.
start_time =
"2000-01-01T00:00:00";
618 instrumentInfo.
is_tof =
true;
625 double tmp_double = 0.0f;
626 int64_t tmp_int64 = 0;
627 uint64_t tmp_timestamp = 0;
633 instrumentInfo.
att_pos = boost::math::iround(tmp_double);
640 uint64_t epochStart{0};
641 auto timeTag = (
useHMScanTime ?
"hmscan/time" :
"scan_dataset/time");
644 instrumentInfo.
start_time = startDateTime.toISO8601String();
653 instrumentInfo.
is_tof = tmp_str ==
"EXTERNAL";
656 tmp_timestamp, tmp_double, tmp_str))
660 tmp_timestamp, tmp_double, tmp_str) &&
665 tmp_timestamp, tmp_double, tmp_str) &&
670 tmp_timestamp, tmp_double, tmp_str))
671 instrumentInfo.
phase_slave = tmp_double < 999.0 ? tmp_double : 0.0;
674 traceStatistics<double>(entry,
"instrument/nvs067/lambda", startTime, endTime,
g_log);
675 traceStatistics<double>(entry,
"instrument/master_chopper_freq", startTime, endTime,
g_log);
676 traceStatistics<double>(entry,
"instrument/t0_chopper_freq", startTime, endTime,
g_log);
677 traceStatistics<double>(entry,
"instrument/t0_chopper_phase", startTime, endTime,
g_log);
683 auto findLtof = logParams.find(
"Ltof_det_value");
684 if (findLtof != logParams.end()) {
685 logParams[
"L1_chopper_value"] = logParams[
"Ltof_det_value"] - logParams[
"L2_det_value"];
687 logParams[
"L1_chopper_value"] = 18.4726;
688 g_log.
warning() <<
"Cannot recover parameter 'L1_chopper_value'"
689 <<
", using default.\n";
double value
The value of the point.
#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.
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.
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) override
Create a Child Algorithm.
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)
int confidence(Nexus::NexusDescriptor &descriptor) const override
Return the confidence value that this algorithm can load the file.
LoadBBY2()
Empty default constructor.
void loadInstrumentParameters(const Nexus::NXEntry &entry, uint64_t startTime, uint64_t endTime, std::map< std::string, double > &logParams, std::map< std::string, std::string > &logStrings, std::map< std::string, std::string > &allParams)
void init() override
Initialise the algorithm.
void createInstrument(const Nexus::NXEntry &entry, uint64_t startTime, uint64_t endTime, InstrumentInfo &instrumentInfo, std::map< std::string, double > &logParams, std::map< std::string, std::string > &logStrings, std::map< std::string, std::string > &allParams)
void execLoader() override
Execute the algorithm.
static std::vector< bool > createRoiVector(const std::string &maskfile)
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.
Records the filename and the description of failure.
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.
The Logger class is in charge of the publishing messages from the framework through various channels.
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
bool isDebug() const
Returns true if log level is at least debug.
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
A specialised Property class for holding a series of time-value pairs.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::string extractWorkspaceTitle(const std::string &nxsFile)
void ReadEventData(ProgressTracker &prog, const Nexus::NXEntry &entry, EventProcessor *handler, uint64_t start_nsec, uint64_t end_nsec, const std::string &neutron_path, int tube_resolution=1024)
bool loadNXString(const Nexus::NXEntry &entry, const std::string &path, std::string &value)
int64_t epochRelDateTimeBase(int64_t epochInNanoSeconds)
bool loadNXDataSet(const Nexus::NXEntry &entry, const std::string &path, T &value, int index)
std::pair< uint64_t, uint64_t > getHMScanLimits(const Nexus::NXEntry &entry, int datasetIx)
uint64_t extractTimedDataSet(const Nexus::NXEntry &entry, const std::string &path, uint64_t startTime, uint64_t endTime, std::vector< uint64_t > ×, std::vector< T > &events, std::string &units)
std::pair< uint64_t, uint64_t > getTimeScanLimits(const Nexus::NXEntry &entry, int datasetIx)
std::vector< Types::Event::TofEvent > * EventVector_pt
pointer to the vector of events
static char const *const FilenameStr
static char const *const FilterByTofMaxStr
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 FilterByTofMinStr
void loadEvents(API::Progress &prog, const char *progMsg, EP &eventProcessor, const Nexus::NXEntry &entry, uint64_t start_nsec, uint64_t end_nsec)
void traceStatistics(const Nexus::NXEntry &entry, const std::string &path, uint64_t startTime, uint64_t endTime, Kernel::Logger &log)
static char const *const MaskStr
static char const *const FilterByTimeStartStr
static const size_t Progress_Total
static char const *const UseHMScanTimeStr
static const std::map< std::string, Anxs::ScanLog > ScanLogMap
static char const *const FilterByTimeStopStr
static const size_t Progress_ReserveMemory
static const int LAST_INDEX
DLLExport void getEventsFrom(EventList &el, std::vector< Types::Event::TofEvent > *&events)
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
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 sample_description
int64_t master2_chopper_id
int64_t master1_chopper_id
@ Input
An input workspace.
@ Output
An output workspace.