Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
AsymptoticCalculator.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id$
2// Author: Kyle Cranmer, Sven Kreiss 23/05/10
3/*************************************************************************
4 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11/** \class RooStats::AsymptoticCalculator
12 \ingroup Roostats
13
14Hypothesis Test Calculator based on the asymptotic formulae for the profile
15likelihood ratio.
16
17It performs hypothesis tests using the asymptotic formula for the profile likelihood, and
18uses the Asimov data set to compute expected significances or limits.
19
20See G. Cowan, K. Cranmer, E. Gross and O. Vitells: Asymptotic formulae for
21likelihood- based tests of new physics. Eur. Phys. J., C71:1–19, 2011.
22It provides methods to perform hypothesis tests using the likelihood function,
23and computes the \f$p\f$-values for the null and the alternate hypothesis using the asymptotic
24formulae for the profile likelihood ratio described in the given paper.
25
26The calculator provides methods to produce the Asimov dataset, *i.e.* a dataset
27generated where the observed values are equal to the expected ones.
28The Asimov data set is then used to compute the observed asymptotic \f$p\f$-value for
29the alternate hypothesis and the asymptotic expected \f$p\f$-values.
30
31The asymptotic formulae are valid only for one POI (parameter of interest). So
32the calculator works only for one-dimensional (one POI) models.
33If more than one POI exists, only the first one is used.
34
35The calculator can generate Asimov datasets from two kinds of PDFs:
36- "Counting" distributions: RooPoisson, RooGaussian, or products of RooPoissons.
37- Extended, *i.e.* number of events can be read off from extended likelihood term.
38
39The fits performed by the calculator can be steered with the global default
40minimizer options, *e.g.* via ROOT::Math::MinimizerOptions::SetDefaultStrategy()
41and ROOT::Math::MinimizerOptions::SetDefaultTolerance() (the tolerance is
42clamped to a minimum value of 1). The RooFitResult objects of the fits are
43retrievable after calling GetHypoTest() via GetFitResultUncondObs(),
44GetFitResultCondObs(), GetFitResultUncondAsimov() and GetFitResultCondAsimov(),
45so quantities like the minimizer status or the EDM at the minimum can be
46inspected, for example to cross-check a fit that did not converge. Note that
47when the calculator is driven by the HypoTestInverter, the stored conditional
48fit results correspond to the last scanned point.
49*/
50
55
56#include "RooArgSet.h"
57#include "RooArgList.h"
58#include "RooProdPdf.h"
59#include "RooSimultaneous.h"
60#include "RooDataSet.h"
61#include "RooCategory.h"
62#include "RooRealVar.h"
63#include "RooMinimizer.h"
64#include "RooFitResult.h"
66#include "RooPoisson.h"
67#include "RooUniform.h"
68#include "RooGamma.h"
69#include "RooGaussian.h"
70#include "RooMultiVarGaussian.h"
71#include "RooBifurGauss.h"
72#include "RooLognormal.h"
73#include "RooDataHist.h"
74#include <cmath>
75#include <typeinfo>
76
79
80#include "TStopwatch.h"
81
82using namespace RooStats;
83using std::string, std::unique_ptr;
84
85
86namespace {
87
88/// Control print level (0 minimal, 1 normal, 2 debug).
89int &fgPrintLevel()
90{
91
92 static int val = 1;
93 return val;
94}
95
96// Forward declaration.
98 std::unique_ptr<RooFitResult> *fitResult = nullptr);
99
100} // namespace
101
102////////////////////////////////////////////////////////////////////////////////
103/// set print level (static function)
104///
105/// - 0 minimal,
106/// - 1 normal,
107/// - 2 debug
108
110 fgPrintLevel() = level;
111}
112
113////////////////////////////////////////////////////////////////////////////////
114/// constructor for asymptotic calculator from Data set and ModelConfig
115
118 const ModelConfig &altModel,
119 const ModelConfig &nullModel, bool nominalAsimov) :
121 fOneSided(false), fOneSidedDiscovery(false), fNominalAsimov(nominalAsimov),
122 fUseQTilde(-1),
123 fNLLObs(0), fNLLAsimov(0),
124 fAsimovData(nullptr)
125{
126 if (!Initialize()) return;
127
128 int verbose = fgPrintLevel();
129 // try to guess default configuration
130 // (this part should be only in constructor because the null snapshot might change during HypoTestInversion
131 const RooArgSet * nullSnapshot = GetNullModel()->GetSnapshot();
133 RooRealVar * muNull = dynamic_cast<RooRealVar*>(nullSnapshot->first() );
134 assert(muNull);
135 if (muNull->getVal() == muNull->getMin()) {
136 fOneSidedDiscovery = true;
137 if (verbose > 0)
138 oocoutI(nullptr,InputArguments) << "AsymptotiCalculator: Minimum of POI is " << muNull->getMin() << " corresponds to null snapshot - default configuration is one-sided discovery formulae " << std::endl;
139 }
140
141}
142
143////////////////////////////////////////////////////////////////////////////////
144/// Initialize the calculator
145/// The initialization will perform a global fit of the model to the data
146/// and build an Asimov data set.
147/// It will then also fit the model to the Asimov data set to find the likelihood value
148/// of the Asimov data set
149/// nominalAsimov is an option for using Asimov data set obtained using nominal nuisance parameter values
150/// By default the nuisance parameters are fitted to the data
151/// NOTE: If a fit has been done before, one for speeding up could set all the initial parameters
152/// to the fit value and in addition set the null snapshot to the best fit
153
155
156 int verbose = fgPrintLevel();
157 if (verbose >= 0)
158 oocoutP(nullptr,Eval) << "AsymptoticCalculator::Initialize...." << std::endl;
159
160
161 RooAbsPdf * nullPdf = GetNullModel()->GetPdf();
162 if (!nullPdf) {
163 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::Initialize - ModelConfig has not a pdf defined" << std::endl;
164 return false;
165 }
166 RooAbsData * obsData = const_cast<RooAbsData *>(GetData() );
167 if (!obsData ) {
168 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::Initialize - data set has not been defined" << std::endl;
169 return false;
170 }
172
173
174
175 const RooArgSet * poi = GetNullModel()->GetParametersOfInterest();
176 if (!poi || poi->empty()) {
177 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::Initialize - ModelConfig has not POI defined." << std::endl;
178 return false;
179 }
180 if (poi->size() > 1) {
181 oocoutW(nullptr,InputArguments) << "AsymptoticCalculator::Initialize - ModelConfig has more than one POI defined \n\t"
182 << "The asymptotic calculator works for only one POI - consider as POI only the first parameter"
183 << std::endl;
184 }
185
186
187 // This will set the poi value to the null snapshot value in the ModelConfig
188 const RooArgSet * nullSnapshot = GetNullModel()->GetSnapshot();
189 if(nullSnapshot == nullptr || nullSnapshot->empty()) {
190 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::Initialize - Null model needs a snapshot. Set using modelconfig->SetSnapshot(poi)." << std::endl;
191 return false;
192 }
193
194 // GetNullModel()->Print();
195 // std::cout << "ASymptotic calc: null snapshot\n";
196 // nullSnapshot->Print("v");
197 // std::cout << "PDF variables ";
198 // nullPdf->getVariables()->Print("v");
199
200 // keep snapshot for the initial parameter values (need for nominal Asimov)
202 std::unique_ptr<RooArgSet> allParams{nullPdf->getParameters(data)};
204 if (fNominalAsimov) {
205 allParams->snapshot(nominalParams);
206 }
210 fFitResultUncondObs.reset();
211 fFitResultCondObs.reset();
213 fFitResultCondAsimov.reset();
214
215 // evaluate the unconditional nll for the full model on the observed data
216 if (verbose >= 0)
217 oocoutP(nullptr,Eval) << "AsymptoticCalculator::Initialize - Find best unconditional NLL on observed data" << std::endl;
220 fFitResultUncondObs->SetName("fitResultUncondObs");
221 fFitResultUncondObs->SetTitle("Unconditional fit to observed data");
222 }
223 // fill also snapshot of best poi
224 poi->snapshot(fBestFitPoi);
225 RooRealVar * muBest = dynamic_cast<RooRealVar*>(fBestFitPoi.first());
226 assert(muBest);
227 if (verbose >= 0)
228 oocoutP(nullptr,Eval) << "Best fitted POI value = " << muBest->getVal() << " +/- " << muBest->getError() << std::endl;
229 // keep snapshot of all best fit parameters
230 allParams->snapshot(fBestFitParams);
231
232 // compute Asimov data set for the background (alt poi ) value
233 const RooArgSet * altSnapshot = GetAlternateModel()->GetSnapshot();
234 if(altSnapshot == nullptr || altSnapshot->empty()) {
235 oocoutE(nullptr,InputArguments) << "Alt (Background) model needs a snapshot. Set using modelconfig->SetSnapshot(poi)." << std::endl;
236 return false;
237 }
238
239 RooArgSet poiAlt(*altSnapshot); // this is the poi snapshot of B (i.e. for mu=0)
240
241 oocoutP(nullptr,Eval) << "AsymptoticCalculator: Building Asimov data Set" << std::endl;
242
243 // check that in case of binned models the n number of bins of the observables are consistent
244 // with the number of bins in the observed data
245 // This number will be used for making the Asimov data set so it will be more consistent with the
246 // observed data
247 int prevBins = 0;
248 RooRealVar * xobs = nullptr;
249 if (GetNullModel()->GetObservables() && GetNullModel()->GetObservables()->size() == 1 ) {
250 xobs = static_cast<RooRealVar*>((GetNullModel()->GetObservables())->first());
251 if (data.IsA() == RooDataHist::Class() ) {
252 if (data.numEntries() != xobs->getBins() ) {
253 prevBins = xobs->getBins();
254 oocoutW(nullptr,InputArguments) << "AsymptoticCalculator: number of bins in " << xobs->GetName() << " are different than data bins "
255 << " set the same data bins " << data.numEntries() << " in range "
256 << " [ " << xobs->getMin() << " , " << xobs->getMax() << " ]" << std::endl;
257 xobs->setBins(data.numEntries());
258 }
259 }
260 }
261
262 if (!fNominalAsimov) {
263 if (verbose >= 0)
264 oocoutI(nullptr,InputArguments) << "AsymptoticCalculator: Asimov data will be generated using fitted nuisance parameter values" << std::endl;
265 std::unique_ptr<RooArgSet> tmp{static_cast<RooArgSet *>(poiAlt.snapshot())};
267 }
268
269 else {
270 // assume use current value of nuisance as nominal ones
271 if (verbose >= 0)
272 oocoutI(nullptr,InputArguments) << "AsymptoticCalculator: Asimovdata set will be generated using nominal (current) nuisance parameter values" << std::endl;
273 nominalParams.assign(poiAlt); // set poi to alt value but keep nuisance at the nominal one
275 }
276
277 if (!fAsimovData) {
278 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator: Error : Asimov data set could not be generated " << std::endl;
279 return false;
280 }
281
282 // set global observables to their Asimov values
285 if (GetNullModel()->GetGlobalObservables() ) {
286 globObs.add(*GetNullModel()->GetGlobalObservables());
287 assert(globObs.size() == fAsimovGlobObs.size() );
288 // store previous snapshot value
289 globObs.snapshot(globObsSnapshot);
290 globObs.assign(fAsimovGlobObs);
291 }
292
293
294 // evaluate the likelihood. Since we use on Asimov data , conditional and unconditional values should be the same
295 // do conditional fit since is faster
296
297 RooRealVar * muAlt = static_cast<RooRealVar*>(poiAlt.first());
298 assert(muAlt);
299 if (verbose >= 0) {
300 oocoutP(nullptr, Eval)
301 << "AsymptoticCalculator::Initialize Find best conditional NLL on ASIMOV data set for given alt POI ( "
302 << muAlt->GetName() << " ) = " << muAlt->getVal() << std::endl;
303 }
304
307 fFitResultUncondAsimov->SetName("fitResultUncondAsimov");
308 fFitResultUncondAsimov->SetTitle("Fit to Asimov data with POI fixed to the alt-model snapshot");
309 }
310 // for unconditional fit
311 //fNLLAsimov = EvaluateNLL( *nullPdf, *fAsimovData);
312 //poi->Print("v");
313
314 // restore previous value
315 globObs.assign(globObsSnapshot);
316
317 // restore number of bins
318 if (prevBins > 0 && xobs) xobs->setBins(prevBins);
319
320 fIsInitialized = true;
321 return true;
322}
323
324namespace {
325
327 std::unique_ptr<RooFitResult> *fitResult)
328{
329 int verbose = fgPrintLevel();
330
331 if (fitResult)
332 fitResult->reset();
333
334 RooAbsPdf &pdf = *modelConfig.GetPdf();
335
337 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
338
339
340 std::unique_ptr<RooArgSet> allParams{pdf.getParameters(data)};
342 // add constraint terms for all non-constant parameters
343
344 // need to call constrain for RooSimultaneous until stripDisconnected problem fixed
345 auto& config = GetGlobalRooStatsConfig();
346 std::unique_ptr<RooAbsReal> nll{modelConfig.createNLL(data, RooFit::Constrain(*allParams), RooFit::Offset(config.useLikelihoodOffset))};
347
348 std::unique_ptr<RooArgSet> attachedSet{nll->getVariables()};
349
350 // if poi are specified - do a conditional fit
352 // support now only one POI
353 if (poiSet && !poiSet->empty()) {
354 RooRealVar * muTest = static_cast<RooRealVar*> (poiSet->first());
355 RooRealVar * poiVar = dynamic_cast<RooRealVar*>(attachedSet->find( muTest->GetName() ) );
356 if (poiVar && !poiVar->isConstant() ) {
357 poiVar->setVal( muTest->getVal() );
358 poiVar->setConstant();
360 }
361 if (poiSet->size() > 1)
362 oocoutW(nullptr,InputArguments) << "Model with more than one POI are not supported - ignore extra parameters, consider only first one" << std::endl;
363
364
365
366 // This for more than one POI (not yet supported)
367 //
368 // RooLinkedListIter it = poiSet->iterator();
369 // RooRealVar* tmpPar = nullptr, *tmpParA=nullptr;
370 // while((tmpPar = (RooRealVar*)it.Next())){
371 // tmpParA = ((RooRealVar*)attachedSet->find(tmpPar->GetName()));
372 // tmpParA->setVal( tmpPar->getVal() );
373 // if (!tmpParA->isConstant() ) {
374 // tmpParA->setConstant();
375 // paramsSetConstant.add(*tmpParA);
376 // }
377 // }
378
379 // check if there are non-const parameters so it is worth to do the minimization
380
381 }
382
384 tw.Start();
385 double val = -1;
386
387 //check if needed to skip the fit
390 bool skipFit = (nllParams.empty());
391
392 if (skipFit) {
393 val = nll->getVal(); // just evaluate nll in conditional fits with model without nuisance params
394 } else {
395
397
398 RooMinimizer minim(*nll);
400 minim.setStrategy( strategy);
401 minim.setEvalErrorWall(config.useEvalErrorWall);
402 // use tolerance - but never smaller than 1 (default in RooMinimizer)
404 tol = std::max(tol,1.0); // 1.0 is the minimum value used in RooMinimizer
405 minim.setEps( tol );
406 //LM: RooMinimizer.setPrintLevel has +1 offset - so subtract here -1
407 minim.setPrintLevel(minimPrintLevel-1);
408 int status = -1;
409 minim.optimizeConst(2);
410 TString minimizer = ""; // empty string to take RooMinimizer default initially
412
413 if (verbose > 0) {
414 oocoutP(nullptr,Eval) << "AsymptoticCalculator::EvaluateNLL ........ using " << minimizer << " / " << algorithm
415 << " with strategy " << strategy << " and tolerance " << tol << std::endl;
416 }
417
418 for (int tries = 1, maxtries = 4; tries <= maxtries; ++tries) {
419 // status = minim.minimize(fMinimizer, ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo().c_str());
420 status = minim.minimize(minimizer, algorithm);
421 // RooMinimizer::minimize returns -1 when the fit fails
422 if (status >= 0) {
423 break;
424 } else {
425 if (tries == 1) {
426 oocoutW(nullptr,Minimization) << " ----> Doing a re-scan first" << std::endl;
427 minim.minimize(minimizer,"Scan");
428 }
429 if (tries == 2) {
431 oocoutW(nullptr,Minimization) << " ----> trying with strategy = 1" << std::endl;
432 minim.setStrategy(1);
433 }
434 else
435 tries++; // skip this trial if strategy is already 1
436 }
437 if (tries == 3) {
438 oocoutW(nullptr,Minimization) << " ----> trying with improve" << std::endl;
439 minimizer = "Minuit";
440 algorithm = "migradimproved";
441 }
442 }
443 }
444
445 // save the fit result also in case of failure, so that the status of a
446 // non-converged fit can be inspected by the user
447 std::unique_ptr<RooFitResult> result{minim.save()};
448
449 // ignore errors in Hesse or in Improve and also when matrix was made pos def (status returned = 1)
450 if (status >= 0 && result) {
451 if (RooStats::NLLOffsetMode() != "initial") {
452 val = result->minNll();
453 } else {
456 val = nll->getVal();
458 }
459
460 } else {
461 oocoutE(nullptr,Fitting) << "FIT FAILED !- return a NaN NLL " << std::endl;
462 val = TMath::QuietNaN();
463 }
464
465 if (fitResult)
466 *fitResult = std::move(result);
467
468 minim.optimizeConst(false);
469 }
470
471 double muTest = 0;
472 if (verbose > 0) {
473 oocoutP(nullptr,Eval) << "AsymptoticCalculator::EvaluateNLL - value = " << val;
474 if (poiSet) {
475 muTest = ( static_cast<RooRealVar*>(poiSet->first()) )->getVal();
476 ooccoutP(nullptr,Eval) << " for poi fixed at = " << muTest;
477 }
478 if (!skipFit) {
479 tw.Stop();
480 ooccoutP(nullptr,Eval) << "\tfit time : " << tw.RealTime() << " s (real) " << tw.CpuTime() << " s (cpu)" << std::endl;
481 } else {
482 ooccoutP(nullptr,Eval) << std::endl;
483 }
484 }
485
486 // reset the parameter free which where set as constant
488
489
490 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(msglevel);
491
492 return val;
493}
494
495} // namespace
496
497////////////////////////////////////////////////////////////////////////////////
498/// It performs an hypothesis tests using the likelihood function
499/// and computes the p values for the null and the alternate using the asymptotic
500/// formulae for the profile likelihood ratio.
501/// See G. Cowan, K. Cranmer, E. Gross and O. Vitells.
502/// Asymptotic formulae for likelihood- based tests of new physics. Eur. Phys. J., C71:1–19, 2011.
503/// The formulae are valid only for one POI. If more than one POI exists consider as POI only the
504/// first one
505
507 int verbose = fgPrintLevel();
508
509 // re-initialized the calculator in case it is needed (pdf or data modified)
510 if (!fIsInitialized) {
511 if (!Initialize() ) {
512 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::GetHypoTest - Error initializing Asymptotic calculator - return nullptr result " << std::endl;
513 return nullptr;
514 }
515 }
516
517 if (!fAsimovData) {
518 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::GetHypoTest - Asimov data set has not been generated - return nullptr result " << std::endl;
519 return nullptr;
520 }
521
523 assert(GetData() );
524
525 RooAbsPdf * nullPdf = GetNullModel()->GetPdf();
527
528 // make conditional fit on null snapshot of poi
529
530 const RooArgSet * nullSnapshot = GetNullModel()->GetSnapshot();
531 assert(nullSnapshot && !nullSnapshot->empty());
532
533 // use as POI the nullSnapshot
534 // if more than one POI exists, consider only the first one
536
537 if (poiTest.size() > 1) {
538 oocoutW(nullptr,InputArguments) << "AsymptoticCalculator::GetHypoTest: snapshot has more than one POI - assume as POI first parameter " << std::endl;
539 }
540
541 std::unique_ptr<RooArgSet> allParams{nullPdf->getParameters(*GetData() )};
542 allParams->assign(fBestFitParams);
543
544 // set the one-side condition
545 // (this works when we have only one params of interest
546 RooRealVar * muHat = dynamic_cast<RooRealVar*> ( fBestFitPoi.first() );
547 assert(muHat && "no best fit parameter defined");
548 RooRealVar * muTest = dynamic_cast<RooRealVar*> ( nullSnapshot->find(muHat->GetName() ) );
549 assert(muTest && "poi snapshot is not existing");
550
551
552
553 if (verbose> 0) {
554 oocoutI(nullptr,Eval) << "\nAsymptoticCalculator::GetHypoTest: - perform an hypothesis test for POI ( " << muTest->GetName() << " ) = " << muTest->getVal() << std::endl;
555 oocoutP(nullptr,Eval) << "AsymptoticCalculator::GetHypoTest - Find best conditional NLL on OBSERVED data set ..... " << std::endl;
556 }
557
558 // evaluate the conditional NLL on the observed data for the snapshot value
559 double condNLL = EvaluateNLL(*GetNullModel(), const_cast<RooAbsData &>(*GetData()), &poiTest, &fFitResultCondObs);
560 if (fFitResultCondObs) {
561 fFitResultCondObs->SetName("fitResultCondObs");
562 fFitResultCondObs->SetTitle(
563 TString::Format("Conditional fit to observed data for %s = %g", muTest->GetName(), muTest->getVal()));
564 }
565
566 double qmu = 2.*(condNLL - fNLLObs);
567
568
569
570 if (verbose > 0)
571 oocoutP(nullptr,Eval) << "\t OBSERVED DATA : qmu = " << qmu << " condNLL = " << condNLL << " uncond " << fNLLObs << std::endl;
572
573
574 // this tolerance is used to avoid having negative qmu due to numerical errors
575 double tol = 2.E-3 * std::max(1.,ROOT::Math::MinimizerOptions::DefaultTolerance());
576 if (qmu < -tol || TMath::IsNaN(fNLLObs) ) {
577
578 if (qmu < 0) {
579 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: Found a negative value of the qmu - retry to do the unconditional fit "
580 << std::endl;
581 } else {
582 oocoutW(nullptr, Minimization)
583 << "AsymptoticCalculator: unconditional fit failed before - retry to do it now " << std::endl;
584 }
585
586 std::unique_ptr<RooFitResult> refitResult;
587 double nll = EvaluateNLL(*GetNullModel(), const_cast<RooAbsData &>(*GetData()), nullptr, &refitResult);
588
589 if (nll < fNLLObs || (TMath::IsNaN(fNLLObs) && !TMath::IsNaN(nll) ) ) {
590 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: Found a better unconditional minimum "
591 << " old NLL = " << fNLLObs << " old muHat " << muHat->getVal() << std::endl;
592
593 // update values
594 fNLLObs = nll;
595 if (refitResult) {
596 fFitResultUncondObs = std::move(refitResult);
597 fFitResultUncondObs->SetName("fitResultUncondObs");
598 fFitResultUncondObs->SetTitle("Unconditional fit to observed data");
599 }
600 const RooArgSet * poi = GetNullModel()->GetParametersOfInterest();
601 assert(poi);
603 poi->snapshot(fBestFitPoi);
604 // restore also muHad since previous pointer has been deleted
605 muHat = dynamic_cast<RooRealVar*> ( fBestFitPoi.first() );
606 assert(muHat);
607
608 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: New minimum found for "
609 << " NLL = " << fNLLObs << " muHat " << muHat->getVal() << std::endl;
610
611
612 qmu = 2.*(condNLL - fNLLObs);
613
614 if (verbose > 0)
615 oocoutP(nullptr,Eval) << "After unconditional refit, new qmu value is " << qmu << std::endl;
616
617 }
618 }
619
620 if (qmu < -tol ) {
621 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: qmu is still < 0 for mu = "
622 << muTest->getVal() << " return a dummy result "
623 << std::endl;
624 return new HypoTestResult();
625 }
626 if (TMath::IsNaN(qmu) ) {
627 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: failure in fitting for qmu or qmuA "
628 << muTest->getVal() << " return a dummy result "
629 << std::endl;
630 return new HypoTestResult();
631 }
632
633
634
635
636
637 // compute conditional ML on Asimov data set
638 // (need to const cast because it uses fitTo which is a non const method
639 // RooArgSet asimovGlobObs;
640 // RooAbsData * asimovData = (const_cast<AsymptoticCalculator*>(this))->MakeAsimovData( poi, asimovGlobObs);
641 // set global observables to their Asimov values
644 if (GetNullModel()->GetGlobalObservables() ) {
645 globObs.add(*GetNullModel()->GetGlobalObservables());
646 // store previous snapshot value
647 globObs.snapshot(globObsSnapshot);
648 globObs.assign(fAsimovGlobObs);
649 }
650
651
652 if (verbose > 0) oocoutP(nullptr,Eval) << "AsymptoticCalculator::GetHypoTest -- Find best conditional NLL on ASIMOV data set .... " << std::endl;
653
656 fFitResultCondAsimov->SetName("fitResultCondAsimov");
657 fFitResultCondAsimov->SetTitle(
658 TString::Format("Conditional fit to Asimov data for %s = %g", muTest->GetName(), muTest->getVal()));
659 }
660
661 double qmu_A = 2.*(condNLL_A - fNLLAsimov );
662
663 if (verbose > 0)
664 oocoutP(nullptr,Eval) << "\t ASIMOV data qmu_A = " << qmu_A << " condNLL = " << condNLL_A << " uncond " << fNLLAsimov << std::endl;
665
666 if (qmu_A < -tol || TMath::IsNaN(fNLLAsimov) ) {
667
668 if (qmu_A < 0) {
669 oocoutW(nullptr, Minimization)
670 << "AsymptoticCalculator: Found a negative value of the qmu Asimov- retry to do the unconditional fit "
671 << std::endl;
672 } else {
673 oocoutW(nullptr, Minimization)
674 << "AsymptoticCalculator: Fit failed for unconditional the qmu Asimov- retry unconditional fit "
675 << std::endl;
676 }
677
678 std::unique_ptr<RooFitResult> refitResult;
679 double nll = EvaluateNLL(*GetNullModel(), *fAsimovData, nullptr, &refitResult);
680
681 if (nll < fNLLAsimov || (TMath::IsNaN(fNLLAsimov) && !TMath::IsNaN(nll) )) {
682 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: Found a better unconditional minimum for Asimov data set"
683 << " old NLL = " << fNLLAsimov << std::endl;
684
685 // update values
686 fNLLAsimov = nll;
687 if (refitResult) {
689 fFitResultUncondAsimov->SetName("fitResultUncondAsimov");
690 fFitResultUncondAsimov->SetTitle("Unconditional fit to Asimov data");
691 }
692
693 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: New minimum found for "
694 << " NLL = " << fNLLAsimov << std::endl;
695 qmu_A = 2.*(condNLL_A - fNLLAsimov);
696
697 if (verbose > 0)
698 oocoutP(nullptr,Eval) << "After unconditional Asimov refit, new qmu_A value is " << qmu_A << std::endl;
699
700 }
701 }
702
703 if (qmu_A < - tol) {
704 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: qmu_A is still < 0 for mu = "
705 << muTest->getVal() << " return a dummy result "
706 << std::endl;
707 return new HypoTestResult();
708 }
709 if (TMath::IsNaN(qmu) ) {
710 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: failure in fitting for qmu or qmuA "
711 << muTest->getVal() << " return a dummy result "
712 << std::endl;
713 return new HypoTestResult();
714 }
715
716
717 // restore previous value of global observables
718 globObs.assign(globObsSnapshot);
719
720 // now we compute p-values using the asymptotic formulae
721 // described in the paper
722 // Cowan et al, Eur.Phys.J. C (2011) 71:1554
723
724 // first try to guess automatically if needed to use qtilde (or ttilde in case of two sided)
725 // if explicitly fUseQTilde this was not set
726 // qtilde is in this case used if poi is bounded at the value of the alt hypothesis
727 // for Qtilde (need to distinguish case when qmu > qmuA = mu^2/ sigma^2)
728 // (see Cowan et al, Eur.Phys.J. C(2011) 71:1554 paper equations 64 and 65
729 // (remember qmu_A = mu^2/sigma^2 )
730 bool useQTilde = false;
731 // default case (check if poi is limited or not to a zero value)
732 if (!fOneSidedDiscovery) { // qtilde is not a discovery test
733 if (fUseQTilde == -1 && !fOneSidedDiscovery) {
734 // alternate snapshot is value for which background is zero (for limits)
735 RooRealVar * muAlt = dynamic_cast<RooRealVar*>(GetAlternateModel()->GetSnapshot()->first() );
736 // null snapshot is value for which background is zero (for discovery)
737 //RooRealVar * muNull = dynamic_cast<RooRealVar*>(GetNullModel()->GetSnapshot()->first() );
738 assert(muAlt != nullptr );
739 if (muTest->getMin() == muAlt->getVal() ) {
740 fUseQTilde = 1;
741 oocoutI(nullptr,InputArguments) << "Minimum of POI is " << muTest->getMin() << " corresponds to alt snapshot - using qtilde asymptotic formulae " << std::endl;
742 } else {
743 fUseQTilde = 0;
744 oocoutI(nullptr,InputArguments) << "Minimum of POI is " << muTest->getMin() << " is different to alt snapshot " << muAlt->getVal()
745 << " - using standard q asymptotic formulae " << std::endl;
746 }
747 }
749 }
750
751 // check for one side condition (remember this is valid only for one poi)
752 // for a signed (uncapped) test statistic the sign of sqrt(qmu) is flipped instead of setting qmu to zero
753 bool flipSign = false;
754 if (fOneSided ) {
755 if ( muHat->getVal() > muTest->getVal() ) {
756 if (fSigned) {
757 oocoutI(nullptr, Eval) << "Using signed one-sided qmu - flipping the sign of the test statistic muHat = "
758 << muHat->getVal() << " muTest = " << muTest->getVal() << std::endl;
759 flipSign = true;
760 } else {
761 oocoutI(nullptr, Eval) << "Using one-sided qmu - setting qmu to zero muHat = " << muHat->getVal()
762 << " muTest = " << muTest->getVal() << std::endl;
763 qmu = 0;
764 }
765 }
766 }
767 if (fOneSidedDiscovery ) {
768 if ( muHat->getVal() < muTest->getVal() ) {
769 if (fSigned) {
770 oocoutI(nullptr, Eval)
771 << "Using signed one-sided discovery qmu - flipping the sign of the test statistic muHat = "
772 << muHat->getVal() << " muTest = " << muTest->getVal() << std::endl;
773 flipSign = true;
774 } else {
775 oocoutI(nullptr, Eval) << "Using one-sided discovery qmu - setting qmu to zero muHat = " << muHat->getVal()
776 << " muTest = " << muTest->getVal() << std::endl;
777 qmu = 0;
778 }
779 }
780 }
781
782 // fix for negative qmu values due to numerical errors
783 if (qmu < 0 && qmu > -tol) qmu = 0;
785
786 // asymptotic formula for pnull and from paper Eur.Phys.J C 2011 71:1554
787 // we have 4 different cases:
788 // t(mu), t_tilde(mu) for the 2-sided
789 // q(mu) and q_tilde(mu) for the one -sided test statistics
790
791 double pnull = -1;
792 double palt = -1;
793
794 // asymptotic formula for pnull (for only one POI)
795 // From fact that qmu is a chi2 with ndf=1
796
797 // for the signed test statistic, sqrtqmu becomes negative when the best fit
798 // value is beyond the tested value; the Gaussian asymptotic formulae below
799 // remain valid also in that case
800 double sqrtqmu = (qmu > 0) ? std::sqrt(qmu) : 0;
801 if (flipSign)
802 sqrtqmu = -sqrtqmu;
803 double sqrtqmu_A = (qmu_A > 0) ? std::sqrt(qmu_A) : 0;
804
805
807 // for one-sided PL (q_mu : equations 56,57)
808 if (verbose>2) {
809 if (fOneSided) {
810 oocoutI(nullptr,Eval) << "Using one-sided limit asymptotic formula (qmu)" << std::endl;
811 } else {
812 oocoutI(nullptr, Eval) << "Using one-sided discovery asymptotic formula (q0)" << std::endl;
813 }
814 }
817 }
818 else {
819 // for 2-sided PL (t_mu : equations 35,36 in asymptotic paper)
820 if (verbose > 2) oocoutI(nullptr,Eval) << "Using two-sided asymptotic formula (tmu)" << std::endl;
824
825 }
826
827 // the qtilde corrections apply when the best fit value is at the boundary
828 // (qmu > qmu_A); they cannot apply when the sign was flipped, because then
829 // the best fit value is on the other side of the tested value
830 if (useQTilde && !flipSign) {
831 if (fOneSided) {
832 // for bounded one-sided (q_mu_tilde: equations 64,65)
833 if ( qmu > qmu_A && (qmu_A > 0 || qmu > tol) ) { // to avoid case 0/0
834 if (verbose > 2) oocoutI(nullptr,Eval) << "Using qmu_tilde (qmu is greater than qmu_A)" << std::endl;
835 pnull = ROOT::Math::normal_cdf_c( (qmu + qmu_A)/(2 * sqrtqmu_A), 1.);
836 palt = ROOT::Math::normal_cdf_c( (qmu - qmu_A)/(2 * sqrtqmu_A), 1.);
837 }
838 }
839 else {
840 // for 2 sided bounded test statistic (N.B there is no one sided discovery qtilde)
841 // t_mu_tilde: equations 43,44 in asymptotic paper
842 if ( qmu > qmu_A && (qmu_A > 0 || qmu > tol) ) {
843 if (verbose > 2) oocoutI(nullptr,Eval) << "Using tmu_tilde (qmu is greater than qmu_A)" << std::endl;
845 ROOT::Math::normal_cdf_c( (qmu + qmu_A)/(2 * sqrtqmu_A), 1.);
847 ROOT::Math::normal_cdf_c( (qmu - qmu_A)/(2 * sqrtqmu_A), 1.);
848 }
849 }
850 }
851
852 // create an HypoTest result but where the sampling distributions are set to zero
853 string resultname = "HypoTestAsymptotic_result";
854 HypoTestResult* res = new HypoTestResult(resultname.c_str(), pnull, palt);
855
856 if (verbose > 0) {
857 oocoutP(nullptr, Eval) << "poi = " << muTest->getVal() << " qmu = " << qmu << " qmu_A = " << qmu_A
858 << " sigma = " << muTest->getVal() / sqrtqmu_A << " CLsplusb = " << pnull
859 << " CLb = " << palt << " CLs = " << res->CLs() << std::endl;
860 }
861
862 return res;
863
864}
865
867 PaltFunction( double offset, double pval, int icase) :
868 fOffset(offset), fPval(pval), fCase(icase) {}
869 double operator() (double x) const {
870 return ROOT::Math::normal_cdf_c(x + fOffset) + ROOT::Math::normal_cdf_c(fCase*(x - fOffset)) - fPval;
871 }
872 double fOffset;
873 double fPval;
874 int fCase;
875};
876
877////////////////////////////////////////////////////////////////////////////////
878/// function given the null and the alt p value - return the expected one given the N - sigma value
879
880double AsymptoticCalculator::GetExpectedPValues(double pnull, double palt, double nsigma, bool useCls, bool oneSided ) {
881 if (oneSided) {
885 if (!useCls) return clsplusb;
886 double clb = ROOT::Math::normal_cdf( nsigma, 1.);
887 return (clb == 0) ? -1 : clsplusb / clb;
888 }
889
890 // case of 2 sided test statistic
891 // need to compute numerically
893 if (sqrttmu == 0) {
894 // here cannot invert the function - skip the point
895 return -1;
896 }
897 // invert formula for palt to get sqrttmu_A
898 PaltFunction f( sqrttmu, palt, -1);
901 brf.SetFunction( wf, 0, 20);
902 bool ret = brf.Solve();
903 if (!ret) {
904 oocoutE(nullptr,Eval) << "Error finding expected p-values - return -1" << std::endl;
905 return -1;
906 }
907 double sqrttmu_A = brf.Root();
908
909 // now invert for expected value
912 brf.SetFunction(wf2,0,20);
913 ret = brf.Solve();
914 if (!ret) {
915 oocoutE(nullptr,Eval) << "Error finding expected p-values - return -1" << std::endl;
916 return -1;
917 }
918 return 2*ROOT::Math::normal_cdf_c( brf.Root(),1.);
919}
920
921namespace {
922
923////////////////////////////////////////////////////////////////////////////////
924/// Fill bins by looping recursively on observables.
925
926void FillBins(const RooAbsPdf & pdf, const RooArgList &obs, RooAbsData & data, int &index, double &binVolume, int &ibin) {
927
928 bool debug = (fgPrintLevel() >= 2);
929
930 RooRealVar * v = dynamic_cast<RooRealVar*>(&(obs[index]) );
931 if (!v) return;
932
933 RooArgSet obstmp(obs);
934 double expectedEvents = pdf.expectedEvents(obstmp);
935
936 if (debug) oocoutI(nullptr,Generation) << "looping on observable " << v->GetName() << std::endl;
937 for (int i = 0; i < v->getBins(); ++i) {
938 v->setBin(i);
939 if (index < int(obs.size()) -1) {
940 index++; // increase index
941 double prevBinVolume = binVolume;
942 binVolume *= v->getBinWidth(i); // increase bin volume
943 FillBins(pdf, obs, data, index, binVolume, ibin);
944 index--; // decrease index
945 binVolume = prevBinVolume; // decrease also bin volume
946 }
947 else {
948
949 // this is now a new bin - compute the pdf in this bin
950 double totBinVolume = binVolume * v->getBinWidth(i);
951 double fval = pdf.getVal(&obstmp)*totBinVolume;
952
953 if (fval*expectedEvents <= 0)
954 {
955 if (fval*expectedEvents < 0) {
956 oocoutW(nullptr,InputArguments)
957 << "AsymptoticCalculator::" << __func__
958 << "(): Bin " << i << " of " << v->GetName() << " has negative expected events! Please check your inputs." << std::endl;
959 }
960 else {
961 oocoutW(nullptr,InputArguments)
962 << "AsymptoticCalculator::" << __func__
963 << "(): Bin " << i << " of " << v->GetName() << " has zero expected events - skip it" << std::endl;
964 }
965 }
966 // have a cut off for overflows ??
967 else {
968 data.add(obs, fval*expectedEvents);
969 }
970
971 if (debug) {
972 oocoutI(nullptr,Generation) << "bin " << ibin << "\t";
973 for (std::size_t j=0; j < obs.size(); ++j) { ooccoutI(nullptr,Generation) << " " << (static_cast<RooRealVar&>( obs[j])).getVal(); }
974 ooccoutI(nullptr,Generation) << " w = " << fval*expectedEvents;
975 ooccoutI(nullptr,Generation) << std::endl;
976 }
977 ibin++;
978 }
979 }
980 //reset bin values
981 if (debug) {
982 oocoutI(nullptr,Generation) << "ending loop on .. " << v->GetName() << std::endl;
983 }
984
985 v->setBin(0);
986
987}
988
989bool setObsToExpected(RooAbsArg &x, RooAbsArg &mean, const RooArgSet &obs, std::string const &errPrefix)
990{
991 // Figure out which of the two arguments is the observable that should be
992 // set to the expected value given by the other one. Usually the observable
993 // is "x", but also the mean parameter can be the observable: this happens
994 // for example in constraint terms, where the global observable takes the
995 // role of the mean.
996 const bool xIsObs = obs.contains(x);
997 const bool meanIsObs = obs.contains(mean);
998 if (xIsObs && meanIsObs) {
999 oocoutF(nullptr, Generation) << errPrefix << "Has two observables ?? " << std::endl;
1000 return false;
1001 }
1002 if (!xIsObs && !meanIsObs) {
1003 oocoutF(nullptr, Generation) << errPrefix << "No observable?" << std::endl;
1004 return false;
1005 }
1006 auto *myobs = dynamic_cast<RooRealVar *>(xIsObs ? &x : &mean);
1007 auto *myexp = dynamic_cast<RooAbsReal *>(xIsObs ? &mean : &x);
1008 if (myobs == nullptr) {
1009 oocoutF(nullptr, Generation) << errPrefix << "Observable is not a RooRealVar??" << std::endl;
1010 return false;
1011 }
1012 if (myexp == nullptr) {
1013 oocoutF(nullptr, Generation) << errPrefix << "Expected is not a RooAbsReal??" << std::endl;
1014 return false;
1015 }
1016
1017 myobs->setVal(myexp->getVal());
1018
1019 if (fgPrintLevel() > 2) {
1020 oocoutI(nullptr,Generation) << "SetObsToExpected : setting " << myobs->GetName() << " to expected value " << myexp->getVal() << " of " << myexp->GetName() << std::endl;
1021 }
1022
1023 return true;
1024}
1025
1026////////////////////////////////////////////////////////////////////////////////
1027/// set observed value to the expected one
1028/// works for Gaussian, Poisson or LogNormal
1029/// need to iterate on the components of the Poisson to get n and nu (nu can be a RooAbsReal)
1030/// (code from G. Petrucciani and extended by L.M.)
1031
1032bool SetObsToExpected(RooGaussian &pdf, const RooArgSet &obs)
1033{
1034 std::string const &errPrefix = "AsymptoticCalculator::SetObsExpected( " + std::string{pdf.ClassName()} + " ) : ";
1035 return setObsToExpected(const_cast<RooAbsReal &>(pdf.getX()), const_cast<RooAbsReal &>(pdf.getMean()), obs,
1036 errPrefix);
1037}
1038
1039bool SetObsToExpected(RooPoisson &pdf, const RooArgSet &obs)
1040{
1041 std::string const &errPrefix = "AsymptoticCalculator::SetObsExpected( " + std::string{pdf.ClassName()} + " ) : ";
1042 return setObsToExpected(const_cast<RooAbsReal &>(pdf.getX()), const_cast<RooAbsReal &>(pdf.getMean()), obs,
1043 errPrefix);
1044}
1045
1047{
1048 // In the case of the multi-variate Gaussian, we need to iterate over the
1049 // dimensions and treat the observable and mean for each dimension
1050 // separately.
1051
1052 std::string const &errPrefix = "AsymptoticCalculator::SetObsExpected( " + std::string{mvgauss.ClassName()} + " ) : ";
1053 bool ret = true;
1054 for (std::size_t iDim = 0; iDim < mvgauss.xVec().size(); ++iDim) {
1055 ret &= setObsToExpected(mvgauss.xVec()[iDim], mvgauss.muVec()[iDim], obs,
1056 errPrefix + " : dim " + std::to_string(iDim) + " ");
1057 }
1058 return ret;
1059}
1060
1061////////////////////////////////////////////////////////////////////////////////
1062/// Inpspect a product pdf to find all the Poisson or Gaussian parts to set the observed
1063/// values to expected ones.
1064
1065bool setObsToExpectedProdPdf(RooProdPdf &prod, const RooArgSet &obs)
1066{
1067 bool ret = true;
1068 for (auto *a : prod.pdfList()) {
1069 if (!a->dependsOn(obs)) continue;
1070 RooPoisson *pois = nullptr;
1071 RooGaussian *gauss = nullptr;
1072 RooMultiVarGaussian *mvgauss = nullptr;
1073 // should try to add also lognormal case ?
1074 if ((pois = dynamic_cast<RooPoisson *>(a)) != nullptr) {
1075 ret &= SetObsToExpected(*pois, obs);
1076 pois->setNoRounding(true); //needed since expected value is not an integer
1077 } else if ((gauss = dynamic_cast<RooGaussian *>(a)) != nullptr) {
1078 ret &= SetObsToExpected(*gauss, obs);
1079 } else if ((mvgauss = dynamic_cast<RooMultiVarGaussian *>(a)) != nullptr) {
1081 } else if (RooProdPdf *subprod = dynamic_cast<RooProdPdf *>(a)) {
1083 } else {
1084 oocoutE(nullptr, InputArguments)
1085 << "Illegal term in counting model: "
1086 << "the PDF " << a->GetName() << " depends on the observables, but is not a Poisson, Gaussian or Product"
1087 << std::endl;
1088 return false;
1089 }
1090 }
1091
1092 return ret;
1093}
1094
1095////////////////////////////////////////////////////////////////////////////////
1096/// Generate counting Asimov data for the case when the pdf cannot be extended.
1097/// This function assumes that the pdf is a RooPoisson or can be decomposed in a product of RooPoisson,
1098/// or is a RooGaussian. Otherwise, we cannot know how to make the Asimov data sets.
1099
1101 RooArgSet obs(observables);
1102 RooProdPdf *prod = dynamic_cast<RooProdPdf *>(&pdf);
1103 RooPoisson *pois = nullptr;
1104 RooGaussian *gauss = nullptr;
1105 RooMultiVarGaussian *mvgauss = nullptr;
1106
1107 if (fgPrintLevel() > 1)
1108 oocoutI(nullptr,Generation) << "generate counting Asimov data for pdf of type " << pdf.ClassName() << std::endl;
1109
1110 bool r = false;
1111 if (prod != nullptr) {
1112 r = setObsToExpectedProdPdf(*prod, observables);
1113 } else if ((pois = dynamic_cast<RooPoisson *>(&pdf)) != nullptr) {
1114 r = SetObsToExpected(*pois, observables);
1115 // we need in this case to set Poisson to real values
1116 pois->setNoRounding(true);
1117 } else if ((gauss = dynamic_cast<RooGaussian *>(&pdf)) != nullptr) {
1118 r = SetObsToExpected(*gauss, observables);
1119 } else if ((mvgauss = dynamic_cast<RooMultiVarGaussian *>(&pdf)) != nullptr) {
1120 r = setObsToExpectedMultiVarGauss(*mvgauss, observables);
1121 } else {
1122 oocoutE(nullptr,InputArguments) << "A counting model pdf must be either a RooProdPdf or a RooPoisson or a RooGaussian" << std::endl;
1123 }
1124 if (!r) return nullptr;
1125 int icat = 0;
1126 if (channelCat) {
1127 icat = channelCat->getCurrentIndex();
1128 }
1129
1130 RooDataSet *ret = new RooDataSet("CountingAsimovData" + std::to_string(icat),
1131 "CountingAsimovData" + std::to_string(icat), obs);
1132 ret->add(obs);
1133 return ret;
1134}
1135
1136////////////////////////////////////////////////////////////////////////////////
1137/// Compute the asimov data set for an observable of a pdf.
1138/// It generates binned data following the binning of the observables.
1139// TODO: (possibility to change number of bins)
1140// TODO: implement integration over bin content
1141
1143
1144 int printLevel = fgPrintLevel();
1145
1146 // Get observables defined by the pdf associated with this state
1147 std::unique_ptr<RooArgSet> obs(pdf.getObservables(allobs) );
1148
1149
1150 // if pdf cannot be extended assume is then a counting experiment
1151 if (!pdf.canBeExtended() ) return GenerateCountingAsimovData(const_cast<RooAbsPdf&>(pdf), *obs, weightVar, channelCat);
1152
1153 RooArgSet obsAndWeight(*obs);
1154 obsAndWeight.add(weightVar);
1155
1156 std::unique_ptr<RooDataSet> asimovData;
1157 if (channelCat) {
1158 int icat = channelCat->getCurrentIndex();
1159 asimovData = std::make_unique<RooDataSet>("AsimovData" + std::to_string(icat),
1160 "combAsimovData" + std::to_string(icat),
1162 }
1163 else {
1164 asimovData = std::make_unique<RooDataSet>("AsimovData","AsimovData",RooArgSet(obsAndWeight),RooFit::WeightVar(weightVar));
1165 }
1166
1167 // This works only for 1D observables
1168 //RooRealVar* thisObs = ((RooRealVar*)obstmp->first());
1169
1170 RooArgList obsList(*obs);
1171
1172 // The Asimov data set is built by looping over the bins of the
1173 // observables. A freshly-constructed RooRealVar now defaults to zero bins,
1174 // so temporarily materialize the historical default binning for any
1175 // observable that has no explicit binning set. The change is undone right
1176 // after filling the bins so that the model observables are left untouched.
1177 std::vector<RooRealVar *> obsWithDefaultBinning;
1178 for (auto *arg : obsList) {
1179 auto *rrv = dynamic_cast<RooRealVar *>(arg);
1180 if (rrv && rrv->getBins() == 0) {
1181 rrv->setBins(RooRealVar::DefaultNBins);
1182 obsWithDefaultBinning.push_back(rrv);
1183 }
1184 }
1185
1186 // loop on observables and on the bins
1187 if (printLevel >= 2) {
1188 oocoutI(nullptr,Generation) << "Generating Asimov data for pdf " << pdf.GetName() << std::endl;
1189 oocoutI(nullptr,Generation) << "list of observables " << std::endl;
1190 obsList.Print();
1191 }
1192
1193 int obsIndex = 0;
1194 double binVolume = 1;
1195 int nbins = 0;
1196 FillBins(pdf, obsList, *asimovData, obsIndex, binVolume, nbins);
1197
1198 // restore the zero-bins default on observables that had no explicit binning
1199 for (auto *rrv : obsWithDefaultBinning) {
1200 rrv->setBins(0);
1201 }
1202 if (printLevel >= 2)
1203 oocoutI(nullptr,Generation) << "filled from " << pdf.GetName() << " " << nbins << " nbins " << " volume is " << binVolume << std::endl;
1204
1205 // for (int iobs = 0; iobs < obsList.size(); ++iobs) {
1206 // RooRealVar * thisObs = dynamic_cast<RooRealVar*> &obsList[i];
1207 // if (thisObs == 0) continue;
1208 // // loop on the bin contents
1209 // for(int ibin=0; ibin<thisObs->numBins(); ++ibin){
1210 // thisObs->setBin(ibin);
1211
1212 // thisNorm=pdftmp->getVal(obstmp)*thisObs->getBinWidth(jj);
1213 // if (thisNorm*expectedEvents <= 0)
1214 // {
1215 // std::cout << "WARNING::Detected bin with zero expected events! Please check your inputs." << std::endl;
1216 // }
1217 // // have a cut off for overflows ??
1218 // obsDataUnbinned->add(*mc->GetObservables(), thisNorm*expectedEvents);
1219 // }
1220
1221 if (printLevel >= 1)
1222 {
1223 asimovData->Print();
1224 }
1225 if( TMath::IsNaN(asimovData->sumEntries()) ){
1226 oocoutE(nullptr,Generation) << "sum entries is nan"<< std::endl;
1227 assert(0);
1228 asimovData = nullptr;
1229 }
1230
1231 return asimovData.release();
1232
1233}
1234
1235} // namespace
1236
1237////////////////////////////////////////////////////////////////////////////////
1238/// generate the asimov data for the observables (not the global ones)
1239/// need to deal with the case of a sim pdf
1240/// \param pdf a RooAbsPdf. Can be also a RooSimultaneous, or a RooProPdf of a RooSimultaneous
1241
1243
1244 int printLevel = fgPrintLevel();
1245
1246 RooRealVar weightVar{"binWeightAsimov", "binWeightAsimov", 1, 0, 1.e30};
1247
1248 if (printLevel > 1) oocoutI(nullptr,Generation) <<" Generate Asimov data for observables"<< std::endl;
1249 // RooDataSet *simData = nullptr;
1250 const RooProdPdf *prodPdf = dynamic_cast<const RooProdPdf *>(&pdf);
1251 RooArgList strippedPdfSet("strippedPdfSet");
1252 if (prodPdf) {
1253 RooArgList list(prodPdf->pdfList());
1254 for (auto ele : list) {
1255 const RooAbsPdf *pdfi = dynamic_cast<const RooAbsPdf *>(ele);
1256 if (pdfi->dependsOn(observables))
1257 strippedPdfSet.add(*pdfi);
1258 }
1259 }
1260 RooProdPdf observableProdPdf("observableProdPdf", "observableProdPdf", strippedPdfSet);
1261 const RooAbsPdf *observablePdf;
1262 if (prodPdf) {
1263 if (strippedPdfSet.getSize() == 1)
1264 observablePdf = dynamic_cast<const RooAbsPdf *>(strippedPdfSet.at(0));
1265 else
1267 } else {
1268 observablePdf = &pdf;
1269 }
1270 const RooSimultaneous *simPdf = dynamic_cast<const RooSimultaneous *>(observablePdf);
1271 if (!simPdf) {
1272 // generate data for non sim pdf
1273 return GenerateAsimovDataSinglePdf(*observablePdf, observables, weightVar, nullptr);
1274 }
1275
1276 std::map<std::string, std::unique_ptr<RooDataSet>> asimovDataMap;
1277
1278 //look at category of simpdf
1279 RooCategory& channelCat = const_cast<RooCategory&>(dynamic_cast<const RooCategory&>(simPdf->indexCat()));
1280 int nrIndices = channelCat.numTypes();
1281 if( nrIndices == 0 ) {
1282 oocoutW(nullptr,Generation) << "Simultaneous pdf does not contain any categories." << std::endl;
1283 }
1284 for (int i=0;i<nrIndices;i++){
1285 channelCat.setIndex(i);
1286 //iFrame++;
1287 // Get pdf associated with state from simpdf
1288 RooAbsPdf* pdftmp = simPdf->getPdf(channelCat.getCurrentLabel()) ;
1289 assert(pdftmp != nullptr);
1290
1291 if (printLevel > 1)
1292 {
1293 oocoutI(nullptr,Generation) << "on type " << channelCat.getCurrentLabel() << " " << channelCat.getCurrentIndex() << std::endl;
1294 }
1295
1296 std::unique_ptr<RooDataSet> dataSinglePdf{static_cast<RooDataSet*>(GenerateAsimovDataSinglePdf( *pdftmp, observables, weightVar, &channelCat))};
1297 if (!dataSinglePdf) {
1298 oocoutE(nullptr,Generation) << "Error generating an Asimov data set for pdf " << pdftmp->GetName() << std::endl;
1299 return nullptr;
1300 }
1301
1302 if (asimovDataMap.count(string(channelCat.getCurrentLabel())) != 0) {
1303 oocoutE(nullptr,Generation) << "AsymptoticCalculator::GenerateAsimovData(): The PDF for " << channelCat.getCurrentLabel()
1304 << " was already defined. It will be overridden. The faulty category definitions follow:" << std::endl;
1305 channelCat.Print("V");
1306 }
1307
1308 if (printLevel > 1)
1309 {
1310 oocoutI(nullptr,Generation) << "channel: " << channelCat.getCurrentLabel() << ", data: ";
1311 dataSinglePdf->Print();
1312 ooccoutI(nullptr,Generation) << std::endl;
1313 }
1314
1315 asimovDataMap[string(channelCat.getCurrentLabel())] = std::move(dataSinglePdf);
1316 }
1317
1318 RooArgSet obsAndWeight(observables);
1319 obsAndWeight.add(weightVar);
1320
1321
1322 return new RooDataSet("asimovDataFullModel","asimovDataFullModel",RooArgSet(obsAndWeight,channelCat),
1324}
1325
1326////////////////////////////////////////////////////////////////////////////////
1327/// Make the Asimov data from the ModelConfig and list of poi
1328/// \param realData Real data
1329/// \param model Model config defining the pdf and the parameters
1330/// \param paramValues The snapshot of POI and parameters used for finding the best nuisance parameter values (conditioned at these values)
1331/// \param[out] asimovGlobObs Global observables set to values satisfying the constraints
1332/// \param genPoiValues Optional. A different set of POI values used for generating. By default the same POI are used for generating and for finding the nuisance parameters
1333/// given an observed data set, a model and a snapshot of the poi.
1334/// \return The asimov data set. The user takes ownership.
1335///
1336
1338
1339 int verbose = fgPrintLevel();
1340
1341
1342 RooArgSet poi(*model.GetParametersOfInterest());
1343 poi.assign(paramValues);
1344
1345 // set poi constant for conditional MLE
1346 // need to fit nuisance parameters at their conditional MLE value
1348 for (auto *tmpPar : static_range_cast<RooRealVar *>(poi)) {
1349 tmpPar->setConstant();
1350 if (verbose>0)
1351 oocoutI(nullptr,Generation) << "MakeAsimov: Setting poi " << tmpPar->GetName() << " to a constant value = " << tmpPar->getVal() << std::endl;
1353 }
1354
1355 // find conditional value of the nuisance parameters
1356 bool hasFloatParams = false;
1358 if (model.GetNuisanceParameters()) {
1361 if (!constrainParams.empty()) hasFloatParams = true;
1362
1363 } else {
1364 // Do we have free parameters anyway that need fitting?
1365 std::unique_ptr<RooArgSet> params(model.GetPdf()->getParameters(realData));
1366 for (auto const *rrv : dynamic_range_cast<RooRealVar *>(*params)) {
1367 if ( rrv != nullptr && rrv->isConstant() == false ) { hasFloatParams = true; break; }
1368 }
1369 }
1370 if (hasFloatParams) {
1371 // models need to be fitted to find best nuisance parameter values
1372
1373 TStopwatch tw2; tw2.Start();
1375 if (verbose>0) {
1376 oocoutP(nullptr,Generation) << "MakeAsimov: doing a conditional fit for finding best nuisance values " << std::endl;
1377 minimPrintLevel = verbose;
1378 if (verbose>1) {
1379 oocoutI(nullptr,Generation) << "POI values:\n"; poi.Print("v");
1380 if (verbose > 2) {
1381 oocoutI(nullptr,Generation) << "Nuis param values:\n";
1382 constrainParams.Print("v");
1383 }
1384 }
1385 }
1387 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
1388
1390 std::vector<RooCmdArg> args{
1391 RooFit::Minimizer("",minimizerAlgo.c_str()), // empty mimimizer type to select default
1394 RooFit::Hesse(false),
1396 RooFit::Offset(GetGlobalRooStatsConfig().useLikelihoodOffset),
1398 };
1399
1400 RooLinkedList argList;
1401 for (auto& arg : args) {
1402 argList.Add(&arg);
1403 }
1404 model.fitTo(realData, argList);
1405 if (verbose>0) {
1406 tw2.Stop();
1407 oocoutP(nullptr,Generation) << "fit time : " << tw2.RealTime() << " s (real) " << tw2.CpuTime() << " s (cpu)" << std::endl;
1408 }
1409 if (verbose > 1) {
1410 // after the fit the nuisance parameters will have their best fit value
1411 if (model.GetNuisanceParameters() ) {
1412 oocoutI(nullptr,Generation) << "Nuisance parameters after fit for asimov dataset: " << std::endl;
1413 model.GetNuisanceParameters()->Print("V");
1414 }
1415 }
1416
1417 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(msglevel);
1418
1419 }
1420
1421 // restore the parameters which were set constant
1423
1424 std::unique_ptr<RooArgSet> allParams{model.GetPdf()->getParameters(realData)};
1425
1427
1428 // if a RooArgSet of poi is passed , different poi will be used for generating the Asimov data set
1429 if (genPoiValues) {
1430 allParams->assign(*genPoiValues);
1431 }
1432
1433 // now do the actual generation of the AsimovData Set
1434 // no need to pass parameters values since we have set them before
1435 return MakeAsimovData(model, *allParams, asimovGlobObs);
1436}
1437
1438////////////////////////////////////////////////////////////////////////////////
1439/// \param model ModelConfig that contains the model pdf and the model parameters
1440/// \param allParamValues The parameters of the model will be set to the values given in this set
1441/// \param[out] asimovGlobObs Global observables set to values satisfying the constraints
1442/// \return Asimov data set. The user takes ownership.
1443///
1444/// The parameter values (including the nuisance parameter) can result from a fit to data or be at the nominal values.
1445///
1446
1448
1449 int verbose = fgPrintLevel();
1450
1451 TStopwatch tw;
1452 tw.Start();
1453
1454 // set the parameter values (do I need the poi to be constant ? )
1455 // the nuisance parameter values could be set at their fitted value (the MLE)
1456 if (!allParamValues.empty()) {
1457 std::unique_ptr<RooArgSet> allVars{model.GetPdf()->getVariables()};
1458 allVars->assign(allParamValues);
1459 }
1460
1461
1462 // generate the Asimov data set for the observables
1463 RooAbsData * asimov = GenerateAsimovData(*model.GetPdf() , *model.GetObservables() );
1464
1465 if (verbose>0) {
1466 oocoutI(nullptr,Generation) << "Generated Asimov data for observables "; (model.GetObservables() )->Print();
1467 if (verbose > 1) {
1468 if (asimov->numEntries() == 1 ) {
1469 oocoutI(nullptr,Generation) << "--- Asimov data values \n";
1470 asimov->get()->Print("v");
1471 }
1472 else {
1473 oocoutI(nullptr,Generation) << "--- Asimov data numEntries = " << asimov->numEntries() << " sumOfEntries = " << asimov->sumEntries() << std::endl;
1474 }
1475 tw.Stop();
1476 oocoutI(nullptr,Generation) << "\ttime for generating : " << tw.RealTime() << " s (real) " << tw.CpuTime() << " s (cpu)" << std::endl;
1477 }
1478 }
1479
1480
1481 // Now need to have in ASIMOV the data sets also the global observables
1482 // Their values must be the one satisfying the constraint.
1483 // to do it make a nuisance pdf with all product of constraints and then
1484 // assign to each constraint a glob observable value = to the current fitted nuisance parameter value
1485 // IN general one should solve in general the system of equations f( gobs| nuispar ) = 0 where f are the
1486 // derivatives of the constraint with respect the nuisance parameter and they are evaluated at the best fit nuisance
1487 // parameter points
1488 // As simple solution assume that constrain has a direct dependence on the nuisance parameter, i.e.
1489 // Constraint (gobs, func( nuispar) ) and the condition is satisfied for
1490 // gobs = func( nuispar) where nunispar is at the MLE value
1491
1492
1493 if (model.GetGlobalObservables() && !model.GetGlobalObservables()->empty()) {
1494
1495 if (verbose>1) {
1496 oocoutI(nullptr,Generation) << "Generating Asimov data for global observables " << std::endl;
1497 }
1498
1500
1501 // snapshot data global observables
1503 SetAllConstant(gobs, true);
1504 gobs.snapshot(snapGlobalObsData);
1505
1506
1508 if (model.GetNuisanceParameters()) nuis.add(*model.GetNuisanceParameters());
1509 if (nuis.empty()) {
1510 oocoutW(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData: model does not have nuisance parameters but has global observables"
1511 << " set global observables to model values " << std::endl;
1512 asimovGlobObs.assign(gobs);
1513 return asimov;
1514 }
1515
1516 // part 1: create the nuisance pdf
1517 std::unique_ptr<RooAbsPdf> nuispdf(RooStats::MakeNuisancePdf(model,"TempNuisPdf") );
1518 if (nuispdf == nullptr) {
1519 oocoutF(nullptr, Generation) << "AsymptoticCalculator::MakeAsimovData: model has nuisance parameters and "
1520 "global obs but no nuisance pdf "
1521 << std::endl;
1522 }
1523 // unfold the nuisance pdf if it is a prod pdf
1524 RooArgList pdfList;
1525 RooProdPdf *prod = dynamic_cast<RooProdPdf *>(nuispdf.get());
1526 if (prod ) {
1527 pdfList.add(prod->pdfList());
1528 } else {
1529 // nothing to unfold - just use the pdf
1530 pdfList.add(*nuispdf);
1531 }
1532
1533 for (auto *cterm : static_range_cast<RooAbsPdf *>(pdfList)) {
1534 assert(dynamic_cast<RooAbsPdf *>(static_cast<RooAbsArg *>(cterm)) &&
1535 "AsimovUtils: a factor of the nuisance pdf is not a Pdf!");
1536
1537 if (!cterm->dependsOn(nuis)) continue; // dummy constraints
1538 // skip also the case of uniform components
1539 if (typeid(*cterm) == typeid(RooUniform)) continue;
1540
1541 std::unique_ptr<RooArgSet> cpars(cterm->getParameters(&gobs));
1542 std::unique_ptr<RooArgSet> cgobs(cterm->getObservables(&gobs));
1543 if (cgobs->size() > 1) {
1544 oocoutE(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData: constraint term " << cterm->GetName()
1545 << " has multiple global observables -cannot generate - skip it" << std::endl;
1546 continue;
1547 }
1548 else if (cgobs->empty()) {
1549 oocoutW(nullptr, Generation)
1550 << "AsymptoticCalculator::MakeAsimovData: constraint term " << cterm->GetName()
1551 << " has no global observables - skip it" << std::endl;
1552 continue;
1553 }
1554 // the variable representing the global observable
1555 RooRealVar &rrv = dynamic_cast<RooRealVar &>(*cgobs->first());
1556
1557 // remove the constant parameters in cpars
1559 if (cpars->size() != 1) {
1560 oocoutE(nullptr, Generation)
1561 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1562 << cterm->GetName() << " has multiple floating params - cannot generate - skip it " << std::endl;
1563 continue;
1564 }
1565
1566 bool foundServer = false;
1567 // note : this will work only for this type of constraints
1568 // expressed as RooPoisson, RooGaussian, RooLognormal, RooGamma
1569 TClass * cClass = cterm->IsA();
1570 if (verbose > 2) oocoutI(nullptr,Generation) << "Constraint " << cterm->GetName() << " of type " << cClass->GetName() << std::endl;
1574 TString className = (cClass) ? cClass->GetName() : "undefined";
1575 oocoutW(nullptr, Generation)
1576 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1577 << cterm->GetName() << " of type " << className
1578 << " is a non-supported type - result might be not correct " << std::endl;
1579 }
1580
1581 // in case of a Poisson constraint make sure the rounding is not set
1582 if (cClass == RooPoisson::Class() ) {
1583 RooPoisson * pois = static_cast<RooPoisson*>(cterm);
1584 assert(dynamic_cast<RooPoisson *>(cterm));
1585 pois->setNoRounding(true);
1586 }
1587
1588 // look at server of the constraint term and check if the global observable is part of the server
1589 RooAbsArg * arg = cterm->findServer(rrv);
1590 if (!arg) {
1591 // special case is for the Gamma where one might define the global observable n and you have a Gamma(b, n+1, ...._
1592 // in this case n+1 is the server and we don;t have a direct dependency, but we want to set n to the b value
1593 // so in case of the Gamma ignore this test
1594 if ( cClass != RooGamma::Class() ) {
1595 oocoutE(nullptr, Generation)
1596 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1597 << cterm->GetName() << " has no direct dependence on global observable- cannot generate it " << std::endl;
1598 continue;
1599 }
1600 }
1601
1602 // loop on the server of the constraint term
1603 // need to treat the Gamma as a special case
1604 // the mode of the Gamma is (k-1)*theta where theta is the inverse of the rate parameter.
1605 // we assume that the global observable is defined as ngobs = k-1 and the theta parameter has the name theta otherwise we use other procedure which might be wrong
1606 RooAbsReal * thetaGamma = nullptr;
1607 if ( cClass == RooGamma::Class() ) {
1608 for (RooAbsArg *a2 : cterm->servers()) {
1609 if (TString(a2->GetName()).Contains("theta") ) {
1610 thetaGamma = dynamic_cast<RooAbsReal*>(a2);
1611 break;
1612 }
1613 }
1614 if (thetaGamma == nullptr) {
1615 oocoutI(nullptr, Generation)
1616 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1617 << cterm->GetName() << " is a Gamma distribution and no server named theta is found. Assume that the Gamma scale is 1 " << std::endl;
1618 }
1619 else if (verbose>2) {
1620 oocoutI(nullptr,Generation) << "Gamma constraint has a scale " << thetaGamma->GetName() << " = " << thetaGamma->getVal() << std::endl;
1621 }
1622 }
1623 for (RooAbsArg *a2 : cterm->servers()) {
1624 RooAbsReal * rrv2 = dynamic_cast<RooAbsReal *>(a2);
1625 if (verbose > 2) oocoutI(nullptr,Generation) << "Loop on constraint server term " << a2->GetName() << std::endl;
1626 if (rrv2 && rrv2->dependsOn(nuis) ) {
1627
1628
1629 // found server depending on nuisance
1630 if (foundServer) {
1631 oocoutE(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData:constraint term "
1632 << cterm->GetName() << " constraint term has more server depending on nuisance- cannot generate it " <<
1633 std::endl;
1634 foundServer = false;
1635 break;
1636 }
1637 if (thetaGamma && thetaGamma->getVal() > 0) {
1638 rrv.setVal( rrv2->getVal() / thetaGamma->getVal() );
1639 } else {
1640 rrv.setVal(rrv2->getVal());
1641 }
1642 foundServer = true;
1643
1644 if (verbose > 2) {
1645 oocoutI(nullptr,Generation) << "setting global observable " << rrv.GetName() << " to value " << rrv.getVal()
1646 << " which comes from " << rrv2->GetName() << std::endl;
1647 }
1648 }
1649 }
1650
1651 if (!foundServer) {
1652 oocoutE(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData - can't find nuisance for constraint term - global observables will not be set to Asimov value " << cterm->GetName() << std::endl;
1653 oocoutE(nullptr,Generation) << "Parameters: " << std::endl;
1654 cpars->Print("V");
1655 oocoutE(nullptr,Generation) << "Observables: " << std::endl;
1656 cgobs->Print("V");
1657 }
1658 }
1659
1660 // make a snapshot of global observables
1661 // needed this ?? (LM)
1662
1663 asimovGlobObs.removeAll();
1664 SetAllConstant(gobs, true);
1665 gobs.snapshot(asimovGlobObs);
1666
1667 // revert global observables to the data value
1668 gobs.assign(snapGlobalObsData);
1669
1670 if (verbose>0) {
1671 oocoutI(nullptr,Generation) << "Generated Asimov data for global observables ";
1672 if (verbose == 1) gobs.Print();
1673 }
1674
1675 if (verbose > 1) {
1676 oocoutI(nullptr,Generation) << "\nGlobal observables for data: " << std::endl;
1677 gobs.Print("V");
1678 oocoutI(nullptr,Generation) << "\nGlobal observables for asimov: " << std::endl;
1679 asimovGlobObs.Print("V");
1680 }
1681
1682
1683 }
1684
1685 return asimov;
1686
1687}
#define f(i)
Definition RSha256.hxx:104
#define a(i)
Definition RSha256.hxx:99
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define oocoutW(o, a)
#define oocoutE(o, a)
#define oocoutF(o, a)
#define oocoutI(o, a)
#define ooccoutI(o, a)
#define ooccoutP(o, a)
#define oocoutP(o, a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void 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 offset
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 char Point_t Rectangle_t WindowAttributes_t index
Class for finding the root of a one dimensional function using the Brent algorithm.
static const std::string & DefaultMinimizerAlgo()
Template class to wrap any C++ callable object which takes one argument i.e.
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
bool contains(const char *name) const
Check if collection contains an argument with a specific name.
virtual void removeAll()
Remove all arguments from our set, deleting them if we own them.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
RooAbsArg * first() const
void Print(Option_t *options=nullptr) const override
This method must be overridden when a class wants to print itself.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:56
virtual double sumEntries() const =0
Return effective number of entries in dataset, i.e., sum all weights.
virtual const RooArgSet * get() const
Definition RooAbsData.h:100
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
virtual double expectedEvents(const RooArgSet *nset) const
Return expected number of events to be used in calculation of extended likelihood.
bool canBeExtended() const
If true, PDF can provide extended likelihood term.
Definition RooAbsPdf.h:214
static constexpr int DefaultNBins
Historical default number of bins, injected by routines that need a concrete bin count when a variabl...
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
static bool hideOffset()
static void setHideOffset(bool flag)
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:159
static TClass * Class()
Object to represent discrete states.
Definition RooCategory.h:28
static TClass * Class()
Container class to hold unbinned data.
Definition RooDataSet.h:32
static TClass * Class()
Plain Gaussian p.d.f.
Definition RooGaussian.h:24
static TClass * Class()
RooAbsReal const & getX() const
Get the x variable.
Definition RooGaussian.h:45
RooAbsReal const & getMean() const
Get the mean parameter.
Definition RooGaussian.h:48
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
virtual void Add(TObject *arg)
static TClass * Class()
Wrapper class around ROOT::Math::Minimizer that provides a seamless interface between the minimizer f...
static RooMsgService & instance()
Return reference to singleton instance.
Multivariate Gaussian p.d.f.
Poisson pdf.
Definition RooPoisson.h:18
RooAbsReal const & getX() const
Get the x variable.
Definition RooPoisson.h:44
static TClass * Class()
RooAbsReal const & getMean() const
Get the mean parameter.
Definition RooPoisson.h:47
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:35
const RooArgList & pdfList() const
Definition RooProdPdf.h:69
Variable that can be changed from the outside.
Definition RooRealVar.h:37
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
std::unique_ptr< RooFitResult > fFitResultCondObs
! result of conditional fit to observed data
std::unique_ptr< RooFitResult > fFitResultUncondAsimov
! result of fit to Asimov data at the alt POI
static double GetExpectedPValues(double pnull, double palt, double nsigma, bool usecls, bool oneSided=true)
function given the null and the alt p value - return the expected one given the N - sigma value
std::unique_ptr< RooFitResult > fFitResultCondAsimov
! result of conditional fit to Asimov data
static void SetPrintLevel(int level)
set print level (static function)
RooArgSet fAsimovGlobObs
snapshot of Asimov global observables
static RooAbsData * GenerateAsimovData(const RooAbsPdf &pdf, const RooArgSet &observables)
generate the asimov data for the observables (not the global ones) need to deal with the case of a si...
int fUseQTilde
flag to indicate if using qtilde or not (-1 (default based on RooRealVar)), 0 false,...
bool fIsInitialized
! flag to check if calculator is initialized
HypoTestResult * GetHypoTest() const override
re-implement HypoTest computation using the asymptotic
bool fOneSided
for one sided PL test statistic (upper limits)
RooArgSet fBestFitParams
snapshot of all best fitted Parameter values
AsymptoticCalculator(RooAbsData &data, const ModelConfig &altModel, const ModelConfig &nullModel, bool nominalAsimov=false)
constructor for asymptotic calculator from Data set and ModelConfig
std::unique_ptr< RooFitResult > fFitResultUncondObs
! result of unconditional fit to observed data
bool fSigned
use signed (uncapped) PL test statistic
bool fOneSidedDiscovery
for one sided PL test statistic (for discovery)
RooAbsData * fAsimovData
asimov data set
RooArgSet fBestFitPoi
snapshot of best fitted POI values
static RooAbsData * MakeAsimovData(RooAbsData &data, const ModelConfig &model, const RooArgSet &poiValues, RooArgSet &globObs, const RooArgSet *genPoiValues=nullptr)
Make Asimov data.
bool fNominalAsimov
make Asimov at nominal parameter values
bool Initialize() const
initialize the calculator by performing a global fit and make the Asimov data set
Common base class for the Hypothesis Test Calculators.
const ModelConfig * GetNullModel(void) const
const ModelConfig * GetAlternateModel(void) const
HypoTestResult is a base class for results from hypothesis tests.
virtual double CLs() const
is simply (not a method, but a quantity)
< A class that holds configuration information for a model using a workspace as a store
Definition ModelConfig.h:34
std::unique_ptr< RooFitResult > fitTo(RooAbsData &data, CmdArgs_t const &...cmdArgs) const
Wrapper around RooAbsPdf::fitTo(), where the pdf and some configuration options are retrieved from th...
const RooArgSet * GetGlobalObservables() const
get RooArgSet for global observables (return nullptr if not existing)
const RooArgSet * GetParametersOfInterest() const
get RooArgSet containing the parameter of interest (return nullptr if not existing)
const RooArgSet * GetNuisanceParameters() const
get RooArgSet containing the nuisance parameters (return nullptr if not existing)
const RooArgSet * GetObservables() const
get RooArgSet for observables (return nullptr if not existing)
RooAbsPdf * GetPdf() const
get model PDF (return nullptr if pdf has not been specified or does not exist)
Flat p.d.f.
Definition RooUniform.h:24
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
Stopwatch class.
Definition TStopwatch.h:28
Basic string class.
Definition TString.h:138
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:2459
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:643
RooCmdArg Index(RooCategory &icat)
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Import(const char *state, TH1 &histo)
RooCmdArg Offset(std::string const &mode)
RooCmdArg Constrain(const RooArgSet &params)
RooCmdArg Minimizer(const char *type, const char *alg=nullptr)
RooCmdArg Hesse(bool flag=true)
RooCmdArg Strategy(Int_t code)
RooCmdArg EvalErrorWall(bool flag)
RooCmdArg PrintLevel(Int_t code)
double normal_cdf_c(double x, double sigma=1, double x0=0)
Complement of the cumulative distribution function of the normal (Gaussian) distribution (upper tail)...
double normal_cdf(double x, double sigma=1, double x0=0)
Cumulative distribution function of the normal (Gaussian) distribution (lower tail).
double normal_quantile(double z, double sigma)
Inverse ( ) of the cumulative distribution function of the lower tail of the normal (Gaussian) distri...
double normal_quantile_c(double z, double sigma)
Inverse ( ) of the cumulative distribution function of the upper tail of the normal (Gaussian) distri...
Double_t x[n]
Definition legend1.C:17
double nll(double pdf, double weight, int binnedL, int doBinOffset)
Definition MathFuncs.h:449
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
Namespace for the RooStats classes.
Definition CodegenImpl.h:66
bool SetAllConstant(const RooAbsCollection &coll, bool constant=true)
utility function to set all variable constant in a collection (from G.
void RemoveConstantParameters(RooArgSet *set)
std::string const & NLLOffsetMode()
Test what offsetting mode RooStats should use by default.
RooAbsPdf * MakeNuisancePdf(RooAbsPdf &pdf, const RooArgSet &observables, const char *name)
extract constraint terms from pdf
RooStatsConfig & GetGlobalRooStatsConfig()
Retrieve the config object which can be used to set flags for things like offsetting the likelihood o...
Bool_t IsNaN(Double_t x)
Definition TMath.h:905
Double_t QuietNaN()
Returns a quiet NaN as defined by IEEE 754.
Definition TMath.h:915
PaltFunction(double offset, double pval, int icase)