From fc2dc30969eecf90dd7f65e0535c1f509f889455 Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Tue, 9 Aug 2016 13:48:17 +0200
Subject: [PATCH] New ExperimentalFit functional test on the way to minimizer
 refactoring

---
 Fit/Minimizer/BasicMinimizer.cpp             |  5 ++
 Fit/Minimizer/BasicMinimizer.h               |  4 ++
 Fit/Minimizer/Configurable.cpp               | 13 ++++++
 Fit/Minimizer/Configurable.h                 |  5 +-
 Fit/Minimizer/MinimizerFactory.cpp           |  4 +-
 Fit/Minimizer/MinimizerOption.h              |  2 +-
 Fit/Minimizer/Minuit2Minimizer.cpp           | 49 ++++++++++++++++++++
 Fit/Minimizer/Minuit2Minimizer.h             | 22 +++++++--
 Tests/Functional/Fit/CMakeLists.txt          |  8 +++-
 Tests/Functional/Fit/ExperimentalFitTest.cpp | 26 +++++++++++
 Tests/Functional/Fit/ExperimentalFitTest.h   | 32 +++++++++++++
 Tests/Functional/Fit/StandardFitsFactory.cpp |  6 +++
 Tests/UnitTests/Fit/CMakeLists.txt           |  5 +-
 13 files changed, 166 insertions(+), 15 deletions(-)
 create mode 100644 Tests/Functional/Fit/ExperimentalFitTest.cpp
 create mode 100644 Tests/Functional/Fit/ExperimentalFitTest.h

diff --git a/Fit/Minimizer/BasicMinimizer.cpp b/Fit/Minimizer/BasicMinimizer.cpp
index 3c301b13710..62e06ecd28c 100644
--- a/Fit/Minimizer/BasicMinimizer.cpp
+++ b/Fit/Minimizer/BasicMinimizer.cpp
@@ -37,3 +37,8 @@ void BasicMinimizer::setAlgorithmName(const std::string &algorithmName)
     m_algorithmName = algorithmName;
 }
 
+void BasicMinimizer::propagateOptions()
+{
+
+}
+
diff --git a/Fit/Minimizer/BasicMinimizer.h b/Fit/Minimizer/BasicMinimizer.h
index a7157d52d61..c91dc226f6b 100644
--- a/Fit/Minimizer/BasicMinimizer.h
+++ b/Fit/Minimizer/BasicMinimizer.h
@@ -28,6 +28,7 @@ class BA_CORE_API_ BasicMinimizer : public IMinimizer
 public:
     explicit BasicMinimizer(const std::string &minimizerName,
                             const std::string &algorithmName = std::string());
+    virtual ~BasicMinimizer(){}
 
     //! Returns name of the minimizer.
     std::string minimizerName() const;
@@ -38,6 +39,9 @@ public:
     //! Sets minimization algorithm.
     void setAlgorithmName(const std::string &algorithmName);
 
+protected:
+   virtual void propagateOptions();
+
 private:
     std::string m_minimizerName;
     std::string m_algorithmName;
diff --git a/Fit/Minimizer/Configurable.cpp b/Fit/Minimizer/Configurable.cpp
index 56035a128b2..d50eaeebaf5 100644
--- a/Fit/Minimizer/Configurable.cpp
+++ b/Fit/Minimizer/Configurable.cpp
@@ -33,6 +33,7 @@ Configurable &Configurable::operator=(const Configurable &other)
 
 Configurable::option_t Configurable::option(const std::string &optionName)
 {
+//    const_cast<option_t >(static_cast<const Configurable*>(this)->option(optionName));
     for(auto option: m_options) {
         if(option->name() == optionName)
             return option;
@@ -42,6 +43,18 @@ Configurable::option_t Configurable::option(const std::string &optionName)
                              + optionName + "'.");
 }
 
