Logo ROOT  
Reference Guide
 
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{
73 // Synchronize MINUIT with function state
74
75 for (std::size_t i = 0; i < _allParams.size(); ++i) {
77 std::stringstream ss;
78 ss << "RooMinimzer: the parameter named " << _allParams[i].GetName()
79 << " is not constant anymore, but it was constant at the time where the RooMinimizer was constructed."
80 " This is illegal. The other way around is supported: you can always change the constant flag of "
81 "parameters that were floating at the time the minimizer was instantiated.";
82 oocxcoutF(nullptr, LinkStateMgmt) << ss.str() << std::endl;
83 throw std::runtime_error(ss.str());
84 }
85 }
86
87 std::vector<ROOT::Fit::ParameterSettings> oldParameters = parameters;
88 parameters.clear();
89
90 for (std::size_t index = 0; index < getNDim(); index++) {
91
92 auto &par = floatableParam(index);
93
94 // make sure the parameter are in dirty state to enable
95 // a real NLL computation when the minimizer calls the function the first time
96 // (see issue #7659)
97 par.setValueDirty();
98
99 // Set the limits, if not infinite
100 double pmin = par.hasMin() ? par.getMin() : 0.0;
101 double pmax = par.hasMax() ? par.getMax() : 0.0;
102
103 // Calculate step size
104 double pstep = par.getError();
105 if (pstep <= 0) {
106 // Floating parameter without error estimate
107 if (par.hasMin() && par.hasMax()) {
108 pstep = 0.1 * (pmax - pmin);
109
110 // Trim default choice of error if within 2 sigma of limit
111 if (pmax - par.getVal() < 2 * pstep) {
112 pstep = (pmax - par.getVal()) / 2;
113 } else if (par.getVal() - pmin < 2 * pstep) {
114 pstep = (par.getVal() - pmin) / 2;
115 }
116
117 // If trimming results in zero error, restore default
118 if (pstep == 0) {
119 pstep = 0.1 * (pmax - pmin);
120 }
121
122 } else {
123 pstep = 1;
124 }
125 if (cfg().verbose) {
126 oocoutW(_context, Minimization)
127 << "RooAbsMinimizerFcn::synchronize: WARNING: no initial error estimate available for " << par.GetName()
128 << ": using " << pstep << std::endl;
129 }
130 }
131
132 if (par.hasMin() && par.hasMax()) {
133 parameters.emplace_back(par.GetName(), par.getVal(), pstep, pmin, pmax);
134 } else {
135 parameters.emplace_back(par.GetName(), par.getVal(), pstep);
136 if (par.hasMin()) {
137 parameters.back().SetLowerLimit(pmin);
138 } else if (par.hasMax()) {
139 parameters.back().SetUpperLimit(pmax);
140 }
141 }
142
143 par.isConstant() ? parameters.back().Fix() : parameters.back().Release();
144 }
145
146 return false;
147}
148
149bool RooAbsMinimizerFcn::Synchronize(std::vector<ROOT::Fit::ParameterSettings> &parameters)
150{
151 return synchronizeParameterSettings(parameters);
152}
153
154/// Transfer MINUIT fit results back into RooFit objects.
155void RooAbsMinimizerFcn::BackProp()
156{
157 auto const &results = _context->fitter()->Result();
158
159 for (std::size_t index = 0; index < getNDim(); index++) {
160
161 auto &param = floatableParam(index);
162
163 double value = results.fParams[index];
165
166 // Set the parabolic error
167 double err = results.fErrors[index];
168 param.setError(err);
169
170 double eminus = results.lowerError(index);
171 double eplus = results.upperError(index);
172
173 if (eplus > 0 || eminus < 0) {
174 // Store the asymmetric error, if it is available
175 param.setAsymError(eminus, eplus);
176 } else {
177 // Clear the asymmetric error
178 param.removeAsymError();
179 }
180 }
181}
182
183/// Change the file name for logging of a RooMinimizer of all MINUIT steppings
184/// through the parameter space. If inLogfile is null, the current log file
185/// is closed and logging is stopped.
186bool RooAbsMinimizerFcn::SetLogFile(const char *inLogfile)
187{
188 if (_logfile) {
189 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: closing previous log file" << std::endl;
190 _logfile->close();
191 delete _logfile;
192 _logfile = nullptr;
193 }
194 _logfile = new std::ofstream(inLogfile);
195 if (!_logfile->good()) {
196 oocoutI(_context, Minimization) << "RooAbsMinimizerFcn::setLogFile: cannot open file " << inLogfile << std::endl;
197 _logfile->close();
198 delete _logfile;
199 _logfile = nullptr;
200 }
201
202 return false;
203}
204
205/// Apply results of given external covariance matrix. i.e. propagate its errors
206/// to all RRV parameter representations and give this matrix instead of the
207/// HESSE matrix at the next save() call
208void RooAbsMinimizerFcn::ApplyCovarianceMatrix(TMatrixDSym &V)
209{
210 for (unsigned int i = 0; i < getNDim(); i++) {
211 floatableParam(i).setError(std::sqrt(V(i, i)));
212 }
213}
214
215/// Set value of parameter i.
216bool RooAbsMinimizerFcn::SetPdfParamVal(int index, double value) const
217{
218 auto &par = floatableParam(index);
219
220 if (par.getVal() != value) {
221 if (cfg().verbose)
222 std::cout << par.GetName() << "=" << value << ", ";
223
224 par.setVal(value);
225 return true;
226 }
227
228 return false;
229}
230
231/// Print information about why evaluation failed.
232/// Using _printEvalErrors, the number of errors printed can be steered.
233/// Negative values disable printing.
234void RooAbsMinimizerFcn::printEvalErrors() const
235{
236 if (cfg().printEvalErrors < 0)
237 return;
238
239 std::ostringstream msg;
240 if (cfg().doEEWall) {
241 msg << "RooAbsMinimizerFcn: Minimized function has error status." << std::endl
242 << "Returning maximum FCN so far (" << _maxFCN
243 << ") to force MIGRAD to back out of this region. Error log follows.\n";
244 } else {
245 msg << "RooAbsMinimizerFcn: Minimized function has error status but is ignored.\n";
246 }
247
248 msg << "Parameter values: ";
249 for (std::size_t i = 0; i < getNDim(); ++i) {
250 auto &var = floatableParam(i);
251 msg << "\t" << var.GetName() << "=" << var.getVal();
252 }
253 msg << std::endl;
254
255 RooAbsReal::printEvalErrors(msg, cfg().printEvalErrors);
256 ooccoutW(_context, Minimization) << msg.str() << std::endl;
257}
258
259/// Apply corrections on the fvalue if errors were signaled.
260///
261/// Two kinds of errors are possible: 1. infinite or nan values (the latter
262/// can be a signaling nan, using RooNaNPacker) or 2. logEvalError-type errors.
263/// Both are caught here and fvalue is updated so that Minuit in turn is nudged
264/// to move the search outside of the problematic parameter space area.
265double RooAbsMinimizerFcn::applyEvalErrorHandling(double fvalue) const
266{
267 if (!std::isfinite(fvalue) || RooAbsReal::numEvalErrors() > 0 || fvalue > 1e30) {
268 printEvalErrors();
270 _numBadNLL++;
271
272 if (cfg().doEEWall) {
273 const double badness = RooNaNPacker::unpackNaN(fvalue);
274 fvalue = (std::isfinite(_maxFCN) ? _maxFCN : 0.) + cfg().recoverFromNaN * badness;
275 }
276 } else {
277 if (_evalCounter > 0 && _evalCounter == _numBadNLL) {
278 // This is the first time we get a valid function value; while before, the
279 // function was always invalid. For invalid cases, we returned values > 0.
280 // Now, we offset valid values such that they are < 0.
282 }
284 _maxFCN = std::max(fvalue, _maxFCN);
285 }
286 return fvalue;
287}
288
289void RooAbsMinimizerFcn::finishDoEval() const
290{
291 _evalCounter++;
292}
293
294RooArgList RooAbsMinimizerFcn::floatParams() const
295{
296 RooArgList out;
297 for (RooAbsArg *param : _allParams) {
298 if (!treatAsConstant(*param))
299 out.add(*param);
300 }
301 return out;
302}
303
304RooArgList RooAbsMinimizerFcn::constParams() const
305{
306 RooArgList out;
307 for (RooAbsArg *param : _allParams) {
308 if (treatAsConstant(*param))
309 out.add(*param);
310 }
311 return out;
312}
313
314RooArgList RooAbsMinimizerFcn::initFloatParams() const
315{
317
318 for (RooAbsArg *param : _allParamsInit) {
319 if (!treatAsConstant(*param))
320 initFloatableParams.add(*param);
321 }
322
323 // Make sure we only return the initial parameters
324 // corresponding to currently floating parameters.
325 RooArgList out;
326 initFloatableParams.selectCommon(floatParams(), out);
327
328 return out;
329}
330
331/// \endcond
double badness
#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:76
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...