Logo ROOT  
Reference Guide
 
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#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
16#define protected public
17#endif
18#include "RooFitResult.h"
19#ifdef protected
20#undef protected
21#endif
22
23#include "xRooFit/xRooFit.h"
24
25#include "RooDataSet.h"
26#include "RooSimultaneous.h"
27#include "RooArgSet.h"
28#include "RooRandom.h"
29#include "RooAbsPdf.h"
30#include "TUUID.h"
31#include "RooProdPdf.h"
32#include "RooGamma.h"
33#include "RooPoisson.h"
34#include "RooGaussian.h"
35#include "RooBifurGauss.h"
36#include "RooLognormal.h"
37#include "RooBinning.h"
38#include "RooUniformBinning.h"
39
41#include "Math/GenAlgoOptions.h"
42#include "RooMinimizer.h"
43#include "coutCapture.h"
44
45#include "TCanvas.h"
46#include "TGraphErrors.h"
47#include "TLegend.h"
48#include "TKey.h"
49#include "RooAbsTestStatistic.h"
50#include "TPRegexp.h"
51#include "RooStringVar.h"
52
53#include "RooRealProxy.h"
54
55#include "xRooFitVersion.h"
56
57#include <signal.h>
58
60
61RooCmdArg xRooFit::ReuseNLL(bool flag)
62{
63 return RooCmdArg("ReuseNLL", flag, 0, 0, 0, 0, 0, 0, 0);
64}
65
66xRooNLLVar xRooFit::createNLL(const std::shared_ptr<RooAbsPdf> pdf, const std::shared_ptr<RooAbsData> data,
67 const RooLinkedList &nllOpts)
68{
69 return xRooNLLVar(pdf, data, nllOpts);
70}
71
72xRooNLLVar xRooFit::createNLL(RooAbsPdf &pdf, RooAbsData *data, const RooLinkedList &nllOpts)
73{
74 return createNLL(std::shared_ptr<RooAbsPdf>(&pdf, [](RooAbsPdf *) {}),
75 std::shared_ptr<RooAbsData>(data, [](RooAbsData *) {}), nllOpts);
76}
77
78xRooNLLVar xRooFit::createNLL(RooAbsPdf &pdf, RooAbsData *data, const RooCmdArg &arg1, const RooCmdArg &arg2,
79 const RooCmdArg &arg3, const RooCmdArg &arg4, const RooCmdArg &arg5,
80 const RooCmdArg &arg6, const RooCmdArg &arg7, const RooCmdArg &arg8)
81{
82
84 l.Add((TObject *)&arg1);
85 l.Add((TObject *)&arg2);
86 l.Add((TObject *)&arg3);
87 l.Add((TObject *)&arg4);
88 l.Add((TObject *)&arg5);
89 l.Add((TObject *)&arg6);
90 l.Add((TObject *)&arg7);
91 l.Add((TObject *)&arg8);
92 return createNLL(pdf, data, l);
93}
94
95std::shared_ptr<const RooFitResult>
96xRooFit::fitTo(RooAbsPdf &pdf,
97 const std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> &data,
98 const RooLinkedList &nllOpts, const ROOT::Fit::FitConfig &fitConf)
99{
100 return xRooNLLVar(std::shared_ptr<RooAbsPdf>(&pdf, [](RooAbsPdf *) {}), data, nllOpts)
101 .minimize(std::shared_ptr<ROOT::Fit::FitConfig>(const_cast<ROOT::Fit::FitConfig *>(&fitConf),
102 [](ROOT::Fit::FitConfig *) {}));
103}
104
105std::shared_ptr<const RooFitResult> xRooFit::fitTo(RooAbsPdf &pdf,
106 const std::pair<RooAbsData *, const RooAbsCollection *> &data,
107 const RooLinkedList &nllOpts, const ROOT::Fit::FitConfig &fitConf)
108{
109 return xRooNLLVar(pdf, data, nllOpts)
110 .minimize(std::shared_ptr<ROOT::Fit::FitConfig>(const_cast<ROOT::Fit::FitConfig *>(&fitConf),
111 [](ROOT::Fit::FitConfig *) {}));
112}
113
114std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>>
115xRooFit::generateFrom(RooAbsPdf &pdf, const std::shared_ptr<const RooFitResult> &fr, bool expected, int seed)
116{
117
118 std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> out;
119
120 if (!fr)
121 return out;
122
123 auto _allVars = std::unique_ptr<RooAbsCollection>(pdf.getVariables());
124 auto _snap = std::unique_ptr<RooAbsCollection>(_allVars->snapshot());
125 *_allVars = fr->constPars();
126 *_allVars = fr->floatParsFinal();
127
128 // determine globs from fr constPars
129 auto _globs = std::unique_ptr<RooAbsCollection>(fr->constPars().selectByAttrib("global", true));
130
131 // bool doBinned = false;
132 // RooAbsPdf::GenSpec** gs = nullptr;
133
134 if (seed == 0)
135 seed = RooRandom::randomGenerator()->Integer(std::numeric_limits<uint32_t>::max());
137
138 TString uuid = TUUID().AsString();
139
140 std::function<std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooArgSet>>(RooAbsPdf *)> genSubPdf;
141
142 genSubPdf = [&](RooAbsPdf *_pdf) {
143 std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooArgSet>> _out;
144 // std::unique_ptr<RooArgSet> _obs(_pdf->getParameters(*pars)); // using this "trick" to get observables can
145 // produce 'error' msg because of RooProdPdf trying to setup partial integrals
146 std::unique_ptr<RooArgSet> _obs(_pdf->getVariables());
147 _obs->remove(fr->constPars(), true, true);
148 _obs->remove(fr->floatParsFinal(), true, true); // use this instead
149
150 if (!_globs->empty()) {
151 RooArgSet *toy_gobs = new RooArgSet(uuid + "_globs");
152 // ensure we use the gobs from the model ...
153 RooArgSet t;
154 t.add(*_globs);
155 std::unique_ptr<RooArgSet> globs(_pdf->getObservables(t));
156 globs->snapshot(*toy_gobs);
157 if (!toy_gobs->empty() &&
158 !dynamic_cast<RooSimultaneous *>(
159 _pdf)) { // if was simPdf will call genSubPdf on each subpdf so no need to generate here
160 if (!expected) {
161 *toy_gobs = *std::unique_ptr<RooDataSet>(_pdf->generate(*globs, 1))->get();
162 } else {
163 // loop over pdfs in top-level prod-pdf,
164 auto pp = dynamic_cast<RooProdPdf *>(_pdf);
165 if (pp) {
166 for (auto thePdf : pp->pdfList()) {
167 auto gob = std::unique_ptr<RooArgSet>(thePdf->getObservables(*globs));
168 if (gob->empty())
169 continue;
170 if (gob->size() > 1) {
171 Warning("generate", "%s contains multiple global obs: %s", thePdf->GetName(),
172 gob->contentsString().c_str());
173 continue;
174 }
175 RooRealVar &rrv = dynamic_cast<RooRealVar &>(*gob->first());
176 std::unique_ptr<RooArgSet> cpars(thePdf->getParameters(*globs));
177
178 bool foundServer = false;
179 // note : this will work only for this type of constraints
180 // expressed as RooPoisson, RooGaussian, RooLognormal, RooGamma
181 TClass *cClass = thePdf->IsA();
182 if (cClass != RooGaussian::Class() && cClass != RooPoisson::Class() &&
183 cClass != RooGamma::Class() && cClass != RooLognormal::Class() &&
184 cClass != RooBifurGauss::Class()) {
185 TString className = (cClass) ? cClass->GetName() : "undefined";
187 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
188 << " of type " << className << " is a non-supported type - result might be not correct "
189 << std::endl;
190 }
191
192 // in case of a Poisson constraint make sure the rounding is not set
193 if (cClass == RooPoisson::Class()) {
194 RooPoisson *pois = dynamic_cast<RooPoisson *>(thePdf);
195 assert(pois);
196 pois->setNoRounding(true);
197 }
198
199 // look at server of the constraint term and check if the global observable is part of the server
200 RooAbsArg *arg = thePdf->findServer(rrv);
201 if (!arg) {
202 // special case is for the Gamma where one might define the global observable n and you have a
203 // Gamma(b, n+1, ...._ in this case n+1 is the server and we don;t have a direct dependency, but
204 // we want to set n to the b value so in case of the Gamma ignore this test
205 if (cClass != RooGamma::Class()) {
207 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
208 << " has no direct dependence on global observable- cannot generate it " << std::endl;
209 continue;
210 }
211 }
212
213 // loop on the server of the constraint term
214 // need to treat the Gamma as a special case
215 // the mode of the Gamma is (k-1)*theta where theta is the inverse of the rate parameter.
216 // we assume that the global observable is defined as ngobs = k-1 and the theta parameter has the
217 // name theta otherwise we use other procedure which might be wrong
218 RooAbsReal *thetaGamma = 0;
219 if (cClass == RooGamma::Class()) {
220 RooFIter itc(thePdf->serverMIterator());
221 for (RooAbsArg *a2 = itc.next(); a2 != 0; a2 = itc.next()) {
222 if (TString(a2->GetName()).Contains("theta")) {
223 thetaGamma = dynamic_cast<RooAbsReal *>(a2);
224 break;
225 }
226 }
227 if (thetaGamma == 0) {
229 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
230 << " is a Gamma distribution and no server named theta is found. Assume that the Gamma "
231 "scale is 1 "
232 << std::endl;
233 }
234 }
235 RooFIter iter2(thePdf->serverMIterator());
236 for (RooAbsArg *a2 = iter2.next(); a2 != 0; a2 = iter2.next()) {
237 RooAbsReal *rrv2 = dynamic_cast<RooAbsReal *>(a2);
238 if (rrv2 && !rrv2->dependsOn(*gob) &&
239 (!rrv2->isConstant() || !rrv2->InheritsFrom("RooConstVar"))) {
240
241 // found server not depending on the gob
242 if (foundServer) {
244 << "AsymptoticCalculator::MakeAsimovData:constraint term " << thePdf->GetName()
245 << " constraint term has more server depending on nuisance- cannot generate it "
246 << std::endl;
247 foundServer = false;
248 break;
249 }
250 if (thetaGamma && thetaGamma->getVal() > 0)
251 rrv.setVal(rrv2->getVal() / thetaGamma->getVal());
252 else
253 rrv.setVal(rrv2->getVal());
254 foundServer = true;
255 }
256 }
257
258 if (!foundServer) {
260 << "AsymptoticCalculator::MakeAsimovData - can't find nuisance for constraint term - global "
261 "observables will not be set to Asimov value "
262 << thePdf->GetName() << std::endl;
263 std::cerr << "Parameters: " << std::endl;
264 cpars->Print("V");
265 std::cerr << "Observables: " << std::endl;
266 gob->Print("V");
267 }
268 }
269 } else {
270 Error("generate", "Cannot generate global observables, pdf is: %s::%s", _pdf->ClassName(),
271 _pdf->GetName());
272 }
273 *toy_gobs = *globs;
274 }
275 }
276 _out.second.reset(toy_gobs);
277 } // end of globs generation
278
279 RooRealVar w("weightVar", "weightVar", 1);
280 if (auto s = dynamic_cast<RooSimultaneous *>(_pdf)) {
281 // do subpdf's individually
282 _obs->add(w);
283 _out.first.reset(new RooDataSet(
284 uuid, TString::Format("%s %s", _pdf->GetTitle(), (expected) ? "Expected" : "Toy"), *_obs, "weightVar"));
285
286 for (auto &c : s->indexCat()) {
287#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 22, 00)
288 std::string cLabel = c.first.c_str();
289#else
290 std::string cLabel = c->GetName();
291#endif
292 auto p = s->getPdf(cLabel.c_str());
293 if (!p)
294 continue;
295 auto toy = genSubPdf(p);
296 if (toy.second && _out.second)
297 *const_cast<RooArgSet *>(_out.second.get()) = *toy.second;
298 _obs->setCatLabel(s->indexCat().GetName(), cLabel.c_str());
299 for (int i = 0; i < toy.first->numEntries(); i++) {
300 *_obs = *toy.first->get(i);
301 _out.first->add(*_obs, toy.first->weight());
302 }
303 }
304 return _out;
305 }
306
307 std::map<RooRealVar *, std::shared_ptr<RooAbsBinning>> binnings;
308
309 for (auto &o : *_obs) {
310 auto r = dynamic_cast<RooRealVar *>(o);
311 if (!r)
312 continue;
313 if (_pdf->isBinnedDistribution(*r)) {
314 binnings[r] = std::shared_ptr<RooAbsBinning>(r->getBinning().clone(r->getBinning().GetName()));
315 auto res = _pdf->binBoundaries(*r, -std::numeric_limits<double>::infinity(),
316 std::numeric_limits<double>::infinity());
317 std::vector<double> boundaries;
318 boundaries.reserve(res->size());
319 for (auto &rr : *res) {
320 if (boundaries.empty() || std::abs(boundaries.back() - rr) > 1e-3 ||
321 std::abs(boundaries.back() - rr) > 1e-5 * boundaries.back())
322 boundaries.push_back(rr);
323 } // sometimes get virtual duplicates of boundaries
324 r->setBinning(RooBinning(boundaries.size() - 1, &boundaries[0]));
325 delete res;
326 } else if (r->numBins(r->getBinning().GetName()) == 0 && expected) {
327 // no bins ... in order to generate expected we need to have some bins
328 binnings[r] = std::shared_ptr<RooAbsBinning>(r->getBinning().clone(r->getBinning().GetName()));
329 r->setBinning(RooUniformBinning(r->getMin(), r->getMax(), 100));
330 }
331 }
332
333 // now can generate
334 if (_obs->empty()) {
335 // no observables, create a single dataset with 1 entry ... why 1 entry??
336 _obs->add(w);
337 RooArgSet _tmp;
338 _tmp.add(w);
339 _out.first.reset(new RooDataSet("", "Toy", _tmp, "weightVar"));
340 _out.first->add(_tmp);
341 } else {
342 if (_pdf->canBeExtended()) {
343 _out.first = std::unique_ptr<RooDataSet>{_pdf->generate(*_obs, RooFit::Extended(), RooFit::ExpectedData(expected))};
344 } else {
345 if (expected) {
346 // use AsymptoticCalculator because generate expected not working correctly on unextended pdf?
347 // TODO: Can the above code for expected globs be used instead, or what about replace above code with
348 // ObsToExpected?
349 _out.first.reset(RooStats::AsymptoticCalculator::GenerateAsimovData(*_pdf, *_obs));
350 } else {
351 _out.first = std::unique_ptr<RooDataSet>{_pdf->generate(*_obs, RooFit::ExpectedData(expected))};
352 }
353 }
354 }
355 _out.first->SetName(TUUID().AsString());
356
357 for (auto &b : binnings) {
358 auto v = b.first;
359 auto binning = b.second;
360 v->setBinning(*binning);
361 // range of variable in dataset may be less than in the workspace
362 // if e.g. generate for a specific channel. So need to expand ranges to match
363 auto x = dynamic_cast<RooRealVar *>(_out.first->get()->find(v->GetName()));
364 auto r = x->getRange();
365 if (r.first > binning->lowBound())
366 x->setMin(binning->lowBound());
367 if (r.second < binning->highBound())
368 x->setMax(binning->highBound());
369 }
370 return _out;
371 };
372
373 out = genSubPdf(&pdf);
374 out.first->SetName(uuid);
375
376#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 26, 00)
377 // store fitResult name on the weightVar
378 if (auto w = dynamic_cast<RooDataSet *>(out.first.get())->weightVar()) {
379 w->setStringAttribute("fitResult", fr->GetName());
380 }
381#endif
382
383 *_allVars = *_snap;
384
385 return out;
386}
387
388std::shared_ptr<RooLinkedList> xRooFit::createNLLOptions()
389{
390 auto out = std::shared_ptr<RooLinkedList>(new RooLinkedList, [](RooLinkedList *l) {
391 l->Delete();
392 delete l;
393 });
394 out->Add(RooFit::Offset().Clone());
395 out->Add(
397 .Clone()); // disable const-optimization at the construction step ... can happen in the minimization though
398 return out;
399}
400
401std::shared_ptr<ROOT::Fit::FitConfig> xRooFit::createFitConfig()
402{
403 auto fFitConfig = std::make_shared<ROOT::Fit::FitConfig>();
404 auto &fitConfig = *fFitConfig;
405 fitConfig.SetParabErrors(true); // will use to run hesse after fit
406 fitConfig.MinimizerOptions().SetMinimizerType("Minuit2");
407 fitConfig.MinimizerOptions().SetErrorDef(0.5); // ensures errors are +/- 1 sigma ..IMPORTANT
408 fitConfig.SetParabErrors(true); // runs HESSE
409 fitConfig.SetMinosErrors(true); // computes asymmetric errors on any parameter with the "minos" attribute set
410 fitConfig.MinimizerOptions().SetMaxFunctionCalls(
411 -1); // calls per iteration. if left as 0 will set automatically to 500*nPars below
412 fitConfig.MinimizerOptions().SetMaxIterations(-1); // if left as 0 will set automatically to 500*nPars
413 fitConfig.MinimizerOptions().SetStrategy(0);
414 // fitConfig.MinimizerOptions().SetTolerance(
415 // 1); // default is 0.01 (i think) but roominimizer uses 1 as default - use specify with
416 // ROOT::Math::MinimizerOptions::SetDefaultTolerance(..)
417 fitConfig.MinimizerOptions().SetPrintLevel(-2);
418 fitConfig.MinimizerOptions().SetExtraOptions(ROOT::Math::GenAlgoOptions());
419 // have to const cast to set extra options
420 auto extraOpts = const_cast<ROOT::Math::IOptions *>(fitConfig.MinimizerOptions().ExtraOptions());
421 extraOpts->SetValue("OptimizeConst", 2); // if 0 will disable constant term optimization and cache-and-track of the
422 // NLL. 1 = just caching, 2 = cache and track
423 extraOpts->SetValue("StrategySequence", "0s01s12s2m");
424 extraOpts->SetValue("LogSize", 0); // length of log to capture and save
425 extraOpts->SetValue("BoundaryCheck",
426 0.); // if non-zero, warn if any post-fit value is close to boundary (e.g. 0.01 = within 1%)
427 extraOpts->SetValue("TrackProgress", 30); // seconds between output to log of evaluation progress
428 extraOpts->SetValue("xRooFitVersion", GIT_COMMIT_HASH); // not really options but here for logging purposes
429 // extraOpts->SetValue("ROOTVersion",ROOT_VERSION_CODE); - not needed as should by part of the ROOT TFile definition
430 return fFitConfig;
431}
432
434public:
435 void (*oldHandlerr)(int) = nullptr;
437 static bool fInterrupt;
438 static void interruptHandler(int signum)
439 {
440 if (signum == SIGINT) {
441 std::cout << "Minimization interrupted ... will exit as soon as possible" << std::endl;
442 // TODO: create a global mutex for this
443 fInterrupt = true;
444 } else {
445 if (me)
446 me->oldHandlerr(signum);
447 }
448 };
449 ProgressMonitor(RooAbsReal &f, int interval = 30)
450 : RooAbsReal(Form("progress_%s", f.GetName()), ""), fFunc("func", "func", this, f), fInterval(interval)
451 {
452 s.Start();
453 oldHandlerr = signal(SIGINT, interruptHandler);
454 me = this;
455 }
457 {
458 if (oldHandlerr) {
459 signal(SIGINT, oldHandlerr);
460 }
461 if (me == this)
462 me = nullptr;
463 };
464 ProgressMonitor(const ProgressMonitor &other, const char *name = 0)
465 : RooAbsReal(other, name), fFunc("func", this, other.fFunc), fInterval(other.fInterval)
466 {
467 }
468 virtual TObject *clone(const char *newname) const override { return new ProgressMonitor(*this, newname); }
469
470 double evaluate() const override
471 {
472 if (fInterrupt)
473 return std::numeric_limits<double>::quiet_NaN();
474 double out = fFunc;
475 if (prevMin == std::numeric_limits<double>::infinity())
476 prevMin = out;
477 if (!std::isnan(out))
478 minVal = std::min(minVal, out);
479 counter++;
480 if (s.RealTime() > fInterval) {
481 s.Reset();
482 std::cerr << (counter) << ") " << TDatime().AsString() << " : " << minVal << " Delta = " << (minVal - prevMin)
483 << std::endl;
484 prevMin = minVal;
485 } else {
486 s.Continue();
487 }
488 return out;
489 }
490
491private:
493 mutable int counter = 0;
494 mutable double minVal = std::numeric_limits<double>::infinity();
495 mutable double prevMin = std::numeric_limits<double>::infinity();
496 mutable int fInterval = 0; // time in seconds before next report
497 mutable TStopwatch s;
498};
499bool ProgressMonitor::fInterrupt = false;
501
502std::shared_ptr<const RooFitResult>
503xRooFit::minimize(RooAbsReal &nll, const std::shared_ptr<ROOT::Fit::FitConfig> &_fitConfig)
504{
505
506 auto myFitConfig = _fitConfig ? _fitConfig : createFitConfig();
507 auto &fitConfig = *myFitConfig;
508
509 auto _nll = &nll;
510
511 TString resultTitle = nll.getStringAttribute("fitresultTitle");
512 TString fitName = TUUID().AsString();
513 if (resultTitle == "")
514 resultTitle = TUUID(fitName).GetTime().AsString();
515
516 // extract any user pars from the nll too
517 RooArgList fUserPars;
518 if (nll.getStringAttribute("userPars")) {
519 TStringToken st(nll.getStringAttribute("userPars"), ",");
520 while (st.NextToken()) {
521 TString parName = st;
522 TString parVal = nll.getStringAttribute(parName);
523 if (parVal.IsFloat())
524 fUserPars.addClone(RooRealVar(parName, parName, parVal.Atof()));
525 else
526 fUserPars.addClone(RooStringVar(parName, parName, parVal));
527 }
528 }
529
530 auto _nllVars = std::unique_ptr<RooAbsCollection>(_nll->getVariables());
531
532 std::unique_ptr<RooAbsCollection> constPars(_nllVars->selectByAttrib("Constant", kTRUE));
533 constPars->add(fUserPars, true); // add here so checked for when loading from cache
534 std::unique_ptr<RooAbsCollection> floatPars(_nllVars->selectByAttrib("Constant", kFALSE));
535
536 int _progress = 0;
537 double boundaryCheck = 0;
538 std::string s;
539 int logSize = 0;
540 if (fitConfig.MinimizerOptions().ExtraOptions()) {
541 fitConfig.MinimizerOptions().ExtraOptions()->GetNamedValue("StrategySequence", s);
542 fitConfig.MinimizerOptions().ExtraOptions()->GetIntValue("TrackProgress", _progress);
543 fitConfig.MinimizerOptions().ExtraOptions()->GetRealValue("BoundaryCheck", boundaryCheck);
544 fitConfig.MinimizerOptions().ExtraOptions()->GetIntValue("LogSize", logSize);
545 }
546 TString m_strategy = s;
547
548 // if fit caching enabled, try to locate a valid fitResult
549 // must have matching constPars
550 TDirectory *cacheDir = gDirectory;
551
552 if (cacheDir) {
553 if (auto nllDir = cacheDir->GetDirectory(nll.GetName()); nllDir) {
554 if (auto keys = nllDir->GetListOfKeys(); keys) {
555 for (auto &&k : *keys) {
556 auto cl = TClass::GetClass(((TKey *)k)->GetClassName());
557 if (cl->InheritsFrom("RooFitResult")) {
558 if (auto cachedFit = nllDir->Get<RooFitResult>(k->GetName()); cachedFit) {
559 bool match = true;
560 if (!cachedFit->floatParsFinal().equals(*floatPars)) {
561 match = false;
562 } else {
563 for (auto &p : *constPars) {
564 auto v = dynamic_cast<RooAbsReal *>(p);
565 if (!v) {
566 match = false;
567 break;
568 };
569 if (auto _p = dynamic_cast<RooAbsReal *>(cachedFit->constPars().find(p->GetName())); _p) {
570 // note: do not need global observable values to match (globals currently added to
571 // constPars list)
572 if (!_p->getAttribute("global") && std::abs(_p->getVal() - v->getVal()) > 1e-12) {
573 match = false;
574 break;
575 }
576 }
577 }
578 }
579 if (match) {
580 return std::shared_ptr<RooFitResult>(cachedFit); // return a copy;
581 } else {
582 delete cachedFit;
583 }
584 }
585 }
586 }
587 }
588 }
589 }
590
591 if (nll.getAttribute("readOnly"))
592 return nullptr;
593
594 int printLevel = fitConfig.MinimizerOptions().PrintLevel();
596 if (printLevel < 0)
598
599 // check how many parameters we have ... if 0 parameters then we wont run a fit, we just evaluate nll and return ...
600 if (floatPars->getSize() == 0 || fitConfig.MinimizerOptions().MaxFunctionCalls() == 1) {
601 std::shared_ptr<RooFitResult> result;
602 RooArgList parsList;
603 parsList.add(*floatPars);
604 // construct an empty fit result ...
605 result = std::make_shared<RooFitResult>(); // if put name here fitresult gets added to dir, we don't want that
606 result->SetName(TUUID().AsString());
607 result->SetTitle(resultTitle);
608 result->setFinalParList(parsList);
609 result->setInitParList(parsList);
610 result->setConstParList(dynamic_cast<RooArgSet &>(*constPars)); /* RooFitResult takes a snapshot */
612 d.ResizeTo(parsList.size(), parsList.size());
613 result->setCovarianceMatrix(d);
614 result->setCovQual(-1);
615 result->setMinNLL(_nll->getVal());
616 result->setEDM(0);
617 result->setStatus(floatPars->getSize() == 0 ? 0 : 1);
618
619 if (cacheDir && cacheDir->IsWritable()) {
620 // save a copy of fit result to relevant dir
621 if (!cacheDir->GetDirectory(nll.GetName()))
622 cacheDir->mkdir(nll.GetName());
623 if (auto dir = cacheDir->GetDirectory(nll.GetName()); dir) {
624 dir->WriteObject(result.get(), result->GetName());
625 }
626 }
627
628 if (printLevel < 0)
630 return result;
631 }
632
633 int strategy = fitConfig.MinimizerOptions().Strategy();
634 // Note: AsymptoticCalculator enforces not less than 1 on tolerance - should we do so too?
635
636 if (_progress) {
637 _nll = new ProgressMonitor(*_nll, _progress);
639 }
640
641 std::string logs;
642 std::unique_ptr<RooFitResult> out;
643 {
644 auto logger = (logSize > 0) ? std::make_unique<cout_redirect>(logs, logSize) : nullptr;
645 RooMinimizer _minimizer(*_nll);
646 _minimizer.fitter()->Config() = fitConfig;
647
648 bool autoMaxCalls = (_minimizer.fitter()->Config().MinimizerOptions().MaxFunctionCalls() == 0);
649 if (autoMaxCalls) {
650 _minimizer.fitter()->Config().MinimizerOptions().SetMaxFunctionCalls(500 * floatPars->size());
651 }
652 if (_minimizer.fitter()->Config().MinimizerOptions().MaxIterations() == 0) {
653 _minimizer.fitter()->Config().MinimizerOptions().SetMaxIterations(500 * floatPars->size());
654 }
655
656 bool hesse = _minimizer.fitter()->Config().ParabErrors();
657 _minimizer.fitter()->Config().SetParabErrors(
658 false); // turn "off" so can run hesse as a separate step, appearing in status
659 bool minos = _minimizer.fitter()->Config().MinosErrors();
660 _minimizer.fitter()->Config().SetMinosErrors(false);
661 bool restore = !_minimizer.fitter()->Config().UpdateAfterFit();
662 _minimizer.fitter()->Config().SetUpdateAfterFit(true); // note: seems to always take effect
663
664 std::vector<std::pair<std::string, int>> statusHistory;
665
666 // gCurrentSampler = this;
667 // gOldHandlerr = signal(SIGINT,toyInterruptHandlerr);
668
669 TString actualFirstMinimizer = _minimizer.fitter()->Config().MinimizerType();
670
671 int status = 0;
672
673 int constOptimize = 2;
674 _minimizer.fitter()->Config().MinimizerOptions().ExtraOptions()->GetValue("OptimizeConst", constOptimize);
675 if (constOptimize) {
676 _minimizer.optimizeConst(constOptimize);
677 // for safety force a refresh of the cache (and tracking) in the nll
678 // DO NOT do a ConfigChange ... this is just a deactivate-reactivate of caching
679 // but it seems like doing this breaks the const optimization and function is badly behaved
680 // so once its turned on never turn it off.
681 // nll.constOptimizeTestStatistic(RooAbsArg::ConfigChange, constOptimize>1 /* do tracking too if >1 */); //
682 // trigger a re-evaluate of which nodes to cache-and-track
683 // the next line seems safe to do but wont bother doing it because not bothering with above
684 // need to understand why turning the cache off and on again breaks it??
685 // nll.constOptimizeTestStatistic(RooAbsArg::ValueChange, constOptimize>1); // update the cache values -- is
686 // this needed??
687 } else {
688 // disable const optimization
689 // warning - if the nll was previously activated then it seems like deactivating may break it.
691 }
692
693 int sIdx = -1;
694 TString minim = _minimizer.fitter()->Config().MinimizerType();
695 TString algo = _minimizer.fitter()->Config().MinimizerAlgoType();
696 if (minim == "Minuit2")
697 sIdx = m_strategy.Index('0' + strategy);
698 else if (minim == "Minuit")
699 sIdx = m_strategy.Index('m');
700
701 int tries = 0;
702 int maxtries = 4;
703 bool first = true;
704 while (tries < maxtries && sIdx != -1) {
705 status = _minimizer.minimize(minim, algo);
706 if (first && actualFirstMinimizer != _minimizer.fitter()->Config().MinimizerType())
707 actualFirstMinimizer = _minimizer.fitter()->Config().MinimizerType();
708 first = false;
709 tries++;
710
711 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff && fff->fInterrupt) {
712 delete _nll;
713 throw std::runtime_error("Keyboard interrupt while minimizing");
714 }
715
716 // RooMinimizer loses the useful status code, so here we will override it
717 status = _minimizer.fitter()
718 ->Result()
719 .Status(); // note: Minuit failure is status code 4, minuit2 that is edm above max
720 minim = _minimizer.fitter()->Config().MinimizerType(); // may have changed value
721 statusHistory.emplace_back(
722 _minimizer.fitter()->Config().MinimizerType() + _minimizer.fitter()->Config().MinimizerAlgoType() +
723 std::to_string(_minimizer.fitter()->Config().MinimizerOptions().Strategy()),
724 status);
725 if (status % 1000 == 0)
726 break; // fit was good
727
728 if (status == 4 && minim != "Minuit") {
729 if (printLevel >= -1)
730 Warning("fitTo", "%s Hit max function calls of %d", fitName.Data(),
731 _minimizer.fitter()->Config().MinimizerOptions().MaxFunctionCalls());
732 if (autoMaxCalls) {
733 if (printLevel >= -1)
734 Warning("fitTo", "will try doubling this");
736 _minimizer.fitter()->Config().MinimizerOptions().MaxFunctionCalls() * 2);
738 _minimizer.fitter()->Config().MinimizerOptions().MaxIterations() * 2);
739 continue;
740 }
741 }
742
743 // NOTE: minuit2 seems to distort the tolerance in a weird way, so that tol becomes 100 times smaller than
744 // specified Also note that if fits are failing because of edm over max, it can be a good idea to activate the
745 // Offset option when building nll
746 if (printLevel >= -1)
747 Warning("fitTo", "%s Status=%d (edm=%f, tol=%f, strat=%d), tries=#%d...", fitName.Data(), status,
748 _minimizer.fitter()->Result().Edm(), _minimizer.fitter()->Config().MinimizerOptions().Tolerance(),
749 _minimizer.fitter()->Config().MinimizerOptions().Strategy(), tries);
750
751 // decide what to do next based on strategy sequence
752 if (sIdx == m_strategy.Length() - 1) {
753 break; // done
754 }
755
756 if (m_strategy(sIdx + 1) == 'm') {
757 minim = "Minuit";
758 algo = "migradImproved";
759 } else if (m_strategy(sIdx + 1) == 's') {
760 algo = "Scan";
761 } else {
762 strategy = int(m_strategy(sIdx + 1) - '0');
763 _minimizer.setStrategy(strategy);
764 minim = "Minuit2";
765 algo = "Migrad";
766 }
767 tries--;
768 sIdx++;
769 }
770
771 /* Minuit2 status codes:
772 * status = 0 : OK
773 status = 1 : Covariance was made pos defined
774 status = 2 : Hesse is invalid
775 status = 3 : Edm is above max
776 status = 4 : Reached call limit
777 status = 5 : Any other failure
778
779 For Minuit its basically 0 is OK, 4 is failure, I think?
780 */
781
782 if (printLevel >= -1 && status != 0) {
783 Warning("fitTo", "%s final status is %d", fitName.Data(), status);
784 }
785
786 if (hesse && _minimizer.fitter()->Result().IsValid()) { // only do hesse if was a valid min
787
788 // remove limits on pars before calculation
789 // interesting note: error on pars before hesse can be significantly
790 // smaller than after hesse ... what is the pre-hesse error corresponding to?
791 auto parSettings = _minimizer.fitter()->Config().ParamsSettings();
792 for (auto &ss : _minimizer.fitter()->Config().ParamsSettings()) {
793 ss.RemoveLimits();
794 }
795
796 //_nll->getVal(); // for reasons I dont understand, if nll evaluated before hesse call the edm is smaller? -
797 // and also becomes WRONG :-S
798 auto _status = _minimizer.hesse(); // note: I have seen that you can get 'full covariance quality' without
799 // running hesse ... is that expected?
800
801 _minimizer.fitter()->Config().SetParamsSettings(parSettings);
802
803 if (auto fff = dynamic_cast<ProgressMonitor *>(_nll); fff && fff->fInterrupt) {
804 delete _nll;
805 throw std::runtime_error("Keyboard interrupt while hesse calculating");
806 }
807 if (_status != 0 && status == 0 && printLevel >= -1) {
808 Warning("fitTo", "%s hesse status is %d", fitName.Data(), _status);
809 }
810 }
811
812 // DO NOT DO THIS - seems to mess with the NLL function in a way that breaks the cache - reactivating wont fix
813 // if(constOptimize) { _minimizer.optimizeConst(0); } // doing this because saw happens in RooAbsPdf::minimizeNLL
814 // method
815
816 // signal(SIGINT,gOldHandlerr);
817 out = std::unique_ptr<RooFitResult>{_minimizer.save(fitName, resultTitle)};
818
819 out->setStatusHistory(statusHistory);
820
821 // userPars wont have been added to the RooFitResult by RooMinimizer
822 const_cast<RooArgList &>(out->constPars()).addClone(fUserPars, true);
823
824 if (boundaryCheck) {
825 // check if any of the parameters are at their limits (potentially a problem with fit)
826 // or their errors go over their limits (just a warning)
827 RooFIter itr = floatPars->fwdIterator();
828 RooAbsArg *a = 0;
829 int limit_status = 0;
830 std::string listpars;
831 while ((a = itr.next())) {
832 RooRealVar *v = dynamic_cast<RooRealVar *>(a);
833 if (!v)
834 continue;
835 double vRange = v->getMax() - v->getMin();
836 if (v->getMin() > v->getVal() - vRange * boundaryCheck ||
837 v->getMax() < v->getVal() + vRange * boundaryCheck) {
838 // within 0.01% of edge
839
840 // check if nll actually lower 'at' the boundary, if it is, refine the best fit to the limit value
841 auto tmp = v->getVal();
842 v->setVal(v->getMin());
843 double boundary_nll = _nll->getVal();
844 if (boundary_nll <= out->minNll()) {
845 static_cast<RooRealVar *>(out->floatParsFinal().find(v->GetName()))->setVal(v->getMin());
846 out->setMinNLL(boundary_nll);
847 // Info("fit","Corrected %s onto minimum @ %g",v->GetName(),v->getMin());
848 } else {
849 // not better, so restore value
850 v->setVal(tmp);
851 }
852
853 // if has a 'physical' range specified, don't warn if near the limit
854 if (v->hasRange("physical"))
855 limit_status = 900;
856 listpars += v->GetName();
857 listpars += ",";
858 } else if (hesse &&
859 (v->getMin() > v->getVal() - v->getError() || v->getMax() < v->getVal() + v->getError())) {
860 if (printLevel >= 0) {
861 Info("minimize", "PARLIM: %s (%f +/- %f) range (%f - %f)", v->GetName(), v->getVal(), v->getError(),
862 v->getMin(), v->getMax());
863 }
864 limit_status = 9000;
865 }
866 }
867 if (limit_status == 900) {
868 if (printLevel >= 0)
869 Warning("miminize", "BOUNDCHK: Parameters within %g%% limit in fit result: %s", boundaryCheck * 100,
870 listpars.c_str());
871 } else if (limit_status > 0) {
872 if (printLevel >= 0)
873 Warning("miminize", "BOUNDCHK: Parameters near limit in fit result");
874 }
875
876 // store the limit check result
877 statusHistory.emplace_back("BOUNDCHK", limit_status);
878 out->setStatusHistory(statusHistory);
879 out->setStatus(out->status() + limit_status);
880 }
881
882 // // automatic parameter range adjustment based on errors
883 // for(auto a : *floatPars) {
884 // RooRealVar *v = dynamic_cast<RooRealVar *>(a);
885 // if(v->getMin() > v->getVal() - 3.*v->getError()) {
886 // v->setMin(v->getVal() - 3.1*v->getError());
887 // }
888 // if(v->getMax() < v->getVal() + 3.*v->getError()) {
889 // v->setMax(v->getVal() + 3.1*v->getError());
890 // }
891 // // also make sure the range isn't too big (fits can struggle)
892 // if(v->getMin() < v->getVal() - 10.*v->getError()) {
893 // v->setMin(v->getVal() - 9.9*v->getError());
894 // }
895 // if(v->getMax() > v->getVal() + 10.*v->getError()) {
896 // v->setMax(v->getVal() + 9.9*v->getError());
897 // }
898 // }
899
900 if (printLevel < 0)
902
903 // before returning we will override _minLL with the actual NLL value ... offsetting could have messed up the
904 // value
905 out->setMinNLL(_nll->getVal());
906
907 // ensure no asymm errors on any pars
908 for (auto o : out->floatParsFinal()) {
909 if (auto v = dynamic_cast<RooRealVar *>(o); v)
910 v->removeAsymError();
911 }
912
913 // minimizer may have slightly altered the fitConfig (e.g. unavailable minimizer etc) so update for that ...
914 if (fitConfig.MinimizerOptions().MinimizerType() != actualFirstMinimizer) {
915 fitConfig.MinimizerOptions().SetMinimizerType(actualFirstMinimizer);
916 }
917
918 if (_progress) {
919 delete _nll;
920 }
921
922 // call minos if requested on any parameters
923 if (status == 0 && minos) {
924 std::unique_ptr<RooAbsCollection> pars(floatPars->selectByAttrib("minos", true));
925 for (auto p : *pars) {
926 xRooFit::minos(nll, *out, p->GetName(), myFitConfig);
927 }
928 if (!pars->empty())
929 *floatPars = out->floatParsFinal(); // put values back to best fit
930 }
931
932 if (restore) {
933 *floatPars = out->floatParsInit();
934 }
935 }
936 if (out && !logs.empty()) {
937 // save logs to StringVar in constPars list
938 const_cast<RooArgList &>(out->constPars()).addOwned(std::make_unique<RooStringVar>(".log", "log", logs.c_str()));
939 }
940
941 if (out && cacheDir && cacheDir->IsWritable()) {
942 // save a copy of fit result to relevant dir
943 if (!cacheDir->GetDirectory(nll.GetName()))
944 cacheDir->mkdir(nll.GetName());
945 if (auto dir = cacheDir->GetDirectory(nll.GetName()); dir) {
946
947 // also save the fitConfig ... unless one with same name already present
948 std::string configName;
949 if (!fitConfig.MinimizerOptions().ExtraOptions()->GetValue("Name", configName)) {
950 auto extraOpts = const_cast<ROOT::Math::IOptions *>(fitConfig.MinimizerOptions().ExtraOptions());
951 configName = TUUID().AsString();
952 extraOpts->SetValue("Name", configName.data());
953 }
954 if (!dir->GetKey(configName.data())) {
955 dir->WriteObject(&fitConfig, configName.data());
956 }
957 // add the fitConfig name into the fit result before writing, so can retrieve in future
958 const_cast<RooArgList &>(out->constPars())
959 .addOwned(std::make_unique<RooStringVar>(".fitConfigName", "fitConfigName", configName.c_str()));
960
961 dir->WriteObject(out.get(), out->GetName());
962 }
963 }
964
965 return std::shared_ptr<const RooFitResult>(std::move(out));
966}
967
968// calculate asymmetric errors, if required, on the named parameter that was floating in the fit
969// returns status code. 0 = all good, 1 = failure, ...
970int xRooFit::minos(RooAbsReal &nll, const RooFitResult &ufit, const char *parName,
971 const std::shared_ptr<ROOT::Fit::FitConfig> &_fitConfig)
972{
973
974 auto par = dynamic_cast<RooRealVar *>(std::unique_ptr<RooArgSet>(nll.getVariables())->find(parName));
975 if (!par)
976 return 1;
977
978 auto par_hat = dynamic_cast<RooRealVar *>(ufit.floatParsFinal().find(parName));
979 if (!par_hat)
980 return 1;
981
982 auto myFitConfig = _fitConfig ? _fitConfig : createFitConfig();
983 auto &fitConfig = *myFitConfig;
984
985 bool pErrs = fitConfig.ParabErrors();
986 fitConfig.SetParabErrors(false);
987 double mErrs = fitConfig.MinosErrors();
988 fitConfig.SetMinosErrors(false);
989
990 double val_best = par_hat->getVal();
991 double val_err = (par_hat->hasError() ? par_hat->getError() : -1);
992 double nll_min = ufit.minNll();
993
994 int status = 0;
995
996 bool isConst = par->isConstant();
997 par->setConstant(true);
998
999 auto findValue = [&](double val_guess, double N_sigma = 1, double precision = 0.002, int printLevel = 0) {
1000 double tmu;
1001 int nrItr = 0;
1002 double sigma_guess = std::abs((val_guess - val_best) / N_sigma);
1003 double val_pre =
1004 val_guess -
1005 10 * precision * sigma_guess; // this is just to set value st. guarantees will do at least one iteration
1006 bool lastOverflow = false, lastUnderflow = false;
1007 while (std::abs(val_pre - val_guess) > precision * sigma_guess) {
1008 val_pre = val_guess;
1009 if (val_guess > 0 && par->getMax() < val_guess)
1010 par->setMax(2 * val_guess);
1011 if (val_guess < 0 && par->getMin() > val_guess)
1012 par->setMin(2 * val_guess);
1013 par->setVal(val_guess);
1014 auto result = xRooFit::minimize(nll, myFitConfig);
1015 if (!result) {
1016 status = 1;
1017 return std::numeric_limits<double>::quiet_NaN();
1018 }
1019 double nll_val = result->minNll();
1020 status += result->status() * 10;
1021 tmu = 2 * (nll_val - nll_min);
1022 sigma_guess = std::abs(val_guess - val_best) / sqrt(tmu);
1023
1024 if (tmu <= 0) {
1025 // found an alternative or improved minima
1026 std::cout << "Warning: Alternative best-fit of " << par->GetName() << " @ " << val_guess << " vs "
1027 << val_best << std::endl;
1028 double new_guess = val_guess + (val_guess - val_best);
1029 val_best = val_guess;
1030 val_guess = new_guess;
1031 sigma_guess = std::abs((val_guess - val_best) / N_sigma);
1032 val_pre = val_guess - 10 * precision * sigma_guess;
1033 status = (status / 10) * 10 + 1;
1034 continue;
1035 }
1036
1037 double corr = /*damping_factor**/ (val_pre - val_best - N_sigma * sigma_guess);
1038
1039 // subtract off the difference in the new and damped correction
1040 val_guess -= corr;
1041
1042 if (printLevel > 1) {
1043 // cout << "nPars: " << nPars << std::endl;
1044 // cout << "NLL: " << nll->GetName() << " = " << nll->getVal() << endl;
1045 // cout << "delta(NLL): " << nll->getVal()-nll_min << endl;
1046 std::cout << "NLL min: " << nll_min << std::endl;
1047 std::cout << "N_sigma*sigma(pre): " << std::abs(val_pre - val_best) << std::endl;
1048 std::cout << "sigma(guess): " << sigma_guess << std::endl;
1049 std::cout << "par(guess): " << val_guess + corr << std::endl;
1050 std::cout << "true val: " << val_best << std::endl;
1051 std::cout << "tmu: " << tmu << std::endl;
1052 std::cout << "Precision: " << sigma_guess * precision << std::endl;
1053 std::cout << "Correction: " << (-corr < 0 ? " " : "") << -corr << std::endl;
1054 std::cout << "N_sigma*sigma(guess): " << std::abs(val_guess - val_best) << std::endl;
1055 std::cout << std::endl;
1056 }
1057 if (val_guess > par->getMax()) {
1058 if (lastOverflow) {
1059 val_guess = par->getMin();
1060 break;
1061 }
1062 lastOverflow = true;
1063 lastUnderflow = false;
1064 val_guess = par->getMax() - 1e-12;
1065 } else if (val_guess < par->getMin()) {
1066 if (lastUnderflow) {
1067 val_guess = par->getMin();
1068 break;
1069 }
1070 lastOverflow = false;
1071 lastUnderflow = true;
1072 val_guess = par->getMin() + 1e-12;
1073 } else {
1074 lastUnderflow = false;
1075 lastOverflow = false;
1076 }
1077
1078 nrItr++;
1079 if (nrItr > 25) {
1080 status = (status / 10) * 10 + 3;
1081 break;
1082 }
1083 }
1084
1085 if (lastOverflow) {
1086 // msg().Error("findSigma","%s at upper limit of %g .. error may be underestimated
1087 // (t=%g)",par->GetName(),par->getMax(),tmu);
1088 status = (status / 10) * 10 + 2;
1089 } else if (lastUnderflow) {
1090 // msg().Error("findSigma","%s at lower limit of %g .. error may be underestimated
1091 // (t=%g)",par->GetName(),par->getMin(),tmu);
1092 status = (status / 10) * 10 + 2;
1093 }
1094
1095 if (printLevel > 1)
1096 std::cout << "Found sigma for nll " << nll.GetName() << ": " << (val_guess - val_best) / N_sigma << std::endl;
1097 if (printLevel > 1)
1098 std::cout << "Finished in " << nrItr << " iterations." << std::endl;
1099 if (printLevel > 1)
1100 std::cout << std::endl;
1101 return (val_guess - val_best) / N_sigma;
1102 };
1103
1104 // determine if asym error defined by temporarily setting error to nan ... will then return non-nan if defined
1105
1106 par_hat->setError(std::numeric_limits<double>::quiet_NaN());
1107 double lo = par_hat->getErrorLo();
1108 double hi = par_hat->getErrorHi();
1109 if (std::isnan(hi)) {
1110 hi = findValue(val_best + val_err, 1);
1111 }
1112 if (std::isnan(lo)) {
1113 lo = -findValue(val_best - val_err, -1);
1114 }
1115 dynamic_cast<RooRealVar *>(ufit.floatParsFinal().find(parName))->setAsymError(lo, hi);
1116 par_hat->setError(val_err);
1117
1118 fitConfig.SetParabErrors(pErrs);
1119 fitConfig.SetMinosErrors(mErrs);
1120 par->setConstant(isConst);
1121
1122 std::vector<std::pair<std::string, int>> statusHistory;
1123 for (unsigned int i = 0; i < ufit.numStatusHistory(); i++) {
1124 statusHistory.emplace_back(ufit.statusLabelHistory(i), ufit.statusCodeHistory(i));
1125 }
1126 statusHistory.emplace_back(TString::Format("xMINOS_%s", parName), status);
1127 const_cast<RooFitResult &>(ufit).setStatusHistory(statusHistory);
1128 const_cast<RooFitResult &>(ufit).setStatus(ufit.status() + status);
1129
1130 return status;
1131}
1132
1133TCanvas *
1134xRooFit::hypoTest(RooWorkspace &w, int nToysNull, int /*nToysAlt*/, const xRooFit::Asymptotics::PLLType &pllType)
1135{
1136 TCanvas *out = nullptr;
1137
1138 // 1. Determine pdf: use top-level, if more than 1 then exit and tell user they need to flag
1139 RooAbsPdf *model = nullptr;
1140 std::deque<RooAbsArg *> topPdfs;
1141 int flagCount = 0;
1142 for (auto p : w.allPdfs()) {
1143 if (p->hasClients())
1144 continue;
1145 flagCount += p->getAttribute("hypoTest");
1146 if (p->getAttribute("hypoTest"))
1147 topPdfs.push_front(p);
1148 else
1149 topPdfs.push_back(p);
1150 }
1151 if (topPdfs.empty()) {
1152 Error("hypoTest", "Cannot find top-level pdf in workspace");
1153 return nullptr;
1154 } else if (topPdfs.size() > 1) {
1155 // should be one flagged
1156 if (flagCount == 0) {
1157 Error("hypoTest", "Multiple top-level pdfs. Flag which one to test with "
1158 "w->pdf(\"pdfName\")->setAttribute(\"hypoTest\",true)");
1159 return out;
1160 } else if (flagCount != 1) {
1161 Error("hypoTest", "Multiple top-level pdfs flagged for hypoTest -- pick one.");
1162 return out;
1163 }
1164 }
1165 model = dynamic_cast<RooAbsPdf *>(topPdfs.front());
1166
1167 Info("hypoTest", "Using PDF: %s", model->GetName());
1168
1169 double CL = 0.95; // TODO: make configurable
1170
1171 // 2. Determine the data (including globs). if more than 1 then exit and tell user they need to flag
1172 RooAbsData *obsData = nullptr;
1173 std::shared_ptr<RooArgSet> obsGlobs = nullptr;
1174
1175 for (auto p : w.allData()) {
1176 if (obsData) {
1177 Error("hypoTest", "Multiple datasets in workspace. Flag which one to test with "
1178 "w->data(\"dataName\")->setAttribute(\"hypoTest\",true)");
1179 return out;
1180 }
1181 obsData = p;
1182 }
1183
1184 if (!obsData) {
1185 Error("hypoTest", "No data -- cannot determine observables");
1186 return nullptr;
1187 }
1188
1189 Info("hypoTest", "Using Dataset: %s", obsData->GetName());
1190
1191 {
1192 auto _globs = xRooNode(w).datasets()[obsData->GetName()]->globs(); // keep alive because may own the globs
1193 obsGlobs = std::make_shared<RooArgSet>();
1194 obsGlobs->addClone(_globs.argList());
1195 Info("hypoTest", "Using Globs: %s", (obsGlobs->empty()) ? " <NONE>" : obsGlobs->contentsString().c_str());
1196 }
1197
1198 // 3. Determine the POI and args - look for model pars with "hypoPoints" binning, if none then cannot scan
1199 // args are const, poi are floating - exception is if only one then assume it is the POI
1200 auto _vars = std::unique_ptr<RooArgSet>(model->getVariables());
1201 RooArgSet poi;
1202 RooArgSet args;
1203 for (auto _v : *_vars) {
1204 if (auto v = dynamic_cast<RooRealVar *>(_v); v && v->hasBinning("hypoPoints")) {
1205 poi.add(*v);
1206 }
1207 }
1208 if (poi.size() > 1) {
1209 auto _const = std::unique_ptr<RooAbsCollection>(poi.selectByAttrib("Constant", true));
1210 args.add(*_const);
1211 poi.remove(*_const);
1212 }
1213 if (!args.empty()) {
1214 Info("hypoTest", "Using Arguments: %s", args.contentsString().c_str());
1215 }
1216 if (poi.empty()) {
1217 Error("hypoTest", "No POI detected: add the hypoPoints binning to at least one non-const model parameter e.g.:\n "
1218 "w->var(\"mu\")->setBinning(RooUniformBinning(0.5,10.5,10),\"hypoPoints\"))");
1219 return nullptr;
1220 }
1221
1222 Info("hypoTest", "Using Parameters of Interest: %s", poi.contentsString().c_str());
1223
1224 out = TCanvas::MakeDefCanvas();
1225
1226 // should check if exist in workspace
1227 auto nllOpts = createNLLOptions();
1228 auto fitConfig = createFitConfig();
1229
1230 xRooNLLVar nll(*model, std::make_pair(obsData, obsGlobs.get()), *nllOpts);
1231 nll.SetFitConfig(fitConfig);
1232
1233 if (poi.size() == 1) {
1234 auto mu = dynamic_cast<RooRealVar *>(poi.first());
1235
1236 double altVal = (mu->getStringAttribute("altVal")) ? TString(mu->getStringAttribute("altVal")).Atof()
1237 : std::numeric_limits<double>::quiet_NaN();
1238
1239 if (std::isnan(altVal) && mu->hasRange("physical")) {
1240 // use the smallest absolute value for the altValue
1241 altVal = mu->getMin("physical");
1242 Info("hypoTest", "No altVal specified - using min of given physical range = %g", altVal);
1243 } else {
1244 if (!std::isnan(altVal))
1245 Info("hypoTest", "alt hypo: %g - CLs activated", altVal);
1246 else
1247 Info("hypoTest", "No altVal found - to specify setStringAttribute(\"altVal\",\"<value>\") on POI or set "
1248 "the physical range");
1249 }
1250 bool doCLs = !std::isnan(altVal) && std::abs(mu->getMin("hypoPoints")) > altVal &&
1251 std::abs(mu->getMax("hypoPoints")) > altVal;
1252
1253 const char *sCL = (doCLs) ? "CLs" : "null";
1254 Info("hypoTest", "%s testing active", sCL);
1255
1256 auto obs_ts = new TGraphErrors;
1257 obs_ts->SetNameTitle("obs_ts", TString::Format("Observed TestStat;%s", mu->GetTitle()));
1258 auto obs_pcls = new TGraphErrors;
1259 obs_pcls->SetNameTitle(TString::Format("obs_p%s", sCL),
1260 TString::Format("Observed p_{%s};%s", sCL, mu->GetTitle()));
1261 auto obs_cls = new TGraphErrors;
1262 obs_cls->SetNameTitle(TString::Format("obs_%s", sCL), TString::Format("Observed %s;%s", sCL, mu->GetTitle()));
1263
1264 std::vector<int> expSig = {-2, -1, 0, 1, 2};
1265 if (std::isnan(altVal))
1266 expSig.clear();
1267 std::map<int, TGraphErrors> exp_pcls, exp_cls;
1268 for (auto &s : expSig) {
1269 exp_pcls[s].SetNameTitle(TString::Format("exp%d_p%s", s, sCL),
1270 TString::Format("Expected (%d#sigma) p_{%s};%s", s, sCL, mu->GetTitle()));
1271 exp_cls[s].SetNameTitle(TString::Format("exp%d_%s", s, sCL),
1272 TString::Format("Expected (%d#sigma) %s;%s", s, sCL, mu->GetTitle()));
1273 }
1274
1275 auto getLimit = [CL](TGraphErrors &pValues) {
1276 double _out = std::numeric_limits<double>::quiet_NaN();
1277 bool lastAbove = false;
1278 for (int i = 0; i < pValues.GetN(); i++) {
1279 bool thisAbove = pValues.GetPointY(i) >= (1. - CL);
1280 if (i != 0 && thisAbove != lastAbove) {
1281 // crossed over ... find limit by interpolation
1282 // using linear interpolation so far
1283 _out = pValues.GetPointX(i - 1) + (pValues.GetPointX(i) - pValues.GetPointX(i - 1)) *
1284 ((1. - CL) - pValues.GetPointY(i - 1)) /
1285 (pValues.GetPointY(i) - pValues.GetPointY(i - 1));
1286 }
1287 lastAbove = thisAbove;
1288 }
1289 return _out;
1290 };
1291
1292 auto testPoint = [&](double testVal) {
1293 auto hp = nll.hypoPoint(mu->GetName(), testVal, altVal, pllType);
1294 obs_ts->SetPoint(obs_ts->GetN(), testVal, hp.pll().first);
1295 obs_ts->SetPointError(obs_ts->GetN() - 1, 0, hp.pll().second);
1296
1297 if (nToysNull > 0) {
1298 }
1299
1300 obs_pcls->SetPoint(obs_pcls->GetN(), testVal, (doCLs) ? hp.pCLs_asymp().first : hp.pNull_asymp().first);
1301 obs_pcls->SetPointError(obs_pcls->GetN() - 1, 0, (doCLs) ? hp.pCLs_asymp().second : hp.pNull_asymp().second);
1302 for (auto &s : expSig) {
1303 exp_pcls[s].SetPoint(exp_pcls[s].GetN(), testVal,
1304 (doCLs) ? hp.pCLs_asymp(s).first : hp.pNull_asymp(s).first);
1305 }
1306 if (doCLs)
1307 Info("hypoTest", "%s=%g: %s=%g sigma_mu=%g %s=%g", mu->GetName(), testVal, obs_ts->GetName(),
1308 obs_ts->GetPointY(obs_ts->GetN() - 1), hp.sigma_mu().first, obs_pcls->GetName(),
1309 obs_pcls->GetPointY(obs_pcls->GetN() - 1));
1310 else
1311 Info("hypoTest", "%s=%g: %s=%g %s=%g", mu->GetName(), testVal, obs_ts->GetName(),
1312 obs_ts->GetPointY(obs_ts->GetN() - 1), obs_pcls->GetName(), obs_pcls->GetPointY(obs_pcls->GetN() - 1));
1313 };
1314
1315 if (mu->getBins("hypoPoints") <= 0) {
1316 // autoTesting
1317 // evaluate min and max points
1318 testPoint(mu->getMin("hypoPoints"));
1319 testPoint(mu->getMax("hypoPoints"));
1320 testPoint((mu->getMax("hypoPoints") + mu->getMin("hypoPoints")) / 2.);
1321
1322 while (std::abs(obs_pcls->GetPointY(obs_pcls->GetN() - 1) - (1. - CL)) > 0.01) {
1323 obs_pcls->Sort();
1324 double nextTest = getLimit(*obs_pcls);
1325 if (std::isnan(nextTest))
1326 break;
1327 testPoint(nextTest);
1328 }
1329 for (auto s : expSig) {
1330 while (std::abs(exp_pcls[s].GetPointY(exp_pcls[s].GetN() - 1) - (1. - CL)) > 0.01) {
1331 exp_pcls[s].Sort();
1332 double nextTest = getLimit(exp_pcls[s]);
1333 if (std::isnan(nextTest))
1334 break;
1335 testPoint(nextTest);
1336 }
1337 }
1338 obs_ts->Sort();
1339 obs_pcls->Sort();
1340 for (auto &s : expSig)
1341 exp_pcls[s].Sort();
1342
1343 } else {
1344 for (int i = 0; i <= mu->getBins("hypoPoints"); i++) {
1345 testPoint((i == mu->getBins("hypoPoints")) ? mu->getBinning("hypoPoints").binHigh(i - 1)
1346 : mu->getBinning("hypoPoints").binLow(i));
1347 }
1348 }
1349
1350 obs_cls->SetPoint(obs_cls->GetN(), getLimit(*obs_pcls), 0.05);
1351 for (auto &s : expSig) {
1352 exp_cls[s].SetPoint(exp_cls[s].GetN(), getLimit(exp_pcls[s]), 0.05);
1353 }
1354
1355 // if more than two hypoPoints, visualize as bands
1356 if (exp_pcls[2].GetN() > 1) {
1357 TGraph *band2 = new TGraph;
1358 band2->SetNameTitle(".pCLs_2sigma", "2 sigma band");
1359 TGraph *band2up = new TGraph;
1360 band2up->SetNameTitle(".pCLs_2sigma_upUncert", "");
1361 TGraph *band2down = new TGraph;
1362 band2down->SetNameTitle(".pCLs_2sigma_downUncert", "");
1363 band2->SetFillColor(kYellow);
1364 band2up->SetFillColor(kYellow);
1365 band2down->SetFillColor(kYellow);
1366 band2up->SetFillStyle(3005);
1367 band2down->SetFillStyle(3005);
1368 for (int i = 0; i < exp_pcls[2].GetN(); i++) {
1369 band2->SetPoint(band2->GetN(), exp_pcls[2].GetPointX(i),
1370 exp_pcls[2].GetPointY(i) - exp_pcls[2].GetErrorYlow(i));
1371 band2up->SetPoint(band2up->GetN(), exp_pcls[2].GetPointX(i),
1372 exp_pcls[2].GetPointY(i) + exp_pcls[2].GetErrorYhigh(i));
1373 }
1374 for (int i = exp_pcls[2].GetN() - 1; i >= 0; i--) {
1375 band2up->SetPoint(band2up->GetN(), exp_pcls[2].GetPointX(i),
1376 exp_pcls[2].GetPointY(i) - exp_pcls[2].GetErrorYlow(i));
1377 }
1378 for (int i = 0; i < exp_pcls[-2].GetN(); i++) {
1379 band2down->SetPoint(band2down->GetN(), exp_pcls[-2].GetPointX(i),
1380 exp_pcls[-2].GetPointY(i) + exp_pcls[-2].GetErrorYhigh(i));
1381 }
1382 for (int i = exp_pcls[-2].GetN() - 1; i >= 0; i--) {
1383 band2->SetPoint(band2->GetN(), exp_pcls[-2].GetPointX(i),
1384 exp_pcls[-2].GetPointY(i) + exp_pcls[-2].GetErrorYhigh(i));
1385 band2down->SetPoint(band2down->GetN(), exp_pcls[-2].GetPointX(i),
1386 exp_pcls[-2].GetPointY(i) - exp_pcls[-2].GetErrorYlow(i));
1387 }
1388 band2->SetBit(kCanDelete);
1389 band2up->SetBit(kCanDelete);
1390 band2down->SetBit(kCanDelete);
1391 auto ax = (TNamed *)band2->Clone(".axis");
1392 ax->SetTitle(TString::Format("Hypothesis Test;%s", mu->GetTitle()));
1393 ax->Draw("AF");
1394 band2->Draw("F");
1395 band2up->Draw("F");
1396 band2down->Draw("F");
1397 }
1398
1399 if (exp_pcls[1].GetN() > 1) {
1400 TGraph *band2 = new TGraph;
1401 band2->SetNameTitle(".pCLs_1sigma", "1 sigma band");
1402 TGraph *band2up = new TGraph;
1403 band2up->SetNameTitle(".pCLs_1sigma_upUncert", "");
1404 TGraph *band2down = new TGraph;
1405 band2down->SetNameTitle(".pCLs_1sigma_downUncert", "");
1406 band2->SetFillColor(kGreen);
1407 band2up->SetFillColor(kGreen);
1408 band2down->SetFillColor(kGreen);
1409 band2up->SetFillStyle(3005);
1410 band2down->SetFillStyle(3005);
1411 for (int i = 0; i < exp_pcls[1].GetN(); i++) {
1412 band2->SetPoint(band2->GetN(), exp_pcls[1].GetPointX(i),
1413 exp_pcls[1].GetPointY(i) - exp_pcls[1].GetErrorYlow(i));
1414 band2up->SetPoint(band2up->GetN(), exp_pcls[1].GetPointX(i),
1415 exp_pcls[1].GetPointY(i) + exp_pcls[1].GetErrorYhigh(i));
1416 }
1417 for (int i = exp_pcls[1].GetN() - 1; i >= 0; i--) {
1418 band2up->SetPoint(band2up->GetN(), exp_pcls[1].GetPointX(i),
1419 exp_pcls[1].GetPointY(i) - exp_pcls[1].GetErrorYlow(i));
1420 }
1421 for (int i = 0; i < exp_pcls[-1].GetN(); i++) {
1422 band2down->SetPoint(band2down->GetN(), exp_pcls[-1].GetPointX(i),
1423 exp_pcls[-1].GetPointY(i) + exp_pcls[-1].GetErrorYhigh(i));
1424 }
1425 for (int i = exp_pcls[-1].GetN() - 1; i >= 0; i--) {
1426 band2->SetPoint(band2->GetN(), exp_pcls[-1].GetPointX(i),
1427 exp_pcls[-1].GetPointY(i) + exp_pcls[-1].GetErrorYhigh(i));
1428 band2down->SetPoint(band2down->GetN(), exp_pcls[-1].GetPointX(i),
1429 exp_pcls[-1].GetPointY(i) - exp_pcls[-1].GetErrorYlow(i));
1430 }
1431 band2->SetBit(kCanDelete);
1432 band2up->SetBit(kCanDelete);
1433 band2down->SetBit(kCanDelete);
1434 band2->Draw("F");
1435 band2up->Draw("F");
1436 band2down->Draw("F");
1437 }
1438
1439 TObject *expPlot = nullptr;
1440 if (exp_cls[0].GetN() > 0) {
1441 exp_pcls[0].SetLineStyle(2);
1442 exp_pcls[0].SetFillColor(kGreen);
1443 exp_pcls[0].SetMarkerStyle(0);
1444 expPlot = exp_pcls[0].DrawClone("L");
1445 }
1446 obs_pcls->SetBit(kCanDelete);
1447 obs_pcls->Draw(gPad->GetListOfPrimitives()->IsEmpty() ? "ALP" : "LP");
1448
1449 obs_ts->SetLineColor(kRed);
1450 obs_ts->SetMarkerColor(kRed);
1451 obs_ts->SetBit(kCanDelete);
1452 obs_ts->Draw("LP");
1453
1454 auto l = new TLegend(0.5, 0.6, 1. - gPad->GetRightMargin(), 1. - gPad->GetTopMargin());
1455 l->SetName("legend");
1456 l->AddEntry(obs_ts, obs_ts->GetTitle(), "LPE");
1457 l->AddEntry(obs_pcls, obs_pcls->GetTitle(), "LPE");
1458 if (expPlot)
1459 l->AddEntry(expPlot, "Expected", "LFE");
1461 l->Draw();
1462
1463 obs_cls->SetMarkerStyle(29);
1464 obs_cls->SetEditable(false);
1465 obs_cls->Draw("LP");
1466 for (auto s : expSig) {
1467 exp_cls[s].SetMarkerStyle(29);
1468 exp_cls[s].SetEditable(false);
1469 exp_cls[s].DrawClone("LP");
1470 }
1471 }
1472
1473 if (out)
1474 out->RedrawAxis();
1475
1476 return out;
1477}
1478
#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
Int_t _status
Definition RooMinuit.h:76
Int_t hesse()
Int_t minos()
#define oocoutW(o, a)
#define oocoutE(o, a)
#define oocoutI(o, a)
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
@ kRed
Definition Rtypes.h:66
@ kGreen
Definition Rtypes.h:66
@ kYellow
Definition Rtypes.h:66
#define gDirectory
Definition TDirectory.h:386
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:230
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:197
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:241
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
char name[80]
Definition TGX11.cxx:110
#define hi
@ kCanDelete
Definition TObject.h:369
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:470
ProgressMonitor(const ProgressMonitor &other, const char *name=0)
Definition xRooFit.cxx:464
static bool fInterrupt
Definition xRooFit.cxx:437
virtual ~ProgressMonitor()
Definition xRooFit.cxx:456
TStopwatch s
Definition xRooFit.cxx:497
RooRealProxy fFunc
Definition xRooFit.cxx:492
ProgressMonitor(RooAbsReal &f, int interval=30)
Definition xRooFit.cxx:449
virtual TObject * clone(const char *newname) const override
Definition xRooFit.cxx:468
static ProgressMonitor * me
Definition xRooFit.cxx:436
static void interruptHandler(int signum)
Definition xRooFit.cxx:438
void(* oldHandlerr)(int)
Definition xRooFit.cxx:435
Class describing the configuration of the fit, options and parameter settings using the ROOT::Fit::Pa...
Definition FitConfig.h:47
bool UpdateAfterFit() const
Update configuration after a fit using the FitResult.
Definition FitConfig.h:213
void SetMinosErrors(bool on=true)
set Minos erros 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 SetParamsSettings(unsigned int npar, const double *params, const double *vstep=nullptr)
set the parameter settings from number of parameters and a vector of values and optionally step value...
const std::vector< ROOT::Fit::ParameterSettings > & ParamsSettings() const
get the vector of parameter settings (const method)
Definition FitConfig.h:86
void SetParabErrors(bool on=true)
set parabolic erros
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:418
const FitConfig & Config() const
access to the fit configuration (const method)
Definition Fitter.h:446
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:31
void SetValue(const char *name, double val)
generic methods for retrieving options
Definition IOptions.h:45
bool GetValue(const char *name, T &t) const
Definition IOptions.h:74
void SetMaxFunctionCalls(unsigned int maxfcn)
set maximum of function calls
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
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:74
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.
bool isConstant() const
Check if the "Constant" attribute is set.
Definition RooAbsArg.h:359
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
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 expresssion tree)
RooAbsArg * findServer(const char *name) const
Return server of this with name name. Returns nullptr if not found.
Definition RooAbsArg.h:208
RooAbsCollection * selectByAttrib(const char *name, bool value) const
Create a subset of the current collection, consisting only of those elements with the specified attri...
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.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
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.
RooAbsData is the common abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:59
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:62
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:91
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
static TClass * Class()
Class RooBinning is an implements RooAbsBinning in terms of an array of boundary values,...
Definition RooBinning.h:27
RooCmdArg is a named container for two doubles, two integers two object points and three string point...
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.
xRooFitResult minimize(const std::shared_ptr< ROOT::Fit::FitConfig > &=nullptr)
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 hesse()
Execute HESSE.
int minimize(const char *type, const char *alg=nullptr)
Minimise the function passed in the constructor.
void setStrategy(int strat)
Change MINUIT strategy to istrat.
ROOT::Fit::Fitter * fitter()
Return underlying ROOT fitter object.
static RooMsgService & instance()
Return reference to singleton instance.
void setGlobalKillBelow(RooFit::MsgLevel level)
RooFit::MsgLevel globalKillBelow() const
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:34
RooProdPdf is an 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:40
void setVal(double value) override
Set value of variable to 'value'.
void setError(double value)
Definition RooRealVar.h:64
bool hasBinning(const char *name) const override
Returns true if variable has a binning named 'name'.
RooSimultaneous 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.
RooUniformBinning is an implementation of RooAbsBinning that provides a uniform binning in 'n' bins b...
The RooWorkspace is a 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:1504
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
TClass * IsA() const override
Definition TClass.h:614
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.
std::enable_if_t<!std::is_base_of< TObject, T >::value, Int_t > WriteObject(const T *obj, const char *name, Option_t *option="", Int_t bufsize=0)
Write an object with proper type checking.
Definition TDirectory.h:282
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/...".
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:2325
Int_t GetN() const
Definition TGraph.h:129
void Draw(Option_t *chopt="") override
Draw this graph with its current attributes.
Definition TGraph.cxx:808
void SetNameTitle(const char *name="", const char *title="") override
Set graph name and title.
Definition TGraph.cxx:2400
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:774
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
void RedrawAxis(Option_t *option="") override
Redraw the frame axis.
Definition TPad.cxx:5297
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 BEGIN_XROOFIT_NAMESPACE
Definition Config.h:24
#define END_XROOFIT_NAMESPACE
Definition Config.h:25
TLine l
Definition textangle.C:4
#define GIT_COMMIT_HASH