From e8c823e1d6a263bd622023165b5f8d8b0b7462cc Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Tue, 15 Oct 2013 17:42:44 +0200
Subject: [PATCH] Minimizer setting parts in User manual and corresponding
 refactoring (MinimizerOptions)

---
 App/src/TestFittingModule1.cpp                |   7 ++
 Core/Tools/src/SamplePrintVisitor.cpp         |   3 +-
 Doc/UserManual/Fitting.tex                    |  44 ++++----
 Doc/UserManual/SimulationExamples.tex         |   3 +-
 Doc/UserManual/SoftwareDesignOverview.tex     |   4 +-
 .../SampleParametersIntro.py                  |   4 +-
 .../FitCylindersPrisms.py                     |   7 ++
 Fit/CMakeLists.txt                            |   6 +-
 Fit/Factory/inc/IMinimizer.h                  |  29 ++++-
 Fit/Factory/inc/MinimizerOptions.h            |  62 +++++++++++
 Fit/Factory/inc/ROOTMinimizer.h               |  13 ++-
 Fit/Factory/src/MinimizerOptions.cpp          |  11 ++
 Fit/Factory/src/ROOTMinimizer.cpp             |  34 ++++--
 Fit/PythonAPI/inc/MinimizerOptions.pypp.h     |  11 ++
 Fit/PythonAPI/inc/PythonFitList.h             |   1 +
 Fit/PythonAPI/src/IMinimizer.pypp.cpp         |  47 ++++++++
 Fit/PythonAPI/src/MinimizerOptions.pypp.cpp   | 101 ++++++++++++++++++
 Fit/PythonAPI/src/PythonModule.cpp            |   2 +
 Fit/python_module.pri                         |   4 +-
 dev-tools/python-bindings/MakePyFit.py        |   1 +
 20 files changed, 354 insertions(+), 40 deletions(-)
 create mode 100644 Fit/Factory/inc/MinimizerOptions.h
 create mode 100644 Fit/Factory/src/MinimizerOptions.cpp
 create mode 100644 Fit/PythonAPI/inc/MinimizerOptions.pypp.h
 create mode 100644 Fit/PythonAPI/src/MinimizerOptions.pypp.cpp

diff --git a/App/src/TestFittingModule1.cpp b/App/src/TestFittingModule1.cpp
index 79f243d1974..e307d442757 100644
--- a/App/src/TestFittingModule1.cpp
+++ b/App/src/TestFittingModule1.cpp
@@ -33,6 +33,7 @@
 #include "ParticleDecoration.h"
 #include "ResolutionFunction2DSimple.h"
 #include "Units.h"
+#include "ROOTMinimizer.h"
 
 #include "TROOT.h"
 #include "TCanvas.h"
@@ -69,6 +70,12 @@ void TestFittingModule1::execute()
     m_fitSuite->addSimulationAndRealData(*mp_simulation, *mp_real_data);
 
     m_fitSuite->setMinimizer( MinimizerFactory::createMinimizer("Minuit2", "Migrad") );
+
+    //ROOTMinimizer *root_minimizer = dynamic_cast<ROOTMinimizer *>(m_fitSuite->getMinimizer());
+    //ROOT::Math::Minimizer *minim = root_minimizer->getROOTMinimizer();
+    //std::cout << " tolerance: " << minim->Tolerance() << " precision:" << minim->Precision() << std::endl;
+    //std::cout << " max_iterations: " << minim->MaxIterations() << " max_function_calls:" << minim->MaxFunctionCalls() << std::endl;
+
     //m_fitSuite->setMinimizer( MinimizerFactory::createMinimizer("Fumili") );
     //m_fitSuite->setMinimizer( MinimizerFactory::createMinimizer("Minuit2", "Fumili") );
     //m_fitSuite->setMinimizer( MinimizerFactory::createMinimizer("GSLMultiFit") ); // LMA
