1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file Fit/Suite/Minuit2Minimizer.cpp
//! @brief Declares class Minuit2Minimizer.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "Fit/Suite/Minuit2Minimizer.h"
#include "Fit/Tool/StringUtil.h"
#include <Minuit2/Minuit2Minimizer.h>
namespace {
std::map<int, std::string> statusDescription()
{
std::map<int, std::string> result;
result[0] = "OK, valid minimum";
result[1] = "Didn't converge, covariance was made pos defined";
result[2] = "Didn't converge, Hessian is invalid";
result[3] = "Didn't converge, Edm is above max";
result[4] = "Didn't converge, reached call limit";
result[5] = "Didn't converge, unknown failure";
return result;
}
std::map<int, std::string> covmatrixStatusDescription()
{
std::map<int, std::string> result;
result[-1] = "Not available (inversion failed or Hessian failed)";
result[0] = "Available but not positive defined";
result[1] = "Covariance only approximate";
result[2] = "Full matrix but forced pos def";
result[3] = "Full accurate";
return result;
}
} // namespace
Minuit2Minimizer::Minuit2Minimizer(const std::string& algorithmName)
: MinimizerAdapter(MinimizerInfo::buildMinuit2Info(algorithmName))
, m_minuit2_minimizer(new ROOT::Minuit2::Minuit2Minimizer(algorithmName.c_str()))
{
addOption("Strategy", 1, "Minimization strategy (0-low, 1-medium, 2-high quality)");
addOption("ErrorDef", 1.0, "Error definition factor for parameter error calculation");
addOption("Tolerance", 0.01, "Tolerance on the function value at the minimum");
addOption("Precision", -1.0, "Relative floating point arithmetic precision");
addOption("PrintLevel", 0, "Minimizer internal print level");
addOption("MaxFunctionCalls", 0, "Maximum number of function calls");
}
Minuit2Minimizer::~Minuit2Minimizer() = default;
void Minuit2Minimizer::setStrategy(int value)
{
setOptionValue("Strategy", value);
}
int Minuit2Minimizer::strategy() const
{
return optionValue<int>("Strategy");
}
void Minuit2Minimizer::setErrorDefinition(double value)
{
setOptionValue("ErrorDef", value);
}
double Minuit2Minimizer::errorDefinition() const
{
return optionValue<double>("ErrorDef");
}
void Minuit2Minimizer::setTolerance(double value)
{
setOptionValue("Tolerance", value);
}
double Minuit2Minimizer::tolerance() const
{
return optionValue<double>("Tolerance");
}
void Minuit2Minimizer::setPrecision(double value)
{
setOptionValue("Precision", value);
}
double Minuit2Minimizer::precision() const
{
return optionValue<double>("Precision");
}
void Minuit2Minimizer::setPrintLevel(int value)
{
setOptionValue("PrintLevel", value);
}
int Minuit2Minimizer::printLevel() const
{
return optionValue<int>("PrintLevel");
}
void Minuit2Minimizer::setMaxFunctionCalls(int value)
{
setOptionValue("MaxFunctionCalls", value);
}
int Minuit2Minimizer::maxFunctionCalls() const
{
return optionValue<int>("MaxFunctionCalls");
}
std::string Minuit2Minimizer::statusToString() const
{
return statusDescription()[rootMinimizer()->Status()];
}
std::map<std::string, std::string> Minuit2Minimizer::statusMap() const
{
auto result = MinimizerAdapter::statusMap();
result["Edm"] = mumufit::stringUtil::scientific(rootMinimizer()->Edm());
result["CovMatrixStatus"] = covmatrixStatusDescription()[rootMinimizer()->CovMatrixStatus()];
result["functionCalls"] = std::to_string(rootMinimizer()->NCalls());
return result;
}
// Fumili algorithm can work only with gradient based objective function, while others can
// work with both, gradient based and chi2 based functions. Historically however, we use
// simplified approach: if not Fumili, then chi2 only. Think of refactoring TODO.
bool Minuit2Minimizer::requiresResiduals()
{
return algorithmName() == "Fumili";
}
//! 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());
m_minuit2_minimizer->SetMaxFunctionCalls(static_cast<unsigned int>(maxFunctionCalls()));
}
const MinimizerAdapter::root_minimizer_t* Minuit2Minimizer::rootMinimizer() const
{
return m_minuit2_minimizer.get();
}
|