Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
xRooNLLVar.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/** \class ROOT::Experimental::XRooFit::xRooNLLVar
14\ingroup xroofit
15
16This xRooNLLVar object has several special methods, e.g. for fitting and toy dataset generation.
17
18 */
19
20#include "ROOT/RVersion.hxx"
21
22#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
23#define protected public
24#endif
25
26#include "RooFitResult.h"
27
28#if ROOT_VERSION_CODE < ROOT_VERSION(6, 33, 00)
29#include "RooNLLVar.h"
30#endif
31
32#ifdef protected
33#undef protected
34#endif
35
36#include "xRooFit/xRooFit.h"
37
38#include "RooCmdArg.h"
39#include "RooAbsPdf.h"
40#include "RooAbsData.h"
41
42#include "RooConstraintSum.h"
43#include "RooSimultaneous.h"
45#include "TPRegexp.h"
46#include "TEfficiency.h"
47
48#include "RooRealVar.h"
49#include "Math/ProbFunc.h"
50#include "RooRandom.h"
51
52#include "TPad.h"
53#include "TSystem.h"
54
55#include "coutCapture.h"
56
57#include <chrono>
58
59#include "Math/GenAlgoOptions.h"
60
61#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
62#define private public
63#define GETWS(a) a->_myws
64#define GETWSSETS(w) w->_namedSets
65#else
66#define GETWS(a) a->workspace()
67#define GETWSSETS(w) w->sets()
68#endif
69#include "RooWorkspace.h"
70#ifdef private
71#undef private
72#endif
73
74#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
75#define protected public
76#endif
78#ifdef protected
79#undef protected
80#endif
81
82#include "TMultiGraph.h"
83#include "TCanvas.h"
84#include "TArrow.h"
85#include "RooStringVar.h"
86#include "TDirectory.h"
87#include "TStyle.h"
88#include "TH1D.h"
89#include "TLegend.h"
90#include "RooCategory.h"
91#include "TTree.h"
92#include "TGraph2D.h"
93
94#include "RooGaussian.h"
95#include "RooPoisson.h"
96
97#include "TROOT.h"
98#include "TKey.h"
99#include "TRegexp.h"
100#include "TStopwatch.h"
101#include "TEnv.h"
102
104
105std::set<int> xRooNLLVar::xRooHypoPoint::allowedStatusCodes = {0};
106
108public:
109 AutoRestorer(const RooAbsCollection &s, xRooNLLVar *nll = nullptr) : fSnap(s.snapshot()), fNll(nll)
110 {
111 fPars.add(s);
112 if (fNll) {
113 // if (!fNll->kReuseNLL) fOldNll = *fNll;
114 fOldData = fNll->getData();
115 fOldName = fNll->get()->GetName();
116 fOldTitle = fNll->get()->getStringAttribute("fitresultTitle");
117 }
118 }
120 {
122 if (fNll) {
123 // commented out code was attempt to speed up things avoid unnecessarily reinitializing things over and over
124 // if (!fNll->kReuseNLL) {
125 // // can be faster just by putting back in old nll
126 // fNll->std::shared_ptr<RooAbsReal>::operator=(fOldNll);
127 // fNll->fData = fOldData.first;
128 // fNll->fGlobs = fOldData.second;
129 // } else {
130 // fNll->setData(fOldData);
131 // fNll->get()->SetName(fOldName);
132 // fNll->get()->setStringAttribute("fitresultTitle", (fOldTitle == "") ? nullptr : fOldTitle);
133 // }
134 fNll->fGlobs = fOldData.second; // will mean globs matching checks are skipped in setData
135 fNll->setData(fOldData);
136 fNll->get()->SetName(fOldName);
137 fNll->get()->setStringAttribute("fitresultTitle", (fOldTitle == "") ? nullptr : fOldTitle);
138 }
139 }
141 std::unique_ptr<RooAbsCollection> fSnap;
142 xRooNLLVar *fNll = nullptr;
143 // std::shared_ptr<RooAbsReal> fOldNll;
144 std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> fOldData;
146};
147
148xRooNLLVar::~xRooNLLVar() {}
149
150xRooNLLVar::xRooNLLVar(RooAbsPdf &pdf, const std::pair<RooAbsData *, const RooAbsCollection *> &data,
151 const RooLinkedList &nllOpts)
152 : xRooNLLVar(std::shared_ptr<RooAbsPdf>(&pdf, [](RooAbsPdf *) {}),
153 std::make_pair(std::shared_ptr<RooAbsData>(data.first, [](RooAbsData *) {}),
154 std::shared_ptr<const RooAbsCollection>(data.second, [](const RooAbsCollection *) {})),
155 nllOpts)
156{
157}
158
159xRooNLLVar::xRooNLLVar(const std::shared_ptr<RooAbsPdf> &pdf,
160 const std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> &data,
161 const RooLinkedList &opts)
162 : fPdf(pdf), fData(data.first), fGlobs(data.second)
163{
164
165#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 37, 00)
167#else
169#endif
170 fOpts = std::shared_ptr<RooLinkedList>(new RooLinkedList, [](RooLinkedList *l) {
171 if (l)
172 l->Delete();
173 delete l;
174 });
175 fOpts->SetName("");
176
177 // we *must* take global observables from the model even if they are included in the dataset
178 // this is because the way xRooNLLVar is coded up it assumes the globs in the funcVars *ARE*
179 // part of the model
180 fOpts->Add(RooFit::GlobalObservablesSource("model").Clone(nullptr));
181
182 for (int i = 0; i < opts.GetSize(); i++) {
183 if (strlen(opts.At(i)->GetName()) == 0)
184 continue; // skipping "none" cmds
185 if (strcmp(opts.At(i)->GetName(), "GlobalObservables") == 0) {
186 // will skip here to add with the obs from the function below
187 // must match global observables
188 auto gl = dynamic_cast<RooCmdArg *>(opts.At(i))->getSet(0);
189 if (!fGlobs || !fGlobs->equals(*gl)) {
190 throw std::runtime_error("GlobalObservables mismatch");
191 }
192 } else {
193 SetOption(dynamic_cast<RooCmdArg &>(*opts.At(i)));
194 }
195 }
196 if (fGlobs) {
197 // add global observables opt with function obs
198 auto _vars = std::unique_ptr<RooArgSet>(fPdf->getVariables());
199 if (auto extCon = dynamic_cast<RooCmdArg *>(fOpts->find("ExternalConstraints"))) {
200 for (auto con : *extCon->getSet(0)) {
201 _vars->add(*std::unique_ptr<RooArgSet>(con->getVariables()));
202 }
203 }
204 auto _funcGlobs = std::unique_ptr<RooArgSet>(dynamic_cast<RooArgSet *>(_vars->selectCommon(*fGlobs)));
205 fOpts->Add(RooFit::GlobalObservables(*_funcGlobs).Clone());
206 }
207
208 if (auto flag = dynamic_cast<RooCmdArg *>(fOpts->find("ReuseNLL"))) {
209 kReuseNLL = flag->getInt(0);
210 }
211
212 // if fit range specified, and pdf is a RooSimultaneous, may need to 'reduce' the model if some of the pdfs are in
213 // range and others are not
214 if (auto range = dynamic_cast<RooCmdArg *>(fOpts->find("RangeWithName"))) {
215 TString rangeName = range->getString(0);
216
217 // reduce the data here for convenience, not really necessary because will happen inside RooNLLVar but still
218 // fData.reset( fData->reduce(RooFit::SelectVars(*fData->get()),RooFit::CutRange(rangeName)) );
219
220 if (auto s = dynamic_cast<RooSimultaneous *>(fPdf.get()); s) {
221 auto &_cat = const_cast<RooAbsCategoryLValue &>(s->indexCat());
222 std::vector<TString> chanPatterns;
223 TStringToken pattern(rangeName, ",");
224 bool hasRange(false);
225 std::string noneCatRanges;
226 while (pattern.NextToken()) {
227 chanPatterns.emplace_back(pattern);
228 if (_cat.hasRange(chanPatterns.back())) {
229 hasRange = true;
230 } else {
231 if (!noneCatRanges.empty())
232 noneCatRanges += ",";
233 noneCatRanges += chanPatterns.back();
234 }
235 }
236 if (hasRange) {
237 // must remove the ranges that referred to selections on channel category
238 // otherwise RooFit will incorrectly evaluate the NLL (it creates a partition for each range given in the
239 // list, which all end up being equal) the NLL would become scaled by the number of ranges given
240 if (noneCatRanges.empty()) {
241 fOpts->Remove(range);
242 SafeDelete(range);
243 } else {
244 range->setString(0, noneCatRanges.c_str());
245 }
246 // must reduce because category var has one of the ranges
247 auto newPdf =
248 std::make_shared<RooSimultaneous>(TString::Format("%s_reduced", s->GetName()), "Reduced model", _cat);
249 for (auto &c : _cat) {
250 auto _pdf = s->getPdf(c.first.c_str());
251 if (!_pdf)
252 continue;
253 _cat.setIndex(c.second);
254 bool matchAny = false;
255 for (auto &p : chanPatterns) {
256 if (_cat.hasRange(p) && _cat.inRange(p)) {
257 matchAny = true;
258 break;
259 }
260 }
261 if (matchAny) {
262 newPdf->addPdf(*_pdf, c.first.c_str());
263 }
264 }
265 fPdf = newPdf;
266 }
267 }
268 }
269
270 // if (fGlobs) {
271 // // must check GlobalObservables is in the list
272 // }
273 //
274 // if (auto globs = dynamic_cast<RooCmdArg*>(fOpts->find("GlobalObservables"))) {
275 // // first remove any obs the pdf doesnt depend on
276 // auto _vars = std::unique_ptr<RooAbsCollection>( fPdf->getVariables() );
277 // auto _funcGlobs = std::unique_ptr<RooAbsCollection>(_vars->selectCommon(*globs->getSet(0)));
278 // fGlobs.reset( std::unique_ptr<RooAbsCollection>(globs->getSet(0)->selectCommon(*_funcGlobs))->snapshot() );
279 // globs->setSet(0,dynamic_cast<const RooArgSet&>(*_funcGlobs)); // globs in linked list has its own argset
280 // but args need to live as long as the func
281 // /*RooArgSet toRemove;
282 // for(auto a : *globs->getSet(0)) {
283 // if (!_vars->find(*a)) toRemove.add(*a);
284 // }
285 // const_cast<RooArgSet*>(globs->getSet(0))->remove(toRemove);
286 // fGlobs.reset( globs->getSet(0)->snapshot() );
287 // fGlobs->setAttribAll("Constant",true);
288 // const_cast<RooArgSet*>(globs->getSet(0))->replace(*fGlobs);*/
289 // }
290}
291
292xRooNLLVar::xRooNLLVar(const std::shared_ptr<RooAbsPdf> &pdf, const std::shared_ptr<RooAbsData> &data,
293 const RooLinkedList &opts)
294 : xRooNLLVar(
295 pdf,
296 std::make_pair(data, std::shared_ptr<const RooAbsCollection>(
297 (opts.find("GlobalObservables"))
298 ? dynamic_cast<RooCmdArg *>(opts.find("GlobalObservables"))->getSet(0)->snapshot()
299 : nullptr)),
300 opts)
301{
302}
303
305{
306 std::cout << "PDF: ";
307 if (fPdf) {
308 fPdf->Print();
309 } else {
310 std::cout << "<null>" << std::endl;
311 }
312 std::cout << "Data: ";
313 if (fData) {
314 fData->Print();
315 } else {
316 std::cout << "<null>" << std::endl;
317 }
318 std::cout << "NLL Options: " << std::endl;
319 for (int i = 0; i < fOpts->GetSize(); i++) {
320 auto c = dynamic_cast<RooCmdArg *>(fOpts->At(i));
321 if (!c)
322 continue;
323 std::cout << " " << c->GetName() << " : ";
324 if (c->getString(0)) {
325 std::cout << c->getString(0);
326 } else if (c->getSet(0) && !c->getSet(0)->empty()) {
327 std::cout << (c->getSet(0)->contentsString());
328 } else {
329 std::cout << c->getInt(0);
330 }
331 std::cout << std::endl;
332 }
333 if (fFitConfig) {
334 std::cout << "Fit Config: " << std::endl;
335 std::cout << " UseParabErrors: " << (fFitConfig->ParabErrors() ? "True" : "False")
336 << " [toggles HESSE algorithm]" << std::endl;
337 std::cout << " MinimizerOptions: " << std::endl;
338 fFitConfig->MinimizerOptions().Print();
339 }
340 std::cout << "Last Rebuild Log Output: " << std::endl << fFuncCreationLog << std::endl;
341}
342
344{
345 TString oldName = "";
346 if (std::shared_ptr<RooAbsReal>::get())
347 oldName = std::shared_ptr<RooAbsReal>::get()->GetName();
348 if (fPdf) {
350 // need to find all RooRealSumPdf nodes and mark them binned or unbinned as required
351 RooArgSet s;
352 fPdf->treeNodeServerList(&s, nullptr, true, false);
353 s.add(*fPdf); // ensure include self in case fitting a RooRealSumPdf
354 bool isBinned = false;
355 bool hasBinned = false; // if no binned option then 'auto bin' ...
356 if (auto a = dynamic_cast<RooCmdArg *>(fOpts->find("Binned")); a) {
357 hasBinned = true;
358 isBinned = a->getInt(0);
359 }
360 std::map<RooAbsArg *, bool> origValues;
361 if (hasBinned) {
362 for (auto a : s) {
363 if (a->InheritsFrom("RooRealSumPdf")) {
364 // since RooNLLVar will assume binBoundaries available (not null), we should check bin boundaries
365 // available
366 bool setBinned = false;
367 if (isBinned) {
368 std::unique_ptr<RooArgSet> obs(a->getObservables(fData->get()));
369 if (obs->size() == 1) { // RooNLLVar requires exactly 1 obs
370 auto *var = static_cast<RooRealVar *>(obs->first());
371 std::unique_ptr<std::list<double>> boundaries{dynamic_cast<RooAbsReal *>(a)->binBoundaries(
372 *var, -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity())};
373 if (boundaries) {
374 if (!std::shared_ptr<RooAbsReal>::get()) {
375 Info("xRooNLLVar", "%s will be evaluated as a Binned PDF (%d bins)", a->GetName(),
376 int(boundaries->size() - 1));
377 }
378 setBinned = true;
379 }
380 }
381 }
382 origValues[a] = a->getAttribute("BinnedLikelihood");
383 a->setAttribute("BinnedLikelihood", setBinned);
384 }
385 }
386 }
387 std::map<RooAbsPdf *, std::string> normRanges;
388 std::set<TObject *> removedOpts;
389 if (auto range = dynamic_cast<RooCmdArg *>(fOpts->find("RangeWithName"))) {
390 TString rangeName = range->getString(0);
391 if (auto sr = dynamic_cast<RooCmdArg *>(fOpts->find("SplitRange"));
392 sr && sr->getInt(0) && dynamic_cast<RooSimultaneous *>(fPdf.get())) {
393 if (auto special = fOpts->find("RangeOptimize")) {
394 removedOpts.insert(sr);
395 fOpts->Remove(sr);
396 removedOpts.insert(range);
397 fOpts->Remove(range);
398 removedOpts.insert(special);
399 fOpts->Remove(special);
400 }
401 // doing split range ... need to loop over categories of simpdf and apply range to each
402 auto simPdf = dynamic_cast<RooSimultaneous *>(fPdf.get());
403 for (auto cat : simPdf->indexCat()) {
404 auto subpdf = simPdf->getPdf(cat.first.c_str());
405 if (!subpdf)
406 continue; // state not in pdf
407 TString srangeName(rangeName);
408 srangeName.ReplaceAll(",", "_" + cat.first + ",");
409 srangeName += "_" + cat.first;
410 RooArgSet ss;
411 subpdf->treeNodeServerList(&ss, nullptr, true, false);
412 ss.add(*subpdf);
413 for (auto a : ss) {
414 if (a->InheritsFrom("RooAddPdf")) {
415 auto p = dynamic_cast<RooAbsPdf *>(a);
416 normRanges[p] = p->normRange() ? p->normRange() : "";
417 p->setNormRange(srangeName);
418 }
419 }
420 }
421 } else {
422 // set range on all AddPdfs before creating - needed in cases where coefs are present and need fractioning
423 // based on fit range bugfix needed: roofit needs to propagate the normRange to AddPdfs child nodes (used in
424 // createExpectedEventsFunc)
425 for (auto a : s) {
426 if (a->InheritsFrom("RooAddPdf")) {
427 auto p = dynamic_cast<RooAbsPdf *>(a);
428 normRanges[p] = p->normRange() ? p->normRange() : "";
429 p->setNormRange(rangeName);
430 }
431 }
432 }
433 }
434 // before creating, clear away caches if any if pdf is in ws
435 if (GETWS(fPdf)) {
436 std::set<std::string> setNames;
437 for (auto &a : GETWSSETS(GETWS(fPdf))) {
438 if (TString(a.first.c_str()).BeginsWith("CACHE_")) {
439 setNames.insert(a.first);
440 }
441 }
442 for (auto &a : setNames) {
443 GETWS(fPdf)->removeSet(a.c_str());
444 }
445 }
446 std::set<std::string> attribs;
447 if (std::shared_ptr<RooAbsReal>::get())
448 attribs = std::shared_ptr<RooAbsReal>::get()->attributes();
449 this->reset(std::unique_ptr<RooAbsReal>{fPdf->createNLL(*fData, *fOpts)}.release());
450 std::shared_ptr<RooAbsReal>::get()->SetName(TString::Format("nll_%s/%s", fPdf->GetName(), fData->GetName()));
451 for (auto o : removedOpts)
452 fOpts->Add(o);
453 // RooFit only swaps in what it calls parameters, this misses out the RooConstVars which we treat as pars as well
454 // so swap those in ... question: is recursiveRedirectServers usage in RooAbsOptTestStatic (and here) a memory
455 // leak?? where do the replaced servers get deleted??
456
457 for (auto &[k, v] : normRanges)
458 k->setNormRange(v == "" ? nullptr : v.c_str());
459
460 for (auto &a : attribs)
461 std::shared_ptr<RooAbsReal>::get()->setAttribute(a.c_str());
462 // create parent on next line to avoid triggering workspace initialization code in constructor of xRooNode
463 if (GETWS(fPdf)) {
464 xRooNode(*GETWS(fPdf), std::make_shared<xRooNode>()).sterilize();
465 } // there seems to be a nasty bug somewhere that can make the cache become invalid, so clear it here
466 if (oldName != "")
467 std::shared_ptr<RooAbsReal>::get()->SetName(oldName);
468 if (!origValues.empty()) {
469 // need to evaluate NOW so that slaves are created while the BinnedLikelihood settings are in place
470 std::shared_ptr<RooAbsReal>::get()->getVal();
471 for (auto &[o, v] : origValues)
472 o->setAttribute("BinnedLikelihood", v);
473 }
474 }
475
476 fFuncVars = std::unique_ptr<RooArgSet>{std::shared_ptr<RooAbsReal>::get()->getVariables()};
477 if (fGlobs) {
478 fFuncGlobs.reset(fFuncVars->selectCommon(*fGlobs));
479 fFuncGlobs->setAttribAll("Constant", true);
480 }
481 fConstVars.reset(fFuncVars->selectByAttrib("Constant", true)); // will check if any of these have floated
482}
483
484std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>>
485xRooNLLVar::generate(bool expected, int seed)
486{
487 if (!fPdf)
488 return std::pair(nullptr, nullptr);
489 auto fr = std::make_shared<RooFitResult>(TUUID().AsString());
490 fr->setFinalParList(RooArgList());
492 l.add((fFuncVars) ? *fFuncVars : *std::unique_ptr<RooAbsCollection>(fPdf->getParameters(*fData)));
493 fr->setConstParList(l);
494 const_cast<RooArgList &>(fr->constPars()).setAttribAll("global", false);
495 if (fGlobs)
496 std::unique_ptr<RooAbsCollection>(fr->constPars().selectCommon(*fGlobs))->setAttribAll("global", true);
497 return xRooFit::generateFrom(*fPdf, *fr, expected, seed);
498}
499
501
502xRooNLLVar::xRooFitResult::xRooFitResult(const std::shared_ptr<xRooNode> &in, const std::shared_ptr<xRooNLLVar> &nll)
503 : std::shared_ptr<const RooFitResult>(std::dynamic_pointer_cast<const RooFitResult>(in->fComp)),
504 fNode(in),
505 fNll(nll),
506 fCfits(std::make_shared<std::map<std::string, xRooFitResult>>())
507{
508}
510{
511 return fNode->get<RooFitResult>();
512}
513// xRooNLLVar::xRooFitResult::operator std::shared_ptr<const RooFitResult>() const { return
514// std::dynamic_pointer_cast<const RooFitResult>(fNode->fComp); }
515xRooNLLVar::xRooFitResult::operator const RooFitResult *() const
516{
517 return fNode->get<const RooFitResult>();
518}
520{
521 fNode->Draw(opt);
522}
523
524xRooNLLVar::xRooFitResult xRooNLLVar::xRooFitResult::cfit(const char *poiValues, const char *alias)
525{
526
527 // create a hypoPoint with ufit equal to this fit
528 // and poi equal to given poi
529 if (!fNll)
530 throw std::runtime_error("xRooFitResult::cfit: Cannot create cfit without nll");
531
532 // see if fit already done
533 if (alias) {
534 if (auto res = fCfits->find(alias); res != fCfits->end()) {
535 return res->second;
536 }
537 }
538 if (auto res = fCfits->find(poiValues); res != fCfits->end()) {
539 return res->second;
540 }
541
542 AutoRestorer s(*fNll->fFuncVars);
543 *fNll->fFuncVars = get()->floatParsFinal();
544 fNll->fFuncVars->assignValueOnly(get()->constPars());
545 std::unique_ptr<RooAbsCollection>(fNll->fFuncVars->selectCommon(get()->floatParsFinal()))
546 ->setAttribAll("Constant", false);
547 std::unique_ptr<RooAbsCollection>(fNll->fFuncVars->selectCommon(get()->constPars()))->setAttribAll("Constant", true);
548
549 auto hp = fNll->hypoPoint(poiValues, std::numeric_limits<double>::quiet_NaN(), xRooFit::Asymptotics::Unknown);
550 hp.fUfit = *this;
551 auto out = xRooNLLVar::xRooFitResult(std::make_shared<xRooNode>(hp.cfit_null(), fNode->fParent), fNll);
552 fCfits->insert(std::pair((alias) ? alias : poiValues, out));
553 return out;
554}
556{
557 RooRealVar *npVar = dynamic_cast<RooRealVar *>((prefit ? get()->floatParsInit() : get()->floatParsFinal()).find(np));
558 if (!npVar)
559 throw std::runtime_error("xRooFitResult::ifit: par not found");
560 return cfit(TString::Format("%s=%f", np, npVar->getVal() + (up ? npVar->getErrorHi() : npVar->getErrorLo())));
561}
562double xRooNLLVar::xRooFitResult::impact(const char *poi, const char *np, bool up, bool prefit, bool covApprox)
563{
564 if (!covApprox) {
565 // get the ifit and get the difference between the postFit poi values
566 RooRealVar *poiHat = dynamic_cast<RooRealVar *>((get()->floatParsFinal()).find(poi));
567 if (!poiHat)
568 throw std::runtime_error("xRooFitResult::impact: poi not found");
569 auto _ifit = ifit(np, up, prefit);
570 if (!_ifit)
571 throw std::runtime_error("xRooFitResult::impact: null ifit");
572 if (_ifit->status() != 0)
573 fNode->Warning("impact", "ifit status code is %d", _ifit->status());
574 return _ifit->floatParsFinal().getRealValue(poi) - poiHat->getVal();
575 } else {
576 // estimate impact from the covariance matrix ....
577 int iPoi = get()->floatParsFinal().index(poi);
578 int iNp = get()->floatParsFinal().index(np);
579 if (iPoi == -1)
580 throw std::runtime_error("xRooFitResult::impact: poi not found");
581 if (iNp == -1)
582 throw std::runtime_error("xRooFitResult::impact: np not found");
583 RooRealVar *npVar =
584 dynamic_cast<RooRealVar *>((prefit ? get()->floatParsInit() : get()->floatParsFinal()).find(np));
585 return get()->covarianceMatrix()(iPoi, iNp) / (up ? npVar->getErrorHi() : npVar->getErrorLo());
586 }
587 return std::numeric_limits<double>::quiet_NaN();
588}
589
590double xRooNLLVar::xRooFitResult::conditionalError(const char *poi, const char *nps, bool up, bool covApprox)
591{
592 // run a fit with given NPs held constant, return quadrature difference
593
594 TString npNames;
595 RooArgList vars;
596 RooAbsArg *poiVar = nullptr;
597 for (auto p : get()->floatParsFinal()) {
598 if (strcmp(p->GetName(), poi) == 0) {
599 vars.add(*p);
600 poiVar = p;
601 continue;
602 }
603 TStringToken pattern(nps, ",");
604 bool matches = false;
605 while (pattern.NextToken()) {
606 TString s(pattern);
607 if ((p->getStringAttribute("group") && s == p->getStringAttribute("group")) ||
608 TString(p->GetName()).Contains(TRegexp(s, true)) || p->getAttribute(s)) {
609 matches = true;
610 break;
611 }
612 }
613 if (matches) {
614 if (npNames.Length())
615 npNames += ",";
616 npNames += p->GetName();
617 } else {
618 vars.add(*p); // keeping in reduced cov matrix
619 }
620 }
621 if (!poiVar) {
622 throw std::runtime_error(TString::Format("Could not find poi: %s", poi));
623 }
624 if (npNames == "") {
625 fNode->Warning("conditionalError", "No parameters selected by: %s", nps);
626 return (up) ? static_cast<RooRealVar *>(poiVar)->getErrorHi() : static_cast<RooRealVar *>(poiVar)->getErrorLo();
627 }
628
629 if (covApprox) {
630 int idx = vars.index(poi);
631 return sqrt(get()->conditionalCovarianceMatrix(vars)(idx, idx));
632 }
633
634 auto _cfit = cfit(npNames.Data(), nps);
635
636 auto _poi = _cfit->floatParsFinal().find(poi);
637
638 return (up) ? static_cast<RooRealVar *>(_poi)->getErrorHi() : static_cast<RooRealVar *>(_poi)->getErrorLo();
639}
640
641RooArgList xRooNLLVar::xRooFitResult::ranknp(const char *poi, bool up, bool prefit, double approxThreshold)
642{
643
644 RooRealVar *poiHat = dynamic_cast<RooRealVar *>((get()->floatParsFinal()).find(poi));
645 if (!poiHat)
646 throw std::runtime_error("xRooFitResult::ranknp: poi not found");
647
648 std::vector<std::pair<std::string, double>> ranks;
649 // first do with the covariance approximation, since that's always available
650 for (auto par : get()->floatParsFinal()) {
651 if (par == poiHat)
652 continue;
653 ranks.emplace_back(std::pair(par->GetName(), impact(poi, par->GetName(), up, prefit, true)));
654 }
655
656 std::sort(ranks.begin(), ranks.end(), [](auto &left, auto &right) {
657 if (std::isnan(left.second) && !std::isnan(right.second))
658 return false;
659 if (!std::isnan(left.second) && std::isnan(right.second))
660 return true;
661 return fabs(left.second) > fabs(right.second);
662 });
663
664 // now redo the ones above the threshold
665 for (auto &[n, v] : ranks) {
666 if (v >= approxThreshold) {
667 try {
668 v = impact(poi, n.c_str(), up, prefit);
669 } catch (...) {
670 v = std::numeric_limits<double>::quiet_NaN();
671 };
672 }
673 }
674
675 // resort
676 std::sort(ranks.begin(), ranks.end(), [](auto &left, auto &right) {
677 if (std::isnan(left.second) && !std::isnan(right.second))
678 return false;
679 if (!std::isnan(left.second) && std::isnan(right.second))
680 return true;
681 return fabs(left.second) > fabs(right.second);
682 });
683
684 RooArgList out;
685 out.setName("rankings");
686 for (auto &[n, v] : ranks) {
687 out.addClone(*get()->floatParsFinal().find(n.c_str()));
688 auto vv = static_cast<RooRealVar *>(out.at(out.size() - 1));
689 vv->setVal(v);
690 vv->removeError();
691 vv->removeMin();
692 vv->removeMax(); // vv->removeRange();
693 }
694 return out;
695}
696
697xRooNLLVar::xRooFitResult xRooNLLVar::minimize(const std::shared_ptr<ROOT::Fit::FitConfig> &_config)
698{
699 auto &nll = *get();
700 auto out = xRooFit::minimize(nll, (_config) ? _config : fitConfig(), fOpts);
701 // add any pars that are const here that aren't in constPars list because they may have been
702 // const-optimized and their values cached with the dataset, so if subsequently floated the
703 // nll wont evaluate correctly
704 // fConstVars.reset( fFuncVars->selectByAttrib("Constant",true) );
705
706 // before returning, flag which of the constPars were actually global observables
707 if (out) {
708 const_cast<RooArgList &>(out->constPars()).setAttribAll("global", false);
709 if (fGlobs)
710 std::unique_ptr<RooAbsCollection>(out->constPars().selectCommon(*fGlobs))->setAttribAll("global", true);
711 }
712
713 if (fOpts->find("GoF")) {
714 // add pgof to the fit result
715 const_cast<RooArgList &>(out->constPars()).addClone(RooRealVar(".pgof", "GoF p-value", pgof()));
716 // and just main term
717 const_cast<RooArgList &>(out->constPars())
718 .addClone(RooRealVar(".mainterm_pgof", "MainTerm GoF p-value", mainTermPgof()));
719 }
720
721 return xRooFitResult(std::make_shared<xRooNode>(out, fPdf), std::make_shared<xRooNLLVar>(*this));
722}
723
724std::shared_ptr<ROOT::Fit::FitConfig> xRooNLLVar::fitConfig()
725{
726 if (!fFitConfig)
728 return fFitConfig;
729}
730
732{
733 if (auto conf = fitConfig(); conf)
734 return const_cast<ROOT::Math::IOptions *>(conf->MinimizerOptions().ExtraOptions());
735 return nullptr;
736}
737
738double xRooNLLVar::getEntryVal(size_t entry) const
739{
740 auto _data = data();
741 if (!_data)
742 return 0;
743 if (size_t(_data->numEntries()) <= entry)
744 return 0;
745 auto _pdf = pdf();
746 *std::unique_ptr<RooAbsCollection>(_pdf->getObservables(_data)) = *_data->get(entry);
747 // if (auto s = dynamic_cast<RooSimultaneous*>(_pdf.get());s) return
748 // -_data->weight()*s->getPdf(s->indexCat().getLabel())->getLogVal(_data->get());
749 return (_data->weight() == 0) ? 0 : (-_data->weight() * _pdf->getLogVal(_data->get()));
750}
751
752std::set<std::string> xRooNLLVar::binnedChannels() const
753{
754 std::set<std::string> out;
755
756 auto binnedOpt = dynamic_cast<RooCmdArg *>(fOpts->find("Binned")); // the binned option, if explicitly specified
757
758 if (auto s = dynamic_cast<RooSimultaneous *>(pdf().get())) {
759 xRooNode simPdf(*s);
760 bool allChannels = true;
761 for (auto c : simPdf.bins()) {
762 // see if there's a RooRealSumPdf in the channel - if there is, if it has BinnedLikelihood set
763 // then assume is a BinnedLikelihood channel
764 RooArgSet nodes;
765 c->get<RooAbsArg>()->treeNodeServerList(&nodes, nullptr, true, false);
766 bool isBinned = false;
767 for (auto a : nodes) {
768 if (a->InheritsFrom("RooRealSumPdf") &&
769 ((binnedOpt && binnedOpt->getInt(0)) || (!binnedOpt && a->getAttribute("BinnedLikelihood")))) {
770 TString chanName(c->GetName());
771 out.insert(chanName(chanName.Index("=") + 1, chanName.Length()).Data());
772 isBinned = true;
773 break;
774 }
775 }
776 if (!isBinned) {
777 allChannels = false;
778 }
779 }
780 if (allChannels) {
781 out.clear();
782 out.insert("*");
783 }
784 } else {
785 RooArgSet nodes;
786 pdf()->treeNodeServerList(&nodes, nullptr, true, false);
787 for (auto a : nodes) {
788 if (a->InheritsFrom("RooRealSumPdf") &&
789 ((binnedOpt && binnedOpt->getInt(0)) || (!binnedOpt && a->getAttribute("BinnedLikelihood")))) {
790 out.insert("*");
791 break;
792 }
793 }
794 }
795 return out;
796}
797
798double xRooNLLVar::getEntryBinWidth(size_t entry) const
799{
800
801 auto _data = data();
802 if (!_data)
803 return 0;
804 if (size_t(_data->numEntries()) <= entry)
805 return 0;
806 auto _pdf = pdf().get();
807 std::unique_ptr<RooAbsCollection> _robs(_pdf->getObservables(_data->get()));
808 *_robs = *_data->get(entry); // only set robs
809 if (auto s = dynamic_cast<RooSimultaneous *>(_pdf); s) {
810 _pdf = s->getPdf(s->indexCat().getCurrentLabel());
811 }
812 double volume = 1.;
813 for (auto o : *_robs) {
814
815 if (auto a = dynamic_cast<RooAbsRealLValue *>(o);
816 a && _pdf->dependsOn(*a)) { // dependsOn check needed until ParamHistFunc binBoundaries method fixed
817 std::unique_ptr<std::list<double>> bins(
818 _pdf->binBoundaries(*a, -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()));
819 if (bins) {
820 double lowEdge = -std::numeric_limits<double>::infinity();
821 for (auto b : *bins) {
822 if (b > a->getVal()) {
823 volume *= (b - lowEdge);
824 break;
825 }
826 lowEdge = b;
827 }
828 }
829 }
830 }
831
832 return volume;
833}
834
836{
837 // for each global observable in the dataset, determine which constraint term is associated to it
838 // and given its type, add the necessary saturated term...
839
840 double out = 0;
841
842 if (!fGlobs)
843 return 0;
844
845 auto cTerm = constraintTerm();
846 if (!cTerm)
847 return 0;
848
849 for (auto c : cTerm->list()) {
850 if (std::string(c->ClassName()) == "RooAbsPdf" ||
851 std::string(c->ClassName()).find("RooNormalizedPdf") != std::string::npos) {
852 // in ROOT 6.32 the constraintTerm is full of RooNormalizedPdfs which aren't public
853 // became public in 6.34, hence now also check for RooNormalizedPdf explicitly
854 // in this case use the first server
855 c = c->servers()[0];
856 }
857 if (auto gaus = dynamic_cast<RooGaussian *>(c)) {
858 auto v = dynamic_cast<RooAbsReal *>(fGlobs->find(gaus->getX().GetName()));
859 if (!v) {
860 v = dynamic_cast<RooAbsReal *>(fGlobs->find(
861 gaus->getMean().GetName())); // shouldn't really happen but does for at least ws made by pyhf
862 }
863 if (!v)
864 continue;
865 out -= std::log(ROOT::Math::gaussian_pdf(v->getVal(), gaus->getSigma().getVal(), v->getVal()));
866 } else if (auto pois = dynamic_cast<RooPoisson *>(c)) {
867 auto v = dynamic_cast<RooAbsReal *>(fGlobs->find(pois->getX().GetName()));
868 if (!v)
869 continue;
870 out -= std::log(TMath::Poisson(v->getVal(), v->getVal()));
871 }
872 }
873
874 return out;
875}
876
877double xRooNLLVar::ndof() const
878{
879 return data()->numEntries() + (fFuncGlobs ? fFuncGlobs->size() : 0) -
880 std::unique_ptr<RooAbsCollection>(pars()->selectByAttrib("Constant", false))->size();
881}
882
883double xRooNLLVar::pgof() const
884{
885 // note that if evaluating this for a single channel, until 6.30 is available if you are using Binned mode the pdf
886 // will need to be part of a Simultaneous
887 return TMath::Prob(2. * (get()->getVal() - saturatedVal()), ndof());
888}
889
891{
892 // need to count number of floating unconstrained parameters
893 // which are floating parameters not featured in the constraintTerm
894 std::unique_ptr<RooAbsCollection> _floats(pars()->selectByAttrib("Constant", false));
895 if (auto _constraintTerm = constraintTerm()) {
896 _floats->remove(*std::unique_ptr<RooAbsCollection>(_constraintTerm->getVariables()));
897 }
898 return data()->numEntries() - _floats->size();
899}
900
902{
903 // using totVal - constraintTerm while new evalbackend causes mainTerm() to return nullptr
904 return get()->getVal() - constraintTermVal();
905}
906
908{
909 if (auto _constraintTerm = constraintTerm()) {
910 return _constraintTerm->getVal();
911 }
912 return 0;
913}
914
916{
918}
919
924
926{
927
928 // Use this term to create a goodness-of-fit metric, which is approx chi2 distributed with numEntries (data) d.o.f:
929 // prob = TMath::Prob( 2.*(nll.mainTerm()->getVal() - nll.saturatedNllTerm()), nll.data()->numEntries() )
930
931 // note that need to construct nll with explicit Binned(1 or 0) option otherwise will pick up nll eval
932 // from attributes in model already, so many get binned mainTerm eval when thinking not binned because didnt specify
933 // Binned(1)
934
935 auto _data = data();
936 if (!_data)
937 return std::numeric_limits<double>::quiet_NaN();
938
939 std::set<std::string> _binnedChannels = binnedChannels();
940
941 // for binned case each entry is: -(-N + Nlog(N) - TMath::LnGamma(N+1))
942 // for unbinned case each entry is: -(N*log(N/(sumN*binW))) = -N*logN + N*log(sumN) + N*log(binW)
943 // but unbinned gets extendedTerm = sumN - sumN*log(sumN)
944 // so resulting sum is just sumN - sum[ N*logN - N*log(binW) ]
945 // which is the same as the binned case without the LnGamma part and with the extra sum[N*log(binW)] part
946
947 const RooAbsCategoryLValue *cat = (dynamic_cast<RooSimultaneous *>(pdf().get()))
948 ? &dynamic_cast<RooSimultaneous *>(pdf().get())->indexCat()
949 : nullptr;
950
951 double out = _data->sumEntries();
952 for (int i = 0; i < _data->numEntries(); i++) {
953 _data->get(i);
954 double w = _data->weight();
955 if (w == 0)
956 continue;
957 out -= w * std::log(w);
958 if (_binnedChannels.count("*")) {
959 out += TMath::LnGamma(w + 1);
960 } else if (_binnedChannels.empty()) {
961 out += w * std::log(getEntryBinWidth(i));
962 } else if (cat) {
963 // need to determine which channel we are in for this entry to decide if binned or unbinned active
964 if (_binnedChannels.count(_data->get()->getCatLabel(cat->GetName()))) {
965 out += TMath::LnGamma(w + 1);
966 } else {
967 out += w * std::log(getEntryBinWidth(i));
968 }
969 } else {
970 throw std::runtime_error("Cannot determine category of RooSimultaneous pdf");
971 }
972 }
973
974 out += simTermVal();
975
976 return out;
977}
978
979std::shared_ptr<RooArgSet> xRooNLLVar::pars(bool stripGlobalObs) const
980{
981 auto out = std::shared_ptr<RooArgSet>(get()->getVariables());
982 if (stripGlobalObs && fGlobs) {
983 out->remove(*fGlobs, true, true);
984 }
985 return out;
986}
987
988TObject *
989xRooNLLVar::Scan(const char *scanPars, const std::vector<std::vector<double>> &coords, const RooArgList &profilePars)
990{
991 return Scan(*std::unique_ptr<RooAbsCollection>(get()->getVariables()->selectByName(scanPars)), coords, profilePars);
992}
993
994TObject *xRooNLLVar::Scan(const RooArgList &scanPars, const std::vector<std::vector<double>> &coords,
995 const RooArgList &profilePars)
996{
997
998 if (scanPars.size() > 2 || scanPars.empty())
999 return nullptr;
1000
1001 TGraph2D *out2d = (scanPars.size() == 2) ? new TGraph2D() : nullptr;
1002 TGraph *out1d = (out2d) ? nullptr : new TGraph();
1003 TNamed *out = (out2d) ? static_cast<TNamed *>(out2d) : static_cast<TNamed *>(out1d);
1004 out->SetName(get()->GetName());
1005 out->SetTitle(TString::Format("%s;%s%s%s", get()->GetTitle(), scanPars.first()->GetTitle(), out2d ? ";" : "",
1006 out2d ? scanPars.at(1)->GetTitle() : ""));
1007
1008 std::unique_ptr<RooAbsCollection> funcVars(get()->getVariables());
1009 AutoRestorer snap(*funcVars);
1010
1011 for (auto &coord : coords) {
1012 if (coord.size() != scanPars.size()) {
1013 throw std::runtime_error("Invalid coordinate");
1014 }
1015 for (size_t i = 0; i < coord.size(); i++) {
1016 static_cast<RooAbsRealLValue &>(scanPars[i]).setVal(coord[i]);
1017 }
1018
1019 if (profilePars.empty()) {
1020 // just evaluate
1021 if (out2d) {
1022 out2d->SetPoint(out2d->GetN(), coord[0], coord[1], get()->getVal());
1023 } else {
1024 out1d->SetPoint(out1d->GetN(), coord[0], get()->getVal());
1025 }
1026 }
1027 }
1028
1029 return out;
1030}
1031
1033{
1034 TString sOpt(opt);
1035
1036 auto _pars = pars();
1037
1038 if (sOpt == "sensitivity") {
1039
1040 // will make a plot of DeltaNLL
1041 }
1042
1043 if (sOpt == "floating") {
1044 // start scanning floating pars
1045 auto floats = std::unique_ptr<RooAbsCollection>(_pars->selectByAttrib("Constant", false));
1046 TVirtualPad *pad = gPad;
1047 if (!pad) {
1049 pad = gPad;
1050 }
1051 TMultiGraph *gr = new TMultiGraph;
1052 gr->SetName("multigraph");
1053 gr->SetTitle(TString::Format("%s;Normalized Parameter Value;#Delta NLL", get()->GetTitle()));
1054 /*((TPad*)pad)->DivideSquare(floats->size());
1055 int i=0;
1056 for(auto a : *floats) {
1057 i++;
1058 pad->cd(i);
1059 Draw(a->GetName());
1060 }*/
1061 return;
1062 }
1063
1064 RooArgList vars;
1065 TStringToken pattern(sOpt, ":");
1066 while (pattern.NextToken()) {
1067 TString s(pattern);
1068 if (auto a = _pars->find(s); a)
1069 vars.add(*a);
1070 }
1071
1072 if (vars.size() == 1) {
1073 TGraph *out = new TGraph;
1074 out->SetBit(kCanDelete);
1075 TGraph *bad = new TGraph;
1076 bad->SetBit(kCanDelete);
1077 bad->SetMarkerColor(kRed);
1078 bad->SetMarkerStyle(5);
1079 TMultiGraph *gr = (gPad) ? dynamic_cast<TMultiGraph *>(gPad->GetPrimitive("multigraph")) : nullptr;
1080 bool normRange = false;
1081 if (!gr) {
1082 gr = new TMultiGraph;
1083 gr->Add(out, "LP");
1085 } else {
1086 normRange = true;
1087 }
1088 out->SetName(get()->GetName());
1089 gr->SetTitle(TString::Format("%s;%s;#Delta NLL", get()->GetTitle(), vars.at(0)->GetTitle()));
1090 // scan outwards from current value towards limits
1091 auto v = dynamic_cast<RooRealVar *>(vars.at(0));
1092 double low = v->getVal();
1093 double high = low;
1094 double step = (v->getMax() - v->getMin()) / 100;
1095 double init = v->getVal();
1096 double initVal = func()->getVal();
1097 // double xscale = (normRange) ? (2.*(v->getMax() - v->getMin())) : 1.;
1098 auto currTime = std::chrono::steady_clock::now();
1099 while (out->GetN() < 100 && (low > v->getMin() || high < v->getMax())) {
1100 if (out->GetN() == 0) {
1101 out->SetPoint(out->GetN(), low, 0);
1102 low -= step;
1103 high += step;
1104 if (!normRange) {
1105 gr->Draw("A");
1106 gPad->SetGrid();
1107 }
1108 continue;
1109 }
1110 if (low > v->getMin()) {
1111 v->setVal(low);
1112 auto _v = func()->getVal();
1113 if (std::isnan(_v) || std::isinf(_v)) {
1114 if (bad->GetN() == 0)
1115 gr->Add(bad, "P");
1116 bad->SetPoint(bad->GetN(), low, out->GetPointY(0));
1117 } else {
1118 out->SetPoint(out->GetN(), low, _v - initVal);
1119 }
1120 low -= step;
1121 }
1122 if (high < v->getMax()) {
1123 v->setVal(high);
1124 auto _v = func()->getVal();
1125 if (std::isnan(_v) || std::isinf(_v)) {
1126 if (bad->GetN() == 0)
1127 gr->Add(bad, "P");
1128 bad->SetPoint(bad->GetN(), high, out->GetPointY(0));
1129 } else {
1130 out->SetPoint(out->GetN(), high, _v - initVal);
1131 }
1132 high += step;
1133 }
1134 out->Sort();
1135 // should only do processEvents once every second in case using x11 (which is slow)
1136 gPad->Modified();
1137 if (std::chrono::steady_clock::now() - currTime > std::chrono::seconds(1)) {
1138 currTime = std::chrono::steady_clock::now();
1139 gPad->Update();
1141 }
1142 }
1143 // add arrow to show current par value
1144 TArrow a;
1145 a.DrawArrow(init, 0, init, -0.1);
1146 gPad->Update();
1147#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 30, 00)
1148 gPad->GetCanvas()->ResetUpdated(); // stops previous canvas being replaced in a jupyter notebook
1149#endif
1151 v->setVal(init);
1152 } else {
1153 Error("Draw", "Name a parameter to scan over: Draw(<name>) , choose from: %s",
1154 _pars->empty() ? "" : _pars->contentsString().c_str());
1155 }
1156}
1157
1158std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> xRooNLLVar::getData() const
1159{
1160 return std::make_pair(fData, fGlobs);
1161}
1162
1164{
1165 if (data.fComp && !data.get<RooAbsData>()) {
1166 return false;
1167 }
1168 return setData(std::dynamic_pointer_cast<RooAbsData>(data.fComp),
1169 std::shared_ptr<const RooAbsCollection>(data.globs().argList().snapshot()));
1170}
1171
1172bool xRooNLLVar::setData(const std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> &_data)
1173{
1174
1175 if (fData == _data.first && fGlobs == _data.second)
1176 return true;
1177
1178 auto _globs = fGlobs; // done to keep globs alive while NLL might still be alive.
1179
1180 auto _dglobs = (_data.second) ? _data.second
1181 : std::shared_ptr<const RooAbsCollection>(_data.first->getGlobalObservables(),
1182 [](const RooAbsCollection *) {});
1183
1184 if (fGlobs && !(fGlobs->empty() && !_dglobs) && _data.first &&
1185 fGlobs != _dglobs) { // second condition allows for no globs being a nullptr, third allow globs to remain if
1186 // nullifying data
1187 if (!_dglobs)
1188 throw std::runtime_error("Missing globs");
1189 // ignore 'extra' globs
1190 RooArgSet s;
1191 s.add(*fGlobs);
1192 std::unique_ptr<RooAbsCollection> _actualGlobs(fPdf->getObservables(s));
1193 RooArgSet s2;
1194 s2.add(*_dglobs);
1195 std::unique_ptr<RooAbsCollection> _actualGlobs2(fPdf->getObservables(s2));
1196 if (!_actualGlobs->equals(*_actualGlobs2)) {
1197 RooArgSet rC;
1198 rC.add(*_actualGlobs2);
1199 rC.remove(*std::unique_ptr<RooAbsCollection>(rC.selectCommon(*_actualGlobs)));
1200 TString r = (!rC.empty()) ? rC.contentsString() : "";
1201 RooArgSet lC;
1202 lC.add(*_actualGlobs);
1203 lC.remove(*std::unique_ptr<RooAbsCollection>(lC.selectCommon(*_actualGlobs2)));
1204 TString l = (!lC.empty()) ? lC.contentsString() : "";
1205 throw std::runtime_error(TString::Format("globs mismatch: adding %s removing %s", r.Data(), l.Data()));
1206 }
1207 fGlobs = _dglobs;
1208 }
1209
1210 if (!std::shared_ptr<RooAbsReal>::get()) {
1211 fData = _data.first;
1212 return true; // not loaded yet so nothing to do
1213 }
1214
1215 try {
1216 if (!kReuseNLL /*|| !mainTerm()*/
1217 /*|| mainTerm()->operMode() == RooAbsTestStatistic::MPMaster*/) { // lost access to RooAbsTestStatistic
1218 // in 6.34, but MP-mode will still throw
1219 // exception, so we will still catch it
1220 // happens when using MP need to rebuild the nll instead
1221 // also happens if there's no mainTerm(), which is the case in 6.32 where RooNLLVar is partially deprecated
1222 AutoRestorer snap(*fFuncVars);
1223 // ensure the const state is back where it was at nll construction time;
1224 fFuncVars->setAttribAll("Constant", false);
1225 fConstVars->setAttribAll("Constant", true);
1226 std::shared_ptr<RooAbsData> __data = fData; // do this just to keep fData alive while killing previous NLLVar
1227 // (can't kill data while NLL constructed with it)
1228 fData = _data.first;
1229 reinitialize();
1230 return true;
1231 }
1232 bool out = false;
1233 if (_data.first) {
1234 // replace in all terms
1235 out = get()->setData(*_data.first, false /* clone data */);
1236 // get()->setValueDirty();
1237 // if (_data.first->getGlobalObservables()) {
1238 // // replace in all terms
1239 // out = get()->setData(*_data.first, false);
1240 // get()->setValueDirty();
1241 // } else {
1242 // // replace just in mainTerm ... note to self: why not just replace in all like above? should
1243 // test! auto _mainTerm = mainTerm(); out = _mainTerm->setData(*_data.first, false /* clone data?
1244 // */); _mainTerm->setValueDirty();
1245 // }
1246 } else {
1247 reset();
1248 }
1249 fData = _data.first;
1250 return out;
1251 } catch (std::runtime_error &) {
1252 // happens when using MP need to rebuild the nll instead
1253 // also happens if there's no mainTerm(), which is the case in 6.32 where RooNLLVar is partially deprecated
1254 AutoRestorer snap(*fFuncVars);
1255 // ensure the const state is back where it was at nll construction time;
1256 fFuncVars->setAttribAll("Constant", false);
1257 fConstVars->setAttribAll("Constant", true);
1258 std::shared_ptr<RooAbsData> __data = fData; // do this just to keep fData alive while killing previous NLLVar
1259 // (can't kill data while NLL constructed with it)
1260 fData = _data.first;
1261 reinitialize();
1262 return true;
1263 }
1264 throw std::runtime_error("Unable to setData");
1265}
1266
1267std::shared_ptr<RooAbsReal> xRooNLLVar::func() const
1268{
1269 if (!(*this)) {
1270 const_cast<xRooNLLVar *>(this)->reinitialize();
1271 } else if (auto f = std::unique_ptr<RooAbsCollection>(fConstVars->selectByAttrib("Constant", false)); !f->empty()) {
1272 // have to reinitialize if const par values have changed - const optimization forces this
1273 // TODO: currently changes to globs also triggers this since the vars includes globs (vars are the non-obs pars)
1274 // std::cout << "Reinitializing because of change of const parameters:" << f->contentsString() << std::endl;
1275 const_cast<xRooNLLVar *>(this)->reinitialize();
1276
1277 // note ... it may be sufficient here to do:
1278 // nll.constOptimizeTestStatistic(RooAbsArg::ConfigChange, constOptimize>1 /* do tracking too if >1 */); //
1279 // trigger a re-evaluate of which nodes to cache-and-track nll.constOptimizeTestStatistic(RooAbsArg::ValueChange,
1280 // constOptimize>1); // update the cache values -- is this needed??
1281 // this forces the optimization to be redone
1282 // for now leave as a reinitialize though, until had a chance to test this properly
1283 }
1284 if (fGlobs && fFuncGlobs) {
1285 *fFuncGlobs = *fGlobs;
1286 fFuncGlobs->setAttribAll("Constant", true);
1287 }
1288 return *this;
1289}
1290
1292{
1293
1294 if (strcmp(opt.GetName(), "Hesse") == 0) {
1295 fitConfig()->SetParabErrors(opt.getInt(0)); // controls hesse
1296 } else if (strcmp(opt.GetName(), "Minos") == 0) {
1297 fitConfig()->SetMinosErrors(opt.getInt(0)); // controls minos
1298 } else if (strcmp(opt.GetName(), "Strategy") == 0) {
1299 fitConfig()->MinimizerOptions().SetStrategy(opt.getInt(0));
1300 } else if (strcmp(opt.GetName(), "StrategySequence") == 0) {
1301 fitConfigOptions()->SetNamedValue("StrategySequence", opt.getString(0));
1302 } else if (strcmp(opt.GetName(), "Tolerance") == 0) {
1303 fitConfig()->MinimizerOptions().SetTolerance(opt.getDouble(0));
1304 } else if (strcmp(opt.GetName(), "MaxCalls") == 0) {
1305 fitConfig()->MinimizerOptions().SetMaxFunctionCalls(opt.getInt(0));
1306 } else if (strcmp(opt.GetName(), "MaxIterations") == 0) {
1307 fitConfig()->MinimizerOptions().SetMaxIterations(opt.getInt(0));
1308 } else if (strcmp(opt.GetName(), "PrintLevel") == 0) {
1309 fitConfig()->MinimizerOptions().SetPrintLevel(opt.getInt(0));
1310 } else {
1311#if ROOT_VERSION_CODE < ROOT_VERSION(6, 41, 00)
1312 if (strcmp(opt.GetName(), "Optimize") == 0) {
1313 // this flag will trigger constOptimizeTestStatistic to be called on the nll in createNLL method
1314 // we should ensure that the fitconfig setting is consistent with it ...
1315 fitConfigOptions()->SetValue("OptimizeConst", opt.getInt(0));
1316 }
1317#endif
1318 if (auto prevObject = fOpts->FindObject(opt.GetName()); prevObject) {
1319 // replace previous option
1320 fOpts->Replace(prevObject, opt.Clone(nullptr));
1321 delete prevObject;
1322 } else {
1323 fOpts->Add(opt.Clone(nullptr)); // nullptr needed because accessing Clone via TObject base class puts
1324 // "" instead, so doesnt copy names
1325 }
1326 if (std::shared_ptr<RooAbsReal>::get()) {
1327 reinitialize(); // do this way to keep name of nll if user set
1328 } else {
1329 reset(); // will trigger reinitialize
1330 }
1331 }
1332}
1333
1335{
1336 return fData.get();
1337 /*
1338#if ROOT_VERSION_CODE < ROOT_VERSION(6, 33, 00)
1339 auto _nll = mainTerm();
1340 if (!_nll)
1341 return fData.get();
1342 RooAbsData *out = &static_cast<RooAbsOptTestStatistic*>(_nll)->data();
1343#else
1344 RooAbsData* out = nullptr; // new backends not conducive to having a reference to a RooAbsData in them (they use
1345buffers instead) #endif if (!out) return fData.get(); return out;
1346 */
1347}
1348
1349/*
1350RooAbsReal *xRooNLLVar::mainTerm() const
1351{
1352 return nullptr;
1353 // the main term is the "other term" in a RooAddition alongside a ConstraintSum
1354 // if can't find the ConstraintSum, just return the function
1355
1356 RooAbsArg* _func = func().get();
1357 if(!_func->InheritsFrom("RooAddition")) {
1358 _func = nullptr;
1359 // happens with new 6.32 backend, where the top-level function is an EvaluatorWrapper
1360 for (auto s : func()->servers()) {
1361 if(s->InheritsFrom("RooAddition")) {
1362 _func = s; break;
1363 }
1364 }
1365 if(!_func) {
1366 return func().get();
1367 }
1368 }
1369 std::set<RooAbsArg*> others,constraints;
1370 for (auto s : _func->servers()) {
1371 if(s->InheritsFrom("RooConstraintSum")) {
1372 constraints.insert(s);
1373 } else {
1374 others.insert(s);
1375 }
1376 }
1377 if(constraints.size()==1 && others.size()==1) {
1378 return static_cast<RooAbsReal*>(*others.begin());
1379 }
1380 return nullptr; // failed to find the right term?
1381
1382
1383}
1384 */
1385
1387{
1388 // returns Nexp - Nobs*log(Nexp)
1389 return fPdf->extendedTerm(fData->sumEntries(), fData->get());
1390}
1391
1393{
1394 // comes from the _simCount code inside RooNLLVar
1395 // is this actually only appropriate if the roosimultaneous is not extended?
1396 // i.e. then this term represents the probability the entry belongs to a given state, and given
1397 // all the states are normalized to 1, this probability is assumed to just be 1/N_states
1398 if (auto s = dynamic_cast<RooSimultaneous *>(fPdf.get()); s) {
1399 return fData->sumEntries() * log(1.0 * (s->servers().size() - 1)); // one of the servers is the cat
1400 }
1401 return 0;
1402}
1403
1405{
1406 // this is only relevant if BinnedLikelihood active
1407 // = sum[ N_i! ] since LnGamma(N_i+1) ~= N_i!
1408 // need to also subtract off sum[ N_i*log(width_i) ] in order to have formula: binnedLL = unbinnedLL + binnedDataTerm
1409 // note this is 0 if all the bin widths are 1
1410 double out = 0;
1411 for (int i = 0; i < fData->numEntries(); i++) {
1412 fData->get(i);
1413 out += TMath::LnGamma(fData->weight() + 1) - fData->weight() * std::log(getEntryBinWidth(i));
1414 }
1415
1416 return out;
1417}
1418
1420{
1421 auto _func = func();
1422 if (auto a = dynamic_cast<RooConstraintSum *>(_func.get()); a)
1423 return a;
1424 for (auto s : _func->servers()) {
1425 if (auto a = dynamic_cast<RooConstraintSum *>(s); a)
1426 return a;
1427 // allow one more depth to support 6.32 (where sum is hidden inside the first server)
1428 for (auto s2 : s->servers()) {
1429 if (auto a2 = dynamic_cast<RooConstraintSum *>(s2); a2)
1430 return a2;
1431 }
1432 }
1433 return nullptr;
1434}
1435
1436/*xRooNLLVar::operator RooAbsReal &() const {
1437 // this works in c++ but not in python
1438 std::cout << "implicit conversion" << std::endl;
1439 return *fFunc;
1440}*/
1441
1443{
1444 TString sWhat(what);
1445 sWhat.ToLower();
1446 sWhat.ReplaceAll(" =", "=").ReplaceAll("= ", "="); // remove spaces around equals signs
1447 bool doTS = sWhat.Contains("ts");
1448 bool doCLs = sWhat.Contains("pcls");
1449 bool doNull = sWhat.Contains("pnull");
1450 bool doAlt = sWhat.Contains("palt");
1451 double nSigma = (sWhat.Contains("exp"))
1452 ? (TString(sWhat(sWhat.Index("exp") + 3, sWhat.Index(" ", sWhat.Index("exp")) == -1
1453 ? sWhat.Length()
1454 : sWhat.Index(" ", sWhat.Index("exp"))))
1455 .Atof())
1456 : std::numeric_limits<double>::quiet_NaN();
1457
1458 bool toys = sWhat.Contains("toys");
1459
1460 // bool asymp = sWhat.Contains("asymp");
1461
1462 bool readOnly = sWhat.Contains("readonly");
1463
1464 if (toys && !readOnly) {
1465 sigma_mu(); // means we will be able to evaluate the asymptotic values too
1466 // only add toys if actually required
1467
1468 size_t nToys = 0;
1469 size_t nToysAlt = 0;
1470 bool autoToys = !sWhat.Contains("toys=");
1471 if(!autoToys) {
1472 // extract number of toys required ... format is "nullToys.altToysFraction" if altToysFraction=0 then use
1473 // same for both, unless explicitly set (i.e. N.0) then means we want no alt toys
1474 // e.g. if doing just pnull significance
1475 TString toyNum = sWhat(sWhat.Index("toys=") + 5, sWhat.Length());
1476 nToys = toyNum.Atoi();
1477 nToysAlt = (toyNum.Atof() - nToys) * nToys;
1478 if (nToysAlt == 0 && !toyNum.Contains('.') && !doNull)
1479 nToysAlt = nToys;
1480 if (nullToys.size() < nToys) {
1481 addNullToys(nToys - nullToys.size());
1482 }
1483 if (altToys.size() < nToysAlt) {
1484 addAltToys(nToysAlt - altToys.size());
1485 }
1486 } else {
1487 // auto toys
1488 if(doCLs) {
1489 auto obs = getVal(sWhat + " readonly");
1490 double target=0.05; double relErrThreshold = 2;
1491 double diff = (target < 0) ? obs.first : std::abs(obs.first - target);
1492 double err = obs.second;
1493 size_t maxToys = gEnv->GetValue("XRooFit.MaxToys",10000);
1494 size_t nAltToys = 100;
1495 // target mode is only used in auto toy generation
1496 if((nullToys.size() < maxToys || altToys.size()<nAltToys) && (std::isnan(err) || (err > 1e-4 && diff <= relErrThreshold * err))) {
1497 // auto toy-generating for limits .. do in blocks of 100
1498 addCLsToys(nAltToys, 0/*seed*/, 0.05, nSigma);
1499 }
1500 } else {
1501 throw std::runtime_error("Auto-generating toys for anything other than CLs not yet supported, please "
1502 "specify number of toys with 'toys=N' ");
1503 }
1504 }
1505
1506 }
1507
1508 struct RestoreNll {
1509 RestoreNll(std::shared_ptr<xRooNLLVar> &v, bool r) : rr(r), var(v)
1510 {
1511 if (rr && var && var->get()) {
1512 _readOnly = var->get()->getAttribute("readOnly");
1513 var->get()->setAttribute("readOnly", rr);
1514 } else {
1515 rr = false;
1516 }
1517 };
1518 ~RestoreNll()
1519 {
1520 if (rr)
1521 var->get()->setAttribute("readOnly", _readOnly);
1522 };
1523
1524 bool rr = false;
1525 bool _readOnly = false;
1526
1527 std::shared_ptr<xRooNLLVar> &var;
1528 };
1529
1530 RestoreNll rest(nllVar, readOnly);
1531
1532 if (doTS)
1533 return (toys) ? ts_toys(nSigma) : ts_asymp(nSigma);
1534 if (doNull)
1535 return (toys) ? pNull_toys(nSigma) : pNull_asymp(nSigma);
1536 if (doAlt)
1537 return (toys) ? pAlt_toys(nSigma) : pAlt_asymp(nSigma);
1538 if (doCLs)
1539 return (toys) ? pCLs_toys(nSigma) : pCLs_asymp(nSigma);
1540
1541 throw std::runtime_error(std::string("Unknown: ") + what);
1542}
1543
1545{
1546 RooArgList out;
1547 out.setName("poi");
1548 out.add(*std::unique_ptr<RooAbsCollection>(coords->selectByAttrib("poi", true)));
1549 return out;
1550}
1551
1553{
1554 RooArgList out;
1555 out.setName("alt_poi");
1556 out.addClone(*std::unique_ptr<RooAbsCollection>(coords->selectByAttrib("poi", true)));
1557 for (auto a : out) {
1558 auto v = dynamic_cast<RooAbsRealLValue *>(a);
1559 if (!v)
1560 continue;
1561 if (auto s = a->getStringAttribute("altVal"); s && strlen(s)) {
1562 v->setVal(TString(s).Atof());
1563 } else {
1564 v->setVal(std::numeric_limits<double>::quiet_NaN());
1565 }
1566 }
1567 return out;
1568}
1569
1571{
1572 auto &me = const_cast<xRooHypoPoint &>(*this);
1573 int out = 0;
1574 if (me.ufit(true) && !allowedStatusCodes.count(me.ufit(true)->status()))
1575 out += 1;
1576 if (me.cfit_null(true) && !allowedStatusCodes.count(me.cfit_null(true)->status()))
1577 out += 1 << 1;
1578 if (me.cfit_alt(true) && !allowedStatusCodes.count(me.cfit_alt(true)->status()))
1579 out += 1 << 2;
1580 if (me.asimov(true))
1581 out += me.asimov(true)->status() << 3;
1582 return out;
1583}
1584
1586{
1587 auto _poi = const_cast<xRooHypoPoint *>(this)->poi();
1588 auto _alt_poi = const_cast<xRooHypoPoint *>(this)->alt_poi();
1589 std::cout << "POI: " << _poi.contentsString() << " , null: ";
1590 bool first = true;
1591 for (auto a : _poi) {
1592 auto v = dynamic_cast<RooAbsReal *>(a);
1593 if (!a)
1594 continue;
1595 if (!first)
1596 std::cout << ",";
1597 std::cout << v->getVal();
1598 first = false;
1599 }
1600 std::cout << " , alt: ";
1601 first = true;
1602 bool any_alt = false;
1603 for (auto a : _alt_poi) {
1604 auto v = dynamic_cast<RooAbsReal *>(a);
1605 if (!a)
1606 continue;
1607 if (!first)
1608 std::cout << ",";
1609 std::cout << v->getVal();
1610 first = false;
1611 if (!std::isnan(v->getVal()))
1612 any_alt = true;
1613 }
1614 std::cout << " , pllType: ";
1615 switch (fPllType) {
1616 case 0: std::cout << "tmu"; break;
1617 case 1: std::cout << "qmu or qmutilde"; break; // should check for 'physical' to decide if is latter
1618 case 2: std::cout << "q0"; break;
1619 case 4: std::cout << "u0"; break;
1620 default: std::cout << "unknown"; break;
1621 }
1622 std::cout << std::endl;
1623
1624 if (fPllType == xRooFit::Asymptotics::Unknown) {
1625 std::cout << " obs ts: " << obs_ts << " +/- " << obs_ts_err << std::endl;
1626 }
1627
1628 std::cout << " - ufit: ";
1629 if (fUfit) {
1630 std::cout << fUfit->GetName() << " " << fUfit->minNll() << " (status=" << fUfit->status() << ") (";
1631 first = true;
1632 for (auto a : _poi) {
1633 auto v = dynamic_cast<RooRealVar *>(fUfit->floatParsFinal().find(a->GetName()));
1634 if (!v)
1635 continue;
1636 if (!first)
1637 std::cout << ",";
1638 std::cout << v->GetName() << "_hat: " << v->getVal() << " +/- " << v->getError();
1639 first = false;
1640 }
1641 std::cout << ")" << std::endl;
1642 } else {
1643 std::cout << "Not calculated" << std::endl;
1644 }
1645 std::cout << " - cfit_null: ";
1646 if (fNull_cfit) {
1647 std::cout << fNull_cfit->GetName() << " " << fNull_cfit->minNll() << " (status=" << fNull_cfit->status() << ")";
1648 } else {
1649 std::cout << "Not calculated";
1650 }
1651 if (any_alt) {
1652 std::cout << std::endl << " - cfit_alt: ";
1653 if (fAlt_cfit) {
1654 std::cout << fAlt_cfit->GetName() << " " << fAlt_cfit->minNll() << " (status=" << fAlt_cfit->status() << ")"
1655 << std::endl;
1656 } else {
1657 std::cout << "Not calculated" << std::endl;
1658 }
1659 std::cout << " sigma_mu: ";
1660 const_cast<xRooHypoPoint *>(this)->asimov(true); // will trigger construction of fAsimov hypoPoint if possible
1661 if (!fAsimov || !fAsimov->fUfit || !fAsimov->fNull_cfit) {
1662 std::cout << "Not calculated";
1663 } else {
1664 std::cout << const_cast<xRooHypoPoint *>(this)->sigma_mu().first << " +/- "
1665 << const_cast<xRooHypoPoint *>(this)->sigma_mu().second;
1666 }
1667 if (fAsimov) {
1668 std::cout << std::endl;
1669 std::cout << " - asimov ufit: ";
1670 if (fAsimov->fUfit) {
1671 std::cout << fAsimov->fUfit->GetName() << " " << fAsimov->fUfit->minNll()
1672 << " (status=" << fAsimov->fUfit->status() << ")";
1673 } else {
1674 std::cout << "Not calculated";
1675 }
1676 std::cout << std::endl << " - asimov cfit_null: ";
1677 if (fAsimov->fNull_cfit) {
1678 std::cout << fAsimov->fNull_cfit->GetName() << " " << fAsimov->fNull_cfit->minNll()
1679 << " (status=" << fAsimov->fNull_cfit->status() << ")";
1680 } else {
1681 std::cout << "Not calculated";
1682 }
1683 }
1684 std::cout << std::endl;
1685 } else {
1686 std::cout << std::endl;
1687 }
1688 if (fLbound_cfit) {
1689 std::cout << " - cfit_lbound: " << fLbound_cfit->GetName() << " " << fLbound_cfit->minNll()
1690 << " (status=" << fLbound_cfit->status() << ")" << std::endl;
1691 }
1692 if (fGenFit)
1693 std::cout << " - gfit: " << fGenFit->GetName() << std::endl;
1694 if (!nullToys.empty() || !altToys.empty()) {
1695 std::cout << " * null toys: " << nullToys.size();
1696 size_t firstToy = 0;
1697 while (firstToy < nullToys.size() && std::isnan(std::get<1>(nullToys[firstToy])))
1698 firstToy++;
1699 if (firstToy > 0)
1700 std::cout << " [ of which " << firstToy << " are bad]";
1701 std::cout << " , alt toys: " << altToys.size();
1702 firstToy = 0;
1703 while (firstToy < altToys.size() && std::isnan(std::get<1>(altToys[firstToy])))
1704 firstToy++;
1705 if (firstToy > 0)
1706 std::cout << " [ of which " << firstToy << " are bad]";
1707 std::cout << std::endl;
1708 }
1709 // std::cout << " nllVar: " << nllVar << std::endl;
1710}
1711
1713{
1714 if (ufit()) {
1715 auto var = dynamic_cast<RooRealVar *>(ufit()->floatParsFinal().find(fPOIName()));
1716 if (var) {
1717 return *var;
1718 } else {
1719 throw std::runtime_error(TString::Format("Cannot find POI: %s", fPOIName()));
1720 }
1721 }
1722 throw std::runtime_error("Unconditional fit unavailable");
1723}
1724
1725std::pair<std::shared_ptr<RooAbsData>, std::shared_ptr<const RooAbsCollection>> xRooNLLVar::xRooHypoPoint::data()
1726{
1727 if (fData.first)
1728 return fData;
1729 if (fGenFit && isExpected) {
1730 // std::cout << "Generating asimov" << std::endl;poi().Print("v");
1731 fData = xRooFit::generateFrom(*nllVar->fPdf, *fGenFit, true);
1732 }
1733 return fData;
1734}
1735
1736xRooNLLVar::xRooHypoPoint::xRooHypoPoint(std::shared_ptr<RooStats::HypoTestResult> htr, const RooAbsCollection *_coords)
1737 : hypoTestResult(htr)
1738{
1739 if (hypoTestResult) {
1740 // load the pllType
1741 fPllType =
1742 xRooFit::Asymptotics::PLLType(hypoTestResult->GetFitInfo()->getGlobalObservables()->getCatIndex("pllType"));
1743 isExpected = hypoTestResult->GetFitInfo()->getGlobalObservables()->getRealValue("isExpected");
1744
1745 // load obsTS value
1746 obs_ts = hypoTestResult->GetTestStatisticData();
1747 obs_ts_err = hypoTestResult->GetFitInfo()->getGlobalObservables()->getRealValue("obs_ts_err");
1748
1749 // load the toys
1750 auto toys = hypoTestResult->GetNullDetailedOutput();
1751 if (toys) {
1752 // load coords from the nullDist globs list
1753 if (toys->getGlobalObservables()) {
1754 coords = std::shared_ptr<RooAbsCollection>(toys->getGlobalObservables()->snapshot());
1755 }
1756 for (int i = 0; i < toys->numEntries(); i++) {
1757 auto toy = toys->get(i);
1758 nullToys.emplace_back(
1759 std::make_tuple(int(toy->getRealValue("seed")), toy->getRealValue("ts"), toys->weight()));
1760 }
1761 }
1762 toys = hypoTestResult->GetAltDetailedOutput();
1763 if (toys) {
1764 for (int i = 0; i < toys->numEntries(); i++) {
1765 auto toy = toys->get(i);
1766 altToys.emplace_back(
1767 std::make_tuple(int(toy->getRealValue("seed")), toy->getRealValue("ts"), toys->weight()));
1768 }
1769 }
1770 }
1771 if (!coords && _coords)
1772 coords.reset(_coords->snapshot());
1773}
1774
1775std::shared_ptr<xRooNLLVar::xRooHypoPoint> xRooNLLVar::xRooHypoPoint::asimov(bool readOnly)
1776{
1777
1778 if (!fAsimov && (nllVar || hypoTestResult)) {
1779 auto theFit = (!fData.first && fGenFit && !isExpected)
1780 ? fGenFit
1781 : cfit_alt(readOnly); // first condition allows genFit to be used as the altFit *if* the data is
1782 // entirely absent, provided not expected data because we postpone data
1783 // creation til later in that case (see below)
1784 if (!theFit || allowedStatusCodes.find(theFit->status()) == allowedStatusCodes.end())
1785 return fAsimov;
1786 fAsimov = std::make_shared<xRooHypoPoint>(*this);
1787 fAsimov->coords.reset(fAsimov->coords->snapshot()); // create a copy so can remove the physical range below
1788 fAsimov->hypoTestResult.reset();
1789 fAsimov->fPllType = xRooFit::Asymptotics::TwoSided;
1790 for (auto p : fAsimov->poi()) {
1791 // dynamic_cast<RooRealVar *>(p)->removeRange("physical"); -- can't use this as will modify shared property
1792 if (auto v = dynamic_cast<RooRealVar *>(p)) {
1793 v->deleteSharedProperties(); // effectively removes all custom ranges
1794 if (v->getVal() == 0) {
1795 // for discovery tests, we generate asimov at mu!=0 and then evaluate the two sided
1796 // at some value of mu. Normally we would use mu=0 but if we have a bin
1797 // with only signal contribution (no bkg) will get asimov data in that bin
1798 // and no prediction ... the cfit(mu=0) will never succeed on this
1799 // so lets move to 0.1% the alt value instead (the value used to generate)
1800 v->setVal(theFit->constPars().getRealValue(v->GetName()) * gEnv->GetValue("XRooFit.AsimovNullValFactor",1e-3));
1801 }
1802 }
1803 }
1804
1805 fAsimov->nullToys.clear();
1806 fAsimov->altToys.clear();
1807 fAsimov->fUfit = retrieveFit(3);
1808 fAsimov->fNull_cfit = retrieveFit(4);
1809 fAsimov->fAlt_cfit.reset();
1810 fAsimov->fData =
1811 std::make_pair(nullptr, nullptr); // postpone generating expected data until we definitely need it
1812 fAsimov->fGenFit = theFit;
1813 fAsimov->isExpected = true;
1814 }
1815
1816 return fAsimov;
1817}
1818
1820{
1821 if (fPllType != xRooFit::Asymptotics::Uncapped && ts_asymp(nSigma).first == 0)
1822 return std::pair<double, double>(1, 0);
1823 auto first_poi = dynamic_cast<RooRealVar *>(poi().first());
1824 if (!first_poi)
1825 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1826 double lowBound = first_poi->getMin("physical");
1827 double hiBound = first_poi->getMax("physical");
1828 // don't need to calculate sigma_mu if physical boundaries at infinity, PValue doesn't depend on it
1829 auto _sigma_mu =
1830 (lowBound == -std::numeric_limits<double>::infinity() && hiBound == std::numeric_limits<double>::infinity())
1831 ? std::pair<double, double>(0, 0)
1832 : sigma_mu();
1833 double nom = xRooFit::Asymptotics::PValue(fPllType, ts_asymp(nSigma).first, fNullVal(), fNullVal(), _sigma_mu.first,
1834 lowBound, hiBound);
1835 double up = xRooFit::Asymptotics::PValue(fPllType, ts_asymp(nSigma).first + ts_asymp(nSigma).second, fNullVal(),
1836 fNullVal(), _sigma_mu.first, lowBound, hiBound);
1837 double down = xRooFit::Asymptotics::PValue(fPllType, ts_asymp(nSigma).first - ts_asymp(nSigma).second, fNullVal(),
1838 fNullVal(), _sigma_mu.first, lowBound, hiBound);
1839 return std::pair(nom, std::max(std::abs(up - nom), std::abs(down - nom)));
1840}
1841
1843{
1844 if (fPllType != xRooFit::Asymptotics::Uncapped && ts_asymp(nSigma).first == 0)
1845 return std::pair<double, double>(1, 0);
1846 auto first_poi = dynamic_cast<RooRealVar *>(poi().first());
1847 if (!first_poi)
1848 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1849 auto _sigma_mu = sigma_mu();
1850 double nom = xRooFit::Asymptotics::PValue(fPllType, ts_asymp(nSigma).first, fNullVal(), fAltVal(), _sigma_mu.first,
1851 first_poi->getMin("physical"), first_poi->getMax("physical"));
1852 double up =
1853 xRooFit::Asymptotics::PValue(fPllType, ts_asymp(nSigma).first + ts_asymp(nSigma).second, fNullVal(), fAltVal(),
1854 _sigma_mu.first, first_poi->getMin("physical"), first_poi->getMax("physical"));
1855 double down =
1856 xRooFit::Asymptotics::PValue(fPllType, ts_asymp(nSigma).first - ts_asymp(nSigma).second, fNullVal(), fAltVal(),
1857 _sigma_mu.first, first_poi->getMin("physical"), first_poi->getMax("physical"));
1858
1859 return std::pair(nom, std::max(std::abs(up - nom), std::abs(down - nom)));
1860}
1861
1863{
1864 if (fNullVal() == fAltVal())
1865 return std::pair<double, double>(1, 0); // by construction
1866
1867 if (fPllType != xRooFit::Asymptotics::Uncapped && ts_asymp(nSigma).first == 0)
1868 return std::pair<double, double>(1, 0);
1869 auto first_poi = dynamic_cast<RooRealVar *>(poi().first());
1870 if (!first_poi)
1871 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1872
1873 auto _ts_asymp = ts_asymp(nSigma);
1874 auto _sigma_mu = sigma_mu();
1875 double nom1 = xRooFit::Asymptotics::PValue(fPllType, _ts_asymp.first, fNullVal(), fNullVal(), _sigma_mu.first,
1876 first_poi->getMin("physical"), first_poi->getMax("physical"));
1877 double up1 =
1878 xRooFit::Asymptotics::PValue(fPllType, _ts_asymp.first + _ts_asymp.second, fNullVal(), fNullVal(),
1879 _sigma_mu.first, first_poi->getMin("physical"), first_poi->getMax("physical"));
1880 double down1 =
1881 xRooFit::Asymptotics::PValue(fPllType, _ts_asymp.first - _ts_asymp.second, fNullVal(), fNullVal(),
1882 _sigma_mu.first, first_poi->getMin("physical"), first_poi->getMax("physical"));
1883 double nom2 = xRooFit::Asymptotics::PValue(fPllType, _ts_asymp.first, fNullVal(), fAltVal(), _sigma_mu.first,
1884 first_poi->getMin("physical"), first_poi->getMax("physical"));
1885 double up2 =
1886 xRooFit::Asymptotics::PValue(fPllType, _ts_asymp.first + _ts_asymp.second, fNullVal(), fAltVal(), _sigma_mu.first,
1887 first_poi->getMin("physical"), first_poi->getMax("physical"));
1888 double down2 =
1889 xRooFit::Asymptotics::PValue(fPllType, _ts_asymp.first - _ts_asymp.second, fNullVal(), fAltVal(), _sigma_mu.first,
1890 first_poi->getMin("physical"), first_poi->getMax("physical"));
1891
1892 auto nom = (nom1 == 0) ? 0 : nom1 / nom2;
1893 auto up = (up1 == 0) ? 0 : up1 / up2;
1894 auto down = (down1 == 0) ? 0 : down1 / down2;
1895
1896 return std::pair(nom, std::max(std::abs(up - nom), std::abs(down - nom)));
1897}
1898
1900{
1901 if (std::isnan(nSigma)) {
1902 return (fPllType == xRooFit::Asymptotics::Unknown) ? std::make_pair(obs_ts, obs_ts_err) : pll();
1903 }
1904
1905 auto first_poi = dynamic_cast<RooRealVar *>(poi().first());
1906 auto _sigma_mu = sigma_mu();
1907 if (!first_poi || (!std::isnan(nSigma) && std::isnan(_sigma_mu.first)))
1908 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1909 double nom = xRooFit::Asymptotics::k(fPllType, ROOT::Math::gaussian_cdf(nSigma), fNullVal(), fAltVal(),
1910 _sigma_mu.first, first_poi->getMin("physical"), first_poi->getMax("physical"));
1911 double up = xRooFit::Asymptotics::k(fPllType, ROOT::Math::gaussian_cdf(nSigma), fNullVal(), fAltVal(),
1912 _sigma_mu.first + _sigma_mu.second, first_poi->getMin("physical"),
1913 first_poi->getMax("physical"));
1914 double down = xRooFit::Asymptotics::k(fPllType, ROOT::Math::gaussian_cdf(nSigma), fNullVal(), fAltVal(),
1915 _sigma_mu.first - _sigma_mu.second, first_poi->getMin("physical"),
1916 first_poi->getMax("physical"));
1917 return std::pair<double, double>(nom, std::max(std::abs(nom - up), std::abs(nom - down)));
1918}
1919
1921{
1922 if (std::isnan(nSigma)) {
1923 return ts_asymp();
1924 }
1925 // nans should appear in the alt toys first ... so loop until past nans
1926 size_t firstToy = 0;
1927 while (firstToy < altToys.size() && std::isnan(std::get<1>(altToys[firstToy])))
1928 firstToy++;
1929 if (firstToy >= altToys.size())
1930 return std::pair(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN());
1931 int targetIdx =
1932 (altToys.size() - firstToy) * ROOT::Math::gaussian_cdf_c(nSigma) + firstToy; // TODO: Account for weights
1933 return std::pair(std::get<1>(altToys[targetIdx]), (std::get<1>(altToys[std::min(int(altToys.size()), targetIdx)]) -
1934 std::get<1>(altToys[std::max(0, targetIdx)])) /
1935 2.);
1936}
1937
1939{
1940 auto _ufit = ufit(readOnly);
1941 if (!_ufit) {
1942 if (hypoTestResult)
1943 return std::pair<double, double>(hypoTestResult->GetTestStatisticData(), 0);
1944 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1945 }
1946 if (allowedStatusCodes.find(_ufit->status()) == allowedStatusCodes.end()) {
1947 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1948 }
1949 if (auto _first_poi = dynamic_cast<RooRealVar *>(poi().first());
1950 _first_poi && _first_poi->getMin("physical") > _first_poi->getMin() &&
1951 mu_hat().getVal() < _first_poi->getMin("physical")) {
1952 // replace _ufit with fit "boundary" conditional fit
1953 _ufit = cfit_lbound(readOnly);
1954 if (!_ufit) {
1955 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1956 }
1957 }
1958 auto cFactor = (fPllType == xRooFit::Asymptotics::TwoSided)
1959 ? 1.
1960 : xRooFit::Asymptotics::CompatFactor(fPllType, fNullVal(), mu_hat().getVal());
1961 if (cFactor == 0)
1962 return std::pair<double, double>(0, 0);
1963 auto _cfit_null = cfit_null(readOnly);
1964 if (!_cfit_null || allowedStatusCodes.find(_cfit_null->status()) == allowedStatusCodes.end())
1965 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
1966 // std::cout << cfit->minNll() << ":" << cfit->edm() << " " << ufit->minNll() << ":" << ufit->edm() << std::endl;
1967 double diff = _cfit_null->minNll() - _ufit->minNll();
1968 if (diff < 0) {
1969 // use edm to attempt a small correction to the diff, i.e. assume edm is an additional correction required to
1970 // minNll
1971 diff += (_ufit->edm() - _cfit_null->edm());
1972 }
1973 return std::pair<double, double>(2. * cFactor * diff,
1974 2. * cFactor * sqrt(pow(cfit_null(readOnly)->edm(), 2) + pow(_ufit->edm(), 2)));
1975 // return 2.*cFactor*(cfit->minNll()+cfit->edm() - ufit->minNll()+ufit->edm());
1976}
1977
1978std::shared_ptr<const RooFitResult> xRooNLLVar::xRooHypoPoint::retrieveFit(int type)
1979{
1980 if (!hypoTestResult)
1981 return nullptr;
1982 // see if can retrieve from that ....
1983 if (auto fits = hypoTestResult->GetFitInfo()) {
1984 for (int i = 0; i < fits->numEntries(); i++) {
1985 auto fit = fits->get(i);
1986 if (fit->getCatIndex("type") != type)
1987 continue;
1988 // found ufit ... construct
1989 std::string _name =
1990 fits->getGlobalObservables()->getStringValue(TString::Format("%s.name", fit->getCatLabel("type")));
1991 // see if can retrieve from any open file ....
1992 TDirectory *tmp = gDirectory;
1993 for (auto file : *gROOT->GetListOfFiles()) {
1994 if (auto k = static_cast<TDirectory *>(file)->FindKeyAny(_name.c_str())) {
1995 // use pre-retrieved fits if available
1996 xRooFit::StoredFitResult *storedFr =
1997 k->GetMotherDir()->GetList()
1998 ? dynamic_cast<xRooFit::StoredFitResult *>(k->GetMotherDir()->GetList()->FindObject(k->GetName()))
1999 : nullptr;
2000 if (auto cachedFit = (storedFr) ? storedFr->fr.get() : k->ReadObject<RooFitResult>(); cachedFit) {
2001 if (!storedFr) {
2002 storedFr = new xRooFit::StoredFitResult(cachedFit);
2003 k->GetMotherDir()->Add(storedFr);
2004 }
2005 gDirectory = tmp; // one of the above calls moves to key's directory ... i didn't check which
2006 return storedFr->fr;
2007 }
2008 }
2009 }
2010 auto rfit = std::make_shared<RooFitResult>(_name.c_str(), TUUID(_name.c_str()).GetTime().AsString());
2011 rfit->setStatus(fit->getRealValue("status"));
2012 rfit->setMinNLL(fit->getRealValue("minNll"));
2013 rfit->setEDM(fit->getRealValue("edm"));
2014 if (type == 0) {
2015 std::unique_ptr<RooAbsCollection> par_hats(
2016 hypoTestResult->GetFitInfo()->getGlobalObservables()->selectByName(coords->contentsString().c_str()));
2017 par_hats->setName("floatParsFinal");
2018 rfit->setFinalParList(*par_hats);
2019 } else {
2020 rfit->setFinalParList(RooArgList());
2021 }
2022 rfit->setConstParList(RooArgList());
2023 rfit->setInitParList(RooArgList());
2024 TMatrixDSym cov(0);
2025 rfit->setCovarianceMatrix(cov);
2026 rfit->setCovQual(fit->getRealValue("covQual"));
2027 return rfit;
2028 }
2029 }
2030 return nullptr;
2031}
2032
2033std::shared_ptr<const RooFitResult> xRooNLLVar::xRooHypoPoint::ufit(bool readOnly)
2034{
2035 if (fUfit)
2036 return fUfit;
2037 if (auto rfit = retrieveFit(0)) {
2038 return fUfit = rfit;
2039 }
2040 if (!nllVar || (readOnly && nllVar->get() && !nllVar->get()->getAttribute("readOnly")))
2041 return nullptr;
2042 if (!nllVar->fFuncVars)
2043 nllVar->reinitialize();
2044 AutoRestorer snap(*nllVar->fFuncVars, nllVar.get());
2045 if (!fData.first) {
2046 if (!readOnly && isExpected && fGenFit) {
2047 // can try to do a readOnly in case can load from cache
2048 bool tmp = nllVar->get()->getAttribute("readOnly");
2049 nllVar->get()->setAttribute("readOnly");
2050 auto out = ufit(true);
2051 nllVar->get()->setAttribute("readOnly", tmp);
2052 if (out) {
2053 // retrieve from cache worked, no need to generate dataset
2054 return out;
2055 } else if (!tmp) { // don't need to setData if doing a readOnly fit
2056 nllVar->setData(data());
2057 }
2058 }
2059 } else if (!nllVar->get()->getAttribute("readOnly")) { // don't need to setData if doing a readOnly fit
2060 nllVar->setData(fData);
2061 }
2062 nllVar->fFuncVars->setAttribAll("Constant", false);
2063 *nllVar->fFuncVars = *coords; // will reconst the coords
2064 if (nllVar->fFuncGlobs)
2065 nllVar->fFuncGlobs->setAttribAll("Constant", true);
2066 std::unique_ptr<RooAbsCollection>(nllVar->fFuncVars->selectCommon(poi()))
2067 ->setAttribAll("Constant", false); // float the poi
2068 if (fGenFit) {
2069 // make initial guess same as pars we generated with
2070 nllVar->fFuncVars->assignValueOnly(fGenFit->constPars());
2071 nllVar->fFuncVars->assignValueOnly(fGenFit->floatParsFinal());
2072 // rename nll so if caching fit results will cache into subdir
2073 nllVar->get()->SetName(
2074 TString::Format("%s/%s_%s", nllVar->get()->GetName(), fGenFit->GetName(), (isExpected) ? "asimov" : "toys"));
2075 if (!isExpected)
2076 nllVar->get()->SetName(TString::Format("%s/%s", nllVar->get()->GetName(), fData.first->GetName()));
2077
2078 } else if (!std::isnan(fAltVal())) {
2079 // guess data given is expected to align with alt value, unless initVal attribute specified
2080 for (auto _poiCoord : poi()) {
2081 auto _poi = dynamic_cast<RooRealVar *>(nllVar->fFuncVars->find(_poiCoord->GetName()));
2082 if (_poi) {
2083 _poi->setVal(_poi->getStringAttribute("initVal") ? TString(_poi->getStringAttribute("initVal")).Atof()
2084 : fAltVal());
2085 }
2086 }
2087 }
2088 return (fUfit = nllVar->minimize());
2089}
2090
2091std::string collectionContents(const RooAbsCollection &coll)
2092{
2093 std::string out;
2094 for (auto &c : coll) {
2095 if (!out.empty())
2096 out += ",";
2097 out += c->GetName();
2098 if (auto v = dynamic_cast<RooAbsReal *>(c); v) {
2099 out += TString::Format("=%g", v->getVal());
2100 } else if (auto cc = dynamic_cast<RooAbsCategory *>(c); cc) {
2101 out += TString::Format("=%s", cc->getLabel());
2102 } else if (auto s = dynamic_cast<RooStringVar *>(c); v) {
2103 out += TString::Format("=%s", s->getVal());
2104 }
2105 }
2106 return out;
2107}
2108
2109std::shared_ptr<const RooFitResult> xRooNLLVar::xRooHypoPoint::cfit_null(bool readOnly)
2110{
2111 if (fNull_cfit)
2112 return fNull_cfit;
2113 if (auto rfit = retrieveFit(1)) {
2114 return fNull_cfit = rfit;
2115 }
2116 if (!nllVar || (readOnly && nllVar->get() && !nllVar->get()->getAttribute("readOnly")))
2117 return nullptr;
2118 if (!nllVar->fFuncVars)
2119 nllVar->reinitialize();
2120 AutoRestorer snap(*nllVar->fFuncVars, nllVar.get());
2121 if (!fData.first) {
2122 if (!readOnly && isExpected && fGenFit) {
2123 // can try to do a readOnly in case can load from cache
2124 bool tmp = nllVar->get()->getAttribute("readOnly");
2125 nllVar->get()->setAttribute("readOnly");
2126 auto out = cfit_null(true);
2127 nllVar->get()->setAttribute("readOnly", tmp);
2128 if (out) {
2129 // retrieve from cache worked, no need to generate dataset
2130 return out;
2131 } else if (!tmp) { // don't need to setData if doing a readOnly fit
2132 nllVar->setData(data());
2133 }
2134 }
2135 } else if (!nllVar->get()->getAttribute("readOnly")) { // don't need to setData if doing a readOnly fit
2136 nllVar->setData(fData);
2137 }
2138 if (fUfit) {
2139 // move to ufit coords before evaluating
2140 *nllVar->fFuncVars = fUfit->floatParsFinal();
2141 }
2142 nllVar->fFuncVars->setAttribAll("Constant", false);
2143 *nllVar->fFuncVars = *coords; // will reconst the coords
2144 if (nllVar->fFuncGlobs)
2145 nllVar->fFuncGlobs->setAttribAll("Constant", true);
2146 if (fPOIName()) {
2147 nllVar->fFuncVars->find(fPOIName())
2148 ->setStringAttribute("altVal", (!std::isnan(fAltVal())) ? TString::Format("%g", fAltVal()) : nullptr);
2149 }
2150 if (fGenFit) {
2151 nllVar->get()->SetName(
2152 TString::Format("%s/%s_%s", nllVar->get()->GetName(), fGenFit->GetName(), (isExpected) ? "asimov" : "toys"));
2153 if (!isExpected)
2154 nllVar->get()->SetName(TString::Format("%s/%s", nllVar->get()->GetName(), fData.first->GetName()));
2155 }
2156 nllVar->get()->setStringAttribute("fitresultTitle", collectionContents(poi()).c_str());
2157 return (fNull_cfit = nllVar->minimize());
2158}
2159
2160std::shared_ptr<const RooFitResult> xRooNLLVar::xRooHypoPoint::cfit_lbound(bool readOnly)
2161{
2162 auto _first_poi = dynamic_cast<RooRealVar *>(poi().first());
2163 if (!_first_poi)
2164 return nullptr;
2165 if (_first_poi->getMin("physical") <= _first_poi->getMin())
2166 return nullptr;
2167 if (fLbound_cfit)
2168 return fLbound_cfit;
2169 if (auto rfit = retrieveFit(6)) {
2170 return fLbound_cfit = rfit;
2171 }
2172 if (!nllVar || (readOnly && nllVar->get() && !nllVar->get()->getAttribute("readOnly")))
2173 return nullptr;
2174 if (!nllVar->fFuncVars)
2175 nllVar->reinitialize();
2176 AutoRestorer snap(*nllVar->fFuncVars, nllVar.get());
2177 if (!fData.first) {
2178 if (!readOnly && isExpected && fGenFit) {
2179 // can try to do a readOnly in case can load from cache
2180 bool tmp = nllVar->get()->getAttribute("readOnly");
2181 nllVar->get()->setAttribute("readOnly");
2182 auto out = cfit_lbound(true);
2183 nllVar->get()->setAttribute("readOnly", tmp);
2184 if (out) {
2185 // retrieve from cache worked, no need to generate dataset
2186 return out;
2187 } else if (!tmp) { // don't need to setData if doing a readOnly fit
2188 nllVar->setData(data());
2189 }
2190 }
2191 } else if (!nllVar->get()->getAttribute("readOnly")) { // don't need to setData if doing a readOnly fit
2192 nllVar->setData(fData);
2193 }
2194 if (fUfit) {
2195 // move to ufit coords before evaluating
2196 *nllVar->fFuncVars = fUfit->floatParsFinal();
2197 }
2198 nllVar->fFuncVars->setAttribAll("Constant", false);
2199 *nllVar->fFuncVars = *coords; // will reconst the coords
2200 nllVar->fFuncVars->setRealValue(_first_poi->GetName(), _first_poi->getMin("physical"));
2201 if (nllVar->fFuncGlobs)
2202 nllVar->fFuncGlobs->setAttribAll("Constant", true);
2203 if (fPOIName()) {
2204 nllVar->fFuncVars->find(fPOIName())
2205 ->setStringAttribute("altVal", (!std::isnan(fAltVal())) ? TString::Format("%g", fAltVal()) : nullptr);
2206 }
2207 if (fGenFit) {
2208 nllVar->get()->SetName(
2209 TString::Format("%s/%s_%s", nllVar->get()->GetName(), fGenFit->GetName(), (isExpected) ? "asimov" : "toys"));
2210 if (!isExpected)
2211 nllVar->get()->SetName(TString::Format("%s/%s", nllVar->get()->GetName(), fData.first->GetName()));
2212 }
2213 nllVar->get()->setStringAttribute(
2214 "fitresultTitle",
2215 collectionContents(*std::unique_ptr<RooAbsCollection>(nllVar->fFuncVars->selectCommon(poi()))).c_str());
2216 return (fLbound_cfit = nllVar->minimize());
2217}
2218
2219std::shared_ptr<const RooFitResult> xRooNLLVar::xRooHypoPoint::cfit_alt(bool readOnly)
2220{
2221 if (std::isnan(fAltVal()))
2222 return nullptr;
2223 if (fAlt_cfit)
2224 return fAlt_cfit;
2225 if (auto rfit = retrieveFit(2)) {
2226 return fAlt_cfit = rfit;
2227 }
2228 if (!nllVar || (readOnly && nllVar->get() && !nllVar->get()->getAttribute("readOnly")))
2229 return nullptr;
2230 if (!nllVar->fFuncVars)
2231 nllVar->reinitialize();
2232 AutoRestorer snap(*nllVar->fFuncVars, nllVar.get());
2233 if (!fData.first) {
2234 if (!readOnly && isExpected && fGenFit) {
2235 // can try to do a readOnly in case can load from cache
2236 bool tmp = nllVar->get()->getAttribute("readOnly");
2237 nllVar->get()->setAttribute("readOnly");
2238 auto out = cfit_alt(true);
2239 nllVar->get()->setAttribute("readOnly", tmp);
2240 if (out) {
2241 // retrieve from cache worked, no need to generate dataset
2242 return out;
2243 } else if (!tmp) { // don't need to setData if doing a readOnly fit
2244 nllVar->setData(data());
2245 }
2246 }
2247 } else if (!nllVar->get()->getAttribute("readOnly")) { // don't need to setData if doing a readOnly fit
2248 nllVar->setData(fData);
2249 }
2250 if (fUfit) {
2251 // move to ufit coords before evaluating
2252 *nllVar->fFuncVars = fUfit->floatParsFinal();
2253 }
2254 nllVar->fFuncVars->setAttribAll("Constant", false);
2255 *nllVar->fFuncVars = *coords; // will reconst the coords
2256 if (nllVar->fFuncGlobs)
2257 nllVar->fFuncGlobs->setAttribAll("Constant", true);
2258 *nllVar->fFuncVars = alt_poi();
2259 if (fGenFit) {
2260 nllVar->get()->SetName(
2261 TString::Format("%s/%s_%s", nllVar->get()->GetName(), fGenFit->GetName(), (isExpected) ? "asimov" : "toys"));
2262 if (!isExpected)
2263 nllVar->get()->SetName(TString::Format("%s/%s", nllVar->get()->GetName(), fData.first->GetName()));
2264 }
2265 nllVar->get()->setStringAttribute("fitresultTitle", collectionContents(alt_poi()).c_str());
2266 return (fAlt_cfit = nllVar->minimize());
2267}
2268
2270{
2271
2272 auto asi = asimov(readOnly);
2273
2274 if (!asi) {
2275 return std::pair<double, double>(std::numeric_limits<double>::quiet_NaN(), 0);
2276 }
2277
2278 auto out = asi->pll(readOnly);
2279 return std::pair<double, double>(std::abs(asi->fNullVal() - fAltVal()) / sqrt(out.first),
2280 out.second * 0.5 * std::abs(asi->fNullVal() - fAltVal()) /
2281 (out.first * sqrt(out.first)));
2282}
2283
2285{
2286 auto _ts = ts_toys(nSigma);
2287 if (std::isnan(_ts.first))
2288 return _ts;
2289 if (fPllType != xRooFit::Asymptotics::Uncapped && _ts.first == 0)
2290 return std::pair<double, double>(1, 0); // don't need toys to compute this point!
2291
2292 TEfficiency eff("", "", 1, 0, 1);
2293
2294 auto &_theToys = (alt) ? altToys : nullToys;
2295
2296 if (_theToys.empty()) {
2297 return std::pair(0.5, std::numeric_limits<double>::infinity());
2298 }
2299
2300 // loop over toys, count how many are > ts value
2301 // nans (mean bad ts evaluations) will count towards uncertainty
2302 int nans = 0;
2303 double result = 0;
2304 double result_err_up = 0;
2305 double result_err_down = 0;
2306 for (auto &toy : _theToys) {
2307 if (std::isnan(std::get<1>(toy))) {
2308 nans++;
2309 } else {
2310 bool res = std::get<1>(toy) >= _ts.first;
2311 if (std::get<2>(toy) != 1) {
2312 eff.FillWeighted(res, 0.5, std::get<2>(toy));
2313 } else {
2314 eff.Fill(res, 0.5);
2315 }
2316 if (res)
2317 result += std::get<2>(toy);
2318 if (std::get<1>(toy) >= _ts.first - _ts.second)
2319 result_err_up += std::get<2>(toy);
2320 if (std::get<1>(toy) >= _ts.first - _ts.second)
2321 result_err_down += std::get<2>(toy);
2322 }
2323 }
2324 // symmetrize the error
2325 result_err_up -= result;
2326 result_err_down -= result;
2327 double result_err = std::max(std::abs(result_err_up), std::abs(result_err_down));
2328 // assume the nans would "add" to the p-value, conservative scenario
2329 result_err += nans;
2330 result_err /= _theToys.size();
2331
2332 // don't include the nans for the central value though
2333 result /= (_theToys.size() - nans);
2334
2335 // add to the result_err (in quadrature) the uncert due to limited stats
2336 result_err = sqrt(result_err * result_err + eff.GetEfficiencyErrorUp(1) * eff.GetEfficiencyErrorUp(1));
2337 return std::pair<double, double>(result, result_err);
2338}
2339
2341{
2342 return pX_toys(false, nSigma);
2343}
2344
2346{
2347 if (!std::isnan(nSigma)) {
2348 return std::pair<double, double>(ROOT::Math::gaussian_cdf(nSigma), 0); // by construction
2349 }
2350 return pX_toys(true, nSigma);
2351}
2352
2354{
2355 xRooHypoPoint out;
2356 out.coords = coords;
2357 out.fPllType = fPllType; // out.fPOIName = fPOIName; out.fNullVal=fNullVal; out.fAltVal = fAltVal;
2358 out.nllVar = nllVar;
2359 if (!nllVar)
2360 return out;
2361 auto _cfit = cfit_null();
2362 if (!_cfit)
2363 return out;
2364 if (!nllVar->fFuncVars)
2365 nllVar->reinitialize();
2366 //*nllVar->fFuncVars = cfit_null()->floatParsFinal();
2367 //*nllVar->fFuncVars = cfit_null()->constPars();
2368 out.fData = xRooFit::generateFrom(*nllVar->fPdf, *_cfit, false, seed); // nllVar->generate(false,seed);
2369 out.fGenFit = _cfit;
2370 return out;
2371}
2372
2374{
2375 xRooHypoPoint out;
2376 out.coords = coords;
2377 out.fPllType = fPllType; // out.fPOIName = fPOIName; out.fNullVal=fNullVal; out.fAltVal = fAltVal;
2378 out.nllVar = nllVar;
2379 if (!nllVar)
2380 return out;
2381 if (!cfit_alt())
2382 return out;
2383 if (!nllVar->fFuncVars)
2384 nllVar->reinitialize();
2385 //*nllVar->fFuncVars = cfit_alt()->floatParsFinal();
2386 //*nllVar->fFuncVars = cfit_alt()->constPars();
2387 out.fData =
2388 xRooFit::generateFrom(*nllVar->fPdf, *cfit_alt(), false, seed); // out.data = nllVar->generate(false,seed);
2389 out.fGenFit = cfit_alt();
2390 return out;
2391}
2392
2393size_t xRooNLLVar::xRooHypoPoint::addToys(bool alt, int nToys, int initialSeed, double target, double target_nSigma,
2394 bool targetCLs, double relErrThreshold, size_t maxToys)
2395{
2396 if ((alt && !cfit_alt()) || (!alt && !cfit_null())) {
2397 throw std::runtime_error("Cannot add toys, invalid conditional fit");
2398 }
2399
2400 maxToys = std::min(maxToys,(size_t)gEnv->GetValue("XRooFit.MaxToys",10000));
2401
2402 auto condition = [&]() { // returns true if need more toys
2403 if (std::isnan(target))
2404 return false;
2405 auto obs = targetCLs ? pCLs_toys(target_nSigma) : (alt ? pAlt_toys(target_nSigma) : pNull_toys(target_nSigma));
2406 if (!std::isnan(obs.first)) {
2407 double diff = (target < 0) ? obs.first : std::abs(obs.first - target);
2408 double err = obs.second;
2409 if (err > 1e-4 && diff <= relErrThreshold * obs.second) {
2410 // return true; // more toys needed
2411 if (targetCLs) {
2412 // decide which type we'd want to generate and update alt flag
2413 auto pNull = pNull_toys(target_nSigma);
2414 auto pAlt = pAlt_toys(target_nSigma);
2415 // std::cout << obs.first << " +/- " << obs.second << ": " << pNull.first << " +/- " << pNull.second << "
2416 // , " << pAlt.first << " +/- " << pAlt.second << std::endl;
2417 alt = (pAlt.second * pNull.first > pNull.second * pAlt.first);
2418 if ((alt ? pAlt.second : pNull.second) < 1e-4)
2419 return false; // stop if error gets too small
2420 if( ((alt) ? altToys.size() : nullToys.size()) >= maxToys )
2421 return false; // stop if hit maxToys
2422 }
2423 return true;
2424 }
2425 }
2426 return false;
2427 };
2428
2429 if (!std::isnan(target) && std::isnan(ts_toys(target_nSigma).first)) {
2430 if (std::isnan(target_nSigma)) {
2431 throw std::runtime_error("Cannot target obs p-value because ts value unavailable");
2432 }
2433 if (targetCLs && pCLs_toys(target_nSigma).second == 0) {
2434 // this happens if the mu_test=mu_alt ... no toys needed
2435 return 0;
2436 }
2437
2438 // try generating 100 alt toys
2439 Info("addToys", "First generating 100 alt toys in order to determine expected ts value");
2440 addToys(true, 100, initialSeed);
2441 // if still null then exit
2442 if (std::isnan(ts_toys(target_nSigma).first)) {
2443 throw std::runtime_error("Unable to determine expected ts value");
2444 }
2445 }
2446
2447 size_t nans = 0;
2448 float lastTime = 0;
2449 int lasti = 0;
2450 auto g = gROOT->Get<TGraph>("toyTime");
2451 if (!g) {
2452 g = new TGraph;
2453 g->SetNameTitle("toyTime", "Time per toy;Toy;time [s]");
2454 gROOT->Add(g);
2455 }
2456 g->Set(0);
2457 TStopwatch s2;
2458 s2.Start();
2459 TStopwatch s;
2460 s.Start();
2461
2462 size_t toysAdded(0);
2463 size_t altToysAdded(0);
2464 if (initialSeed) {
2465 RooRandom::randomGenerator()->SetSeed(initialSeed);
2466 }
2467 do {
2468 auto &toys = (alt) ? altToys : nullToys;
2469 if (toys.size() >= maxToys) {
2470 // cannot generate more toys, reached limit already
2471 break;
2472 }
2473 // don't generate toys if reached target
2474 if (!std::isnan(target) && !condition()) {
2475 break;
2476 }
2477 auto currVal = std::isnan(target) ? std::pair(0., 0.)
2478 : (targetCLs ? pCLs_toys(target_nSigma)
2479 : (alt ? pAlt_toys(target_nSigma) : pNull_toys(target_nSigma)));
2480 size_t nnToys = std::min(size_t(nToys), (maxToys - toys.size()));
2481
2482 for (size_t i = 0; i < nnToys; i++) {
2483 int seed = RooRandom::randomGenerator()->Integer(std::numeric_limits<uint32_t>::max());
2484 auto toy = ((alt) ? generateAlt(seed) : generateNull(seed));
2485 {
2486 TDirectory::TContext ctx{nullptr}; // disables any saving of fit results for toys
2487 toys.push_back(std::make_tuple(seed, toy.pll().first, 1.));
2488 }
2489 (alt ? altToysAdded : toysAdded)++;
2490 if (std::isnan(std::get<1>(toys.back())))
2491 nans++;
2492 g->SetPoint(g->GetN(), g->GetN(), s.RealTime() - lastTime); // stops the clock
2493 lastTime = s.RealTime();
2494 if (s.RealTime() > 10) {
2495 std::cout << "\r"
2496 << TString::Format("Generated %d/%d %s hypothesis toys [%.2f toys/s]",
2497 int(alt ? altToysAdded : toysAdded), int(nnToys), alt ? "alt" : "null",
2498 double(altToysAdded + toysAdded - lasti) / s.RealTime());
2499 if (!std::isnan(target)) {
2500 std::cout << " [current=" << currVal.first << "+/-" << currVal.second << " target=" << target
2501 << " nSigma=" << target_nSigma << "]";
2502 }
2503 std::cout << "..." << std::flush;
2504 lasti = altToysAdded + toysAdded;
2505 s.Reset();
2506 if (!gROOT->IsBatch()) {
2507 Draw();
2508 if (gPad) {
2509 gPad->Update();
2510#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 30, 00)
2511 gPad->GetCanvas()->ResetUpdated(); // stops previous canvas being replaced in a jupyter notebook
2512#endif
2514 }
2515 }
2516 s.Start();
2517 // std::cout << "Generated " << i << "/" << nToys << (alt ? " alt " : " null ") << " hypothesis toys " ..."
2518 // << std::endl;
2519 }
2520 s.Continue();
2521 }
2522 // sort the toys ... put nans first - do by setting all as negative inf (is that still necessary with the custom
2523 // sort below??)
2524 for (auto &t : toys) {
2525 if (std::isnan(std::get<1>(t)))
2526 std::get<1>(t) = -std::numeric_limits<double>::infinity();
2527 }
2528 std::sort(toys.begin(), toys.end(),
2529 [](const decltype(nullToys)::value_type &a, const decltype(nullToys)::value_type &b) -> bool {
2530 if (std::isnan(std::get<1>(a)))
2531 return true;
2532 if (std::isnan(std::get<1>(b)))
2533 return false;
2534 return std::get<1>(a) < std::get<1>(b);
2535 });
2536 for (auto &t : toys) {
2537 if (std::isinf(std::get<1>(t)))
2538 std::get<1>(t) = std::numeric_limits<double>::quiet_NaN();
2539 }
2540 if (std::isnan(target)) {
2541 break; // no more toys if not doing a target
2542 }
2543 // if(condition()) {
2544 // Info("addToys","Generating more toys to determine p-value ... currently: %f +/-
2545 // %f",pNull_toys(target_nSigma).first,pNull_toys(target_nSigma).second);
2546 // }
2547 } while (condition());
2548 if (lasti) {
2549 std::cout << "\r"
2550 << "Finished Generating ";
2551 if (toysAdded) {
2552 std::cout << toysAdded << " null ";
2553 }
2554 if (altToysAdded) {
2555 std::cout << altToysAdded << " alt ";
2556 }
2557 std::cout << "toys " << TString::Format("[%.2f toys/s overall]", double(toysAdded + altToysAdded) / s2.RealTime())
2558 << std::endl;
2559 if (!gROOT->IsBatch()) {
2560 Draw();
2561 if (gPad) {
2562 gPad->Update();
2563#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 30, 00)
2564 gPad->GetCanvas()->ResetUpdated(); // stops previous canvas being replaced in a jupyter notebook
2565#endif
2567 }
2568 }
2569 }
2570
2571 if (nans > 0) {
2572 std::cout << "Warning: " << nans << " toys were bad" << std::endl;
2573 }
2574 return toysAdded;
2575}
2576
2577void xRooNLLVar::xRooHypoPoint::addNullToys(int nToys, int seed, double target, double target_nSigma)
2578{
2579 addToys(false, nToys, seed, target, target_nSigma);
2580}
2581void xRooNLLVar::xRooHypoPoint::addAltToys(int nToys, int seed, double target, double target_nSigma)
2582{
2583 addToys(true, nToys, seed, target, target_nSigma);
2584}
2585
2586void xRooNLLVar::xRooHypoPoint::addCLsToys(int nToys, int seed, double target, double target_nSigma)
2587{
2588 addToys(false, nToys, seed, target, target_nSigma, true);
2589 return;
2590}
2591
2593xRooNLLVar::hypoPoint(const char *poiValues, double alt_value, const xRooFit::Asymptotics::PLLType &pllType)
2594{
2595 xRooHypoPoint out;
2596 // out.fPOIName = parName; out.fNullVal = value; out.fAltVal = alt_value;
2597
2598 if (!fFuncVars) {
2599 reinitialize();
2600 }
2601 AutoRestorer snap(*fFuncVars);
2602
2603 out.nllVar = std::make_shared<xRooNLLVar>(*this);
2604 // clear the underlying RooAbsReal, so that we don't accidentally alter it (e.g. setAttribute readOnly)
2605 // and therefore alter the xRooNLLVar object we are creating this hypoPoint from
2606 // basically ensure the hypoPoint has an independent version of the function
2607 out.nllVar->reset();
2608 out.fData = getData();
2609
2610 TStringToken pattern(poiValues, ",");
2611 TString poiNames;
2612 while (pattern.NextToken()) {
2613 TString s = pattern.Data();
2614 TString cName = s;
2615 double val = std::numeric_limits<double>::quiet_NaN();
2616 auto i = s.Index("=");
2617 if (i != -1) {
2618 cName = s(0, i);
2619 TString cVal = s(i + 1, s.Length());
2620 if (!cVal.IsFloat())
2621 throw std::runtime_error("poiValues must contain value");
2622 val = cVal.Atof();
2623 }
2624 auto v = dynamic_cast<RooRealVar *>(fFuncVars->find(cName));
2625 if (!v)
2626 throw std::runtime_error("Cannot find poi");
2627 if (!std::isnan(val))
2628 v->setVal(val);
2629 v->setConstant(); // because will select constants as coords
2630 if (poiNames != "") {
2631 poiNames += ",";
2632 }
2633 poiNames += cName;
2634 }
2635 if (poiNames == "") {
2636 throw std::runtime_error("No poi");
2637 }
2638
2639 auto _snap = std::unique_ptr<RooAbsCollection>(fFuncVars->selectByAttrib("Constant", true))->snapshot();
2640 _snap->setAttribAll("poi", false);
2641 std::unique_ptr<RooAbsCollection> _poi(_snap->selectByName(poiNames));
2642 _poi->setAttribAll("poi", true);
2643 if (std::isnan(alt_value)) {
2644 for (auto a : *_poi)
2645 a->setStringAttribute("altVal", nullptr);
2646 } else {
2647 for (auto a : *_poi)
2648 a->setStringAttribute("altVal", TString::Format("%g", alt_value));
2649 }
2650 if (fGlobs)
2651 _snap->remove(*fGlobs, true, true);
2652 out.coords.reset(_snap);
2653
2654 auto _type = pllType;
2655 if (_type == xRooFit::Asymptotics::Unknown) {
2656 // decide based on values
2657 if (std::isnan(alt_value)) {
2659 } else if (dynamic_cast<RooRealVar *>(_poi->first())->getVal() >= alt_value) {
2661 } else {
2663 // for uncapped, should check min is not at physical boundary
2664 for (auto b : out.poi()) {
2665 if (auto r = dynamic_cast<RooRealVar *>(b)) {
2666 if (r->hasRange("physical") && r->getMin() >= r->getMin("physical")) {
2667 ::Info(
2668 "xRooNLLVar::hypoPoint",
2669 "fitting min of %s is >= physical limit (%g), but using uncapped test-statistic, so will set to "
2670 "-max = %g",
2671 r->GetName(), r->getMin("physical"), -r->getMax());
2672 r->setMin(-r->getMax());
2673 }
2674 }
2675 }
2676 }
2677 }
2678
2679 out.fPllType = _type;
2680
2681 // if doing onesidedpositive with an alt value, will assume we need a physical boundary
2682 if (!std::isnan(alt_value) && out.fPllType == xRooFit::Asymptotics::OneSidedPositive) {
2683 std::unique_ptr<RooAbsCollection> thePoi(fFuncVars->selectByName(poiNames));
2684 for (auto b : *thePoi) {
2685 if (!static_cast<RooRealVar *>(b)->hasRange("physical")) {
2686 static_cast<RooRealVar *>(b)->setRange("physical", 0, std::numeric_limits<double>::infinity());
2687 }
2688 }
2689 }
2690
2691 return out;
2692}
2693
2694xRooNLLVar::xRooHypoPoint
2695xRooNLLVar::hypoPoint(double value, double alt_value, const xRooFit::Asymptotics::PLLType &pllType)
2696{
2697 if (!fFuncVars) {
2698 reinitialize();
2699 }
2700 std::unique_ptr<RooAbsCollection> _poi(fFuncVars->selectByAttrib("poi", true));
2701 if (_poi->empty()) {
2702 throw std::runtime_error("No POI specified in model");
2703 } else if (_poi->size() != 1) {
2704 throw std::runtime_error("Multiple POI specified in model");
2705 }
2706 return hypoPoint(_poi->first()->GetName(), value, alt_value, pllType);
2707}
2708
2710xRooNLLVar::hypoPoint(const char *parName, double value, double alt_value, const xRooFit::Asymptotics::PLLType &pllType)
2711{
2712 return hypoPoint(TString::Format("%s=%f", parName, value), alt_value, pllType);
2713}
2714
2716{
2717
2718 if (!nllVar && !hypoTestResult)
2719 return;
2720
2721 TString sOpt(opt);
2722 sOpt.ToLower();
2723 bool hasSame = sOpt.Contains("same");
2724 sOpt.ReplaceAll("same", "");
2725
2726 TVirtualPad *pad = gPad;
2727
2728 TH1 *hAxis = nullptr;
2729
2730 auto clearPad = []() {
2731 gPad->Clear();
2732 if (gPad->GetNumber() == 0) {
2733 gPad->SetBottomMargin(gStyle->GetPadBottomMargin());
2734 gPad->SetTopMargin(gStyle->GetPadTopMargin());
2735 gPad->SetLeftMargin(gStyle->GetPadLeftMargin());
2736 gPad->SetRightMargin(gStyle->GetPadRightMargin());
2737 }
2738 };
2739
2740 if (!hasSame || !pad) {
2741 if (!pad) {
2743 pad = gPad;
2744 }
2745 clearPad();
2746 } else {
2747 // get the histogram representing the axes
2748 hAxis = dynamic_cast<TH1 *>(pad->GetPrimitive(".axis"));
2749 if (!hAxis) {
2750 for (auto o : *pad->GetListOfPrimitives()) {
2751 if (hAxis = dynamic_cast<TH1 *>(o); hAxis)
2752 break;
2753 }
2754 }
2755 }
2756
2757 // get min and max values
2758 double _min = std::numeric_limits<double>::quiet_NaN();
2759 double _max = -std::numeric_limits<double>::quiet_NaN();
2760
2761 for (auto &p : nullToys) {
2762 if (std::get<2>(p) == 0)
2763 continue;
2764 if (std::isnan(std::get<1>(p)))
2765 continue;
2766 _min = std::min(std::get<1>(p), _min);
2767 _max = std::max(std::get<1>(p), _max);
2768 }
2769 for (auto &p : altToys) {
2770 if (std::get<2>(p) == 0)
2771 continue;
2772 if (std::isnan(std::get<1>(p)))
2773 continue;
2774 _min = std::min(std::get<1>(p), _min);
2775 _max = std::max(std::get<1>(p), _max);
2776 }
2777
2778 auto obs = ts_asymp();
2779 if (!std::isnan(obs.first)) {
2780 _min = std::min(obs.first - std::abs(obs.first) * 0.1, _min);
2781 _max = std::max(obs.first + std::abs(obs.first) * 0.1, _max);
2782 }
2783 // these are used down below to add obs p-values to legend, but up here because can trigger fits that create asimov
2784 auto pNull = pNull_toys();
2785 auto pAlt = pAlt_toys();
2786 auto pNullA = (fPllType == xRooFit::Asymptotics::Unknown)
2787 ? std::pair(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN())
2788 : pNull_asymp();
2789 auto pAltA = (fPllType == xRooFit::Asymptotics::Unknown)
2790 ? std::pair(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN())
2791 : pAlt_asymp();
2792 sigma_mu(true);
2793 auto asi = (fPllType != xRooFit::Asymptotics::Unknown && fAsimov && fAsimov->fUfit && fAsimov->fNull_cfit)
2794 ? fAsimov->pll().first
2795 : std::numeric_limits<double>::quiet_NaN();
2796 if (!std::isnan(asi) && asi > 0) {
2797 // can calculate asymptotic distributions,
2798 _min = std::min(asi - std::abs(asi), _min);
2799 _max = std::max(asi + std::abs(asi), _max);
2800 }
2801 if (_min > 0)
2802 _min = 0;
2803
2804 auto _poi = dynamic_cast<RooRealVar *>(poi().first());
2805
2806 auto makeHist = [&](bool isAlt) {
2807 TString title;
2808 auto h = new TH1D((isAlt) ? "alt_toys" : "null_toys", "", 100, _min, _max + (_max - _min) * 0.01);
2809 h->SetDirectory(nullptr);
2810 size_t nBadOrZero = 0;
2811 for (auto &p : (isAlt) ? altToys : nullToys) {
2812 double w = std::isnan(std::get<1>(p)) ? 0 : std::get<2>(p);
2813 if (w == 0)
2814 nBadOrZero++;
2815 if (!std::isnan(std::get<1>(p)))
2816 h->Fill(std::get<1>(p), w);
2817 }
2818 if (h->GetEntries() > 0)
2819 h->Scale(1. / h->Integral(0, h->GetNbinsX() + 1));
2820
2821 // add POI values to identify hypos
2822 // for(auto p : *fPOI) {
2823 // if (auto v = dynamic_cast<RooRealVar*>(p)) {
2824 // if (auto v2 = dynamic_cast<RooRealVar*>(fAltPoint->fCoords->find(*v)); v2 &&
2825 // v2->getVal()!=v->getVal()) {
2826 // // found point that differs in poi and altpoint value, so print my coords value for this
2827 // title += TString::Format("%s' = %g,
2828 // ",v->GetTitle(),dynamic_cast<RooRealVar*>(fCoords->find(*v))->getVal());
2829 // }
2830 // }
2831 // }
2832 if (fPOIName())
2833 title += TString::Format("%s' = %g", fPOIName(), (isAlt) ? fAltVal() : fNullVal());
2834 title += TString::Format(" , N_{toys}=%d", int((isAlt) ? altToys.size() : nullToys.size()));
2835 if (nBadOrZero > 0)
2836 title += TString::Format(" (N_{bad/0}=%d)", int(nBadOrZero));
2837 title += ";";
2838 title += tsTitle();
2839 title += TString::Format(";Probability Mass");
2840 h->SetTitle(title);
2841 h->SetLineColor(isAlt ? kRed : kBlue);
2842 h->SetLineWidth(2);
2843 h->SetMarkerSize(0);
2844 h->SetStats(false);
2845 h->SetBit(kCanDelete);
2846 return h;
2847 };
2848
2849 auto nullHist = makeHist(false);
2850 auto altHist = makeHist(true);
2851
2852 TLegend *l = nullptr;
2853 auto h = (nullHist->GetEntries()) ? nullHist : altHist;
2854 if (!hasSame) {
2855 gPad->SetLogy();
2856 auto axis = static_cast<TH1 *>(h->Clone(".axis"));
2857 axis->SetBit(kCanDelete);
2858 axis->SetStats(false);
2859 axis->Reset("ICES");
2860 axis->SetTitle(TString::Format("%s HypoPoint", collectionContents(poi()).c_str()));
2861 axis->SetLineWidth(0);
2862 axis->Draw(""); // h->Draw("axis"); cant use axis option if want title drawn
2863 axis->SetMinimum(1e-7);
2864 axis->GetYaxis()->SetRangeUser(1e-7, 10);
2865 axis->SetMaximum(h->GetMaximum());
2866 hAxis = axis;
2867 l = new TLegend(0.4, 0.7, 1. - gPad->GetRightMargin(), 1. - gPad->GetTopMargin());
2868 l->SetName("legend");
2869 l->SetFillStyle(0);
2870 l->SetBorderSize(0);
2872 l->Draw();
2873 l->ConvertNDCtoPad();
2874 } else {
2875 for (auto o : *gPad->GetListOfPrimitives()) {
2876 l = dynamic_cast<TLegend *>(o);
2877 if (l)
2878 break;
2879 }
2880 }
2881
2882 if (h->GetEntries() > 0) {
2883 h->Draw("esame");
2884 } else {
2885 h->Draw("axissame"); // for unknown reason if second histogram empty it still draws with two weird bars???
2886 }
2887 h = altHist;
2888 if (h->GetEntries() > 0) {
2889 h->Draw("esame");
2890 } else {
2891 h->Draw("axissame"); // for unknown reason if second histogram empty it still draws with two weird bars???
2892 }
2893
2894 if (l) {
2895 l->AddEntry(nullHist);
2896 l->AddEntry(altHist);
2897 }
2898
2899 if (fAsimov && fAsimov->fUfit && fAsimov->fNull_cfit && !std::isnan(sigma_mu().first) && !std::isnan(fAltVal())) {
2900 auto hh = static_cast<TH1 *>(nullHist->Clone("null_asymp"));
2901 hh->SetBit(kCanDelete);
2902 hh->SetStats(false);
2903 hh->SetLineStyle(2);
2904 hh->Reset();
2905 for (int i = 1; i <= hh->GetNbinsX(); i++) {
2906 hh->SetBinContent(
2907 i, xRooFit::Asymptotics::PValue(fPllType, hh->GetBinLowEdge(i), fNullVal(), fNullVal(), sigma_mu().first,
2908 _poi->getMin("physical"), _poi->getMax("physical")) -
2909 xRooFit::Asymptotics::PValue(fPllType, hh->GetBinLowEdge(i + 1), fNullVal(), fNullVal(),
2910 sigma_mu().first, _poi->getMin("physical"), _poi->getMax("physical")));
2911 }
2912 hh->Draw("lsame");
2913 hh = static_cast<TH1 *>(altHist->Clone("alt_asymp"));
2914 hh->SetBit(kCanDelete);
2915 hh->SetStats(false);
2916 hh->SetLineStyle(2);
2917 hh->Reset();
2918 for (int i = 1; i <= hh->GetNbinsX(); i++) {
2919 hh->SetBinContent(
2920 i, xRooFit::Asymptotics::PValue(fPllType, hh->GetBinLowEdge(i), fNullVal(), fAltVal(), sigma_mu().first,
2921 _poi->getMin("physical"), _poi->getMax("physical")) -
2922 xRooFit::Asymptotics::PValue(fPllType, hh->GetBinLowEdge(i + 1), fNullVal(), fAltVal(),
2923 sigma_mu().first, _poi->getMin("physical"), _poi->getMax("physical")));
2924 }
2925 hh->Draw("lsame");
2926 }
2927
2928 // draw observed points
2929 TLine ll;
2930 ll.SetLineStyle(1);
2931 ll.SetLineWidth(3);
2932 // for(auto p : fObs) {
2933 auto tl = ll.DrawLine(obs.first, hAxis->GetMinimum(), obs.first, 0.1);
2934 auto label = TString::Format("obs ts = %.4f", obs.first);
2935 if (obs.second)
2936 label += TString::Format(" #pm %.4f", obs.second);
2937
2938 l->AddEntry(tl, label, "l");
2939 label = "";
2940 if (nullHist->GetEntries() || altHist->GetEntries()) {
2941 auto pCLs = pCLs_toys();
2942 label += " p_{toy}=(";
2943 label += (std::isnan(pNull.first)) ? "-" : TString::Format("%.4f #pm %.4f", pNull.first, pNull.second);
2944 label += (std::isnan(pAlt.first)) ? ",-" : TString::Format(",%.4f #pm %.4f", pAlt.first, pAlt.second);
2945 label += (std::isnan(pCLs.first)) ? ",-)" : TString::Format(",%.4f #pm %.4f)", pCLs.first, pCLs.second);
2946 }
2947 if (label.Length() > 0)
2948 l->AddEntry("", label, "");
2949 label = "";
2950 if (!std::isnan(pNullA.first) || !std::isnan(pAltA.first)) {
2951 auto pCLs = pCLs_asymp();
2952 label += " p_{asymp}=(";
2953 label += (std::isnan(pNullA.first)) ? "-" : TString::Format("%.4f #pm %.4f", pNullA.first, pNullA.second);
2954 label += (std::isnan(pAltA.first)) ? ",-" : TString::Format(",%.4f #pm %.4f", pAltA.first, pAltA.second);
2955 label += (std::isnan(pCLs.first)) ? ",-)" : TString::Format(",%.4f #pm %.4f)", pCLs.first, pCLs.second);
2956 }
2957 if (label.Length() > 0)
2958 l->AddEntry("", label, "");
2959
2960 if (auto ax = dynamic_cast<TH1 *>(gPad->GetPrimitive(".axis")))
2961 ax->GetYaxis()->SetRangeUser(1e-7, 1);
2962}
2963
2965{
2966 auto v = dynamic_cast<RooRealVar *>(poi().empty() ? nullptr : poi().first());
2968 if (v && v->hasRange("physical") && v->getMin("physical") != -std::numeric_limits<double>::infinity()) {
2969 return (inWords) ? TString::Format("Lower-Bound One-Sided Limit PLR")
2970 : TString::Format("#tilde{q}_{%s=%g}", v->GetTitle(), v->getVal());
2971 } else if (v) {
2972 return (inWords) ? TString::Format("One-Sided Limit PLR")
2973 : TString::Format("q_{%s=%g}", v->GetTitle(), v->getVal());
2974 } else {
2975 return "q";
2976 }
2977 } else if (fPllType == xRooFit::Asymptotics::TwoSided) {
2978 if (v && v->hasRange("physical") && v->getMin("physical") != -std::numeric_limits<double>::infinity()) {
2979 return (inWords) ? TString::Format("Lower-Bound PLR")
2980 : TString::Format("#tilde{t}_{%s=%g}", v->GetTitle(), v->getVal());
2981 } else if (v) {
2982 return (inWords) ? TString::Format("-2log[L(%s,#hat{#hat{#theta}})/L(#hat{%s},#hat{#theta})]", v->GetTitle(),
2983 v->GetTitle())
2984 : TString::Format("t_{%s=%g}", v->GetTitle(), v->getVal());
2985 } else
2986 return "t";
2987 } else if (fPllType == xRooFit::Asymptotics::OneSidedNegative) {
2988 if (v && v->hasRange("physical") && v->getMin("physical") != -std::numeric_limits<double>::infinity()) {
2989 return (inWords) ? TString::Format("Lower-Bound One-Sided Discovery PLR")
2990 : TString::Format("#tilde{r}_{%s=%g}", v->GetTitle(), v->getVal());
2991 } else if (v) {
2992 return (inWords) ? TString::Format("One-Sided Discovery PLR")
2993 : TString::Format("r_{%s=%g}", v->GetTitle(), v->getVal());
2994 } else {
2995 return "r";
2996 }
2997 } else if (fPllType == xRooFit::Asymptotics::Uncapped) {
2998 if (v && v->hasRange("physical") && v->getMin("physical") != -std::numeric_limits<double>::infinity()) {
2999 return (inWords) ? TString::Format("Lower-Bound Uncapped PLR")
3000 : TString::Format("#tilde{u}_{%s=%g}", v->GetTitle(), v->getVal());
3001 } else if (v) {
3002 return (inWords) ? TString::Format("Uncapped PLR") : TString::Format("u_{%s=%g}", v->GetTitle(), v->getVal());
3003 } else {
3004 return "u";
3005 }
3006 } else {
3007 return "Test Statistic";
3008 }
3009}
3010
3012{
3013 return (poi().empty()) ? nullptr : (poi().first())->GetName();
3014}
3016{
3017 auto first_poi = dynamic_cast<RooAbsReal *>(poi().first());
3018 return (first_poi == nullptr) ? std::numeric_limits<double>::quiet_NaN() : first_poi->getVal();
3019}
3021{
3022 auto _alt_poi = alt_poi(); // need to keep alive as alt_poi owns its contents
3023 auto first_poi = dynamic_cast<RooAbsReal *>(_alt_poi.first());
3024 return (first_poi == nullptr) ? std::numeric_limits<double>::quiet_NaN() : first_poi->getVal();
3025}
3026
3028{
3029 auto first_poi = dynamic_cast<RooAbsRealLValue *>(poi().first());
3030 if (!first_poi) {
3031 throw std::runtime_error("HypoPoint has no POI, cannot set null value");
3032 }
3033 first_poi->setVal(val);
3034}
3036{
3037 auto first_poi = dynamic_cast<RooAbsArg *>(poi().first());
3038 if (!first_poi) {
3039 throw std::runtime_error("HypoPoint has no POI, cannot set alt value");
3040 }
3041 first_poi->setStringAttribute("altVal", TString::Format("%g", val).Data());
3042}
3043
3044xRooNLLVar::xRooHypoSpace xRooNLLVar::hypoSpace(const char *parName, int nPoints, double low, double high,
3045 double alt_value, const xRooFit::Asymptotics::PLLType &pllType,
3046 int tsType)
3047{
3048 if (nPoints < 0 || tsType < 0) {
3049 // nPoints<0 catches case where pyROOT has converted TestStatistic enum to int
3050 if (nPoints < 0) {
3051 tsType = nPoints;
3052 nPoints = int(low + 0.5);
3053 low = high;
3054 high = alt_value;
3055 }
3056 if (alt_value == std::numeric_limits<double>::quiet_NaN()) {
3058 alt_value = 0;
3059 } else if (tsType == xRooFit::TestStatistic::q0 || tsType == xRooFit::TestStatistic::uncappedq0) {
3060 alt_value = 1;
3061 }
3062 }
3063
3064 auto out = hypoSpace(parName, pllType, alt_value);
3065
3066 // TODO: things like the physical range and alt value can't be stored on the poi
3067 // because if they change they will change for all hypoSpaces at once, so cannot have
3068 // two hypoSpace with e.g. different physical ranges.
3069 // the hypoSpace should make a copy of them at some point
3070 for (auto p : out.poi()) {
3071 if (tsType == xRooFit::TestStatistic::qmutilde) {
3072 dynamic_cast<RooRealVar *>(p)->setRange("physical", 0, std::numeric_limits<double>::infinity());
3073 Info("xRooNLLVar::hypoSpace", "Setting physical range of %s to [0,inf]", p->GetName());
3074 } else if (auto v = dynamic_cast<RooRealVar *>(p); v->hasRange("physical")) {
3075 v->removeMin("physical");
3076 v->removeMax("physical"); // v->removeRange("physical");
3077 Info("xRooNLLVar::hypoSpace", "Removing physical range of %s", p->GetName());
3078 }
3079 }
3080
3081 // ensure pll type is set explicitly if known at this point
3083 out.fTestStatType = xRooFit::Asymptotics::OneSidedPositive;
3084 } else if (tsType == xRooFit::TestStatistic::uncappedq0) {
3085 out.fTestStatType = xRooFit::Asymptotics::Uncapped;
3086 } else if (tsType == xRooFit::TestStatistic::q0) {
3087 out.fTestStatType = xRooFit::Asymptotics::OneSidedNegative;
3088 }
3089
3090 if (nPoints > 0) {
3091 out.AddPoints(parName, nPoints, low, high);
3092 } else {
3093 // if (!std::isnan(low) && !std::isnan(high) && !(std::isinf(low) && std::isinf(high))) {
3094 for (auto p : out.poi()) {
3095 if (auto r = dynamic_cast<RooRealVar *>(p)) {
3096 r->setRange("scan", std::isnan(low) ? r->getMin() : low, std::isnan(high) ? r->getMax() : high);
3097 }
3098 }
3099 //}
3100 }
3101 return out;
3102 }
3103
3104 xRooNLLVar::xRooHypoSpace hs = hypoSpace(parName, pllType, alt_value);
3105 if (nPoints > 0)
3106 hs.AddPoints(parName, nPoints, low, high);
3107 else {
3108 // if (!std::isnan(low) && !std::isnan(high) && !(std::isinf(low) && std::isinf(high))) {
3109 for (auto p : hs.poi()) {
3110 if (auto r = dynamic_cast<RooRealVar *>(p)) {
3111 r->setRange("scan", std::isnan(low) ? r->getMin() : low, std::isnan(high) ? r->getMax() : high);
3112 }
3113 }
3114 //}
3115 }
3116 return hs;
3117}
3118
3119xRooNLLVar::xRooHypoSpace xRooNLLVar::hypoSpace(int nPoints, double low, double high, double alt_value,
3120 const xRooFit::Asymptotics::PLLType &pllType)
3121{
3122 auto _poi = std::unique_ptr<RooAbsCollection>(
3123 std::unique_ptr<RooAbsCollection>(pdf()->getVariables())->selectByAttrib("poi", true));
3124 if (_poi->empty())
3125 throw std::runtime_error("You must specify a POI for the hypoSpace");
3126 return hypoSpace(_poi->first()->GetName(), nPoints, low, high, alt_value, pllType);
3127}
3128
3130xRooNLLVar::hypoSpace(const char *parName, const xRooFit::Asymptotics::PLLType &pllType, double alt_value)
3131{
3132 xRooNLLVar::xRooHypoSpace s(parName, parName);
3133
3134 s.AddModel(pdf());
3135 if (strlen(parName)) {
3136 std::unique_ptr<RooAbsCollection> axes(s.pars()->selectByName(parName));
3137 if (axes->empty())
3138 throw std::runtime_error("parameter not found");
3139 axes->setAttribAll("axis", true);
3140 }
3141 /*if (std::unique_ptr<RooAbsCollection>(s.pars()->selectByAttrib("poi", true))->empty()) {
3142 throw std::runtime_error("You must specify at least one POI for the hypoSpace");
3143 }*/
3144 s.fNlls[s.fPdfs.begin()->second] = std::make_shared<xRooNLLVar>(*this);
3145 // clear the underlying RooAbsReal, so that we don't accidentally alter it (e.g. setAttribute readOnly)
3146 // and therefore alter the xRooNLLVar object we are creating this hypoPoint from
3147 // basically ensure the hypoPoint has an independent version of the function
3148 s.fNlls[s.fPdfs.begin()->second]->reset();
3149 s.fTestStatType = pllType;
3150
3151 for (auto poi : s.poi()) {
3152 poi->setStringAttribute("altVal", std::isnan(alt_value) ? nullptr : TString::Format("%f", alt_value));
3153 // default scan range to range of poi
3154 if (auto r = dynamic_cast<RooRealVar *>(poi)) {
3155 r->setRange("scan", r->getMin(), r->getMax());
3156 }
3157 }
3158
3159 return s;
3160}
3161
3163{
3164 if (hypoTestResult) {
3165 return *hypoTestResult;
3166 }
3168 out.SetBackgroundAsAlt(true);
3169 out.SetName(TUUID().AsString());
3170 out.SetTitle(TString::Format("%s HypoPoint", collectionContents(poi()).c_str()));
3171
3172 bool setReadonly = false;
3173 if (nllVar && !nllVar->get()->getAttribute("readOnly")) {
3174 setReadonly = true;
3175 nllVar->get()->setAttribute("readOnly");
3176 }
3177
3178 out.SetTestStatisticData(ts_asymp().first);
3179
3180 // build a ds to hold all fits ... store coords in the globs list of the nullDist
3181 // also need to store at least mu_hat value(s)
3182 RooArgList fitDetails;
3183 RooArgList fitMeta;
3184 fitMeta.addClone(RooCategory("pllType", "test statistic type",
3185 {{"TwoSided", 0},
3186 {"OneSidedPositive", 1},
3187 {"OneSidedNegative", 2},
3188 {"OneSidedAbsolute", 3},
3189 {"Uncapped", 4},
3190 {"Unknown", 5}}));
3191 if (ufit()) {
3192 fitMeta.addClone(ufit()->floatParsFinal());
3193 }
3194 fitMeta.setCatIndex("pllType", int(fPllType));
3195 fitMeta.addClone(RooRealVar("isExpected", "isExpected", int(isExpected)));
3196 fitMeta.addClone(RooRealVar("obs_ts_err", "obs_ts_err", obs_ts_err));
3197 fitDetails.addClone(RooCategory("type", "fit type",
3198 {{"ufit", 0},
3199 {"cfit_null", 1},
3200 {"cfit_alt", 2},
3201 {"asimov_ufit", 3},
3202 {"asimov_cfit_null", 4},
3203 {"gen", 5},
3204 {"cfit_lbound", 6}}));
3205 // fitDetails.addClone(RooStringVar("name", "Fit Name", "")); -- not supported properly in ROOT yet
3206 fitDetails.addClone(RooRealVar("status", "status", 0));
3207 fitDetails.addClone(RooRealVar("covQual", "covQual", 0));
3208 fitDetails.addClone(RooRealVar("minNll", "minNll", 0));
3209 fitDetails.addClone(RooRealVar("edm", "edm", 0));
3210 auto fitDS = new RooDataSet("fits", "fit summary data", fitDetails);
3211 // fitDS->convertToTreeStore(); // strings not stored properly in vector store, so do convert! - not needed since
3212 // string var storage not properly supported - storing in globs list instead
3213
3214 for (int i = 0; i < 7; i++) {
3215 std::shared_ptr<const RooFitResult> fit;
3216 switch (i) {
3217 case 0: fit = ufit(); break;
3218 case 1: fit = cfit_null(); break;
3219 case 2: fit = cfit_alt(); break;
3220 case 3: fit = asimov() ? asimov()->ufit(true) : nullptr; break;
3221 case 4: fit = asimov() ? asimov()->cfit_null(true) : nullptr; break;
3222 case 5: fit = fGenFit; break;
3223 case 6: fit = cfit_lbound(); break;
3224 }
3225 if (fit) {
3226 fitDetails.setCatIndex("type", i);
3227 fitMeta.addClone(RooStringVar(TString::Format("%s.name", fitDetails.getCatLabel("type")),
3228 fitDetails.getCatLabel("type"), fit->GetName()));
3229 // fitDetails.setStringValue("name",fit->GetName());
3230 fitDetails.setRealValue("status", fit->status());
3231 fitDetails.setRealValue("minNll", fit->minNll());
3232 fitDetails.setRealValue("edm", fit->edm());
3233 fitDetails.setRealValue("covQual", fit->covQual());
3234 fitDS->add(fitDetails);
3235 }
3236 }
3237 fitDS->setGlobalObservables(fitMeta);
3238
3239 out.SetFitInfo(fitDS);
3240
3241 RooArgList nullDetails;
3242 RooArgList nullMeta;
3243 nullMeta.addClone(*coords);
3244 nullDetails.addClone(RooRealVar("seed", "Toy Seed", 0));
3245 nullDetails.addClone(RooRealVar("ts", "test statistic value", 0));
3246 nullDetails.addClone(RooRealVar("weight", "weight", 1));
3247 auto nullToyDS = new RooDataSet("nullToys", "nullToys", nullDetails, RooFit::WeightVar("weight"));
3248 nullToyDS->setGlobalObservables(nullMeta);
3249 if (!nullToys.empty()) {
3250
3251 std::vector<double> values;
3252 std::vector<double> weights;
3253 values.reserve(nullToys.size());
3254 weights.reserve(nullToys.size());
3255
3256 for (auto &t : nullToys) {
3257 values.push_back(std::get<1>(t));
3258 weights.push_back(std::get<2>(t));
3259 nullDetails.setRealValue("seed", std::get<0>(t));
3260 nullDetails.setRealValue("ts", std::get<1>(t));
3261 nullToyDS->add(nullDetails, std::get<2>(t));
3262 }
3263 out.SetNullDistribution(new RooStats::SamplingDistribution("null", "Null dist", values, weights, tsTitle()));
3264#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
3265 out.fNullPValue = pNull_toys().first; // technically set above
3266 out.fNullPValueError =
3267 pNull_toys().second; // overrides binomial error used in SamplingDistribution::IntegralAndError
3268#else
3269 out.SetNullPValue(pNull_toys().first); // technically set above
3271 pNull_toys().second); // overrides binomial error used in SamplingDistribution::IntegralAndError
3272#endif
3273 } else {
3274#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
3275 out.fNullPValue = pNull_asymp().first;
3276 out.fNullPValueError = pNull_asymp().second;
3277#else
3278 out.SetNullPValue(pNull_asymp().first);
3279 out.SetNullPValueError(pNull_asymp().second);
3280#endif
3281 }
3282 out.SetNullDetailedOutput(nullToyDS);
3283
3284 if (!altToys.empty()) {
3285 std::vector<double> values;
3286 std::vector<double> weights;
3287 values.reserve(altToys.size());
3288 weights.reserve(altToys.size());
3289 RooArgList altDetails;
3290 RooArgList altMeta;
3291 altDetails.addClone(RooRealVar("seed", "Toy Seed", 0));
3292 altDetails.addClone(RooRealVar("ts", "test statistic value", 0));
3293 altDetails.addClone(RooRealVar("weight", "weight", 1));
3294 auto altToyDS = new RooDataSet("altToys", "altToys", altDetails, RooFit::WeightVar("weight"));
3295 altToyDS->setGlobalObservables(altMeta);
3296 for (auto &t : altToys) {
3297 values.push_back(std::get<1>(t));
3298 weights.push_back(std::get<2>(t));
3299 altDetails.setRealValue("seed", std::get<0>(t));
3300 altDetails.setRealValue("ts", std::get<1>(t));
3301 altToyDS->add(altDetails, std::get<2>(t));
3302 }
3303 out.SetAltDistribution(new RooStats::SamplingDistribution("alt", "Alt dist", values, weights, tsTitle()));
3304 out.SetAltDetailedOutput(altToyDS);
3305#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
3306 out.fAlternatePValue = pAlt_toys().first; // technically set above
3308 pAlt_toys().second; // overrides binomial error used in SamplingDistribution::IntegralAndError
3309#else
3310 out.SetAltPValue(pAlt_toys().first); // technically set above
3312 pAlt_toys().second); // overrides binomial error used in SamplingDistribution::IntegralAndError
3313#endif
3314
3315 } else if (fPllType != xRooFit::Asymptotics::Unknown) {
3316#if ROOT_VERSION_CODE < ROOT_VERSION(6, 27, 00)
3317 out.fAlternatePValue = pAlt_asymp().first;
3318 out.fAlternatePValueError = pAlt_asymp().second;
3319#else
3320 out.SetAltPValue(pAlt_asymp().first);
3321 out.SetAltPValueError(pAlt_asymp().second);
3322#endif
3323 }
3324
3325 if (setReadonly) {
3326 nllVar->get()->setAttribute("readOnly", false);
3327 }
3328
3329 return out;
3330}
3331
3333
3334std::string cling::printValue(const XROOFIT_NAMESPACE_NAME::xRooNLLVar::xValueWithError *v)
3335{
3336 if (!v)
3337 return "xValueWithError: nullptr\n";
3338 return v->__repr__();
3339}
3340std::string cling::printValue(const std::map<std::string, XROOFIT_NAMESPACE_NAME::xRooNLLVar::xValueWithError> *m)
3341{
3342 if (!m)
3343 return "nullptr\n";
3344 std::string out = "{\n";
3345 for (auto [k, v] : *m) {
3346 out += "\"" + k + "\" => " + printValue(&v) + "\n";
3347 }
3348 out += "}\n";
3349 return out;
3350}
#define SafeDelete(p)
Definition RConfig.hxx:507
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
@ kRed
Definition Rtypes.h:66
@ kBlue
Definition Rtypes.h:66
#define gDirectory
Definition TDirectory.h:385
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
winID h TVirtualViewer3D TVirtualGLPainter p
winID h TVirtualViewer3D vv
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 Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t np
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
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
@ kCanDelete
Definition TObject.h:375
#define gROOT
Definition TROOT.h:417
static char * Format(const char *format, va_list ap)
Format a string in a circular formatting buffer (using a printf style format descriptor).
Definition TString.cxx:2524
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define gPad
AutoRestorer(const RooAbsCollection &s, xRooNLLVar *nll=nullptr)
RooArgSet fPars
TString fOldTitle
TString fOldName
std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > fOldData
xRooNLLVar * fNll
std::unique_ptr< RooAbsCollection > fSnap
static double k(const IncompatFunc &compatRegions, double pValue, double poiVal, double poiPrimeVal, double sigma_mu=0, double mu_low=-std::numeric_limits< double >::infinity(), double mu_high=std::numeric_limits< double >::infinity())
static int CompatFactor(const IncompatFunc &func, double mu_hat)
static double PValue(const IncompatFunc &compatRegions, double k, double mu, double mu_prime, double sigma_mu=0, double mu_low=-std::numeric_limits< double >::infinity(), double mu_high=std::numeric_limits< double >::infinity())
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:762
static std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > generateFrom(RooAbsPdf &pdf, const RooFitResult &fr, bool expected=false, int seed=0)
Definition xRooFit.cxx:154
static std::shared_ptr< ROOT::Fit::FitConfig > createFitConfig()
Definition xRooFit.cxx:497
double impact(const char *poi, const char *np, bool up=true, bool prefit=false, bool approx=false)
xRooFitResult ifit(const char *np, bool up, bool prefit=false)
double conditionalError(const char *poi, const char *nps, bool up=true, bool approx=false)
RooArgList ranknp(const char *poi, bool up=true, bool prefit=false, double approxThreshold=std::numeric_limits< double >::infinity())
xRooFitResult cfit(const char *poiValues, const char *alias=nullptr)
std::shared_ptr< RooStats::HypoTestResult > hypoTestResult
Definition xRooNLLVar.h:281
std::shared_ptr< const RooFitResult > retrieveFit(int type)
std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > fData
Definition xRooNLLVar.h:181
std::vector< std::tuple< int, double, double > > altToys
Definition xRooNLLVar.h:278
std::shared_ptr< const RooAbsCollection > coords
Definition xRooNLLVar.h:264
std::shared_ptr< const RooFitResult > cfit_lbound(bool readOnly=false)
void Draw(Option_t *opt="") override
Default Draw method for all objects.
xValueWithError ts_toys(double nSigma=std::numeric_limits< double >::quiet_NaN())
std::shared_ptr< const RooFitResult > fUfit
Definition xRooNLLVar.h:266
xRooHypoPoint(std::shared_ptr< RooStats::HypoTestResult > htr=nullptr, const RooAbsCollection *_coords=nullptr)
xValueWithError sigma_mu(bool readOnly=false)
xValueWithError pAlt_asymp(double nSigma=std::numeric_limits< double >::quiet_NaN())
std::vector< std::tuple< int, double, double > > nullToys
Definition xRooNLLVar.h:276
std::shared_ptr< xRooHypoPoint > asimov(bool readOnly=false)
xValueWithError pAlt_toys(double nSigma=std::numeric_limits< double >::quiet_NaN())
std::shared_ptr< const RooFitResult > ufit(bool readOnly=false)
void Print(Option_t *opt="") const override
Print TNamed name and title.
std::shared_ptr< const RooFitResult > cfit_null(bool readOnly=false)
std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > data()
xValueWithError pCLs_asymp(double nSigma=std::numeric_limits< double >::quiet_NaN())
std::shared_ptr< const RooFitResult > cfit_alt(bool readOnly=false)
void addAltToys(int nToys=1, int seed=0, double target=std::numeric_limits< double >::quiet_NaN(), double target_nSigma=std::numeric_limits< double >::quiet_NaN())
size_t addToys(bool alt, int nToys, int initialSeed=0, double target=std::numeric_limits< double >::quiet_NaN(), double target_nSigma=std::numeric_limits< double >::quiet_NaN(), bool targetCLs=false, double relErrThreshold=2., size_t maxToys=-1)
void addCLsToys(int nToys=1, int seed=0, double target=std::numeric_limits< double >::quiet_NaN(), double target_nSigma=std::numeric_limits< double >::quiet_NaN())
xValueWithError pX_toys(bool alt, double nSigma=std::numeric_limits< double >::quiet_NaN())
std::shared_ptr< const RooFitResult > fGenFit
Definition xRooNLLVar.h:267
void addNullToys(int nToys=1, int seed=0, double target=std::numeric_limits< double >::quiet_NaN(), double target_nSigma=std::numeric_limits< double >::quiet_NaN())
xValueWithError ts_asymp(double nSigma=std::numeric_limits< double >::quiet_NaN())
xValueWithError pNull_asymp(double nSigma=std::numeric_limits< double >::quiet_NaN())
xValueWithError pNull_toys(double nSigma=std::numeric_limits< double >::quiet_NaN())
std::shared_ptr< RooArgSet > pars() const
Definition xRooNLLVar.h:326
bool AddModel(const xRooNode &pdf, const char *validity="")
std::map< std::shared_ptr< xRooNode >, std::shared_ptr< xRooNLLVar > > fNlls
Definition xRooNLLVar.h:391
int AddPoints(const char *parName, size_t nPoints, double low, double high)
std::set< std::pair< std::shared_ptr< RooArgList >, std::shared_ptr< xRooNode > > > fPdfs
Definition xRooNLLVar.h:393
This xRooNLLVar object has several special methods, e.g.
Definition xRooNLLVar.h:59
std::shared_ptr< RooAbsCollection > fFuncGlobs
Definition xRooNLLVar.h:509
std::shared_ptr< const RooAbsCollection > fGlobs
Definition xRooNLLVar.h:502
std::shared_ptr< RooLinkedList > fOpts
Definition xRooNLLVar.h:504
std::shared_ptr< RooAbsReal > func() const
std::set< std::string > binnedChannels() const
ROOT::Math::IOptions * fitConfigOptions()
RooConstraintSum * constraintTerm() const
std::shared_ptr< ROOT::Fit::FitConfig > fFitConfig
Definition xRooNLLVar.h:505
xRooHypoSpace hypoSpace(const char *parName, int nPoints, double low, double high, double alt_value=std::numeric_limits< double >::quiet_NaN(), const xRooFit::Asymptotics::PLLType &pllType=xRooFit::Asymptotics::Unknown, int tsType=0)
TObject * Scan(const RooArgList &scanPars, const std::vector< std::vector< double > > &coords, const RooArgList &profilePars=RooArgList())
std::shared_ptr< RooAbsCollection > fConstVars
Definition xRooNLLVar.h:508
xRooNLLVar(RooAbsPdf &pdf, const std::pair< RooAbsData *, const RooAbsCollection * > &data, const RooLinkedList &nllOpts=RooLinkedList())
std::shared_ptr< RooAbsPdf > pdf() const
Definition xRooNLLVar.h:453
std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > generate(bool expected=false, int seed=0)
std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > getData() const
double getEntryVal(size_t entry) const
std::shared_ptr< RooAbsCollection > fFuncVars
Definition xRooNLLVar.h:507
double getEntryBinWidth(size_t entry) const
std::shared_ptr< ROOT::Fit::FitConfig > fitConfig()
std::shared_ptr< RooArgSet > pars(bool stripGlobalObs=true) const
void SetOption(const RooCmdArg &opt)
std::shared_ptr< RooAbsData > fData
Definition xRooNLLVar.h:501
std::shared_ptr< RooAbsPdf > fPdf
Definition xRooNLLVar.h:500
bool setData(const std::pair< std::shared_ptr< RooAbsData >, std::shared_ptr< const RooAbsCollection > > &_data)
xRooHypoPoint hypoPoint(const char *parName, double value, double alt_value=std::numeric_limits< double >::quiet_NaN(), const xRooFit::Asymptotics::PLLType &pllType=xRooFit::Asymptotics::Unknown)
xRooFitResult minimize(const std::shared_ptr< ROOT::Fit::FitConfig > &=nullptr)
The xRooNode class is designed to wrap over a TObject and provide functionality to aid with interacti...
Definition xRooNode.h:52
xRooNode bins() const
bins of a channel or sample, or channels of a multi-channel pdf
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
virtual void SetNamedValue(const char *, const char *)
Definition IOptions.cxx:50
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
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.
Abstract base class for objects that represent a discrete value that can be set from the outside,...
A space to attach TBranches.
Abstract container object that can hold multiple RooAbsArg objects.
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.
RooAbsCollection * snapshot(bool deepCopy=true) const
Take a snap shot of current collection contents.
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...
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
Storage_t::size_type size() const
RooAbsArg * first() const
bool setCatIndex(const char *name, Int_t newVal=0, bool verbose=false)
Set index value of a RooAbsCategoryLValue stored in set with given name to newVal.
bool setRealValue(const char *name, double newVal=0.0, bool verbose=false)
Set value of a RooAbsRealLValue stored in set with given name to newVal No error messages are printed...
virtual RooAbsArg * addClone(const RooAbsArg &var, bool silent=false)
Add a clone of the specified argument to list.
const char * getCatLabel(const char *name, const char *defVal="", bool verbose=false) const
Get state name of a RooAbsCategory stored in set with given name.
std::string contentsString() const
Return comma separated list of contained object names as STL string.
void setName(const char *name)
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
virtual const RooArgSet * get() const
Definition RooAbsData.h:99
virtual Int_t numEntries() const
Return number of entries in dataset, i.e., count unweighted entries.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
virtual void setVal(double value)=0
Set the current value of the object. Needs to be overridden by implementations.
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
bool hasRange(const char *name) const override
Check if variable has a binning with given name.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
virtual bool setData(RooAbsData &, bool=true)
Definition RooAbsReal.h:364
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
RooArgSet * selectCommon(const RooAbsCollection &refColl) const
Use RooAbsCollection::selecCommon(), but return as RooArgSet.
Definition RooArgSet.h:154
Object to represent discrete states.
Definition RooCategory.h:28
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
double getDouble(Int_t idx) const
Return double stored in slot idx.
Definition RooCmdArg.h:92
Int_t getInt(Int_t idx) const
Definition RooCmdArg.h:87
TObject * Clone(const char *newName=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooCmdArg.h:58
const char * getString(Int_t idx) const
Return string stored in slot idx.
Definition RooCmdArg.h:96
Calculates the sum of the -(log) likelihoods of a set of RooAbsPfs that represent constraint function...
Container class to hold unbinned data.
Definition RooDataSet.h:32
RooFitResult is a container class to hold the input and output of a PDF fit to a dataset.
Plain Gaussian p.d.f.
Definition RooGaussian.h:24
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
Int_t GetSize() const
TObject * At(int index) const
Return object stored in sequential position given by index.
static RooMsgService & instance()
Return reference to singleton instance.
StreamConfig & getStream(Int_t id)
Poisson pdf.
Definition RooPoisson.h:18
static TRandom * randomGenerator()
Return a pointer to a singleton random-number generator implementation.
Definition RooRandom.cxx:47
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
double getErrorLo() const
Definition RooRealVar.h:68
double getErrorHi() const
Definition RooRealVar.h:69
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
RooAbsPdf * getPdf(RooStringView catName) const
Return the p.d.f associated with the given index category name.
HypoTestResult is a base class for results from hypothesis tests.
void SetAltDetailedOutput(RooDataSet *d)
double fNullPValue
p-value for the null hypothesis (small number means disfavoured)
double fAlternatePValueError
error of p-value for the alternate hypothesis (small number means disfavoured)
void SetNullDetailedOutput(RooDataSet *d)
void SetBackgroundAsAlt(bool l=true)
void SetAltPValue(double pvalue)
void SetNullDistribution(SamplingDistribution *null)
void SetTestStatisticData(const double tsd)
void SetAltPValueError(double err)
void SetFitInfo(RooDataSet *d)
double fNullPValueError
error of p-value for the null hypothesis (small number means disfavoured)
void SetAltDistribution(SamplingDistribution *alt)
double fAlternatePValue
p-value for the alternate hypothesis (small number means disfavoured)
void SetNullPValue(double pvalue)
void SetNullPValueError(double err)
This class simply holds a sampling distribution of some test statistic.
A RooAbsArg implementing string values.
Draw all kinds of Arrows.
Definition TArrow.h:29
virtual TArrow * DrawArrow(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Float_t arrowsize=0, Option_t *option="")
Draw this arrow with new coordinates.
Definition TArrow.cxx:129
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:46
virtual void SetLineWidth(Width_t lwidth)
Set the line width.
Definition TAttLine.h:47
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
static TCanvas * MakeDefCanvas()
Static function to build a default canvas.
Definition TCanvas.cxx:1536
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition TDatime.cxx:98
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
Describe directory structure in memory.
Definition TDirectory.h:45
virtual TKey * FindKeyAny(const char *) const
Definition TDirectory.h:199
Class to handle efficiency histograms.
Definition TEfficiency.h:29
void FillWeighted(Bool_t bPassed, Double_t weight, Double_t x, Double_t y=0, Double_t z=0)
This function is used for filling the two histograms with a weight.
Double_t GetEfficiencyErrorUp(Int_t bin) const
Returns the upper error on the efficiency in the given global bin.
void Fill(Bool_t bPassed, Double_t x, Double_t y=0, Double_t z=0)
This function is used for filling the two histograms.
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:511
Graphics object made of three arrays X, Y and Z with the same number of points each.
Definition TGraph2D.h:41
Int_t GetN() const
Definition TGraph2D.h:121
virtual void SetPoint(Int_t point, Double_t x, Double_t y, Double_t z)
Sets point number n.
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:2386
Int_t GetN() const
Definition TGraph.h:131
virtual void Sort(Bool_t(*greater)(const TGraph *, Int_t, Int_t)=&TGraph::CompareX, Bool_t ascending=kTRUE, Int_t low=0, Int_t high=-1111)
Sorts the points of this TGraph using in-place quicksort (see e.g.
Definition TGraph.cxx:2530
virtual void Add(TF1 *f, Double_t c1=1)
Performs the operation: y = y + c1*f(x,y) Errors are not recalculated.
Definition TGraph.cxx:650
void SetName(const char *name="") override
Set graph name.
Definition TGraph.cxx:2425
void Draw(Option_t *chopt="") override
Draw this graph with its current attributes.
Definition TGraph.cxx:859
virtual Double_t GetPointY(Int_t i) const
Get y value for point i.
Definition TGraph.cxx:1584
void SetTitle(const char *title="") override
Change (i.e.
Definition TGraph.cxx:2441
void SetNameTitle(const char *name="", const char *title="") override
Set graph name and title.
Definition TGraph.cxx:2461
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:926
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
virtual Double_t GetMinimum(Double_t minval=-FLT_MAX) const
Return minimum value larger than minval of bins in the range, unless the value has been overridden by...
Definition TH1.cxx:8868
This class displays a legend box (TPaveText) containing several legend entries.
Definition TLegend.h:23
void Draw(Option_t *option="") override
Draw this legend with its current attributes.
Definition TLegend.cxx:424
Use the TLine constructor to create a simple line.
Definition TLine.h:22
virtual TLine * DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Draw this line with new coordinates.
Definition TLine.cxx:103
A TMultiGraph is a collection of TGraph (or derived) objects.
Definition TMultiGraph.h:34
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
void Clear(Option_t *option="") override
Set name and title to empty strings ("").
Definition TNamed.cxx:63
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
Mother of all ROOT objects.
Definition TObject.h:42
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:461
virtual void Delete(Option_t *option="")
Delete this object.
Definition TObject.cxx:267
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:886
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:292
virtual void SetSeed(ULong_t seed=0)
Set the random generator seed.
Definition TRandom.cxx:614
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
Definition TRandom.cxx:360
Regular expression class.
Definition TRegexp.h:31
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.
Basic string class.
Definition TString.h:137
Ssiz_t Length() const
Definition TString.h:426
void ToLower()
Change string to lower-case.
Definition TString.cxx:1190
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:2069
Double_t Atof() const
Return floating-point value contained in string.
Definition TString.cxx:2135
Bool_t IsFloat() const
Returns kTRUE if string contains a floating point or integer number.
Definition TString.cxx:1939
const char * Data() const
Definition TString.h:385
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:714
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:633
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:2460
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:642
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:661
Float_t GetPadRightMargin() const
Definition TStyle.h:216
Float_t GetPadLeftMargin() const
Definition TStyle.h:215
Float_t GetPadBottomMargin() const
Definition TStyle.h:213
Float_t GetPadTopMargin() const
Definition TStyle.h:214
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:419
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:701
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:53
virtual TList * GetListOfPrimitives() const =0
virtual TObject * GetPrimitive(const char *name) const =0
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg GlobalObservables(Args_t &&... argsOrArgSet)
RooCmdArg GlobalObservablesSource(const char *sourceName)
double gaussian_pdf(double x, double sigma=1, double x0=0)
Probability density function of the normal (Gaussian) distribution with mean x0 and standard deviatio...
const Int_t n
Definition legend1.C:16
TGraphErrors * gr
Definition legend1.C:25
double gaussian_cdf(double x, double sigma=1, double x0=0)
Alternative name for same function.
double gaussian_cdf_c(double x, double sigma=1, double x0=0)
Alternative name for same function.
static constexpr auto NumIntegration
Alias of MsgLevel::NumericIntegration for backwards compatibility.
@ NumericIntegration
Double_t Prob(Double_t chi2, Int_t ndf)
Computation of the probability for a certain Chi-squared (chi2) and number of degrees of freedom (ndf...
Definition TMath.cxx:637
Double_t Poisson(Double_t x, Double_t par)
Computes the Poisson distribution function for (x,par).
Definition TMath.cxx:587
Double_t LnGamma(Double_t z)
Computation of ln[gamma(z)] for all z.
Definition TMath.cxx:509
#define BEGIN_XROOFIT_NAMESPACE
Definition Config.h:24
#define END_XROOFIT_NAMESPACE
Definition Config.h:25
static const char * what
Definition stlLoader.cc:5
void removeTopic(RooFit::MsgTopic oldTopic)
th1 Draw()
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4
std::string collectionContents(const RooAbsCollection &coll)
#define GETWS(a)
#define GETWSSETS(w)