diff --git a/Core/Tools/src/SamplePrintVisitor.cpp b/Core/Tools/src/SamplePrintVisitor.cpp
index a4e93a54996..3111b0cb743 100644
--- a/Core/Tools/src/SamplePrintVisitor.cpp
+++ b/Core/Tools/src/SamplePrintVisitor.cpp
@@ -109,7 +109,8 @@ void SamplePrintVisitor::visit(const Particle *sample)
 {
     assert(sample);
     std::cout << get_indent() << "Particle " << sample->getName()
-              << " Index:" << sample->getRefractiveIndex()
+              << " " << (sample->getMaterial() ? sample->getMaterial()->getName() : "0_MATERIAL")
+              << " " << sample->getRefractiveIndex()
               << std::endl;
 
     goForward();
diff --git a/Doc/UserManual/Fitting.tex b/Doc/UserManual/Fitting.tex
index a01ffbbf455..b5e15a4ee17 100644
--- a/Doc/UserManual/Fitting.tex
+++ b/Doc/UserManual/Fitting.tex
@@ -146,8 +146,10 @@ is required to provide reduced and \textbf{normalized} data.
 \subsection{Minimizer settings.}
 
 \BornAgain\ contains a variety of minimization engines from \Code{ROOT} and \Code{GSL}
-libraries. By default \Code{Minuit2} minimizer with default settings will be used.
-The remainder of this section explains expert setting which can be applied to get better 
+libraries. They are listed in Table~\ref{table:fit_minimizers}.
+By default \Code{Minuit2} minimizer with default settings will be used and no additional
+configuration needs to be done.
+The remainder of this section explains some of the expert setting which can be applied to get better 
 fit results.
 
 The default minimization algorithm can be changed using 
@@ -158,9 +160,9 @@ minimizer = MinimizerFactory.createMinimizer("<Minimizer name>","<algorithm>")
 fit_suite.setMinimizer(minimizer)
 \end{lstlisting}
 
-where \Code{<Minimizer
-name>} and \Code{<algorithm>} can be chosen from the first and
-second column of Table~\ref{table:fit_minimizers} respectively. The list of algorithms
+where \Code{<Minimizer name>} and \Code{<algorithm>} can be chosen from the first and
+second column of Table~\ref{table:fit_minimizers} respectively. 
+The list of algorithms
 can also be obtained using \Code{MinimizerFactory.printCatalogue()} command.
 
 
@@ -221,25 +223,27 @@ Algorithm\\
 \label{table:fit_minimizers}
 \end{table}
 
+There are several options common for every minimization algorithms, which can be changed
+before minimization starts. They are handled by \Code{MinimizerOptions} class:
+\begin{lstlisting}[language=python, style=eclipseboxed, numbers = none]
+options = MinimizerOptions()
+options.setMaxFunctionCall(10)
+FitSuite().getMinimizer().setOptions()
+\end{lstlisting}
+In given code snippet a number of ``maximum function calls'', namely a number of times the minimizer is allowed to call the simulation, is limited to the 10. The minimizer will take that number into consideration and will try to limit number of iterations by that value.
 
-Every minimization algorithm have a number of setting which is set by default to the most
-
-which can be changed to tune minimization
-flow and achieve best results. 
-
-They will be explained elsewhere.
-
-
-
-
-
-
+There is also a number of expert level options common for all minimizers as well
+as a number of possibilities to tune individual minimization algorithms.
+They will be explained in \SecRef{AdvancedFitting}.
 
 
 
 \input{FittingExamples}
 
-\section {How to get right answer from \BornAgain\ fitting.}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section {How to get right answer from \BornAgain\ fitting.} \SecLabel{HowToGetRightAnswer}
 
 \begin{itemize}
 \item It is recommended to start from default minimizer settings and turn to the fine tunings
@@ -247,6 +251,10 @@ only after some experience has been acquired.
 
 \end{itemize}
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section {Advanced fitting.} \SecLabel{AdvancedFitting}
 
 
 
diff --git a/Doc/UserManual/SimulationExamples.tex b/Doc/UserManual/SimulationExamples.tex
index fcba8d8c8b1..e85a9c03d09 100644
--- a/Doc/UserManual/SimulationExamples.tex
+++ b/Doc/UserManual/SimulationExamples.tex
@@ -300,7 +300,8 @@ and we will briefly explain it using example from the previous
 
 Inside \BornAgain\ sample is described by a hierarchical tree of objects.
 For the multilayer created in previous section this tree can be graphically
-represented as shown in Fig.~\ref{fig:sample_tree}. 
+represented as shown in Fig.~\ref{fig:sample_tree}. Similar tree can be printed in Python
+session by running \Code{multi\_layer.printSampleTree()}
 
 \begin{figure}[p!]
 
diff --git a/Doc/UserManual/SoftwareDesignOverview.tex b/Doc/UserManual/SoftwareDesignOverview.tex
index 78ea2611151..ac33eb54954 100644
--- a/Doc/UserManual/SoftwareDesignOverview.tex
+++ b/Doc/UserManual/SoftwareDesignOverview.tex
@@ -96,7 +96,9 @@ This interface and two of its subclasses are sketched in \reffig{isample}.
 
 
 
-\subsection{The FitSuite class hierarchy} \SecLabel{FitSuiteClass}
+\subsection{The FitSuite class.} \SecLabel{FitSuiteClass}
 
+\subsection{The IMinimizer class.} \SecLabel{IMinimizerClass}
 
+\subsection{The MinimizerOptions class.} \SecLabel{MinimizerOptionsClass}
 
diff --git a/Examples/python/fitting/ex001_SampleParametersIntro/SampleParametersIntro.py b/Examples/python/fitting/ex001_SampleParametersIntro/SampleParametersIntro.py
index 0d9780bc909..f2619507de9 100644
--- a/Examples/python/fitting/ex001_SampleParametersIntro/SampleParametersIntro.py
+++ b/Examples/python/fitting/ex001_SampleParametersIntro/SampleParametersIntro.py
@@ -55,9 +55,11 @@ def run_simulations():
     """
 
     sample = get_sample()
+    print "The tree structure of the sample"
+    sample.printSampleTree()
+
     print "The sample contains following parameters ('name':value)"
     sample.printParameters()
-    sample.printSampleTree()
 
     simulation = get_simulation()
 
diff --git a/Examples/python/fitting/ex002_FitCylindersAndPrisms/FitCylindersPrisms.py b/Examples/python/fitting/ex002_FitCylindersAndPrisms/FitCylindersPrisms.py
index 585d8540c4c..f9fe9e9a90c 100644
--- a/Examples/python/fitting/ex002_FitCylindersAndPrisms/FitCylindersPrisms.py
+++ b/Examples/python/fitting/ex002_FitCylindersAndPrisms/FitCylindersPrisms.py
@@ -137,6 +137,13 @@ def run_fitting():
 
     MinimizerFactory.printCatalogue()
 
+    options = MinimizerOptions()
+    
+    options.setMaxFunctionCalls(5)
+    fitSuite.getMinimizer().setOptions(options)
+
+    print options.getTolerance(), options.getMaxIterations()
+
     # setting fitting minimizer
     #fitSuite.setMinimizer(MinimizerFactory.createMinimizer("Minuit2","Migrad")) #: Minuit2, Migrad
     #fitSuite.setMinimizer(MinimizerFactory.createMinimizer ("Minuit2","Simplex"))
diff --git a/Fit/CMakeLists.txt b/Fit/CMakeLists.txt
index 2965bd37a7a..7c1ccf45239 100644
--- a/Fit/CMakeLists.txt
+++ b/Fit/CMakeLists.txt
@@ -19,8 +19,10 @@ file(GLOB include_files
 )
 
 if(BORNAGAIN_PYTHON)
-    file(GLOB pythonapi "PythonAPI/src/*.cpp")
-    list(APPEND source_files ${pythonapi})
+    file(GLOB source_pythonapi "PythonAPI/src/*.cpp")
+    list(APPEND source_files ${source_pythonapi})
+    file(GLOB include_pythonapi "PythonAPI/inc/*.h")
+    list(APPEND include_files ${include_pythonapi})
     include_directories(
         ${CMAKE_CURRENT_SOURCE_DIR}/PythonAPI/inc
     )
diff --git a/Fit/Factory/inc/IMinimizer.h b/Fit/Factory/inc/IMinimizer.h
index c971198b4f7..34708ea1c69 100644
--- a/Fit/Factory/inc/IMinimizer.h
+++ b/Fit/Factory/inc/IMinimizer.h
@@ -21,6 +21,7 @@
 #include <boost/function.hpp>
 #include "Exceptions.h"
 #include <vector>
+#include "MinimizerOptions.h"
 
 class FitParameter;
 class FitSuiteParameters;
@@ -75,11 +76,19 @@ class BA_CORE_API_ IMinimizer
     //! Prints fit results
     virtual void printResults() const;
 
-    //! Sets minimizer option
-    virtual void setOptions(const std::string& option);
 
     //! Returns number of calls of minimized function
     virtual size_t getNCalls() const;
+
+    //! return minimizer options
+    virtual MinimizerOptions getOptions() const;
+
+    //! set minimizer options
+    virtual void setOptions(const MinimizerOptions &options);
+
+    //! set minimizer option string
+    virtual void setOptions(const std::string& options);
+
 };
 
 inline void IMinimizer::setParameter(size_t /*index*/, const FitParameter* /*par*/)
@@ -137,14 +146,24 @@ inline void IMinimizer::printResults() const
     throw NotImplementedException("IMinimizer::printResults() -> Not implemented.");
 }
 
-inline void IMinimizer::setOptions(const std::string& /*options*/)
+inline size_t IMinimizer::getNCalls() const
+{
+    throw NotImplementedException("IMinimizer::getNCalls() -> Not implemented.");
+}
+
+inline MinimizerOptions IMinimizer::getOptions() const
+{
+    throw NotImplementedException("IMinimizer::getOptions() -> Not implemented.");
+}
+
+inline void IMinimizer::setOptions(const MinimizerOptions &/*options*/)
 {
     throw NotImplementedException("IMinimizer::setOptions() -> Not implemented.");
 }
 
-inline size_t IMinimizer::getNCalls() const
+inline void IMinimizer::setOptions(const std::string &/*options*/)
 {
-    throw NotImplementedException("IMinimizer::getNCalls() -> Not implemented.");
+    throw NotImplementedException("IMinimizer::setOptions() -> Not implemented.");
 }
 
 #endif // IMINIMIZER_H
diff --git a/Fit/Factory/inc/MinimizerOptions.h b/Fit/Factory/inc/MinimizerOptions.h
new file mode 100644
index 00000000000..1c4b6455216
--- /dev/null
+++ b/Fit/Factory/inc/MinimizerOptions.h
@@ -0,0 +1,62 @@
+#ifndef MINIMIZEROPTIONS_H
+#define MINIMIZEROPTIONS_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.                   *
+// ********************************************************************
+#include "WinDllMacros.h"
+
+//! The MinimizerOptions class contains options for minimization algorithms
+
+class BA_CORE_API_ MinimizerOptions
+{
+public:
+    MinimizerOptions();
+    virtual ~MinimizerOptions(){}
+
+    //! return minimizer tolerance
+    double getTolerance() const { return m_tolerance; }
+    //! set minimizer tolerance
+    void setTolerance(double tolerance) { m_tolerance = tolerance; }
+
+    //! return minimizer precision
+    double getPrecision() const { return m_precision; }
+    //! set minimizer precision
+    void setPrecision(double precision) { m_precision = precision; }
+
+    //! return maximum number of allowed iterations
+    int getMaxIterations() const { return m_max_iterations; }
+    //! set maximum number of allowed iterations
+    void setMaxIterations(int max_iterations) { m_max_iterations = max_iterations; }
+
+    //! return maximum number of allowed function calls
+    int getMaxFunctionCalls() const { return m_max_function_calls; }
+    //! set maximum number of allowed function calls
+    void setMaxFunctionCalls(int max_function_calls) { m_max_function_calls = max_function_calls; }
+
+private:
+    double m_tolerance; //!< Tolerance on the function value at the minimum.
+    //!< the default tolerance value is 0.01 and the minimization will stop
+    //!< when the estimated vertical distance to the minimum (EDM) is less
+    //! than 0.001*m_tolerance*up. Here up=1 for chi squared fit and up=0.5
+    //! for negative log likelihood fit
+
+    double m_precision; //!< Relative floating point arithmetic precision.
+    //!< Should be adjusted when the user knows that FCN function value is not
+    //!< calculated to the nominal machine accuracy. Typical values are
+    //!< between 10^-5 and 10^-14. If the value is equal to -1 then minimizer
+    //!< specific will be used
+
+    int m_max_iterations; //!< Max number of iterations.
+
+    int m_max_function_calls; //!< Max number of function calls.
+
+};
+
+
+#endif // MINIMIZEROPTIONS_H
diff --git a/Fit/Factory/inc/ROOTMinimizer.h b/Fit/Factory/inc/ROOTMinimizer.h
index a284ee6e654..7359420fff7 100644
--- a/Fit/Factory/inc/ROOTMinimizer.h
+++ b/Fit/Factory/inc/ROOTMinimizer.h
@@ -61,15 +61,22 @@ class ROOTMinimizer : public IMinimizer
 
     virtual void clear() { m_root_minimizer->Clear(); }
 
-    virtual void setOptions(const std::string& options);
-
     virtual size_t getNCalls() const;
 
+    //! return minimizer options
+    virtual MinimizerOptions getOptions() const;
+
+    //! set minimizer options
+    virtual void setOptions(const MinimizerOptions &options);
+
+    //! set minimizer option string
+    virtual void setOptions(const std::string& options);
+
     //! Returns created minimizer
     ROOT::Math::Minimizer *getROOTMinimizer() { return m_root_minimizer; }
 
     //! Checks if type of algorithm is Levenberg-Marquardt or similar
-    bool isGradientBasedAgorithm();
+    bool isGradientBasedAgorithm();    
 
  private:
     ROOTMinimizer(const ROOTMinimizer& );
diff --git a/Fit/Factory/src/MinimizerOptions.cpp b/Fit/Factory/src/MinimizerOptions.cpp
new file mode 100644
index 00000000000..6d6d816baee
--- /dev/null
+++ b/Fit/Factory/src/MinimizerOptions.cpp
@@ -0,0 +1,11 @@
+#include "MinimizerOptions.h"
+
+
+MinimizerOptions::MinimizerOptions()
+    : m_tolerance(0.01)
+    , m_precision(-1)
+    , m_max_iterations(0)
+    , m_max_function_calls(0)
+{
+
+}
diff --git a/Fit/Factory/src/ROOTMinimizer.cpp b/Fit/Factory/src/ROOTMinimizer.cpp
index fd4fd06667a..a0d7167a102 100644
--- a/Fit/Factory/src/ROOTMinimizer.cpp
+++ b/Fit/Factory/src/ROOTMinimizer.cpp
@@ -10,6 +10,7 @@
 #include "ROOTGSLNLSMinimizer.h"
 #include "ROOTGSLSimAnMinimizer.h"
 #include "ROOTMinimizerHelper.h"
+#include "MinimizerOptions.h"
 
 
 // ----------------------------------------------------------------------------
@@ -38,8 +39,6 @@ ROOTMinimizer::ROOTMinimizer(const std::string& minimizer_name, const std::strin
     if(!m_root_minimizer) {
         throw LogicErrorException("Can't create minimizer with name '"+minimizer_name+"', algo '" + algo_type+"'");
     }
-    m_root_minimizer->SetMaxIterations(10000);
-    m_root_minimizer->SetMaxFunctionCalls(10000);
 }
 
 
@@ -147,14 +146,35 @@ void ROOTMinimizer::printResults() const
 }
 
 
-void ROOTMinimizer::setOptions(const std::string& options)
+size_t ROOTMinimizer::getNCalls() const
 {
-    // TODO: refactor ROOTMinimizerHelper::setOptions
-    ROOTMinimizerHelper::setOptions(m_root_minimizer, options);
+    return m_root_minimizer->NCalls();
 }
 
-size_t ROOTMinimizer::getNCalls() const
+
+MinimizerOptions ROOTMinimizer::getOptions() const
 {
-    return m_root_minimizer->NCalls();
+    MinimizerOptions options;
+    options.setTolerance(m_root_minimizer->Tolerance());
+    options.setPrecision(m_root_minimizer->Precision());
+    options.setMaxFunctionCalls(m_root_minimizer->MaxFunctionCalls());
+    options.setMaxIterations(m_root_minimizer->MaxIterations());
+    return options;
+}
+
+void ROOTMinimizer::setOptions(const MinimizerOptions &options)
+{
+    m_root_minimizer->SetTolerance(options.getTolerance());
+    m_root_minimizer->SetPrecision(options.getPrecision());
+    m_root_minimizer->SetMaxFunctionCalls(options.getMaxFunctionCalls());
+    m_root_minimizer->SetMaxIterations(options.getMaxIterations());
 }
 
+void ROOTMinimizer::setOptions(const std::string& options)
+{
+    ROOTMinimizerHelper::setOptions(m_root_minimizer, options);
+}
+
+
+
+
diff --git a/Fit/PythonAPI/inc/MinimizerOptions.pypp.h b/Fit/PythonAPI/inc/MinimizerOptions.pypp.h
new file mode 100644
index 00000000000..d377a84be5c
--- /dev/null
+++ b/Fit/PythonAPI/inc/MinimizerOptions.pypp.h
@@ -0,0 +1,11 @@
+// This file has been generated by Py++.
+
+// BornAgain: simulate and fit scattering at grazing incidence 
+//! @brief automatically generated boost::python code for PythonCoreAPI  
+
+#ifndef MinimizerOptions_hpp__pyplusplus_wrapper
+#define MinimizerOptions_hpp__pyplusplus_wrapper
+
+void register_MinimizerOptions_class();
+
+#endif//MinimizerOptions_hpp__pyplusplus_wrapper
diff --git a/Fit/PythonAPI/inc/PythonFitList.h b/Fit/PythonAPI/inc/PythonFitList.h
index 687ac7b6c97..119ab055625 100644
--- a/Fit/PythonAPI/inc/PythonFitList.h
+++ b/Fit/PythonAPI/inc/PythonFitList.h
@@ -12,6 +12,7 @@
 #include "FitSuiteParameters.h"
 #include "MinimizerFactory.h"
 #include "MathFunctions.h"
+#include "MinimizerOptions.h"
 #include "ISquaredFunction.h"
 #include "IOutputDataNormalizer.h"
 
diff --git a/Fit/PythonAPI/src/IMinimizer.pypp.cpp b/Fit/PythonAPI/src/IMinimizer.pypp.cpp
index dd5847e04e1..43dda64bd50 100644
--- a/Fit/PythonAPI/src/IMinimizer.pypp.cpp
+++ b/Fit/PythonAPI/src/IMinimizer.pypp.cpp
@@ -83,6 +83,18 @@ struct IMinimizer_wrapper : IMinimizer, bp::wrapper< IMinimizer > {
         return IMinimizer::getNumberOfVariables( );
     }
 
+    virtual ::MinimizerOptions getOptions(  ) const  {
+        if( bp::override func_getOptions = this->get_override( "getOptions" ) )
+            return func_getOptions(  );
+        else
+            return this->IMinimizer::getOptions(  );
+    }
+    
+    
+    ::MinimizerOptions default_getOptions(  ) const  {
+        return IMinimizer::getOptions( );
+    }
+
     virtual double getValueOfVariableAtMinimum( ::std::size_t arg0 ) const  {
         if( bp::override func_getValueOfVariableAtMinimum = this->get_override( "getValueOfVariableAtMinimum" ) )
             return func_getValueOfVariableAtMinimum( arg0 );
@@ -124,6 +136,18 @@ struct IMinimizer_wrapper : IMinimizer, bp::wrapper< IMinimizer > {
         IMinimizer::printResults( );
     }
 
+    virtual void setOptions( ::MinimizerOptions const & arg0 ) {
+        if( bp::override func_setOptions = this->get_override( "setOptions" ) )
+            func_setOptions( boost::ref(arg0) );
+        else
+            this->IMinimizer::setOptions( boost::ref(arg0) );
+    }
+    
+    
+    void default_setOptions( ::MinimizerOptions const & arg0 ) {
+        IMinimizer::setOptions( boost::ref(arg0) );
+    }
+
     virtual void setOptions( ::std::string const & arg0 ) {
         if( bp::override func_setOptions = this->get_override( "setOptions" ) )
             func_setOptions( arg0 );
@@ -211,6 +235,17 @@ void register_IMinimizer_class(){
                 , getNumberOfVariables_function_type(&::IMinimizer::getNumberOfVariables)
                 , default_getNumberOfVariables_function_type(&IMinimizer_wrapper::default_getNumberOfVariables) );
         
+        }
+        { //::IMinimizer::getOptions
+        
+            typedef ::MinimizerOptions ( ::IMinimizer::*getOptions_function_type )(  ) const;
+            typedef ::MinimizerOptions ( IMinimizer_wrapper::*default_getOptions_function_type )(  ) const;
+            
+            IMinimizer_exposer.def( 
+                "getOptions"
+                , getOptions_function_type(&::IMinimizer::getOptions)
+                , default_getOptions_function_type(&IMinimizer_wrapper::default_getOptions) );
+        
         }
         { //::IMinimizer::getValueOfVariableAtMinimum
         
@@ -254,6 +289,18 @@ void register_IMinimizer_class(){
                 , printResults_function_type(&::IMinimizer::printResults)
                 , default_printResults_function_type(&IMinimizer_wrapper::default_printResults) );
         
+        }
+        { //::IMinimizer::setOptions
+        
+            typedef void ( ::IMinimizer::*setOptions_function_type )( ::MinimizerOptions const & ) ;
+            typedef void ( IMinimizer_wrapper::*default_setOptions_function_type )( ::MinimizerOptions const & ) ;
+            
+            IMinimizer_exposer.def( 
+                "setOptions"
+                , setOptions_function_type(&::IMinimizer::setOptions)
+                , default_setOptions_function_type(&IMinimizer_wrapper::default_setOptions)
+                , ( bp::arg("arg0") ) );
+        
         }
         { //::IMinimizer::setOptions
         
diff --git a/Fit/PythonAPI/src/MinimizerOptions.pypp.cpp b/Fit/PythonAPI/src/MinimizerOptions.pypp.cpp
new file mode 100644
index 00000000000..40c2e5b47b3
--- /dev/null
+++ b/Fit/PythonAPI/src/MinimizerOptions.pypp.cpp
@@ -0,0 +1,101 @@
+// This file has been generated by Py++.
+
+// BornAgain: simulate and fit scattering at grazing incidence 
+//! @brief automatically generated boost::python code for PythonCoreAPI  
+
+#include "Macros.h"
+GCC_DIAG_OFF(unused-parameter);
+GCC_DIAG_OFF(missing-field-initializers);
+#include "boost/python.hpp"
+GCC_DIAG_ON(unused-parameter);
+GCC_DIAG_ON(missing-field-initializers);
+#include "PythonFitList.h"
+#include "MinimizerOptions.pypp.h"
+
+namespace bp = boost::python;
+
+void register_MinimizerOptions_class(){
+
+    { //::MinimizerOptions
+        typedef bp::class_< MinimizerOptions > MinimizerOptions_exposer_t;
+        MinimizerOptions_exposer_t MinimizerOptions_exposer = MinimizerOptions_exposer_t( "MinimizerOptions", bp::init< >() );
+        bp::scope MinimizerOptions_scope( MinimizerOptions_exposer );
+        { //::MinimizerOptions::getMaxFunctionCalls
+        
+            typedef int ( ::MinimizerOptions::*getMaxFunctionCalls_function_type )(  ) const;
+            
+            MinimizerOptions_exposer.def( 
+                "getMaxFunctionCalls"
+                , getMaxFunctionCalls_function_type( &::MinimizerOptions::getMaxFunctionCalls ) );
+        
+        }
+        { //::MinimizerOptions::getMaxIterations
+        
+            typedef int ( ::MinimizerOptions::*getMaxIterations_function_type )(  ) const;
+            
+            MinimizerOptions_exposer.def( 
+                "getMaxIterations"
+                , getMaxIterations_function_type( &::MinimizerOptions::getMaxIterations ) );
+        
+        }
+        { //::MinimizerOptions::getPrecision
+        
+            typedef double ( ::MinimizerOptions::*getPrecision_function_type )(  ) const;
+            
+            MinimizerOptions_exposer.def( 
+                "getPrecision"
+                , getPrecision_function_type( &::MinimizerOptions::getPrecision ) );
+        
+        }
+        { //::MinimizerOptions::getTolerance
+        
+            typedef double ( ::MinimizerOptions::*getTolerance_function_type )(  ) const;
+            
+            MinimizerOptions_exposer.def( 
+                "getTolerance"
+                , getTolerance_function_type( &::MinimizerOptions::getTolerance ) );
+        
+        }
+        { //::MinimizerOptions::setMaxFunctionCalls
+        
+            typedef void ( ::MinimizerOptions::*setMaxFunctionCalls_function_type )( int ) ;
+            
+            MinimizerOptions_exposer.def( 
+                "setMaxFunctionCalls"
+                , setMaxFunctionCalls_function_type( &::MinimizerOptions::setMaxFunctionCalls )
+                , ( bp::arg("max_function_calls") ) );
+        
+        }
+        { //::MinimizerOptions::setMaxIterations
+        
+            typedef void ( ::MinimizerOptions::*setMaxIterations_function_type )( int ) ;
+            
+            MinimizerOptions_exposer.def( 
+                "setMaxIterations"
+                , setMaxIterations_function_type( &::MinimizerOptions::setMaxIterations )
+                , ( bp::arg("max_iterations") ) );
+        
+        }
+        { //::MinimizerOptions::setPrecision
+        
+            typedef void ( ::MinimizerOptions::*setPrecision_function_type )( double ) ;
+            
+            MinimizerOptions_exposer.def( 
+                "setPrecision"
+                , setPrecision_function_type( &::MinimizerOptions::setPrecision )
+                , ( bp::arg("precision") ) );
+        
+        }
+        { //::MinimizerOptions::setTolerance
+        
+            typedef void ( ::MinimizerOptions::*setTolerance_function_type )( double ) ;
+            
+            MinimizerOptions_exposer.def( 
+                "setTolerance"
+                , setTolerance_function_type( &::MinimizerOptions::setTolerance )
+                , ( bp::arg("tolerance") ) );
+        
+        }
+    }
+
+}
diff --git a/Fit/PythonAPI/src/PythonModule.cpp b/Fit/PythonAPI/src/PythonModule.cpp
index f91603a5761..fe0a2c4b7b3 100644
--- a/Fit/PythonAPI/src/PythonModule.cpp
+++ b/Fit/PythonAPI/src/PythonModule.cpp
@@ -11,6 +11,7 @@ GCC_DIAG_ON(missing-field-initializers);
 #include "ISquaredFunction.pypp.h" 
 #include "MinimizerFactory.pypp.h" 
 #include "OutputDataNormalizer.pypp.h" 
+#include "MinimizerOptions.pypp.h" 
 #include "SquaredFunctionWithSystematicError.pypp.h" 
 #include "IOutputDataNormalizer.pypp.h" 
 #include "SquaredFunctionWhichOnlyWorks.pypp.h" 
@@ -33,6 +34,7 @@ BOOST_PYTHON_MODULE(libBornAgainFit){
     register_IOutputDataNormalizer_class();
     register_ISquaredFunction_class();
     register_MinimizerFactory_class();
+    register_MinimizerOptions_class();
     register_OutputDataNormalizer_class();
     register_OutputDataSimpleNormalizer_class();
     register_SquaredFunctionDefault_class();
diff --git a/Fit/python_module.pri b/Fit/python_module.pri
index c6699b4472f..eefb2ee68a4 100644
--- a/Fit/python_module.pri
+++ b/Fit/python_module.pri
@@ -6,6 +6,7 @@ HEADERS +=  \
     PythonAPI/inc/ISquaredFunction.pypp.h \
     PythonAPI/inc/MinimizerFactory.pypp.h \
     PythonAPI/inc/OutputDataNormalizer.pypp.h \
+    PythonAPI/inc/MinimizerOptions.pypp.h \
     PythonAPI/inc/SquaredFunctionWithSystematicError.pypp.h \
     PythonAPI/inc/IOutputDataNormalizer.pypp.h \
     PythonAPI/inc/SquaredFunctionWhichOnlyWorks.pypp.h \
@@ -33,7 +34,8 @@ SOURCES +=  \
     PythonAPI/src/MinimizerFactory.pypp.cpp \
     PythonAPI/src/ISquaredFunction.pypp.cpp \
     PythonAPI/src/IOutputDataNormalizer.pypp.cpp \
-    PythonAPI/src/FitSuiteParameters.pypp.cpp 
+    PythonAPI/src/FitSuiteParameters.pypp.cpp \
+    PythonAPI/src/MinimizerOptions.pypp.cpp 
 
 INCLUDEPATH += ./PythonAPI/inc 
 DEPENDPATH  += ./PythonAPI/inc 
diff --git a/dev-tools/python-bindings/MakePyFit.py b/dev-tools/python-bindings/MakePyFit.py
index 76c46ca9d68..cca1fe11df2 100644
--- a/dev-tools/python-bindings/MakePyFit.py
+++ b/dev-tools/python-bindings/MakePyFit.py
@@ -40,6 +40,7 @@ include_classes = [
 "IOutputDataNormalizer",
 "ISquaredFunction",
 "MinimizerFactory",
+"MinimizerOptions",
 "OutputDataNormalizer",
 "OutputDataSimpleNormalizer",
 "SquaredFunctionDefault",
-- 
GitLab