+const Configurable::option_t Configurable::option(const std::string &optionName) const
+{
+    for(const option_t option: m_options) {
+        if(option->name() == optionName)
+            return option;
+    }
+
+    throw std::runtime_error("Configurable::getOption() -> Error. No option with name '"
+                             + optionName + "'.");
+
+}
+
 bool Configurable::exists(const std::string &name)
 {
     for(auto option: m_options) {
diff --git a/Fit/Minimizer/Configurable.h b/Fit/Minimizer/Configurable.h
index 4382cf660d0..8d7fa6ce2ba 100644
--- a/Fit/Minimizer/Configurable.h
+++ b/Fit/Minimizer/Configurable.h
@@ -41,9 +41,10 @@ public:
                        const std::string &description = std::string());
 
     option_t option(const std::string &optionName);
+    const option_t option(const std::string &optionName) const;
 
     template<class T>
-    T optionValue(const std::string &optionName);
+    T optionValue(const std::string &optionName) const;
 
     //! Sets the value of option. Option should hold same value type already.
     template<class T>
@@ -69,7 +70,7 @@ Configurable::option_t Configurable::addOption(const std::string &optionName, T
 }
 
 template<class T>
-T Configurable::optionValue(const std::string &optionName)
+T Configurable::optionValue(const std::string &optionName) const
 {
     return option(optionName)->get<T>();
 }
diff --git a/Fit/Minimizer/MinimizerFactory.cpp b/Fit/Minimizer/MinimizerFactory.cpp
index b6e39f90bce..f7a4e75103f 100644
--- a/Fit/Minimizer/MinimizerFactory.cpp
+++ b/Fit/Minimizer/MinimizerFactory.cpp
@@ -109,9 +109,7 @@ IMinimizer* MinimizerFactory::createMinimizer(
 
     IMinimizer* result(0);
     if( minimizer == "Test" ) {
-        //result = new TrivialMinimizer();
-        result = new Minuit2Minimizer();
-
+        result = new TrivialMinimizer();
         /* temporarily disabled
     } else if( minimizer == "Scan" ) {
         result = new ScanningMinimizer();
diff --git a/Fit/Minimizer/MinimizerOption.h b/Fit/Minimizer/MinimizerOption.h
index fa491366eb3..0fc770958b8 100644
--- a/Fit/Minimizer/MinimizerOption.h
+++ b/Fit/Minimizer/MinimizerOption.h
@@ -24,7 +24,7 @@
 //! @ingroup fitting_internal
 //! @brief The MinimizerOption class is intended to store a single option for minimization
 //! algorithm. Int, double, string values are available.
-//! Relies on https://github.com/mapbox/variant
+//! Relies on https://github.com/mapbox/variant, will be switched to std::variant in C++-17.
 
 class BA_CORE_API_ MinimizerOption
 {
diff --git a/Fit/Minimizer/Minuit2Minimizer.cpp b/Fit/Minimizer/Minuit2Minimizer.cpp
index ef3e12ea7ac..9735999e65f 100644
--- a/Fit/Minimizer/Minuit2Minimizer.cpp
+++ b/Fit/Minimizer/Minuit2Minimizer.cpp
@@ -26,6 +26,7 @@ const std::string O_PRINTLEVEL = "PrintLevel";
 
 Minuit2Minimizer::Minuit2Minimizer()
     : BasicMinimizer(MinimizerNames::Minuit, AlgorithmNames::Migrad)
+    , m_minuit2_minimizer(new BA_ROOT::Minuit2::Minuit2Minimizer("xxx"))
 {
     addOption(O_STRATEGY, 1,
               "Minimization strategy (0-low, 1-medium, 2-high quality)");
@@ -35,6 +36,13 @@ Minuit2Minimizer::Minuit2Minimizer()
               "Tolerance on the function value at the minimum.");
     addOption(O_PRECISION, -1.0,
               "Relative floating point arithmetic precision.");
+    addOption(O_PRINTLEVEL, 0,
+              "Minimizer internal print level.");
+
+}
+
+Minuit2Minimizer::~Minuit2Minimizer()
+{
 
 }
 
@@ -43,18 +51,59 @@ void Minuit2Minimizer::setStrategy(int value)
     setOptionValue(O_STRATEGY, value);
 }
 
+int Minuit2Minimizer::strategy() const
+{
+    return optionValue<int>(O_STRATEGY);
+}
+
 void Minuit2Minimizer::setErrorDefinition(double value)
 {
     setOptionValue(O_ERRORDEF, value);
 }
 
+double Minuit2Minimizer::errorDefinition() const
+{
+    return optionValue<double>(O_ERRORDEF);
+}
+
 void Minuit2Minimizer::setTolerance(double value)
 {
     setOptionValue(O_TOLERANCE, value);
 }
 
+double Minuit2Minimizer::tolerance() const
+{
+    return optionValue<double>(O_TOLERANCE);
+}
+
 void Minuit2Minimizer::setPrecision(double value)
 {
     setOptionValue(O_PRECISION, value);
 }
 
+double Minuit2Minimizer::precision() const
+{
+    return optionValue<double>(O_PRECISION);
+}
+
+void Minuit2Minimizer::setPrintLevel(int value)
+{
+    setOptionValue(O_PRINTLEVEL, value);
+}
+
+int Minuit2Minimizer::printLevel() const
+{
+    return optionValue<int>(O_PRINTLEVEL);
+}
+
+//! Propagate options down to ROOT's Minuit2Minimizer.
+
+void Minuit2Minimizer::propagateOptions()
+{
+    m_minuit2_minimizer->SetStrategy(strategy());
+    m_minuit2_minimizer->SetErrorDef(errorDefinition());
+    m_minuit2_minimizer->SetTolerance(tolerance());
+    m_minuit2_minimizer->SetPrecision(precision());
+    m_minuit2_minimizer->SetPrintLevel(printLevel());
+}
+
diff --git a/Fit/Minimizer/Minuit2Minimizer.h b/Fit/Minimizer/Minuit2Minimizer.h
index 1c5178445fe..711daca9c70 100644
--- a/Fit/Minimizer/Minuit2Minimizer.h
+++ b/Fit/Minimizer/Minuit2Minimizer.h
@@ -17,6 +17,8 @@
 #define MINUIT2MINIMIZER_H
 
 #include "BasicMinimizer.h"
+#include "Minuit2/Minuit2Minimizer.h"
+#include <memory>
 
 //! @class Minuit2Minimizer
 //! @ingroup fitting_internal
@@ -27,38 +29,48 @@ class BA_CORE_API_ Minuit2Minimizer : public BasicMinimizer
 {
 public:
     Minuit2Minimizer();
+    ~Minuit2Minimizer();
 
     //! Sets minimization strategy (0-low, 1-medium, 2-high minimization quality).
-    //! At low quality number of function calls will be economized. Default value is 1.
+    //! At low quality number of function calls will be economized.
+    //! Default value is 1.
     void setStrategy(int value);
+    int strategy() const;
 
     //! Sets error definition factor for parameter error calculation.
     //! If objective function (OF) is the usual chisquare function and if the user wants the usual
     //! one-standard-deviation errors, then the error definition should be 1.0. If OF is a
     //! negative-log-likelihood function, then 0.5. If OF is a chisquare, but the user wants
     //! two-standard-deviation errors, 4.0.
-    //! Default value is 1.0
+    //! Default value is 1.0.
     void setErrorDefinition(double value);
+    double errorDefinition() const;
 
     //!< Sets tolerance on the function value at the minimum.
     //!< Minimization will stop when the estimated vertical distance to the minimum (EDM) is less
-    //! than 0.001*tolerance*ErrorDef. Here ErrorDef=1 for chi squared fit and ErrorDef=0.5
+    //! than 0.001*tolerance*ErrorDef. Here ErrorDef=1.0 for chi squared fit and ErrorDef=0.5
     //! for negative log likelihood fit.
-    //! Default value is 0.01
+    //! Default value is 0.01.
     void setTolerance(double value);
+    double tolerance() const;
 
     //!< Sets relative floating point arithmetic precision.
     //!< Should be adjusted when the user knows that objectiove function value is not
     //!< calculated to the nominal machine accuracy. Typical values are between 10^-5 and 10^-14.
     //!  Default value is -1.0 (minimizer specific will be used).
     void setPrecision(double value);
+    double precision() const;
 
     //! Sets minimizer internal print level.
     //! Default value is 0 (silent).
     void setPrintLevel(int value);
+    int printLevel() const;
 
-private:
+protected:
+    void propagateOptions();
 
+private:
+    std::unique_ptr<BA_ROOT::Minuit2::Minuit2Minimizer> m_minuit2_minimizer;
 };
 
 #endif
diff --git a/Tests/Functional/Fit/CMakeLists.txt b/Tests/Functional/Fit/CMakeLists.txt
index f9cf473180b..215e1f16154 100644
--- a/Tests/Functional/Fit/CMakeLists.txt
+++ b/Tests/Functional/Fit/CMakeLists.txt
@@ -11,6 +11,7 @@ set(test_cases
     Minuit2_Fumili
     Minuit2_Migrad
     RectDetectorFit
+    ExperimentalFit
 )
 
 # for some reason these flags doesn't propagated here by SetUpWindows.cmake
@@ -31,7 +32,12 @@ include_directories(
 #file(GLOB source_files "*.cpp")
 #file(GLOB include_files "*.h")
 
-add_executable(FitTest FitTest.cpp IMinimizerTest.cpp  IMinimizerTest.h  MinimizerTests.cpp  MinimizerTests.h RectDetectorFitTest.cpp  RectDetectorFitTest.h  StandardFitsFactory.cpp  StandardFitsFactory.h)
+add_executable(FitTest
+    FitTest.cpp IMinimizerTest.cpp  IMinimizerTest.h  MinimizerTests.cpp
+    MinimizerTests.h RectDetectorFitTest.cpp  RectDetectorFitTest.h
+    StandardFitsFactory.cpp StandardFitsFactory.h
+    ExperimentalFitTest.h ExperimentalFitTest.cpp
+    )
 
 target_link_libraries(FitTest BornAgainFit BornAgainCore BornAgainTestMachinery)
 foreach(test_case ${test_cases})
diff --git a/Tests/Functional/Fit/ExperimentalFitTest.cpp b/Tests/Functional/Fit/ExperimentalFitTest.cpp
new file mode 100644
index 00000000000..0bdccc17f8f
--- /dev/null
+++ b/Tests/Functional/Fit/ExperimentalFitTest.cpp
@@ -0,0 +1,26 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Tests/Functional/Fit/ExperimentalFitTest.cpp
+//! @brief     Implements class ExperimentalFitTest.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#include "ExperimentalFitTest.h"
+#include "GISASSimulation.h"
+#include "Histogram2D.h"
+#include "Rectangle.h"
+#include "RectangularDetector.h"
+#include "Units.h"
+
+ExperimentalFitTest::ExperimentalFitTest()
+    : IMinimizerTest("Minuit2", "Migrad")
+{
+}
diff --git a/Tests/Functional/Fit/ExperimentalFitTest.h b/Tests/Functional/Fit/ExperimentalFitTest.h
new file mode 100644
index 00000000000..735d209d637
--- /dev/null
+++ b/Tests/Functional/Fit/ExperimentalFitTest.h
@@ -0,0 +1,32 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Tests/Functional/Fit/ExperimentalFitTest.h
+//! @brief     Declares class ExperimentalFitTest.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#ifndef EXPERIMENTALFITTEST_H
+#define EXPERIMENTALFITTEST_H
+
+#include "IMinimizerTest.h"
+
+//! @class ExperimentalFitTest
+//! @ingroup standard_samples
+//! @brief Experimental test on the way to refactored minimizers
+
+class ExperimentalFitTest : public IMinimizerTest
+{
+public:
+    ExperimentalFitTest();
+
+};
+
+#endif // EXPERIMENTALFITTEST_H
diff --git a/Tests/Functional/Fit/StandardFitsFactory.cpp b/Tests/Functional/Fit/StandardFitsFactory.cpp
index 920cde1a0c7..d9ecffe09e8 100644
--- a/Tests/Functional/Fit/StandardFitsFactory.cpp
+++ b/Tests/Functional/Fit/StandardFitsFactory.cpp
@@ -16,6 +16,7 @@
 #include "StandardFitsFactory.h"
 #include "MinimizerTests.h"
 #include "RectDetectorFitTest.h"
+#include "ExperimentalFitTest.h"
 #include <boost/format.hpp>
 
 StandardFitsFactory::StandardFitsFactory()
@@ -59,6 +60,11 @@ StandardFitsFactory::StandardFitsFactory()
         "RectDetectorFit",
         create_new<RectDetectorFitTest>,
         "Fit of rectangular detector, with crop and masks applied");
+
+    registerItem(
+        "ExperimentalFit",
+        create_new<ExperimentalFitTest>,
+        "Experimental fit on the way to refactoring");
 }
 
 IFunctionalTest* StandardFitsFactory::createTest(const std::string& test_name)
diff --git a/Tests/UnitTests/Fit/CMakeLists.txt b/Tests/UnitTests/Fit/CMakeLists.txt
index 1eb78612b4e..356d5a8cd8d 100644
--- a/Tests/UnitTests/Fit/CMakeLists.txt
+++ b/Tests/UnitTests/Fit/CMakeLists.txt
@@ -3,16 +3,15 @@
 ############################################################################
 
 include_directories(
-    ${Boost_INCLUDE_DIRS}
     ${BornAgainCore_INCLUDE_DIRS}
     ${BornAgainFit_INCLUDE_DIRS}
     ${EIGEN3_INCLUDE_DIR}
-    ${GSL_INCLUDE_DIR}
+    ${RootMinimizers_INCLUDE_DIRS}
 )
 
 if(BORNAGAIN_OPENMPI)
     include_directories(${MPI_INCLUDE_PATH})
 endif()
 
-#message(WARNING "Some unit tests disabled")
 WRAP_GTEST(TestFit0 "*.h" ${BornAgainCore_LIBRARY} 0)
+
-- 
GitLab