Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
RooAbsMinimizerFcn.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*****************************************************************************
4 * Project: RooFit *
5 * Package: RooFitCore *
6 * @(#)root/roofitcore:$Id$
7 * Authors: *
8 * AL, Alfio Lazzaro, INFN Milan, alfio.lazzaro@mi.infn.it *
9 * PB, Patrick Bos, Netherlands eScience Center, p.bos@esciencecenter.nl *
10 * *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17//////////////////////////////////////////////////////////////////////////////
18//
19// RooAbsMinimizerFcn is an interface class to the ROOT::Math function
20// for minimization. It contains only the "logistics" of synchronizing
21// between Minuit and RooFit. Its subclasses implement actual interfacing
22// to Minuit by subclassing IMultiGenFunction or IMultiGradFunction.
23//
24
25#include "RooAbsMinimizerFcn.h"
26
27#include "RooAbsArg.h"
28#include "RooAbsPdf.h"
29#include "RooArgSet.h"
30#include "RooDataSet.h"
31#include "RooRealVar.h"
32#include "RooMsgService.h"
33#include "RooNaNPacker.h"
34
35#include "TClass.h"
36#include "TMatrixDSym.h"
37
38#include <fstream>
39#include <iomanip>
40
41RooAbsMinimizerFcn::RooAbsMinimizerFcn(RooArgList paramList, RooMinimizer *context) : _context{context}
42{
43 _allParams.add(paramList);
44
46
47 // Examine parameter list
48 for (RooAbsArg *param : _allParams) {
49
50 // Treat all non-RooRealVar parameters as constants (MINUIT cannot handle them)
51 if (!param->isConstant() && !canBeFloating(*param)) {
52 oocoutW(_context, Minimization) << "RooAbsMinimizerFcn::RooAbsMinimizerFcn: removing parameter "
53 << param->GetName() << " from list because it is not of type RooRealVar"
54 << std::endl;
55 }
56 }
57
58 _allParams.snapshot(_allParamsInit, false);
59
60 std::size_t iParam = 0;
61 for (RooAbsArg *param : _allParamsInit) {
62 if (!treatAsConstant(*param)) {
64 }
65 ++iParam;
66 }
67}
68
69/// Internal function to synchronize TMinimizer with current
70/// information in RooAbsReal function parameters
71bool RooAbsMinimizerFcn::synchronizeParameterSettings(std::vector<ROOT::Fit::ParameterSettings> &parameters,
72 bool optConst)
73{
74 // Synchronize MINUIT with function state
75
76 for (std::size_t i = 0; i < _allParams.size(); ++i) {
78 std::stringstream ss;
79 ss << "RooMinimzer: the parameter named " << _allParams[i].GetName()
80 << " is not constant anymore, but it was constant at the time where the RooMinimizer was constructed."
81 " This is illegal. The other way around is supported: you can always change the constant flag of "
82 "parameters that were floating at the time the minimizer was instantiated.";
83 oocxcoutF(nullptr, LinkStateMgmt) << ss.str() << std::endl;
84 throw std::runtime_error(ss.str());
85 }
86 }
87
88 std::vector<ROOT::Fit::ParameterSettings> oldParameters = parameters;
89 parameters.clear();
90
91 for (std::size_t index = 0; index < getNDim(); index++) {
92
93 auto &par = floatableParam(index);
94
95 // make sure the parameter are in dirty state to enable
96 // a real NLL computation when the minimizer calls the function the first time
97 // (see issue #7659)
98 par.setValueDirty();
99
100 // Set the limits, if not infinite
101 double pmin = par.hasMin() ? par.getMin() : 0.0;
102 double pmax = par.hasMax() ? par.getMax() : 0.0;
103
104 // Calculate step size
105 double pstep = par.getError();
106 if (pstep <= 0) {
107 // Floating parameter without error estimate
108 if (par.hasMin() && par.hasMax()) {
109 pstep = 0.1 * (pmax - pmin);
110
111 // Trim default choice of error if within 2 sigma of limit
112 if (pmax - par.getVal() < 2 * pstep) {
113 pstep = (pmax - par.getVal()) / 2;
114 } else if (par.getVal() - pmin < 2 * pstep) {
115 pstep = (par.getVal() - pmin) / 2;
116 }
117
118 // If trimming results in zero error, restore default
119 if (pstep == 0) {
120 pstep = 0.1 * (pmax - pmin);
121 }
122
123 } else {
124 pstep = 1;
125 }
126 if (cfg().verbose) {
127 oocoutW(_context, Minimization)
128 << "RooAbsMinimizerFcn::synchronize: WARNING: no initial error estimate available for " << par.GetName()
129 << ": using " << pstep << std::endl;
130 }
131 }
132
133 if (par.hasMin() && par.hasMax()) {
134 parameters.emplace_back(par.GetName(), par.getVal(), pstep, pmin, pmax);
135 } else {
136 parameters.emplace_back(par.GetName(), par.getVal(), pstep);
137 if (par.hasMin()) {
138 parameters.back().SetLowerLimit(pmin);
139 } else if (par.hasMax()) {
140 parameters.back().SetUpperLimit(pmax);
141 }
142 }
143
144 par.isConstant() ? parameters.back().Fix() : parameters.back().Release();
145 }
146
147 if (optConst) {
148 bool constStateChange = false;
149 bool constValChange = false;
150 for (std::size_t i = 0; i < oldParameters.size(); ++i) {
151 auto const &newParam = parameters[i];
152 auto const &oldParam = oldParameters[i];
153 constStateChange &= (newParam.IsFixed() != oldParam.IsFixed());
154 constValChange &= (newParam.IsFixed() && (newParam.Value() != oldParam.Value()));
155 }
157 }
158
159 return false;
160}
161
162bool RooAbsMinimizerFcn::Synchronize(std::vector<ROOT::Fit::ParameterSettings> &parameters)
163{
164 return synchronizeParameterSettings(parameters, _optConst);
165}
166
167/// Transfer MINUIT fit results back into RooFit objects.
168void RooAbsMinimizerFcn::BackProp()
169{
170 auto const &results = _context->fitter()->Result();
171
172 for (std::size_t index = 0; index < getNDim(); index++) {
173
174 auto &param = floatableParam(index);
175
176 double value = results.fParams[index];
178
179 // Set the parabolic error
180 double err = results.fErrors[index];
181 param.setError(err);
182
183 double eminus = results.lowerError(index);
184 double eplus = results.upperError(index);
185
186 if (eplus > 0 || eminus < 0) {
187 // Store the asymmetric error, if it is available
188 param.setAsymError(eminus, eplus);
189 } else {
190 // Clear the asymmetric error
191 param.removeAsymError();
192 }
193 }
194}
195
196/// Change the file name for logging of a RooMinimizer of all MINUIT steppings
197/// through the parameter space. If inLogfile is null, the current log file
198/// is closed and logging is stopped.
199bool RooAbsMinimizerFcn::SetLogFile(const char *inLogfile)
200{
201 if (_logfile) {
202 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: closing previous log file" << std::endl;
203 _logfile->close();
204 delete _logfile;
205 _logfile = nullptr;
206 }
207 _logfile = new std::ofstream(inLogfile);
208 if (!_logfile->good()) {
209 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: cannot open file " << inLogfile << std::endl;
210 _logfile->close();
211 delete _logfile;
212 _logfile = nullptr;
213 }
214
215 return false;
216}
217
218/// Apply results of given external covariance matrix. i.e. propagate its errors
219/// to all RRV parameter representations and give this matrix instead of the
220/// HESSE matrix at the next save() call
221void RooAbsMinimizerFcn::ApplyCovarianceMatrix(TMatrixDSym &V)
222{
223 for (unsigned int i = 0; i < getNDim(); i++) {
224 floatableParam(i).setError(std::sqrt(V(i, i)));
225 }
226}
227
228/// Set value of parameter i.
229bool RooAbsMinimizerFcn::SetPdfParamVal(int index, double value) const
230{
231 auto &par = floatableParam(index);
232
233 if (par.getVal() != value) {
234 if (cfg().verbose)
235 std::cout << par.GetName() << "=" << value << ", ";
236
237 par.setVal(value);
238 return true;
239 }
240
241 return false;
242}
243
244/// Print information about why evaluation failed.
245/// Using _printEvalErrors, the number of errors printed can be steered.
246/// Negative values disable printing.
247void RooAbsMinimizerFcn::printEvalErrors() const
248{
249 if (cfg().printEvalErrors < 0)
250 return;
251
252 std::ostringstream msg;
253 if (cfg().doEEWall) {
254 msg << "RooAbsMinimizerFcn: Minimized function has error status." << std::endl
255 << "Returning maximum FCN so far (" << _maxFCN
256 << ") to force MIGRAD to back out of this region. Error log follows.\n";
257 } else {
258 msg << "RooAbsMinimizerFcn: Minimized function has error status but is ignored.\n";
259 }
260
261 msg << "Parameter values: ";
262 for (std::size_t i = 0; i < getNDim(); ++i) {
263 auto &var = floatableParam(i);
264 msg << "\t" << var.GetName() << "=" << var.getVal();
265 }
266 msg << std::endl;
267
268 RooAbsReal::printEvalErrors(msg, cfg().printEvalErrors);
269 ooccoutW(_context, Minimization) << msg.str() << std::endl;
270}
271
272/// Apply corrections on the fvalue if errors were signaled.
273///
274/// Two kinds of errors are possible: 1. infinite or nan values (the latter
275/// can be a signaling nan, using RooNaNPacker) or 2. logEvalError-type errors.
276/// Both are caught here and fvalue is updated so that Minuit in turn is nudged
277/// to move the search outside of the problematic parameter space area.
278double RooAbsMinimizerFcn::applyEvalErrorHandling(double fvalue) const
279{
280 if (!std::isfinite(fvalue) || RooAbsReal::numEvalErrors() > 0 || fvalue > 1e30) {
281 printEvalErrors();
283 _numBadNLL++;
284
285 if (cfg().doEEWall) {
286 const double badness = RooNaNPacker::unpackNaN(fvalue);
287 fvalue = (std::isfinite(_maxFCN) ? _maxFCN : 0.) + cfg().recoverFromNaN * badness;
288 }
289 } else {
290 if (_evalCounter > 0 && _evalCounter == _numBadNLL) {
291 // This is the first time we get a valid function value; while before, the
292 // function was always invalid. For invalid cases, we returned values > 0.
293 // Now, we offset valid values such that they are < 0.
295 }
297 _maxFCN = std::max(fvalue, _maxFCN);
298 }
299 return fvalue;
300}
301
302void RooAbsMinimizerFcn::finishDoEval() const
303{
304 _evalCounter++;
305}
306
307void RooAbsMinimizerFcn::setOptimizeConst(int flag)
308{
309 auto ctx = _context->makeEvalErrorContext();
310
311 if (_optConst && !flag) {
312 if (_context->getPrintLevel() > -1) {
313 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization"
314 << std::endl;
315 }
316 setOptimizeConstOnFunction(RooAbsArg::DeActivate, true);
317 _optConst = flag;
318 } else if (!_optConst && flag) {
319 if (_context->getPrintLevel() > -1) {
320 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: activating const optimization"
321 << std::endl;
322 }
323 setOptimizeConstOnFunction(RooAbsArg::Activate, flag > 1);
324 _optConst = flag;
325 } else if (_optConst && flag) {
326 if (_context->getPrintLevel() > -1) {
327 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: const optimization already active"
328 << std::endl;
329 }
330 } else {
331 if (_context->getPrintLevel() > -1) {
332 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: const optimization wasn't active"
333 << std::endl;
334 }
335 }
336}
337
338void RooAbsMinimizerFcn::optimizeConstantTerms(bool constStatChange, bool constValChange)
339{
340 auto ctx = _context->makeEvalErrorContext();
341
342 if (constStatChange) {
343
344 oocoutI(_context, Minimization)
345 << "RooAbsMinimizerFcn::optimizeConstantTerms: set of constant parameters changed, rerunning const optimizer"
346 << std::endl;
347 setOptimizeConstOnFunction(RooAbsArg::ConfigChange, true);
348 } else if (constValChange) {
349 oocoutI(_context, Minimization)
350 << "RooAbsMinimizerFcn::optimizeConstantTerms: constant parameter values changed, rerunning const optimizer"
351 << std::endl;
352 setOptimizeConstOnFunction(RooAbsArg::ValueChange, true);
353 }
354}
355
356RooArgList RooAbsMinimizerFcn::floatParams() const
357{
358 RooArgList out;
359 for (RooAbsArg *param : _allParams) {
360 if (!treatAsConstant(*param))
361 out.add(*param);
362 }
363 return out;
364}
365
366RooArgList RooAbsMinimizerFcn::constParams() const
367{
368 RooArgList out;
369 for (RooAbsArg *param : _allParams) {
370 if (treatAsConstant(*param))
371 out.add(*param);
372 }
373 return out;
374}
375
376RooArgList RooAbsMinimizerFcn::initFloatParams() const
377{
379
380 for (RooAbsArg *param : _allParamsInit) {
381 if (!treatAsConstant(*param))
382 initFloatableParams.add(*param);
383 }
384
385 // Make sure we only return the initial parameters
386 // corresponding to currently floating parameters.
387 RooArgList out;
388 initFloatableParams.selectCommon(floatParams(), out);
389
390 return out;
391}
392
393/// \endcond
#define oocoutW(o, a)
#define oocoutI(o, a)
#define ooccoutW(o, a)
#define oocxcoutF(o, a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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:77
const char * GetName() const override
Returns name of object.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
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...
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...