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 "RooMsgService.h"
31#include "RooNaNPacker.h"
32
33#include "TClass.h"
34#include "TMatrixDSym.h"
35
36#include <fstream>
37#include <iomanip>
38
39RooAbsMinimizerFcn::RooAbsMinimizerFcn(RooArgList paramList, RooMinimizer *context) : _context{context}
40{
41 _allParams.add(paramList);
42
44
45 // Examine parameter list
46 for (RooAbsArg *param : _allParams) {
47
48 // Treat all non-RooRealVar parameters as constants (MINUIT cannot handle them)
49 if (!param->isConstant() && !canBeFloating(*param)) {
50 oocoutW(_context, Minimization) << "RooAbsMinimizerFcn::RooAbsMinimizerFcn: removing parameter "
51 << param->GetName() << " from list because it is not of type RooRealVar"
52 << std::endl;
53 }
54 }
55
57
58 std::size_t iParam = 0;
59 for (RooAbsArg *param : _allParamsInit) {
60 if (!treatAsConstant(*param)) {
61 _floatableParamIndices.push_back(iParam);
62 }
63 ++iParam;
64 }
65}
66
67/// Internal function to synchronize TMinimizer with current
68/// information in RooAbsReal function parameters
69bool RooAbsMinimizerFcn::synchronizeParameterSettings(std::vector<ROOT::Fit::ParameterSettings> &parameters,
70 bool optConst)
71{
72 // Synchronize MINUIT with function state
73
74 for (std::size_t i = 0; i < _allParams.size(); ++i) {
76 std::stringstream ss;
77 ss << "RooMinimzer: the parameter named " << _allParams[i].GetName()
78 << " is not constant anymore, but it was constant at the time where the RooMinimizer was constructed."
79 " This is illegal. The other way around is supported: you can always change the constant flag of "
80 "parameters that were floating at the time the minimizer was instantiated.";
81 oocxcoutF(nullptr, LinkStateMgmt) << ss.str() << std::endl;
82 throw std::runtime_error(ss.str());
83 }
84 }
85
86 std::vector<ROOT::Fit::ParameterSettings> oldParameters = parameters;
87 parameters.clear();
88
89 for (std::size_t index = 0; index < getNDim(); index++) {
90
91 auto &par = floatableParam(index);
92
93 // make sure the parameter are in dirty state to enable
94 // a real NLL computation when the minimizer calls the function the first time
95 // (see issue #7659)
96 par.setValueDirty();
97
98 // Set the limits, if not infinite
99 double pmin = par.hasMin() ? par.getMin() : 0.0;
100 double pmax = par.hasMax() ? par.getMax() : 0.0;
101
102 // Calculate step size
103 double pstep = par.getError();
104 if (pstep <= 0) {
105 // Floating parameter without error estimate
106 if (par.hasMin() && par.hasMax()) {
107 pstep = 0.1 * (pmax - pmin);
108
109 // Trim default choice of error if within 2 sigma of limit
110 if (pmax - par.getVal() < 2 * pstep) {
111 pstep = (pmax - par.getVal()) / 2;
112 } else if (par.getVal() - pmin < 2 * pstep) {
113 pstep = (par.getVal() - pmin) / 2;
114 }
115
116 // If trimming results in zero error, restore default
117 if (pstep == 0) {
118 pstep = 0.1 * (pmax - pmin);
119 }
120
121 } else {
122 pstep = 1;
123 }
124 if (cfg().verbose) {
125 oocoutW(_context, Minimization)
126 << "RooAbsMinimizerFcn::synchronize: WARNING: no initial error estimate available for " << par.GetName()
127 << ": using " << pstep << std::endl;
128 }
129 }
130
131 if (par.hasMin() && par.hasMax()) {
132 parameters.emplace_back(par.GetName(), par.getVal(), pstep, pmin, pmax);
133 } else {
134 parameters.emplace_back(par.GetName(), par.getVal(), pstep);
135 if (par.hasMin()) {
136 parameters.back().SetLowerLimit(pmin);
137 } else if (par.hasMax()) {
138 parameters.back().SetUpperLimit(pmax);
139 }
140 }
141
142 par.isConstant() ? parameters.back().Fix() : parameters.back().Release();
143 }
144
145 if (optConst) {
146 bool constStateChange = false;
147 bool constValChange = false;
148 for (std::size_t i = 0; i < oldParameters.size(); ++i) {
149 auto const &newParam = parameters[i];
150 auto const &oldParam = oldParameters[i];
151 constStateChange &= (newParam.IsFixed() != oldParam.IsFixed());
152 constValChange &= (newParam.IsFixed() && (newParam.Value() != oldParam.Value()));
153 }
154 optimizeConstantTerms(constStateChange, constValChange);
155 }
156
157 return false;
158}
159
160bool RooAbsMinimizerFcn::Synchronize(std::vector<ROOT::Fit::ParameterSettings> &parameters)
161{
162 return synchronizeParameterSettings(parameters, _optConst);
163}
164
165/// Transfer MINUIT fit results back into RooFit objects.
167{
168 auto const &results = _context->fitter()->Result();
169
170 for (std::size_t index = 0; index < getNDim(); index++) {
171
172 auto &param = floatableParam(index);
173
174 double value = results.fParams[index];
176
177 // Set the parabolic error
178 double err = results.fErrors[index];
179 param.setError(err);
180
181 double eminus = results.lowerError(index);
182 double eplus = results.upperError(index);
183
184 if (eplus > 0 || eminus < 0) {
185 // Store the asymmetric error, if it is available
186 param.setAsymError(eminus, eplus);
187 } else {
188 // Clear the asymmetric error
189 param.removeAsymError();
190 }
191 }
192}
193
194/// Change the file name for logging of a RooMinimizer of all MINUIT steppings
195/// through the parameter space. If inLogfile is null, the current log file
196/// is closed and logging is stopped.
197bool RooAbsMinimizerFcn::SetLogFile(const char *inLogfile)
198{
199 if (_logfile) {
200 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: closing previous log file" << std::endl;
201 _logfile->close();
202 delete _logfile;
203 _logfile = nullptr;
204 }
205 _logfile = new std::ofstream(inLogfile);
206 if (!_logfile->good()) {
207 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: cannot open file " << inLogfile << std::endl;
208 _logfile->close();
209 delete _logfile;
210 _logfile = nullptr;
211 }
212
213 return false;
214}
215
216/// Apply results of given external covariance matrix. i.e. propagate its errors
217/// to all RRV parameter representations and give this matrix instead of the
218/// HESSE matrix at the next save() call
220{
221 for (unsigned int i = 0; i < getNDim(); i++) {
222 floatableParam(i).setError(std::sqrt(V(i, i)));
223 }
224}
225
226/// Set value of parameter i.
228{
229 auto &par = floatableParam(index);
230
231 if (par.getVal() != value) {
232 if (cfg().verbose)
233 std::cout << par.GetName() << "=" << value << ", ";
234
235 par.setVal(value);
236 return true;
237 }
238
239 return false;
240}
241
242/// Print information about why evaluation failed.
243/// Using _printEvalErrors, the number of errors printed can be steered.
244/// Negative values disable printing.
246{
247 if (cfg().printEvalErrors < 0)
248 return;
249
250 std::ostringstream msg;
251 if (cfg().doEEWall) {
252 msg << "RooAbsMinimizerFcn: Minimized function has error status." << std::endl
253 << "Returning maximum FCN so far (" << _maxFCN
254 << ") to force MIGRAD to back out of this region. Error log follows.\n";
255 } else {
256 msg << "RooAbsMinimizerFcn: Minimized function has error status but is ignored.\n";
257 }
258
259 msg << "Parameter values: ";
260 for (std::size_t i = 0; i < getNDim(); ++i) {
261 auto &var = floatableParam(i);
262 msg << "\t" << var.GetName() << "=" << var.getVal();
263 }
264 msg << std::endl;
265
267 ooccoutW(_context, Minimization) << msg.str() << std::endl;
268}
269
270/// Apply corrections on the fvalue if errors were signaled.
271///
272/// Two kinds of errors are possible: 1. infinite or nan values (the latter
273/// can be a signaling nan, using RooNaNPacker) or 2. logEvalError-type errors.
274/// Both are caught here and fvalue is updated so that Minuit in turn is nudged
275/// to move the search outside of the problematic parameter space area.
277{
278 if (!std::isfinite(fvalue) || RooAbsReal::numEvalErrors() > 0 || fvalue > 1e30) {
281 _numBadNLL++;
282
283 if (cfg().doEEWall) {
284 const double badness = RooNaNPacker::unpackNaN(fvalue);
285 fvalue = (std::isfinite(_maxFCN) ? _maxFCN : 0.) + cfg().recoverFromNaN * badness;
286 }
287 } else {
288 if (_evalCounter > 0 && _evalCounter == _numBadNLL) {
289 // This is the first time we get a valid function value; while before, the
290 // function was always invalid. For invalid cases, we returned values > 0.
291 // Now, we offset valid values such that they are < 0.
292 _funcOffset = -fvalue;
293 }
294 fvalue += _funcOffset;
295 _maxFCN = std::max(fvalue, _maxFCN);
296 }
297 return fvalue;
298}
299
301{
302 _evalCounter++;
303}
304
306{
307 auto ctx = _context->makeEvalErrorContext();
308
309 if (_optConst && !flag) {
310 if (_context->getPrintLevel() > -1) {
311 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization"
312 << std::endl;
313 }
315 _optConst = flag;
316 } else if (!_optConst && flag) {
317 if (_context->getPrintLevel() > -1) {
318 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: activating const optimization"
319 << std::endl;
320 }
322 _optConst = flag;
323 } else if (_optConst && flag) {
324 if (_context->getPrintLevel() > -1) {
325 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: const optimization already active"
326 << std::endl;
327 }
328 } else {
329 if (_context->getPrintLevel() > -1) {
330 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setOptimizeConst: const optimization wasn't active"
331 << std::endl;
332 }
333 }
334}
335
336void RooAbsMinimizerFcn::optimizeConstantTerms(bool constStatChange, bool constValChange)
337{
338 auto ctx = _context->makeEvalErrorContext();
339
340 if (constStatChange) {
341
342 oocoutI(_context, Minimization)
343 << "RooAbsMinimizerFcn::optimizeConstantTerms: set of constant parameters changed, rerunning const optimizer"
344 << std::endl;
346 } else if (constValChange) {
347 oocoutI(_context, Minimization)
348 << "RooAbsMinimizerFcn::optimizeConstantTerms: constant parameter values changed, rerunning const optimizer"
349 << std::endl;
351 }
352}
353
355{
356 RooArgList out;
357 for (RooAbsArg *param : _allParams) {
358 if (!treatAsConstant(*param))
359 out.add(*param);
360 }
361 return out;
362}
363
365{
366 RooArgList out;
367 for (RooAbsArg *param : _allParams) {
368 if (treatAsConstant(*param))
369 out.add(*param);
370 }
371 return out;
372}
373
375{
376 RooArgList initFloatableParams;
377
378 for (RooAbsArg *param : _allParamsInit) {
379 if (!treatAsConstant(*param))
380 initFloatableParams.add(*param);
381 }
382
383 // Make sure we only return the initial parameters
384 // corresponding to currently floating parameters.
385 RooArgList out;
386 initFloatableParams.selectCommon(floatParams(), out);
387
388 return out;
389}
#define oocoutW(o, a)
#define oocoutI(o, a)
#define ooccoutW(o, a)
#define oocxcoutF(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:77
RooAbsCollection * snapshot(bool deepCopy=true) const
Take a snap shot of current collection contents.
const char * GetName() const override
Returns name of object.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
bool selectCommon(const RooAbsCollection &refColl, RooAbsCollection &outColl) const
Create a subset of the current collection, consisting only of those elements that are contained as we...
std::vector< std::size_t > _floatableParamIndices
void setOptimizeConst(Int_t flag)
static bool canBeFloating(RooAbsArg const &arg)
static bool treatAsConstant(RooAbsArg const &arg)
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...
RooArgList constParams() const
RooMinimizer::Config const & cfg() const
void optimizeConstantTerms(bool constStatChange, bool constValChange)
void printEvalErrors() const
Print information about why evaluation failed.
std::ofstream * _logfile
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.
RooArgList initFloatParams() const
RooRealVar & floatableParam(std::size_t i) const
void BackProp()
Put Minuit results back into RooFit objects.
bool SetPdfParamVal(int index, double value) const
Set value of parameter i.
RooArgList floatParams() const
unsigned int getNDim() const
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
void setError(double value)
Definition RooRealVar.h:60
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...