CMS 3D CMS Logo

HybridMinimizer.cc
Go to the documentation of this file.
1 // @(#)root/minuit2:$Id$
2 // Author: L. Moneta Wed Oct 18 11:48:00 2006
3 
4 /**********************************************************************
5  * *
6  * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7  * *
8  * *
9  **********************************************************************/
10 
11 // by lhx: Note copied and modifed from the Minuit2Minimizer to suit our purpose
12 // Changes mainly to make the SetMinimizerType public so that user can re-new to
13 // different minimizer...
14 // Implementation file for class HybridMinimizer
15 
17 
18 #include "Math/IFunction.h"
19 #include "Math/IOptions.h"
20 
21 #include "Minuit2/FCNAdapter.h"
22 #include "Minuit2/FumiliFCNAdapter.h"
23 #include "Minuit2/FCNGradAdapter.h"
24 #include "Minuit2/FunctionMinimum.h"
25 #include "Minuit2/MnMigrad.h"
26 #include "Minuit2/MnMinos.h"
27 #include "Minuit2/MinosError.h"
28 #include "Minuit2/MnHesse.h"
29 #include "Minuit2/MinuitParameter.h"
30 #include "Minuit2/MnUserFcn.h"
31 #include "Minuit2/MnPrint.h"
32 #include "Minuit2/FunctionMinimum.h"
33 #include "Minuit2/VariableMetricMinimizer.h"
34 #include "Minuit2/SimplexMinimizer.h"
35 #include "Minuit2/CombinedMinimizer.h"
36 #include "Minuit2/ScanMinimizer.h"
37 #include "Minuit2/FumiliMinimizer.h"
38 #include "Minuit2/MnParameterScan.h"
39 #include "Minuit2/MnContours.h"
40 
41 #include <cassert>
42 #include <iostream>
43 #include <algorithm>
44 #include <functional>
45 
46 namespace PSFitter {
47 
48  using namespace ROOT::Minuit2;
49 
50  // functions needed to control siwthc off of Minuit2 printing level
51 #ifdef USE_ROOT_ERROR
52  int TurnOffPrintInfoLevel() {
53  // switch off Minuit2 printing of INFO message (cut off is 1001)
54  int prevErrorIgnoreLevel = gErrorIgnoreLevel;
55  if (prevErrorIgnoreLevel < 1001) {
56  gErrorIgnoreLevel = 1001;
57  return prevErrorIgnoreLevel;
58  }
59  return -2; // no op in this case
60  }
61 
63 #else
64  // dummy functions
65  int TurnOffPrintInfoLevel() { return -1; }
66  int ControlPrintLevel() { return -1; }
67  void RestoreGlobalPrintLevel(int) {}
68 #endif
69 
71  : Minimizer(), fDim(0), fMinimizer(nullptr), fMinuitFCN(nullptr), fMinimum(nullptr) {
72  // Default constructor implementation depending on minimizer type
73  SetMinimizerType(type);
74  }
75 
76  HybridMinimizer::HybridMinimizer(const char *type)
77  : Minimizer(), fDim(0), fMinimizer(nullptr), fMinuitFCN(nullptr), fMinimum(nullptr) {
78  // constructor from a string
79 
80  std::string algoname(type);
81  // tolower() is not an std function (Windows)
82  std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int (*)(int))tolower);
83 
84  EMinimizerType algoType = kMigrad;
85  if (algoname == "simplex")
86  algoType = kSimplex;
87  if (algoname == "minimize")
88  algoType = kCombined;
89  if (algoname == "scan")
90  algoType = kScan;
91  if (algoname == "fumili")
92  algoType = kFumili;
93 
94  SetMinimizerType(algoType);
95  }
96 
97  void HybridMinimizer::SetMinimizerType(EMinimizerType type) {
98  // Set minimizer algorithm type
99  fUseFumili = false;
100 
101  if (fMinimizer)
102  delete fMinimizer;
103 
104  switch (type) {
105  case kMigrad:
106  //std::cout << "HybridMinimizer: minimize using MIGRAD " << std::endl;
107  SetMinimizer(new ROOT::Minuit2::VariableMetricMinimizer());
108  return;
109  case kSimplex:
110  //std::cout << "HybridMinimizer: minimize using SIMPLEX " << std::endl;
111  SetMinimizer(new ROOT::Minuit2::SimplexMinimizer());
112  return;
113  case kCombined:
114  SetMinimizer(new ROOT::Minuit2::CombinedMinimizer());
115  return;
116  case kScan:
117  SetMinimizer(new ROOT::Minuit2::ScanMinimizer());
118  return;
119  case kFumili:
120  SetMinimizer(new ROOT::Minuit2::FumiliMinimizer());
121  fUseFumili = true;
122  return;
123  default:
124  //migrad minimizer
125  SetMinimizer(new ROOT::Minuit2::VariableMetricMinimizer());
126  }
127  }
128 
130  // Destructor implementation.
131  if (fMinimizer)
132  delete fMinimizer;
133  if (fMinuitFCN)
134  delete fMinuitFCN;
135  if (fMinimum)
136  delete fMinimum;
137  }
138 
139  HybridMinimizer::HybridMinimizer(const HybridMinimizer &) : ROOT::Math::Minimizer() {
140  // Implementation of copy constructor.
141  }
142 
144  // Implementation of assignment operator.
145  if (this == &rhs)
146  return *this; // time saving self-test
147  return *this;
148  }
149 
150  void HybridMinimizer::Clear() {
151  // delete the state in case of consecutive minimizations
152  fState = MnUserParameterState();
153  // clear also the function minimum
154  if (fMinimum)
155  delete fMinimum;
156  fMinimum = nullptr;
157  }
158 
159  // set variables
160 
161  bool HybridMinimizer::SetVariable(unsigned int ivar, const std::string &name, double val, double step) {
162  // set a free variable.
163  // Add the variable if not existing otherwise set value if exists already
164  // this is implemented in MnUserParameterState::Add
165  // if index is wrong (i.e. variable already exists but with a different index return false) but
166  // value is set for corresponding variable name
167 
168  // std::cout << " add parameter " << name << " " << val << " step " << step << std::endl;
169 
170  if (step <= 0) {
171  std::string txtmsg = "Parameter " + name + " has zero or invalid step size - consider it as constant ";
172  MN_INFO_MSG2("HybridMinimizer::SetVariable", txtmsg);
173  fState.Add(name, val);
174  } else
175  fState.Add(name, val, step);
176 
177  unsigned int minuit2Index = fState.Index(name);
178  if (minuit2Index != ivar) {
179  std::string txtmsg("Wrong index used for the variable " + name);
180  MN_INFO_MSG2("HybridMinimizer::SetVariable", txtmsg);
181  MN_INFO_VAL2("HybridMinimizer::SetVariable", minuit2Index);
182  return false;
183  }
184  fState.RemoveLimits(ivar);
185 
186  return true;
187  }
188 
190  unsigned int ivar, const std::string &name, double val, double step, double lower) {
191  // add a lower bounded variable
192  if (!SetVariable(ivar, name, val, step))
193  return false;
194  fState.SetLowerLimit(ivar, lower);
195  return true;
196  }
197 
199  unsigned int ivar, const std::string &name, double val, double step, double upper) {
200  // add a upper bounded variable
201  if (!SetVariable(ivar, name, val, step))
202  return false;
203  fState.SetUpperLimit(ivar, upper);
204  return true;
205  }
206 
208  unsigned int ivar, const std::string &name, double val, double step, double lower, double upper) {
209  // add a double bound variable
210  if (!SetVariable(ivar, name, val, step))
211  return false;
212  fState.SetLimits(ivar, lower, upper);
213  return true;
214  }
215 
216  bool HybridMinimizer::SetFixedVariable(unsigned int ivar, const std::string &name, double val) {
217  // add a fixed variable
218  // need a step size otherwise treated as a constant
219  // use 10%
220  double step = (val != 0) ? 0.1 * std::abs(val) : 0.1;
221  if (!SetVariable(ivar, name, val, step)) {
222  ivar = fState.Index(name);
223  }
224  fState.Fix(ivar);
225  return true;
226  }
227 
228  std::string HybridMinimizer::VariableName(unsigned int ivar) const {
229  // return the variable name
230  if (ivar >= fState.MinuitParameters().size())
231  return std::string();
232  return fState.GetName(ivar);
233  }
234 
236  // return the variable index
237  // check if variable exist
238  return fState.Trafo().FindIndex(name);
239  }
240 
241  bool HybridMinimizer::SetVariableValue(unsigned int ivar, double val) {
242  // set value for variable ivar (only for existing parameters)
243  if (ivar >= fState.MinuitParameters().size())
244  return false;
245  fState.SetValue(ivar, val);
246  return true;
247  }
248 
249  bool HybridMinimizer::SetVariableValues(const double *x) {
250  // set value for variable ivar (only for existing parameters)
251  unsigned int n = fState.MinuitParameters().size();
252  if (n == 0)
253  return false;
254  for (unsigned int ivar = 0; ivar < n; ++ivar)
255  fState.SetValue(ivar, x[ivar]);
256  return true;
257  }
258 
259  void HybridMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction &func) {
260  // set function to be minimized
261  if (fMinuitFCN)
262  delete fMinuitFCN;
263  fDim = func.NDim();
264  if (!fUseFumili) {
265  fMinuitFCN = new ROOT::Minuit2::FCNAdapter<ROOT::Math::IMultiGenFunction>(func, ErrorDef());
266  } else {
267  // for Fumili the fit method function interface is required
268  const ROOT::Math::FitMethodFunction *fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
269  if (!fcnfunc) {
270  MN_ERROR_MSG("HybridMinimizer: Wrong Fit method function for Fumili");
271  return;
272  }
273  fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodFunction>(*fcnfunc, fDim, ErrorDef());
274  }
275  }
276 
277  void HybridMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction &func) {
278  // set function to be minimized
279  fDim = func.NDim();
281  delete fMinuitFCN;
282  if (!fUseFumili) {
283  fMinuitFCN = new ROOT::Minuit2::FCNGradAdapter<ROOT::Math::IMultiGradFunction>(func, ErrorDef());
284  } else {
285  // for Fumili the fit method function interface is required
286  const ROOT::Math::FitMethodGradFunction *fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(&func);
287  if (!fcnfunc) {
288  MN_ERROR_MSG("HybridMinimizer: Wrong Fit method function for Fumili");
289  return;
290  }
291  fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodGradFunction>(*fcnfunc, fDim, ErrorDef());
292  }
293  }
294 
296  // perform the minimization
297  // store a copy of FunctionMinimum
298  if (!fMinuitFCN) {
299  MN_ERROR_MSG2("HybridMinimizer::Minimize", "FCN function has not been set");
300  return false;
301  }
302 
303  assert(GetMinimizer() != nullptr);
304 
305  // delete result of previous minimization
306  if (fMinimum)
307  delete fMinimum;
308  fMinimum = nullptr;
309 
310  int maxfcn = MaxFunctionCalls();
311  double tol = Tolerance();
312  int strategyLevel = Strategy();
313  fMinuitFCN->SetErrorDef(ErrorDef());
314 
315  /*
316  if (PrintLevel() >=1) {
317  // print the real number of maxfcn used (defined in ModularFuncitonMinimizer)
318  int maxfcn_used = maxfcn;
319  if (maxfcn_used == 0) {
320  int nvar = fState.VariableParameters();
321  maxfcn_used = 200 + 100*nvar + 5*nvar*nvar;
322  }
323 // std::cout << "HybridMinimizer: Minimize with max-calls " << maxfcn_used
324 // << " convergence for edm < " << tol << " strategy "
325 // << strategyLevel << std::endl;
326  }
327  */
328 
329  // internal minuit messages
330  MnPrint::SetLevel(PrintLevel());
331 
332  // switch off Minuit2 printing
333  int prev_level = (PrintLevel() <= 0) ? TurnOffPrintInfoLevel() : -2;
334 
335  // set the precision if needed
336  if (Precision() > 0)
337  fState.SetPrecision(Precision());
338 
339  // set strategy and add extra options if needed
340  ROOT::Minuit2::MnStrategy strategy(strategyLevel);
341  ROOT::Math::IOptions *minuit2Opt = ROOT::Math::MinimizerOptions::FindDefault("Minuit2");
342  if (minuit2Opt) {
343  // set extra strategy options
344  int nGradCycles = strategy.GradientNCycles();
345  int nHessCycles = strategy.HessianNCycles();
346  int nHessGradCycles = strategy.HessianGradientNCycles();
347 
348  double gradTol = strategy.GradientTolerance();
349  double gradStepTol = strategy.GradientStepTolerance();
350  double hessStepTol = strategy.HessianStepTolerance();
351  double hessG2Tol = strategy.HessianG2Tolerance();
352 
353  minuit2Opt->GetValue("GradientNCycles", nGradCycles);
354  minuit2Opt->GetValue("HessianNCycles", nHessCycles);
355  minuit2Opt->GetValue("HessianGradientNCycles", nHessGradCycles);
356 
357  minuit2Opt->GetValue("GradientTolerance", gradTol);
358  minuit2Opt->GetValue("GradientStepTolerance", gradStepTol);
359  minuit2Opt->GetValue("HessianStepTolerance", hessStepTol);
360  minuit2Opt->GetValue("HessianG2Tolerance", hessG2Tol);
361 
362  strategy.SetGradientNCycles(nGradCycles);
363  strategy.SetHessianNCycles(nHessCycles);
364  strategy.SetHessianGradientNCycles(nHessGradCycles);
365 
366  strategy.SetGradientTolerance(gradTol);
367  strategy.SetGradientStepTolerance(gradStepTol);
368  strategy.SetHessianStepTolerance(hessStepTol);
369  strategy.SetHessianG2Tolerance(hessStepTol);
370 
371  if (PrintLevel() > 0) {
372  // std::cout << "HybridMinimizer::Minuit - Changing default stratgey options" << std::endl;
373  minuit2Opt->Print();
374  }
375  }
376 
377  const ROOT::Minuit2::FCNGradientBase *gradFCN = dynamic_cast<const ROOT::Minuit2::FCNGradientBase *>(fMinuitFCN);
378  if (gradFCN != nullptr) {
379  // use gradient
380  //SetPrintLevel(3);
381  ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*gradFCN, fState, strategy, maxfcn, tol);
382  fMinimum = new ROOT::Minuit2::FunctionMinimum(min);
383  } else {
384  ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*GetFCN(), fState, strategy, maxfcn, tol);
385  fMinimum = new ROOT::Minuit2::FunctionMinimum(min);
386  }
387 
388  // check if Hesse needs to be run
389  if (fMinimum->IsValid() && IsValidError() && fMinimum->State().Error().Dcovar() != 0) {
390  // run Hesse (Hesse will add results in the last state of fMinimum
391  ROOT::Minuit2::MnHesse hesse(strategy);
392  hesse(*fMinuitFCN, *fMinimum, maxfcn);
393  }
394 
395  // -2 is the highest low invalid value for gErrorIgnoreLevel
396  if (prev_level > -2)
397  RestoreGlobalPrintLevel(prev_level);
398 
399  fState = fMinimum->UserState();
400  bool ok = ExamineMinimum(*fMinimum);
401  //fMinimum = 0;
402  return ok;
403  }
404 
405  bool HybridMinimizer::ExamineMinimum(const ROOT::Minuit2::FunctionMinimum &min) {
407 
408  // debug ( print all the states)
409  int debugLevel = PrintLevel();
410  if (debugLevel >= 3) {
411  /*
412  const std::vector<ROOT::Minuit2::MinimumState>& iterationStates = min.States();
413  std::cout << "Number of iterations " << iterationStates.size() << std::endl;
414  for (unsigned int i = 0; i < iterationStates.size(); ++i) {
415  //std::cout << iterationStates[i] << std::endl;
416  const ROOT::Minuit2::MinimumState & st = iterationStates[i];
417  std::cout << "----------> Iteration " << i << std::endl;
418  int pr = std::cout.precision(12);
419  std::cout << " FVAL = " << st.Fval() << " Edm = " << st.Edm() << " Nfcn = " << st.NFcn() << std::endl;
420  std::cout.precision(pr);
421  std::cout << " Error matrix change = " << st.Error().Dcovar() << std::endl;
422  std::cout << " Parameters : ";
423  // need to transform from internal to external
424  for (int j = 0; j < st.size() ; ++j) std::cout << " p" << j << " = " << fState.Int2ext( j, st.Vec()(j) );
425  std::cout << std::endl;
426  }
427 */
428  }
429 
430  fStatus = 0;
431  std::string txt;
432  if (min.HasMadePosDefCovar()) {
433  txt = "Covar was made pos def";
434  fStatus = 1;
435  }
436  if (min.HesseFailed()) {
437  txt = "Hesse is not valid";
438  fStatus = 2;
439  }
440  if (min.IsAboveMaxEdm()) {
441  txt = "Edm is above max";
442  fStatus = 3;
443  }
444  if (min.HasReachedCallLimit()) {
445  txt = "Reached call limit";
446  fStatus = 4;
447  }
448 
449  bool validMinimum = min.IsValid();
450  if (validMinimum) {
451  // print a warning message in case something is not ok
452  if (fStatus != 0 && debugLevel > 0)
453  MN_INFO_MSG2("HybridMinimizer::Minimize", txt);
454  } else {
455  // minimum is not valid when state is not valid and edm is over max or has passed call limits
456  if (fStatus == 0) {
457  // this should not happen
458  txt = "unknown failure";
459  fStatus = 5;
460  }
461  std::string msg = "Minimization did NOT converge, " + txt;
462  MN_INFO_MSG2("HybridMinimizer::Minimize", msg);
463  }
464 
465  if (debugLevel >= 1)
466  PrintResults();
467  return validMinimum;
468  }
469 
471  // print results of minimization
472  if (!fMinimum)
473  return;
474  if (fMinimum->IsValid()) {
475  // valid minimum
476  /*
477  std::cout << "HybridMinimizer : Valid minimum - status = " << fStatus << std::endl;
478  int pr = std::cout.precision(18);
479  std::cout << "FVAL = " << fState.Fval() << std::endl;
480  std::cout << "Edm = " << fState.Edm() << std::endl;
481  std::cout.precision(pr);
482  std::cout << "Nfcn = " << fState.NFcn() << std::endl;
483  for (unsigned int i = 0; i < fState.MinuitParameters().size(); ++i) {
484  const MinuitParameter & par = fState.Parameter(i);
485  std::cout << par.Name() << "\t = " << par.Value() << "\t ";
486  if (par.IsFixed() ) std::cout << "(fixed)" << std::endl;
487  else if (par.IsConst() ) std::cout << "(const)" << std::endl;
488  else if (par.HasLimits() )
489  std::cout << "+/- " << par.Error() << "\t(limited)"<< std::endl;
490  else
491  std::cout << "+/- " << par.Error() << std::endl;
492  }
493 */
494  } else {
495  /*
496  std::cout << "HybridMinimizer : Invalid Minimum - status = " << fStatus << std::endl;
497  std::cout << "FVAL = " << fState.Fval() << std::endl;
498  std::cout << "Edm = " << fState.Edm() << std::endl;
499  std::cout << "Nfcn = " << fState.NFcn() << std::endl;
500 */
501  }
502  }
503 
504  const double *HybridMinimizer::X() const {
505  // return values at minimum
506  const std::vector<MinuitParameter> &paramsObj = fState.MinuitParameters();
507  if (paramsObj.empty())
508  return nullptr;
509  assert(fDim == paramsObj.size());
510  // be careful for multiple calls of this function. I will redo an allocation here
511  // only when size of vectors has changed (e.g. after a new minimization)
512  if (fValues.size() != fDim)
513  fValues.resize(fDim);
514  for (unsigned int i = 0; i < fDim; ++i) {
515  fValues[i] = paramsObj[i].Value();
516  }
517 
518  return &fValues.front();
519  }
520 
521  const double *HybridMinimizer::Errors() const {
522  // return error at minimum (set to zero for fixed and constant params)
523  const std::vector<MinuitParameter> &paramsObj = fState.MinuitParameters();
524  if (paramsObj.empty())
525  return nullptr;
526  assert(fDim == paramsObj.size());
527  // be careful for multiple calls of this function. I will redo an allocation here
528  // only when size of vectors has changed (e.g. after a new minimization)
529  if (fErrors.size() != fDim)
530  fErrors.resize(fDim);
531  for (unsigned int i = 0; i < fDim; ++i) {
532  const MinuitParameter &par = paramsObj[i];
533  if (par.IsFixed() || par.IsConst())
534  fErrors[i] = 0;
535  else
536  fErrors[i] = par.Error();
537  }
538 
539  return &fErrors.front();
540  }
541 
542  double HybridMinimizer::CovMatrix(unsigned int i, unsigned int j) const {
543  // get value of covariance matrices (transform from external to internal indices)
544  if (i >= fDim || i >= fDim)
545  return 0;
546  if (!fState.HasCovariance())
547  return 0; // no info available when minimization has failed
548  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst())
549  return 0;
550  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
551  return 0;
552  unsigned int k = fState.IntOfExt(i);
553  unsigned int l = fState.IntOfExt(j);
554  return fState.Covariance()(k, l);
555  }
556 
557  bool HybridMinimizer::GetCovMatrix(double *cov) const {
558  // get value of covariance matrices
559  if (!fState.HasCovariance())
560  return false; // no info available when minimization has failed
561  for (unsigned int i = 0; i < fDim; ++i) {
562  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst()) {
563  for (unsigned int j = 0; j < fDim; ++j) {
564  cov[i * fDim + j] = 0;
565  }
566  } else {
567  unsigned int l = fState.IntOfExt(i);
568  for (unsigned int j = 0; j < fDim; ++j) {
569  // could probably speed up this loop (if needed)
570  int k = i * fDim + j;
571  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
572  cov[k] = 0;
573  else {
574  // need to transform from external to internal indices)
575  // for taking care of the removed fixed row/columns in the Minuit2 representation
576  unsigned int m = fState.IntOfExt(j);
577  cov[k] = fState.Covariance()(l, m);
578  }
579  }
580  }
581  }
582  return true;
583  }
584 
585  bool HybridMinimizer::GetHessianMatrix(double *hess) const {
586  // get value of Hessian matrix
587  // this is the second derivative matrices
588  if (!fState.HasCovariance())
589  return false; // no info available when minimization has failed
590  for (unsigned int i = 0; i < fDim; ++i) {
591  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst()) {
592  for (unsigned int j = 0; j < fDim; ++j) {
593  hess[i * fDim + j] = 0;
594  }
595  } else {
596  unsigned int l = fState.IntOfExt(i);
597  for (unsigned int j = 0; j < fDim; ++j) {
598  // could probably speed up this loop (if needed)
599  int k = i * fDim + j;
600  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
601  hess[k] = 0;
602  else {
603  // need to transform from external to internal indices)
604  // for taking care of the removed fixed row/columns in the Minuit2 representation
605  unsigned int m = fState.IntOfExt(j);
606  hess[k] = fState.Hessian()(l, m);
607  }
608  }
609  }
610  }
611 
612  return true;
613  }
614 
615  double HybridMinimizer::Correlation(unsigned int i, unsigned int j) const {
616  // get correlation between parameter i and j
617  if (i >= fDim || i >= fDim)
618  return 0;
619  if (!fState.HasCovariance())
620  return 0; // no info available when minimization has failed
621  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst())
622  return 0;
623  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
624  return 0;
625  unsigned int k = fState.IntOfExt(i);
626  unsigned int l = fState.IntOfExt(j);
627  double cij = fState.IntCovariance()(k, l);
628  double tmp = std::sqrt(std::abs(fState.IntCovariance()(k, k) * fState.IntCovariance()(l, l)));
629  if (tmp > 0)
630  return cij / tmp;
631  return 0;
632  }
633 
634  double HybridMinimizer::GlobalCC(unsigned int i) const {
635  // get global correlation coefficient for the parameter i. This is a number between zero and one which gives
636  // the correlation between the i-th parameter and that linear combination of all other parameters which
637  // is most strongly correlated with i.
638 
639  if (i >= fDim || i >= fDim)
640  return 0;
641  // no info available when minimization has failed or has some problems
642  if (!fState.HasGlobalCC())
643  return 0;
644  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst())
645  return 0;
646  unsigned int k = fState.IntOfExt(i);
647  return fState.GlobalCC().GlobalCC()[k];
648  }
649 
650  bool HybridMinimizer::GetMinosError(unsigned int i, double &errLow, double &errUp, int runopt) {
651  // return the minos error for parameter i
652  // if a minimum does not exist an error is returned
653  // runopt is a flag which specifies if only lower or upper error needs to be run
654  // if runopt = 0 both, = 1 only lower, + 2 only upper errors
655  errLow = 0;
656  errUp = 0;
657  bool runLower = runopt != 2;
658  bool runUpper = runopt != 1;
659 
661 
662  // need to know if parameter is const or fixed
663  if (fState.Parameter(i).IsConst() || fState.Parameter(i).IsFixed()) {
664  return false;
665  }
666 
667  int debugLevel = PrintLevel();
668  // internal minuit messages
669  MnPrint::SetLevel(debugLevel);
670 
671  // to run minos I need function minimum class
672  // redo minimization from current state
673  // ROOT::Minuit2::FunctionMinimum min =
674  // GetMinimizer()->Minimize(*GetFCN(),fState, ROOT::Minuit2::MnStrategy(strategy), MaxFunctionCalls(), Tolerance());
675  // fState = min.UserState();
676  if (fMinimum == nullptr) {
677  MN_ERROR_MSG("HybridMinimizer::GetMinosErrors: failed - no function minimum existing");
678  return false;
679  }
680 
681  if (!fMinimum->IsValid()) {
682  MN_ERROR_MSG("HybridMinimizer::MINOS failed due to invalid function minimum");
683  return false;
684  }
685 
686  fMinuitFCN->SetErrorDef(ErrorDef());
687  // if error def has been changed update it in FunctionMinimum
688  if (ErrorDef() != fMinimum->Up())
689  fMinimum->SetErrorDef(ErrorDef());
690 
691  // switch off Minuit2 printing
692  int prev_level = (PrintLevel() <= 0) ? TurnOffPrintInfoLevel() : -2;
693 
694  // set the precision if needed
695  if (Precision() > 0)
696  fState.SetPrecision(Precision());
697 
698  ROOT::Minuit2::MnMinos minos(*fMinuitFCN, *fMinimum);
699 
700  // run MnCross
701  MnCross low;
702  MnCross up;
703  int maxfcn = MaxFunctionCalls();
704  double tol = Tolerance();
705 
706  // const char * par_name = fState.Name(i);
707 
708  // now input tolerance for migrad calls inside Minos (MnFunctionCross)
709  // before it was fixed to 0.05
710  // cut off too small tolerance (they are not needed)
711  tol = std::max(tol, 0.01);
712 
713  /*
714  if (PrintLevel() >=1) {
715  // print the real number of maxfcn used (defined in MnMinos)
716  int maxfcn_used = maxfcn;
717  if (maxfcn_used == 0) {
718  int nvar = fState.VariableParameters();
719  maxfcn_used = 2*(nvar+1)*(200 + 100*nvar + 5*nvar*nvar);
720  }
721 // std::cout << "HybridMinimizer::GetMinosError for parameter " << i << " " << par_name
722 // << " using max-calls " << maxfcn_used << ", tolerance " << tol << std::endl;
723  }
724  */
725 
726  if (runLower)
727  low = minos.Loval(i, maxfcn, tol);
728  if (runUpper)
729  up = minos.Upval(i, maxfcn, tol);
730 
731  ROOT::Minuit2::MinosError me(i, fMinimum->UserState().Value(i), low, up);
732 
733  if (prev_level > -2)
734  RestoreGlobalPrintLevel(prev_level);
735 
736  // debug result of Minos
737  // print error message in Minos
738 
739  if (debugLevel >= 1) {
740  /*
741  if (runLower) {
742  if (!me.LowerValid() )
743  std::cout << "Minos: Invalid lower error for parameter " << par_name << std::endl;
744  if(me.AtLowerLimit())
745  std::cout << "Minos: Parameter : " << par_name << " is at Lower limit."<<std::endl;
746  if(me.AtLowerMaxFcn())
747  std::cout << "Minos: Maximum number of function calls exceeded when running for lower error" <<std::endl;
748  if(me.LowerNewMin() )
749  std::cout << "Minos: New Minimum found while running Minos for lower error" <<std::endl;
750 
751  if (debugLevel > 1) std::cout << "Minos: Lower error for parameter " << par_name << " : " << me.Lower() << std::endl;
752 
753  }
754  if (runUpper) {
755  if (!me.UpperValid() )
756  std::cout << "Minos: Invalid upper error for parameter " << par_name << std::endl;
757  if(me.AtUpperLimit())
758  std::cout << "Minos: Parameter " << par_name << " is at Upper limit."<<std::endl;
759  if(me.AtUpperMaxFcn())
760  std::cout << "Minos: Maximum number of function calls exceeded when running for upper error" <<std::endl;
761  if(me.UpperNewMin() )
762  std::cout << "Minos: New Minimum found while running Minos for upper error" <<std::endl;
763 
764  if (debugLevel > 1) std::cout << "Minos: Upper error for parameter " << par_name << " : " << me.Upper() << std::endl;
765  }
766 */
767  }
768 
769  bool lowerInvalid = (runLower && !me.LowerValid());
770  bool upperInvalid = (runUpper && !me.UpperValid());
771  int mstatus = 0;
772  if (lowerInvalid || upperInvalid) {
773  // set status accroding to bit
774  // bit 1: lower invalid Minos errors
775  // bit 2: uper invalid Minos error
776  // bit 3: invalid because max FCN
777  // bit 4 : invalid because a new minimum has been found
778  if (lowerInvalid) {
779  mstatus |= 1;
780  if (me.AtLowerMaxFcn())
781  mstatus |= 4;
782  if (me.LowerNewMin())
783  mstatus |= 8;
784  }
785  if (upperInvalid) {
786  mstatus |= 3;
787  if (me.AtUpperMaxFcn())
788  mstatus |= 4;
789  if (me.UpperNewMin())
790  mstatus |= 8;
791  }
792  //std::cout << "Error running Minos for parameter " << i << std::endl;
793  fStatus += 10 * mstatus;
794  }
795 
796  errLow = me.Lower();
797  errUp = me.Upper();
798 
799  bool isValid = (runLower && me.LowerValid()) || (runUpper && me.UpperValid());
800  return isValid;
801  }
802 
803  bool HybridMinimizer::Scan(unsigned int ipar, unsigned int &nstep, double *x, double *y, double xmin, double xmax) {
804  // scan a parameter (variable) around the minimum value
805  // the parameters must have been set before
806  // if xmin=0 && xmax == 0 by default scan around 2 sigma of the error
807  // if the errors are also zero then scan from min and max of parameter range
808 
809  if (!fMinuitFCN) {
810  MN_ERROR_MSG2("HybridMinimizer::Scan", " Function must be set before using Scan");
811  return false;
812  }
813 
814  if (ipar > fState.MinuitParameters().size()) {
815  MN_ERROR_MSG2("HybridMinimizer::Scan", " Invalid number. Minimizer variables must be set before using Scan");
816  return false;
817  }
818 
819  // switch off Minuit2 printing
820  int prev_level = (PrintLevel() <= 0) ? TurnOffPrintInfoLevel() : -2;
821 
822  MnPrint::SetLevel(PrintLevel());
823 
824  // set the precision if needed
825  if (Precision() > 0)
826  fState.SetPrecision(Precision());
827 
828  MnParameterScan scan(*fMinuitFCN, fState.Parameters());
829  double amin = scan.Fval(); // fcn value of the function before scan
830 
831  // first value is param value
832  std::vector<std::pair<double, double> > result = scan(ipar, nstep - 1, xmin, xmax);
833 
834  if (prev_level > -2)
835  RestoreGlobalPrintLevel(prev_level);
836 
837  if (result.size() != nstep) {
838  MN_ERROR_MSG2("HybridMinimizer::Scan", " Invalid result from MnParameterScan");
839  return false;
840  }
841  // sort also the returned points in x
842  std::sort(result.begin(), result.end());
843 
844  for (unsigned int i = 0; i < nstep; ++i) {
845  x[i] = result[i].first;
846  y[i] = result[i].second;
847  }
848 
849  // what to do if a new minimum has been found ?
850  // use that as new minimum
851  if (scan.Fval() < amin) {
852  if (PrintLevel() > 0)
853  MN_INFO_MSG2("HybridMinimizer::Scan", "A new minimum has been found");
854  fState.SetValue(ipar, scan.Parameters().Value(ipar));
855  }
856 
857  return true;
858  }
859 
860  bool HybridMinimizer::Contour(unsigned int ipar, unsigned int jpar, unsigned int &npoints, double *x, double *y) {
861  // contour plot for parameter i and j
862  // need a valid FunctionMinimum otherwise exits
863  if (fMinimum == nullptr) {
864  MN_ERROR_MSG2("HybridMinimizer::Contour", " no function minimum existing. Must minimize function before");
865  return false;
866  }
867 
868  if (!fMinimum->IsValid()) {
869  MN_ERROR_MSG2("HybridMinimizer::Contour", "Invalid function minimum");
870  return false;
871  }
873 
874  fMinuitFCN->SetErrorDef(ErrorDef());
875  // if error def has been changed update it in FunctionMinimum
876  if (ErrorDef() != fMinimum->Up())
877  fMinimum->SetErrorDef(ErrorDef());
878 
879  // switch off Minuit2 printing (for level of 0,1)
880  int prev_level = (PrintLevel() <= 1) ? TurnOffPrintInfoLevel() : -2;
881 
882  MnPrint::SetLevel(PrintLevel());
883 
884  // set the precision if needed
885  if (Precision() > 0)
886  fState.SetPrecision(Precision());
887 
888  // eventually one should specify tolerance in contours
889  MnContours contour(*fMinuitFCN, *fMinimum, Strategy());
890 
891  if (prev_level > -2)
892  RestoreGlobalPrintLevel(prev_level);
893 
894  std::vector<std::pair<double, double> > result = contour(ipar, jpar, npoints);
895  if (result.size() != npoints) {
896  MN_ERROR_MSG2("HybridMinimizer::Contour", " Invalid result from MnContours");
897  return false;
898  }
899  for (unsigned int i = 0; i < npoints; ++i) {
900  x[i] = result[i].first;
901  y[i] = result[i].second;
902  }
903 
904  return true;
905  }
906 
907  bool HybridMinimizer::Hesse() {
908  // find Hessian (full second derivative calculations)
909  // the contained state will be updated with the Hessian result
910  // in case a function minimum exists and is valid the result will be
911  // appended in the function minimum
912 
913  if (!fMinuitFCN) {
914  MN_ERROR_MSG2("HybridMinimizer::Hesse", "FCN function has not been set");
915  return false;
916  }
917 
918  int strategy = Strategy();
919  int maxfcn = MaxFunctionCalls();
920 
921  // switch off Minuit2 printing
922  int prev_level = (PrintLevel() <= 0) ? TurnOffPrintInfoLevel() : -2;
923 
924  MnPrint::SetLevel(PrintLevel());
925 
926  // set the precision if needed
927  if (Precision() > 0)
928  fState.SetPrecision(Precision());
929 
930  ROOT::Minuit2::MnHesse hesse(strategy);
931 
932  // case when function minimum exists
933  if (fMinimum) {
934  // run hesse and function minimum will be updated with Hesse result
935  hesse(*fMinuitFCN, *fMinimum, maxfcn);
936  fState = fMinimum->UserState();
937  }
938 
939  else {
940  // run Hesse on point stored in current state (independent of function minimum validity)
941  // (x == 0)
942  fState = hesse(*fMinuitFCN, fState, maxfcn);
943  }
944 
945  if (prev_level > -2)
946  RestoreGlobalPrintLevel(prev_level);
947 
948  if (PrintLevel() >= 3) {
949  // std::cout << "State returned from Hesse " << std::endl;
950  // std::cout << fState << std::endl;
951  }
952 
953  if (!fState.HasCovariance()) {
954  // if false means error is not valid and this is due to a failure in Hesse
955  if (PrintLevel() > 0)
956  MN_INFO_MSG2("HybridMinimizer::Hesse", "Hesse failed ");
957  // update minimizer error status
958  int hstatus = 4;
959  // information on error state can be retrieved only if fMinimum is available
960  if (fMinimum) {
961  if (fMinimum->Error().HesseFailed())
962  hstatus = 1;
963  if (fMinimum->Error().InvertFailed())
964  hstatus = 2;
965  else if (!(fMinimum->Error().IsPosDef()))
966  hstatus = 3;
967  }
968  fStatus += 100 * hstatus;
969  return false;
970  }
971 
972  return true;
973  }
974 
976  // return status of covariance matrix
977  //-1 - not available (inversion failed or Hesse failed)
978  // 0 - available but not positive defined
979  // 1 - covariance only approximate
980  // 2 full matrix but forced pos def
981  // 3 full accurate matrix
982 
983  if (fMinimum) {
984  // case a function minimum is available
985  if (fMinimum->HasAccurateCovar())
986  return 3;
987  else if (fMinimum->HasMadePosDefCovar())
988  return 2;
989  else if (fMinimum->HasValidCovariance())
990  return 1;
991  else if (fMinimum->HasCovariance())
992  return 0;
993  return -1;
994  } else {
995  // case fMinimum is not available - use state information
996  return fState.CovarianceStatus();
997  }
998  return 0;
999  }
1000 
1001 } // namespace PSFitter
npoints
static const int npoints
Definition: NuclearInteractionFTFSimulator.h:38
PSFitter::HybridMinimizer::SetVariable
bool SetVariable(unsigned int ivar, const std::string &name, double val, double step) override
set free variable
Definition: HybridMinimizer.cc:164
mps_fire.i
i
Definition: mps_fire.py:355
PSFitter::HybridMinimizer::operator=
HybridMinimizer & operator=(const HybridMinimizer &rhs)
Definition: HybridMinimizer.cc:146
METSignificanceParams_cfi.jpar
jpar
Definition: METSignificanceParams_cfi.py:19
PSFitter::HybridMinimizer::kFumili
Definition: HybridMinimizer.h:46
dqmiodumpmetadata.n
n
Definition: dqmiodumpmetadata.py:28
PSFitter::HybridMinimizer::PrintResults
void PrintResults() override
print result of minimization
Definition: HybridMinimizer.cc:473
PSFitter::HybridMinimizer::kCombined
Definition: HybridMinimizer.h:46
PSFitter::HybridMinimizer::GetCovMatrix
bool GetCovMatrix(double *cov) const override
Definition: HybridMinimizer.cc:560
step
step
Definition: StallMonitor.cc:94
min
T min(T a, T b)
Definition: MathUtil.h:58
PSFitter::HybridMinimizer::CovMatrixStatus
int CovMatrixStatus() const override
Definition: HybridMinimizer.cc:978
PSFitter::HybridMinimizer::~HybridMinimizer
~HybridMinimizer() override
Definition: HybridMinimizer.cc:132
HLT_2018_cff.debugLevel
debugLevel
Definition: HLT_2018_cff.py:81378
PSFitter::HybridMinimizer::fValues
std::vector< double > fValues
Definition: HybridMinimizer.h:280
PSFitter::HybridMinimizer::GetMinimizer
virtual const ROOT::Minuit2::ModularFunctionMinimizer * GetMinimizer() const
Definition: HybridMinimizer.h:262
PSFitter::HybridMinimizer::Correlation
double Correlation(unsigned int i, unsigned int j) const override
Definition: HybridMinimizer.cc:618
PSFitter
Definition: HybridMinimizer.cc:45
cms::cuda::assert
assert(be >=bs)
mps_check.msg
tuple msg
Definition: mps_check.py:285
PSFitter::HybridMinimizer::SetUpperLimitedVariable
bool SetUpperLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double upper) override
set upper limit variable (override if minimizer supports them )
Definition: HybridMinimizer.cc:201
PSFitter::HybridMinimizer::GetHessianMatrix
bool GetHessianMatrix(double *h) const override
Definition: HybridMinimizer.cc:588
ROOT::Minuit2
Definition: HybridMinimizer.h:28
PSFitter::HybridMinimizer::Errors
const double * Errors() const override
return errors at the minimum
Definition: HybridMinimizer.cc:524
PSFitter::ControlPrintLevel
int ControlPrintLevel()
Definition: HybridMinimizer.cc:69
createJobs.tmp
tmp
align.sh
Definition: createJobs.py:716
PSFitter::HybridMinimizer::SetFunction
void SetFunction(const ROOT::Math::IMultiGenFunction &func) override
set the function to minimize
Definition: HybridMinimizer.cc:262
convertSQLiteXML.ok
bool ok
Definition: convertSQLiteXML.py:98
PSFitter::HybridMinimizer::fMinimum
ROOT::Minuit2::FunctionMinimum * fMinimum
Definition: HybridMinimizer.h:279
PSFitter::TurnOffPrintInfoLevel
int TurnOffPrintInfoLevel()
Definition: HybridMinimizer.cc:68
PSFitter::HybridMinimizer::fState
ROOT::Minuit2::MnUserParameterState fState
Definition: HybridMinimizer.h:275
PSFitter::HybridMinimizer::GetFCN
virtual const ROOT::Minuit2::FCNBase * GetFCN() const
Definition: HybridMinimizer.h:266
PSFitter::HybridMinimizer::SetMinimizerType
void SetMinimizerType(EMinimizerType type)
Definition: HybridMinimizer.cc:100
PSFitter::HybridMinimizer::X
const double * X() const override
return pointer to X values at the minimum
Definition: HybridMinimizer.cc:507
visualization-live-secondInstance_cfg.m
m
Definition: visualization-live-secondInstance_cfg.py:72
mathSSE::sqrt
T sqrt(T t)
Definition: SSEVec.h:19
vertices_cff.x
x
Definition: vertices_cff.py:29
PSFitter::HybridMinimizer::GetMinosError
bool GetMinosError(unsigned int i, double &errLow, double &errUp, int=0) override
Definition: HybridMinimizer.cc:653
HcalDetIdTransform::transform
unsigned transform(const HcalDetId &id, unsigned transformCode)
Definition: HcalDetIdTransform.cc:7
PSFitter::HybridMinimizer::SetLowerLimitedVariable
bool SetLowerLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double lower) override
set lower limit variable (override if minimizer supports them )
Definition: HybridMinimizer.cc:192
PSFitter::RestoreGlobalPrintLevel
void RestoreGlobalPrintLevel(int)
Definition: HybridMinimizer.cc:70
dqmdumpme.k
k
Definition: dqmdumpme.py:60
PSFitter::HybridMinimizer::fDim
unsigned int fDim
Definition: HybridMinimizer.h:272
PSFitter::HybridMinimizer::SetMinimizer
virtual void SetMinimizer(ROOT::Minuit2::ModularFunctionMinimizer *m)
Definition: HybridMinimizer.h:264
PSFitter::HybridMinimizer::Scan
bool Scan(unsigned int i, unsigned int &nstep, double *x, double *y, double xmin=0, double xmax=0) override
Definition: HybridMinimizer.cc:806
PSFitter::HybridMinimizer::Hesse
bool Hesse() override
Definition: HybridMinimizer.cc:910
utils.gErrorIgnoreLevel
gErrorIgnoreLevel
Definition: utils.py:27
AlCaHLTBitMon_QueryRunRegistry.string
string
Definition: AlCaHLTBitMon_QueryRunRegistry.py:256
PSFitter::HybridMinimizer::HybridMinimizer
HybridMinimizer(EMinimizerType type=kMigrad)
Definition: HybridMinimizer.cc:73
PSFitter::HybridMinimizer::Minimize
bool Minimize() override
Definition: HybridMinimizer.cc:298
SiStripPI::max
Definition: SiStripPayloadInspectorHelper.h:169
PSFitter::HybridMinimizer::SetVariableValue
bool SetVariableValue(unsigned int ivar, double val) override
set variable
Definition: HybridMinimizer.cc:244
PSFitter::HybridMinimizer::fMinuitFCN
ROOT::Minuit2::FCNBase * fMinuitFCN
Definition: HybridMinimizer.h:278
PSFitter::HybridMinimizer::kScan
Definition: HybridMinimizer.h:46
PSFitter::HybridMinimizer::fErrors
std::vector< double > fErrors
Definition: HybridMinimizer.h:281
createfilelist.int
int
Definition: createfilelist.py:10
PSFitter::HybridMinimizer::fMinimizer
ROOT::Minuit2::ModularFunctionMinimizer * fMinimizer
Definition: HybridMinimizer.h:277
PSFitter::HybridMinimizer::kMigrad
Definition: HybridMinimizer.h:46
PSFitter::HybridMinimizer::SetLimitedVariable
bool SetLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double, double) override
set upper/lower limited variable (override if minimizer supports them )
Definition: HybridMinimizer.cc:210
value
Definition: value.py:1
PSFitter::HybridMinimizer::SetVariableValues
bool SetVariableValues(const double *val) override
Definition: HybridMinimizer.cc:252
TrackCollections2monitor_cff.func
func
Definition: TrackCollections2monitor_cff.py:359
PSFitter::HybridMinimizer::EMinimizerType
EMinimizerType
Definition: HybridMinimizer.h:46
g4SimHits_cfi.Tolerance
Tolerance
Definition: g4SimHits_cfi.py:63
cmsLHEtoEOSManager.l
l
Definition: cmsLHEtoEOSManager.py:193
PSFitter::HybridMinimizer
Definition: HybridMinimizer.h:44
PSFitter::HybridMinimizer::CovMatrix
double CovMatrix(unsigned int i, unsigned int j) const override
Definition: HybridMinimizer.cc:545
PSFitter::HybridMinimizer::kSimplex
Definition: HybridMinimizer.h:46
type
type
Definition: HCALResponse.h:21
heppy_batch.val
val
Definition: heppy_batch.py:351
PSFitter::HybridMinimizer::VariableName
std::string VariableName(unsigned int ivar) const override
get name of variables (override if minimizer support storing of variable names)
Definition: HybridMinimizer.cc:231
TrackerOfflineValidation_Dqm_cff.xmax
xmax
Definition: TrackerOfflineValidation_Dqm_cff.py:11
relativeConstraints.value
value
Definition: relativeConstraints.py:53
PSFitter::HybridMinimizer::Clear
void Clear() override
Definition: HybridMinimizer.cc:153
detailsBasic3DVector::y
float float y
Definition: extBasic3DVector.h:14
pileupCalc.upper
upper
Definition: pileupCalc.py:214
Skims_PA_cff.name
name
Definition: Skims_PA_cff.py:17
PSFitter::HybridMinimizer::VariableIndex
int VariableIndex(const std::string &name) const override
Definition: HybridMinimizer.cc:238
mps_fire.result
result
Definition: mps_fire.py:303
funct::abs
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
TrackerOfflineValidation_Dqm_cff.xmin
xmin
Definition: TrackerOfflineValidation_Dqm_cff.py:10
dqmiolumiharvest.j
j
Definition: dqmiolumiharvest.py:66
hlt_dqm_clientPB-live_cfg.me
me
Definition: hlt_dqm_clientPB-live_cfg.py:61
PSFitter::HybridMinimizer::SetFixedVariable
bool SetFixedVariable(unsigned int, const std::string &, double) override
set fixed variable (override if minimizer supports them )
Definition: HybridMinimizer.cc:219
PSFitter::HybridMinimizer::fUseFumili
bool fUseFumili
Definition: HybridMinimizer.h:273
HybridMinimizer.h
PSFitter::HybridMinimizer::GlobalCC
double GlobalCC(unsigned int i) const override
Definition: HybridMinimizer.cc:637
ROOT
Definition: Transform3DPJ.h:35
LaserClient_cfi.low
low
Definition: LaserClient_cfi.py:52
up
Definition: BitonicSort.h:7
PSFitter::HybridMinimizer::Contour
bool Contour(unsigned int i, unsigned int j, unsigned int &npoints, double *xi, double *xj) override
Definition: HybridMinimizer.cc:863
PSFitter::HybridMinimizer::ExamineMinimum
bool ExamineMinimum(const ROOT::Minuit2::FunctionMinimum &min)
examine the minimum result
Definition: HybridMinimizer.cc:408