Mantid
Loading...
Searching...
No Matches
LogManager.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
12
13#include <nexus/NeXusFile.hpp>
14
15namespace Mantid::API {
16
17using namespace Kernel;
18using namespace Types::Core;
19
20namespace {
22Logger g_log("LogManager");
23
25template <typename T> bool convertSingleValue(const Property *property, double &value) {
26 if (auto log = dynamic_cast<const PropertyWithValue<T> *>(property)) {
27 value = static_cast<double>(*log);
28 return true;
29 } else {
30 return false;
31 }
32}
33
35template <typename T>
36bool convertTimeSeriesToDouble(const Property *property, double &value, const Math::StatisticType &function) {
37 if (const auto *log = dynamic_cast<const TimeSeriesProperty<T> *>(property)) {
38 switch (function) {
40 value = static_cast<double>(log->timeAverageValue());
41 break;
43 value = static_cast<double>(log->firstValue());
44 break;
45 case Math::LastValue:
46 value = static_cast<double>(log->lastValue());
47 break;
48 case Math::Maximum:
49 value = static_cast<double>(log->maxValue());
50 break;
51 case Math::Minimum:
52 value = static_cast<double>(log->minValue());
53 break;
54 case Math::Mean:
55 value = static_cast<double>(log->mean());
56 break;
57 case Math::Median:
58 value = log->getStatistics().median;
59 break;
60 default: // should not happen
61 throw std::invalid_argument("Statistic type not recognised/supported");
62 }
63 return true;
64 } else {
65 return false;
66 }
67}
68
70template <typename T>
71bool convertPropertyToDouble(const Property *property, double &value, const Math::StatisticType &function) {
72 return convertSingleValue<T>(property, value) || convertTimeSeriesToDouble<T>(property, value, function);
73}
74
76bool convertPropertyToDouble(const Property *property, double &value, const Math::StatisticType &function) {
77 // Order these with double and int first, and less likely options later.
78 // The first one to succeed short-circuits and the value is returned.
79 // If all fail, returns false.
80 return convertPropertyToDouble<double>(property, value, function) ||
81 convertPropertyToDouble<int32_t>(property, value, function) ||
82 convertPropertyToDouble<int64_t>(property, value, function) ||
83 convertPropertyToDouble<uint32_t>(property, value, function) ||
84 convertPropertyToDouble<uint64_t>(property, value, function) ||
85 convertPropertyToDouble<float>(property, value, function);
86}
87} // namespace
88
91const char *LogManager::PROTON_CHARGE_LOG_NAME = "gd_prtn_chrg";
92//----------------------------------------------------------------------
93// Public member functions
94//----------------------------------------------------------------------
95
97 : m_manager(std::make_unique<Kernel::PropertyManager>()),
98 m_singleValueCache(
99 std::make_unique<Kernel::Cache<std::pair<std::string, Kernel::Math::StatisticType>, double>>()) {}
100
102 : m_manager(std::make_unique<Kernel::PropertyManager>(*other.m_manager)),
103 m_singleValueCache(std::make_unique<Kernel::Cache<std::pair<std::string, Kernel::Math::StatisticType>, double>>(
104 *other.m_singleValueCache)) {}
105
106// Defined as default in source for forward declaration with std::unique_ptr.
107LogManager::~LogManager() = default;
108
110 *m_manager = *other.m_manager;
111 m_singleValueCache = std::make_unique<Kernel::Cache<std::pair<std::string, Kernel::Math::StatisticType>, double>>(
112 *other.m_singleValueCache);
113 return *this;
114}
115
121void LogManager::setStartAndEndTime(const Types::Core::DateAndTime &start, const Types::Core::DateAndTime &end) {
122 this->addProperty<std::string>("start_time", start.toISO8601String(), true);
123 this->addProperty<std::string>("end_time", end.toISO8601String(), true);
124}
125
133const Types::Core::DateAndTime LogManager::startTime() const {
134 const std::string start_prop("start_time");
135 if (hasProperty(start_prop)) {
136 try {
137 DateAndTime start_time(getProperty(start_prop)->value());
138 if (start_time != DateAndTime::GPS_EPOCH) {
139 return start_time;
140 }
141 } catch (std::invalid_argument &) { /*Swallow and move on*/
142 }
143 }
144
145 const std::string run_start_prop("run_start");
146 if (hasProperty(run_start_prop)) {
147 try {
148 DateAndTime start_time(getProperty(run_start_prop)->value());
149 if (start_time != DateAndTime::GPS_EPOCH) {
150 return start_time;
151 }
152 } catch (std::invalid_argument &) { /*Swallow and move on*/
153 }
154 }
155
156 throw std::runtime_error("No valid start time has been set for this run.");
157}
158
165const Types::Core::DateAndTime LogManager::endTime() const {
166 const std::string end_prop("end_time");
167 if (hasProperty(end_prop)) {
168 try {
169 return DateAndTime(getProperty(end_prop)->value());
170 } catch (std::invalid_argument &) { /*Swallow and move on*/
171 }
172 }
173
174 const std::string run_end_prop("run_end");
175 if (hasProperty(run_end_prop)) {
176 try {
177 return DateAndTime(getProperty(run_end_prop)->value());
178 } catch (std::invalid_argument &) { /*Swallow and move on*/
179 }
180 }
181
182 throw std::runtime_error("No valid end time has been set for this run.");
183}
184
185//-----------------------------------------------------------------------------------------------
196void LogManager::filterByTime(const Types::Core::DateAndTime start, const Types::Core::DateAndTime stop) {
197 // The propery manager operator will make all timeseriesproperties filter.
198 m_manager->filterByTime(start, stop);
199}
200
201//-----------------------------------------------------------------------------------------------
209void LogManager::splitByTime(TimeSplitterType &splitter, std::vector<LogManager *> outputs) const {
210 // Make a vector of managers for the splitter. Fun!
211 const size_t n = outputs.size();
212 std::vector<PropertyManager *> output_managers(outputs.size(), nullptr);
213 for (size_t i = 0; i < n; i++) {
214 if (outputs[i]) {
215 output_managers[i] = outputs[i]->m_manager.get();
216 }
217 }
218
219 // Now that will do the split down here.
220 m_manager->splitByTime(splitter, output_managers);
221}
222
223//-----------------------------------------------------------------------------------------------
232 const std::vector<std::string> &excludedFromFiltering) {
233 // This will invalidate the cache
234 m_singleValueCache->clear();
235 m_manager->filterByProperty(filter, excludedFromFiltering);
236}
237
238//-----------------------------------------------------------------------------------------------
247void LogManager::addProperty(std::unique_ptr<Kernel::Property> prop, bool overwrite) {
248 // Make an exception for the proton charge
249 // and overwrite it's value as we don't want to store the proton charge in two
250 // separate locations
251 // Similar we don't want more than one run_title
252 std::string name = prop->name();
253 if (hasProperty(name) && (overwrite || prop->name() == PROTON_CHARGE_LOG_NAME || prop->name() == "run_title")) {
254 removeProperty(name);
255 }
256 m_manager->declareProperty(std::move(prop), "");
257}
258
259//-----------------------------------------------------------------------------------------------
265bool LogManager::hasProperty(const std::string &name) const { return m_manager->existsProperty(name); }
266
267//-----------------------------------------------------------------------------------------------
275void LogManager::removeProperty(const std::string &name, bool delProperty) {
276 // Remove any cached entries for this log. Need to make this more general
277 for (unsigned int stat = 0; stat < 7; ++stat) {
278 m_singleValueCache->removeCache(std::make_pair(name, static_cast<Math::StatisticType>(stat)));
279 }
280 m_manager->removeProperty(name, delProperty);
281}
282
287const std::vector<Kernel::Property *> &LogManager::getProperties() const { return m_manager->getProperties(); }
288
289//-----------------------------------------------------------------------------------------------
293 size_t total = 0;
294 std::vector<Property *> props = m_manager->getProperties();
295 for (auto p : props) {
296 if (p)
297 total += p->getMemorySize() + sizeof(Property *);
298 }
299 return total;
300}
301
308template <typename T> Kernel::TimeSeriesProperty<T> *LogManager::getTimeSeriesProperty(const std::string &name) const {
309 Kernel::Property *prop = getProperty(name);
310 if (auto *tsp = dynamic_cast<Kernel::TimeSeriesProperty<T> *>(prop)) {
311 return tsp;
312 } else {
313 throw std::invalid_argument("Run::getTimeSeriesProperty - '" + name + "' is not a TimeSeriesProperty");
314 }
315}
316
322double LogManager::getTimeAveragedStd(const std::string &name) const {
323 return getTimeSeriesProperty<double>(name)->getStatistics().time_standard_deviation;
324}
325
332template <typename HeldType> HeldType LogManager::getPropertyValueAsType(const std::string &name) const {
333 Kernel::Property *prop = getProperty(name);
334 if (auto *valueProp = dynamic_cast<Kernel::PropertyWithValue<HeldType> *>(prop)) {
335 return (*valueProp)();
336 } else {
337 throw std::invalid_argument("Run::getPropertyValueAsType - '" + name + "' is not of the requested type");
338 }
339}
340
349double LogManager::getPropertyAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic) const {
350 double singleValue(0.0);
351 const auto key = std::make_pair(name, statistic);
352 if (!m_singleValueCache->getCache(key, singleValue)) {
353 const Property *log = getProperty(name);
354 if (!convertPropertyToDouble(log, singleValue, statistic)) {
355 if (const auto stringLog = dynamic_cast<const PropertyWithValue<std::string> *>(log)) {
356 // Try to lexically cast string to a double
357 try {
358 singleValue = std::stod(stringLog->value());
359 } catch (const std::invalid_argument &) {
360 throw std::invalid_argument("Run::getPropertyAsSingleValue - Property \"" + name +
361 "\" cannot be converted to a numeric value.");
362 }
363 } else {
364 throw std::invalid_argument("Run::getPropertyAsSingleValue - Property \"" + name +
365 "\" is not a single numeric value or numeric time series.");
366 }
367 }
368 // Put it in the cache
369 m_singleValueCache->setCache(key, singleValue);
370 }
371 return singleValue;
372}
373
381int LogManager::getPropertyAsIntegerValue(const std::string &name) const {
382 int singleValue(0);
383 double discard(0);
384
385 Property *prop = getProperty(name);
386
387 if (convertSingleValue<int32_t>(prop, discard) || convertSingleValue<int64_t>(prop, discard) ||
388 convertSingleValue<uint32_t>(prop, discard) || convertSingleValue<uint64_t>(prop, discard)) {
389 singleValue = std::stoi(prop->value());
390 } else {
391 throw std::invalid_argument("Run::getPropertyAsIntegerValue - Property \"" + name +
392 "\" cannot be converted to an integer value.");
393 }
394
395 return singleValue;
396}
397
404Kernel::Property *LogManager::getProperty(const std::string &name) const { return m_manager->getProperty(name); }
405
413 auto &props = getProperties();
414
415 // Loop over the set of properties, identifying those that are time-series
416 // properties
417 // and then clearing them out.
418 for (auto prop : props) {
419 if (auto tsp = dynamic_cast<ITimeSeriesProperty *>(prop)) {
420 tsp->clear();
421 }
422 }
423}
424
430 auto &props = getProperties();
431 for (auto prop : props) {
432 if (auto tsp = dynamic_cast<ITimeSeriesProperty *>(prop)) {
433 tsp->clearOutdated();
434 }
435 }
436}
437
438//--------------------------------------------------------------------------------------------
445void LogManager::saveNexus(::NeXus::File *file, const std::string &group, bool keepOpen) const {
446 file->makeGroup(group, "NXgroup", true);
447 file->putAttr("version", 1);
448
449 // Save all the properties as NXlog
450 std::vector<Property *> props = m_manager->getProperties();
451 for (auto &prop : props) {
452 try {
453 prop->saveProperty(file);
454 } catch (std::invalid_argument &exc) {
455 g_log.warning(exc.what());
456 }
457 }
458 if (!keepOpen)
459 file->closeGroup();
460}
461
462//--------------------------------------------------------------------------------------------
471void LogManager::loadNexus(::NeXus::File * /*file*/, const std::string & /*group*/,
472 const Mantid::Kernel::NexusHDF5Descriptor & /*fileInfo*/, const std::string & /*prefix*/,
473 bool /*keepOpen*/) {}
474
475//--------------------------------------------------------------------------------------------
484void LogManager::loadNexus(::NeXus::File *file, const std::string &group, bool keepOpen) {
485 if (!group.empty()) {
486 file->openGroup(group, "NXgroup");
487 }
488 std::map<std::string, std::string> entries;
489 file->getEntries(entries);
490 LogManager::loadNexus(file, entries);
491
492 if (!(group.empty() || keepOpen)) {
493 file->closeGroup();
494 }
495}
496
497void LogManager::loadNexus(::NeXus::File *file, const Mantid::Kernel::NexusHDF5Descriptor &fileInfo,
498 const std::string &prefix) {
499
500 // Only load from NXlog entries
501 const auto &allEntries = fileInfo.getAllEntries();
502 auto itNxLogEntries = allEntries.find("NXlog");
503 const std::set<std::string> &nxLogEntries =
504 (itNxLogEntries != allEntries.end()) ? itNxLogEntries->second : std::set<std::string>{};
505
506 const auto levels = std::count(prefix.begin(), prefix.end(), '/');
507
508 auto itLower = nxLogEntries.lower_bound(prefix);
509
510 if (itLower == nxLogEntries.end()) {
511 return;
512 }
513 if (itLower->compare(0, prefix.size(), prefix) != 0) {
514 return;
515 }
516
517 for (auto it = itLower; it != nxLogEntries.end() && it->compare(0, prefix.size(), prefix) == 0; ++it) {
518 // only next level entries
519 const std::string &absoluteEntryName = *it;
520 if (std::count(absoluteEntryName.begin(), absoluteEntryName.end(), '/') != levels + 1) {
521 continue;
522 }
523 const std::string nameClass = absoluteEntryName.substr(absoluteEntryName.find_last_of('/') + 1);
524
525 auto prop = PropertyNexus::loadProperty(file, nameClass, fileInfo, prefix);
526 if (prop) {
527 if (m_manager->existsProperty(prop->name())) {
528 m_manager->removeProperty(prop->name());
529 }
530 m_manager->declareProperty(std::move(prop));
531 }
532 }
533}
534
535//--------------------------------------------------------------------------------------------
542void LogManager::loadNexus(::NeXus::File *file, const std::map<std::string, std::string> &entries) {
543
544 for (const auto &name_class : entries) {
545 // NXLog types are the main one.
546 if (name_class.second == "NXlog") {
547 auto prop = PropertyNexus::loadProperty(file, name_class.first);
548 if (prop) {
549 if (m_manager->existsProperty(prop->name())) {
550 m_manager->removeProperty(prop->name());
551 }
552 m_manager->declareProperty(std::move(prop));
553 }
554 }
555 }
556}
557
562
565std::string LogManager::getInvalidValuesFilterLogName(const std::string &logName) {
567}
568
570bool LogManager::hasInvalidValuesFilter(const std::string &logName) const {
572}
573
577 try {
578 auto log = getLogData(getInvalidValuesFilterLogName(logName));
579 if (auto tsp = dynamic_cast<TimeSeriesProperty<bool> *>(log)) {
580 return tsp;
581 }
582 } catch (Exception::NotFoundError &) {
583 // do nothing, just drop through tto the return line below
584 }
585 return nullptr;
586}
587
588bool LogManager::operator==(const LogManager &other) const { return *m_manager == *(other.m_manager); }
589
590bool LogManager::operator!=(const LogManager &other) const { return *m_manager != *(other.m_manager); }
591
592//-----------------------------------------------------------------------------------------------------------------------
593// Private methods
594//-----------------------------------------------------------------------------------------------------------------------
595
598#define INSTANTIATE(TYPE) \
599 template MANTID_API_DLL Kernel::TimeSeriesProperty<TYPE> *LogManager::getTimeSeriesProperty(const std::string &) \
600 const; \
601 template MANTID_API_DLL TYPE LogManager::getPropertyValueAsType(const std::string &) const;
602
603INSTANTIATE(double)
604INSTANTIATE(int32_t)
605INSTANTIATE(int64_t)
606INSTANTIATE(uint32_t)
607INSTANTIATE(uint64_t)
608INSTANTIATE(std::string)
609INSTANTIATE(bool)
610
611template MANTID_API_DLL uint16_t LogManager::getPropertyValueAsType(const std::string &) const;
612template MANTID_API_DLL std::vector<double> LogManager::getPropertyValueAsType(const std::string &) const;
613template MANTID_API_DLL std::vector<size_t> LogManager::getPropertyValueAsType(const std::string &) const;
614template MANTID_API_DLL std::vector<int> LogManager::getPropertyValueAsType(const std::string &) const;
615template MANTID_API_DLL std::vector<long> LogManager::getPropertyValueAsType(const std::string &) const;
618} // namespace Mantid::API
double value
The value of the point.
Definition: FitMW.cpp:51
#define INSTANTIATE(TYPE)
Definition: Statistics.cpp:403
This class contains the information about the log entries.
Definition: LogManager.h:44
double getTimeAveragedStd(const std::string &name) const
Get the time averaged standard deviation for a log.
Definition: LogManager.cpp:322
bool operator!=(const LogManager &other) const
Definition: LogManager.cpp:590
virtual size_t getMemorySize() const
Return an approximate memory size for the object in bytes.
Definition: LogManager.cpp:292
const Types::Core::DateAndTime endTime() const
Return the run end time.
Definition: LogManager.cpp:165
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Definition: LogManager.cpp:265
const std::vector< Kernel::Property * > & getLogData() const
Access all log entries.
Definition: LogManager.h:134
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.
Definition: LogManager.cpp:471
std::unique_ptr< Kernel::PropertyManager > m_manager
A pointer to a property manager.
Definition: LogManager.h:198
Kernel::TimeSeriesProperty< bool > * getInvalidValuesFilter(const std::string &logName) const
returns the invalid values log if the log has a matching invalid values log filter
Definition: LogManager.cpp:576
void filterByLog(const Kernel::TimeSeriesProperty< bool > &filter, const std::vector< std::string > &excludedFromFiltering=std::vector< std::string >())
Filter the run by the given boolean log.
Definition: LogManager.cpp:231
const Types::Core::DateAndTime startTime() const
Return the run start time.
Definition: LogManager.cpp:133
void clearOutdatedTimeSeriesLogValues()
Empty all but the last value out of all TimeSeriesProperty logs.
Definition: LogManager.cpp:429
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.
Definition: LogManager.cpp:445
virtual ~LogManager()
Destructor.
static const char * PROTON_CHARGE_LOG_NAME
Name of the log entry containing the proton charge when retrieved using getProtonCharge.
Definition: LogManager.h:201
int getPropertyAsIntegerValue(const std::string &name) const
Returns a property as an integer value.
Definition: LogManager.cpp:381
std::unique_ptr< Kernel::Cache< std::pair< std::string, Kernel::Math::StatisticType >, double > > m_singleValueCache
Cache for the retrieved single values.
Definition: LogManager.h:205
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
Definition: LogManager.cpp:404
void removeProperty(const std::string &name, bool delProperty=true)
Remove a named property.
Definition: LogManager.cpp:275
virtual void filterByTime(const Types::Core::DateAndTime start, const Types::Core::DateAndTime stop)
Filter the logs by time.
Definition: LogManager.cpp:196
const std::vector< Kernel::Property * > & getProperties() const
Return all of the current properties.
Definition: LogManager.cpp:287
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition: LogManager.h:79
double getPropertyAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic=Kernel::Math::Mean) const
Returns a property as a single double value from its name.
Definition: LogManager.cpp:349
static std::string getInvalidValuesFilterLogName(const std::string &logName)
Gets the correct log name for the matching invalid values log for a given log name.
Definition: LogManager.cpp:565
void clearTimeSeriesLogs()
Empty the values out of all TimeSeriesProperty logs.
Definition: LogManager.cpp:412
LogManager & operator=(const LogManager &other)
Definition: LogManager.cpp:109
bool operator==(const LogManager &other) const
Definition: LogManager.cpp:588
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
Definition: LogManager.cpp:332
void clearLogs()
Clear the logs.
Definition: LogManager.cpp:561
Kernel::TimeSeriesProperty< T > * getTimeSeriesProperty(const std::string &name) const
Returns a property as a time series property.
Definition: LogManager.cpp:308
bool hasInvalidValuesFilter(const std::string &logName) const
returns true if the log has a matching invalid values log filter
Definition: LogManager.cpp:570
void setStartAndEndTime(const Types::Core::DateAndTime &start, const Types::Core::DateAndTime &end)
Set the run start and end.
Definition: LogManager.cpp:121
virtual void splitByTime(Kernel::TimeSplitterType &splitter, std::vector< LogManager * > outputs) const
Split the logs based on the given intervals.
Definition: LogManager.cpp:209
Cache is a generic caching storage class.
Definition: Cache.h:27
Exception for when an item is not found in a collection.
Definition: Exception.h:145
A non-templated interface to a TimeSeriesProperty.
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
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.
static std::string getInvalidValuesFilterLogName(const std::string &logName)
Gets the correct log name for the matching invalid values log for a given log name.
The concrete, templated class for properties.
Base class for properties.
Definition: Property.h:94
virtual std::string value() const =0
Returns the value of the property as a string.
A specialised Property class for holding a series of time-value pairs.
Kernel::Logger g_log("ExperimentInfo")
static logger object
StatisticType
Maps a "statistic" to a number.
Definition: Statistics.h:18
DLLExport std::unique_ptr< Property > loadProperty(::NeXus::File *file, const std::string &group, const Mantid::Kernel::NexusHDF5Descriptor &fileInfo, const std::string &prefix)
Opens a NXlog group in a nexus file and creates the correct Property object from it.
std::vector< SplittingInterval > TimeSplitterType
A typedef for splitting events according their pulse time.
Definition: LogManager.h:31
STL namespace.