15#include <nexus/NeXusFile.hpp>
17#include <boost/lexical_cast.hpp>
25using namespace Kernel;
29const int ADDABLES = 12;
31const std::string ADDABLE[ADDABLES] = {
"tot_prtn_chrg",
"rawfrm",
"goodfrm",
"dur",
32 "gd_prtn_chrg",
"uA.hour",
"monitor0_counts",
"monitor1_counts",
33 "monitor2_counts",
"monitor3_counts",
"monitor4_counts",
"monitor5_counts"};
35const char *GONIOMETER_LOG_NAME =
"goniometer";
36const char *GONIOMETERS_LOG_NAME =
"goniometers";
38const char *HISTO_BINS_LOG_NAME =
"processed_histogram_bins";
39const char *PEAK_RADIUS_GROUP =
"peak_radius";
40const char *INNER_BKG_RADIUS_GROUP =
"inner_bkg_radius";
41const char *OUTER_BKG_RADIUS_GROUP =
"outer_bkg_radius";
44Kernel::Logger
g_log(
"Run");
49 m_goniometers.push_back(std::make_unique<Geometry::Goniometer>());
79 auto clone = std::make_shared<Run>();
80 for (
auto property : this->
m_manager->getProperties()) {
81 clone->addProperty(property->clone());
83 clone->copyGoniometers(
const_cast<Run &
>(*
this));
101void Run::filterByTime(
const Types::Core::DateAndTime start,
const Types::Core::DateAndTime stop) {
118 for (
const auto &name : ADDABLE) {
119 if (
rhs.m_manager->existsProperty(name)) {
130 m_manager->declareProperty(std::unique_ptr<Property>(
right->clone()),
"");
151 for (
auto output : outputs) {
153 auto run =
dynamic_cast<Run *
>(output);
166 const std::string PROTON_CHARGE_UNITS(
"uA.hour");
171 charge_prop->
setValue(boost::lexical_cast<std::string>(charge));
172 charge_prop->
setUnits(PROTON_CHARGE_UNITS);
186 g_log.
notice() <<
"There is no proton charge associated with this workspace" << std::endl;
215 g_log.
warning(logname +
" log was not found. The value of the total proton "
216 "charge has not been set");
223 double total = std::accumulate(logValues.begin(), logValues.end(), 0.0);
224 const std::string &unit = log->
units();
226 if (unit.find(
"picoCoulomb") != std::string::npos) {
228 const double currentConversion = 1.e-6 / 3600.;
229 total *= currentConversion;
230 }
else if (!unit.empty() && unit !=
"uAh") {
231 g_log.
warning(logname +
" log has units other than uAh or "
232 "picoCoulombs. The value of the total proton charge has "
233 "been left at the sum of the log values.");
237 g_log.
warning(logname +
" log was not a time series property. The value of the total proton "
238 "charge has not been set");
252 if (histoBins.size() < 2) {
253 std::ostringstream os;
254 os <<
"Run::storeEnergyBinBoundaries - Fewer than 2 values given, size=" << histoBins.size()
255 <<
". Cannot interpret values as bin boundaries.";
256 throw std::invalid_argument(os.str());
258 if (histoBins.front() >= histoBins.back()) {
259 std::ostringstream os;
260 os <<
"Run::storeEnergyBinBoundaries - Inconsistent start & end values "
262 << histoBins.size() <<
". Cannot interpret values as bin boundaries.";
263 throw std::out_of_range(os.str());
277 throw std::runtime_error(
"Run::histogramBoundaries - No energy bins have "
278 "been stored for this run");
282 std::ostringstream os;
283 os <<
"Run::histogramBinBoundaries- Value lower than first bin boundary. "
286 throw std::out_of_range(os.str());
289 std::ostringstream os;
290 os <<
"Run::histogramBinBoundaries- Value greater than last bin boundary. "
293 throw std::out_of_range(os.str());
306 throw std::runtime_error(
"Run::histogramBoundaries - No energy bins have "
307 "been stored for this run");
339 m_goniometers.emplace_back(std::make_unique<Geometry::Goniometer>(goniometer));
342 }
catch (std::runtime_error &) {
357 }
catch (std::runtime_error &) {
382 m_goniometers.emplace_back(std::make_unique<Geometry::Goniometer>(goniometer));
398 throw std::out_of_range(
"Run::getGoniometer() const: index is out of range.");
410 throw std::out_of_range(
"Run::getGoniometer() const: index is out of range.");
423 throw std::out_of_range(
"Run::getGoniometer() const: index is out of range.");
432 std::vector<Kernel::Matrix<double>> goniometers;
435 goniometers.emplace_back((*it)->getR());
446void Run::saveNexus(::NeXus::File *file,
const std::string &group,
bool keepOpen)
const {
453 file->makeGroup(GONIOMETERS_LOG_NAME,
"NXcollection",
true);
454 file->writeData(
"num_goniometer",
int(
m_goniometers.size()));
463 file->makeGroup(HISTO_BINS_LOG_NAME,
"NXdata",
true);
468 const std::vector<double> &values = this->getPropertyValueAsType<std::vector<double>>(
"PeakRadius");
470 file->makeGroup(PEAK_RADIUS_GROUP,
"NXdata",
true);
471 file->writeData(
"value", values);
475 file->makeGroup(INNER_BKG_RADIUS_GROUP,
"NXdata",
true);
476 const std::vector<double> &values = this->getPropertyValueAsType<std::vector<double>>(
"BackgroundInnerRadius");
477 file->writeData(
"value", values);
481 file->makeGroup(OUTER_BKG_RADIUS_GROUP,
"NXdata",
true);
482 const std::vector<double> &values = this->getPropertyValueAsType<std::vector<double>>(
"BackgroundOuterRadius");
483 file->writeData(
"value", values);
499 const std::string &prefix,
bool keepOpen) {
501 if (!group.empty()) {
502 file->openGroup(group,
"NXgroup");
506 const std::string absoluteGroupName = prefix +
"/" + group;
510 const auto levels = std::count(absoluteGroupName.begin(), absoluteGroupName.end(),
'/');
514 for (
const auto &nxClassPair : allEntries) {
515 const std::set<std::string> &nxClassEntries = nxClassPair.second;
520 auto itLower = nxClassEntries.lower_bound(absoluteGroupName);
522 if (itLower == nxClassEntries.end()) {
525 if (itLower->compare(0, absoluteGroupName.size(), absoluteGroupName) != 0) {
530 for (
auto it = itLower;
531 it != nxClassEntries.end() && it->compare(0, absoluteGroupName.size(), absoluteGroupName) == 0; ++it) {
534 const std::string &absoluteEntryName = *it;
535 if (std::count(absoluteEntryName.begin(), absoluteEntryName.end(),
'/') != levels + 1) {
538 const std::string nameClass = absoluteEntryName.substr(absoluteEntryName.find_last_of(
'/') + 1);
543 if (!(group.empty() || keepOpen))
565void Run::loadNexus(::NeXus::File *file,
const std::string &group,
bool keepOpen) {
567 if (!group.empty()) {
568 file->openGroup(group,
"NXgroup");
570 std::map<std::string, std::string> entries;
571 file->getEntries(entries);
573 for (
const auto &name_class : entries) {
576 if (!(group.empty() || keepOpen))
598 for (
size_t i = 0; i <
m_goniometers[0]->getNumberAxes(); ++i) {
599 const std::string axisName =
m_goniometers[0]->getAxis(i).name;
604 if (minAngle != maxAngle && !(std::isnan(minAngle) && std::isnan(maxAngle))) {
606 g_log.
warning(
"Goniometer angle changed in " + axisName +
" log from " +
607 boost::lexical_cast<std::string>(minAngle) +
" to " + boost::lexical_cast<std::string>(maxAngle) +
608 ". Used time averaged value = " + boost::lexical_cast<std::string>(angle) +
".");
609 if (axisName ==
"omega") {
610 g_log.
warning(
"To set to last angle, replace omega with " + boost::lexical_cast<std::string>(lastAngle) +
612 "SetGoniometer(Workspace=\'workspace\',Axis0=omega,0,1,0,"
613 "1\',Axis1='chi,0,0,1,1',Axis2='phi,0,1,0,1')");
614 }
else if (axisName ==
"chi") {
615 g_log.
warning(
"To set to last angle, replace chi with " + boost::lexical_cast<std::string>(lastAngle) +
617 "SetGoniometer(Workspace=\'workspace\',Axis0=omega,0,1,0,"
618 "1\',Axis1='chi,0,0,1,1',Axis2='phi,0,1,0,1')");
619 }
else if (axisName ==
"phi") {
620 g_log.
warning(
"To set to last angle, replace phi with " + boost::lexical_cast<std::string>(lastAngle) +
622 "SetGoniometer(Workspace=\'workspace\',Axis0=omega,0,1,0,"
623 "1\',Axis1='chi,0,0,1,1',Axis2='phi,0,1,0,1')");
636 throw std::runtime_error(
"Run::calculateGoniometerMatrices must include axes for goniometer");
638 const size_t num_log_values = getTimeSeriesProperty<double>(goniometer.
getAxis(0).
name)->size();
643 for (
size_t i = 0; i < num_log_values; ++i)
644 m_goniometers.emplace_back(std::make_unique<Geometry::Goniometer>(goniometer));
647 const auto angles = getTimeSeriesProperty<double>(goniometer.
getAxis(i).
name)->valuesAsVector();
648 if (angles.size() != num_log_values)
649 throw std::runtime_error(
"Run::calculateGoniometerMatrices different "
650 "number of log entries between axes");
652 for (
size_t j = 0; j < num_log_values; ++j) {
667 for (
auto ptr : inc) {
668 const std::string &rhs_name = ptr->name();
672 lhs_prop->
merge(ptr);
675 auto copy = std::unique_ptr<Property>(ptr->clone());
688 for (
const auto &goniometer : other.m_goniometers) {
689 auto new_goniometer = std::make_unique<Geometry::Goniometer>(*goniometer);
695 if (nameClass == GONIOMETER_LOG_NAME) {
698 }
else if (nameClass == GONIOMETERS_LOG_NAME) {
699 file->openGroup(nameClass,
"NXcollection");
701 file->readData(
"num_goniometer", num_goniometer);
704 for (
int i = 0; i < num_goniometer; i++) {
705 m_goniometers.emplace_back(std::make_unique<Geometry::Goniometer>());
709 }
else if (nameClass == HISTO_BINS_LOG_NAME) {
710 file->openGroup(nameClass,
"NXdata");
713 }
else if (nameClass == PEAK_RADIUS_GROUP) {
714 file->openGroup(nameClass,
"NXdata");
715 std::vector<double> values;
716 file->readData(
"value", values);
719 }
else if (nameClass == INNER_BKG_RADIUS_GROUP) {
720 file->openGroup(nameClass,
"NXdata");
721 std::vector<double> values;
722 file->readData(
"value", values);
724 this->
addProperty(
"BackgroundInnerRadius", values,
true);
725 }
else if (nameClass == OUTER_BKG_RADIUS_GROUP) {
726 file->openGroup(nameClass,
"NXdata");
727 std::vector<double> values;
728 file->readData(
"value", values);
730 this->
addProperty(
"BackgroundOuterRadius", values,
true);
731 }
else if (nameClass ==
"proton_charge" && !this->
hasProperty(
"proton_charge")) {
734 file->readData(
"proton_charge", charge);
const std::vector< double > & rhs
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
This class contains the information about the log entries.
virtual size_t getMemorySize() const
Return an approximate memory size for the object in bytes.
bool hasProperty(const std::string &name) const
Does the property exist on the object.
virtual void loadNexus(::NeXus::File *file, const std::string &group, const Mantid::Kernel::NexusHDF5Descriptor &fileInfo, const std::string &prefix, bool keepOpen=false)
Load the run from a NeXus file with a given group name.
std::unique_ptr< Kernel::PropertyManager > m_manager
A pointer to a property manager.
virtual void saveNexus(::NeXus::File *file, const std::string &group, bool keepOpen=false) const
Save the run to a NeXus file with a given group name.
static const char * PROTON_CHARGE_LOG_NAME
Name of the log entry containing the proton charge when retrieved using getProtonCharge.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
virtual void filterByTime(const Types::Core::DateAndTime start, const Types::Core::DateAndTime stop)
Filter the logs by time.
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
LogManager & operator=(const LogManager &other)
bool operator==(const LogManager &other) const
double getLogAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic=Kernel::Math::Mean) const
virtual void splitByTime(Kernel::TimeSplitterType &splitter, std::vector< LogManager * > outputs) const
Split the logs based on the given intervals.
This class stores information regarding an experimental run as a series of log entries.
void splitByTime(Kernel::TimeSplitterType &splitter, std::vector< LogManager * > outputs) const override
Split the logs based on the given intervals.
void storeHistogramBinBoundaries(const std::vector< double > &histoBins)
Store the given values as a set of histogram bin boundaries.
bool operator!=(const Run &other)
void setProtonCharge(const double charge)
Set the proton charge.
bool operator==(const Run &other)
Run & operator+=(const Run &rhs)
Addition.
void integrateProtonCharge(const std::string &logname="proton_charge") const
Integrate the proton charge over the whole run time - default log proton_charge.
void copyGoniometers(const Run &other)
Copy the goniometers from another.
std::vector< double > getBinBoundaries() const
Returns the vector of bin boundaries.
std::vector< std::unique_ptr< Geometry::Goniometer > > m_goniometers
Goniometer for this run.
size_t getNumGoniometers() const
Get the number of goniometers in the Run.
void clearGoniometers()
Clear all goniometers on the Run.
void calculateGoniometerMatrices(const Geometry::Goniometer &goniometer)
Calculate the gonoimeter matrices from logs.
void setGoniometer(const Geometry::Goniometer &goniometer, const bool useLogValues)
Set a single gonoimeter & read the average values from the logs if told to do so.
void calculateAverageGoniometerMatrix()
Calculate the average gonoimeter matrix.
Geometry::Goniometer & mutableGoniometer()
Return reference to the first non-const Goniometer object for this run.
const Geometry::Goniometer & getGoniometer() const
Return reference to the first const Goniometer object for this run.
size_t getMemorySize() const override
Return an approximate memory size for the object in bytes.
const Kernel::Matrix< double > & getGoniometerMatrix() const
Retrieve the first goniometer rotation matrix.
void filterByTime(const Types::Core::DateAndTime start, const Types::Core::DateAndTime stop) override
Filter the logs by time.
size_t addGoniometer(const Geometry::Goniometer &goniometer)
Append a goniometer to the run.
std::shared_ptr< Run > clone()
Clone.
double getProtonCharge() const
Get the proton charge.
void saveNexus(::NeXus::File *file, const std::string &group, bool keepOpen=false) const override
Save the run to a NeXus file with a given group name.
void loadNexusCommon(::NeXus::File *file, const std::string &nameClass)
void loadNexus(::NeXus::File *file, const std::string &group, const Mantid::Kernel::NexusHDF5Descriptor &fileInfo, const std::string &prefix, bool keepOpen=false) override
Load the run from a NeXus file with a given group name.
void mergeMergables(Mantid::Kernel::PropertyManager &sum, const Mantid::Kernel::PropertyManager &toAdd)
Adds all the time series in from one property manager into another.
std::pair< double, double > histogramBinBoundaries(const double value) const
Returns the bin boundaries for a given value.
void setGoniometers(const Geometry::Goniometer &goniometer)
Set the gonoimeters using the individual values.
Run & operator=(const Run &other)
const std::vector< Kernel::Matrix< double > > getGoniometerMatrices() const
Get vector of all goniometer matrices in the Run.
std::vector< double > m_histoBins
A set of histograms that can be stored here for future reference.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
size_t getNumberAxes() const
const GoniometerAxis & getAxis(size_t axisnumber) const
Get GoniometerAxis obfject using motor number.
Exception for when an item is not found in a collection.
void notice(const std::string &msg)
Logs at notice level.
void warning(const std::string &msg)
Logs at warning level.
const std::map< std::string, std::set< std::string > > & getAllEntries() const noexcept
Returns a const reference of the internal map holding all entries in the NeXus HDF5 file.
Property manager helper class.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void declareProperty(std::unique_ptr< Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
const std::vector< Property * > & getProperties() const override
Get the list of managed properties.
The concrete, templated class for properties.
std::string value() const override
Returns the value of the property as a string.
Base class for properties.
virtual const std::string & units() const
Returns the units of the property, if any, as a string.
virtual std::string setValue(const std::string &)=0
Set the value of the property via a string.
virtual void setUnits(const std::string &unit)
Sets the units of the property, as a string.
virtual Property & merge(Property *)
Just returns the property (*this) unless overridden.
A specialised Property class for holding a series of time-value pairs.
std::vector< TYPE > valuesAsVector() const
Return the time series's values (unfiltered) as a vector<TYPE>
Kernel::Logger g_log("ExperimentInfo")
static logger object
MANTID_KERNEL_DLL int getBinIndex(const std::vector< double > &bins, const double value)
Return the index into a vector of bin boundaries for a particular X value.
std::vector< SplittingInterval > TimeSplitterType
A typedef for splitting events according their pulse time.
std::string to_string(const wide_integer< Bits, Signed > &n)