diff --git a/Code/Mantid/Framework/API/CMakeLists.txt b/Code/Mantid/Framework/API/CMakeLists.txt index 5cab1ee7c95bc22646a27cd5b25e53d7ff85044e..2e708a5450ef6bc536fc136f2b0b8bdef890950d 100644 --- a/Code/Mantid/Framework/API/CMakeLists.txt +++ b/Code/Mantid/Framework/API/CMakeLists.txt @@ -73,6 +73,7 @@ set ( SRC_FILES src/LoadAlgorithmFactory.cpp src/LocatedDataRef.cpp src/LocatedDataValue.cpp + src/LogManager.cpp src/MDGeometry.cpp src/MatrixWSIndexCalculator.cpp src/MatrixWorkspace.cpp @@ -213,6 +214,7 @@ set ( INC_FILES inc/MantidAPI/LoadAlgorithmFactory.h inc/MantidAPI/LocatedDataRef.h inc/MantidAPI/LocatedDataValue.h + inc/MantidAPI/LogManager.h inc/MantidAPI/MDGeometry.h inc/MantidAPI/MatrixWSIndexCalculator.h inc/MantidAPI/MatrixWorkspace.h diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/ITableWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/ITableWorkspace.h index 4e899515269d87e588434d0ce043b95ccf1596b9..3610818272772776efb65d28eae9db1cf006ba55 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/ITableWorkspace.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/ITableWorkspace.h @@ -8,7 +8,7 @@ #include "MantidAPI/Workspace.h" #include "MantidAPI/Column.h" #include "MantidKernel/V3D.h" -#include "MantidKernel/PropertyManager.h" + #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> @@ -125,7 +125,7 @@ public: // ===================================================================================== -class ITableWorkspace_DllExport ITableWorkspace: public API::Workspace,public Kernel::PropertyManager +class ITableWorkspace_DllExport ITableWorkspace: public API::Workspace { public: /// Virtual destructor. diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h b/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h new file mode 100644 index 0000000000000000000000000000000000000000..e2c483cd78a8230215d29437ca545e8e6b5bb09b --- /dev/null +++ b/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h @@ -0,0 +1,208 @@ +#ifndef MANTID_API_LOGMANAGER_H_ +#define MANTID_API_LOGMANAGER_H_ + +#include "MantidAPI/DllConfig.h" +#include "MantidGeometry/Instrument/Goniometer.h" +#include "MantidKernel/Cache.h" +#include "MantidKernel/PropertyManager.h" +#include "MantidKernel/Statistics.h" +#include "MantidKernel/TimeSplitter.h" +#include "MantidKernel/Matrix.h" +#include "MantidNexusCPP/NeXusFile.hpp" +#include <vector> + +namespace Mantid +{ + namespace Kernel + { + template<typename TYPE> + class TimeSeriesProperty; + } + + namespace API + { + + /** + This class contains the information about the log entries + + + @author Martyn Gigg, Tessella plc + @date 02/10/201 + + Copyright © 2010 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class MANTID_API_DLL LogManager + { + public: + /// Default constructor + LogManager(); + /// Destructor. Doesn't need to be virtual as long as nothing inherits from this class. + virtual ~LogManager(); + /// Copy constructor + LogManager(const LogManager& copy); + /// Assignment operator + const LogManager& operator=(const LogManager& rhs); + /// Addition + LogManager& operator+=(const LogManager& rhs); + + + //------------------------------------------------------------- + /// Set the run start and end + void setStartAndEndTime(const Kernel::DateAndTime & start, const Kernel::DateAndTime & end); + /// Return the run start time + const Kernel::DateAndTime startTime() const; + /// Return the run end time + const Kernel::DateAndTime endTime() const; + //------------------------------------------------------------- + + /// Filter the logs by time + void filterByTime(const Kernel::DateAndTime start, const Kernel::DateAndTime stop); + /// Split the logs based on the given intervals + void splitByTime(Kernel::TimeSplitterType& splitter, std::vector< LogManager* > outputs) const; + /// Filter the run by the given boolean log + void filterByLog(const Kernel::TimeSeriesProperty<bool> & filter); + + /// Return an approximate memory size for the object in bytes + size_t getMemorySize() const; + + /// Add data to the object in the form of a property + void addProperty(Kernel::Property *prop, bool overwrite = false); + /// Add a property of given type + template<class TYPE> + void addProperty(const std::string & name, const TYPE & value, bool overwrite = false); + + template<class TYPE> + void addProperty(const std::string & name, const TYPE & value, const std::string & units, + bool overwrite = false); + + /// Does the property exist on the object + bool hasProperty(const std::string & name) const; + /// Remove a named property + void removeProperty(const std::string &name, bool delproperty=true); + /** + * Return all of the current properties + * @returns A vector of the current list of properties + */ + inline const std::vector<Kernel::Property*>& getProperties() const { return m_manager.getProperties(); } + /// Returns a property as a time series property. It will throw if it is not valid + template<typename T> + Kernel::TimeSeriesProperty<T> * getTimeSeriesProperty(const std::string & name) const; + /// Get the value of a property as the given TYPE. Throws if the type is not correct + template<typename HeldType> + HeldType getPropertyValueAsType(const std::string & name) const; + /// Returns a property as a single double value from its name + double getPropertyAsSingleValue(const std::string & name, Kernel::Math::StatisticType statistic = Kernel::Math::Mean) const; + /// Returns the named property as a pointer + Kernel::Property * getProperty(const std::string & name) const; + + /// Set the proton charge + void setProtonCharge( const double charge); + /// Get the proton charge + double getProtonCharge() const; + /// Integrate the proton charge over the whole run time + double integrateProtonCharge(); + + + /** + * Add a log entry + * @param p :: A pointer to the property containing the log entry + */ + void addLogData( Kernel::Property *p ) { addProperty(p); } + /** + * Access a single log entry + * @param name :: The name of the log entry to retrieve + * @returns A pointer to a property containing the log entry + */ + Kernel::Property* getLogData(const std::string &name) const { return getProperty(name); } + /** + * Access all log entries + * @returns A list of all of the log entries + */ + const std::vector< Kernel::Property* >& getLogData() const {return getProperties(); } + /** + * Remove a named log entry + * @param name :: The name of the entry to remove + * @param delproperty :: If true, delete the log entry + */ + void removeLogData(const std::string &name, const bool delproperty=true) { return removeProperty(name, delproperty); } + /** + * @param name :: The name of the property + * @param statistic :: Defines how to calculate the single value from series (default=Mean) + * @return A log as a single value using the given statistic type + */ + double getLogAsSingleValue(const std::string & name, Kernel::Math::StatisticType statistic = Kernel::Math::Mean) const { return getPropertyAsSingleValue(name, statistic); } + + /// Empty the values out of all TimeSeriesProperty logs + void clearTimeSeriesLogs(); + + /// Save the run to a NeXus file with a given group name + void saveNexus(::NeXus::File * file, const std::string & group) const; + /// Load the run from a NeXus file with a given group name + void loadNexus(::NeXus::File * file, const std::string & group); + + protected: + /// Static reference to the logger class + static Kernel::Logger &g_log; + /// A pointer to a property manager + Kernel::PropertyManager m_manager; + /// Name of the log entry containing the proton charge when retrieved using getProtonCharge + static const char * PROTON_CHARGE_LOG_NAME; + private: + /// Adds all the time series in from one property manager into another + void mergeMergables(Mantid::Kernel::PropertyManager & sum, const Mantid::Kernel::PropertyManager & toAdd); + /// Cache type for single value logs + typedef Kernel::Cache<std::pair<std::string,Kernel::Math::StatisticType>, double> SingleValueCache; + /// Cache for the retrieved single values + mutable SingleValueCache m_singleValueCache; + }; + + /** + * Add a property of a specified type (Simply creates a Kernel::Property of that type + * @param name :: The name of the type + * @param value :: The value of the property + * @param overwrite :: If true, a current value is overwritten. (Default: False) + */ + template<class TYPE> + void LogManager::addProperty(const std::string & name, const TYPE & value, bool overwrite) + { + addProperty(new Kernel::PropertyWithValue<TYPE>(name, value), overwrite); + } + + /** + * Add a property of a specified type (Simply creates a Kernel::Property of that type) + * and set its units. + * @param name :: The name of the type + * @param value :: The value of the property + * @param units :: a string giving the units of the property. + * @param overwrite :: If true, a current value is overwritten. (Default: False) + */ + template<class TYPE> + void LogManager::addProperty(const std::string & name, const TYPE & value, const std::string& units, bool overwrite) + { + Kernel::Property * newProp = new Kernel::PropertyWithValue<TYPE>(name, value); + newProp->setUnits(units); + addProperty(newProp, overwrite); + } + + } +} + +#endif //MANTID_API_LOGMANAGER_H_ diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/Run.h b/Code/Mantid/Framework/API/inc/MantidAPI/Run.h index e3526b95a7e4ddd34ad23d38c6ccd0c104379729..fe78873ee5c45a4ee5d36ba7ecc092ce82da86ad 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/Run.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/Run.h @@ -2,22 +2,16 @@ #define MANTID_API_RUN_H_ #include "MantidAPI/DllConfig.h" +#include "MantidAPI/LogManager.h" #include "MantidGeometry/Instrument/Goniometer.h" -#include "MantidKernel/Cache.h" -#include "MantidKernel/PropertyManager.h" #include "MantidKernel/Statistics.h" #include "MantidKernel/TimeSplitter.h" -#include "MantidKernel/Matrix.h" #include "MantidNexusCPP/NeXusFile.hpp" #include <vector> namespace Mantid { - namespace Kernel - { - template<typename TYPE> - class TimeSeriesProperty; - } + namespace API { @@ -49,7 +43,7 @@ namespace Mantid File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>. Code Documentation is available at: <http://doxygen.mantidproject.org> */ - class MANTID_API_DLL Run + class MANTID_API_DLL Run : public LogManager { public: /// Default constructor @@ -60,56 +54,15 @@ namespace Mantid Run(const Run& copy); /// Assignment operator const Run& operator=(const Run& rhs); - /// Addition - Run& operator+=(const Run& rhs); - - /// Set the run start and end - void setStartAndEndTime(const Kernel::DateAndTime & start, const Kernel::DateAndTime & end); - /// Return the run start time - const Kernel::DateAndTime startTime() const; - /// Return the run end time - const Kernel::DateAndTime endTime() const; - + /// Filter the logs by time void filterByTime(const Kernel::DateAndTime start, const Kernel::DateAndTime stop); /// Split the logs based on the given intervals void splitByTime(Kernel::TimeSplitterType& splitter, std::vector< Run * > outputs) const; - /// Filter the run by the given boolean log - void filterByLog(const Kernel::TimeSeriesProperty<bool> & filter); - + /// Return an approximate memory size for the object in bytes size_t getMemorySize() const; - /// Add data to the object in the form of a property - void addProperty(Kernel::Property *prop, bool overwrite = false); - /// Add a property of given type - template<class TYPE> - void addProperty(const std::string & name, const TYPE & value, bool overwrite = false); - - template<class TYPE> - void addProperty(const std::string & name, const TYPE & value, const std::string & units, - bool overwrite = false); - - /// Does the property exist on the object - bool hasProperty(const std::string & name) const; - /// Remove a named property - void removeProperty(const std::string &name, bool delproperty=true); - /** - * Return all of the current properties - * @returns A vector of the current list of properties - */ - inline const std::vector<Kernel::Property*>& getProperties() const { return m_manager.getProperties(); } - /// Returns a property as a time series property. It will throw if it is not valid - template<typename T> - Kernel::TimeSeriesProperty<T> * getTimeSeriesProperty(const std::string & name) const; - /// Get the value of a property as the given TYPE. Throws if the type is not correct - template<typename HeldType> - HeldType getPropertyValueAsType(const std::string & name) const; - /// Returns a property as a single double value from its name - double getPropertyAsSingleValue(const std::string & name, Kernel::Math::StatisticType statistic = Kernel::Math::Mean) const; - /// Returns the named property as a pointer - Kernel::Property * getProperty(const std::string & name) const; - /// Set the proton charge void setProtonCharge( const double charge); /// Get the proton charge @@ -132,92 +85,23 @@ namespace Mantid // Retrieve the goniometer rotation matrix const Kernel::DblMatrix & getGoniometerMatrix() const; - /** - * Add a log entry - * @param p :: A pointer to the property containing the log entry - */ - void addLogData( Kernel::Property *p ) { addProperty(p); } - /** - * Access a single log entry - * @param name :: The name of the log entry to retrieve - * @returns A pointer to a property containing the log entry - */ - Kernel::Property* getLogData(const std::string &name) const { return getProperty(name); } - /** - * Access all log entries - * @returns A list of all of the log entries - */ - const std::vector< Kernel::Property* >& getLogData() const {return getProperties(); } - /** - * Remove a named log entry - * @param name :: The name of the entry to remove - * @param delproperty :: If true, delete the log entry - */ - void removeLogData(const std::string &name, const bool delproperty=true) { return removeProperty(name, delproperty); } - /** - * @param name :: The name of the property - * @param statistic :: Defines how to calculate the single value from series (default=Mean) - * @return A log as a single value using the given statistic type - */ - double getLogAsSingleValue(const std::string & name, Kernel::Math::StatisticType statistic = Kernel::Math::Mean) const { return getPropertyAsSingleValue(name, statistic); } - - /// Empty the values out of all TimeSeriesProperty logs - void clearTimeSeriesLogs(); - /// Save the run to a NeXus file with a given group name void saveNexus(::NeXus::File * file, const std::string & group) const; /// Load the run from a NeXus file with a given group name void loadNexus(::NeXus::File * file, const std::string & group); private: - /// Adds all the time series in from one property manager into another - void mergeMergables(Mantid::Kernel::PropertyManager & sum, const Mantid::Kernel::PropertyManager & toAdd); /// Calculate the gonoimeter matrix void calculateGoniometerMatrix(); /// Static reference to the logger class static Kernel::Logger &g_log; - - /// A pointer to a property manager - Kernel::PropertyManager m_manager; /// Goniometer for this run Mantid::Geometry::Goniometer m_goniometer; /// A set of histograms that can be stored here for future reference std::vector<double> m_histoBins; - /// Cache type for single value logs - typedef Kernel::Cache<std::pair<std::string,Kernel::Math::StatisticType>, double> SingleValueCache; - /// Cache for the retrieved single values - mutable SingleValueCache m_singleValueCache; - }; - - /** - * Add a property of a specified type (Simply creates a Kernel::Property of that type - * @param name :: The name of the type - * @param value :: The value of the property - * @param overwrite :: If true, a current value is overwritten. (Default: False) - */ - template<class TYPE> - void Run::addProperty(const std::string & name, const TYPE & value, bool overwrite) - { - addProperty(new Kernel::PropertyWithValue<TYPE>(name, value), overwrite); - } - - /** - * Add a property of a specified type (Simply creates a Kernel::Property of that type) - * and set its units. - * @param name :: The name of the type - * @param value :: The value of the property - * @param units :: a string giving the units of the property. - * @param overwrite :: If true, a current value is overwritten. (Default: False) - */ - template<class TYPE> - void Run::addProperty(const std::string & name, const TYPE & value, const std::string& units, bool overwrite) - { - Kernel::Property * newProp = new Kernel::PropertyWithValue<TYPE>(name, value); - newProp->setUnits(units); - addProperty(newProp, overwrite); - } + }; } } diff --git a/Code/Mantid/Framework/API/src/LogManager.cpp b/Code/Mantid/Framework/API/src/LogManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..439620ae8a7dedf198a78f6031906a22eb3711ed --- /dev/null +++ b/Code/Mantid/Framework/API/src/LogManager.cpp @@ -0,0 +1,524 @@ +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidAPI/LogManager.h" +#include "MantidAPI/PropertyNexus.h" + +#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/DateAndTime.h" +#include "MantidKernel/TimeSplitter.h" +#include "MantidKernel/TimeSeriesProperty.h" +#include "MantidKernel/VectorHelper.h" + +#include <boost/lexical_cast.hpp> + +#include <algorithm> + +namespace Mantid +{ +namespace API +{ + +using namespace Kernel; +namespace +{ + /// The number of log entries summed when adding a run + const int ADDABLES = 6; + /// The names of the log entries summed when adding two runs together + const std::string ADDABLE[ADDABLES] = {"tot_prtn_chrg", "rawfrm", "goodfrm", "dur", "gd_prtn_chrg", "uA.hour"}; +} + +// Get a reference to the logger +Kernel::Logger& LogManager::g_log = Kernel::Logger::get("LogManager"); + + /// Name of the log entry containing the proton charge when retrieved using getProtonCharge + const char * LogManager::PROTON_CHARGE_LOG_NAME = "gd_prtn_chrg"; + + //---------------------------------------------------------------------- + // Public member functions + //---------------------------------------------------------------------- + /** + * Default constructor + */ + LogManager::LogManager() : m_manager(), m_singleValueCache() + { + } + + /** + * Destructor + */ + LogManager::~LogManager() + { + } + + /** + * Copy constructor + * @param copy :: The object to initialize the copy from + */ + LogManager::LogManager(const LogManager& copy) : m_manager(copy.m_manager), + m_singleValueCache(copy.m_singleValueCache) + { + } + + + //----------------------------------------------------------------------------------------------- + /** + * Assignment operator + * @param rhs :: The object whose properties should be copied into this + * @returns A cont reference to the copied object + */ + const LogManager& LogManager::operator=(const LogManager& rhs) + { + if( this == &rhs ) return *this; + m_manager = rhs.m_manager; + return *this; + } + + + //----------------------------------------------------------------------------------------------- + /** + * Adds just the properties that are safe to add. All time series are + * merged together and the list of addable properties are added + * @param rhs The object that is being added to this. + * @returns A reference to the summed object + */ + LogManager& LogManager::operator+=(const LogManager& rhs) + { + //merge and copy properties where there is no risk of corrupting data + mergeMergables(m_manager, rhs.m_manager); + + // Other properties are added to gether if they are on the approved list + for(int i = 0; i < ADDABLES; ++i ) + { + if (rhs.m_manager.existsProperty(ADDABLE[i])) + { + // get a pointer to the property on the right-handside workspace + Property * right = rhs.m_manager.getProperty(ADDABLE[i]); + + // now deal with the left-handside + if (m_manager.existsProperty(ADDABLE[i])) + { + Property * left = m_manager.getProperty(ADDABLE[i]); + left->operator+=(right); + } + else + //no property on the left-handside, create one and copy the right-handside across verbatum + m_manager.declareProperty(right->clone(), ""); + } + } + return *this; + } + + /** + * Set the run start and end + * @param start :: The run start + * @param end :: The run end + */ + void LogManager::setStartAndEndTime(const Kernel::DateAndTime & start, const Kernel::DateAndTime & end) + { + this->addProperty<std::string>("start_time", start.toISO8601String(), true); + this->addProperty<std::string>("end_time", end.toISO8601String(), true); + } + + /// Return the run start time + const Kernel::DateAndTime LogManager::startTime() const + { + // Use start_time if found, else use run_start + const std::string start_prop("start_time"); + const std::string run_start_prop("run_start"); + if( this->hasProperty(start_prop) ) + { + std::string start = this->getProperty(start_prop)->value(); + return DateAndTime(start); + } + else if ( this->hasProperty(run_start_prop) ) + { + std::string start = this->getProperty(run_start_prop)->value(); + return DateAndTime(start); + + } + else + { + throw std::runtime_error("Run::startTime() - No start time has been set for this run."); + } + } + + /// Return the run end time + const Kernel::DateAndTime LogManager::endTime() const + { + // Use end_time if found, else use run_end + const std::string end_prop("end_time"); + const std::string run_end_prop("run_end"); + if( this->hasProperty(end_prop) ) + { + std::string end = this->getProperty(end_prop)->value(); + return DateAndTime(end); + } + else if( this->hasProperty(run_end_prop) ) + { + std::string end = this->getProperty(run_end_prop)->value(); + return DateAndTime(end); + } + { + throw std::runtime_error("Run::endTime() - No end time has been set for this run."); + } + } + + + //----------------------------------------------------------------------------------------------- + /** + * Filter out a run by time. Takes out any TimeSeriesProperty log entries outside of the given + * absolute time range. + * + * @param start :: Absolute start time. Any log entries at times >= to this time are kept. + * @param stop :: Absolute stop time. Any log entries at times < than this time are kept. + */ + void LogManager::filterByTime(const Kernel::DateAndTime start, const Kernel::DateAndTime stop) + { + //The propery manager operator will make all timeseriesproperties filter. + m_manager.filterByTime(start, stop); + + } + + + //----------------------------------------------------------------------------------------------- + /** + * Split a run by time (splits the TimeSeriesProperties contained). + * + * + * @param splitter :: TimeSplitterType with the intervals and destinations. + * @param outputs :: Vector of output runs. + */ + void LogManager::splitByTime(TimeSplitterType& splitter, std::vector< LogManager * > outputs) const + { + //Make a vector of managers for the splitter. Fun! + std::vector< PropertyManager *> output_managers; + size_t n = outputs.size(); + for (size_t i=0; i<n; i++) + { + if (outputs[i]) + output_managers.push_back( &(outputs[i]->m_manager) ); + else + output_managers.push_back( NULL ); + } + + //Now that will do the split down here. + m_manager.splitByTime(splitter, output_managers); + + } + + //----------------------------------------------------------------------------------------------- + /** + * Filter the run by the given boolean log. It replaces all time + * series properties with filtered time series properties + * @param filter :: A boolean time series to filter each log on + */ + void LogManager::filterByLog(const Kernel::TimeSeriesProperty<bool> & filter) + { + // This will invalidate the cache + m_singleValueCache.clear(); + m_manager.filterByProperty(filter); + } + + + //----------------------------------------------------------------------------------------------- + /** + * Add data to the object in the form of a property + * @param prop :: A pointer to a property whose ownership is transferred to this object + * @param overwrite :: If true, a current value is overwritten. (Default: False) + */ + void LogManager::addProperty(Kernel::Property *prop, bool overwrite) + { + // Make an exception for the proton charge + // and overwrite it's value as we don't want to store the proton charge in two separate locations + // Similar we don't want more than one run_title + std::string name = prop->name(); + if( hasProperty(name) && (overwrite || prop->name() == PROTON_CHARGE_LOG_NAME || prop->name()=="run_title") ) + { + removeProperty(name); + } + m_manager.declareProperty(prop, ""); + } + + //----------------------------------------------------------------------------------------------- + /** + * Returns true if the named property exists + * @param name :: The name of the property + * @return True if the property exists, false otherwise + */ + bool LogManager::hasProperty(const std::string & name) const + { + return m_manager.existsProperty(name); + } + + //----------------------------------------------------------------------------------------------- + /** + * Remove a named property + * @param name :: The name of the property + * @param delProperty :: If true the property is deleted (default=true) + * @return True if the property exists, false otherwise + */ + + void LogManager::removeProperty(const std::string &name, bool delProperty) + { + // Remove any cached entries for this log. Need to make this more general + for(unsigned int stat = 0; stat < 7; ++stat) + { + m_singleValueCache.removeCache(std::make_pair(name,(Math::StatisticType)stat)); + } + m_manager.removeProperty(name, delProperty); + } + + + //----------------------------------------------------------------------------------------------- + /** Return the total memory used by the run object, in bytes. + */ + size_t LogManager::getMemorySize() const + { + size_t total = 0; + std::vector< Property*> props = m_manager.getProperties(); + for (size_t i=0; i < props.size(); i++) + { + Property * p = props[i]; + if (p) + total += p->getMemorySize() + sizeof(Property *); + } + return total; + } + + /** + * Returns a property as a time series property. It will throw if it is not valid or the + * property does not exist + * @param name The name of a time-series property + * @return A pointer to the time-series property + */ + template<typename T> + Kernel::TimeSeriesProperty<T> * LogManager::getTimeSeriesProperty(const std::string & name) const + { + Kernel::Property *prop = getProperty(name); + if(Kernel::TimeSeriesProperty<T>* tsp = dynamic_cast<Kernel::TimeSeriesProperty<T>*>(prop)) + { + return tsp; + } + else + { + throw std::invalid_argument("Run::getTimeSeriesProperty - '" + name + "' is not a TimeSeriesProperty"); + } + } + + /** + * Get the value of a property as the requested type. Throws if the type is not correct + * @param name :: The name of the property + * @return The value of as the requested type + */ + template<typename HeldType> + HeldType LogManager::getPropertyValueAsType(const std::string & name) const + { + Kernel::Property *prop = getProperty(name); + if(Kernel::PropertyWithValue<HeldType>* valueProp = dynamic_cast<Kernel::PropertyWithValue<HeldType>*>(prop)) + { + return (*valueProp)(); + } + else + { + throw std::invalid_argument("Run::getPropertyValueAsType - '" + name + "' is not of the requested type"); + } + } + + /** + * Returns a property as a single double value from its name @see getPropertyAsSingleValue + * @param name :: The name of the property + * @param statistic :: The statistic to use to calculate the single value (default=Mean) @see StatisticType + * @return A single double value + */ + double LogManager::getPropertyAsSingleValue(const std::string & name, Kernel::Math::StatisticType statistic) const + { + double singleValue(0.0); + const auto key = std::make_pair(name, statistic); + if(!m_singleValueCache.getCache(key, singleValue)) + { + const Property *log = getProperty(name); + if(auto singleDouble = dynamic_cast<const PropertyWithValue<double>*>(log)) + { + singleValue = (*singleDouble)(); + } + else if(auto seriesDouble = dynamic_cast<const TimeSeriesProperty<double>*>(log)) + { + singleValue = Mantid::Kernel::filterByStatistic(seriesDouble, statistic); + } + else + { + throw std::invalid_argument("Run::getPropertyAsSingleValue - Property \"" + name + "\" is not a single double or time series double."); + } + PARALLEL_CRITICAL(Run_getPropertyAsSingleValue) + { + // Put it in the cache + m_singleValueCache.setCache(key, singleValue); + } + } + return singleValue; + } + + /** + * Get a pointer to a property by name + * @param name :: The name of a property, throws an Exception::NotFoundError if it does not exist + * @return A pointer to the named property + */ + Kernel::Property * LogManager::getProperty(const std::string & name) const + { + return m_manager.getProperty(name); + } + + /** Clear out the contents of all logs of type TimeSeriesProperty. + * Single-value properties will be left unchanged. + * + * The method has been fully implemented here instead of as a pass-through to + * PropertyManager to limit its visibility to Run clients. + */ + void LogManager::clearTimeSeriesLogs() + { + auto & props = getProperties(); + + // Loop over the set of properties, identifying those that are time-series properties + // and then clearing them out. + for ( auto it = props.begin(); it != props.end(); ++it) + { + if ( auto tsp = dynamic_cast<ITimeSeriesProperty*>(*it) ) + { + tsp->clear(); + } + } + } + + + //-------------------------------------------------------------------------------------------- + /** Save the object to an open NeXus file. + * @param file :: open NeXus file + * @param group :: name of the group to create + */ + void LogManager::saveNexus(::NeXus::File * file, const std::string & group) const + { + file->makeGroup(group, "NXgroup", 1); + file->putAttr("version", 1); + + //// Now the goniometer + //m_goniometer.saveNexus(file, GONIOMETER_LOG_NAME); + + //// Now the histogram bins, if there are any + //if(!m_histoBins.empty()) + //{ + // file->makeGroup(HISTO_BINS_LOG_NAME, "NXdata", 1); + // file->writeData("value", m_histoBins); + // file->closeGroup(); + //} + + // Save all the properties as NXlog + std::vector<Property *> props = m_manager.getProperties(); + for (size_t i=0; i<props.size(); i++) + { + try + { + PropertyNexus::saveProperty(file, props[i]); + } + catch(std::invalid_argument &exc) + { + g_log.warning(exc.what()); + } + } + file->closeGroup(); + } + + //-------------------------------------------------------------------------------------------- + /** Load the object from an open NeXus file. + * @param file :: open NeXus file + * @param group :: name of the group to open. Empty string to NOT open a group, but + * load any NXlog in the current open group. + */ + void LogManager::loadNexus(::NeXus::File * file, const std::string & group) + { + if (!group.empty()) file->openGroup(group, "NXgroup"); + + std::map<std::string, std::string> entries; + file->getEntries(entries); + std::map<std::string, std::string>::iterator it = entries.begin(); + std::map<std::string, std::string>::iterator it_end = entries.end(); + for (; it != it_end; ++it) + { + // Get the name/class pair + const std::pair<std::string, std::string> & name_class = *it; + // NXLog types are the main one. + if (name_class.second == "NXlog") + { + Property * prop = PropertyNexus::loadProperty(file, name_class.first); + if (prop) + { + if (m_manager.existsProperty(prop->name() )) + m_manager.removeProperty(prop->name() ); + m_manager.declareProperty(prop); + } + } + } + if (!group.empty()) file->closeGroup(); + + + //if( this->hasProperty("proton_charge") ) + //{ + // // Old files may have a proton_charge field, single value. + // // Modern files (e.g. SNS) have a proton_charge TimeSeriesProperty. + // PropertyWithValue<double> *charge_log = dynamic_cast<PropertyWithValue<double>*>(this->getProperty("proton_charge")); + // if (charge_log) + // { this->setProtonCharge(boost::lexical_cast<double>(charge_log->value())); + // } + //} + } + + //----------------------------------------------------------------------------------------------------------------------- + // Private methods + //----------------------------------------------------------------------------------------------------------------------- + + /** Adds all the time series in the second property manager to those in the first + * @param sum the properties to add to + * @param toAdd the properties to add + */ + void LogManager::mergeMergables(Mantid::Kernel::PropertyManager & sum, const Mantid::Kernel::PropertyManager & toAdd) + { + // get pointers to all the properties on the right-handside and prepare to loop through them + const std::vector<Property*> inc = toAdd.getProperties(); + std::vector<Property*>::const_iterator end = inc.end(); + for (std::vector<Property*>::const_iterator it=inc.begin(); it != end;++it) + { + const std::string rhs_name = (*it)->name(); + try + { + //now get pointers to the same properties on the left-handside + Property * lhs_prop(sum.getProperty(rhs_name)); + lhs_prop->merge(*it); + } + catch (Exception::NotFoundError &) + { + //copy any properties that aren't already on the left hand side + Property * copy = (*it)->clone(); + //And we add a copy of that property to *this + sum.declareProperty(copy, ""); + } + } + } + + + + /// @cond + /// Macro to instantiate concrete template members +#define INSTANTIATE(TYPE) \ + template MANTID_API_DLL Kernel::TimeSeriesProperty<TYPE> * LogManager::getTimeSeriesProperty(const std::string &) const;\ + template MANTID_API_DLL TYPE LogManager::getPropertyValueAsType(const std::string &) const; + + INSTANTIATE(double); + INSTANTIATE(int); + INSTANTIATE(std::string); + INSTANTIATE(bool); + /// @endcond + +} //API namespace + +} + diff --git a/Code/Mantid/Framework/API/src/Run.cpp b/Code/Mantid/Framework/API/src/Run.cpp index ca19cdb0279b84f04101acf478714c98a919d080..ebc3429bdf97228093fbff1c9e048a6c8f083698 100644 --- a/Code/Mantid/Framework/API/src/Run.cpp +++ b/Code/Mantid/Framework/API/src/Run.cpp @@ -23,12 +23,6 @@ using namespace Kernel; namespace { - /// The number of log entries summed when adding a run - const int ADDABLES = 6; - /// The names of the log entries summed when adding two runs together - const std::string ADDABLE[ADDABLES] = {"tot_prtn_chrg", "rawfrm", "goodfrm", "dur", "gd_prtn_chrg", "uA.hour"}; - /// Name of the log entry containing the proton charge when retrieved using getProtonCharge - const char * PROTON_CHARGE_LOG_NAME = "gd_prtn_chrg"; /// Name of the goniometer log when saved to a NeXus file const char * GONIOMETER_LOG_NAME = "goniometer"; /// Name of the stored histogram bins log when saved to NeXus @@ -43,7 +37,7 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); /** * Default constructor */ - Run::Run() : m_manager(), m_goniometer(), m_histoBins(), m_singleValueCache() + Run::Run() : m_goniometer(), m_histoBins() { } @@ -58,8 +52,8 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); * Copy constructor * @param copy :: The object to initialize the copy from */ - Run::Run(const Run& copy) : m_manager(copy.m_manager), - m_goniometer(copy.m_goniometer), m_singleValueCache(copy.m_singleValueCache) + Run::Run(const Run& copy) : LogManager(copy), + m_goniometer(copy.m_goniometer) { } @@ -78,98 +72,7 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); return *this; } - - //----------------------------------------------------------------------------------------------- - /** - * Adds just the properties that are safe to add. All time series are - * merged together and the list of addable properties are added - * @param rhs The object that is being added to this. - * @returns A reference to the summed object - */ - Run& Run::operator+=(const Run& rhs) - { - //merge and copy properties where there is no risk of corrupting data - mergeMergables(m_manager, rhs.m_manager); - - // Other properties are added to gether if they are on the approved list - for(int i = 0; i < ADDABLES; ++i ) - { - if (rhs.m_manager.existsProperty(ADDABLE[i])) - { - // get a pointer to the property on the right-handside workspace - Property * right = rhs.m_manager.getProperty(ADDABLE[i]); - - // now deal with the left-handside - if (m_manager.existsProperty(ADDABLE[i])) - { - Property * left = m_manager.getProperty(ADDABLE[i]); - left->operator+=(right); - } - else - //no property on the left-handside, create one and copy the right-handside across verbatum - m_manager.declareProperty(right->clone(), ""); - } - } - return *this; - } - - /** - * Set the run start and end - * @param start :: The run start - * @param end :: The run end - */ - void Run::setStartAndEndTime(const Kernel::DateAndTime & start, const Kernel::DateAndTime & end) - { - this->addProperty<std::string>("start_time", start.toISO8601String(), true); - this->addProperty<std::string>("end_time", end.toISO8601String(), true); - } - - /// Return the run start time - const Kernel::DateAndTime Run::startTime() const - { - // Use start_time if found, else use run_start - const std::string start_prop("start_time"); - const std::string run_start_prop("run_start"); - if( this->hasProperty(start_prop) ) - { - std::string start = this->getProperty(start_prop)->value(); - return DateAndTime(start); - } - else if ( this->hasProperty(run_start_prop) ) - { - std::string start = this->getProperty(run_start_prop)->value(); - return DateAndTime(start); - - } - else - { - throw std::runtime_error("Run::startTime() - No start time has been set for this run."); - } - } - - /// Return the run end time - const Kernel::DateAndTime Run::endTime() const - { - // Use end_time if found, else use run_end - const std::string end_prop("end_time"); - const std::string run_end_prop("run_end"); - if( this->hasProperty(end_prop) ) - { - std::string end = this->getProperty(end_prop)->value(); - return DateAndTime(end); - } - else if( this->hasProperty(run_end_prop) ) - { - std::string end = this->getProperty(run_end_prop)->value(); - return DateAndTime(end); - } - { - throw std::runtime_error("Run::endTime() - No end time has been set for this run."); - } - } - - - //----------------------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------------------- /** * Filter out a run by time. Takes out any TimeSeriesProperty log entries outside of the given * absolute time range. @@ -181,9 +84,7 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); */ void Run::filterByTime(const Kernel::DateAndTime start, const Kernel::DateAndTime stop) { - //The propery manager operator will make all timeseriesproperties filter. - m_manager.filterByTime(start, stop); - + LogManager::filterByTime(start,stop); //Re-integrate proton charge this->integrateProtonCharge(); } @@ -200,89 +101,22 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); */ void Run::splitByTime(TimeSplitterType& splitter, std::vector< Run * > outputs) const { - //Make a vector of managers for the splitter. Fun! - std::vector< PropertyManager *> output_managers; size_t n = outputs.size(); - for (size_t i=0; i<n; i++) - { - if (outputs[i]) - output_managers.push_back( &(outputs[i]->m_manager) ); - else - output_managers.push_back( NULL ); - } - - //Now that will do the split down here. - m_manager.splitByTime(splitter, output_managers); + std::vector<LogManager *> outputsBase(outputs.begin(),outputs.end()); + LogManager::splitByTime(splitter,outputsBase); //Re-integrate proton charge of all outputs for (size_t i=0; i<n; i++) { - if (outputs[i]) + if (outputsBase[i]) + { + outputs[i] = dynamic_cast<Run *>(outputsBase[i]); outputs[i]->integrateProtonCharge(); + } } } - //----------------------------------------------------------------------------------------------- - /** - * Filter the run by the given boolean log. It replaces all time - * series properties with filtered time series properties - * @param filter :: A boolean time series to filter each log on - */ - void Run::filterByLog(const Kernel::TimeSeriesProperty<bool> & filter) - { - // This will invalidate the cache - m_singleValueCache.clear(); - m_manager.filterByProperty(filter); - } - - - //----------------------------------------------------------------------------------------------- - /** - * Add data to the object in the form of a property - * @param prop :: A pointer to a property whose ownership is transferred to this object - * @param overwrite :: If true, a current value is overwritten. (Default: False) - */ - void Run::addProperty(Kernel::Property *prop, bool overwrite) - { - // Make an exception for the proton charge - // and overwrite it's value as we don't want to store the proton charge in two separate locations - // Similar we don't want more than one run_title - std::string name = prop->name(); - if( hasProperty(name) && (overwrite || prop->name() == PROTON_CHARGE_LOG_NAME || prop->name()=="run_title") ) - { - removeProperty(name); - } - m_manager.declareProperty(prop, ""); - } - - //----------------------------------------------------------------------------------------------- - /** - * Returns true if the named property exists - * @param name :: The name of the property - * @return True if the property exists, false otherwise - */ - bool Run::hasProperty(const std::string & name) const - { - return m_manager.existsProperty(name); - } - - //----------------------------------------------------------------------------------------------- - /** - * Remove a named property - * @param name :: The name of the property - * @param delProperty :: If true the property is deleted (default=true) - * @return True if the property exists, false otherwise - */ - - void Run::removeProperty(const std::string &name, bool delProperty) - { - // Remove any cached entries for this log. Need to make this more general - for(unsigned int stat = 0; stat < 7; ++stat) - { - m_singleValueCache.removeCache(std::make_pair(name,(Math::StatisticType)stat)); - } - m_manager.removeProperty(name, delProperty); - } + //----------------------------------------------------------------------------------------------- @@ -420,120 +254,12 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); */ size_t Run::getMemorySize() const { - size_t total = 0; - std::vector< Property*> props = m_manager.getProperties(); - for (size_t i=0; i < props.size(); i++) - { - Property * p = props[i]; - if (p) - total += p->getMemorySize() + sizeof(Property *); - } + size_t total = LogManager::getMemorySize(); + total += sizeof(m_goniometer); + total += m_histoBins.size()*sizeof(double); return total; } - /** - * Returns a property as a time series property. It will throw if it is not valid or the - * property does not exist - * @param name The name of a time-series property - * @return A pointer to the time-series property - */ - template<typename T> - Kernel::TimeSeriesProperty<T> * Run::getTimeSeriesProperty(const std::string & name) const - { - Kernel::Property *prop = getProperty(name); - if(Kernel::TimeSeriesProperty<T>* tsp = dynamic_cast<Kernel::TimeSeriesProperty<T>*>(prop)) - { - return tsp; - } - else - { - throw std::invalid_argument("Run::getTimeSeriesProperty - '" + name + "' is not a TimeSeriesProperty"); - } - } - - /** - * Get the value of a property as the requested type. Throws if the type is not correct - * @param name :: The name of the property - * @return The value of as the requested type - */ - template<typename HeldType> - HeldType Run::getPropertyValueAsType(const std::string & name) const - { - Kernel::Property *prop = getProperty(name); - if(Kernel::PropertyWithValue<HeldType>* valueProp = dynamic_cast<Kernel::PropertyWithValue<HeldType>*>(prop)) - { - return (*valueProp)(); - } - else - { - throw std::invalid_argument("Run::getPropertyValueAsType - '" + name + "' is not of the requested type"); - } - } - - /** - * Returns a property as a single double value from its name @see getPropertyAsSingleValue - * @param name :: The name of the property - * @param statistic :: The statistic to use to calculate the single value (default=Mean) @see StatisticType - * @return A single double value - */ - double Run::getPropertyAsSingleValue(const std::string & name, Kernel::Math::StatisticType statistic) const - { - double singleValue(0.0); - const auto key = std::make_pair(name, statistic); - if(!m_singleValueCache.getCache(key, singleValue)) - { - const Property *log = getProperty(name); - if(auto singleDouble = dynamic_cast<const PropertyWithValue<double>*>(log)) - { - singleValue = (*singleDouble)(); - } - else if(auto seriesDouble = dynamic_cast<const TimeSeriesProperty<double>*>(log)) - { - singleValue = Mantid::Kernel::filterByStatistic(seriesDouble, statistic); - } - else - { - throw std::invalid_argument("Run::getPropertyAsSingleValue - Property \"" + name + "\" is not a single double or time series double."); - } - PARALLEL_CRITICAL(Run_getPropertyAsSingleValue) - { - // Put it in the cache - m_singleValueCache.setCache(key, singleValue); - } - } - return singleValue; - } - - /** - * Get a pointer to a property by name - * @param name :: The name of a property, throws an Exception::NotFoundError if it does not exist - * @return A pointer to the named property - */ - Kernel::Property * Run::getProperty(const std::string & name) const - { - return m_manager.getProperty(name); - } - - /** Clear out the contents of all logs of type TimeSeriesProperty. - * Single-value properties will be left unchanged. - * - * The method has been fully implemented here instead of as a pass-through to - * PropertyManager to limit its visibility to Run clients. - */ - void Run::clearTimeSeriesLogs() - { - auto & props = getProperties(); - - // Loop over the set of properties, identifying those that are time-series properties - // and then clearing them out. - for ( auto it = props.begin(); it != props.end(); ++it) - { - if ( auto tsp = dynamic_cast<ITimeSeriesProperty*>(*it) ) - { - tsp->clear(); - } - } - } //----------------------------------------------------------------------------------------------- /** @@ -672,35 +398,6 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); // Private methods //----------------------------------------------------------------------------------------------------------------------- - /** Adds all the time series in the second property manager to those in the first - * @param sum the properties to add to - * @param toAdd the properties to add - */ - void Run::mergeMergables(Mantid::Kernel::PropertyManager & sum, const Mantid::Kernel::PropertyManager & toAdd) - { - // get pointers to all the properties on the right-handside and prepare to loop through them - const std::vector<Property*> inc = toAdd.getProperties(); - std::vector<Property*>::const_iterator end = inc.end(); - for (std::vector<Property*>::const_iterator it=inc.begin(); it != end;++it) - { - const std::string rhs_name = (*it)->name(); - try - { - //now get pointers to the same properties on the left-handside - Property * lhs_prop(sum.getProperty(rhs_name)); - lhs_prop->merge(*it); - } - catch (Exception::NotFoundError &) - { - //copy any properties that aren't already on the left hand side - Property * copy = (*it)->clone(); - //And we add a copy of that property to *this - sum.declareProperty(copy, ""); - } - } - } - - /** * Calculate the goniometer matrix */ @@ -714,18 +411,6 @@ Kernel::Logger& Run::g_log = Kernel::Logger::get("Run"); } - /// @cond - /// Macro to instantiate concrete template members -#define INSTANTIATE(TYPE) \ - template MANTID_API_DLL Kernel::TimeSeriesProperty<TYPE> * Run::getTimeSeriesProperty(const std::string &) const;\ - template MANTID_API_DLL TYPE Run::getPropertyValueAsType(const std::string &) const; - - INSTANTIATE(double); - INSTANTIATE(int); - INSTANTIATE(std::string); - INSTANTIATE(bool); - /// @endcond - } //API namespace } diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h index b8e3d28b59166f7b6521e056fdfab666fd7b1931..363b8719b5eb106dcbe82e0a825e87b7d37b76ca 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h @@ -224,6 +224,7 @@ namespace Mantid TYPE getSingleValue(const DateAndTime& t, int& index) const; /// Returns total value, added up for all times regardless of filter TYPE getTotalValue() const; + //template<typename U,typename TYPE> U getTotalValue() const; /// Returns n-th valid time interval, in a very inefficient way. TimeInterval nthInterval(int n) const; diff --git a/Code/Mantid/Framework/Kernel/src/TimeSeriesProperty.cpp b/Code/Mantid/Framework/Kernel/src/TimeSeriesProperty.cpp index 4f8747d32c05a6ec51df2d9da9af9b3d2bed5154..0f41a9658919472daeb7c70cbde29ebb927c71b1 100644 --- a/Code/Mantid/Framework/Kernel/src/TimeSeriesProperty.cpp +++ b/Code/Mantid/Framework/Kernel/src/TimeSeriesProperty.cpp @@ -961,7 +961,7 @@ namespace Mantid * Returns total value, added up for all times regardless of filter * @return Total value from all times */ - template<typename TYPE> + template<typename TYPE> TYPE TimeSeriesProperty<TYPE>::getTotalValue() const { TYPE total = 0; @@ -973,6 +973,20 @@ namespace Mantid return total; } + /* template<> + int TimeSeriesProperty<bool>::getTotalValue() const + { + int total = 0; + + for (size_t i = 0; i < m_values.size(); ++i) + { + if(m_values[i].value())total++; + } + return total; + }*/ + + + /** Returns n-th valid time interval, in a very inefficient way. * * Here are some special cases