From e9d6cbd8028d02dbfe0a891089682a5bb03a7a3e Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Thu, 22 Sep 2016 17:08:06 +0200
Subject: [PATCH] New functional test to verify minimizer chain.

---
 .../Fit/AdjustMinimizerStrategyTest.cpp       | 55 +++++++++++++++++++
 ...itTest.h => AdjustMinimizerStrategyTest.h} | 17 +++---
 Tests/Functional/Fit/ExperimentalFitTest.cpp  | 34 ------------
 Tests/Functional/Fit/FitParameterPlan.cpp     | 22 +++++---
 Tests/Functional/Fit/FitParameterPlan.h       |  5 +-
 Tests/Functional/Fit/IMinimizerTest.cpp       | 50 ++++++++++-------
 Tests/Functional/Fit/IMinimizerTest.h         | 14 +----
 .../Functional/Fit/ObjectiveFunctionPlan.cpp  |  3 +-
 Tests/Functional/Fit/StandardFitsFactory.cpp  |  8 +--
 9 files changed, 121 insertions(+), 87 deletions(-)
 create mode 100644 Tests/Functional/Fit/AdjustMinimizerStrategyTest.cpp
 rename Tests/Functional/Fit/{ExperimentalFitTest.h => AdjustMinimizerStrategyTest.h} (61%)
 delete mode 100644 Tests/Functional/Fit/ExperimentalFitTest.cpp

diff --git a/Tests/Functional/Fit/AdjustMinimizerStrategyTest.cpp b/Tests/Functional/Fit/AdjustMinimizerStrategyTest.cpp
new file mode 100644
index 00000000000..1cc7b8e39ce
--- /dev/null
+++ b/Tests/Functional/Fit/AdjustMinimizerStrategyTest.cpp
@@ -0,0 +1,55 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Tests/Functional/Fit/AdjustMinimizerStrategyTest.cpp
+//! @brief     Implements class AdjustMinimizerStrategyTest.
+//!
+//! @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 "AdjustMinimizerStrategyTest.h"
+#include "Units.h"
+#include "FitSuite.h"
+#include "MinimizerFactory.h"
+#include "FitStrategyAdjustMinimizer.h"
+#include "MinimizerConstants.h"
+
+
+AdjustMinimizerStrategyTest::AdjustMinimizerStrategyTest()
+    : IMinimizerTest("undefined", "undefined")
+{}
+
+void AdjustMinimizerStrategyTest::initParameterPlan()
+{
+    m_parameters.clear();
+    m_parameters.push_back(FitParameterPlan("*Height", 1.0 * Units::nanometer,
+                                            5.0 * Units::nanometer,
+                                            AttLimits::limited(0.01, 30.0), 0.05));
+    m_parameters.push_back(FitParameterPlan("*Radius", 20.0 * Units::nanometer,
+                                            5.0 * Units::nanometer,
+                                            AttLimits::limited(0.01, 30.0), 0.05));
+
+}
+
+std::unique_ptr<FitSuite> AdjustMinimizerStrategyTest::createFitSuite() {
+  std::unique_ptr<FitSuite> result(new FitSuite());
+  result->initPrint(10);
+
+  result->addFitStrategy(FitStrategyAdjustMinimizer(
+      MinimizerNames::Genetic, std::string(), "MaxIterations=2;"));
+
+  result->addFitStrategy(FitStrategyAdjustMinimizer(MinimizerNames::Minuit2,
+                                                    AlgorithmNames::Migrad));
+
+  for (size_t i = 0; i < m_parameters.size(); ++i)
+    result->addFitParameter(m_parameters[i].m_name,
+                            m_parameters[i].m_start_value,
+                            m_parameters[i].m_limits, m_parameters[i].m_step);
+  return result;
+}
diff --git a/Tests/Functional/Fit/ExperimentalFitTest.h b/Tests/Functional/Fit/AdjustMinimizerStrategyTest.h
similarity index 61%
rename from Tests/Functional/Fit/ExperimentalFitTest.h
rename to Tests/Functional/Fit/AdjustMinimizerStrategyTest.h
index 5df4e31ee00..a961dc31b2e 100644
--- a/Tests/Functional/Fit/ExperimentalFitTest.h
+++ b/Tests/Functional/Fit/AdjustMinimizerStrategyTest.h
@@ -2,8 +2,8 @@
 //
 //  BornAgain: simulate and fit scattering at grazing incidence
 //
