/*****************************************************************************
* Project: RooFit *
* Package: RooFitCore *
* @(#)root/roofitcore:$Id$
* Authors: *
* WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
* DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
* *
* Copyright (c) 2000-2005, Regents of the University of California *
* and Stanford University. All rights reserved. *
* *
* Redistribution and use in source and binary forms, *
* with or without modification, are permitted according to the terms *
* listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
*****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// RooMinuit is a wrapper class around TFitter/TMinuit that
// provides a seamless interface between the MINUIT functionality
// and the native RooFit interface.
//
// RooMinuit can minimize any RooAbsReal function with respect to
// its parameters. Usual choices for minimization are RooNLLVar
// and RooChi2Var
//
// RooMinuit has methods corresponding to MINUIT functions like
// hesse(), migrad(), minos() etc. In each of these function calls
// the state of the MINUIT engine is synchronized with the state
// of the RooFit variables: any change in variables, change
// in the constant status etc is forwarded to MINUIT prior to
// execution of the MINUIT call. Afterwards the RooFit objects
// are resynchronized with the output state of MINUIT: changes
// parameter values, errors are propagated.
//
// Various methods are available to control verbosity, profiling,
// automatic PDF optimization.
// END_HTML
//
#include "RooFit.h"
#include "Riostream.h"
#include "TClass.h"
#include
#include
#include "TH1.h"
#include "TH2.h"
#include "TMarker.h"
#include "TGraph.h"
#include "TStopwatch.h"
#include "TFitter.h"
#include "TMinuit.h"
#include "TDirectory.h"
#include "TMatrixDSym.h"
#include "RooMinuit.h"
#include "RooArgSet.h"
#include "RooArgList.h"
#include "RooAbsReal.h"
#include "RooAbsRealLValue.h"
#include "RooRealVar.h"
#include "RooFitResult.h"
#include "RooAbsPdf.h"
#include "RooSentinel.h"
#include "RooMsgService.h"
#include "RooPlot.h"
#if (__GNUC__==3&&__GNUC_MINOR__==2&&__GNUC_PATCHLEVEL__==3)
char* operator+( streampos&, char* );
#endif
using namespace std;
ClassImp(RooMinuit)
;
TVirtualFitter *RooMinuit::_theFitter = 0 ;
//_____________________________________________________________________________
void RooMinuit::cleanup()
{
// Cleanup method called by atexit handler installed by RooSentinel
// to delete all global heap objects when the program is terminated
if (_theFitter) {
delete _theFitter ;
_theFitter =0 ;
}
}
//_____________________________________________________________________________
RooMinuit::RooMinuit(RooAbsReal& function)
{
// Construct MINUIT interface to given function. Function can be anything,
// but is typically a -log(likelihood) implemented by RooNLLVar or a chi^2
// (implemented by RooChi2Var). Other frequent use cases are a RooAddition
// of a RooNLLVar plus a penalty or constraint term. This class propagates
// all RooFit information (floating parameters, their values and errors)
// to MINUIT before each MINUIT call and propagates all MINUIT information
// back to the RooFit object at the end of each call (updated parameter
// values, their (asymmetric errors) etc. The default MINUIT error level
// for HESSE and MINOS error analysis is taken from the defaultErrorLevel()
// value of the input function.
RooSentinel::activate() ;
// Store function reference
_evalCounter = 0 ;
_extV = 0 ;
_func = &function ;
_logfile = 0 ;
_optConst = kFALSE ;
_verbose = kFALSE ;
_profile = kFALSE ;
_handleLocalErrors = kTRUE ;
_printLevel = 1 ;
_printEvalErrors = 10 ;
_warnLevel = -999 ;
_maxEvalMult = 500 ;
_doEvalErrorWall = kTRUE ;
// Examine parameter list
RooArgSet* paramSet = function.getParameters(RooArgSet()) ;
RooArgList paramList(*paramSet) ;
delete paramSet ;
_floatParamList = (RooArgList*) paramList.selectByAttrib("Constant",kFALSE) ;
if (_floatParamList->getSize()>1) {
_floatParamList->sort() ;
}
_floatParamList->setName("floatParamList") ;
_constParamList = (RooArgList*) paramList.selectByAttrib("Constant",kTRUE) ;
if (_constParamList->getSize()>1) {
_constParamList->sort() ;
}
_constParamList->setName("constParamList") ;
// Remove all non-RooRealVar parameters from list (MINUIT cannot handle them)
TIterator* pIter = _floatParamList->createIterator() ;
RooAbsArg* arg ;
while((arg=(RooAbsArg*)pIter->Next())) {
if (!arg->IsA()->InheritsFrom(RooAbsRealLValue::Class())) {
coutW(Minimization) << "RooMinuit::RooMinuit: removing parameter " << arg->GetName()
<< " from list because it is not of type RooRealVar" << endl ;
_floatParamList->remove(*arg) ;
}
}
_nPar = _floatParamList->getSize() ;
delete pIter ;
updateFloatVec() ;
// Save snapshot of initial lists
_initFloatParamList = (RooArgList*) _floatParamList->snapshot(kFALSE) ;
_initConstParamList = (RooArgList*) _constParamList->snapshot(kFALSE) ;
// Initialize MINUIT
Int_t nPar= _floatParamList->getSize() + _constParamList->getSize() ;
if (_theFitter) delete _theFitter ;
_theFitter = new TFitter(nPar*2+1) ; //WVE Kludge, nPar*2 works around TMinuit memory allocation bug
_theFitter->SetObjectFit(this) ;
// Shut up for now
setPrintLevel(-1) ;
_theFitter->Clear();
// Tell MINUIT to use our global glue function
_theFitter->SetFCN(RooMinuitGlue);
// Use +0.5 for 1-sigma errors
setErrorLevel(function.defaultErrorLevel()) ;
// Declare our parameters to MINUIT
synchronize(kFALSE) ;
// Reset the *largest* negative log-likelihood value we have seen so far
_maxFCN= -1e30 ;
_numBadNLL = 0 ;
// Now set default verbosity
if (RooMsgService::instance().silentMode()) {
setWarnLevel(-1) ;
setPrintLevel(-1) ;
} else {
setWarnLevel(1) ;
setPrintLevel(1) ;
}
}
//_____________________________________________________________________________
RooMinuit::~RooMinuit()
{
// Destructor
delete _floatParamList ;
delete _initFloatParamList ;
delete _constParamList ;
delete _initConstParamList ;
if (_extV) {
delete _extV ;
}
}
//_____________________________________________________________________________
void RooMinuit::setStrategy(Int_t istrat)
{
// Change MINUIT strategy to istrat. Accepted codes
// are 0,1,2 and represent MINUIT strategies for dealing
// most efficiently with fast FCNs (0), expensive FCNs (2)
// and 'intermediate' FCNs (1)
Double_t stratArg(istrat) ;
_theFitter->ExecuteCommand("SET STR",&stratArg,1) ;
}
//_____________________________________________________________________________
void RooMinuit::setErrorLevel(Double_t level)
{
// Set the level for MINUIT error analysis to the given
// value. This function overrides the default value
// that is taken in the RooMinuit constructor from
// the defaultErrorLevel() method of the input function
_theFitter->ExecuteCommand("SET ERR",&level,1);
}
//_____________________________________________________________________________
void RooMinuit::setEps(Double_t eps)
{
// Change MINUIT epsilon
_theFitter->ExecuteCommand("SET EPS",&eps,1) ;
}
//_____________________________________________________________________________
void RooMinuit::setOffsetting(Bool_t flag)
{
// Enable internal likelihood offsetting for enhanced numeric precision
_func->enableOffsetting(flag) ;
}
//_____________________________________________________________________________
RooFitResult* RooMinuit::fit(const char* options)
{
// Parse traditional RooAbsPdf::fitTo driver options
//
// s - Run Hesse first to estimate initial step size
// m - Run Migrad only
// h - Run Hesse to estimate errors
// v - Verbose mode
// l - Log parameters after each Minuit steps to file
// t - Activate profile timer
// r - Save fit result
// 0 - Run Migrad with strategy 0
if (_floatParamList->getSize()==0) {
return 0 ;
}
_theFitter->SetObjectFit(this) ;
TString opts(options) ;
opts.ToLower() ;
// Initial configuration
if (opts.Contains("v")) setVerbose(1) ;
if (opts.Contains("t")) setProfile(1) ;
if (opts.Contains("l")) setLogFile(Form("%s.log",_func->GetName())) ;
if (opts.Contains("c")) optimizeConst(1) ;
// Fitting steps
if (opts.Contains("s")) hesse() ;
if (opts.Contains("0")) setStrategy(0) ;
migrad() ;
if (opts.Contains("0")) setStrategy(1) ;
if (opts.Contains("h")||!opts.Contains("m")) hesse() ;
if (!opts.Contains("m")) minos() ;
return (opts.Contains("r")) ? save() : 0 ;
}
//_____________________________________________________________________________
Int_t RooMinuit::migrad()
{
// Execute MIGRAD. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Double_t arglist[2];
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
arglist[1]= 1.0; // tolerance
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("MIGRAD",arglist,2);
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
saveStatus("MIGRAD",_status) ;
return _status ;
}
//_____________________________________________________________________________
Int_t RooMinuit::hesse()
{
// Execute HESSE. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Double_t arglist[2];
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("HESSE",arglist,1);
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
saveStatus("HESSE",_status) ;
return _status ;
}
//_____________________________________________________________________________
Int_t RooMinuit::minos()
{
// Execute MINOS. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Double_t arglist[2];
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("MINOS",arglist,1);
// check also the status of Minos looking at fCstatu
if (_status == 0 && gMinuit->fCstatu != "SUCCESSFUL") {
if (gMinuit->fCstatu == "FAILURE" ||
gMinuit->fCstatu == "PROBLEMS") _status = 5;
_status = 6;
}
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
saveStatus("MINOS",_status) ;
return _status ;
}
// added FMV, 08/18/03
//_____________________________________________________________________________
Int_t RooMinuit::minos(const RooArgSet& minosParamList)
{
// Execute MINOS for given list of parameters. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Int_t nMinosPar(0) ;
Double_t* arglist = new Double_t[_nPar+1];
if (minosParamList.getSize()>0) {
TIterator* aIter = minosParamList.createIterator() ;
RooAbsArg* arg ;
while((arg=(RooAbsArg*)aIter->Next())) {
RooAbsArg* par = _floatParamList->find(arg->GetName());
if (par && !par->isConstant()) {
Int_t index = _floatParamList->index(par);
nMinosPar++;
arglist[nMinosPar]=index+1;
}
}
delete aIter ;
}
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("MINOS",arglist,1+nMinosPar);
// check also the status of Minos looking at fCstatu
if (_status == 0 && gMinuit->fCstatu != "SUCCESSFUL") {
if (gMinuit->fCstatu == "FAILURE" ||
gMinuit->fCstatu == "PROBLEMS") _status = 5;
_status = 6;
}
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
delete[] arglist ;
saveStatus("MINOS",_status) ;
return _status ;
}
//_____________________________________________________________________________
Int_t RooMinuit::seek()
{
// Execute SEEK. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Double_t arglist[2];
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("SEEK",arglist,1);
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
saveStatus("SEEK",_status) ;
return _status ;
}
//_____________________________________________________________________________
Int_t RooMinuit::simplex()
{
// Execute SIMPLEX. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Double_t arglist[2];
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
arglist[1]= 1.0; // tolerance
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("SIMPLEX",arglist,2);
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
saveStatus("SIMPLEX",_status) ;
return _status ;
}
//_____________________________________________________________________________
Int_t RooMinuit::improve()
{
// Execute IMPROVE. Changes in parameter values
// and calculated errors are automatically
// propagated back the RooRealVars representing
// the floating parameters in the MINUIT operation
if (_floatParamList->getSize()==0) {
return -1 ;
}
_theFitter->SetObjectFit(this) ;
Double_t arglist[2];
arglist[0]= _maxEvalMult*_nPar; // maximum iterations
synchronize(_verbose) ;
profileStart() ;
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
RooAbsReal::clearEvalErrorLog() ;
_status= _theFitter->ExecuteCommand("IMPROVE",arglist,1);
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
profileStop() ;
backProp() ;
saveStatus("IMPROVE",_status) ;
return _status ;
}
//_____________________________________________________________________________
Int_t RooMinuit::setPrintLevel(Int_t newLevel)
{
// Change the MINUIT internal printing level
Int_t ret = _printLevel ;
Double_t arg(newLevel) ;
_theFitter->ExecuteCommand("SET PRINT",&arg,1);
_printLevel = newLevel ;
return ret ;
}
//_____________________________________________________________________________
void RooMinuit::setNoWarn()
{
// Instruct MINUIT to suppress warnings
Double_t arg(0) ;
_theFitter->ExecuteCommand("SET NOWARNINGS",&arg,1);
_warnLevel = -1 ;
}
//_____________________________________________________________________________
Int_t RooMinuit::setWarnLevel(Int_t newLevel)
{
// Set MINUIT warning level to given level
if (newLevel==_warnLevel) {
return _warnLevel ;
}
Int_t ret = _warnLevel ;
Double_t arg(newLevel) ;
if (newLevel>=0) {
_theFitter->ExecuteCommand("SET WARNINGS",&arg,1);
} else {
Double_t arg2(0) ;
_theFitter->ExecuteCommand("SET NOWARNINGS",&arg2,1);
}
_warnLevel = newLevel ;
return ret ;
}
//_____________________________________________________________________________
Bool_t RooMinuit::synchronize(Bool_t verbose)
{
// Internal function to synchronize TMinuit with current
// information in RooAbsReal function parameters
Int_t oldPrint = setPrintLevel(-1) ;
gMinuit->fNwrmes[0] = 0; // to clear buffer
Int_t oldWarn = setWarnLevel(-1) ;
Bool_t constValChange(kFALSE) ;
Bool_t constStatChange(kFALSE) ;
Int_t index(0) ;
// Handle eventual migrations from constParamList -> floatParamList
for(index= 0; index < _constParamList->getSize() ; index++) {
RooRealVar *par= dynamic_cast(_constParamList->at(index)) ;
if (!par) continue ;
RooRealVar *oldpar= dynamic_cast(_initConstParamList->at(index)) ;
if (!oldpar) continue ;
// Test if constness changed
if (!par->isConstant()) {
// Remove from constList, add to floatList
_constParamList->remove(*par) ;
_floatParamList->add(*par) ;
_initFloatParamList->addClone(*oldpar) ;
_initConstParamList->remove(*oldpar) ;
constStatChange=kTRUE ;
_nPar++ ;
if (verbose) {
coutI(Minimization) << "RooMinuit::synchronize: parameter " << par->GetName() << " is now floating." << endl ;
}
}
// Test if value changed
if (par->getVal()!= oldpar->getVal()) {
constValChange=kTRUE ;
if (verbose) {
coutI(Minimization) << "RooMinuit::synchronize: value of constant parameter " << par->GetName()
<< " changed from " << oldpar->getVal() << " to " << par->getVal() << endl ;
}
}
}
// Update reference list
*_initConstParamList = *_constParamList ;
// Synchronize MINUIT with function state
for(index= 0; index < _nPar; index++) {
RooRealVar *par= dynamic_cast(_floatParamList->at(index)) ;
if (!par) continue ;
Double_t pstep(0) ;
Double_t pmin(0) ;
Double_t pmax(0) ;
if(!par->isConstant()) {
// Verify that floating parameter is indeed of type RooRealVar
if (!par->IsA()->InheritsFrom(RooRealVar::Class())) {
coutW(Minimization) << "RooMinuit::fit: Error, non-constant parameter " << par->GetName()
<< " is not of type RooRealVar, skipping" << endl ;
continue ;
}
// Set the limits, if not infinite
if (par->hasMin() && par->hasMax()) {
pmin = par->getMin();
pmax = par->getMax();
}
// Calculate step size
pstep= par->getError();
if(pstep <= 0) {
// Floating parameter without error estitimate
if (par->hasMin() && par->hasMax()) {
pstep= 0.1*(pmax-pmin);
// Trim default choice of error if within 2 sigma of limit
if (pmax - par->getVal() < 2*pstep) {
pstep = (pmax - par->getVal())/2 ;
} else if (par->getVal() - pmin < 2*pstep) {
pstep = (par->getVal() - pmin )/2 ;
}
// If trimming results in zero error, restore default
if (pstep==0) {
pstep= 0.1*(pmax-pmin);
}
} else {
pstep=1 ;
}
if(_verbose) {
coutW(Minimization) << "RooMinuit::synchronize: WARNING: no initial error estimate available for "
<< par->GetName() << ": using " << pstep << endl;
}
}
} else {
pmin = par->getVal() ;
pmax = par->getVal() ;
}
// Extract previous information
Double_t oldVar,oldVerr,oldVlo,oldVhi ;
char oldParname[100] ;
Int_t ierr = _theFitter->GetParameter(index,oldParname,oldVar,oldVerr,oldVlo,oldVhi) ;
// Determine if parameters is currently fixed in MINUIT
Int_t ix ;
Bool_t oldFixed(kFALSE) ;
if (ierr>=0) {
for (ix = 1; ix <= gMinuit->fNpfix; ++ix) {
if (gMinuit->fIpfix[ix-1] == index+1) oldFixed=kTRUE ;
}
}
if (par->isConstant() && !oldFixed) {
// Parameter changes floating -> constant : update only value if necessary
if (oldVar!=par->getVal()) {
Double_t arglist[2] ;
arglist[0] = index+1 ;
arglist[1] = par->getVal() ;
_theFitter->ExecuteCommand("SET PAR",arglist,2) ;
if (verbose) {
coutI(Minimization) << "RooMinuit::synchronize: value of parameter " << par->GetName() << " changed from " << oldVar << " to " << par->getVal() << endl ;
}
}
_theFitter->FixParameter(index) ;
constStatChange=kTRUE ;
if (verbose) {
coutI(Minimization) << "RooMinuit::synchronize: parameter " << par->GetName() << " is now fixed." << endl ;
}
} else if (par->isConstant() && oldFixed) {
// Parameter changes constant -> constant : update only value if necessary
if (oldVar!=par->getVal()) {
Double_t arglist[2] ;
arglist[0] = index+1 ;
arglist[1] = par->getVal() ;
_theFitter->ExecuteCommand("SET PAR",arglist,2) ;
constValChange=kTRUE ;
if (verbose) {
coutI(Minimization) << "RooMinuit::synchronize: value of fixed parameter " << par->GetName() << " changed from " << oldVar << " to " << par->getVal() << endl ;
}
}
} else {
if (!par->isConstant() && oldFixed) {
_theFitter->ReleaseParameter(index) ;
constStatChange=kTRUE ;
if (verbose) {
coutI(Minimization) << "RooMinuit::synchronize: parameter " << par->GetName() << " is now floating." << endl ;
}
}
// Parameter changes constant -> floating : update all if necessary
if (oldVar!=par->getVal() || oldVlo!=pmin || oldVhi != pmax || oldVerr!=pstep) {
_theFitter->SetParameter(index, par->GetName(), par->getVal(), pstep, pmin, pmax);
}
// Inform user about changes in verbose mode
if (verbose && ierr>=0) {
// if ierr<0, par was moved from the const list and a message was already printed
if (oldVar!=par->getVal()) {
coutI(Minimization) << "RooMinuit::synchronize: value of parameter " << par->GetName() << " changed from " << oldVar << " to " << par->getVal() << endl ;
}
if (oldVlo!=pmin || oldVhi!=pmax) {
coutI(Minimization) << "RooMinuit::synchronize: limits of parameter " << par->GetName() << " changed from [" << oldVlo << "," << oldVhi
<< "] to [" << pmin << "," << pmax << "]" << endl ;
}
// If oldVerr=0, then parameter was previously fixed
if (oldVerr!=pstep && oldVerr!=0) {
coutI(Minimization) << "RooMinuit::synchronize: error/step size of parameter " << par->GetName() << " changed from " << oldVerr << " to " << pstep << endl ;
}
}
}
}
gMinuit->fNwrmes[0] = 0; // to clear buffer
oldWarn = setWarnLevel(oldWarn) ;
oldPrint = setPrintLevel(oldPrint) ;
if (_optConst) {
if (constStatChange) {
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
coutI(Minimization) << "RooMinuit::synchronize: set of constant parameters changed, rerunning const optimizer" << endl ;
_func->constOptimizeTestStatistic(RooAbsArg::ConfigChange) ;
} else if (constValChange) {
coutI(Minimization) << "RooMinuit::synchronize: constant parameter values changed, rerunning const optimizer" << endl ;
_func->constOptimizeTestStatistic(RooAbsArg::ValueChange) ;
}
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
}
updateFloatVec() ;
return 0 ;
}
//_____________________________________________________________________________
void RooMinuit::optimizeConst(Int_t flag)
{
// If flag is true, perform constant term optimization on
// function being minimized.
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CollectErrors) ;
if (_optConst && !flag){
if (_printLevel>-1) coutI(Minimization) << "RooMinuit::optimizeConst: deactivating const optimization" << endl ;
_func->constOptimizeTestStatistic(RooAbsArg::DeActivate,flag>1) ;
_optConst = flag ;
} else if (!_optConst && flag) {
if (_printLevel>-1) coutI(Minimization) << "RooMinuit::optimizeConst: activating const optimization" << endl ;
_func->constOptimizeTestStatistic(RooAbsArg::Activate,flag>1) ;
_optConst = flag ;
} else if (_optConst && flag) {
if (_printLevel>-1) coutI(Minimization) << "RooMinuit::optimizeConst: const optimization already active" << endl ;
} else {
if (_printLevel>-1) coutI(Minimization) << "RooMinuit::optimizeConst: const optimization wasn't active" << endl ;
}
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::PrintErrors) ;
}
//_____________________________________________________________________________
RooFitResult* RooMinuit::save(const char* userName, const char* userTitle)
{
// Save and return a RooFitResult snaphot of current minimizer status.
// This snapshot contains the values of all constant parameters,
// the value of all floating parameters at RooMinuit construction and
// after the last MINUIT operation, the MINUIT status, variance quality,
// EDM setting, number of calls with evaluation problems, the minimized
// function value and the full correlation matrix
TString name,title ;
name = userName ? userName : Form("%s", _func->GetName()) ;
title = userTitle ? userTitle : Form("%s", _func->GetTitle()) ;
if (_floatParamList->getSize()==0) {
RooFitResult* fitRes = new RooFitResult(name,title) ;
fitRes->setConstParList(*_constParamList) ;
fitRes->setInitParList(RooArgList()) ;
fitRes->setFinalParList(RooArgList()) ;
fitRes->setStatus(-999) ;
fitRes->setCovQual(-999) ;
fitRes->setMinNLL(_func->getVal()) ;
fitRes->setNumInvalidNLL(0) ;
fitRes->setEDM(-999) ;
return fitRes ;
}
RooFitResult* fitRes = new RooFitResult(name,title) ;
// Move eventual fixed parameters in floatList to constList
Int_t i ;
RooArgList saveConstList(*_constParamList) ;
RooArgList saveFloatInitList(*_initFloatParamList) ;
RooArgList saveFloatFinalList(*_floatParamList) ;
for (i=0 ; i<_floatParamList->getSize() ; i++) {
RooAbsArg* par = _floatParamList->at(i) ;
if (par->isConstant()) {
saveFloatInitList.remove(*saveFloatInitList.find(par->GetName()),kTRUE) ;
saveFloatFinalList.remove(*par) ;
saveConstList.add(*par) ;
}
}
saveConstList.sort() ;
fitRes->setConstParList(saveConstList) ;
fitRes->setInitParList(saveFloatInitList) ;
Double_t edm, errdef, minVal;
Int_t nvpar, nparx;
Int_t icode = _theFitter->GetStats(minVal, edm, errdef, nvpar, nparx);
fitRes->setStatus(_status) ;
fitRes->setCovQual(icode) ;
fitRes->setMinNLL(minVal) ;
fitRes->setNumInvalidNLL(_numBadNLL) ;
fitRes->setEDM(edm) ;
fitRes->setFinalParList(saveFloatFinalList) ;
if (!_extV) {
fitRes->fillCorrMatrix() ;
} else {
fitRes->setCovarianceMatrix(*_extV) ;
}
fitRes->setStatusHistory(_statusHistory) ;
return fitRes ;
}
//_____________________________________________________________________________
RooPlot* RooMinuit::contour(RooRealVar& var1, RooRealVar& var2, Double_t n1, Double_t n2, Double_t n3, Double_t n4, Double_t n5, Double_t n6)
{
// Create and draw a TH2 with the error contours in parameters var1 and v2 at up to 6 'sigma' settings
// where 'sigma' is calculated as n*n*errorLevel
_theFitter->SetObjectFit(this) ;
RooArgList* paramSave = (RooArgList*) _floatParamList->snapshot() ;
// Verify that both variables are floating parameters of PDF
Int_t index1= _floatParamList->index(&var1);
if(index1 < 0) {
coutE(Minimization) << "RooMinuit::contour(" << GetName()
<< ") ERROR: " << var1.GetName() << " is not a floating parameter of " << _func->GetName() << endl ;
return 0;
}
Int_t index2= _floatParamList->index(&var2);
if(index2 < 0) {
coutE(Minimization) << "RooMinuit::contour(" << GetName()
<< ") ERROR: " << var2.GetName() << " is not a floating parameter of PDF " << _func->GetName() << endl ;
return 0;
}
// create and draw a frame
RooPlot* frame = new RooPlot(var1,var2) ;
// draw a point at the current parameter values
TMarker *point= new TMarker(var1.getVal(), var2.getVal(), 8);
frame->addObject(point) ;
// remember our original value of ERRDEF
Double_t errdef= gMinuit->fUp;
Double_t n[6] ;
n[0] = n1 ; n[1] = n2 ; n[2] = n3 ; n[3] = n4 ; n[4] = n5 ; n[5] = n6 ;
for (Int_t ic = 0 ; ic<6 ; ic++) {
if(n[ic] > 0) {
// set the value corresponding to an n1-sigma contour
gMinuit->SetErrorDef(n[ic]*n[ic]*errdef);
// calculate and draw the contour
TGraph* graph= (TGraph*)gMinuit->Contour(50, index1, index2);
if (!graph) {
coutE(Minimization) << "RooMinuit::contour(" << GetName() << ") ERROR: MINUIT did not return a contour graph for n=" << n[ic] << endl ;
} else {
graph->SetName(Form("contour_%s_n%f",_func->GetName(),n[ic])) ;
graph->SetLineStyle(ic+1) ;
graph->SetLineWidth(2) ;
graph->SetLineColor(kBlue) ;
frame->addObject(graph,"L") ;
}
}
}
// restore the original ERRDEF
gMinuit->SetErrorDef(errdef);
// restore parameter values
*_floatParamList = *paramSave ;
delete paramSave ;
return frame ;
}
//_____________________________________________________________________________
Bool_t RooMinuit::setLogFile(const char* inLogfile)
{
// Change the file name for logging of a RooMinuit of all MINUIT steppings
// through the parameter space. If inLogfile is null, the current log file
// is closed and logging is stopped.
if (_logfile) {
coutI(Minimization) << "RooMinuit::setLogFile: closing previous log file" << endl ;
_logfile->close() ;
delete _logfile ;
_logfile = 0 ;
}
_logfile = new ofstream(inLogfile) ;
if (!_logfile->good()) {
coutI(Minimization) << "RooMinuit::setLogFile: cannot open file " << inLogfile << endl ;
_logfile->close() ;
delete _logfile ;
_logfile= 0;
}
return kFALSE ;
}
//_____________________________________________________________________________
Double_t RooMinuit::getPdfParamVal(Int_t index)
{
// Access PDF parameter value by ordinal index (needed by MINUIT)
return ((RooRealVar*)_floatParamList->at(index))->getVal() ;
}
//_____________________________________________________________________________
Double_t RooMinuit::getPdfParamErr(Int_t index)
{
// Access PDF parameter error by ordinal index (needed by MINUIT)
return ((RooRealVar*)_floatParamList->at(index))->getError() ;
}
//_____________________________________________________________________________
Bool_t RooMinuit::setPdfParamVal(Int_t index, Double_t value, Bool_t verbose)
{
// Modify PDF parameter value by ordinal index (needed by MINUIT)
//RooRealVar* par = (RooRealVar*)_floatParamList->at(index) ;
RooRealVar* par = (RooRealVar*)_floatParamVec[index] ;
if (par->getVal()!=value) {
if (verbose) cout << par->GetName() << "=" << value << ", " ;
par->setVal(value) ;
return kTRUE ;
}
return kFALSE ;
}
//_____________________________________________________________________________
void RooMinuit::setPdfParamErr(Int_t index, Double_t value)
{
// Modify PDF parameter error by ordinal index (needed by MINUIT)
((RooRealVar*)_floatParamList->at(index))->setError(value) ;
}
//_____________________________________________________________________________
void RooMinuit::clearPdfParamAsymErr(Int_t index)
{
// Modify PDF parameter error by ordinal index (needed by MINUIT)
((RooRealVar*)_floatParamList->at(index))->removeAsymError() ;
}
//_____________________________________________________________________________
void RooMinuit::setPdfParamErr(Int_t index, Double_t loVal, Double_t hiVal)
{
// Modify PDF parameter error by ordinal index (needed by MINUIT)
((RooRealVar*)_floatParamList->at(index))->setAsymError(loVal,hiVal) ;
}
//_____________________________________________________________________________
void RooMinuit::profileStart()
{
// Start profiling timer
if (_profile) {
_timer.Start() ;
_cumulTimer.Start(kFALSE) ;
}
}
//_____________________________________________________________________________
void RooMinuit::profileStop()
{
// Stop profiling timer and report results of last session
if (_profile) {
_timer.Stop() ;
_cumulTimer.Stop() ;
coutI(Minimization) << "Command timer: " ; _timer.Print() ;
coutI(Minimization) << "Session timer: " ; _cumulTimer.Print() ;
}
}
//_____________________________________________________________________________
void RooMinuit::backProp()
{
// Transfer MINUIT fit results back into RooFit objects
Double_t val,err,vlo,vhi, eplus, eminus, eparab, globcc;
char buffer[10240];
Int_t index ;
for(index= 0; index < _nPar; index++) {
_theFitter->GetParameter(index, buffer, val, err, vlo, vhi);
setPdfParamVal(index, val);
_theFitter->GetErrors(index, eplus, eminus, eparab, globcc);
// Set the parabolic error
setPdfParamErr(index, err);
if(eplus > 0 || eminus < 0) {
// Store the asymmetric error, if it is available
setPdfParamErr(index, eminus,eplus);
} else {
// Clear the asymmetric error
clearPdfParamAsymErr(index) ;
}
}
}
//_____________________________________________________________________________
void RooMinuit::updateFloatVec()
{
_floatParamVec.clear() ;
RooFIter iter = _floatParamList->fwdIterator() ;
RooAbsArg* arg ;
_floatParamVec.resize(_floatParamList->getSize()) ;
Int_t i(0) ;
while((arg=iter.next())) {
_floatParamVec[i++] = arg ;
}
}
//_____________________________________________________________________________
void RooMinuit::applyCovarianceMatrix(TMatrixDSym& V)
{
// Apply results of given external covariance matrix. i.e. propagate its errors
// to all RRV parameter representations and give this matrix instead of the
// HESSE matrix at the next save() call
_extV = (TMatrixDSym*) V.Clone() ;
for (Int_t i=0 ; iat(i)->isConstant()) {
continue ;
}
cout << "setting parameter " << i << " error to " << sqrt((*_extV)(i,i)) << endl ;
setPdfParamErr(i, sqrt((*_extV)(i,i))) ;
}
}
void RooMinuitGlue(Int_t& /*np*/, Double_t* /*gin*/,
Double_t &f, Double_t *par, Int_t /*flag*/)
{
// Static function that interfaces minuit with RooMinuit
// Retrieve fit context and its components
RooMinuit* context = (RooMinuit*) RooMinuit::_theFitter->GetObjectFit() ;
ofstream* logf = context->logfile() ;
Double_t& maxFCN = context->maxFCN() ;
Bool_t verbose = context->_verbose ;
// Set the parameter values for this iteration
Int_t nPar= context->getNPar();
for(Int_t index= 0; index < nPar; index++) {
if (logf) (*logf) << par[index] << " " ;
context->setPdfParamVal(index, par[index],verbose);
}
// Calculate the function for these parameters
RooAbsReal::setHideOffset(kFALSE) ;
f= context->_func->getVal() ;
RooAbsReal::setHideOffset(kTRUE) ;
context->_evalCounter++ ;
if ( RooAbsPdf::evalError() || RooAbsReal::numEvalErrors()>0 || f>1e30) {
if (context->_printEvalErrors>=0) {
if (context->_doEvalErrorWall) {
oocoutW(context,Minimization) << "RooFitGlue: Minimized function has error status." << endl
<< "Returning maximum FCN so far (" << maxFCN
<< ") to force MIGRAD to back out of this region. Error log follows" << endl ;
} else {
oocoutW(context,Minimization) << "RooFitGlue: Minimized function has error status but is ignored" << endl ;
}
TIterator* iter = context->_floatParamList->createIterator() ;
RooRealVar* var ;
Bool_t first(kTRUE) ;
ooccoutW(context,Minimization) << "Parameter values: " ;
while((var=(RooRealVar*)iter->Next())) {
if (first) { first = kFALSE ; } else ooccoutW(context,Minimization) << ", " ;
ooccoutW(context,Minimization) << var->GetName() << "=" << var->getVal() ;
}
delete iter ;
ooccoutW(context,Minimization) << endl ;
RooAbsReal::printEvalErrors(ooccoutW(context,Minimization),context->_printEvalErrors) ;
ooccoutW(context,Minimization) << endl ;
}
if (context->_doEvalErrorWall) {
f = maxFCN+1 ;
}
RooAbsPdf::clearEvalError() ;
RooAbsReal::clearEvalErrorLog() ;
context->_numBadNLL++ ;
} else if (f>maxFCN) {
maxFCN = f ;
}
// Optional logging
if (logf) (*logf) << setprecision(15) << f << setprecision(4) << endl;
if (verbose) {
cout << "\nprevFCN" << (context->_func->isOffsetting()?"-offset":"") << " = " << setprecision(10) << f << setprecision(4) << " " ;
cout.flush() ;
}
}