Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
xRooFit.cxx
Go to the documentation of this file.
1/*
2 * Project: xRooFit
3 * Author:
4 * Will Buttinger, RAL 2022
5 *
6 * Copyright (c) 2022, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
13#include "RVersion.h"
14
15// #define private public
16// #include "Minuit2/Minuit2Minimizer.h"
17// #undef private
18// #include "Minuit2/FunctionMinimum.h"
19
20#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
21#define protected public
22#endif
23#include "RooFitResult.h"
24#ifdef protected
25#undef protected
26#endif
27
28#include "xRooFit/xRooFit.h"
29
30#include "RooDataSet.h"
31#include "RooSimultaneous.h"
32#include "RooArgSet.h"
33#include "RooRandom.h"
34#include "RooAbsPdf.h"
35#include "TUUID.h"
36#include "RooProdPdf.h"
37#include "RooGamma.h"
38#include "RooPoisson.h"
39#include "RooGaussian.h"
40#include "RooBifurGauss.h"
41#include "RooLognormal.h"
42#include "RooBinning.h"
43#include "RooUniformBinning.h"
44
46#include "Math/GenAlgoOptions.h"
47#include "Math/Minimizer.h"
48#include "RooMinimizer.h"
49#include "coutCapture.h"
50
51#include "TCanvas.h"
52#include "TGraphErrors.h"
53#include "TLegend.h"
54#include "TKey.h"
55#include "RooAbsTestStatistic.h"
56#include "TPRegexp.h"
57#include "RooStringVar.h"
58
59#include "RooRealProxy.h"
60#include "RooSuperCategory.h"
61
62#include "xRooFitVersion.h"
63
64#include <signal.h>
65
67
68std::shared_ptr<RooLinkedList> xRooFit::sDefaultNLLOptions = nullptr;
69std::shared_ptr<ROOT::Fit::FitConfig> xRooFit::sDefaultFitConfig = nullptr;
70
71RooCmdArg xRooFit::ReuseNLL(bool flag)
72{
73 return RooCmdArg("ReuseNLL", flag, 0, 0, 0, 0, 0, 0, 0);
74}
75
76RooCmdArg xRooFit::Tolerance(double val)
77{
78 return RooCmdArg("Tolerance", 0, 0, val);
79}
80
81RooCmdArg xRooFit::StrategySequence(const char *val)
82{
83 return RooCmdArg("StrategySequence", 0, 0, 0, 0, val);
84}
85
86xRooNLLVar xRooFit::createNLL(const std::shared_ptr<RooAbsPdf> pdf, const std::shared_ptr<RooAbsData> data,
87 const RooLinkedList &nllOpts)
88{
89 return xRooNLLVar(pdf, data, nllOpts);
90}
91
92xRooNLLVar xRooFit::createNLL(RooAbsPdf &pdf, RooAbsData *data, const RooLinkedList &nllOpts)
93{
94 return createNLL(std::shared_ptr<RooAbsPdf>(&pdf, [](RooAbsPdf *) {}),
95 std::shared_ptr<RooAbsData>(data, [](RooAbsData *) {}), nllOpts);
96}
97
98xRooNLLVar xRooFit::createNLL(RooAbsPdf &pdf, RooAbsData *data, const RooCmdArg &arg1, const RooCmdArg &arg2,
99 const RooCmdArg &arg3, const RooCmdArg &arg4, const RooCmdArg &arg5,
100 const RooCmdArg &arg6, const RooCmdArg &arg7, const RooCmdArg &arg8)
101{
102
104 l.Add((TObject *)&arg1);
105 l.Add((TObject *)&arg2);
106 l.Add((TObject *)&arg3);
107 l.Add((TObject *)&arg4);
108 l.Add((TObject *)&arg5);
109 l.Add((TObject *)&arg6);
110 l.Add((TObject *)&arg7);
111 l.Add((TObject *)&arg8);
112 return createNLL(pdf, data, l);
113}
114
115std::shared_ptr<const RooFitResult>
116xRooFit::fitTo(RooAbsPdf &pdf,
117 const std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> &data,
118 const RooLinkedList &nllOpts, const ROOT::Fit::FitConfig &fitConf)
119{
120 return xRooNLLVar(std::shared_ptr<RooAbsPdf>(&pdf, [](RooAbsPdf *) {}), data, nllOpts)
121 .minimize(std::shared_ptr<ROOT::Fit::FitConfig>(const_cast<ROOT::Fit::FitConfig *>(&fitConf),
122 [](ROOT::Fit::FitConfig *) {}));
123}
124
125std::shared_ptr<const RooFitResult> xRooFit::fitTo(RooAbsPdf &pdf,
126 const std::pair<RooAbsData *, const RooAbsCollection *> &data,
127 const RooLinkedList &nllOpts, const ROOT::Fit::FitConfig &fitConf)
128{
129 return xRooNLLVar(pdf, data, nllOpts)
130 .minimize(std::shared_ptr<ROOT::Fit::FitConfig>(const_cast<ROOT::Fit::FitConfig *>(&fitConf),
131 [](ROOT::Fit::FitConfig *) {}));
132}
133
134std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>>
135xRooFit::generateFrom(RooAbsPdf &pdf, const RooFitResult &_fr, bool expected, int seed)
136{
137
138 std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> out;
139
140 auto fr = &_fr;
141 if (!fr)
142 return out;
143
144 auto _allVars = std::unique_ptr<RooAbsCollection>(pdf.getVariables());
145 auto _snap = std::unique_ptr<RooAbsCollection>(_allVars->snapshot());
146 *_allVars = fr->constPars();
147 *_allVars = fr->floatParsFinal();
148
149 // determine globs from fr constPars
150 auto _globs = std::unique_ptr<RooAbsCollection>(fr->constPars().selectByAttrib("global", true));
151
152 // bool doBinned = false;
153 // RooAbsPdf::GenSpec** gs = nullptr;
154
155 if (seed == 0)
156 seed = RooRandom::randomGenerator()->Integer(std::numeric_limits<uint32_t>::max());
158
159 TString uuid = TUUID().AsString();
160
161 std::function<std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooArgSet>>(RooAbsPdf *)> genSubPdf;
162
163 genSubPdf = [&](RooAbsPdf *_pdf) {
164 std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooArgSet>> _out;
165 // std::unique_ptr<RooArgSet> _obs(_pdf->getParameters(*pars)); // using this "trick" to get observables can
166 // produce 'error' msg because of RooProdPdf trying to setup partial integrals
167 std::unique_ptr<RooArgSet> _obs(_pdf->getVariables());
168 _obs->remove(fr->constPars(), true, true);
169 _obs->remove(fr->floatParsFinal(), true, true); // use this instead
170
171 if (!_globs->empty()) {
172 RooArgSet *toy_gobs = new RooArgSet(uuid + "_globs");
173 // ensure we use the gobs from the model ...
174 RooArgSet t;
175 t.add(*_globs);
176 std::unique_ptr<RooArgSet> globs(_pdf->getObservables(t));
177 globs->snapshot(*toy_gobs);
178 if (!toy_gobs->empty() &&
179 !dynamic_cast<RooSimultaneous *>(
180 _pdf)) { // if was simPdf will call genSubPdf on each subpdf so no need to generate here
181 if (!expected) {
182 *toy_gobs = *std::unique_ptr<RooDataSet>(_pdf->generate(*globs, 1))->get();
183 } else {
184 // loop over pdfs in top-level prod-pdf,
185 auto pp = dynamic_cast<RooProdPdf *>(_pdf);
186 if (pp) {
187 for (auto thePdf : pp->pdfList()) {
188 auto gob = std::unique_ptr<RooArgSet>(thePdf->getObservables(*globs));
189 if (gob->empty())
190 continue;
191 if (gob->size() > 1) {
192 Warning("generate", "%s contains multiple global obs: %s", thePdf->GetName(),
193 gob->contentsString().c_str());
194 continue;
195 }
196 RooRealVar &rrv = dynamic_cast<RooRealVar &>(*gob->first());
197 std::unique_ptr<RooArgSet> cpars(thePdf->getParameters(*globs));
198
199 bool foundServer = false;
200 // note : this will work only for this type of constraints
201 // expressed as RooPoisson, RooGaussian, RooLognormal, RooGamma
202 TClass *cClass = thePdf->IsA();
203 if (cClass != RooGaussian::Class() && cClass != RooPoisson::Class() &&
204 cClass != RooGamma::Class() && cClass != RooLognormal::Class() &&
205 cClass != RooBifurGauss::Class()) {
206 TString className = (cClass) ? cClass->GetName() : "undefined";
207 oocoutW((TObject *)0, Generation)
208 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
209 << " of type " << className << " is a non-supported type - result might be not correct "
210 << std::endl;
211 }
212
213 // in case of a Poisson constraint make sure the rounding is not set
214 if (cClass == RooPoisson::Class()) {
215 RooPoisson *pois = dynamic_cast<RooPoisson *>(thePdf);
216 assert(pois);
217 pois->setNoRounding(true);
218 }
219
220 // look at server of the constraint term and check if the global observable is part of the server
221 RooAbsArg *arg = thePdf->findServer(rrv);
222 if (!arg) {
223 // special case is for the Gamma where one might define the global observable n and you have a
224 // Gamma(b, n+1, ...._ in this case n+1 is the server and we don;t have a direct dependency, but
225 // we want to set n to the b value so in case of the Gamma ignore this test
226 if (cClass != RooGamma::Class()) {
227 oocoutE((TObject *)0, Generation)
228 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
229 << " has no direct dependence on global observable- cannot generate it " << std::endl;
230 continue;
231 }
232 }
233
234 // loop on the server of the constraint term
235 // need to treat the Gamma as a special case
236 // the mode of the Gamma is (k-1)*theta where theta is the inverse of the rate parameter.
237 // we assume that the global observable is defined as ngobs = k-1 and the theta parameter has the
238 // name theta otherwise we use other procedure which might be wrong
239 RooAbsReal *thetaGamma = 0;
240 if (cClass == RooGamma::Class()) {
241 RooFIter itc(thePdf->serverMIterator());
242 for (RooAbsArg *a2 = itc.next(); a2 != 0; a2 = itc.next()) {
243 if (TString(a2->GetName()).Contains("theta")) {
244 thetaGamma = dynamic_cast<RooAbsReal *>(a2);
245 break;
246 }
247 }
248 if (thetaGamma == 0) {
249 oocoutI((TObject *)0, Generation)
250 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
251 << " is a Gamma distribution and no server named theta is found. Assume that the Gamma "
252 "scale is 1 "
253 << std::endl;
254 }
255 }
256 RooFIter iter2(thePdf->serverMIterator());
257 for (RooAbsArg *a2 = iter2.next(); a2 != 0; a2 = iter2.next()) {
258 RooAbsReal *rrv2 = dynamic_cast<RooAbsReal *>(a2);
259 if (rrv2 && !rrv2->dependsOn(*gob) &&
260 (!rrv2->isConstant() || !rrv2->InheritsFrom("RooConstVar"))) {
261
262 // found server not depending on the gob
263 if (foundServer) {
264 oocoutE((TObject *)0, Generation)
265 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
266 << " constraint term has more server depending on nuisance- cannot generate it "
267 << std::endl;
268 foundServer = false;
269 break;
270 }
271 if (thetaGamma && thetaGamma->getVal() > 0)
272 rrv.setVal(rrv2->getVal() / thetaGamma->getVal());
273 else
274 rrv.setVal(rrv2->getVal());
275 foundServer = true;
276 }
277 }
278
279 if (!foundServer) {
280 oocoutE((TObject *)0, Generation)
281 << "AsymptoticCalculator::MakeAsimovData - can't find nuisance for constraint term - global "
282 "observables will not be set to Asimov value "
283 << thePdf->GetName() << std::endl;
284 std::cerr << "Parameters: " << std::endl;
285 cpars->Print("V");
286 std::cerr << "Observables: " << std::endl;
287 gob->Print("V");
288 }
289 }
290 } else {
291 Error("generate", "Cannot generate global observables, pdf is: %s::%s", _pdf->ClassName(),
292 _pdf->GetName());
293 }
294 *toy_gobs = *globs;
295 }
296 }
297 _out.second.reset(toy_gobs);
298 } // end of globs generation
299
300 RooRealVar w("weightVar", "weightVar", 1);
301 if (auto s = dynamic_cast<RooSimultaneous *>(_pdf)) {
302 // do subpdf's individually
303 _obs->add(w);
304 _out.first.reset(new RooDataSet(
305 uuid, TString::Format("%s %s", _pdf->GetTitle(), (expected) ? "Expected" : "Toy"), *_obs, "weightVar"));
306
307 for (auto &c : s->indexCat()) {
308#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 22, 00)
309 std::string cLabel = c.first.c_str();
310#else
311 std::string cLabel = c->GetName();
312#endif
313 auto p = s->getPdf(cLabel.c_str());
314 if (!p)
315 continue;
316 auto toy = genSubPdf(p);
317 if (toy.second && _out.second)
318 *const_cast<RooArgSet *>(_out.second.get()) = *toy.second;
319 _obs->setCatLabel(s->indexCat().GetName(), cLabel.c_str());
320 for (int i = 0; i < toy.first->numEntries(); i++) {
321 *_obs = *toy.first->get(i);
322 _out.first->add(*_obs, toy.first->weight());
323 }
324 }
325 return _out;
326 }
327
328 std::map<RooRealVar *, std::shared_ptr<RooAbsBinning>> binnings;
329
330 for (auto &o : *_obs) {
331 auto r = dynamic_cast<RooRealVar *>(o);
332 if (!r)
333 continue;
334 if (auto res = _pdf->binBoundaries(*r, -std::numeric_limits<double>::infinity(),
335 std::numeric_limits<double>::infinity())) {
336 binnings[r] = std::shared_ptr<RooAbsBinning>(r->getBinning().clone(r->getBinning().GetName()));
337
338 std::vector<double> boundaries;
339 boundaries.reserve(res->size());
340 for (auto &rr : *res) {
341 if (boundaries.empty() || std::abs(boundaries.back() - rr) > 1e-3 ||
342 std::abs(boundaries.back() - rr) > 1e-5 * boundaries.back())
343 boundaries.push_back(rr);
344 } // sometimes get virtual duplicates of boundaries
345 r->setBinning(RooBinning(boundaries.size() - 1, &boundaries[0]));
346 delete res;
347 } else if (r->numBins(r->getBinning().GetName()) == 0 && expected) {
348 // no bins ... in order to generate expected we need to have some bins
349 binnings[r] = std::shared_ptr<RooAbsBinning>(r->getBinning().clone(r->getBinning().GetName()));
350 r->setBinning(RooUniformBinning(r->getMin(), r->getMax(), 100));
351 }
352 }
353
354 // now can generate
355 if (_obs->empty()) {
356 // no observables, create a single dataset with 1 entry ... why 1 entry??
357 _obs->add(w);
358 RooArgSet _tmp;
359 _tmp.add(w);
360 _out.first.reset(new RooDataSet("", "Toy", _tmp, "weightVar"));
361 _out.first->add(_tmp);
362 } else {
363 if (_pdf->canBeExtended()) {
364 _out.first =
365 std::unique_ptr<RooDataSet>{_pdf->generate(*_obs, RooFit::Extended(), RooFit::ExpectedData(expected))};
366 } else {
367 if (expected) {
368 // use AsymptoticCalculator because generate expected not working correctly on unextended pdf?
369 // TODO: Can the above code for expected globs be used instead, or what about replace above code with
370 // ObsToExpected?
371 _out.first.reset(RooStats::AsymptoticCalculator::GenerateAsimovData(*_pdf, *_obs));
372 } else {
373 _out.first = std::unique_ptr<RooDataSet>{_pdf->generate(*_obs, RooFit::ExpectedData(expected))};
374 }
375 }
376 }
377 _out.first->SetName(TUUID().AsString());
378
379 for (auto &b : binnings) {
380 auto v = b.first;
381 auto binning = b.second;
382 v->setBinning(*binning);
383 // range of variable in dataset may be less than in the workspace
384 // if e.g. generate for a specific channel. So need to expand ranges to match
385 auto x = dynamic_cast<RooRealVar *>(_out.first->get()->find(v->GetName()));
386 auto r = x->getRange();
387 if (r.first > binning->lowBound())
388 x->setMin(binning->lowBound());
389 if (r.second < binning->highBound())
390 x->setMax(binning->highBound());
391 }
392 return _out;
393 };
394
395 out = genSubPdf(&pdf);
396 out.first->SetName(expected ? (TString(fr->GetName()) + "_asimov") : uuid);
397
398 // from now on we store the globs in the dataset
399 if (out.second) {
400 out.first->setGlobalObservables(*out.second);
401 out.second.reset();
402 }
403
404#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 26, 00)
405 // store fitResult name on the weightVar
406 if (auto w = dynamic_cast<RooDataSet *>(out.first.get())->weightVar()) {
407 w->setStringAttribute("fitResult", fr->GetName());
408 w->setAttribute("expected", expected);
409 }
410#endif
411
412 *_allVars = *_snap;
413
414 // June2023: Added this because found that generation was otherwise getting progressively slower
415 // the RooAbsPdf::generate does a clone, and it seems that the RooCacheManager of the original pdf
416 // is getting polluted on each generate call, causing it to grow larger and therefore the clone of it
417 // to take longer and longer. So sterilize to clear the caches of all components
418#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
419 auto _ws = pdf._myws;
420#else
421 auto _ws = pdf.workspace();
422#endif
423 if (_ws) {
424 // do explicitly rather than via xRooNode sterilize method because don't want to invoke the constructor
425 // workspace tweaking features (which sets poi etc etc)
426 for (auto obj : _ws->components()) {
427 for (int i = 0; i < obj->numCaches(); i++) {
428 if (auto cache = dynamic_cast<RooObjCacheManager *>(obj->getCache(i))) {
429 cache->reset();
430 }
431 }
432 if (RooAbsPdf *p = dynamic_cast<RooAbsPdf *>(obj); p) {
433 p->setNormRange(p->normRange());
434 }
435 obj->setValueDirty();
436 }
437 // xRooNode(pdf.workspace()).sterilize();
438 }
439
440 return out;
441}
442
443std::shared_ptr<RooLinkedList> xRooFit::createNLLOptions()
444{
445 auto out = std::shared_ptr<RooLinkedList>(new RooLinkedList, [](RooLinkedList *l) {
446 l->Delete();
447 delete l;
448 });
449 for (auto opt : *defaultNLLOptions()) {
450 out->Add(opt->Clone(nullptr)); // nullptr needed because accessing Clone via TObject base class puts
451 // "" instead, so doesnt copy names
452 }
453 return out;
454}
455
456std::shared_ptr<RooLinkedList> xRooFit::defaultNLLOptions()
457{
458 if (sDefaultNLLOptions)
459 return sDefaultNLLOptions;
460 sDefaultNLLOptions = std::shared_ptr<RooLinkedList>(new RooLinkedList, [](RooLinkedList *l) {
461 l->Delete();
462 delete l;
463 });
464 sDefaultNLLOptions->Add(RooFit::Offset().Clone());
465 // disable const-optimization at the construction step ... can happen in the minimization though
466 sDefaultNLLOptions->Add(RooFit::Optimize(0).Clone());
467 return sDefaultNLLOptions;
468}
469
470std::shared_ptr<ROOT::Fit::FitConfig> xRooFit::createFitConfig()
471{
472 return std::make_shared<ROOT::Fit::FitConfig>(*defaultFitConfig());
473}
474
475std::shared_ptr<ROOT::Fit::FitConfig> xRooFit::defaultFitConfig()
476{
477 if (sDefaultFitConfig)
478 return sDefaultFitConfig;
479 sDefaultFitConfig = std::make_shared<ROOT::Fit::FitConfig>();
480 auto &fitConfig = *sDefaultFitConfig;
481 fitConfig.SetParabErrors(true); // will use to run hesse after fit
482 fitConfig.MinimizerOptions().SetMinimizerType("Minuit2");
483 fitConfig.MinimizerOptions().SetErrorDef(0.5); // ensures errors are +/- 1 sigma ..IMPORTANT
484 fitConfig.SetParabErrors(true); // runs HESSE
485 fitConfig.SetMinosErrors(true); // computes asymmetric errors on any parameter with the "minos" attribute set
486 fitConfig.MinimizerOptions().SetMaxFunctionCalls(
487 -1); // calls per iteration. if left as 0 will set automatically to 500*nPars below
488 fitConfig.MinimizerOptions().SetMaxIterations(-1); // if left as 0 will set automatically to 500*nPars
489 fitConfig.MinimizerOptions().SetStrategy(-1); // will start at front of StrategySequence (given below)
490 // fitConfig.MinimizerOptions().SetTolerance(
491 // 1); // default is 0.01 (i think) but roominimizer uses 1 as default - use specify with
492 // ROOT::Math::MinimizerOptions::SetDefaultTolerance(..)
493 fitConfig.MinimizerOptions().SetPrintLevel(-2);
494 fitConfig.MinimizerOptions().SetExtraOptions(ROOT::Math::GenAlgoOptions());
495 // have to const cast to set extra options
496 auto extraOpts = const_cast<ROOT::Math::IOptions *>(fitConfig.MinimizerOptions().ExtraOptions());
497 extraOpts->SetValue("OptimizeConst", 2); // if 0 will disable constant term optimization and cache-and-track of the
498 // NLL. 1 = just caching, 2 = cache and track
499#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 29, 00)
500 extraOpts->SetValue("StrategySequence", "0s01s12s2s3m");
501 extraOpts->SetValue("HesseStrategy", 3); // if hesse is run after minimization, will use this strategy
502#else
503 extraOpts->SetValue("StrategySequence", "0s01s12s2m");
504 extraOpts->SetValue("HesseStrategy", 2); // when hesse is run after minimization, will use this strategy
505#endif
506 extraOpts->SetValue("LogSize", 0); // length of log to capture and save
507 extraOpts->SetValue("BoundaryCheck",
508 0.); // if non-zero, warn if any post-fit value is close to boundary (e.g. 0.01 = within 1%)
509 extraOpts->SetValue("TrackProgress", 30); // seconds between output to log of evaluation progress
510 extraOpts->SetValue("xRooFitVersion", GIT_COMMIT_HASH); // not really options but here for logging purposes
511 // extraOpts->SetValue("ROOTVersion",ROOT_VERSION_CODE); - not needed as should by part of the ROOT TFile definition
512
513 // extraOpts->SetValue("HessianStepTolerance",0.);
514 // extraOpts->SetValue("HessianG2Tolerance",0.);
515
516 return sDefaultFitConfig;
517}
518
520public:
521 void (*oldHandlerr)(int) = nullptr;
523 static bool fInterrupt;
524 static void interruptHandler(int signum)
525 {
526 if (signum == SIGINT) {
527 std::cout << "Minimization interrupted ... will exit as soon as possible" << std::endl;
528 // TODO: create a global mutex for this
529 fInterrupt = true;
530 } else {
531 if (me)
532 me->oldHandlerr(signum);
533 }
534 };
535 ProgressMonitor(RooAbsReal &f, int interval = 30)
536 : RooAbsReal(Form("progress_%s", f.GetName()), ""), fFunc("func", "func", this, f), fInterval(interval)
537 {
538 s.Start();
539 oldHandlerr = signal(SIGINT, interruptHandler);
540 me = this;
541 vars.reset(std::unique_ptr<RooAbsCollection>(f.getVariables())->selectByAttrib("Constant", false));
542 }
544 {
545 if (oldHandlerr) {
546 signal(SIGINT, oldHandlerr);
547 }
548 if (me == this)
549 me = nullptr;
550 };
551 ProgressMonitor(const ProgressMonitor &other, const char *name = 0)
552 : RooAbsReal(other, name), fFunc("func", this, other.fFunc), fInterval(other.fInterval)
553 {
554 }
555 virtual TObject *clone(const char *newname) const override { return new ProgressMonitor(*this, newname); }
556
557 double evaluate() const override
558 {
559 if (fInterrupt) {
560 throw std::runtime_error("Keyboard interrupt");
561 return std::numeric_limits<double>::quiet_NaN();
562 }
563 double out = fFunc;
564 if (prevMin == std::numeric_limits<double>::infinity()) {
565 prevMin = out;
567 }
568 if (!std::isnan(out)) {
569 if (out < minVal) {
570 if (minPars.empty())
572 minPars = *vars;
573 }
574 minVal = std::min(minVal, out);
575 }
576 counter++;
577 if (s.RealTime() > fInterval) {
578 double evalRate = (counter - prevCounter) / s.RealTime();
579 s.Reset();
580 std::cerr << (counter) << ") (" << evalRate << "Hz) " << TDatime().AsString();
581 if (!fState.empty())
582 std::cerr << " : " << fState;
583 std::cerr << " : " << minVal << " Delta = " << (minVal - prevMin);
584 if (minVal < prevMin) {
585 std::cerr << " : ";
586 // compare minPars and prevPars, print biggest deltas
587 std::vector<std::pair<double, std::string>> parDeltas;
588 parDeltas.reserve(minPars.size());
589 for (auto p : minPars) {
590 parDeltas.emplace_back(std::pair<double, std::string>(
591 dynamic_cast<RooRealVar *>(p)->getVal() - prevPars.getRealValue(p->GetName()), p->GetName()));
592 }
593 std::sort(parDeltas.begin(), parDeltas.end(),
594 [](auto &left, auto &right) { return std::abs(left.first) > std::abs(right.first); });
595 int i;
596 for (i = 0; i < std::min(3, int(parDeltas.size())); i++) {
597 if (parDeltas.at(i).first == 0)
598 break;
599 if (i != 0)
600 std::cerr << ",";
601 std::cerr << parDeltas.at(i).second << (parDeltas.at(i).first >= 0 ? "+" : "-") << "="
602 << std::abs(parDeltas.at(i).first) << "("
603 << minPars.getRealValue(parDeltas.at(i).second.c_str()) << ")";
604 }
605 if (i < int(parDeltas.size()) && parDeltas.at(i).first != 0)
606 std::cerr << " ...";
608 }
609 std::cerr << std::endl;
610 prevMin = minVal;
612 } else {
613 s.Continue();
614 }
615 return out;
616 }
617
618 std::string fState;
619
620private:
622 mutable int counter = 0;
623 mutable double minVal = std::numeric_limits<double>::infinity();
624 mutable double prevMin = std::numeric_limits<double>::infinity();
627 mutable int prevCounter = 0;
628 mutable int fInterval = 0; // time in seconds before next report
629 mutable TStopwatch s;
630 std::shared_ptr<RooAbsCollection> vars;
631};
632bool ProgressMonitor::fInterrupt = false;
634
635xRooFit::StoredFitResult::StoredFitResult(RooFitResult *_fr) : TNamed(*_fr)
636{
637 fr.reset(_fr);
638}
639
640xRooFit::StoredFitResult::StoredFitResult(const std::shared_ptr<RooFitResult> &_fr) : TNamed(*_fr)
641{
642 fr = _fr;
643}
644
645std::shared_ptr<const RooFitResult> xRooFit::minimize(RooAbsReal &nll,
646 const std::shared_ptr<ROOT::Fit::FitConfig> &_fitConfig,
647 const std::shared_ptr<RooLinkedList> &nllOpts)
648{
649
650 auto myFitConfig = _fitConfig ? _fitConfig : createFitConfig();
651 auto &fitConfig = *myFitConfig;
652
653 auto _nll = &nll;
654
655 TString resultTitle = nll.getStringAttribute("fitresultTitle");
656 TString fitName = TUUID().AsString();
657 if (resultTitle == "")
658 resultTitle = TUUID(fitName).GetTime().AsString();
659
660 // extract any user pars from the nll too
661 RooArgList fUserPars;
662 if (nll.getStringAttribute("userPars")) {
663 TStringToken st(nll.getStringAttribute("userPars"), ",");
664 while (st.NextToken()) {
665 TString parName = st;
666 TString parVal = nll.getStringAttribute(parName);
667 if (parVal.IsFloat())
668 fUserPars.addClone(RooRealVar(parName, parName, parVal.Atof()));
669 else
670 fUserPars.addClone(RooStringVar(parName, parName, parVal));
671 }
672 }
673
674 auto _nllVars = std::unique_ptr<RooAbsCollection>(_nll->getVariables());
675
676 std::unique_ptr<RooAbsCollection> constPars(_nllVars->selectByAttrib("Constant", true));
677 constPars->add(fUserPars, true); // add here so checked for when loading from cache
678 std::unique_ptr<RooAbsCollection> floatPars(_nllVars->selectByAttrib("Constant", false));
679
680 int _progress = 0;
681 double boundaryCheck = 0;
682 std::string s;
683 int logSize = 0;
684#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 29, 00)
685 int hesseStrategy = 3; // uses most precise hesse settings (step sizes and g2 tolerances)
686#else
687 int hesseStrategy = 2; // uses most precise hesse settings (step sizes and g2 tolerances)
688#endif
689 if (fitConfig.MinimizerOptions().ExtraOptions()) {
690 fitConfig.MinimizerOptions().ExtraOptions()->GetNamedValue("StrategySequence", s);
691 fitConfig.MinimizerOptions().ExtraOptions()->GetIntValue("TrackProgress", _progress);
692 fitConfig.MinimizerOptions().ExtraOptions()->GetRealValue("BoundaryCheck", boundaryCheck);
693 fitConfig.MinimizerOptions().ExtraOptions()->GetIntValue("LogSize", logSize);
694 fitConfig.MinimizerOptions().ExtraOptions()->GetIntValue("HesseStrategy", hesseStrategy);
695 }
696 TString m_strategy = s;
697
698 // if fit caching enabled, try to locate a valid fitResult
699 // must have matching constPars
700 TDirectory *cacheDir = gDirectory;
701
702 if (cacheDir) {
703 if (auto nllDir = cacheDir->GetDirectory(nll.GetName()); nllDir) {
704 if (auto keys = nllDir->GetListOfKeys(); keys) {
705 for (auto &&k : *keys) {
706 auto cl = TClass::GetClass(((TKey *)k)->GetClassName());
707 if (cl->InheritsFrom("RooFitResult")) {
708 StoredFitResult *storedFr =
709 nllDir->GetList() ? dynamic_cast<StoredFitResult *>(nllDir->GetList()->FindObject(k->GetName()))
710 : nullptr;
711 if (auto cachedFit =
712 (storedFr) ? storedFr->fr.get() : dynamic_cast<TKey *>(k)->ReadObject<RooFitResult>();
713 cachedFit) {
714 if (!storedFr) {
715 storedFr = new StoredFitResult(cachedFit);
716 nllDir->Add(storedFr);
717 // std::cout << "Loaded " << nllDir->GetPath() << "/" << k->GetName() << " : " << k->GetTitle()
718 // << std::endl;
719 }
720 bool match = true;
721 if (!cachedFit->floatParsFinal().equals(*floatPars)) {
722 match = false;
723 } else {
724 for (auto &p : *constPars) {
725 auto v = dynamic_cast<RooAbsReal *>(p);
726 if (!v) {
727 match = false;
728 break;
729 };
730 if (auto _p = dynamic_cast<RooAbsReal *>(cachedFit->constPars().find(p->GetName())); _p) {
731 // note: do not need global observable values to match (globals currently added to
732 // constPars list)
733 if (!_p->getAttribute("global") && std::abs(_p->getVal() - v->getVal()) > 1e-12) {
734 match = false;
735 break;
736 }
737 }
738 }
739 }
740 if (match) {
741 return storedFr->fr;
742 // return std::shared_ptr<RooFitResult>(cachedFit,[](RooFitResult*){}); // dir owns the
743 // fitResult - this means dir needs to stay open for fits to be valid return
744 // std::make_shared<RooFitResult>(*cachedFit); // return a copy ... dir doesn't need to stay
745 // open, but fit result isn't shared
746 } else {
747 // delete cachedFit;
748 }
749 }
750 }
751 }
752 }
753 }
754 }
755
756 if (nll.getAttribute("readOnly"))
757 return nullptr;
758
759 int printLevel = fitConfig.MinimizerOptions().PrintLevel();
761 if (printLevel < 0)
763
764 // check how many parameters we have ... if 0 parameters then we wont run a fit, we just evaluate nll and return ...
765 if (floatPars->empty() || fitConfig.MinimizerOptions().MaxFunctionCalls() == 1) {
766 std::shared_ptr<RooFitResult> result;
767 RooArgList parsList;
768 parsList.add(*floatPars);
769 // construct an empty fit result ...
770 result = std::make_shared<RooFitResult>(); // if put name here fitresult gets added to dir, we don't want that
771 result->SetName(TUUID().AsString());
772 result->SetTitle(resultTitle);
773 result->setFinalParList(parsList);
774 result->setInitParList(parsList);
775 result->setConstParList(dynamic_cast<RooArgSet &>(*constPars)); /* RooFitResult takes a snapshot */
777 d.ResizeTo(parsList.size(), parsList.size());
778 result->setCovarianceMatrix(d);
779 result->setCovQual(-1);
780 result->setMinNLL(_nll->getVal());
781 result->setEDM(0);
782 result->setStatus(floatPars->getSize() == 0 ? 0 : 1);
783
784 std::vector<std::pair<std::string, int>> statusHistory;
785 statusHistory.emplace_back(std::make_pair("EVAL", result->status()));
786 result->setStatusHistory(statusHistory);
787
788 if (cacheDir && cacheDir->IsWritable()) {
789 // save a copy of fit result to relevant dir
790 if (!cacheDir->GetDirectory(nll.GetName()))
791 cacheDir->mkdir(nll.GetName());
792 if (auto dir = cacheDir->GetDirectory(nll.GetName()); dir) {
793 // save NLL opts if was given one, unless already present
794 if (nllOpts) {
795 if (strlen(nllOpts->GetName()) == 0) {
796 nllOpts->SetName(TUUID().AsString());
797 }
798 if (!dir->FindKey(nllOpts->GetName())) {
799 dir->WriteObject(nllOpts.get(), nllOpts->GetName());
800 }
801 }
802 dir->WriteObject(result.get(), result->GetName());
803 }
804 }
805
806 if (printLevel < 0)
808 return result;
809 }
810
811 std::shared_ptr<RooFitResult> out;
812
813 // check if any floatPars are categorical .. if so, need to a "discrete minimization" over the permutations
814 RooArgSet floatCats;
815 for (auto p : *floatPars) {
816 if (p->isCategory()) {
817 floatCats.add(*p);
818 }
819 }
820 if (!floatCats.empty()) {
821 RooSuperCategory allCats("floatCats", "Floating categorical parameters", floatCats);
822 std::unique_ptr<RooAbsCollection> _snap(floatCats.snapshot());
823 floatCats.setAttribAll("Constant");
824
825 std::shared_ptr<const RooFitResult> bestFr;
826 for (auto c : allCats) {
827 allCats.setIndex(c.second);
828 Info("minimize", "Minimizing with discrete %s", c.first.c_str());
829 auto fr = minimize(nll, _fitConfig, nllOpts);
830 if (!fr) {
831 Warning("minimize", "Minimization with discrete %s failed", c.first.c_str());
832 continue;
833 }
834 if (!bestFr || fr->minNll() < bestFr->minNll()) {
835 bestFr = fr;
836 }
837 }
838
839 floatCats.setAttribAll("Constant", false);
840
841 if (!bestFr)
842 return out;
843
844 // create a copy of the fit result, give it a new uuid, and move the const categories into the float area
845 out = std::make_shared<RooFitResult>(*bestFr);
846 const_cast<RooArgList &>(out->floatParsFinal())
847 .addClone(*std::unique_ptr<RooAbsCollection>(out->constPars().selectCommon(floatCats)));
848 const_cast<RooArgList &>(out->floatParsInit()).addClone(*_snap);
849 const_cast<RooArgList &>(out->constPars()).remove(floatCats);
850 out->SetName(TUUID().AsString());
851 }
852
853 bool restore = !fitConfig.UpdateAfterFit();
854 std::string logs;
855 if (!out) {
856 int strategy = fitConfig.MinimizerOptions().Strategy();
857 // Note: AsymptoticCalculator enforces not less than 1 on tolerance - should we do so too?
858 if (_progress) {
859 _nll = new ProgressMonitor(*_nll, _progress);
861 }
862 auto logger = (logSize > 0) ? std::make_unique<cout_redirect>(logs, logSize) : nullptr;
863 RooMinimizer _minimizer(*_nll);
864 _minimizer.fitter()->Config() = fitConfig;
865 // if(fitConfig.MinimizerOptions().ExtraOptions()) {
866 // //for loading hesse options
867 // double a;
868 // if(fitConfig.MinimizerOptions().ExtraOptions()->GetValue("HessianStepTolerance",a)) {
869 // ROOT::Math::MinimizerOptions::Default("Minuit2").SetValue("HessianStepTolerance",a);
870 // }
871 // if(fitConfig.MinimizerOptions().ExtraOptions()->GetValue("HessianG2Tolerance",a)) {
872 // ROOT::Math::MinimizerOptions::Default("Minuit2").SetValue("HessianG2Tolerance",a);
873 // }
874 // }
875
876 bool autoMaxCalls = (_minimizer.fitter()->Config().MinimizerOptions().MaxFunctionCalls() == 0);
877 if (autoMaxCalls) {
879 500 * floatPars->size() * floatPars->size()); // hesse requires O(N^2) function calls
880 }
881 if (_minimizer.fitter()->Config().MinimizerOptions().MaxIterations() == 0) {
882 _minimizer.fitter()->Config().MinimizerOptions().SetMaxIterations(500 * floatPars->size());
883 }
884
885 bool hesse = _minimizer.fitter()->Config().ParabErrors();
886 _minimizer.fitter()->Config().SetParabErrors(
887 false); // turn "off" so can run hesse as a separate step, appearing in status
888 bool minos = _minimizer.fitter()->Config().MinosErrors();
889 _minimizer.fitter()->Config().SetMinosErrors(false);
890 _minimizer.fitter()->Config().SetUpdateAfterFit(true); // note: seems to always take effect
891
892 std::vector<std::pair<std::string, int>> statusHistory;
893
894 // gCurrentSampler = this;
895 // gOldHandlerr = signal(SIGINT,toyInterruptHandlerr);
896
897 TString actualFirstMinimizer = _minimizer.fitter()->Config().MinimizerType();
898
899 int status = 0;
900
901 int constOptimize = 2;
902 _minimizer.fitter()->Config().MinimizerOptions().ExtraOptions()->GetValue("OptimizeConst", constOptimize);
903 if (constOptimize) {
904 _minimizer.optimizeConst(constOptimize);
905 // for safety force a refresh of the cache (and tracking) in the nll
906 // DO NOT do a ConfigChange ... this is just a deactivate-reactivate of caching
907 // but it seems like doing this breaks the const optimization and function is badly behaved
908 // so once its turned on never turn it off.
909 // nll.constOptimizeTestStatistic(RooAbsArg::ConfigChange, constOptimize>1 /* do tracking too if >1 */); //
910 // trigger a re-evaluate of which nodes to cache-and-track
911 // the next line seems safe to do but wont bother doing it because not bothering with above
912 // need to understand why turning the cache off and on again breaks it??
913 // nll.constOptimizeTestStatistic(RooAbsArg::ValueChange, constOptimize>1); // update the cache values -- is
914 // this needed??
915 } else {
916 // disable const optimization
917 // warning - if the nll was previously activated then it seems like deactivating may break it.
919 }
920
921 int sIdx = -1;
922 TString minim = _minimizer.fitter()->Config().MinimizerType();
923 TString algo = _minimizer.fitter()->Config().MinimizerAlgoType();
924 if (minim == "Minuit2") {
925 if (strategy == -1)
926 sIdx = 0;
927 else
928 sIdx = m_strategy.Index('0' + strategy);
929 if (sIdx == -1) {
930 Warning("minimize", "Strategy %d not specified in StrategySequence %s ... defaulting to start of sequence",
931 strategy, m_strategy.Data());
932 sIdx = 0;
933 }
934 } else if (minim == "Minuit")
935 sIdx = m_strategy.Index('m');
936
937 int tries = 0;
938 int maxtries = 4;
939 bool first = true;
940 while (tries < maxtries && sIdx != -1) {
941 if (m_strategy(sIdx) == 'm') {
942 minim = "Minuit";
943 algo = "migradImproved";
944 } else if (m_strategy(sIdx) == 's') {
945 algo = "Scan";
946 } else {
947 strategy = int(m_strategy(sIdx) - '0');
948 _minimizer.setStrategy(strategy);
949 minim = "Minuit2";
950 algo = "Migrad";
951 }
952 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff) {
953 fff->fState = minim + algo + std::to_string(_minimizer.fitter()->Config().MinimizerOptions().Strategy());
954 }
955 try {
956 status = _minimizer.minimize(minim, algo);
957 } catch (const std::exception &e) {
958 std::cerr << "Exception while minimizing: " << e.what() << std::endl;
959 }
960 if (first && actualFirstMinimizer != _minimizer.fitter()->Config().MinimizerType())
961 actualFirstMinimizer = _minimizer.fitter()->Config().MinimizerType();
962 first = false;
963 tries++;
964
965 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff && fff->fInterrupt) {
966 delete _nll;
967 throw std::runtime_error("Keyboard interrupt while minimizing");
968 }
969
970 // RooMinimizer loses the useful status code, so here we will override it
971 status = _minimizer.fitter()
972 ->Result()
973 .Status(); // note: Minuit failure is status code 4, minuit2 that is edm above max
974 minim = _minimizer.fitter()->Config().MinimizerType(); // may have changed value
975 statusHistory.emplace_back(_minimizer.fitter()->Config().MinimizerType() +
976 _minimizer.fitter()->Config().MinimizerAlgoType() +
977 std::to_string(_minimizer.fitter()->Config().MinimizerOptions().Strategy()),
978 status);
979 if (status % 1000 == 0)
980 break; // fit was good
981
982 if (status == 4 && minim != "Minuit") {
983 if (printLevel >= -1)
984 Warning("fitTo", "%s Hit max function calls of %d", fitName.Data(),
985 _minimizer.fitter()->Config().MinimizerOptions().MaxFunctionCalls());
986 if (autoMaxCalls) {
987 if (printLevel >= -1)
988 Warning("fitTo", "will try doubling this");
990 _minimizer.fitter()->Config().MinimizerOptions().MaxFunctionCalls() * 2);
992 _minimizer.fitter()->Config().MinimizerOptions().MaxIterations() * 2);
993 continue;
994 }
995 }
996
997 // NOTE: minuit2 seems to distort the tolerance in a weird way, so that tol becomes 1000 times smaller than
998 // specified Also note that if fits are failing because of edm over max, it can be a good idea to activate the
999 // Offset option when building nll
1000 if (printLevel >= -1)
1001 Warning("fitTo", "%s %s%s Status=%d (edm=%f, tol=%f, strat=%d), tries=#%d...", fitName.Data(),
1002 _minimizer.fitter()->Config().MinimizerType().c_str(),
1003 _minimizer.fitter()->Config().MinimizerAlgoType().c_str(), status,
1004 _minimizer.fitter()->Result().Edm(), _minimizer.fitter()->Config().MinimizerOptions().Tolerance(),
1005 _minimizer.fitter()->Config().MinimizerOptions().Strategy(), tries);
1006
1007 // decide what to do next based on strategy sequence
1008 if (sIdx == m_strategy.Length() - 1) {
1009 break; // done
1010 }
1011
1012 tries--;
1013 sIdx++;
1014 }
1015
1016 /* Minuit2 status codes:
1017 * status = 0 : OK
1018 status = 1 : Covariance was made pos defined
1019 status = 2 : Hesse is invalid
1020 status = 3 : Edm is above max
1021 status = 4 : Reached call limit
1022 status = 5 : Any other failure
1023
1024 For Minuit its basically 0 is OK, 4 is failure, I think?
1025 */
1026
1027 if (printLevel >= -1 && status != 0) {
1028 Warning("fitTo", "%s final status is %d", fitName.Data(), status);
1029 }
1030
1031 // currently dont have a way to access the covariance "dcovar" which is a metric from iterative
1032 // covariance method that is used by minuit2 to say if the covariance is accurate or not
1033 // See MinimumError.h: IsAccurate if Dcovar < 0.1
1034 // Note that if strategy=2 or strategy=1 and Dcovar>0.05 then hesse will be forced to be run (see
1035 // VariadicMetricBuilder) So only in Strategy=0 can you skip hesse (even if SetParabErrors false).
1036
1037 double dCovar = std::numeric_limits<double>::quiet_NaN();
1038 // if(auto _minuit2 = dynamic_cast<ROOT::Minuit2::Minuit2Minimizer*>(_minimizer.fitter()->GetMinimizer());
1039 // _minuit2 && _minuit2->fMinimum) {
1040 // dCovar = _minuit2->fMinimum->Error().Dcovar();
1041 // }
1042
1043 // only do hesse if was a valid min and not strat2 or above (since such strat already ran hesse, albeit with
1044 // allowing for forced pos-def) or if requested hesse strategy is different to the strategy that minimization ran
1045 // at
1046 if (hesse && (strategy < 2 || strategy != hesseStrategy) && _minimizer.fitter()->Result().IsValid()) {
1047 // Note: minima where the covariance was made posdef are deemed 'valid' ...
1048
1049 // remove limits on pars before calculation - CURRENTLY HAS NO EFFECT, minuit still holds the state as
1050 // transformed interesting note: error on pars before hesse can be significantly smaller than after hesse ...
1051 // what is the pre-hesse error corresponding to? - corresponds to approximation of covariance matrix calculated
1052 // with iterative method
1053 /*auto parSettings = _minimizer.fitter()->Config().ParamsSettings();
1054 for (auto &ss : _minimizer.fitter()->Config().ParamsSettings()) {
1055 ss.RemoveLimits();
1056 }
1057
1058 for(auto f : *floatPars) {
1059 auto v = dynamic_cast<RooRealVar*>(f);
1060 if(v->hasRange(nullptr)) v->setRange("backup",v->getMin(),v->getMax());
1061 v->removeRange();
1062 }*/
1063
1064 // std::cout << "nIterations = " << _minimizer.fitter()->GetMinimizer()->NIterations() << std::endl;
1065 // std::cout << "covQual before hesse = " << _minimizer.fitter()->GetMinimizer()->CovMatrixStatus() <<
1066 // std::endl;
1067
1068 _minimizer.fitter()->Config().MinimizerOptions().SetStrategy(hesseStrategy);
1069
1070 // const_cast<ROOT::Math::IOptions*>(_minimizer.fitter()->Config().MinimizerOptions().ExtraOptions())->SetValue("HessianStepTolerance",0.1);
1071 // const_cast<ROOT::Math::IOptions*>(_minimizer.fitter()->Config().MinimizerOptions().ExtraOptions())->SetValue("HessianG2Tolerance",0.02);
1072
1073 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff) {
1074 fff->fState = TString::Format("Hesse%d", _minimizer.fitter()->Config().MinimizerOptions().Strategy());
1075 }
1076
1077 //_nll->getVal(); // for reasons I dont understand, if nll evaluated before hesse call the edm is smaller? -
1078 // and also becomes WRONG :-S
1079
1080 // auto _status = (_minimizer.fitter()->CalculateHessErrors()) ? _minimizer.fitter()->Result().Status() : -1;
1081 auto _status = _minimizer.hesse(); // note: I have seen that you can get 'full covariance quality' without
1082 // running hesse ... is that expected?
1083 // note: hesse status will be -1 if hesse failed (no covariance matrix)
1084 // otherwise the status appears to be whatever was the status before
1085 // note that hesse succeeds even if the cov matrix it calculates is forced pos def. Failure is only
1086 // if it cannot calculate a cov matrix at all.
1087 if (_status != -1)
1088 _status = 0; // mark as hesse succeeded, although need to look at covQual to see if was any good
1089
1090 /*for(auto f : *floatPars) {
1091 auto v = dynamic_cast<RooRealVar*>(f);
1092 if(v->hasRange("backup")) {
1093 v->setRange(v->getMin(),v->getMax());
1094 v->removeRange("backup");
1095 }
1096 }
1097 _minimizer.fitter()->Config().SetParamsSettings(parSettings);*/
1098
1099 /*for (auto &ss : _minimizer.fitter()->Config().ParamsSettings()) {
1100 if( ss.HasLowerLimit() || ss.HasUpperLimit() ) std::cout << ss.Name() << " limit restored " <<
1101 ss.LowerLimit() << " - " << ss.UpperLimit() << std::endl;
1102 }*/
1103
1104 statusHistory.push_back(std::pair<std::string, int>(
1105 TString::Format("Hesse%d", _minimizer.fitter()->Config().MinimizerOptions().Strategy()), _status));
1106
1107 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff && fff->fInterrupt) {
1108 delete _nll;
1109 throw std::runtime_error("Keyboard interrupt while hesse calculating");
1110 }
1111 if (_status != 0 && status == 0 && printLevel >= -1) {
1112 Warning("fitTo", "%s hesse status is %d", fitName.Data(), _status);
1113 }
1114 }
1115
1116 // call minos if requested on any parameters
1117 if (status == 0 && minos) {
1118 if (std::unique_ptr<RooAbsCollection> mpars(floatPars->selectByAttrib("minos", true)); !mpars->empty()) {
1119 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff) {
1120 fff->fState = "Minos";
1121 }
1122 auto _status = _minimizer.minos(*mpars);
1123 statusHistory.push_back(std::pair("Minos", _status));
1124 }
1125 }
1126
1127 // DO NOT DO THIS - seems to mess with the NLL function in a way that breaks the cache - reactivating wont fix
1128 // if(constOptimize) { _minimizer.optimizeConst(0); } // doing this because saw happens in RooAbsPdf::minimizeNLL
1129 // method
1130
1131 // signal(SIGINT,gOldHandlerr);
1132 out = std::unique_ptr<RooFitResult>{_minimizer.save(fitName, resultTitle)};
1133
1134 // if status is 0 (min succeeded) but the covQual isn't fully accurate but requested hesse, reflect that in the
1135 // status
1136 if (out->status() == 0 && out->covQual() != 3 && hesse) {
1137 if (out->covQual() == 2) { // was made posdef
1138 out->setStatus(1); // indicates covariance made pos-def
1139 } else { // anything else indicates either hessian is approximate or something else wrong (e.g. not pos-def
1140 // return from strat3)
1141 out->setStatus(2); // hesse invalid
1142 }
1143 }
1144
1145 out->setStatusHistory(statusHistory);
1146
1147 // userPars wont have been added to the RooFitResult by RooMinimizer
1148 const_cast<RooArgList &>(out->constPars()).addClone(fUserPars, true);
1149
1150 if (!std::isnan(dCovar)) {
1151 const_cast<RooArgList &>(out->constPars())
1152 .addClone(RooRealVar(".dCovar", "dCovar from minimization", dCovar), true);
1153 }
1154
1155 if (boundaryCheck) {
1156 // check if any of the parameters are at their limits (potentially a problem with fit)
1157 // or their errors go over their limits (just a warning)
1158 RooFIter itr = floatPars->fwdIterator();
1159 RooAbsArg *a = 0;
1160 int limit_status = 0;
1161 std::string listpars;
1162 while ((a = itr.next())) {
1163 RooRealVar *v = dynamic_cast<RooRealVar *>(a);
1164 if (!v)
1165 continue;
1166 double vRange = v->getMax() - v->getMin();
1167 if (v->getMin() > v->getVal() - vRange * boundaryCheck ||
1168 v->getMax() < v->getVal() + vRange * boundaryCheck) {
1169 // within 0.01% of edge
1170
1171 // check if nll actually lower 'at' the boundary, if it is, refine the best fit to the limit value
1172 auto tmp = v->getVal();
1173 v->setVal(v->getMin());
1174 double boundary_nll = _nll->getVal();
1175 if (boundary_nll <= out->minNll()) {
1176 static_cast<RooRealVar *>(out->floatParsFinal().find(v->GetName()))->setVal(v->getMin());
1177 out->setMinNLL(boundary_nll);
1178 // Info("fit","Corrected %s onto minimum @ %g",v->GetName(),v->getMin());
1179 } else {
1180 // not better, so restore value
1181 v->setVal(tmp);
1182 }
1183
1184 // if has a 'physical' range specified, don't warn if near the limit
1185 if (v->hasRange("physical"))
1186 limit_status = 900;
1187 listpars += v->GetName();
1188 listpars += ",";
1189 } else if (hesse &&
1190 (v->getMin() > v->getVal() - v->getError() || v->getMax() < v->getVal() + v->getError())) {
1191 if (printLevel >= 0) {
1192 Info("minimize", "PARLIM: %s (%f +/- %f) range (%f - %f)", v->GetName(), v->getVal(), v->getError(),
1193 v->getMin(), v->getMax());
1194 }
1195 limit_status = 9000;
1196 }
1197 }
1198 if (limit_status == 900) {
1199 if (printLevel >= 0)
1200 Warning("minimize", "BOUNDCHK: Parameters within %g%% limit in fit result: %s", boundaryCheck * 100,
1201 listpars.c_str());
1202 } else if (limit_status > 0) {
1203 if (printLevel >= 0)
1204 Warning("minimize", "BOUNDCHK: Parameters near limit in fit result");
1205 }
1206
1207 // store the limit check result
1208 statusHistory.emplace_back("BOUNDCHK", limit_status);
1209 out->setStatusHistory(statusHistory);
1210 out->setStatus(out->status() + limit_status);
1211 }
1212
1213 // // automatic parameter range adjustment based on errors
1214 // for(auto a : *floatPars) {
1215 // RooRealVar *v = dynamic_cast<RooRealVar *>(a);
1216 // if(v->getMin() > v->getVal() - 3.*v->getError()) {
1217 // v->setMin(v->getVal() - 3.1*v->getError());
1218 // }
1219 // if(v->getMax() < v->getVal() + 3.*v->getError()) {
1220 // v->setMax(v->getVal() + 3.1*v->getError());
1221 // }
1222 // // also make sure the range isn't too big (fits can struggle)
1223 // if(v->getMin() < v->getVal() - 10.*v->getError()) {
1224 // v->setMin(v->getVal() - 9.9*v->getError());
1225 // }
1226 // if(v->getMax() > v->getVal() + 10.*v->getError()) {
1227 // v->setMax(v->getVal() + 9.9*v->getError());
1228 // }
1229 // }
1230
1231 if (printLevel < 0)
1233
1234 // before returning we will override _minLL with the actual NLL value ... offsetting could have messed up the
1235 // value
1236 out->setMinNLL(_nll->getVal());
1237
1238 // ensure no asymm errors on any pars unless had minuitMinos
1239 for (auto o : out->floatParsFinal()) {
1240 if (auto v = dynamic_cast<RooRealVar *>(o);
1241 v && !v->getAttribute("minos") && !v->getAttribute("xminos") && !v->getAttribute("xMinos"))
1242 v->removeAsymError();
1243 }
1244
1245 // minimizer may have slightly altered the fitConfig (e.g. unavailable minimizer etc) so update for that ...
1246 if (fitConfig.MinimizerOptions().MinimizerType() != actualFirstMinimizer) {
1247 fitConfig.MinimizerOptions().SetMinimizerType(actualFirstMinimizer);
1248 }
1249
1250 if (_progress) {
1251 delete _nll;
1252 }
1253
1254 // call minos if requested on any parameters
1255 if (status == 0 && minos) {
1256 for (auto label : {"xminos", "xMinos"}) {
1257 std::unique_ptr<RooAbsCollection> pars(floatPars->selectByAttrib(label, true));
1258 for (auto p : *pars) {
1259 Info("minimize", "Computing xminos error for %s", p->GetName());
1260 xRooFit::minos(nll, *out, p->GetName(), myFitConfig);
1261 }
1262 if (!pars->empty())
1263 *floatPars = out->floatParsFinal(); // put values back to best fit
1264 }
1265 }
1266 }
1267
1268 if (restore) {
1269 *floatPars = out->floatParsInit();
1270 }
1271
1272 if (out && !logs.empty()) {
1273 // save logs to StringVar in constPars list
1274#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 28, 00)
1275 const_cast<RooArgList &>(out->constPars()).addOwned(std::make_unique<RooStringVar>(".log", "log", logs.c_str()));
1276#else
1277 const_cast<RooArgList &>(out->constPars()).addOwned(*new RooStringVar(".log", "log", logs.c_str()));
1278#endif
1279 }
1280
1281 if (out && cacheDir && cacheDir->IsWritable()) {
1282 // std::cout << "Saving " << out->GetName() << " " << out->GetTitle() << " to " << nll.GetName() << std::endl;
1283 // save a copy of fit result to relevant dir
1284 if (!cacheDir->GetDirectory(nll.GetName()))
1285 cacheDir->mkdir(nll.GetName());
1286 if (auto dir = cacheDir->GetDirectory(nll.GetName()); dir) {
1287 // save NLL opts if was given one, unless already present
1288 if (nllOpts) {
1289 if (strlen(nllOpts->GetName()) == 0) {
1290 nllOpts->SetName(TUUID().AsString());
1291 }
1292 if (!dir->FindKey(nllOpts->GetName())) {
1293 dir->WriteObject(nllOpts.get(), nllOpts->GetName());
1294 }
1295 }
1296
1297 // also save the fitConfig ... unless one with same name already present
1298 std::string configName;
1299 if (!fitConfig.MinimizerOptions().ExtraOptions()->GetValue("Name", configName)) {
1300 auto extraOpts = const_cast<ROOT::Math::IOptions *>(fitConfig.MinimizerOptions().ExtraOptions());
1301 configName = TUUID().AsString();
1302 extraOpts->SetValue("Name", configName.data());
1303 }
1304 if (!dir->GetKey(configName.data())) {
1305 dir->WriteObject(&fitConfig, configName.data());
1306 }
1307 // add the fitConfig name into the fit result before writing, so can retrieve in future
1308#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 28, 00)
1309 const_cast<RooArgList &>(out->constPars())
1310 .addOwned(std::make_unique<RooStringVar>(".fitConfigName", "fitConfigName", configName.c_str()));
1311#else
1312 const_cast<RooArgList &>(out->constPars())
1313 .addOwned(*new RooStringVar(".fitConfigName", "fitConfigName", configName.c_str()));
1314#endif
1315 dir->WriteObject(out.get(), out->GetName());
1316 auto sfr = new StoredFitResult(out);
1317 dir->Add(sfr);
1318 return sfr->fr;
1319 // return std::shared_ptr<const RooFitResult>(out, [](const RooFitResult*){}); // disowned shared_ptr
1320 }
1321 }
1322
1323 return out;
1324}
1325
1326// calculate asymmetric errors, if required, on the named parameter that was floating in the fit
1327// returns status code. 0 = all good, 1 = failure, ...
1328int xRooFit::minos(RooAbsReal &nll, const RooFitResult &ufit, const char *parName,
1329 const std::shared_ptr<ROOT::Fit::FitConfig> &_fitConfig)
1330{
1331
1332 auto par = dynamic_cast<RooRealVar *>(std::unique_ptr<RooArgSet>(nll.getVariables())->find(parName));
1333 if (!par)
1334 return 1;
1335
1336 auto par_hat = dynamic_cast<RooRealVar *>(ufit.floatParsFinal().find(parName));
1337 if (!par_hat)
1338 return 1;
1339
1340 auto myFitConfig = _fitConfig ? _fitConfig : createFitConfig();
1341 auto &fitConfig = *myFitConfig;
1342
1343 bool pErrs = fitConfig.ParabErrors();
1344 fitConfig.SetParabErrors(false);
1345 double mErrs = fitConfig.MinosErrors();
1346 fitConfig.SetMinosErrors(false);
1347
1348 double val_best = par_hat->getVal();
1349 double val_err = (par_hat->hasError() ? par_hat->getError() : -1);
1350 double orig_err = val_err;
1351 double nll_min = ufit.minNll();
1352
1353 int status = 0;
1354
1355 bool isConst = par->isConstant();
1356 par->setConstant(true);
1357
1358 auto findValue = [&](double val_guess, double N_sigma = 1, double precision = 0.002, int printLevel = 0) {
1359 double tmu;
1360 int nrItr = 0;
1361 double sigma_guess = std::abs((val_guess - val_best) / N_sigma);
1362 double val_pre =
1363 val_guess -
1364 10 * precision * sigma_guess; // this is just to set value st. guarantees will do at least one iteration
1365 bool lastOverflow = false, lastUnderflow = false;
1366 while (std::abs(val_pre - val_guess) > precision * sigma_guess) {
1367 val_pre = val_guess;
1368 if (val_guess > 0 && par->getMax() < val_guess)
1369 par->setMax(2 * val_guess);
1370 if (val_guess < 0 && par->getMin() > val_guess)
1371 par->setMin(2 * val_guess);
1372 par->setVal(val_guess);
1373 // std::cout << "Guessing " << val_guess << std::endl;
1374 auto result = xRooFit::minimize(nll, myFitConfig);
1375 if (!result) {
1376 status = 1;
1377 return std::numeric_limits<double>::quiet_NaN();
1378 }
1379 double nll_val = result->minNll();
1380 status += result->status() * 10;
1381 tmu = 2 * (nll_val - nll_min);
1382 sigma_guess = std::abs(val_guess - val_best) / sqrt(tmu);
1383
1384 if (tmu <= 0) {
1385 // found an alternative or improved minima
1386 std::cout << "Warning: Alternative best-fit of " << par->GetName() << " @ " << val_guess << " vs "
1387 << val_best << " (delta=" << tmu / 2. << ")" << std::endl;
1388 double new_guess = val_guess + (val_guess - val_best);
1389 val_best = val_guess;
1390 val_guess = new_guess;
1391 sigma_guess = std::abs((val_guess - val_best) / N_sigma);
1392 val_pre = val_guess - 10 * precision * sigma_guess;
1393 status = (status / 10) * 10 + 1;
1394 continue;
1395 }
1396
1397 double corr = /*damping_factor**/ (val_pre - val_best - N_sigma * sigma_guess);
1398
1399 // subtract off the difference in the new and damped correction
1400 val_guess -= corr;
1401
1402 if (printLevel > 1) {
1403 // cout << "nPars: " << nPars << std::endl;
1404 // cout << "NLL: " << nll->GetName() << " = " << nll->getVal() << endl;
1405 // cout << "delta(NLL): " << nll->getVal()-nll_min << endl;
1406 std::cout << "NLL min: " << nll_min << std::endl;
1407 std::cout << "N_sigma*sigma(pre): " << std::abs(val_pre - val_best) << std::endl;
1408 std::cout << "sigma(guess): " << sigma_guess << std::endl;
1409 std::cout << "par(guess): " << val_guess + corr << std::endl;
1410 std::cout << "true val: " << val_best << std::endl;
1411 std::cout << "tmu: " << tmu << std::endl;
1412 std::cout << "Precision: " << sigma_guess * precision << std::endl;
1413 std::cout << "Correction: " << (-corr < 0 ? " " : "") << -corr << std::endl;
1414 std::cout << "N_sigma*sigma(guess): " << std::abs(val_guess - val_best) << std::endl;
1415 std::cout << std::endl;
1416 }
1417 if (val_guess > par->getMax()) {
1418 if (lastOverflow) {
1419 val_guess = par->getMin();
1420 break;
1421 }
1422 lastOverflow = true;
1423 lastUnderflow = false;
1424 val_guess = par->getMax() - 1e-12;
1425 } else if (val_guess < par->getMin()) {
1426 if (lastUnderflow) {
1427 val_guess = par->getMin();
1428 break;
1429 }
1430 lastOverflow = false;
1431 lastUnderflow = true;
1432 val_guess = par->getMin() + 1e-12;
1433 } else {
1434 lastUnderflow = false;
1435 lastOverflow = false;
1436 }
1437
1438 nrItr++;
1439 if (nrItr > 25) {
1440 status = (status / 10) * 10 + 3;
1441 break;
1442 }
1443 }
1444
1445 if (lastOverflow) {
1446 // msg().Error("findSigma","%s at upper limit of %g .. error may be underestimated
1447 // (t=%g)",par->GetName(),par->getMax(),tmu);
1448 status = (status / 10) * 10 + 2;
1449 } else if (lastUnderflow) {
1450 // msg().Error("findSigma","%s at lower limit of %g .. error may be underestimated
1451 // (t=%g)",par->GetName(),par->getMin(),tmu);
1452 status = (status / 10) * 10 + 2;
1453 }
1454
1455 if (printLevel > 1)
1456 std::cout << "Found sigma for nll " << nll.GetName() << ": " << (val_guess - val_best) / N_sigma << std::endl;
1457 if (printLevel > 1)
1458 std::cout << "Finished in " << nrItr << " iterations." << std::endl;
1459 if (printLevel > 1)
1460 std::cout << std::endl;
1461 return (val_guess - val_best) / N_sigma;
1462 };
1463
1464 // determine if asym error defined by temporarily setting error to nan ... will then return non-nan if defined
1465
1466 par_hat->setError(std::numeric_limits<double>::quiet_NaN());
1467 double lo = par_hat->getErrorLo();
1468 double hi = par_hat->getErrorHi();
1469 if (std::isnan(hi)) {
1470 hi = findValue(val_best + val_err, 1) + val_best -
1471 par_hat->getVal(); // put error wrt par_hat value, even if found better min
1472 if (hi > val_err)
1473 val_err = hi; // in case val_err was severe underestimate, don't want to waste time being too 'near' min
1474 }
1475 if (std::isnan(lo)) {
1476 lo = -findValue(val_best - val_err, -1) + val_best -
1477 par_hat->getVal(); // put error wrt par_hat value, even if found better min
1478 }
1479 dynamic_cast<RooRealVar *>(ufit.floatParsFinal().find(parName))->setAsymError(lo, hi);
1480 par_hat->setError(orig_err);
1481
1482 fitConfig.SetParabErrors(pErrs);
1483 fitConfig.SetMinosErrors(mErrs);
1484 par->setConstant(isConst);
1485
1486 std::vector<std::pair<std::string, int>> statusHistory;
1487 for (unsigned int i = 0; i < ufit.numStatusHistory(); i++) {
1488 statusHistory.emplace_back(ufit.statusLabelHistory(i), ufit.statusCodeHistory(i));
1489 }
1490 statusHistory.emplace_back(TString::Format("xMinos:%s", parName), status);
1491 const_cast<RooFitResult &>(ufit).setStatusHistory(statusHistory);
1492 const_cast<RooFitResult &>(ufit).setStatus(ufit.status() + status);
1493
1494 return status;
1495}
1496
1497TCanvas *
1498xRooFit::hypoTest(RooWorkspace &w, int nToysNull, int /*nToysAlt*/, const xRooFit::Asymptotics::PLLType &pllType)
1499{
1500 TCanvas *out = nullptr;
1501
1502 // 1. Determine pdf: use top-level, if more than 1 then exit and tell user they need to flag
1503 RooAbsPdf *model = nullptr;
1504 std::deque<RooAbsArg *> topPdfs;
1505 int flagCount = 0;
1506 for (auto p : w.allPdfs()) {
1507 if (p->hasClients())
1508 continue;
1509 flagCount += p->getAttribute("hypoTest");
1510 if (p->getAttribute("hypoTest"))
1511 topPdfs.push_front(p);
1512 else
1513 topPdfs.push_back(p);
1514 }
1515 if (topPdfs.empty()) {
1516 Error("hypoTest", "Cannot find top-level pdf in workspace");
1517 return nullptr;
1518 } else if (topPdfs.size() > 1) {
1519 // should be one flagged
1520 if (flagCount == 0) {
1521 Error("hypoTest", "Multiple top-level pdfs. Flag which one to test with "
1522 "w->pdf(\"pdfName\")->setAttribute(\"hypoTest\",true)");
1523 return out;
1524 } else if (flagCount != 1) {
1525 Error("hypoTest", "Multiple top-level pdfs flagged for hypoTest -- pick one.");
1526 return out;
1527 }
1528 }
1529 model = dynamic_cast<RooAbsPdf *>(topPdfs.front());
1530
1531 Info("hypoTest", "Using PDF: %s", model->GetName());
1532
1533 double CL = 0.95; // TODO: make configurable
1534
1535 // 2. Determine the data (including globs). if more than 1 then exit and tell user they need to flag
1536 RooAbsData *obsData = nullptr;
1537 std::shared_ptr<RooArgSet> obsGlobs = nullptr;
1538
1539 for (auto p : w.allData()) {
1540 if (obsData) {
1541 Error("hypoTest", "Multiple datasets in workspace. Flag which one to test with "
1542 "w->data(\"dataName\")->setAttribute(\"hypoTest\",true)");
1543 return out;
1544 }
1545 obsData = p;
1546 }
1547
1548 if (!obsData) {
1549 Error("hypoTest", "No data -- cannot determine observables");
1550 return nullptr;
1551 }
1552
1553 Info("hypoTest", "Using Dataset: %s", obsData->GetName());
1554
1555 {
1556 auto _globs = xRooNode(w).datasets()[obsData->GetName()]->globs(); // keep alive because may own the globs
1557 obsGlobs = std::make_shared<RooArgSet>();
1558 obsGlobs->addClone(_globs.argList());
1559 Info("hypoTest", "Using Globs: %s", (obsGlobs->empty()) ? " <NONE>" : obsGlobs->contentsString().c_str());
1560 }
1561
1562 // 3. Determine the POI and args - look for model pars with "hypoPoints" binning, if none then cannot scan
1563 // args are const, poi are floating - exception is if only one then assume it is the POI
1564 auto _vars = std::unique_ptr<RooArgSet>(model->getVariables());
1565 RooArgSet poi;
1566 RooArgSet args;
1567 for (auto _v : *_vars) {
1568 if (auto v = dynamic_cast<RooRealVar *>(_v); v && v->hasBinning("hypoPoints")) {
1569 poi.add(*v);
1570 }
1571 }
1572 if (poi.size() > 1) {
1573 auto _const = std::unique_ptr<RooAbsCollection>(poi.selectByAttrib("Constant", true));
1574 args.add(*_const);
1575 poi.remove(*_const);
1576 }
1577 if (!args.empty()) {
1578 Info("hypoTest", "Using Arguments: %s", args.contentsString().c_str());
1579 }
1580 if (poi.empty()) {
1581 Error("hypoTest", "No POI detected: add the hypoPoints binning to at least one non-const model parameter e.g.:\n "
1582 "w->var(\"mu\")->setBinning(RooUniformBinning(0.5,10.5,10),\"hypoPoints\"))");
1583 return nullptr;
1584 }
1585
1586 Info("hypoTest", "Using Parameters of Interest: %s", poi.contentsString().c_str());
1587
1589
1590 // should check if exist in workspace
1591 auto nllOpts = createNLLOptions();
1592 auto fitConfig = createFitConfig();
1593
1594 xRooNLLVar nll(*model, std::make_pair(obsData, obsGlobs.get()), *nllOpts);
1595 nll.SetFitConfig(fitConfig);
1596
1597 if (poi.size() == 1) {
1598 auto mu = dynamic_cast<RooRealVar *>(poi.first());
1599
1600 double altVal = (mu->getStringAttribute("altVal")) ? TString(mu->getStringAttribute("altVal")).Atof()
1601 : std::numeric_limits<double>::quiet_NaN();
1602
1603 if (std::isnan(altVal) && mu->hasRange("physical")) {
1604 // use the smallest absolute value for the altValue
1605 altVal = mu->getMin("physical");
1606 Info("hypoTest", "No altVal specified - using min of given physical range = %g", altVal);
1607 } else {
1608 if (!std::isnan(altVal))
1609 Info("hypoTest", "alt hypo: %g - CLs activated", altVal);
1610 else
1611 Info("hypoTest", "No altVal found - to specify setStringAttribute(\"altVal\",\"<value>\") on POI or set "
1612 "the physical range");
1613 }
1614 bool doCLs = !std::isnan(altVal) && std::abs(mu->getMin("hypoPoints")) > altVal &&
1615 std::abs(mu->getMax("hypoPoints")) > altVal;
1616
1617 const char *sCL = (doCLs) ? "CLs" : "null";
1618 Info("hypoTest", "%s testing active", sCL);
1619
1620 auto obs_ts = new TGraphErrors;
1621 obs_ts->SetNameTitle("obs_ts", TString::Format("Observed TestStat;%s", mu->GetTitle()));
1622 auto obs_pcls = new TGraphErrors;
1623 obs_pcls->SetNameTitle(TString::Format("obs_p%s", sCL),
1624 TString::Format("Observed p_{%s};%s", sCL, mu->GetTitle()));
1625 auto obs_cls = new TGraphErrors;
1626 obs_cls->SetNameTitle(TString::Format("obs_%s", sCL), TString::Format("Observed %s;%s", sCL, mu->GetTitle()));
1627
1628 std::vector<int> expSig = {-2, -1, 0, 1, 2};
1629 if (std::isnan(altVal))
1630 expSig.clear();
1631 std::map<int, TGraphErrors> exp_pcls, exp_cls;
1632 for (auto &s : expSig) {
1633 exp_pcls[s].SetNameTitle(TString::Format("exp%d_p%s", s, sCL),
1634 TString::Format("Expected (%d#sigma) p_{%s};%s", s, sCL, mu->GetTitle()));
1635 exp_cls[s].SetNameTitle(TString::Format("exp%d_%s", s, sCL),
1636 TString::Format("Expected (%d#sigma) %s;%s", s, sCL, mu->GetTitle()));
1637 }
1638
1639 auto getLimit = [CL](TGraphErrors &pValues) {
1640 double _out = std::numeric_limits<double>::quiet_NaN();
1641 bool lastAbove = false;
1642 for (int i = 0; i < pValues.GetN(); i++) {
1643 bool thisAbove = pValues.GetPointY(i) >= (1. - CL);
1644 if (i != 0 && thisAbove != lastAbove) {
1645 // crossed over ... find limit by interpolation
1646 // using linear interpolation so far
1647 _out = pValues.GetPointX(i - 1) + (pValues.GetPointX(i) - pValues.GetPointX(i - 1)) *
1648 ((1. - CL) - pValues.GetPointY(i - 1)) /
1649 (pValues.GetPointY(i) - pValues.GetPointY(i - 1));
1650 }
1651 lastAbove = thisAbove;
1652 }
1653 return _out;
1654 };
1655
1656 auto testPoint = [&](double testVal) {
1657 auto hp = nll.hypoPoint(mu->GetName(), testVal, altVal, pllType);
1658 obs_ts->SetPoint(obs_ts->GetN(), testVal, hp.pll().first);
1659 obs_ts->SetPointError(obs_ts->GetN() - 1, 0, hp.pll().second);
1660
1661 if (nToysNull > 0) {
1662 }
1663
1664 obs_pcls->SetPoint(obs_pcls->GetN(), testVal, (doCLs) ? hp.pCLs_asymp().first : hp.pNull_asymp().first);
1665 obs_pcls->SetPointError(obs_pcls->GetN() - 1, 0, (doCLs) ? hp.pCLs_asymp().second : hp.pNull_asymp().second);
1666 for (auto &s : expSig) {
1667 exp_pcls[s].SetPoint(exp_pcls[s].GetN(), testVal,
1668 (doCLs) ? hp.pCLs_asymp(s).first : hp.pNull_asymp(s).first);
1669 }
1670 if (doCLs)
1671 Info("hypoTest", "%s=%g: %s=%g sigma_mu=%g %s=%g", mu->GetName(), testVal, obs_ts->GetName(),
1672 obs_ts->GetPointY(obs_ts->GetN() - 1), hp.sigma_mu().first, obs_pcls->GetName(),
1673 obs_pcls->GetPointY(obs_pcls->GetN() - 1));
1674 else
1675 Info("hypoTest", "%s=%g: %s=%g %s=%g", mu->GetName(), testVal, obs_ts->GetName(),
1676 obs_ts->GetPointY(obs_ts->GetN() - 1), obs_pcls->GetName(), obs_pcls->GetPointY(obs_pcls->GetN() - 1));
1677 };
1678
1679 if (mu->getBins("hypoPoints") <= 0) {
1680 // autoTesting
1681 // evaluate min and max points
1682 testPoint(mu->getMin("hypoPoints"));
1683 testPoint(mu->getMax("hypoPoints"));
1684 testPoint((mu->getMax("hypoPoints") + mu->getMin("hypoPoints")) / 2.);
1685
1686 while (std::abs(obs_pcls->GetPointY(obs_pcls->GetN() - 1) - (1. - CL)) > 0.01) {
1687 obs_pcls->Sort();
1688 double nextTest = getLimit(*obs_pcls);
1689 if (std::isnan(nextTest))
1690 break;
1691 testPoint(nextTest);
1692 }
1693 for (auto s : expSig) {
1694 while (std::abs(exp_pcls[s].GetPointY(exp_pcls[s].GetN() - 1) - (1. - CL)) > 0.01) {
1695 exp_pcls[s].Sort();
1696 double nextTest = getLimit(exp_pcls[s]);
1697 if (std::isnan(nextTest))
1698 break;
1699 testPoint(nextTest);
1700 }
1701 }
1702 obs_ts->Sort();
1703 obs_pcls->Sort();
1704 for (auto &s : expSig)
1705 exp_pcls[s].Sort();
1706
1707 } else {
1708 for (int i = 0; i <= mu->getBins("hypoPoints"); i++) {
1709 testPoint((i == mu->getBins("hypoPoints")) ? mu->getBinning("hypoPoints").binHigh(i - 1)
1710 : mu->getBinning("hypoPoints").binLow(i));
1711 }
1712 }
1713
1714 obs_cls->SetPoint(obs_cls->GetN(), getLimit(*obs_pcls), 0.05);
1715 for (auto &s : expSig) {
1716 exp_cls[s].SetPoint(exp_cls[s].GetN(), getLimit(exp_pcls[s]), 0.05);
1717 }
1718
1719 // if more than two hypoPoints, visualize as bands
1720 if (exp_pcls[2].GetN() > 1) {
1721 TGraph *band2 = new TGraph;
1722 band2->SetNameTitle(".pCLs_2sigma", "2 sigma band");
1723 TGraph *band2up = new TGraph;
1724 band2up->SetNameTitle(".pCLs_2sigma_upUncert", "");
1725 TGraph *band2down = new TGraph;
1726 band2down->SetNameTitle(".pCLs_2sigma_downUncert", "");
1727 band2->SetFillColor(kYellow);
1728 band2up->SetFillColor(kYellow);
1729 band2down->SetFillColor(kYellow);
1730 band2up->SetFillStyle(3005);
1731 band2down->SetFillStyle(3005);
1732 for (int i = 0; i < exp_pcls[2].GetN(); i++) {
1733 band2->SetPoint(band2->GetN(), exp_pcls[2].GetPointX(i),
1734 exp_pcls[2].GetPointY(i) - exp_pcls[2].GetErrorYlow(i));
1735 band2up->SetPoint(band2up->GetN(), exp_pcls[2].GetPointX(i),
1736 exp_pcls[2].GetPointY(i) + exp_pcls[2].GetErrorYhigh(i));
1737 }
1738 for (int i = exp_pcls[2].GetN() - 1; i >= 0; i--) {
1739 band2up->SetPoint(band2up->GetN(), exp_pcls[2].GetPointX(i),
1740 exp_pcls[2].GetPointY(i) - exp_pcls[2].GetErrorYlow(i));
1741 }
1742 for (int i = 0; i < exp_pcls[-2].GetN(); i++) {
1743 band2down->SetPoint(band2down->GetN(), exp_pcls[-2].GetPointX(i),
1744 exp_pcls[-2].GetPointY(i) + exp_pcls[-2].GetErrorYhigh(i));
1745 }
1746 for (int i = exp_pcls[-2].GetN() - 1; i >= 0; i--) {
1747 band2->SetPoint(band2->GetN(), exp_pcls[-2].GetPointX(i),
1748 exp_pcls[-2].GetPointY(i) + exp_pcls[-2].GetErrorYhigh(i));
1749 band2down->SetPoint(band2down->GetN(), exp_pcls[-2].GetPointX(i),
1750 exp_pcls[-2].GetPointY(i) - exp_pcls[-2].GetErrorYlow(i));
1751 }
1752 band2->SetBit(kCanDelete);
1753 band2up->SetBit(kCanDelete);
1754 band2down->SetBit(kCanDelete);
1755 auto ax = (TNamed *)band2->Clone(".axis");
1756 ax->SetTitle(TString::Format("Hypothesis Test;%s", mu->GetTitle()));
1757 ax->Draw("AF");
1758 band2->Draw("F");
1759 band2up->Draw("F");
1760 band2down->Draw("F");
1761 }
1762
1763 if (exp_pcls[1].GetN() > 1) {
1764 TGraph *band2 = new TGraph;
1765 band2->SetNameTitle(".pCLs_1sigma", "1 sigma band");
1766 TGraph *band2up = new TGraph;
1767 band2up->SetNameTitle(".pCLs_1sigma_upUncert", "");
1768 TGraph *band2down = new TGraph;
1769 band2down->SetNameTitle(".pCLs_1sigma_downUncert", "");
1770 band2->SetFillColor(kGreen);
1771 band2up->SetFillColor(kGreen);
1772 band2down->SetFillColor(kGreen);
1773 band2up->SetFillStyle(3005);
1774 band2down->SetFillStyle(3005);
1775 for (int i = 0; i < exp_pcls[1].GetN(); i++) {
1776 band2->SetPoint(band2->GetN(), exp_pcls[1].GetPointX(i),
1777 exp_pcls[1].GetPointY(i) - exp_pcls[1].GetErrorYlow(i));
1778 band2up->SetPoint(band2up->GetN(), exp_pcls[1].GetPointX(i),
1779 exp_pcls[1].GetPointY(i) + exp_pcls[1].GetErrorYhigh(i));
1780 }
1781 for (int i = exp_pcls[1].GetN() - 1; i >= 0; i--) {
1782 band2up->SetPoint(band2up->GetN(), exp_pcls[1].GetPointX(i),
1783 exp_pcls[1].GetPointY(i) - exp_pcls[1].GetErrorYlow(i));
1784 }
1785 for (int i = 0; i < exp_pcls[-1].GetN(); i++) {
1786 band2down->SetPoint(band2down->GetN(), exp_pcls[-1].GetPointX(i),
1787 exp_pcls[-1].GetPointY(i) + exp_pcls[-1].GetErrorYhigh(i));
1788 }
1789 for (int i = exp_pcls[-1].GetN() - 1; i >= 0; i--) {
1790 band2->SetPoint(band2->GetN(), exp_pcls[-1].GetPointX(i),
1791 exp_pcls[-1].GetPointY(i) + exp_pcls[-1].GetErrorYhigh(i));
1792 band2down->SetPoint(band2down->GetN(), exp_pcls[-1].GetPointX(i),
1793 exp_pcls[-1].GetPointY(i) - exp_pcls[-1].GetErrorYlow(i));
1794 }
1795 band2->SetBit(kCanDelete);
1796 band2up->SetBit(kCanDelete);
1797 band2down->SetBit(kCanDelete);
1798 band2->Draw("F");
1799 band2up->Draw("F");
1800 band2down->Draw("F");
1801 }
1802
1803 TObject *expPlot = nullptr;
1804 if (exp_cls[0].GetN() > 0) {
1805 exp_pcls[0].SetLineStyle(2);
1806 exp_pcls[0].SetFillColor(kGreen);
1807 exp_pcls[0].SetMarkerStyle(0);
1808 expPlot = exp_pcls[0].DrawClone("L");
1809 }
1810 obs_pcls->SetBit(kCanDelete);
1811 obs_pcls->Draw(gPad->GetListOfPrimitives()->IsEmpty() ? "ALP" : "LP");
1812
1813 obs_ts->SetLineColor(kRed);
1814 obs_ts->SetMarkerColor(kRed);
1815 obs_ts->SetBit(kCanDelete);
1816 obs_ts->Draw("LP");
1817
1818 auto l = new TLegend(0.5, 0.6, 1. - gPad->GetRightMargin(), 1. - gPad->GetTopMargin());
1819 l->SetName("legend");
1820 l->AddEntry(obs_ts, obs_ts->GetTitle(), "LPE");
1821 l->AddEntry(obs_pcls, obs_pcls->GetTitle(), "LPE");
1822 if (expPlot)
1823 l->AddEntry(expPlot, "Expected", "LFE");
1825 l->Draw();
1826
1827 obs_cls->SetMarkerStyle(29);
1828 obs_cls->SetEditable(false);
1829 obs_cls->Draw("LP");
1830 for (auto s : expSig) {
1831 exp_cls[s].SetMarkerStyle(29);
1832 exp_cls[s].SetEditable(false);
1833 exp_cls[s].DrawClone("LP");
1834 }
1835 }
1836
1837 if (out)
1838 out->RedrawAxis();
1839
1840 return out;
1841}
1842
1843double round_to_digits(double value, int digits)
1844{
1845 if (value == 0.0)
1846 return 0.0;
1847 double factor = pow(10.0, digits - ceil(log10(std::abs(value))));
1848 return std::round(value * factor) / factor;
1849};
1850double round_to_decimal(double value, int decimal_places)
1851{
1852 const double multiplier = std::pow(10.0, decimal_places);
1853 return std::round(value * multiplier) / multiplier;
1854}
1855
1856// rounds error to 1 or 2 sig fig and round value to match that precision
1857std::pair<double, double> xRooFit::matchPrecision(const std::pair<double, double> &in)
1858{
1859 auto out = in;
1860 if (!std::isinf(out.second)) {
1861 auto tmp = out.second;
1862 out.second = round_to_digits(out.second, 2);
1863 int expo = (out.second == 0) ? 0 : (int)std::floor(std::log10(std::abs(out.second)));
1864 if (TString::Format("%e", out.second)(0) != '1') {
1865 out.second = round_to_digits(tmp, 1);
1866 out.first = (expo >= 0) ? round(out.first) : round_to_decimal(out.first, -expo);
1867 } else if (out.second != 0) {
1868 out.first = (expo >= 0) ? round(out.first) : round_to_decimal(out.first, -expo + 1);
1869 }
1870 }
1871 return out;
1872}
1873
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
#define oocoutW(o, a)
#define oocoutE(o, a)
#define oocoutI(o, a)
@ kRed
Definition Rtypes.h:66
@ kGreen
Definition Rtypes.h:66
@ kYellow
Definition Rtypes.h:66
#define gDirectory
Definition TDirectory.h:384
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:218
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:229
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
#define hi
@ kCanDelete
Definition TObject.h:367
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2467
#define gPad
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
Definition xRooFit.cxx:557
ProgressMonitor(const ProgressMonitor &other, const char *name=0)
Definition xRooFit.cxx:551
std::string fState
Definition xRooFit.cxx:618
static bool fInterrupt
Definition xRooFit.cxx:523
virtual ~ProgressMonitor()
Definition xRooFit.cxx:543
TStopwatch s
Definition xRooFit.cxx:629
std::shared_ptr< RooAbsCollection > vars
Definition xRooFit.cxx:630
RooArgList minPars
Definition xRooFit.cxx:625
RooRealProxy fFunc
Definition xRooFit.cxx:621
ProgressMonitor(RooAbsReal &f, int interval=30)
Definition xRooFit.cxx:535
virtual TObject * clone(const char *newname) const override
Definition xRooFit.cxx:555
static ProgressMonitor * me
Definition xRooFit.cxx:522
RooArgList prevPars
Definition xRooFit.cxx:626
static void interruptHandler(int signum)
Definition xRooFit.cxx:524
void(* oldHandlerr)(int)
Definition xRooFit.cxx:521
static int minos(RooAbsReal &nll, const RooFitResult &ufit, const char *parName="", const std::shared_ptr< ROOT::Fit::FitConfig > &_fitConfig=nullptr)
Definition xRooFit.cxx:1328
static std::shared_ptr< const RooFitResult > minimize(RooAbsReal &nll, const std::shared_ptr< ROOT::Fit::FitConfig > &fitConfig=nullptr, const std::shared_ptr< RooLinkedList > &nllOpts=nullptr)
Definition xRooFit.cxx:645
static std::shared_ptr< RooLinkedList > createNLLOptions()
Definition xRooFit.cxx:443
static TCanvas * hypoTest(RooWorkspace &w, const xRooFit::Asymptotics::PLLType &pllType=xRooFit::Asymptotics::Unknown)
Definition xRooFit.h:221
static std::shared_ptr< ROOT::Fit::FitConfig > createFitConfig()
Definition xRooFit.cxx:470
static std::pair< double, double > matchPrecision(const std::pair< double, double > &in)
Definition xRooFit.cxx:1857
This xRooNLLVar object has several special methods, e.g.
Definition xRooNLLVar.h:59
xRooFitResult minimize(const std::shared_ptr< ROOT::Fit::FitConfig > &=nullptr)
Class describing the configuration of the fit, options and parameter settings using the ROOT::Fit::Pa...
Definition FitConfig.h:47
void SetMinosErrors(bool on=true)
set Minos errors computation to be performed after fitting
Definition FitConfig.h:231
const std::string & MinimizerAlgoType() const
return type of minimizer algorithms
Definition FitConfig.h:194
bool ParabErrors() const
do analysis for parabolic errors
Definition FitConfig.h:207
void SetUpdateAfterFit(bool on=true)
Update configuration after a fit using the FitResult.
Definition FitConfig.h:245
void SetParabErrors(bool on=true)
set parabolic errors
Definition FitConfig.h:228
const std::string & MinimizerType() const
return type of minimizer package
Definition FitConfig.h:189
ROOT::Math::MinimizerOptions & MinimizerOptions()
access to the minimizer control parameter (non const method)
Definition FitConfig.h:167
bool MinosErrors() const
do minos errors analysis on the parameters
Definition FitConfig.h:210
bool IsValid() const
True if fit successful, otherwise false.
Definition FitResult.h:105
double Edm() const
Expected distance from minimum.
Definition FitResult.h:117
int Status() const
minimizer status code
Definition FitResult.h:128
const FitResult & Result() const
get fit result
Definition Fitter.h:393
const FitConfig & Config() const
access to the fit configuration (const method)
Definition Fitter.h:421
class implementing generic options for a numerical algorithm Just store the options in a map of strin...
Generic interface for defining configuration options of a numerical algorithm.
Definition IOptions.h:28
void SetValue(const char *name, double val)
generic methods for retrieving options
Definition IOptions.h:42
bool GetValue(const char *name, T &t) const
Definition IOptions.h:54
void SetMaxFunctionCalls(unsigned int maxfcn)
set maximum of function calls
void SetStrategy(int stra)
set the strategy
void SetMaxIterations(unsigned int maxiter)
set maximum iterations (one iteration can have many function calls)
const IOptions * ExtraOptions() const
return extra options (NULL pointer if they are not present)
double Tolerance() const
absolute tolerance
unsigned int MaxIterations() const
max iterations
unsigned int MaxFunctionCalls() const
max number of function calls
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:79
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
RooWorkspace * _myws
Prevent 'AlwaysDirty' mode for this node.
Definition RooAbsArg.h:734
bool isConstant() const
Check if the "Constant" attribute is set.
Definition RooAbsArg.h:363
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
RooWorkspace * workspace() const
Definition RooAbsArg.h:552
virtual void constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt=true)
Interface function signaling a request to perform constant term optimization.
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
RooAbsArg * findServer(const char *name) const
Return server of this with name name. Returns nullptr if not found.
Definition RooAbsArg.h:212
RooAbsCollection * selectByAttrib(const char *name, bool value) const
Create a subset of the current collection, consisting only of those elements with the specified attri...
double getRealValue(const char *name, double defVal=0.0, bool verbose=false) const
Get value of a RooAbsReal stored in set with given name.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Storage_t const & get() const
Const access to the underlying stl container.
void assignFast(const RooAbsCollection &other, bool setValDirty=true) const
Functional equivalent of assign() but assumes this and other collection have same layout.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
void setAttribAll(const Text_t *name, bool value=true)
Set given attribute in each element of the collection by calling each elements setAttribute() functio...
Storage_t::size_type size() const
RooAbsArg * first() const
virtual RooAbsArg * addClone(const RooAbsArg &var, bool silent=false)
Add a clone of the specified argument to list.
std::string contentsString() const
Return comma separated list of contained object names as STL string.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:178
static TClass * Class()
Class RooBinning is an implements RooAbsBinning in terms of an array of boundary values,...
Definition RooBinning.h:27
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
RooDataSet is a container class to hold unbinned data.
Definition RooDataSet.h:57
RooRealVar * weightVar() const
Returns a pointer to the weight variable (if set).
Definition RooDataSet.h:124
A one-time forward iterator working on RooLinkedList or RooAbsCollection.
RooAbsArg * next()
Return next element or nullptr if at end.
RooFitResult is a container class to hold the input and output of a PDF fit to a dataset.
Int_t statusCodeHistory(UInt_t icycle) const
const char * statusLabelHistory(UInt_t icycle) const
const RooArgList & floatParsFinal() const
Return list of floating parameters after fit.
Int_t status() const
Return MINUIT status code.
UInt_t numStatusHistory() const
double minNll() const
Return minimized -log(L) value.
static TClass * Class()
static TClass * Class()
RooLinkedList is an collection class for internal use, storing a collection of RooAbsArg pointers in ...
static TClass * Class()
RooMinimizer is a wrapper class around ROOT::Fit:Fitter that provides a seamless interface between th...
void optimizeConst(int flag)
If flag is true, perform constant term optimization on function being minimized.
RooFit::OwningPtr< RooFitResult > save(const char *name=nullptr, const char *title=nullptr)
Save and return a RooFitResult snapshot of current minimizer status.
int minos()
Execute MINOS.
int hesse()
Execute HESSE.
int minimize(const char *type, const char *alg=nullptr)
Minimise the function passed in the constructor.
ROOT::Fit::Fitter * fitter()
Return underlying ROOT fitter object.
void setStrategy(int istrat)
Change MINUIT strategy to istrat.
static RooMsgService & instance()
Return reference to singleton instance.
void setGlobalKillBelow(RooFit::MsgLevel level)
RooFit::MsgLevel globalKillBelow() const
Class RooObjCacheManager is an implementation of class RooCacheManager<RooAbsCacheElement> and specia...
Poisson pdf.
Definition RooPoisson.h:19
static TClass * Class()
void setNoRounding(bool flag=true)
Switch off/on rounding of x to the nearest integer.
Definition RooPoisson.h:36
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:33
static TRandom * randomGenerator()
Return a pointer to a singleton random-number generator implementation.
Definition RooRandom.cxx:51
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
void setError(double value)
Definition RooRealVar.h:60
bool hasBinning(const char *name) const override
Returns true if variable has a binning named 'name'.
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
static RooAbsData * GenerateAsimovData(const RooAbsPdf &pdf, const RooArgSet &observables)
generate the asimov data for the observables (not the global ones) need to deal with the case of a si...
RooStringVar is a RooAbsArg implementing string values.
Joins several RooAbsCategoryLValue objects into a single category.
bool setIndex(value_type index, bool printError=true) override
Set the value of the super category to the specified index.
RooUniformBinning is an implementation of RooAbsBinning that provides a uniform binning in 'n' bins b...
Persistable container for RooFit projects.
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
Definition TAttFill.h:37
virtual void SetFillStyle(Style_t fstyle)
Set the fill area style.
Definition TAttFill.h:39
The Canvas class.
Definition TCanvas.h:23
static TCanvas * MakeDefCanvas()
Static function to build a default canvas.
Definition TCanvas.cxx:1514
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
TClass * IsA() const override
Definition TClass.h:618
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2968
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition TDatime.h:37
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition TDatime.cxx:102
Describe directory structure in memory.
Definition TDirectory.h:45
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual Bool_t IsWritable() const
Definition TDirectory.h:237
virtual TDirectory * mkdir(const char *name, const char *title="", Bool_t returnExistingDirectory=kFALSE)
Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
void SetName(const char *newname) override
Set the name for directory If the directory name is changed after the directory was written once,...
A TGraphErrors is a TGraph with error bars.
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Set x and y values for point number i.
Definition TGraph.cxx:2315
Int_t GetN() const
Definition TGraph.h:130
void Draw(Option_t *chopt="") override
Draw this graph with its current attributes.
Definition TGraph.cxx:809
void SetNameTitle(const char *name="", const char *title="") override
Set graph name and title.
Definition TGraph.cxx:2390
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
This class displays a legend box (TPaveText) containing several legend entries.
Definition TLegend.h:23
TMatrixTBase< Element > & ResizeTo(Int_t nrows, Int_t ncols, Int_t=-1) override
Set size of the matrix to nrows x ncols New dynamic elements are created, the overlapping part of the...
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:74
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:439
virtual TObject * DrawClone(Option_t *option="") const
Draw a clone of this object in the current selected pad with: gROOT->SetSelectedPad(c1).
Definition TObject.cxx:299
virtual void Delete(Option_t *option="")
Delete this object.
Definition TObject.cxx:248
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:780
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:274
virtual void SetSeed(ULong_t seed=0)
Set the random generator seed.
Definition TRandom.cxx:608
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
Definition TRandom.cxx:360
Stopwatch class.
Definition TStopwatch.h:28
Double_t RealTime()
Stop the stopwatch (if it is running) and return the realtime (in seconds) passed between the start a...
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
void Continue()
Resume a stopped stopwatch.
void Reset()
Definition TStopwatch.h:52
Provides iteration through tokens of a given string.
Definition TPRegexp.h:143
Bool_t NextToken()
Get the next token, it is stored in this TString.
Definition TPRegexp.cxx:975
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:421
Double_t Atof() const
Return floating-point value contained in string.
Definition TString.cxx:2032
Bool_t IsFloat() const
Returns kTRUE if string contains a floating point or integer number.
Definition TString.cxx:1836
const char * Data() const
Definition TString.h:380
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2356
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:636
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
This class defines a UUID (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDent...
Definition TUUID.h:42
TDatime GetTime() const
Get time from UUID.
Definition TUUID.cxx:670
const char * AsString() const
Return UUID as string. Copy string immediately since it will be reused.
Definition TUUID.cxx:571
RooCmdArg Offset(std::string const &mode)
RooCmdArg Optimize(Int_t flag=2)
RooCmdArg Extended(bool flag=true)
RooCmdArg ExpectedData(bool flag=true)
Double_t x[n]
Definition legend1.C:17
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Sort the n elements of the array a of generic templated type Element.
Definition TMathBase.h:431
Definition first.py:1
#define END_XROOFIT_NAMESPACE
Definition Config.h:25
TLine l
Definition textangle.C:4
#define GIT_COMMIT_HASH
double round_to_decimal(double value, int decimal_places)
Definition xRooFit.cxx:1850
BEGIN_XROOFIT_NAMESPACE
Definition xRooFit.cxx:66
double round_to_digits(double value, int digits)
Definition xRooFit.cxx:1843