Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooAbsMinimizerFcn.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * AL, Alfio Lazzaro, INFN Milan, alfio.lazzaro@mi.infn.it *
7 * PB, Patrick Bos, Netherlands eScience Center, p.bos@esciencecenter.nl *
8 * *
9 * *
10 * Redistribution and use in source and binary forms, *
11 * with or without modification, are permitted according to the terms *
12 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
13 *****************************************************************************/
14
15//////////////////////////////////////////////////////////////////////////////
16//
17// RooAbsMinimizerFcn is an interface class to the ROOT::Math function
18// for minimization. It contains only the "logistics" of synchronizing
19// between Minuit and RooFit. Its subclasses implement actual interfacing
20// to Minuit by subclassing IMultiGenFunction or IMultiGradFunction.
21//
22
23#include "RooAbsMinimizerFcn.h"
24
25#include "RooAbsArg.h"
26#include "RooAbsPdf.h"
27#include "RooArgSet.h"
28#include "RooDataSet.h"
29#include "RooRealVar.h"
30#include "RooAbsRealLValue.h"
31#include "RooMsgService.h"
32#include "RooNaNPacker.h"
33
34#include "TClass.h"
35#include "TMatrixDSym.h"
36
37#include <fstream>
38#include <iomanip>
39
40using std::endl, std::ofstream, std::cout;
41
42RooAbsMinimizerFcn::RooAbsMinimizerFcn(RooArgList paramList, RooMinimizer *context) : _context(context)
43{
44 // Examine parameter list
45 _floatParamList.reset(static_cast<RooArgList *>(paramList.selectByAttrib("Constant", false)));
46 if (_floatParamList->size() > 1) {
47 _floatParamList->sort();
48 }
49 _floatParamList->setName("floatParamList");
50
51 _constParamList.reset(static_cast<RooArgList *>(paramList.selectByAttrib("Constant", true)));
52 if (_constParamList->size() > 1) {
53 _constParamList->sort();
54 }
55 _constParamList->setName("constParamList");
56
57 // Remove all non-RooRealVar parameters from list (MINUIT cannot handle them)
58 for (unsigned int i = 0; i < _floatParamList->size();) { // Note: Counting loop, since removing from collection!
59 const RooAbsArg *arg = (*_floatParamList).at(i);
61 oocoutW(_context, Minimization) << "RooAbsMinimizerFcn::RooAbsMinimizerFcn: removing parameter "
62 << arg->GetName() << " from list because it is not of type RooRealVar" << endl;
63 _floatParamList->remove(*arg);
64 } else {
65 ++i;
66 }
67 }
68
69 _nDim = _floatParamList->size();
70
71 // Save snapshot of initial lists
72 _initFloatParamList = std::make_unique<RooArgList>();
73 _initConstParamList = std::make_unique<RooArgList>();
74 _floatParamList->snapshot(*_initFloatParamList, false);
75 _constParamList->snapshot(*_initConstParamList, false);
76}
77
79 : _context(other._context),
80 _maxFCN(other._maxFCN),
81 _funcOffset(other._funcOffset),
82 _numBadNLL(other._numBadNLL),
83 _evalCounter(other._evalCounter),
84 _nDim(other._nDim),
85 _optConst(other._optConst),
86 _floatParamList(std::make_unique<RooArgList>(*other._floatParamList)),
87 _constParamList(std::make_unique<RooArgList>(*other._constParamList)),
88 _initFloatParamList(std::make_unique<RooArgList>()),
89 _initConstParamList(std::make_unique<RooArgList>()),
90 _logfile(other._logfile)
91{
92 other._initFloatParamList->snapshot(*_initFloatParamList, false);
93 other._initConstParamList->snapshot(*_initConstParamList, false);
94}
95
96/// Internal function to synchronize TMinimizer with current
97/// information in RooAbsReal function parameters
98bool RooAbsMinimizerFcn::synchronizeParameterSettings(std::vector<ROOT::Fit::ParameterSettings> &parameters,
99 bool optConst)
100{
101 bool constValChange(false);
102 bool constStatChange(false);
103
104 // Handle eventual migrations from constParamList -> floatParamList
105 for (std::size_t index = 0; index < _constParamList->size(); index++) {
106
107 RooRealVar *par = dynamic_cast<RooRealVar *>(_constParamList->at(index));
108 if (!par)
109 continue;
110
111 RooRealVar *oldpar = dynamic_cast<RooRealVar *>(_initConstParamList->at(index));
112 if (!oldpar)
113 continue;
114
115 // Test if constness changed
116 if (!par->isConstant()) {
117
118 // Remove from constList, add to floatList
119 _constParamList->remove(*par);
120 _floatParamList->add(*par);
121 _initFloatParamList->addClone(*oldpar);
122 _initConstParamList->remove(*oldpar);
123 constStatChange = true;
124 _nDim++;
125
126 if (cfg().verbose) {
127 oocoutI(_context, Minimization)
128 << "RooAbsMinimizerFcn::synchronize: parameter " << par->GetName() << " is now floating." << endl;
129 }
130 }
131
132 // Test if value changed
133 if (par->getVal() != oldpar->getVal()) {
134 constValChange = true;
135 if (cfg().verbose) {
136 oocoutI(_context, Minimization)
137 << "RooAbsMinimizerFcn::synchronize: value of constant parameter " << par->GetName() << " changed from "
138 << oldpar->getVal() << " to " << par->getVal() << endl;
139 }
140 }
141 }
142
143 // Update reference list
145
146 // Synchronize MINUIT with function state
147 // Handle floatParamList
148 for (std::size_t index = 0; index < _floatParamList->size(); index++) {
149 RooRealVar *par = dynamic_cast<RooRealVar *>(_floatParamList->at(index));
150
151 if (!par)
152 continue;
153
154 double pstep(0);
155 double pmin(0);
156 double pmax(0);
157
158 if (!par->isConstant()) {
159
160 // Verify that floating parameter is indeed of type RooRealVar
161 if (!par->IsA()->InheritsFrom(RooRealVar::Class())) {
162 oocoutW(_context, Minimization) << "RooAbsMinimizerFcn::fit: Error, non-constant parameter "
163 << par->GetName() << " is not of type RooRealVar, skipping" << endl;
164 _floatParamList->remove(*par);
165 index--;
166 _nDim--;
167 continue;
168 }
169 // make sure the parameter are in dirty state to enable
170 // a real NLL computation when the minimizer calls the function the first time
171 // (see issue #7659)
172 par->setValueDirty();
173
174 // Set the limits, if not infinite
175 if (par->hasMin())
176 pmin = par->getMin();
177 if (par->hasMax())
178 pmax = par->getMax();
179
180 // Calculate step size
181 pstep = par->getError();
182 if (pstep <= 0) {
183 // Floating parameter without error estitimate
184 if (par->hasMin() && par->hasMax()) {
185 pstep = 0.1 * (pmax - pmin);
186
187 // Trim default choice of error if within 2 sigma of limit
188 if (pmax - par->getVal() < 2 * pstep) {
189 pstep = (pmax - par->getVal()) / 2;
190 } else if (par->getVal() - pmin < 2 * pstep) {
191 pstep = (par->getVal() - pmin) / 2;
192 }
193
194 // If trimming results in zero error, restore default
195 if (pstep == 0) {
196 pstep = 0.1 * (pmax - pmin);
197 }
198
199 } else {
200 pstep = 1;
201 }
202 if (cfg().verbose) {
203 oocoutW(_context, Minimization)
204 << "RooAbsMinimizerFcn::synchronize: WARNING: no initial error estimate available for "
205 << par->GetName() << ": using " << pstep << endl;
206 }
207 }
208 } else {
209 pmin = par->getVal();
210 pmax = par->getVal();
211 }
212
213 // new parameter
214 if (index >= parameters.size()) {
215
216 if (par->hasMin() && par->hasMax()) {
217 parameters.emplace_back(par->GetName(), par->getVal(), pstep, pmin, pmax);
218 } else {
219 parameters.emplace_back(par->GetName(), par->getVal(), pstep);
220 if (par->hasMin()) {
221 parameters.back().SetLowerLimit(pmin);
222 } else if (par->hasMax()) {
223 parameters.back().SetUpperLimit(pmax);
224 }
225 }
226
227 continue;
228 }
229
230 bool oldFixed = parameters[index].IsFixed();
231 double oldVar = parameters[index].Value();
232 double oldVerr = parameters[index].StepSize();
233 double oldVlo = parameters[index].LowerLimit();
234 double oldVhi = parameters[index].UpperLimit();
235
236 if (par->isConstant() && !oldFixed) {
237
238 // Parameter changes floating -> constant : update only value if necessary
239 if (oldVar != par->getVal()) {
240 parameters[index].SetValue(par->getVal());
241 if (cfg().verbose) {
242 oocoutI(_context, Minimization)
243 << "RooAbsMinimizerFcn::synchronize: value of parameter " << par->GetName() << " changed from "
244 << oldVar << " to " << par->getVal() << endl;
245 }
246 }
247 parameters[index].Fix();
248 constStatChange = true;
249 if (cfg().verbose) {
250 oocoutI(_context, Minimization)
251 << "RooAbsMinimizerFcn::synchronize: parameter " << par->GetName() << " is now fixed." << endl;
252 }
253
254 } else if (par->isConstant() && oldFixed) {
255
256 // Parameter changes constant -> constant : update only value if necessary
257 if (oldVar != par->getVal()) {
258 parameters[index].SetValue(par->getVal());
259 constValChange = true;
260
261 if (cfg().verbose) {
262 oocoutI(_context, Minimization)
263 << "RooAbsMinimizerFcn::synchronize: value of fixed parameter " << par->GetName() << " changed from "
264 << oldVar << " to " << par->getVal() << endl;
265 }
266 }
267
268 } else {
269 // Parameter changes constant -> floating
270 if (!par->isConstant() && oldFixed) {
271 parameters[index].Release();
272 constStatChange = true;
273
274 if (cfg().verbose) {
275 oocoutI(_context, Minimization)
276 << "RooAbsMinimizerFcn::synchronize: parameter " << par->GetName() << " is now floating." << endl;
277 }
278 }
279
280 // Parameter changes constant -> floating : update all if necessary
281 if (oldVar != par->getVal() || oldVlo != pmin || oldVhi != pmax || oldVerr != pstep) {
282 parameters[index].SetValue(par->getVal());
283 parameters[index].SetStepSize(pstep);
284 if (par->hasMin() && par->hasMax()) {
285 parameters[index].SetLimits(pmin, pmax);
286 } else if (par->hasMin()) {
287 parameters[index].SetLowerLimit(pmin);
288 } else if (par->hasMax()) {
289 parameters[index].SetUpperLimit(pmax);
290 }
291 }
292
293 // Inform user about changes in verbose mode
294 if (cfg().verbose) {
295 // if ierr<0, par was moved from the const list and a message was already printed
296
297 if (oldVar != par->getVal()) {
298 oocoutI(_context, Minimization)
299 << "RooAbsMinimizerFcn::synchronize: value of parameter " << par->GetName() << " changed from "
300 << oldVar << " to " << par->getVal() << endl;
301 }
302 if (oldVlo != pmin || oldVhi != pmax) {
303 oocoutI(_context, Minimization)
304 << "RooAbsMinimizerFcn::synchronize: limits of parameter " << par->GetName() << " changed from ["
305 << oldVlo << "," << oldVhi << "] to [" << pmin << "," << pmax << "]" << endl;
306 }
307
308 // If oldVerr=0, then parameter was previously fixed
309 if (oldVerr != pstep && oldVerr != 0) {
310 oocoutI(_context, Minimization)
311 << "RooAbsMinimizerFcn::synchronize: error/step size of parameter " << par->GetName()
312 << " changed from " << oldVerr << " to " << pstep << endl;
313 }
314 }
315 }
316 }
317
318 if (optConst) {
319 optimizeConstantTerms(constStatChange, constValChange);
320 }
321
322 return false;
323}
324
325bool RooAbsMinimizerFcn::Synchronize(std::vector<ROOT::Fit::ParameterSettings> &parameters)
326{
327 return synchronizeParameterSettings(parameters, _optConst);
328}
329
330/// Modify PDF parameter error by ordinal index (needed by MINUIT)
332{
333 static_cast<RooRealVar *>(_floatParamList->at(index))->setError(value);
334}
335
336/// Modify PDF parameter error by ordinal index (needed by MINUIT)
338{
339 static_cast<RooRealVar *>(_floatParamList->at(index))->removeAsymError();
340}
341
342/// Modify PDF parameter error by ordinal index (needed by MINUIT)
343void RooAbsMinimizerFcn::SetPdfParamErr(int index, double loVal, double hiVal)
344{
345 static_cast<RooRealVar *>(_floatParamList->at(index))->setAsymError(loVal, hiVal);
346}
347
348/// Transfer MINUIT fit results back into RooFit objects.
350{
351 auto const &results = _context->fitter()->Result();
352
353 for (unsigned int index = 0; index < _nDim; index++) {
354 double value = results.fParams[index];
356
357 // Set the parabolic error
358 double err = results.fErrors[index];
359 SetPdfParamErr(index, err);
360
361 double eminus = results.lowerError(index);
362 double eplus = results.upperError(index);
363
364 if (eplus > 0 || eminus < 0) {
365 // Store the asymmetric error, if it is available
366 SetPdfParamErr(index, eminus, eplus);
367 } else {
368 // Clear the asymmetric error
370 }
371 }
372}
373
374/// Change the file name for logging of a RooMinimizer of all MINUIT steppings
375/// through the parameter space. If inLogfile is null, the current log file
376/// is closed and logging is stopped.
377bool RooAbsMinimizerFcn::SetLogFile(const char *inLogfile)
378{
379 if (_logfile) {
380 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: closing previous log file" << endl;
381 _logfile->close();
382 delete _logfile;
383 _logfile = nullptr;
384 }
385 _logfile = new ofstream(inLogfile);
386 if (!_logfile->good()) {
387 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: cannot open file " << inLogfile << endl;
388 _logfile->close();
389 delete _logfile;
390 _logfile = nullptr;
391 }
392
393 return false;
394}
395
396/// Apply results of given external covariance matrix. i.e. propagate its errors
397/// to all RRV parameter representations and give this matrix instead of the
398/// HESSE matrix at the next save() call
400{
401 for (unsigned int i = 0; i < _nDim; i++) {
402 // Skip fixed parameters
403 if (_floatParamList->at(i)->isConstant()) {
404 continue;
405 }
406 SetPdfParamErr(i, sqrt(V(i, i)));
407 }
408}
409
410/// Set value of parameter i.
412{
413 auto par = static_cast<RooRealVar *>(&(*_floatParamList)[index]);
414
415 if (par->getVal() != value) {
416 if (cfg().verbose)
417 cout << par->GetName() << "=" << value << ", ";
418
419 par->setVal(value);
420 return true;
421 }
422
423 return false;
424}
425
426/// Print information about why evaluation failed.
427/// Using _printEvalErrors, the number of errors printed can be steered.
428/// Negative values disable printing.
430{
431 if (cfg().printEvalErrors < 0)
432 return;
433
434 std::ostringstream msg;
435 if (cfg().doEEWall) {
436 msg << "RooAbsMinimizerFcn: Minimized function has error status." << endl
437 << "Returning maximum FCN so far (" << _maxFCN
438 << ") to force MIGRAD to back out of this region. Error log follows.\n";
439 } else {
440 msg << "RooAbsMinimizerFcn: Minimized function has error status but is ignored.\n";
441 }
442
443 msg << "Parameter values: ";
444 for (const auto par : *_floatParamList) {
445 auto var = static_cast<const RooRealVar *>(par);
446 msg << "\t" << var->GetName() << "=" << var->getVal();
447 }
448 msg << std::endl;
449
451 ooccoutW(_context, Minimization) << msg.str() << endl;
452}
453
454/// Apply corrections on the fvalue if errors were signaled.
455///
456/// Two kinds of errors are possible: 1. infinite or nan values (the latter
457/// can be a signaling nan, using RooNaNPacker) or 2. logEvalError-type errors.
458/// Both are caught here and fvalue is updated so that Minuit in turn is nudged
459/// to move the search outside of the problematic parameter space area.
461{
462 if (!std::isfinite(fvalue) || RooAbsReal::numEvalErrors() > 0 || fvalue > 1e30) {
465 _numBadNLL++;
466
467 if (cfg().doEEWall) {
468 const double badness = RooNaNPacker::unpackNaN(fvalue);
469 fvalue = (std::isfinite(_maxFCN) ? _maxFCN : 0.) + cfg().recoverFromNaN * badness;
470 }
471 } else {
472 if (_evalCounter > 0 && _evalCounter == _numBadNLL) {
473 // This is the first time we get a valid function value; while before, the
474 // function was always invalid. For invalid cases, we returned values > 0.
475 // Now, we offset valid values such that they are < 0.
476 _funcOffset = -fvalue;
477 }
478 fvalue += _funcOffset;
479 _maxFCN = std::max(fvalue, _maxFCN);
480 }
481 return fvalue;
482}
483
485{
486 _evalCounter++;
487}
488
490{
491 auto ctx = _context->makeEvalErrorContext();
492
493 if (_optConst && !flag) {
494 if (_context->getPrintLevel() > -1) {
495 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization"
496 << endl;
497 }
499 _optConst = flag;
500 } else if (!_optConst && flag) {
501 if (_context->getPrintLevel() > -1) {
502 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: activating const optimization"
503 << endl;
504 }
506 _optConst = flag;
507 } else if (_optConst && flag) {
508 if (_context->getPrintLevel() > -1) {
509 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: const optimization already active"
510 << endl;
511 }
512 } else {
513 if (_context->getPrintLevel() > -1) {
514 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: const optimization wasn't active"
515 << endl;
516 }
517 }
518}
519
520void RooAbsMinimizerFcn::optimizeConstantTerms(bool constStatChange, bool constValChange)
521{
522 auto ctx = _context->makeEvalErrorContext();
523
524 if (constStatChange) {
525
526 oocoutI(_context, Minimization)
527 << "RooAbsMinimizerFcn::optimizeConstantTerms: set of constant parameters changed, rerunning const optimizer"
528 << endl;
530 } else if (constValChange) {
531 oocoutI(_context, Minimization)
532 << "RooAbsMinimizerFcn::optimizeConstantTerms: constant parameter values changed, rerunning const optimizer"
533 << endl;
535 }
536}
#define oocoutW(o, a)
#define oocoutI(o, a)
#define ooccoutW(o, a)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:79
bool isConstant() const
Check if the "Constant" attribute is set.
Definition RooAbsArg.h:335
void setValueDirty()
Mark the element dirty. This forces a re-evaluation when a value is requested.
Definition RooAbsArg.h:462
RooAbsCollection * selectByAttrib(const char *name, bool value) const
Create a subset of the current collection, consisting only of those elements with the specified attri...
void setOptimizeConst(Int_t flag)
std::unique_ptr< RooArgList > _floatParamList
bool SetLogFile(const char *inLogfile)
Change the file name for logging of a RooMinimizer of all MINUIT steppings through the parameter spac...
RooAbsMinimizerFcn(RooArgList paramList, RooMinimizer *context)
virtual bool Synchronize(std::vector< ROOT::Fit::ParameterSettings > &parameters)
Like synchronizeParameterSettings, Synchronize informs Minuit through its parameter_settings vector o...
double applyEvalErrorHandling(double fvalue) const
Apply corrections on the fvalue if errors were signaled.
virtual void setOptimizeConstOnFunction(RooAbsArg::ConstOpCode opcode, bool doAlsoTrackingOpt)=0
This function must be overridden in the derived class to pass on constant term optimization configura...
RooMinimizer::Config const & cfg() const
void optimizeConstantTerms(bool constStatChange, bool constValChange)
void printEvalErrors() const
Print information about why evaluation failed.
void ClearPdfParamAsymErr(Int_t index)
Modify PDF parameter error by ordinal index (needed by MINUIT)
std::ofstream * _logfile
void SetPdfParamErr(Int_t index, double value)
Modify PDF parameter error by ordinal index (needed by MINUIT)
bool synchronizeParameterSettings(std::vector< ROOT::Fit::ParameterSettings > &parameters, bool optConst)
Informs Minuit through its parameter_settings vector of RooFit parameter properties.
void ApplyCovarianceMatrix(TMatrixDSym &V)
Set different external covariance matrix.
std::unique_ptr< RooArgList > _initConstParamList
std::unique_ptr< RooArgList > _constParamList
void BackProp()
Put Minuit results back into RooFit objects.
bool SetPdfParamVal(int index, double value) const
Set value of parameter i.
std::unique_ptr< RooArgList > _initFloatParamList
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
bool hasMax(const char *name=nullptr) const
Check if variable has an upper bound.
static TClass * Class()
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
bool hasMin(const char *name=nullptr) const
Check if variable has a lower bound.
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
static Int_t numEvalErrors()
Return the number of logged evaluation errors since the last clearing.
static void printEvalErrors(std::ostream &os=std::cout, Int_t maxPerNode=10000000)
Print all outstanding logged evaluation error on the given ostream.
static void clearEvalErrorLog()
Clear the stack of evaluation error messages.
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
Wrapper class around ROOT::Math::Minimizer that provides a seamless interface between the minimizer f...
int getPrintLevel()
Get the MINUIT internal printing level.
auto fitter()
Return underlying ROOT fitter object.
std::unique_ptr< RooAbsReal::EvalErrorContext > makeEvalErrorContext() const
Variable that can be changed from the outside.
Definition RooRealVar.h:37
static TClass * Class()
double getError() const
Definition RooRealVar.h:58
TClass * IsA() const override
Definition RooRealVar.h:173
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4874
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
TClass * IsA() const override
Definition TNamed.h:58
static float unpackNaN(double val)
If val is NaN and a this NaN has been tagged as containing a payload, unpack the float from the manti...