#include "TROOT.h"
#include "TFitterMinuit.h"
#include "TMath.h"
#include "TF1.h"
#include "TH1.h"
#include "TGraph.h"
#include "TChi2FCN.h"
#include "TChi2ExtendedFCN.h"
#include "TBinLikelihoodFCN.h"
#include "Minuit2/MnMigrad.h"
#include "Minuit2/MnMinos.h"
#include "Minuit2/MnHesse.h"
#include "Minuit2/MinuitParameter.h"
#include "Minuit2/MnPrint.h"
#include "Minuit2/FunctionMinimum.h"
#include "Minuit2/VariableMetricMinimizer.h"
#include "Minuit2/SimplexMinimizer.h"
#include "Minuit2/CombinedMinimizer.h"
#include "Minuit2/ScanMinimizer.h"
using namespace ROOT::Minuit2;
#ifndef ROOT_TMethodCall
#include "TMethodCall.h"
#endif
//for the G__p2f2funcname symbol
#include "Api.h"
//#define DEBUG 1
//#define OLDFCN_INTERFACE
#ifdef OLDFCN_INTERFACE
extern void H1FitChisquare(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag);
extern void H1FitLikelihood(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag);
extern void Graph2DFitChisquare(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag);
extern void MultiGraphFitChisquare(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag);
#endif
ClassImp(TFitterMinuit);
TFitterMinuit* gMinuit2 = 0;
TFitterMinuit::TFitterMinuit() : fErrorDef(0.) , fEDMVal(0.), fGradient(false),
fState(MnUserParameterState()), fMinosErrors(std::vector<MinosError>()), fMinimizer(0), fMinuitFCN(0), fDebug(1), fStrategy(1), fMinTolerance(0) {
Initialize();
}
// needed this additional contructor ?
TFitterMinuit::TFitterMinuit(Int_t /* maxpar */) : fErrorDef(0.) , fEDMVal(0.), fGradient(false), fState(MnUserParameterState()), fMinosErrors(std::vector<MinosError>()), fMinimizer(0), fMinuitFCN(0), fDebug(1), fStrategy(1), fMinTolerance(0) {
Initialize();
}
void TFitterMinuit::Initialize() {
SetName("Minuit2");
gMinuit2 = this;
gROOT->GetListOfSpecials()->Add(gMinuit2);
}
// create the minimizer engine and register the plugin in ROOT
void TFitterMinuit::CreateMinimizer(EMinimizerType type) {
#ifdef DEBUG
std::cout<<"TFitterMinuit:create minimizer of type "<< type << std::endl;
#endif
if (fMinimizer) delete fMinimizer;
switch (type) {
case kMigrad:
SetMinimizer( new VariableMetricMinimizer() );
return;
case kSimplex:
SetMinimizer( new SimplexMinimizer() );
return;
case kCombined:
SetMinimizer( new CombinedMinimizer() );
return;
case kScan:
SetMinimizer( new ScanMinimizer() );
return;
case kFumili:
std::cout << "TFitterMinuit::Error - Fumili Minimizer must be created from TFitterFumili " << std::endl;
SetMinimizer(0);
return;
default:
//migrad minimizer
SetMinimizer( new VariableMetricMinimizer() );
}
}
// destructor - deletes the minimizer and minuit fcn
// if using TVirtualFitter one should use Clear() and not delete()
TFitterMinuit::~TFitterMinuit() {
//std::cout << "delete minimizer and FCN" << std::endl;
if (fMinuitFCN) delete fMinuitFCN;
if (fMinimizer) delete fMinimizer;
}
Double_t TFitterMinuit::Chisquare(Int_t npar, Double_t *params) const {
// do chisquare calculations in case of likelihood fits
TChi2FCN chi2( *this );
std::vector<double> p(npar);
for (int i = 0; i < npar; ++i)
p[i] = params[i];
return chi2(p);
}
void TFitterMinuit::Clear(Option_t*) {
//std::cout<<"clear "<<std::endl;
fErrorDef = 0;
fEDMVal = 0;
fGradient = false;
State() = MnUserParameterState();
fMinosErrors.clear();
fDebug = 1;
fStrategy = 1;
fMinTolerance = 0;
if (fMinuitFCN) {
delete fMinuitFCN;
fMinuitFCN = 0;
}
if (fMinimizer) {
delete fMinimizer;
fMinimizer = 0;
}
}
FunctionMinimum TFitterMinuit::DoMinimization( int nfcn, double edmval) {
assert(GetMinuitFCN() != 0 );
assert(GetMinimizer() != 0 );
// use always strategy 1 (2 is not yet fully tested)
return GetMinimizer()->Minimize(*GetMinuitFCN(), State(), MnStrategy(fStrategy), nfcn, edmval);
}
int TFitterMinuit::Minimize( int nfcn, double edmval) {
// min tolerance
edmval = std::max(fMinTolerance, edmval);
if (fDebug >=0) {
std::cout << "TFitterMinuit - Minimize with max iterations " << nfcn << " edmval " << edmval << std::endl;
}
FunctionMinimum min = DoMinimization(nfcn,edmval);
fState = min.UserState();
return ExamineMinimum(min);
}
Int_t TFitterMinuit::ExecuteCommand(const char *command, Double_t *args, Int_t nargs){
#ifdef DEBUG
std::cout<<"Execute command= "<<command<<std::endl;
#endif
// MIGRAD
if (strncmp(command,"MIG",3) == 0 || strncmp(command,"mig",3) == 0) {
int nfcn = 0; // default values for Minuit
double edmval = 0.1;
// nfcn = GetMaxIterations();
// edmval = GetPrecision();
if (nargs > 0) nfcn = int ( args[0] );
if (nargs > 1) edmval = args[1];
// create migrad minimizer
CreateMinimizer(kMigrad);
return Minimize(nfcn, edmval);
// if(fGradient) {
// MnMigrad migrad(theFcn, State());
// theMinimum = migrad(theNFcn, fEDMVal);
// State() = theMinimum.userParameters();
// } else {
// std::cout<<"State(): "<<State()<<std::endl;
// std::cout<<"State(): "<<State()<<std::endl;
// }
}
//Minimize
if (strncmp(command,"MINI",4) == 0 || strncmp(command,"mini",4) == 0) {
int nfcn = 0; // default values for Minuit
double edmval = 0.1;
if (nargs > 0) nfcn = int ( args[0] );
if (nargs > 1) edmval = args[1];
// create combined minimizer
CreateMinimizer(kCombined);
return Minimize(nfcn, edmval);
}
//Simplex
if (strncmp(command,"SIM",3) == 0 || strncmp(command,"sim",3) == 0) {
int nfcn = 0; // default values for Minuit
double edmval = 0.1;
if (nargs > 0) nfcn = int ( args[0] );
if (nargs > 1) edmval = args[1];
// create combined minimizer
CreateMinimizer(kSimplex);
return Minimize(nfcn, edmval);
}
//SCan
if (strncmp(command,"SCA",3) == 0 || strncmp(command,"sca",3) == 0) {
int nfcn = 0; // default values for Minuit
double edmval = 0.1;
if (nargs > 0) nfcn = int ( args[0] );
if (nargs > 1) edmval = args[1];
// create combined minimizer
CreateMinimizer(kScan);
return Minimize(nfcn, edmval);
}
// MINOS
else if (strncmp(command,"MINO",4) == 0 || strncmp(command,"mino",4) == 0) {
// recall minimize using default nfcn and edmval
// should use maybe FunctionMinimum from previous call to migrad
// need to keep a pointer to function minimum in the class
FunctionMinimum min = DoMinimization();
if (!min.IsValid() ) {
std::cout << "TFitterMinuit::MINOS failed due to invalid function minimum" << std::endl;
return -10;
}
MnMinos minos( *fMinuitFCN, min);
fMinosErrors.clear();
for(unsigned int i = 0; i < State().VariableParameters(); i++) {
MinosError me = minos.Minos(State().ExtOfInt(i));
fMinosErrors.push_back(me);
}
if (fDebug >= 3) {
for(std::vector<MinosError>::const_iterator ime = fMinosErrors.begin();
ime != fMinosErrors.end(); ime++)
std::cout<<*ime<<std::endl;
}
return 0;
}
//HESSE
else if (strncmp(command,"HES",3) == 0 || strncmp(command,"hes",3) == 0) {
MnHesse hesse( GetStrategy() );
// update the state
const FCNBase * fcn = GetMinuitFCN();
assert(fcn != 0);
fState = hesse(*fcn, State(),100000 );
if (!fState.IsValid() ) {
std::cout << "TFitterMinuit::Hesse calculation failed " << std::endl;
return -10;
}
return 0;
}
// FIX
else if (strncmp(command,"FIX",3) == 0 || strncmp(command,"fix",3) == 0) {
for(int i = 0; i < nargs; i++) {
FixParameter(int(args[i]));
}
return 0;
}
// SET LIMIT (uper and lower)
else if (strncmp(command,"SET LIM",7) == 0 || strncmp(command,"set lim",7) == 0) {
assert(nargs >= 3);
int ipar = int(args[0]);
double low = args[1];
double up = args[2];
State().SetLimits(ipar, low, up);
return 0;
}
// SET PRINT
else if (strncmp(command,"SET PRINT",9) == 0 || strncmp(command,"set print",9) == 0) {
fDebug = int(args[0]);
#ifdef DEBUG
fDebug = 3;
#endif
return 0;
}
// SET STRATEGY
else if (strncmp(command,"SET STR",7) == 0 || strncmp(command,"set str",7) == 0) {
fStrategy = int(args[0]);
return 0;
}
//SET GRAD (not impl.)
else if (strncmp(command,"SET GRA",7) == 0 || strncmp(command,"set gra",7) == 0) {
// not yet available
// fGradient = true;
return -1;
}
// CALL FCN
else if (strncmp(command,"CALL FCN",8) == 0 || strncmp(command,"call fcn",8) == 0) {
// call fcn function
if (nargs < 1 || fFCN == 0) return -1;
const std::vector<double> & params = State().Params();
std::cout << State() << std::endl;
int npar = params.size();
double fval = 0;
(*fFCN)(npar, 0, fval, const_cast<double *>(¶ms.front()),int(args[0]) ) ;
return 0;
}
else {
// other commands passed
return 0;
}
}
/// study the function minimum
int TFitterMinuit::ExamineMinimum(const FunctionMinimum & min) {
// debug ( print all the states)
if (fDebug >= 3) {
const std::vector<MinimumState>& iterationStates = min.States();
std::cout << "Number of iterations " << iterationStates.size() << std::endl;
for (unsigned int i = 0; i < iterationStates.size(); ++i) {
//std::cout << iterationStates[i] << std::endl;
const MinimumState & st = iterationStates[i];
std::cout << "----------> Iteration " << i << std::endl;
std::cout << " FVAL = " << st.Fval() << " Edm = " << st.Edm() << " Nfcn = " << st.NFcn() << std::endl;
std::cout << " Error matrix change = " << st.Error().Dcovar() << std::endl;
std::cout << " Internal parameters : ";
for (int j = 0; j < st.size() ; ++j) std::cout << " p" << j << " = " << st.Vec()(j);
std::cout << std::endl;
}
}
// print result
if (min.IsValid() ) {
if (fDebug >=1 ) {
std::cout << "Minimum Found" << std::endl;
std::cout << "FVAL = " << State().Fval() << std::endl;
std::cout << "Edm = " << State().Edm() << std::endl;
std::cout << "Nfcn = " << State().NFcn() << std::endl;
std::vector<double> par = State().Params();
std::vector<double> err = State().Errors();
for (unsigned int i = 0; i < State().Params().size(); ++i)
std::cout << State().Parameter(i).Name() << "\t = " << par[i] << "\t +/- " << err[i] << std::endl;
}
return 0;
}
else {
if (fDebug >= 1) std::cout << "TFitterMinuit::Minimization DID not converge !" << std::endl;
if (min.HasMadePosDefCovar() ) {
if (fDebug >= 1) std::cout << " Covar was made pos def" << std::endl;
return -11;
}
if (min.HesseFailed() ) {
if (fDebug >= 1) std::cout << " Hesse is not valid" << std::endl;
return -12;
}
if (min.IsAboveMaxEdm() ) {
if (fDebug >= 1) std::cout << " Edm is above max" << std::endl;
return -13;
}
if (min.HasReachedCallLimit() ) {
if (fDebug >= 1) std::cout << " Reached call limit" << std::endl;
return -14;
}
return -10;
}
return 0;
}
void TFitterMinuit::FixParameter(Int_t ipar) {
// std::cout<<"FixParameter"<<std::endl;
State().Fix(ipar);
}
Double_t* TFitterMinuit::GetCovarianceMatrix() const {
return (Double_t*)(&(State().Covariance().Data().front()));
}
Double_t TFitterMinuit::GetCovarianceMatrixElement(Int_t i, Int_t j) const {
std::cout<<"GetCovarianceMatrix not implemented"<<std::endl;
return State().Covariance()(i,j);
}
Int_t TFitterMinuit::GetErrors(Int_t ipar,Double_t &eplus, Double_t &eminus, Double_t &eparab, Double_t &globcc) const {
// std::cout<<"GetError"<<std::endl;
if(fMinosErrors.empty()) {
eplus = 0.;
eminus = 0.;
} else {
unsigned int nintern = State().IntOfExt(ipar);
eplus = fMinosErrors[nintern].Upper();
eminus = fMinosErrors[nintern].Lower();
}
eparab = State().Error(ipar);
globcc = State().GlobalCC().GlobalCC()[ipar];
return 0;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// here is example of deficit of new Minuit interface
//////////////////////////////////////////////
Int_t TFitterMinuit::GetNumberTotalParameters() const {
return State().Parameters().Parameters().size();
}
Int_t TFitterMinuit::GetNumberFreeParameters() const {
return State().Parameters().VariableParameters();
}
Double_t TFitterMinuit::GetParError(Int_t ipar) const {
// std::cout<<"GetParError"<<std::endl;
return State().Error(ipar);
}
Double_t TFitterMinuit::GetParameter(Int_t ipar) const {
// std::cout<<"GetParameter"<<std::endl;
return State().Value(ipar);
}
Int_t TFitterMinuit::GetParameter(Int_t ipar,char *name,Double_t &value,Double_t &verr,Double_t &vlow, Double_t &vhigh) const {
// std::cout<<"GetParameter(Int_t ipar,char"<<std::endl;
const MinuitParameter& mp = State().Parameter(ipar);
// std::cout<<"i= "<<ipar<<" verr= "<<mp.error()<<std::endl;
name = const_cast<char*>(mp.Name());
value = mp.Value();
verr = mp.Error();
vlow = mp.LowerLimit();
vhigh = mp.UpperLimit();
return 0;
}
Int_t TFitterMinuit::GetStats(Double_t &amin, Double_t &edm, Double_t &errdef, Int_t &nvpar, Int_t &nparx) const {
// std::cout<<"GetStats"<<std::endl;
amin = State().Fval();
edm = State().Edm();
errdef = fErrorDef;
nvpar = State().VariableParameters();
nparx = State().Parameters().Parameters().size();
return 0;
}
Double_t TFitterMinuit::GetSumLog(Int_t) {
// std::cout<<"GetSumLog"<<std::endl;
return 0.;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Bool_t TFitterMinuit::IsFixed(Int_t ipar) const {
return State().Parameter(ipar).IsFixed();
}
void TFitterMinuit::PrintResults(Int_t level, Double_t) const {
// std::cout<<"PrintResults"<<std::endl;
// std::cout<<State().parameters()<<std::endl;
std::cout<<State()<<std::endl;
if (level > 3) {
for(std::vector<MinosError>::const_iterator ime = fMinosErrors.begin();
ime != fMinosErrors.end(); ime++) {
std::cout<<*ime<<std::endl;
}
}
}
void TFitterMinuit::ReleaseParameter(Int_t ipar) {
// std::cout<<"ReleaseParameter"<<std::endl;
State().Release(ipar);
}
void TFitterMinuit::SetFitMethod(const char *name) {
#ifdef DEBUG
std::cout<<"SetFitMethod to "<< name << std::endl;
#endif
if (!strcmp(name,"H1FitChisquare")) {
fErrorDef = 1.;
// old way of passing
#ifdef OLDFCN_INTERFACE
SetFCN(H1FitChisquare);
#else
// call function (because overloaded by derived class)
CreateChi2FCN();
#endif
return;
}
if (!strcmp(name,"GraphFitChisquare")) {
fErrorDef = 1.;
#ifdef OLDFCN_INTERFACE
SetFCN(GraphFitChisquare);
#else
// use for graph extended chi2 to include error in X coordinate
if (!GetFitOption().W1)
CreateChi2ExtendedFCN( );
else
CreateChi2FCN( );
#endif
return;
}
if (!strcmp(name, "Graph2DFitChisquare")) {
fErrorDef = 1.;
#ifdef OLDFCN_INTERFACE
SetFCN(Graph2DFitChisquare);
#else
// use for graph extended chi2 to include error in X and Y coordinates
// if (!GetFitOption().W1) {
// CreateChi2ExtendedFCN( );
// else
CreateChi2FCN( );
#endif
return;
}
if (!strcmp(name, "MultiGraphFitChisquare")) {
fErrorDef = 1.;
#ifdef OLDFCN_INTERFACE
SetFCN(MultiGraphFitChisquare);
#else
CreateChi2FCN();
#endif
return;
}
if (!strcmp(name, "H1FitLikelihood")) {
// old way of passing
#ifdef OLDFCN_INTERFACE
fErrorDef = 1.;
SetFCN(H1FitLikelihood);
#else
fErrorDef = 0.5;
CreateBinLikelihoodFCN();
#endif
return;
}
std::cout << "TFitterMinuit::fit method " << name << " is not supported !" << std::endl;
assert(fMinuitFCN != 0);
//
// } else {
// SetFCN(H1FitChisquare);
// }
// TFitterMinuit manages the data
}
Int_t TFitterMinuit::SetParameter(Int_t,const char *parname,Double_t value,Double_t verr,Double_t vlow, Double_t vhigh) {
#ifdef DEBUG
std::cout<<"SetParameter";
std::cout << parname<<" value = " << value << " verr= "<<verr<<std::endl;
#endif
if(vlow < vhigh) {
State().Add(parname, value, verr, vlow, vhigh);
}
else
State().Add(parname, value, verr);
// treat constant parameter as fixed
if (verr == 0) State().Fix(parname);
return 0;
}
// override setFCN to use the Adapter
void TFitterMinuit::SetFCN(void (*fcn)(Int_t &, Double_t *, Double_t &f, Double_t *, Int_t))
{
//*-*-*-*-*-*-*To set the address of the minimization function*-*-*-*-*-*-*-*
//*-* ===============================================
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
fFCN = fcn;
if (fMinuitFCN) delete fMinuitFCN;
fMinuitFCN = new TFcnAdapter(fFCN);
}
// need for interactive environment
// global functions needed by interpreter
//______________________________________________________________________________
void InteractiveFCNm2(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag)
{
//*-*-*-*-*-*-*Static function called when SetFCN is called in interactive mode
//*-* ===============================================
TMethodCall *m = gMinuit2->GetMethodCall();
if (!m) return;
Long_t args[5];
args[0] = (Long_t)∦
args[1] = (Long_t)gin;
args[2] = (Long_t)&f;
args[3] = (Long_t)u;
args[4] = (Long_t)flag;
m->SetParamPtrs(args);
Double_t result;
m->Execute(result);
}
//______________________________________________________________________________
void TFitterMinuit::SetFCN(void *fcn)
{
//*-*-*-*-*-*-*To set the address of the minimization function*-*-*-*-*-*-*-*
//*-* ===============================================
// this function is called by CINT instead of the function above
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
if (!fcn) return;
char *funcname = G__p2f2funcname(fcn);
if (funcname) {
fMethodCall = new TMethodCall();
fMethodCall->InitWithPrototype(funcname,"Int_t&,Double_t*,Double_t&,Double_t*,Int_t");
}
fFCN = InteractiveFCNm2;
gMinuit2 = this; //required by InteractiveFCNm
if (fMinuitFCN) delete fMinuitFCN;
fMinuitFCN = new TFcnAdapter(fFCN);
}
void TFitterMinuit::SetMinuitFCN( FCNBase * f) {
// class takes the ownership of the passed pointer
// so needs to delete previous one
if (fMinuitFCN) delete fMinuitFCN;
fMinuitFCN = f;
}
void TFitterMinuit::CreateChi2FCN() {
SetMinuitFCN(new TChi2FCN( *this ) );
}
void TFitterMinuit::CreateChi2ExtendedFCN() {
SetMinuitFCN(new TChi2ExtendedFCN( *this ) );
}
void TFitterMinuit::CreateBinLikelihoodFCN() {
SetMinuitFCN(new TBinLikelihoodFCN( *this ) );
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.