-//! @file      Tests/Functional/Fit/ExperimentalFitTest.h
-//! @brief     Declares class ExperimentalFitTest.
+//! @file      Tests/Functional/Fit/MinimizerStrategyTest.h
+//! @brief     Declares class MinimizerStrategyTest.
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -18,18 +18,19 @@
 
 #include "IMinimizerTest.h"
 
-//! @class ExperimentalFitTest
+//! @class MinimizerStrategyTest
 //! @ingroup standard_samples
-//! @brief Experimental test on the way to refactored minimizers
+//! @brief The MinimizerStrategyTest verifies fitting with the chain of minimizers.
 
-class ExperimentalFitTest : public IMinimizerTest
+class AdjustMinimizerStrategyTest : public IMinimizerTest
 {
 public:
-    ExperimentalFitTest();
+    AdjustMinimizerStrategyTest();
 
 protected:
-    virtual std::unique_ptr<FitSuite> createFitSuite();
+    void initParameterPlan() override;
+    std::unique_ptr<FitSuite> createFitSuite() override;
 
 };
 
-#endif // EXPERIMENTALFITTEST_H
+#endif
diff --git a/Tests/Functional/Fit/ExperimentalFitTest.cpp b/Tests/Functional/Fit/ExperimentalFitTest.cpp
deleted file mode 100644
index bceb8e90d6f..00000000000
--- a/Tests/Functional/Fit/ExperimentalFitTest.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// ************************************************************************** //
-//
-//  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 "Minuit2Minimizer.h"
-#include "FitSuite.h"
-
-ExperimentalFitTest::ExperimentalFitTest()
-    : IMinimizerTest("Minuit2", "Migrad")
-{}
-
-std::unique_ptr<FitSuite> ExperimentalFitTest::createFitSuite()
-{
-    std::unique_ptr<FitSuite> result(new FitSuite());
-    result->initPrint(10);
-    result->setMinimizer( new Minuit2Minimizer() );
-    for (const auto& par: m_parameters)
-        result->addFitParameter(
-            par.m_name, par.m_start_value,
-            AttLimits::lowerLimited(0.01), par.m_start_value/100.);
-    return result;
-}
diff --git a/Tests/Functional/Fit/FitParameterPlan.cpp b/Tests/Functional/Fit/FitParameterPlan.cpp
index e7c08b08ac4..0f2c8a79a2b 100644
--- a/Tests/Functional/Fit/FitParameterPlan.cpp
+++ b/Tests/Functional/Fit/FitParameterPlan.cpp
@@ -15,9 +15,22 @@
 
 #include "FitParameterPlan.h"
 
