From fb87fc50300f66da39cb0d4a668f993b0b6fc9a1 Mon Sep 17 00:00:00 2001 From: pospelov <pospelov@fz-juelich.de> Date: Fri, 14 Dec 2012 17:57:22 +0100 Subject: [PATCH] New signal mechanism for PoolParameter/IParameterized, set of dedicated units tests --- Core/Core.pro | 5 +- .../src/PythonInterface_classes_3.cpp | 14 +-- Core/Tools/inc/FitParameterLinked.h | 5 +- Core/Tools/inc/IChangeable.h | 41 ++++++++ Core/Tools/inc/IParameterized.h | 11 +- Core/Tools/inc/ParameterPool.h | 39 ++------ Core/Tools/inc/RealParameterWrapper.h | 68 +++++++++++++ Core/Tools/src/FitParameterLinked.cpp | 4 +- Core/Tools/src/ParameterPool.cpp | 60 ++++------- Core/Tools/src/RealParameterWrapper.cpp | 23 +++++ Doc/Doxygen/Doxyfile | 2 +- Macros/BoostPythonGenerator/codegenerator.py | 1 + Macros/GitUtils/gisasfw_loc.png | Bin 16893 -> 16905 bytes UnitTests/TestCore/IParameterizedTest.h | 61 ++++++++++++ UnitTests/TestCore/ParameterPoolTest.h | 90 +++++++++++++++++ UnitTests/TestCore/RealParameterWrapperTest.h | 94 ++++++++++++++++++ UnitTests/TestCore/TestCore.pro | 13 ++- UnitTests/TestCore/main.cpp | 3 + shared.pri | 4 +- 19 files changed, 444 insertions(+), 94 deletions(-) create mode 100644 Core/Tools/inc/IChangeable.h create mode 100644 Core/Tools/inc/RealParameterWrapper.h create mode 100644 Core/Tools/src/RealParameterWrapper.cpp create mode 100644 UnitTests/TestCore/IParameterizedTest.h create mode 100644 UnitTests/TestCore/ParameterPoolTest.h create mode 100644 UnitTests/TestCore/RealParameterWrapperTest.h diff --git a/Core/Core.pro b/Core/Core.pro index 9f838bb2a61..9b9f3625cea 100644 --- a/Core/Core.pro +++ b/Core/Core.pro @@ -113,6 +113,7 @@ SOURCES += \ Tools/src/OutputDataWriter.cpp \ Tools/src/ParameterPool.cpp \ Tools/src/ProgramOptions.cpp \ + Tools/src/RealParameterWrapper.cpp \ Tools/src/StochasticGaussian.cpp \ Tools/src/StochasticSampledParameter.cpp \ Tools/src/Types.cpp \ @@ -145,6 +146,7 @@ HEADERS += \ Algorithms/inc/IChiSquaredModule.h \ Algorithms/inc/IDetectorResolution.h \ Algorithms/inc/IFittingDataSelector.h \ + Algorithms/inc/IIntensityFunction.h \ Algorithms/inc/IInterferenceFunctionStrategy.h \ Algorithms/inc/IOutputDataNormalizer.h \ Algorithms/inc/IResolutionFunction2D.h \ @@ -263,6 +265,7 @@ HEADERS += \ Tools/inc/OutputDataWriter.h \ Tools/inc/ParameterPool.h \ Tools/inc/ProgramOptions.h \ + Tools/inc/RealParameterWrapper.h \ Tools/inc/TRange.h \ Tools/inc/StochasticDiracDelta.h \ Tools/inc/StochasticGaussian.h \ @@ -282,7 +285,7 @@ HEADERS += \ PythonAPI/inc/PythonOutputData.h \ PythonAPI/inc/PythonPlusplusHelper.h \ PythonAPI/inc/IPythonWrapper.h \ - Algorithms/inc/IIntensityFunction.h + Tools/inc/IChangeable.h INCLUDEPATH += ./Algorithms/inc ./FormFactors/inc ./Geometry/inc ./Samples/inc ./Tools/inc ./PythonAPI/inc DEPENDPATH += ./Algorithms/inc ./FormFactors/inc ./Geometry/inc ./Samples/inc ./Tools/inc ./PythonAPI/inc diff --git a/Core/PythonAPI/src/PythonInterface_classes_3.cpp b/Core/PythonAPI/src/PythonInterface_classes_3.cpp index 723e7f5f29c..1ae48dca202 100644 --- a/Core/PythonAPI/src/PythonInterface_classes_3.cpp +++ b/Core/PythonAPI/src/PythonInterface_classes_3.cpp @@ -1776,24 +1776,24 @@ void register_classes_3(){ typedef bp::class_< ParameterPool, boost::noncopyable > ParameterPool_exposer_t; ParameterPool_exposer_t ParameterPool_exposer = ParameterPool_exposer_t( "ParameterPool", bp::init< >() ); bp::scope ParameterPool_scope( ParameterPool_exposer ); - bp::class_< ParameterPool::RealPar >( "RealPar", bp::no_init ) + bp::class_< ParameterPool::RealParameterWrapper >( "RealPar", bp::no_init ) .def( "checkNull" - , (void ( ::ParameterPool::RealPar::* )( ) const)( &::ParameterPool::RealPar::checkNull ) ) + , (void ( ::ParameterPool::RealPar::* )( ) const)( &::ParameterPool::RealParameterWrapper::checkNull ) ) .def( "getValue" - , (double ( ::ParameterPool::RealPar::* )( ) const)( &::ParameterPool::RealPar::getValue ) ) + , (double ( ::ParameterPool::RealPar::* )( ) const)( &::ParameterPool::RealParameterWrapper::getValue ) ) .def( "isNull" - , (bool ( ::ParameterPool::RealPar::* )( ) )( &::ParameterPool::RealPar::isNull ) ) + , (bool ( ::ParameterPool::RealPar::* )( ) )( &::ParameterPool::RealParameterWrapper::isNull ) ) .def( "setValue" - , (void ( ::ParameterPool::RealPar::* )( double ) )( &::ParameterPool::RealPar::setValue ) + , (void ( ::ParameterPool::RealPar::* )( double ) )( &::ParameterPool::RealParameterWrapper::setValue ) , ( bp::arg("value") ) ) .def( bp::self_ns::str( bp::self ) ); { //::ParameterPool::addParameter - typedef bool ( ::ParameterPool::*addParameter_function_type )( ::std::string const &,::ParameterPool::RealPar ) ; + typedef bool ( ::ParameterPool::*addParameter_function_type )( ::std::string const &,::ParameterPool::RealParameterWrapper ) ; ParameterPool_exposer.def( "addParameter" @@ -1833,7 +1833,7 @@ void register_classes_3(){ } { //::ParameterPool::getParameter - typedef ::ParameterPool::RealPar ( ::ParameterPool::*getParameter_function_type )( ::std::string const & ) const; + typedef ::ParameterPool::RealParameterWrapper ( ::ParameterPool::*getParameter_function_type )( ::std::string const & ) const; ParameterPool_exposer.def( "getParameter" diff --git a/Core/Tools/inc/FitParameterLinked.h b/Core/Tools/inc/FitParameterLinked.h index 29395e50acb..bff3515ed1a 100644 --- a/Core/Tools/inc/FitParameterLinked.h +++ b/Core/Tools/inc/FitParameterLinked.h @@ -30,8 +30,7 @@ class FitParameterLinked : public FitParameter { public: - typedef ParameterPool::RealPar PoolParameter_t; - typedef std::vector<PoolParameter_t > PoolParameterColl_t; + typedef std::vector<ParameterPool::parameter_t > PoolParameterColl_t; FitParameterLinked(); FitParameterLinked(const std::string &name, double value, double step, const AttLimits &attlim=AttLimits::limitless()); @@ -47,7 +46,7 @@ public: } //! add real parameter to the collection - virtual void addParameter(PoolParameter_t par); + virtual void addParameter(ParameterPool::parameter_t par); //! add parameters from pool which match given wildcard virtual void addMatchedParametersFromPool(const ParameterPool *pool, const std::string &wildcard = std::string()); diff --git a/Core/Tools/inc/IChangeable.h b/Core/Tools/inc/IChangeable.h new file mode 100644 index 00000000000..2240fe2ce73 --- /dev/null +++ b/Core/Tools/inc/IChangeable.h @@ -0,0 +1,41 @@ +#ifndef ICHANGEABLE_H +#define ICHANGEABLE_H +// ******************************************************************** +// * The BornAgain project * +// * Simulation of neutron and x-ray scattering at grazing incidence * +// * * +// * LICENSE AND DISCLAIMER * +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris * +// * eget quam orci. Quisque porta varius dui, quis posuere nibh * +// * mollis quis. Mauris commodo rhoncus porttitor. * +// ******************************************************************** +//! @file IChangeable.h +//! @brief Definition of IChangeable interface +//! @author Scientific Computing Group at FRM II +//! @date Dec 14, 2012 + + +//- ------------------------------------------------------------------- +//! @class IChangeable +//! @brief Definition of IChangeable +//- ------------------------------------------------------------------- +class IChangeable +{ +public: + IChangeable(bool is_changed=false) : m_is_changed(is_changed){} + virtual ~IChangeable(){} + + bool isChanged() + { + bool result = m_is_changed; + m_is_changed = false; + return result; + } + + void setIsChanged(bool is_changed) { m_is_changed = is_changed; } + +private: + bool m_is_changed; +}; + +#endif // ICHANGEABLE_H diff --git a/Core/Tools/inc/IParameterized.h b/Core/Tools/inc/IParameterized.h index 20c30f81275..b70001161d9 100644 --- a/Core/Tools/inc/IParameterized.h +++ b/Core/Tools/inc/IParameterized.h @@ -15,6 +15,7 @@ //! @date Oct 10, 2012 #include "INamed.h" +#include "IChangeable.h" #include "ParameterPool.h" @@ -35,13 +36,19 @@ public: //! add parameters from local pool to external pool and call recursion over direct children virtual std::string addParametersToExternalPool(std::string path, ParameterPool *external_pool, int copy_number=-1) const; - void printParameters() const; + virtual void printParameters() const; + + virtual bool areParametersChanged() { return m_status.isChanged(); } + + virtual void setParametersAreChanged() { m_status.setIsChanged(true); } + protected: //! initialize pool parameters, i.e. register some of class members for later access via parameter pool (to overload) virtual void init_parameters(); ParameterPool m_parameters; //! parameter pool - + IChangeable m_status; }; + #endif /* IPARAMETERIZED_H_ */ diff --git a/Core/Tools/inc/ParameterPool.h b/Core/Tools/inc/ParameterPool.h index e57f04715f8..889526f89af 100644 --- a/Core/Tools/inc/ParameterPool.h +++ b/Core/Tools/inc/ParameterPool.h @@ -15,6 +15,7 @@ //! @date 18.06.2012 #include "Exceptions.h" +#include "RealParameterWrapper.h" #include <string> #include <map> #include <vector> @@ -29,20 +30,9 @@ class ParameterPool { public: - class RealPar { - public: - explicit RealPar(double *par) : m_data(par) {} - void setValue(double value) { checkNull(); *m_data = value; } - double getValue() const { checkNull(); return *m_data; } - bool isNull() { return (m_data ? false : true); } - void checkNull() const { if(!m_data) throw NullPointerException("ParameterPool::RealPar::getValue() -> Attempt to access uninitialised pointer."); } - friend std::ostream &operator<<(std::ostream &ostr, const RealPar &p) { ostr << p.m_data; return ostr; } - private: - volatile double *m_data; - }; - //! definition of parameter type and parameter container - typedef std::map<std::string, RealPar > parametermap_t; + typedef RealParameterWrapper parameter_t; + typedef std::map<std::string, parameter_t > parametermap_t; ParameterPool(); virtual ~ParameterPool(); @@ -66,21 +56,13 @@ public: bool registerParameter(const std::string &name, double *parpointer); //! add parameter to the pool - bool addParameter(const std::string &name, RealPar par); - -// //! access to parameter container -// iterator_t begin() { return m_map.begin(); } -// iterator_t end() { return m_map.end(); } - -// //! const access to parameter container -// const_iterator_t begin() const { return m_map.begin(); } -// const_iterator_t end() const { return m_map.end(); } + bool addParameter(const std::string &name, parameter_t par); //! return parameter with given name - RealPar getParameter(const std::string &name) const; + parameter_t getParameter(const std::string &name) const; //! return vector of parameters which fit pattern - std::vector<RealPar > getMatchedParameters(const std::string &wildcards) const; + std::vector<parameter_t > getMatchedParameters(const std::string &wildcards) const; //! set parameter value, return true in the case of success bool setParameterValue(const std::string &name, double value); @@ -89,14 +71,11 @@ public: int setMatchedParametersValue(const std::string &wildcards, double value); //! print parameter pool - friend std::ostream &operator<<(std::ostream &ostr, const ParameterPool &obj) - { - obj.print(ostr); return ostr; - } + friend std::ostream &operator<<(std::ostream &ostr, const ParameterPool &obj) { obj.print(ostr); return ostr; } protected: - //! disabled copy constructors and assignment operator - ParameterPool(const ParameterPool &); + //! disabling assignment operator, hiding copy constructor + ParameterPool(const ParameterPool &other); ParameterPool &operator=(const ParameterPool &); //! print parameter pool content diff --git a/Core/Tools/inc/RealParameterWrapper.h b/Core/Tools/inc/RealParameterWrapper.h new file mode 100644 index 00000000000..6d674184395 --- /dev/null +++ b/Core/Tools/inc/RealParameterWrapper.h @@ -0,0 +1,68 @@ +#ifndef REALPARAMETERWRAPPER_H +#define REALPARAMETERWRAPPER_H +// ******************************************************************** +// * The BornAgain project * +// * Simulation of neutron and x-ray scattering at grazing incidence * +// * * +// * LICENSE AND DISCLAIMER * +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris * +// * eget quam orci. Quisque porta varius dui, quis posuere nibh * +// * mollis quis. Mauris commodo rhoncus porttitor. * +// ******************************************************************** +//! @file RealParameterWrapper.h +//! @brief Definition of RealParameterWrapper class +//! @author Scientific Computing Group at FRM II +//! @date 14.12.2012 + +#include "Exceptions.h" +#include <boost/signal.hpp> + + +//- ------------------------------------------------------------------- +//! @class RealParameterWrapper +//! @brief Definition of wrapper to real parameter for remote access to its +//! value and callback abilities +//- ------------------------------------------------------------------- +class RealParameterWrapper { +public: + //! type of the signal given parameter can emmit + typedef boost::signal<void ()> signal_t; + + explicit RealParameterWrapper(double *par) : m_data(par) {} + RealParameterWrapper(const RealParameterWrapper &other ); + RealParameterWrapper &operator=(const RealParameterWrapper &other); + ~RealParameterWrapper(){} + + //! set value of wrapped parameter and emmit signal + void setValue(double value) + { + checkNull(); + if(value != *m_data) { + *m_data = value; + m_signal(); + } + } + + //! get value of wrapped parameter + double getValue() const { checkNull(); return *m_data; } + + //! connect external slot with signal which parameter will emmit + void connect(const signal_t::slot_type &slot) { m_signal.connect(slot); } + + //! return true if wrapped parameter was not initialized with proper real value + bool isNull() const { return (m_data ? false : true); } + + //! throw exception if parameter was not initialized with proper value + void checkNull() const { if(isNull()) throw NullPointerException("RealParameterWrapper::getValue() -> Attempt to access uninitialised pointer."); } + + friend std::ostream &operator<<(std::ostream &ostr, const RealParameterWrapper &p) { ostr << p.m_data; return ostr; } +private: + //! swap function + void swapContent(RealParameterWrapper &other); + + volatile double *m_data; + signal_t m_signal; +}; + + +#endif // REALPARAMETERPROXY_H diff --git a/Core/Tools/src/FitParameterLinked.cpp b/Core/Tools/src/FitParameterLinked.cpp index d2da689262d..ae1944e1c0d 100644 --- a/Core/Tools/src/FitParameterLinked.cpp +++ b/Core/Tools/src/FitParameterLinked.cpp @@ -17,7 +17,7 @@ FitParameterLinked::FitParameterLinked(const std::string &name, double value, do /* ************************************************************************* */ //! add real parameter to the collection /* ************************************************************************* */ -void FitParameterLinked::addParameter(PoolParameter_t par) +void FitParameterLinked::addParameter(ParameterPool::parameter_t par) { if( !par.isNull() ) { m_parametercoll.push_back(par); @@ -35,7 +35,7 @@ void FitParameterLinked::addMatchedParametersFromPool(const ParameterPool *pool, std::string wildcard_to_use = getName(); if( !wildcard.empty()) wildcard_to_use = wildcard; - std::vector<ParameterPool::RealPar > matched_pars = pool->getMatchedParameters(wildcard_to_use); + PoolParameterColl_t matched_pars = pool->getMatchedParameters(wildcard_to_use); m_parametercoll.insert(m_parametercoll.end(), matched_pars.begin(), matched_pars.end()); if( matched_pars.empty() ) { diff --git a/Core/Tools/src/ParameterPool.cpp b/Core/Tools/src/ParameterPool.cpp index 42fecbe76f3..f9df4b9646a 100644 --- a/Core/Tools/src/ParameterPool.cpp +++ b/Core/Tools/src/ParameterPool.cpp @@ -5,6 +5,9 @@ #include <sstream> +/* ************************************************************************* */ +// constructors +/* ************************************************************************* */ ParameterPool::ParameterPool() { } @@ -14,26 +17,15 @@ ParameterPool::~ParameterPool() clear(); } -/* ************************************************************************* */ -// copy constructor for completeness -// declared private, to avoid unconscious copying of parameters that point to previous owner -/* ************************************************************************* */ ParameterPool::ParameterPool(const ParameterPool &other) { m_map = other.m_map; } -/* ************************************************************************* */ -// assignment operator for completeness -// declared private, to avoid unconscious copying of parameters that point to previous owner -/* ************************************************************************* */ -ParameterPool &ParameterPool::operator=(const ParameterPool &other) +ParameterPool *ParameterPool::clone() { - if( this != &other) - { - m_map = other.m_map; - } - return *this; + ParameterPool *new_pool = new ParameterPool(*this); + return new_pool; } /* ************************************************************************* */ @@ -50,11 +42,11 @@ void ParameterPool::clear() /* ************************************************************************* */ bool ParameterPool::registerParameter(const std::string &name, double *parameter_address) { - RealPar par(parameter_address); + parameter_t par(parameter_address); return addParameter(name, par); } -bool ParameterPool::addParameter(const std::string &name, RealPar par) +bool ParameterPool::addParameter(const std::string &name, parameter_t par) { parametermap_t::iterator it = m_map.find(name); if( it!=m_map.end() ) { @@ -66,16 +58,6 @@ bool ParameterPool::addParameter(const std::string &name, RealPar par) return m_map.insert(parametermap_t::value_type(name, par ) ).second; } -/* ************************************************************************* */ -// Clone method. Clones everything. -/* ************************************************************************* */ -ParameterPool *ParameterPool::clone() -{ - ParameterPool *new_pool = new ParameterPool; - new_pool->m_map = m_map; - return new_pool; -} - /* ************************************************************************* */ // Clone method that adds a prefix to parameter's keys /* ************************************************************************* */ @@ -103,14 +85,15 @@ void ParameterPool::copyToExternalPool(const std::string &prefix, ParameterPool /* ************************************************************************* */ // return parameter with given name /* ************************************************************************* */ -ParameterPool::RealPar ParameterPool::getParameter(const std::string &name) const +ParameterPool::parameter_t ParameterPool::getParameter(const std::string &name) const { parametermap_t::const_iterator it = m_map.find(name); if( it!=m_map.end() ) { return (*it).second; } else { - std::cout << "ParameterPool::getParameter() -> Warning. No parameter with name '" << name << std::endl; - return RealPar(0); +// std::cout << "ParameterPool::getParameter() -> Warning. No parameter with name '" << name << std::endl; +// return parameter_t(0); + throw LogicErrorException("ParameterPool::getParameter() -> Warning. No parameter with name '"+name+"'"); } } @@ -118,9 +101,9 @@ ParameterPool::RealPar ParameterPool::getParameter(const std::string &name) cons /* ************************************************************************* */ // return vector of parameters which fit pattern /* ************************************************************************* */ -std::vector<ParameterPool::RealPar > ParameterPool::getMatchedParameters(const std::string &wildcards) const +std::vector<ParameterPool::parameter_t > ParameterPool::getMatchedParameters(const std::string &wildcards) const { - std::vector<ParameterPool::RealPar > selected_parameters; + std::vector<ParameterPool::parameter_t > selected_parameters; // loop over all parameters in the pool for(parametermap_t::const_iterator it=m_map.begin(); it!= m_map.end(); ++it) { // (*it).first - parameter key, (*it).second - parameter itself @@ -145,7 +128,7 @@ std::vector<ParameterPool::RealPar > ParameterPool::getMatchedParameters(const /* ************************************************************************* */ bool ParameterPool::setParameterValue(const std::string &name, double value) { - RealPar x = getParameter(name); + parameter_t x = getParameter(name); if( x.isNull() ) { std::cout << "ParameterPool::setParameterValue() -> Warning. No parameter with name '" << name << "'" << std::endl; throw LogicErrorException("ParameterPool::setParameterValue() -> Warning. No such parameter"); @@ -175,26 +158,21 @@ int ParameterPool::setMatchedParametersValue(const std::string &wildcards, doubl /* ************************************************************************* */ void ParameterPool::print(std::ostream &ostr) const { - // output depends on size of the pool - size_t nsize = m_map.size(); - - if(nsize) { + const int number_of_pars_in_line(4); + if( m_map.size() ) { // printing in one line - if(nsize < 4) { - ostr << "POOL_" << nsize; + if(m_map.size() < number_of_pars_in_line) { + ostr << "POOL_" << m_map.size(); ostr << "("; for(parametermap_t::const_iterator it=m_map.begin(); it!= m_map.end(); ++it) { std::cout << "'" << (*it).first << "'" << ":" << it->second.getValue() << " " ; } ostr << ")"; - // printing in several lines } else { for(parametermap_t::const_iterator it=m_map.begin(); it!= m_map.end(); ++it) { std::cout << "'" << (*it).first << "'" << ":" << it->second.getValue() << std::endl; } } - - } } diff --git a/Core/Tools/src/RealParameterWrapper.cpp b/Core/Tools/src/RealParameterWrapper.cpp new file mode 100644 index 00000000000..b4e499e3ca6 --- /dev/null +++ b/Core/Tools/src/RealParameterWrapper.cpp @@ -0,0 +1,23 @@ +#include "RealParameterWrapper.h" + + + +RealParameterWrapper::RealParameterWrapper(const RealParameterWrapper &other ) +{ + m_data = other.m_data; +} + +RealParameterWrapper &RealParameterWrapper::operator=(const RealParameterWrapper &other) +{ + if( this != &other ) { + RealParameterWrapper tmp(other); + tmp.swapContent(*this); + } + return *this; +} + +void RealParameterWrapper::swapContent(RealParameterWrapper &other) +{ + std::swap(this->m_data, other.m_data); +} + diff --git a/Doc/Doxygen/Doxyfile b/Doc/Doxygen/Doxyfile index 31fd7034bd1..2e8c4a5fe7f 100644 --- a/Doc/Doxygen/Doxyfile +++ b/Doc/Doxygen/Doxyfile @@ -1573,7 +1573,7 @@ HIDE_UNDOC_RELATIONS = YES # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) -HAVE_DOT = NO +HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will diff --git a/Macros/BoostPythonGenerator/codegenerator.py b/Macros/BoostPythonGenerator/codegenerator.py index 6c03f22a946..48c0b4f879f 100644 --- a/Macros/BoostPythonGenerator/codegenerator.py +++ b/Macros/BoostPythonGenerator/codegenerator.py @@ -70,6 +70,7 @@ myFiles=[ 'DiffuseParticleInfo.h', 'PythonOutputData.h', 'PythonPlusplusHelper.h', + 'RealParameterWrapper.h', 'Transform3D.h', 'Units.h', 'Types.h', diff --git a/Macros/GitUtils/gisasfw_loc.png b/Macros/GitUtils/gisasfw_loc.png index 3a204838a68c5666983eea4441144df06094f070..5a0bad0546b81bba53c9a89fb05a0272edf3dca4 100644 GIT binary patch delta 13211 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 delta 13271 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 diff --git a/UnitTests/TestCore/IParameterizedTest.h b/UnitTests/TestCore/IParameterizedTest.h new file mode 100644 index 00000000000..39332d36139 --- /dev/null +++ b/UnitTests/TestCore/IParameterizedTest.h @@ -0,0 +1,61 @@ +#ifndef IPARAMETERIZEDTEST_H +#define IPARAMETERIZEDTEST_H + +#include "IParameterized.h" + + +class IParameterizedTest : public ::testing::Test +{ +protected: + IParameterizedTest() {} + virtual ~IParameterizedTest(){} + + IParameterized m_initial_object; + + class ParameterizedObject : public IParameterized + { + public: + ParameterizedObject() : m_real_par1(0), m_real_par2(0) { + setName("Parameterized"); init_parameters(); } + double m_real_par1; + double m_real_par2; + protected: + virtual void init_parameters() + { + getParameterPool()->registerParameter("par1",&m_real_par1); + getParameterPool()->registerParameter("par2",&m_real_par2); + } + }; + ParameterizedObject m_parameterized; +}; + + +TEST_F(IParameterizedTest, InitialState) +{ + EXPECT_FALSE( m_initial_object.areParametersChanged() ); + m_initial_object.setParametersAreChanged(); + EXPECT_TRUE( m_initial_object.areParametersChanged() ); // after this call object has to change state + EXPECT_FALSE( m_initial_object.areParametersChanged() ); + EXPECT_EQ( size_t(0), m_initial_object.getParameterPool()->size() ); + IParameterized obj2(m_initial_object); + EXPECT_FALSE( obj2.areParametersChanged() ); +} + + +TEST_F(IParameterizedTest, DealingWithPool) +{ + EXPECT_EQ( size_t(2), m_parameterized.getParameterPool()->size()); + IParameterizedTest::ParameterizedObject obj2 = m_parameterized; + EXPECT_EQ( size_t(0), obj2.getParameterPool()->size()); + ParameterPool *pool = m_parameterized.createParameterTree(); + //POOL_2('/Parameterized/par1':0 '/Parameterized/par2':0 ) + //std::cout << *pool << std::endl; + pool->getParameter("/Parameterized/par1").setValue(1.0); + pool->getParameter("/Parameterized/par2").setValue(2.0); + EXPECT_EQ( double(1.0), m_parameterized.m_real_par1); + EXPECT_EQ( double(2.0), m_parameterized.m_real_par2); +} + + + +#endif // IPARAMETERIZEDTEST_H diff --git a/UnitTests/TestCore/ParameterPoolTest.h b/UnitTests/TestCore/ParameterPoolTest.h new file mode 100644 index 00000000000..d06ea262dc4 --- /dev/null +++ b/UnitTests/TestCore/ParameterPoolTest.h @@ -0,0 +1,90 @@ +#ifndef PARAMETERPOOLTEST_H +#define PARAMETERPOOLTEST_H + + +#include "ParameterPool.h" + + +class ParameterPoolTest : public ::testing::Test +{ +protected: + ParameterPoolTest(); + virtual ~ParameterPoolTest(){} + + ParameterPool m_empty_pool; + ParameterPool m_pool; + double m_real_par1; + double m_real_par2; + double m_real_par3; + double m_real_par4; +}; + + +ParameterPoolTest::ParameterPoolTest() : m_real_par1(1.0), m_real_par2(2.0), m_real_par3(3.0), m_real_par4(4.0) +{ + m_pool.registerParameter("a_par1",&m_real_par1); + m_pool.registerParameter("a_par2",&m_real_par2); + ParameterPool::parameter_t poolpar(&m_real_par3); + m_pool.addParameter("b_par3",poolpar); +} + + +TEST_F(ParameterPoolTest, InitialState) +{ + EXPECT_EQ( size_t(0), m_empty_pool.size() ); + ASSERT_THROW( m_empty_pool.getParameter("NotExistingName"), LogicErrorException ); +} + + +TEST_F(ParameterPoolTest, registerParameters) +{ + EXPECT_EQ( size_t(3), m_pool.size() ); + EXPECT_EQ( double(1.0), m_pool.getParameter("a_par1").getValue()); + EXPECT_EQ( double(2.0), m_pool.getParameter("a_par2").getValue()); + EXPECT_EQ( double(3.0), m_pool.getParameter("b_par3").getValue()); + m_real_par3 = 3.1; + EXPECT_EQ( double(3.1), m_pool.getParameter("b_par3").getValue()); + std::vector<ParameterPool::parameter_t > pars = m_pool.getMatchedParameters("*par*"); + EXPECT_EQ( size_t(3), pars.size() ); + pars = m_pool.getMatchedParameters("a_par*"); + EXPECT_EQ( size_t(2), pars.size() ); + + ASSERT_THROW( m_pool.setParameterValue("NonExistingName", 3.2), LogicErrorException ); + m_pool.setParameterValue("b_par3", 3.2); + EXPECT_EQ( double(3.2), m_pool.getParameter("b_par3").getValue()); + + EXPECT_EQ( int(3), m_pool.setMatchedParametersValue("*par*",5.0)); + EXPECT_EQ( double(5.0), m_real_par1); + EXPECT_EQ( double(5.0), m_real_par2); + EXPECT_EQ( double(5.0), m_real_par3); +} + + +TEST_F(ParameterPoolTest, PoolClone) +{ + ParameterPool *pool = m_pool.clone(); + EXPECT_EQ( size_t(3), pool->size() ); +} + + +TEST_F(ParameterPoolTest, CopyToExternalPool) +{ + m_real_par1 = 1.0; + m_real_par2 = 2.0; + m_real_par3 = 3.0; + m_real_par4 = 4.0; + ParameterPool external_pool; + external_pool.registerParameter("par4",&m_real_par4); + m_pool.copyToExternalPool("Another/",&external_pool); + std::cout << external_pool << std::endl; + EXPECT_EQ( double(1.0), external_pool.getParameter("Another/a_par1").getValue()); + EXPECT_EQ( double(2.0), external_pool.getParameter("Another/a_par2").getValue()); + EXPECT_EQ( double(3.0), external_pool.getParameter("Another/b_par3").getValue()); + EXPECT_EQ( double(4.0), external_pool.getParameter("par4").getValue()); + +// EXPECT_EQ( size_t(0), m_pool.size() ); +} + + + +#endif // PARAMETERPOOLTEST_H diff --git a/UnitTests/TestCore/RealParameterWrapperTest.h b/UnitTests/TestCore/RealParameterWrapperTest.h new file mode 100644 index 00000000000..3d640e09d51 --- /dev/null +++ b/UnitTests/TestCore/RealParameterWrapperTest.h @@ -0,0 +1,94 @@ +#ifndef REALPARAMETERWRAPPERTEST_H +#define REALPARAMETERWRAPPERTEST_H + +#include "RealParameterWrapper.h" +#include "Exceptions.h" +#include <boost/bind.hpp> + +class RealParameterWrapperTest : public ::testing::Test +{ +protected: + RealParameterWrapperTest(); + virtual ~RealParameterWrapperTest(); + + double m_real_parameter; + RealParameterWrapper m_null_par; + + class ObjectToNotify + { + public: + void set_status_true() { m_status = true; } + void set_status_false() { m_status = false; } + bool m_status; + }; +}; + + +RealParameterWrapperTest::RealParameterWrapperTest() : m_real_parameter(3.141), m_null_par(0) +{ + +} + +RealParameterWrapperTest::~RealParameterWrapperTest() +{ + +} + +TEST_F(RealParameterWrapperTest, InitialState) +{ + EXPECT_TRUE( m_null_par.isNull() ); + ASSERT_THROW( m_null_par.getValue(), NullPointerException ); + ASSERT_THROW( m_null_par.setValue(1.0), NullPointerException ); + + RealParameterWrapper par(m_null_par); + EXPECT_TRUE( par.isNull() ); + ASSERT_THROW( par.getValue(), NullPointerException ); + ASSERT_THROW( par.setValue(1.0), NullPointerException ); +} + +TEST_F(RealParameterWrapperTest, ParameterAccess) +{ + RealParameterWrapper par11(&m_real_parameter); + EXPECT_EQ( m_real_parameter, par11.getValue() ); + + RealParameterWrapper par12 = par11; + EXPECT_EQ( m_real_parameter, par12.getValue() ); + + m_real_parameter = 2.0; + EXPECT_EQ( double(2.0), par11.getValue() ); + EXPECT_EQ( double(2.0), par12.getValue() ); + std::vector<RealParameterWrapper > parameters; + parameters.push_back(par11); + parameters.push_back(par12); + + parameters[0].setValue(3.0); + EXPECT_EQ( double(3.0), m_real_parameter ); + EXPECT_EQ( double(3.0), parameters[1].getValue() ); +} + +TEST_F(RealParameterWrapperTest, ParameterSignals) +{ + // check that parameter emmits signals to two objects + m_real_parameter = 1.0; + RealParameterWrapper par(&m_real_parameter); + ObjectToNotify obj1, obj2; + RealParameterWrapper::signal_t::slot_type fun1 = boost::bind(&ObjectToNotify::set_status_true, &obj1); + RealParameterWrapper::signal_t::slot_type fun2 = boost::bind(&ObjectToNotify::set_status_true, &obj2); + par.connect(fun1); + par.connect(fun2); + obj1.m_status = false; + obj2.m_status = false; + par.setValue(2.0); // at this point status of object has to be changed by signal emmited from the parameter + EXPECT_TRUE( obj1.m_status ); + EXPECT_TRUE( obj2.m_status ); + // par2 should not emmit signals since they are not copied + RealParameterWrapper par2 = par; + obj1.m_status = false; + obj2.m_status = false; + par2.setValue(3.0); + EXPECT_FALSE( obj1.m_status ); + EXPECT_FALSE( obj2.m_status ); +} + + +#endif // REALPARAMETERWRAPPERTEST_H diff --git a/UnitTests/TestCore/TestCore.pro b/UnitTests/TestCore/TestCore.pro index a12bd08d33a..6212bf78474 100644 --- a/UnitTests/TestCore/TestCore.pro +++ b/UnitTests/TestCore/TestCore.pro @@ -20,7 +20,10 @@ HEADERS += \ OutputDataTest.h \ OutputDataIteratorTest.h \ GISASExperimentTest.h \ - ChiSquaredModuleTest.h + ChiSquaredModuleTest.h \ + RealParameterWrapperTest.h \ + IParameterizedTest.h \ + ParameterPoolTest.h OBJECTS_DIR = obj @@ -28,14 +31,14 @@ INCLUDEPATH += ../../Core/Algorithms/inc ../../Core/FormFactors/inc ../../Core/G DEPENDPATH += ../../Core/Algorithms/inc ../../Core/FormFactors/inc ../../Core/Geometry/inc ../../Core/Samples/inc ../../Core/Tools/inc ../../ThirdParty/gtest/gtest-1.6.0/include DEPENDPATH += $$PWD/. -LIBS = -L/opt/local/lib -lfftw3 +#LIBS = -L/opt/local/lib -lfftw3 -CONFIG(JCNS) { +#CONFIG(JCNS) { #LIBS -= -lfftw3 #LIBS += -Bstatic -lfftw3 -Bdynamic # request for static (with fPIC option) # "-lfftw3f" - with fPIC option, "-lfftw3" - without fPIC option - LIBS = -L/usr/users/jcns/pospelov/software/lib -lfftw3 -} + #LIBS = -L/usr/users/jcns/pospelov/software/lib -lfftw3 +#} ############################################################################### # generating package dependency flags diff --git a/UnitTests/TestCore/main.cpp b/UnitTests/TestCore/main.cpp index d587feee84f..cdc363828ed 100644 --- a/UnitTests/TestCore/main.cpp +++ b/UnitTests/TestCore/main.cpp @@ -5,10 +5,13 @@ #include "DetectorTest.h" #include "ExperimentTest.h" #include "GISASExperimentTest.h" +#include "IParameterizedTest.h" #include "MaskTest.h" #include "AxisDoubleTest.h" #include "OutputDataTest.h" #include "OutputDataIteratorTest.h" +#include "ParameterPoolTest.h" +#include "RealParameterWrapperTest.h" int main(int argc, char** argv) { diff --git a/shared.pri b/shared.pri index 305feea9f38..95523d087d9 100644 --- a/shared.pri +++ b/shared.pri @@ -59,7 +59,7 @@ for(dir, BOOST_LIB_LOCATIONS): isEmpty(BOOST_LIB) { isEmpty(BOOST_LIB): message("Can't find" $${BOOST_LIBFILES} "in" $${BOOST_LIB_LOCATIONS}) INCLUDEPATH *= $${BOOST_INCLUDE} LIBS *= -L$${BOOST_LIB} -LIBS += -lboost_program_options -lboost_iostreams -lboost_system -lboost_filesystem -lboost_regex -lboost_thread +LIBS += -lboost_program_options -lboost_iostreams -lboost_system -lboost_signals -lboost_filesystem -lboost_regex -lboost_thread # checking special case when system doesn't have libboost_thread library but have libbost_thread-mt NumberOfSuchFiles=$$system(ls $${BOOST_LIB}/libboost_thread-mt* 2> /dev/null | wc -l) !isEqual(NumberOfSuchFiles, 0) { @@ -92,7 +92,7 @@ isEqual(env_jcns_variable, "yes") { CONFIG(JCNS) { message("Special config for JCNS") INCLUDEPATH += /usr/users/jcns/pospelov/software/include - LIBS = -L/usr/users/jcns/pospelov/software/lib -L/usr/local/lib -L/usr/lib64 -lgsl -lgslcblas -lfftw3 -lboost_program_options -lboost_iostreams -lboost_system -lboost_filesystem -lboost_regex -lboost_thread + LIBS = -L/usr/users/jcns/pospelov/software/lib -L/usr/local/lib -L/usr/lib64 -lgsl -lgslcblas -lfftw3 -lboost_program_options -lboost_iostreams -lboost_system -lboost_signals -lboost_filesystem -lboost_regex -lboost_thread } -- GitLab