-FitParameterPlan::FitParameterPlan(double start_value, double expected_value,
+FitParameterPlan::FitParameterPlan()
+    : m_name(std::string())
+    , m_start_value(0.0)
+    , m_expected_value(0.0)
+    , m_limits(AttLimits::limitless())
+    , m_step(0.0)
+    , m_threshold(0.0)
+{
+
+}
+
+FitParameterPlan::FitParameterPlan(const std::string &name, double start_value,
+                                   double expected_value,
                                    const AttLimits &limits, double step)
-    : m_start_value(start_value)
+    : m_name(name)
+    , m_start_value(start_value)
     , m_expected_value(expected_value)
     , m_limits(limits)
     , m_step(step)
@@ -25,8 +38,3 @@ FitParameterPlan::FitParameterPlan(double start_value, double expected_value,
 {
 
 }
-
-FitParameterPlan::~FitParameterPlan()
-{
-
-}
diff --git a/Tests/Functional/Fit/FitParameterPlan.h b/Tests/Functional/Fit/FitParameterPlan.h
index d86c610f08c..9910206e28d 100644
--- a/Tests/Functional/Fit/FitParameterPlan.h
+++ b/Tests/Functional/Fit/FitParameterPlan.h
@@ -26,10 +26,11 @@
 class FitParameterPlan
 {
 public:
-    FitParameterPlan(double start_value, double expected_value,
+    FitParameterPlan();
+    FitParameterPlan(const std::string &name, double start_value, double expected_value,
                      const AttLimits &limits, double step);
-    ~FitParameterPlan();
 
+    std::string m_name;
     double m_start_value; //!< starting value of fit parameter
     double m_expected_value; //!< expected value to find in the fit
     AttLimits m_limits; //!< limits of fit parameter
diff --git a/Tests/Functional/Fit/IMinimizerTest.cpp b/Tests/Functional/Fit/IMinimizerTest.cpp
index 360173f724e..3d0b746cb1d 100644
--- a/Tests/Functional/Fit/IMinimizerTest.cpp
+++ b/Tests/Functional/Fit/IMinimizerTest.cpp
@@ -25,13 +25,13 @@
 #include <boost/format.hpp>
 #include <memory>
 
-IMinimizerTest::TestParameter::TestParameter(const std::string &name,
-                                             double real_value,
-                                             double start_value)
-    : m_name(name)
-    , m_real_value(real_value)
-    , m_start_value(start_value)
-    , m_found_value(0.0) {}
+//IMinimizerTest::TestParameter::TestParameter(const std::string &name,
+//                                             double real_value,
+//                                             double start_value)
+//    : m_name(name)
+//    , m_real_value(real_value)
+//    , m_start_value(start_value)
+//    , m_found_value(0.0) {}
 
 IMinimizerTest::IMinimizerTest(const std::string& minimizer_name,
                                const std::string& minimizer_algorithm)
@@ -41,18 +41,14 @@ IMinimizerTest::IMinimizerTest(const std::string& minimizer_name,
     , m_sample_builder_name("CylindersInBABuilder")
     , m_parameter_tolerance(0.01)
 {
-    m_parameters.push_back(
-        TestParameter("*Height", 5.0 * Units::nanometer, 4.5 * Units::nanometer));
-    m_parameters.push_back(
-        TestParameter("*Radius", 5.0 * Units::nanometer, 5.5 * Units::nanometer));
 }
 
 
 bool IMinimizerTest::runTest()
 {
+    initParameterPlan();
+
     std::unique_ptr<MultiLayer> sample(createSample());
-    for (size_t i = 0; i < m_parameters.size(); ++i)
-        sample->setParameterValue(m_parameters[i].m_name, m_parameters[i].m_real_value);
 
     std::unique_ptr<GISASSimulation> simulation(createSimulation());
     simulation->setSample(*sample.get());
@@ -67,34 +63,46 @@ bool IMinimizerTest::runTest()
     fitSuite->runFit();
 
     std::vector<double> valuesAtMinimum = fitSuite->fitParameters()->values();
-    for (size_t i = 0; i < m_parameters.size(); ++i)
-        m_parameters[i].m_found_value = valuesAtMinimum[i];
 
     // analyze results
     bool success = true;
     for (size_t i = 0; i < m_parameters.size(); ++i) {
-        double diff = std::abs(m_parameters[i].m_found_value - m_parameters[i].m_real_value)
-                      / m_parameters[i].m_real_value;
+        double foundValue = valuesAtMinimum[i];
+        double diff = std::abs(foundValue - m_parameters[i].m_expected_value)
+                      / m_parameters[i].m_expected_value;
         if (diff > m_parameter_tolerance)
             success = false;
         std::cout << boost::format("%|12t| %-10s : %-6.4f (diff %6.4g) %s\n") %
-            m_parameters[i].m_name % m_parameters[i].m_found_value % diff %
+            m_parameters[i].m_name % foundValue % diff %
             (success ? "OK" : "FAILED");
     }
     return success;
 }
 
+//! Creates plan with initial/real values of fit parameters.
+
+void IMinimizerTest::initParameterPlan() {
+  m_parameters.clear();
+  m_parameters.push_back(FitParameterPlan("*Height", 4.5 * Units::nanometer,
+                                          5.0 * Units::nanometer,
+                                          AttLimits::lowerLimited(0.01), 0.01));
+  m_parameters.push_back(FitParameterPlan("*Radius", 5.5 * Units::nanometer,
+                                          5.0 * Units::nanometer,
+                                          AttLimits::lowerLimited(0.01), 0.01));
+}
+
 std::unique_ptr<FitSuite> IMinimizerTest::createFitSuite()
 {
     std::unique_ptr<FitSuite> result(new FitSuite());
     result->initPrint(10);
     IMinimizer* minimizer = MinimizerFactory::createMinimizer(
-        m_minimizer_name, m_minimizer_algorithm);
+                m_minimizer_name, m_minimizer_algorithm);
     result->setMinimizer(minimizer);
+
     for (size_t i = 0; i < m_parameters.size(); ++i)
         result->addFitParameter(
             m_parameters[i].m_name, m_parameters[i].m_start_value,
-            AttLimits::lowerLimited(0.01), m_parameters[i].m_start_value / 100.);
+            m_parameters[i].m_limits, m_parameters[i].m_start_value / 100.);
     return result;
 }
 
@@ -102,6 +110,8 @@ std::unique_ptr<MultiLayer> IMinimizerTest::createSample()
 {
     SampleBuilderFactory builderFactory;
     std::unique_ptr<MultiLayer> result(builderFactory.createSample(m_sample_builder_name));
+    for (size_t i = 0; i < m_parameters.size(); ++i)
+        result->setParameterValue(m_parameters[i].m_name, m_parameters[i].m_expected_value);
     return result;
 }
 
diff --git a/Tests/Functional/Fit/IMinimizerTest.h b/Tests/Functional/Fit/IMinimizerTest.h
index 95ec49cb61a..af82f67f50f 100644
--- a/Tests/Functional/Fit/IMinimizerTest.h
+++ b/Tests/Functional/Fit/IMinimizerTest.h
@@ -18,6 +18,7 @@
 
 #include "IFunctionalTest.h"
 #include "OutputData.h"
+#include "FitParameterPlan.h"
 #include <memory>
 
 class FitSuite;
@@ -37,25 +38,16 @@ public:
 
     bool runTest() final;
 
-    class TestParameter
-    {
-    public:
-        TestParameter(const std::string &name, double real_value, double start_value);
-        std::string m_name;   //!< sample parameter name
-        double m_real_value;  //!< real value to construct the sample
-        double m_start_value; //!< starting value for the minimizer
-        double m_found_value; //!< the value found during the fit
-    };
-
     void setParameterTolerance(double value) { m_parameter_tolerance = value; }
 
 protected:
+    virtual void initParameterPlan();
     virtual std::unique_ptr<FitSuite> createFitSuite();
     virtual std::unique_ptr<MultiLayer> createSample();
     virtual std::unique_ptr<GISASSimulation> createSimulation();
     virtual std::unique_ptr<OutputData<double>> createOutputData(const GISASSimulation* simulation);
 
-    std::vector<TestParameter> m_parameters;
+    std::vector<FitParameterPlan> m_parameters;
     std::string m_minimizer_name;
     std::string m_minimizer_algorithm;
     std::string m_simulation_name;
diff --git a/Tests/Functional/Fit/ObjectiveFunctionPlan.cpp b/Tests/Functional/Fit/ObjectiveFunctionPlan.cpp
index d8b5f63609f..cccc0353028 100644
--- a/Tests/Functional/Fit/ObjectiveFunctionPlan.cpp
+++ b/Tests/Functional/Fit/ObjectiveFunctionPlan.cpp
@@ -29,7 +29,8 @@ ObjectiveFunctionPlan::ObjectiveFunctionPlan(const std::string &name, objective_
 void ObjectiveFunctionPlan::addParameter(double start_value, double expected_value,
                                          const AttLimits &limits, double step)
 {
-    m_parameters.push_back(FitParameterPlan(start_value, expected_value, limits, step));
+    std::string name = "par"+std::to_string(m_parameters.size());
+    m_parameters.push_back(FitParameterPlan(name, start_value, expected_value, limits, step));
 }
 
 //! Plan for finding rosenbrock function minimum
diff --git a/Tests/Functional/Fit/StandardFitsFactory.cpp b/Tests/Functional/Fit/StandardFitsFactory.cpp
index dabd05c54e8..d505c3a0303 100644
--- a/Tests/Functional/Fit/StandardFitsFactory.cpp
+++ b/Tests/Functional/Fit/StandardFitsFactory.cpp
@@ -16,7 +16,7 @@
 #include "StandardFitsFactory.h"
 #include "MinimizerTests.h"
 #include "RectDetectorFitTest.h"
-#include "ExperimentalFitTest.h"
+#include "AdjustMinimizerStrategyTest.h"
 #include "StandaloneFitTest.h"
 #include <boost/format.hpp>
 
@@ -63,9 +63,9 @@ StandardFitsFactory::StandardFitsFactory()
         "Fit of rectangular detector, with crop and masks applied");
 
     registerItem(
-        "ExperimentalFit",
-        create_new<ExperimentalFitTest>,
-        "Experimental fit on the way to refactoring");
+        "AdjustMinimizerStrategy",
+        create_new<AdjustMinimizerStrategyTest>,
+        "Test of minimizer chain: genetic -> minuit2");
 
     registerItem(
         "StandaloneFit",
-- 
GitLab