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 TString minimizer = ""; // empty string to take RooMinimizer default initially
411
412 if (verbose > 0) {
413 oocoutP(nullptr,Eval) << "AsymptoticCalculator::EvaluateNLL ........ using " << minimizer << " / " << algorithm
414 << " with strategy " << strategy << " and tolerance " << tol << std::endl;
415 }
416
417 for (int tries = 1, maxtries = 4; tries <= maxtries; ++tries) {
418 // status = minim.minimize(fMinimizer, ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo().c_str());
419 status = minim.minimize(minimizer, algorithm);
420 // RooMinimizer::minimize returns -1 when the fit fails
421 if (status >= 0) {
422 break;
423 } else {
424 if (tries == 1) {
425 oocoutW(nullptr,Minimization) << " ----> Doing a re-scan first" << std::endl;
426 minim.minimize(minimizer,"Scan");
427 }
428 if (tries == 2) {
430 oocoutW(nullptr,Minimization) << " ----> trying with strategy = 1" << std::endl;
431 minim.setStrategy(1);
432 }
433 else
434 tries++; // skip this trial if strategy is already 1
435 }
436 if (tries == 3) {
437 oocoutW(nullptr,Minimization) << " ----> trying with improve" << std::endl;
438 minimizer = "Minuit";
439 algorithm = "migradimproved";
440 }
441 }
442 }
443
444 // save the fit result also in case of failure, so that the status of a
445 // non-converged fit can be inspected by the user
446 std::unique_ptr<RooFitResult> result{minim.save()};
447
448 // ignore errors in Hesse or in Improve and also when matrix was made pos def (status returned = 1)
449 if (status >= 0 && result) {
450 if (RooStats::NLLOffsetMode() != "initial") {
451 val = result->minNll();
452 } else {
455 val = nll->getVal();
457 }
458
459 } else {
460 oocoutE(nullptr,Fitting) << "FIT FAILED !- return a NaN NLL " << std::endl;
461 val = TMath::QuietNaN();
462 }
463
464 if (fitResult)
465 *fitResult = std::move(result);
466 }
467
468 double muTest = 0;
469 if (verbose > 0) {
470 oocoutP(nullptr,Eval) << "AsymptoticCalculator::EvaluateNLL - value = " << val;
471 if (poiSet) {
472 muTest = ( static_cast<RooRealVar*>(poiSet->first()) )->getVal();
473 ooccoutP(nullptr,Eval) << " for poi fixed at = " << muTest;
474 }
475 if (!skipFit) {
476 tw.Stop();
477 ooccoutP(nullptr,Eval) << "\tfit time : " << tw.RealTime() << " s (real) " << tw.CpuTime() << " s (cpu)" << std::endl;
478 } else {
479 ooccoutP(nullptr,Eval) << std::endl;
480 }
481 }
482
483 // reset the parameter free which where set as constant
485
486
487 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(msglevel);
488
489 return val;
490}
491
492} // namespace
493
494////////////////////////////////////////////////////////////////////////////////
495/// It performs an hypothesis tests using the likelihood function
496/// and computes the p values for the null and the alternate using the asymptotic
497/// formulae for the profile likelihood ratio.
498/// See G. Cowan, K. Cranmer, E. Gross and O. Vitells.
499/// Asymptotic formulae for likelihood- based tests of new physics. Eur. Phys. J., C71:1–19, 2011.
500/// The formulae are valid only for one POI. If more than one POI exists consider as POI only the
501/// first one
502
504 int verbose = fgPrintLevel();
505
506 // re-initialized the calculator in case it is needed (pdf or data modified)
507 if (!fIsInitialized) {
508 if (!Initialize() ) {
509 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::GetHypoTest - Error initializing Asymptotic calculator - return nullptr result " << std::endl;
510 return nullptr;
511 }
512 }
513
514 if (!fAsimovData) {
515 oocoutE(nullptr,InputArguments) << "AsymptoticCalculator::GetHypoTest - Asimov data set has not been generated - return nullptr result " << std::endl;
516 return nullptr;
517 }
518
520 assert(GetData() );
521
522 RooAbsPdf * nullPdf = GetNullModel()->GetPdf();
524
525 // make conditional fit on null snapshot of poi
526
527 const RooArgSet * nullSnapshot = GetNullModel()->GetSnapshot();
528 assert(nullSnapshot && !nullSnapshot->empty());
529
530 // use as POI the nullSnapshot
531 // if more than one POI exists, consider only the first one
533
534 if (poiTest.size() > 1) {
535 oocoutW(nullptr,InputArguments) << "AsymptoticCalculator::GetHypoTest: snapshot has more than one POI - assume as POI first parameter " << std::endl;
536 }
537
538 std::unique_ptr<RooArgSet> allParams{nullPdf->getParameters(*GetData() )};
539 allParams->assign(fBestFitParams);
540
541 // set the one-side condition
542 // (this works when we have only one params of interest
543 RooRealVar * muHat = dynamic_cast<RooRealVar*> ( fBestFitPoi.first() );
544 assert(muHat && "no best fit parameter defined");
545 RooRealVar * muTest = dynamic_cast<RooRealVar*> ( nullSnapshot->find(muHat->GetName() ) );
546 assert(muTest && "poi snapshot is not existing");
547
548
549
550 if (verbose> 0) {
551 oocoutI(nullptr,Eval) << "\nAsymptoticCalculator::GetHypoTest: - perform an hypothesis test for POI ( " << muTest->GetName() << " ) = " << muTest->getVal() << std::endl;
552 oocoutP(nullptr,Eval) << "AsymptoticCalculator::GetHypoTest - Find best conditional NLL on OBSERVED data set ..... " << std::endl;
553 }
554
555 // evaluate the conditional NLL on the observed data for the snapshot value
556 double condNLL = EvaluateNLL(*GetNullModel(), const_cast<RooAbsData &>(*GetData()), &poiTest, &fFitResultCondObs);
557 if (fFitResultCondObs) {
558 fFitResultCondObs->SetName("fitResultCondObs");
559 fFitResultCondObs->SetTitle(
560 TString::Format("Conditional fit to observed data for %s = %g", muTest->GetName(), muTest->getVal()));
561 }
562
563 double qmu = 2.*(condNLL - fNLLObs);
564
565
566
567 if (verbose > 0)
568 oocoutP(nullptr,Eval) << "\t OBSERVED DATA : qmu = " << qmu << " condNLL = " << condNLL << " uncond " << fNLLObs << std::endl;
569
570
571 // this tolerance is used to avoid having negative qmu due to numerical errors
572 double tol = 2.E-3 * std::max(1.,ROOT::Math::MinimizerOptions::DefaultTolerance());
573 if (qmu < -tol || TMath::IsNaN(fNLLObs) ) {
574
575 if (qmu < 0) {
576 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: Found a negative value of the qmu - retry to do the unconditional fit "
577 << std::endl;
578 } else {
579 oocoutW(nullptr, Minimization)
580 << "AsymptoticCalculator: unconditional fit failed before - retry to do it now " << std::endl;
581 }
582
583 std::unique_ptr<RooFitResult> refitResult;
584 double nll = EvaluateNLL(*GetNullModel(), const_cast<RooAbsData &>(*GetData()), nullptr, &refitResult);
585
586 if (nll < fNLLObs || (TMath::IsNaN(fNLLObs) && !TMath::IsNaN(nll) ) ) {
587 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: Found a better unconditional minimum "
588 << " old NLL = " << fNLLObs << " old muHat " << muHat->getVal() << std::endl;
589
590 // update values
591 fNLLObs = nll;
592 if (refitResult) {
593 fFitResultUncondObs = std::move(refitResult);
594 fFitResultUncondObs->SetName("fitResultUncondObs");
595 fFitResultUncondObs->SetTitle("Unconditional fit to observed data");
596 }
597 const RooArgSet * poi = GetNullModel()->GetParametersOfInterest();
598 assert(poi);
600 poi->snapshot(fBestFitPoi);
601 // restore also muHad since previous pointer has been deleted
602 muHat = dynamic_cast<RooRealVar*> ( fBestFitPoi.first() );
603 assert(muHat);
604
605 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: New minimum found for "
606 << " NLL = " << fNLLObs << " muHat " << muHat->getVal() << std::endl;
607
608
609 qmu = 2.*(condNLL - fNLLObs);
610
611 if (verbose > 0)
612 oocoutP(nullptr,Eval) << "After unconditional refit, new qmu value is " << qmu << std::endl;
613
614 }
615 }
616
617 if (qmu < -tol ) {
618 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: qmu is still < 0 for mu = "
619 << muTest->getVal() << " return a dummy result "
620 << std::endl;
621 return new HypoTestResult();
622 }
623 if (TMath::IsNaN(qmu) ) {
624 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: failure in fitting for qmu or qmuA "
625 << muTest->getVal() << " return a dummy result "
626 << std::endl;
627 return new HypoTestResult();
628 }
629
630
631
632
633
634 // compute conditional ML on Asimov data set
635 // (need to const cast because it uses fitTo which is a non const method
636 // RooArgSet asimovGlobObs;
637 // RooAbsData * asimovData = (const_cast<AsymptoticCalculator*>(this))->MakeAsimovData( poi, asimovGlobObs);
638 // set global observables to their Asimov values
641 if (GetNullModel()->GetGlobalObservables() ) {
642 globObs.add(*GetNullModel()->GetGlobalObservables());
643 // store previous snapshot value
644 globObs.snapshot(globObsSnapshot);
645 globObs.assign(fAsimovGlobObs);
646 }
647
648
649 if (verbose > 0) oocoutP(nullptr,Eval) << "AsymptoticCalculator::GetHypoTest -- Find best conditional NLL on ASIMOV data set .... " << std::endl;
650
653 fFitResultCondAsimov->SetName("fitResultCondAsimov");
654 fFitResultCondAsimov->SetTitle(
655 TString::Format("Conditional fit to Asimov data for %s = %g", muTest->GetName(), muTest->getVal()));
656 }
657
658 double qmu_A = 2.*(condNLL_A - fNLLAsimov );
659
660 if (verbose > 0)
661 oocoutP(nullptr,Eval) << "\t ASIMOV data qmu_A = " << qmu_A << " condNLL = " << condNLL_A << " uncond " << fNLLAsimov << std::endl;
662
663 if (qmu_A < -tol || TMath::IsNaN(fNLLAsimov) ) {
664
665 if (qmu_A < 0) {
666 oocoutW(nullptr, Minimization)
667 << "AsymptoticCalculator: Found a negative value of the qmu Asimov- retry to do the unconditional fit "
668 << std::endl;
669 } else {
670 oocoutW(nullptr, Minimization)
671 << "AsymptoticCalculator: Fit failed for unconditional the qmu Asimov- retry unconditional fit "
672 << std::endl;
673 }
674
675 std::unique_ptr<RooFitResult> refitResult;
676 double nll = EvaluateNLL(*GetNullModel(), *fAsimovData, nullptr, &refitResult);
677
678 if (nll < fNLLAsimov || (TMath::IsNaN(fNLLAsimov) && !TMath::IsNaN(nll) )) {
679 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: Found a better unconditional minimum for Asimov data set"
680 << " old NLL = " << fNLLAsimov << std::endl;
681
682 // update values
683 fNLLAsimov = nll;
684 if (refitResult) {
686 fFitResultUncondAsimov->SetName("fitResultUncondAsimov");
687 fFitResultUncondAsimov->SetTitle("Unconditional fit to Asimov data");
688 }
689
690 oocoutW(nullptr,Minimization) << "AsymptoticCalculator: New minimum found for "
691 << " NLL = " << fNLLAsimov << std::endl;
692 qmu_A = 2.*(condNLL_A - fNLLAsimov);
693
694 if (verbose > 0)
695 oocoutP(nullptr,Eval) << "After unconditional Asimov refit, new qmu_A value is " << qmu_A << std::endl;
696
697 }
698 }
699
700 if (qmu_A < - tol) {
701 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: qmu_A is still < 0 for mu = "
702 << muTest->getVal() << " return a dummy result "
703 << std::endl;
704 return new HypoTestResult();
705 }
706 if (TMath::IsNaN(qmu) ) {
707 oocoutE(nullptr,Minimization) << "AsymptoticCalculator: failure in fitting for qmu or qmuA "
708 << muTest->getVal() << " return a dummy result "
709 << std::endl;
710 return new HypoTestResult();
711 }
712
713
714 // restore previous value of global observables
715 globObs.assign(globObsSnapshot);
716
717 // now we compute p-values using the asymptotic formulae
718 // described in the paper
719 // Cowan et al, Eur.Phys.J. C (2011) 71:1554
720
721 // first try to guess automatically if needed to use qtilde (or ttilde in case of two sided)
722 // if explicitly fUseQTilde this was not set
723 // qtilde is in this case used if poi is bounded at the value of the alt hypothesis
724 // for Qtilde (need to distinguish case when qmu > qmuA = mu^2/ sigma^2)
725 // (see Cowan et al, Eur.Phys.J. C(2011) 71:1554 paper equations 64 and 65
726 // (remember qmu_A = mu^2/sigma^2 )
727 bool useQTilde = false;
728 // default case (check if poi is limited or not to a zero value)
729 if (!fOneSidedDiscovery) { // qtilde is not a discovery test
730 if (fUseQTilde == -1 && !fOneSidedDiscovery) {
731 // alternate snapshot is value for which background is zero (for limits)
732 RooRealVar * muAlt = dynamic_cast<RooRealVar*>(GetAlternateModel()->GetSnapshot()->first() );
733 // null snapshot is value for which background is zero (for discovery)
734 //RooRealVar * muNull = dynamic_cast<RooRealVar*>(GetNullModel()->GetSnapshot()->first() );
735 assert(muAlt != nullptr );
736 if (muTest->getMin() == muAlt->getVal() ) {
737 fUseQTilde = 1;
738 oocoutI(nullptr,InputArguments) << "Minimum of POI is " << muTest->getMin() << " corresponds to alt snapshot - using qtilde asymptotic formulae " << std::endl;
739 } else {
740 fUseQTilde = 0;
741 oocoutI(nullptr,InputArguments) << "Minimum of POI is " << muTest->getMin() << " is different to alt snapshot " << muAlt->getVal()
742 << " - using standard q asymptotic formulae " << std::endl;
743 }
744 }
746 }
747
748 // check for one side condition (remember this is valid only for one poi)
749 // for a signed (uncapped) test statistic the sign of sqrt(qmu) is flipped instead of setting qmu to zero
750 bool flipSign = false;
751 if (fOneSided ) {
752 if ( muHat->getVal() > muTest->getVal() ) {
753 if (fSigned) {
754 oocoutI(nullptr, Eval) << "Using signed one-sided qmu - flipping the sign of the test statistic muHat = "
755 << muHat->getVal() << " muTest = " << muTest->getVal() << std::endl;
756 flipSign = true;
757 } else {
758 oocoutI(nullptr, Eval) << "Using one-sided qmu - setting qmu to zero muHat = " << muHat->getVal()
759 << " muTest = " << muTest->getVal() << std::endl;
760 qmu = 0;
761 }
762 }
763 }
764 if (fOneSidedDiscovery ) {
765 if ( muHat->getVal() < muTest->getVal() ) {
766 if (fSigned) {
767 oocoutI(nullptr, Eval)
768 << "Using signed one-sided discovery qmu - flipping the sign of the test statistic muHat = "
769 << muHat->getVal() << " muTest = " << muTest->getVal() << std::endl;
770 flipSign = true;
771 } else {
772 oocoutI(nullptr, Eval) << "Using one-sided discovery qmu - setting qmu to zero muHat = " << muHat->getVal()
773 << " muTest = " << muTest->getVal() << std::endl;
774 qmu = 0;
775 }
776 }
777 }
778
779 // fix for negative qmu values due to numerical errors
780 if (qmu < 0 && qmu > -tol) qmu = 0;
782
783 // asymptotic formula for pnull and from paper Eur.Phys.J C 2011 71:1554
784 // we have 4 different cases:
785 // t(mu), t_tilde(mu) for the 2-sided
786 // q(mu) and q_tilde(mu) for the one -sided test statistics
787
788 double pnull = -1;
789 double palt = -1;
790
791 // asymptotic formula for pnull (for only one POI)
792 // From fact that qmu is a chi2 with ndf=1
793
794 // for the signed test statistic, sqrtqmu becomes negative when the best fit
795 // value is beyond the tested value; the Gaussian asymptotic formulae below
796 // remain valid also in that case
797 double sqrtqmu = (qmu > 0) ? std::sqrt(qmu) : 0;
798 if (flipSign)
799 sqrtqmu = -sqrtqmu;
800 double sqrtqmu_A = (qmu_A > 0) ? std::sqrt(qmu_A) : 0;
801
802
804 // for one-sided PL (q_mu : equations 56,57)
805 if (verbose>2) {
806 if (fOneSided) {
807 oocoutI(nullptr,Eval) << "Using one-sided limit asymptotic formula (qmu)" << std::endl;
808 } else {
809 oocoutI(nullptr, Eval) << "Using one-sided discovery asymptotic formula (q0)" << std::endl;
810 }
811 }
814 }
815 else {
816 // for 2-sided PL (t_mu : equations 35,36 in asymptotic paper)
817 if (verbose > 2) oocoutI(nullptr,Eval) << "Using two-sided asymptotic formula (tmu)" << std::endl;
821
822 }
823
824 // the qtilde corrections apply when the best fit value is at the boundary
825 // (qmu > qmu_A); they cannot apply when the sign was flipped, because then
826 // the best fit value is on the other side of the tested value
827 if (useQTilde && !flipSign) {
828 if (fOneSided) {
829 // for bounded one-sided (q_mu_tilde: equations 64,65)
830 if ( qmu > qmu_A && (qmu_A > 0 || qmu > tol) ) { // to avoid case 0/0
831 if (verbose > 2) oocoutI(nullptr,Eval) << "Using qmu_tilde (qmu is greater than qmu_A)" << std::endl;
832 pnull = ROOT::Math::normal_cdf_c( (qmu + qmu_A)/(2 * sqrtqmu_A), 1.);
833 palt = ROOT::Math::normal_cdf_c( (qmu - qmu_A)/(2 * sqrtqmu_A), 1.);
834 }
835 }
836 else {
837 // for 2 sided bounded test statistic (N.B there is no one sided discovery qtilde)
838 // t_mu_tilde: equations 43,44 in asymptotic paper
839 if ( qmu > qmu_A && (qmu_A > 0 || qmu > tol) ) {
840 if (verbose > 2) oocoutI(nullptr,Eval) << "Using tmu_tilde (qmu is greater than qmu_A)" << std::endl;
842 ROOT::Math::normal_cdf_c( (qmu + qmu_A)/(2 * sqrtqmu_A), 1.);
844 ROOT::Math::normal_cdf_c( (qmu - qmu_A)/(2 * sqrtqmu_A), 1.);
845 }
846 }
847 }
848
849 // create an HypoTest result but where the sampling distributions are set to zero
850 string resultname = "HypoTestAsymptotic_result";
851 HypoTestResult* res = new HypoTestResult(resultname.c_str(), pnull, palt);
852
853 if (verbose > 0) {
854 oocoutP(nullptr, Eval) << "poi = " << muTest->getVal() << " qmu = " << qmu << " qmu_A = " << qmu_A
855 << " sigma = " << muTest->getVal() / sqrtqmu_A << " CLsplusb = " << pnull
856 << " CLb = " << palt << " CLs = " << res->CLs() << std::endl;
857 }
858
859 return res;
860
861}
862
864 PaltFunction( double offset, double pval, int icase) :
865 fOffset(offset), fPval(pval), fCase(icase) {}
866 double operator() (double x) const {
867 return ROOT::Math::normal_cdf_c(x + fOffset) + ROOT::Math::normal_cdf_c(fCase*(x - fOffset)) - fPval;
868 }
869 double fOffset;
870 double fPval;
871 int fCase;
872};
873
874////////////////////////////////////////////////////////////////////////////////
875/// function given the null and the alt p value - return the expected one given the N - sigma value
876
877double AsymptoticCalculator::GetExpectedPValues(double pnull, double palt, double nsigma, bool useCls, bool oneSided ) {
878 if (oneSided) {
882 if (!useCls) return clsplusb;
883 double clb = ROOT::Math::normal_cdf( nsigma, 1.);
884 return (clb == 0) ? -1 : clsplusb / clb;
885 }
886
887 // case of 2 sided test statistic
888 // need to compute numerically
890 if (sqrttmu == 0) {
891 // here cannot invert the function - skip the point
892 return -1;
893 }
894 // invert formula for palt to get sqrttmu_A
895 PaltFunction f( sqrttmu, palt, -1);
898 brf.SetFunction( wf, 0, 20);
899 bool ret = brf.Solve();
900 if (!ret) {
901 oocoutE(nullptr,Eval) << "Error finding expected p-values - return -1" << std::endl;
902 return -1;
903 }
904 double sqrttmu_A = brf.Root();
905
906 // now invert for expected value
909 brf.SetFunction(wf2,0,20);
910 ret = brf.Solve();
911 if (!ret) {
912 oocoutE(nullptr,Eval) << "Error finding expected p-values - return -1" << std::endl;
913 return -1;
914 }
915 return 2*ROOT::Math::normal_cdf_c( brf.Root(),1.);
916}
917
918namespace {
919
920////////////////////////////////////////////////////////////////////////////////
921/// Fill bins by looping recursively on observables.
922
923void FillBins(const RooAbsPdf & pdf, const RooArgList &obs, RooAbsData & data, int &index, double &binVolume, int &ibin) {
924
925 bool debug = (fgPrintLevel() >= 2);
926
927 RooRealVar * v = dynamic_cast<RooRealVar*>(&(obs[index]) );
928 if (!v) return;
929
930 RooArgSet obstmp(obs);
931 double expectedEvents = pdf.expectedEvents(obstmp);
932
933 if (debug) oocoutI(nullptr,Generation) << "looping on observable " << v->GetName() << std::endl;
934 for (int i = 0; i < v->getBins(); ++i) {
935 v->setBin(i);
936 if (index < int(obs.size()) -1) {
937 index++; // increase index
938 double prevBinVolume = binVolume;
939 binVolume *= v->getBinWidth(i); // increase bin volume
940 FillBins(pdf, obs, data, index, binVolume, ibin);
941 index--; // decrease index
942 binVolume = prevBinVolume; // decrease also bin volume
943 }
944 else {
945
946 // this is now a new bin - compute the pdf in this bin
947 double totBinVolume = binVolume * v->getBinWidth(i);
948 double fval = pdf.getVal(&obstmp)*totBinVolume;
949
950 if (fval*expectedEvents <= 0)
951 {
952 if (fval*expectedEvents < 0) {
953 oocoutW(nullptr,InputArguments)
954 << "AsymptoticCalculator::" << __func__
955 << "(): Bin " << i << " of " << v->GetName() << " has negative expected events! Please check your inputs." << std::endl;
956 }
957 else {
958 oocoutW(nullptr,InputArguments)
959 << "AsymptoticCalculator::" << __func__
960 << "(): Bin " << i << " of " << v->GetName() << " has zero expected events - skip it" << std::endl;
961 }
962 }
963 // have a cut off for overflows ??
964 else {
965 data.add(obs, fval*expectedEvents);
966 }
967
968 if (debug) {
969 oocoutI(nullptr,Generation) << "bin " << ibin << "\t";
970 for (std::size_t j=0; j < obs.size(); ++j) { ooccoutI(nullptr,Generation) << " " << (static_cast<RooRealVar&>( obs[j])).getVal(); }
971 ooccoutI(nullptr,Generation) << " w = " << fval*expectedEvents;
972 ooccoutI(nullptr,Generation) << std::endl;
973 }
974 ibin++;
975 }
976 }
977 //reset bin values
978 if (debug) {
979 oocoutI(nullptr,Generation) << "ending loop on .. " << v->GetName() << std::endl;
980 }
981
982 v->setBin(0);
983
984}
985
986bool setObsToExpected(RooAbsArg &x, RooAbsArg &mean, const RooArgSet &obs, std::string const &errPrefix)
987{
988 // Figure out which of the two arguments is the observable that should be
989 // set to the expected value given by the other one. Usually the observable
990 // is "x", but also the mean parameter can be the observable: this happens
991 // for example in constraint terms, where the global observable takes the
992 // role of the mean.
993 const bool xIsObs = obs.contains(x);
994 const bool meanIsObs = obs.contains(mean);
995 if (xIsObs && meanIsObs) {
996 oocoutF(nullptr, Generation) << errPrefix << "Has two observables ?? " << std::endl;
997 return false;
998 }
999 if (!xIsObs && !meanIsObs) {
1000 oocoutF(nullptr, Generation) << errPrefix << "No observable?" << std::endl;
1001 return false;
1002 }
1003 auto *myobs = dynamic_cast<RooRealVar *>(xIsObs ? &x : &mean);
1004 auto *myexp = dynamic_cast<RooAbsReal *>(xIsObs ? &mean : &x);
1005 if (myobs == nullptr) {
1006 oocoutF(nullptr, Generation) << errPrefix << "Observable is not a RooRealVar??" << std::endl;
1007 return false;
1008 }
1009 if (myexp == nullptr) {
1010 oocoutF(nullptr, Generation) << errPrefix << "Expected is not a RooAbsReal??" << std::endl;
1011 return false;
1012 }
1013
1014 myobs->setVal(myexp->getVal());
1015
1016 if (fgPrintLevel() > 2) {
1017 oocoutI(nullptr,Generation) << "SetObsToExpected : setting " << myobs->GetName() << " to expected value " << myexp->getVal() << " of " << myexp->GetName() << std::endl;
1018 }
1019
1020 return true;
1021}
1022
1023////////////////////////////////////////////////////////////////////////////////
1024/// set observed value to the expected one
1025/// works for Gaussian, Poisson or LogNormal
1026/// need to iterate on the components of the Poisson to get n and nu (nu can be a RooAbsReal)
1027/// (code from G. Petrucciani and extended by L.M.)
1028
1029bool SetObsToExpected(RooGaussian &pdf, const RooArgSet &obs)
1030{
1031 std::string const &errPrefix = "AsymptoticCalculator::SetObsExpected( " + std::string{pdf.ClassName()} + " ) : ";
1032 return setObsToExpected(const_cast<RooAbsReal &>(pdf.getX()), const_cast<RooAbsReal &>(pdf.getMean()), obs,
1033 errPrefix);
1034}
1035
1036bool SetObsToExpected(RooPoisson &pdf, const RooArgSet &obs)
1037{
1038 std::string const &errPrefix = "AsymptoticCalculator::SetObsExpected( " + std::string{pdf.ClassName()} + " ) : ";
1039 return setObsToExpected(const_cast<RooAbsReal &>(pdf.getX()), const_cast<RooAbsReal &>(pdf.getMean()), obs,
1040 errPrefix);
1041}
1042
1044{
1045 // In the case of the multi-variate Gaussian, we need to iterate over the
1046 // dimensions and treat the observable and mean for each dimension
1047 // separately.
1048
1049 std::string const &errPrefix = "AsymptoticCalculator::SetObsExpected( " + std::string{mvgauss.ClassName()} + " ) : ";
1050 bool ret = true;
1051 for (std::size_t iDim = 0; iDim < mvgauss.xVec().size(); ++iDim) {
1052 ret &= setObsToExpected(mvgauss.xVec()[iDim], mvgauss.muVec()[iDim], obs,
1053 errPrefix + " : dim " + std::to_string(iDim) + " ");
1054 }
1055 return ret;
1056}
1057
1058////////////////////////////////////////////////////////////////////////////////
1059/// Inpspect a product pdf to find all the Poisson or Gaussian parts to set the observed
1060/// values to expected ones.
1061
1062bool setObsToExpectedProdPdf(RooProdPdf &prod, const RooArgSet &obs)
1063{
1064 bool ret = true;
1065 for (auto *a : prod.pdfList()) {
1066 if (!a->dependsOn(obs)) continue;
1067 RooPoisson *pois = nullptr;
1068 RooGaussian *gauss = nullptr;
1069 RooMultiVarGaussian *mvgauss = nullptr;
1070 // should try to add also lognormal case ?
1071 if ((pois = dynamic_cast<RooPoisson *>(a)) != nullptr) {
1072 ret &= SetObsToExpected(*pois, obs);
1073 pois->setNoRounding(true); //needed since expected value is not an integer
1074 } else if ((gauss = dynamic_cast<RooGaussian *>(a)) != nullptr) {
1075 ret &= SetObsToExpected(*gauss, obs);
1076 } else if ((mvgauss = dynamic_cast<RooMultiVarGaussian *>(a)) != nullptr) {
1078 } else if (RooProdPdf *subprod = dynamic_cast<RooProdPdf *>(a)) {
1080 } else {
1081 oocoutE(nullptr, InputArguments)
1082 << "Illegal term in counting model: "
1083 << "the PDF " << a->GetName() << " depends on the observables, but is not a Poisson, Gaussian or Product"
1084 << std::endl;
1085 return false;
1086 }
1087 }
1088
1089 return ret;
1090}
1091
1092////////////////////////////////////////////////////////////////////////////////
1093/// Generate counting Asimov data for the case when the pdf cannot be extended.
1094/// This function assumes that the pdf is a RooPoisson or can be decomposed in a product of RooPoisson,
1095/// or is a RooGaussian. Otherwise, we cannot know how to make the Asimov data sets.
1096
1098 RooArgSet obs(observables);
1099 RooProdPdf *prod = dynamic_cast<RooProdPdf *>(&pdf);
1100 RooPoisson *pois = nullptr;
1101 RooGaussian *gauss = nullptr;
1102 RooMultiVarGaussian *mvgauss = nullptr;
1103
1104 if (fgPrintLevel() > 1)
1105 oocoutI(nullptr,Generation) << "generate counting Asimov data for pdf of type " << pdf.ClassName() << std::endl;
1106
1107 bool r = false;
1108 if (prod != nullptr) {
1109 r = setObsToExpectedProdPdf(*prod, observables);
1110 } else if ((pois = dynamic_cast<RooPoisson *>(&pdf)) != nullptr) {
1111 r = SetObsToExpected(*pois, observables);
1112 // we need in this case to set Poisson to real values
1113 pois->setNoRounding(true);
1114 } else if ((gauss = dynamic_cast<RooGaussian *>(&pdf)) != nullptr) {
1115 r = SetObsToExpected(*gauss, observables);
1116 } else if ((mvgauss = dynamic_cast<RooMultiVarGaussian *>(&pdf)) != nullptr) {
1117 r = setObsToExpectedMultiVarGauss(*mvgauss, observables);
1118 } else {
1119 oocoutE(nullptr,InputArguments) << "A counting model pdf must be either a RooProdPdf or a RooPoisson or a RooGaussian" << std::endl;
1120 }
1121 if (!r) return nullptr;
1122 int icat = 0;
1123 if (channelCat) {
1124 icat = channelCat->getCurrentIndex();
1125 }
1126
1127 RooDataSet *ret = new RooDataSet("CountingAsimovData" + std::to_string(icat),
1128 "CountingAsimovData" + std::to_string(icat), obs);
1129 ret->add(obs);
1130 return ret;
1131}
1132
1133////////////////////////////////////////////////////////////////////////////////
1134/// Compute the asimov data set for an observable of a pdf.
1135/// It generates binned data following the binning of the observables.
1136// TODO: (possibility to change number of bins)
1137// TODO: implement integration over bin content
1138
1140
1141 int printLevel = fgPrintLevel();
1142
1143 // Get observables defined by the pdf associated with this state
1144 std::unique_ptr<RooArgSet> obs(pdf.getObservables(allobs) );
1145
1146
1147 // if pdf cannot be extended assume is then a counting experiment
1148 if (!pdf.canBeExtended() ) return GenerateCountingAsimovData(const_cast<RooAbsPdf&>(pdf), *obs, weightVar, channelCat);
1149
1150 RooArgSet obsAndWeight(*obs);
1151 obsAndWeight.add(weightVar);
1152
1153 std::unique_ptr<RooDataSet> asimovData;
1154 if (channelCat) {
1155 int icat = channelCat->getCurrentIndex();
1156 asimovData = std::make_unique<RooDataSet>("AsimovData" + std::to_string(icat),
1157 "combAsimovData" + std::to_string(icat),
1159 }
1160 else {
1161 asimovData = std::make_unique<RooDataSet>("AsimovData","AsimovData",RooArgSet(obsAndWeight),RooFit::WeightVar(weightVar));
1162 }
1163
1164 // This works only for 1D observables
1165 //RooRealVar* thisObs = ((RooRealVar*)obstmp->first());
1166
1167 RooArgList obsList(*obs);
1168
1169 // The Asimov data set is built by looping over the bins of the
1170 // observables. A freshly-constructed RooRealVar now defaults to zero bins,
1171 // so temporarily materialize the historical default binning for any
1172 // observable that has no explicit binning set. The change is undone right
1173 // after filling the bins so that the model observables are left untouched.
1174 std::vector<RooRealVar *> obsWithDefaultBinning;
1175 for (auto *arg : obsList) {
1176 auto *rrv = dynamic_cast<RooRealVar *>(arg);
1177 if (rrv && rrv->getBins() == 0) {
1178 rrv->setBins(RooRealVar::DefaultNBins);
1179 obsWithDefaultBinning.push_back(rrv);
1180 }
1181 }
1182
1183 // loop on observables and on the bins
1184 if (printLevel >= 2) {
1185 oocoutI(nullptr,Generation) << "Generating Asimov data for pdf " << pdf.GetName() << std::endl;
1186 oocoutI(nullptr,Generation) << "list of observables " << std::endl;
1187 obsList.Print();
1188 }
1189
1190 int obsIndex = 0;
1191 double binVolume = 1;
1192 int nbins = 0;
1193 FillBins(pdf, obsList, *asimovData, obsIndex, binVolume, nbins);
1194
1195 // restore the zero-bins default on observables that had no explicit binning
1196 for (auto *rrv : obsWithDefaultBinning) {
1197 rrv->setBins(0);
1198 }
1199 if (printLevel >= 2)
1200 oocoutI(nullptr,Generation) << "filled from " << pdf.GetName() << " " << nbins << " nbins " << " volume is " << binVolume << std::endl;
1201
1202 // for (int iobs = 0; iobs < obsList.size(); ++iobs) {
1203 // RooRealVar * thisObs = dynamic_cast<RooRealVar*> &obsList[i];
1204 // if (thisObs == 0) continue;
1205 // // loop on the bin contents
1206 // for(int ibin=0; ibin<thisObs->numBins(); ++ibin){
1207 // thisObs->setBin(ibin);
1208
1209 // thisNorm=pdftmp->getVal(obstmp)*thisObs->getBinWidth(jj);
1210 // if (thisNorm*expectedEvents <= 0)
1211 // {
1212 // std::cout << "WARNING::Detected bin with zero expected events! Please check your inputs." << std::endl;
1213 // }
1214 // // have a cut off for overflows ??
1215 // obsDataUnbinned->add(*mc->GetObservables(), thisNorm*expectedEvents);
1216 // }
1217
1218 if (printLevel >= 1)
1219 {
1220 asimovData->Print();
1221 }
1222 if( TMath::IsNaN(asimovData->sumEntries()) ){
1223 oocoutE(nullptr,Generation) << "sum entries is nan"<< std::endl;
1224 assert(0);
1225 asimovData = nullptr;
1226 }
1227
1228 return asimovData.release();
1229
1230}
1231
1232} // namespace
1233
1234////////////////////////////////////////////////////////////////////////////////
1235/// generate the asimov data for the observables (not the global ones)
1236/// need to deal with the case of a sim pdf
1237/// \param pdf a RooAbsPdf. Can be also a RooSimultaneous, or a RooProPdf of a RooSimultaneous
1238
1240
1241 int printLevel = fgPrintLevel();
1242
1243 RooRealVar weightVar{"binWeightAsimov", "binWeightAsimov", 1, 0, 1.e30};
1244
1245 if (printLevel > 1) oocoutI(nullptr,Generation) <<" Generate Asimov data for observables"<< std::endl;
1246 // RooDataSet *simData = nullptr;
1247 const RooProdPdf *prodPdf = dynamic_cast<const RooProdPdf *>(&pdf);
1248 RooArgList strippedPdfSet("strippedPdfSet");
1249 if (prodPdf) {
1250 RooArgList list(prodPdf->pdfList());
1251 for (auto ele : list) {
1252 const RooAbsPdf *pdfi = dynamic_cast<const RooAbsPdf *>(ele);
1253 if (pdfi->dependsOn(observables))
1254 strippedPdfSet.add(*pdfi);
1255 }
1256 }
1257 RooProdPdf observableProdPdf("observableProdPdf", "observableProdPdf", strippedPdfSet);
1258 const RooAbsPdf *observablePdf;
1259 if (prodPdf) {
1260 if (strippedPdfSet.getSize() == 1)
1261 observablePdf = dynamic_cast<const RooAbsPdf *>(strippedPdfSet.at(0));
1262 else
1264 } else {
1265 observablePdf = &pdf;
1266 }
1267 const RooSimultaneous *simPdf = dynamic_cast<const RooSimultaneous *>(observablePdf);
1268 if (!simPdf) {
1269 // generate data for non sim pdf
1270 return GenerateAsimovDataSinglePdf(*observablePdf, observables, weightVar, nullptr);
1271 }
1272
1273 std::map<std::string, std::unique_ptr<RooDataSet>> asimovDataMap;
1274
1275 //look at category of simpdf
1276 RooCategory& channelCat = const_cast<RooCategory&>(dynamic_cast<const RooCategory&>(simPdf->indexCat()));
1277 int nrIndices = channelCat.numTypes();
1278 if( nrIndices == 0 ) {
1279 oocoutW(nullptr,Generation) << "Simultaneous pdf does not contain any categories." << std::endl;
1280 }
1281 for (int i=0;i<nrIndices;i++){
1282 channelCat.setIndex(i);
1283 //iFrame++;
1284 // Get pdf associated with state from simpdf
1285 RooAbsPdf* pdftmp = simPdf->getPdf(channelCat.getCurrentLabel()) ;
1286 assert(pdftmp != nullptr);
1287
1288 if (printLevel > 1)
1289 {
1290 oocoutI(nullptr,Generation) << "on type " << channelCat.getCurrentLabel() << " " << channelCat.getCurrentIndex() << std::endl;
1291 }
1292
1293 std::unique_ptr<RooDataSet> dataSinglePdf{static_cast<RooDataSet*>(GenerateAsimovDataSinglePdf( *pdftmp, observables, weightVar, &channelCat))};
1294 if (!dataSinglePdf) {
1295 oocoutE(nullptr,Generation) << "Error generating an Asimov data set for pdf " << pdftmp->GetName() << std::endl;
1296 return nullptr;
1297 }
1298
1299 if (asimovDataMap.count(string(channelCat.getCurrentLabel())) != 0) {
1300 oocoutE(nullptr,Generation) << "AsymptoticCalculator::GenerateAsimovData(): The PDF for " << channelCat.getCurrentLabel()
1301 << " was already defined. It will be overridden. The faulty category definitions follow:" << std::endl;
1302 channelCat.Print("V");
1303 }
1304
1305 if (printLevel > 1)
1306 {
1307 oocoutI(nullptr,Generation) << "channel: " << channelCat.getCurrentLabel() << ", data: ";
1308 dataSinglePdf->Print();
1309 ooccoutI(nullptr,Generation) << std::endl;
1310 }
1311
1312 asimovDataMap[string(channelCat.getCurrentLabel())] = std::move(dataSinglePdf);
1313 }
1314
1315 RooArgSet obsAndWeight(observables);
1316 obsAndWeight.add(weightVar);
1317
1318
1319 return new RooDataSet("asimovDataFullModel","asimovDataFullModel",RooArgSet(obsAndWeight,channelCat),
1321}
1322
1323////////////////////////////////////////////////////////////////////////////////
1324/// Make the Asimov data from the ModelConfig and list of poi
1325/// \param realData Real data
1326/// \param model Model config defining the pdf and the parameters
1327/// \param paramValues The snapshot of POI and parameters used for finding the best nuisance parameter values (conditioned at these values)
1328/// \param[out] asimovGlobObs Global observables set to values satisfying the constraints
1329/// \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
1330/// given an observed data set, a model and a snapshot of the poi.
1331/// \return The asimov data set. The user takes ownership.
1332///
1333
1335
1336 int verbose = fgPrintLevel();
1337
1338
1339 RooArgSet poi(*model.GetParametersOfInterest());
1340 poi.assign(paramValues);
1341
1342 // set poi constant for conditional MLE
1343 // need to fit nuisance parameters at their conditional MLE value
1345 for (auto *tmpPar : static_range_cast<RooRealVar *>(poi)) {
1346 tmpPar->setConstant();
1347 if (verbose>0)
1348 oocoutI(nullptr,Generation) << "MakeAsimov: Setting poi " << tmpPar->GetName() << " to a constant value = " << tmpPar->getVal() << std::endl;
1350 }
1351
1352 // find conditional value of the nuisance parameters
1353 bool hasFloatParams = false;
1355 if (model.GetNuisanceParameters()) {
1356 constrainParams.add(*model.GetNuisanceParameters());
1358 if (!constrainParams.empty()) hasFloatParams = true;
1359
1360 } else {
1361 // Do we have free parameters anyway that need fitting?
1362 std::unique_ptr<RooArgSet> params(model.GetPdf()->getParameters(realData));
1363 for (auto const *rrv : dynamic_range_cast<RooRealVar *>(*params)) {
1364 if ( rrv != nullptr && rrv->isConstant() == false ) { hasFloatParams = true; break; }
1365 }
1366 }
1367 if (hasFloatParams) {
1368 // models need to be fitted to find best nuisance parameter values
1369
1370 TStopwatch tw2; tw2.Start();
1372 if (verbose>0) {
1373 oocoutP(nullptr,Generation) << "MakeAsimov: doing a conditional fit for finding best nuisance values " << std::endl;
1374 minimPrintLevel = verbose;
1375 if (verbose>1) {
1376 oocoutI(nullptr,Generation) << "POI values:\n"; poi.Print("v");
1377 if (verbose > 2) {
1378 oocoutI(nullptr,Generation) << "Nuis param values:\n";
1379 constrainParams.Print("v");
1380 }
1381 }
1382 }
1384 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
1385
1387 std::vector<RooCmdArg> args{
1388 RooFit::Minimizer("",minimizerAlgo.c_str()), // empty mimimizer type to select default
1391 RooFit::Hesse(false),
1393 RooFit::Offset(GetGlobalRooStatsConfig().useLikelihoodOffset),
1395 };
1396
1397 RooLinkedList argList;
1398 for (auto& arg : args) {
1399 argList.Add(&arg);
1400 }
1401 model.fitTo(realData, argList);
1402 if (verbose>0) {
1403 tw2.Stop();
1404 oocoutP(nullptr,Generation) << "fit time : " << tw2.RealTime() << " s (real) " << tw2.CpuTime() << " s (cpu)" << std::endl;
1405 }
1406 if (verbose > 1) {
1407 // after the fit the nuisance parameters will have their best fit value
1408 if (model.GetNuisanceParameters() ) {
1409 oocoutI(nullptr,Generation) << "Nuisance parameters after fit for asimov dataset: " << std::endl;
1410 model.GetNuisanceParameters()->Print("V");
1411 }
1412 }
1413
1414 if (verbose < 2) RooMsgService::instance().setGlobalKillBelow(msglevel);
1415
1416 }
1417
1418 // restore the parameters which were set constant
1420
1421 std::unique_ptr<RooArgSet> allParams{model.GetPdf()->getParameters(realData)};
1422
1424
1425 // if a RooArgSet of poi is passed , different poi will be used for generating the Asimov data set
1426 if (genPoiValues) {
1427 allParams->assign(*genPoiValues);
1428 }
1429
1430 // now do the actual generation of the AsimovData Set
1431 // no need to pass parameters values since we have set them before
1432 return MakeAsimovData(model, *allParams, asimovGlobObs);
1433}
1434
1435////////////////////////////////////////////////////////////////////////////////
1436/// \param model ModelConfig that contains the model pdf and the model parameters
1437/// \param allParamValues The parameters of the model will be set to the values given in this set
1438/// \param[out] asimovGlobObs Global observables set to values satisfying the constraints
1439/// \return Asimov data set. The user takes ownership.
1440///
1441/// The parameter values (including the nuisance parameter) can result from a fit to data or be at the nominal values.
1442///
1443
1445
1446 int verbose = fgPrintLevel();
1447
1448 TStopwatch tw;
1449 tw.Start();
1450
1451 // set the parameter values (do I need the poi to be constant ? )
1452 // the nuisance parameter values could be set at their fitted value (the MLE)
1453 if (!allParamValues.empty()) {
1454 std::unique_ptr<RooArgSet> allVars{model.GetPdf()->getVariables()};
1455 allVars->assign(allParamValues);
1456 }
1457
1458
1459 // generate the Asimov data set for the observables
1460 RooAbsData * asimov = GenerateAsimovData(*model.GetPdf() , *model.GetObservables() );
1461
1462 if (verbose>0) {
1463 oocoutI(nullptr,Generation) << "Generated Asimov data for observables "; (model.GetObservables() )->Print();
1464 if (verbose > 1) {
1465 if (asimov->numEntries() == 1 ) {
1466 oocoutI(nullptr,Generation) << "--- Asimov data values \n";
1467 asimov->get()->Print("v");
1468 }
1469 else {
1470 oocoutI(nullptr,Generation) << "--- Asimov data numEntries = " << asimov->numEntries() << " sumOfEntries = " << asimov->sumEntries() << std::endl;
1471 }
1472 tw.Stop();
1473 oocoutI(nullptr,Generation) << "\ttime for generating : " << tw.RealTime() << " s (real) " << tw.CpuTime() << " s (cpu)" << std::endl;
1474 }
1475 }
1476
1477
1478 // Now need to have in ASIMOV the data sets also the global observables
1479 // Their values must be the one satisfying the constraint.
1480 // to do it make a nuisance pdf with all product of constraints and then
1481 // assign to each constraint a glob observable value = to the current fitted nuisance parameter value
1482 // IN general one should solve in general the system of equations f( gobs| nuispar ) = 0 where f are the
1483 // derivatives of the constraint with respect the nuisance parameter and they are evaluated at the best fit nuisance
1484 // parameter points
1485 // As simple solution assume that constrain has a direct dependence on the nuisance parameter, i.e.
1486 // Constraint (gobs, func( nuispar) ) and the condition is satisfied for
1487 // gobs = func( nuispar) where nunispar is at the MLE value
1488
1489
1490 if (model.GetGlobalObservables() && !model.GetGlobalObservables()->empty()) {
1491
1492 if (verbose>1) {
1493 oocoutI(nullptr,Generation) << "Generating Asimov data for global observables " << std::endl;
1494 }
1495
1496 RooArgSet gobs(*model.GetGlobalObservables());
1497
1498 // snapshot data global observables
1500 SetAllConstant(gobs, true);
1501 gobs.snapshot(snapGlobalObsData);
1502
1503
1505 if (model.GetNuisanceParameters()) nuis.add(*model.GetNuisanceParameters());
1506 if (nuis.empty()) {
1507 oocoutW(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData: model does not have nuisance parameters but has global observables"
1508 << " set global observables to model values " << std::endl;
1509 asimovGlobObs.assign(gobs);
1510 return asimov;
1511 }
1512
1513 // part 1: create the nuisance pdf
1514 std::unique_ptr<RooAbsPdf> nuispdf(RooStats::MakeNuisancePdf(model,"TempNuisPdf") );
1515 if (nuispdf == nullptr) {
1516 oocoutF(nullptr, Generation) << "AsymptoticCalculator::MakeAsimovData: model has nuisance parameters and "
1517 "global obs but no nuisance pdf "
1518 << std::endl;
1519 }
1520 // unfold the nuisance pdf if it is a prod pdf
1521 RooArgList pdfList;
1522 RooProdPdf *prod = dynamic_cast<RooProdPdf *>(nuispdf.get());
1523 if (prod ) {
1524 pdfList.add(prod->pdfList());
1525 } else {
1526 // nothing to unfold - just use the pdf
1527 pdfList.add(*nuispdf);
1528 }
1529
1530 for (auto *cterm : static_range_cast<RooAbsPdf *>(pdfList)) {
1531 assert(dynamic_cast<RooAbsPdf *>(static_cast<RooAbsArg *>(cterm)) &&
1532 "AsimovUtils: a factor of the nuisance pdf is not a Pdf!");
1533
1534 if (!cterm->dependsOn(nuis)) continue; // dummy constraints
1535 // skip also the case of uniform components
1536 if (typeid(*cterm) == typeid(RooUniform)) continue;
1537
1538 std::unique_ptr<RooArgSet> cpars(cterm->getParameters(&gobs));
1539 std::unique_ptr<RooArgSet> cgobs(cterm->getObservables(&gobs));
1540 if (cgobs->size() > 1) {
1541 oocoutE(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData: constraint term " << cterm->GetName()
1542 << " has multiple global observables -cannot generate - skip it" << std::endl;
1543 continue;
1544 }
1545 else if (cgobs->empty()) {
1546 oocoutW(nullptr, Generation)
1547 << "AsymptoticCalculator::MakeAsimovData: constraint term " << cterm->GetName()
1548 << " has no global observables - skip it" << std::endl;
1549 continue;
1550 }
1551 // the variable representing the global observable
1552 RooRealVar &rrv = dynamic_cast<RooRealVar &>(*cgobs->first());
1553
1554 // remove the constant parameters in cpars
1556 if (cpars->size() != 1) {
1557 oocoutE(nullptr, Generation)
1558 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1559 << cterm->GetName() << " has multiple floating params - cannot generate - skip it " << std::endl;
1560 continue;
1561 }
1562
1563 bool foundServer = false;
1564 // note : this will work only for this type of constraints
1565 // expressed as RooPoisson, RooGaussian, RooLognormal, RooGamma
1566 TClass * cClass = cterm->IsA();
1567 if (verbose > 2) oocoutI(nullptr,Generation) << "Constraint " << cterm->GetName() << " of type " << cClass->GetName() << std::endl;
1571 TString className = (cClass) ? cClass->GetName() : "undefined";
1572 oocoutW(nullptr, Generation)
1573 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1574 << cterm->GetName() << " of type " << className
1575 << " is a non-supported type - result might be not correct " << std::endl;
1576 }
1577
1578 // in case of a Poisson constraint make sure the rounding is not set
1579 if (cClass == RooPoisson::Class() ) {
1580 RooPoisson * pois = static_cast<RooPoisson*>(cterm);
1581 assert(dynamic_cast<RooPoisson *>(cterm));
1582 pois->setNoRounding(true);
1583 }
1584
1585 // look at server of the constraint term and check if the global observable is part of the server
1586 RooAbsArg * arg = cterm->findServer(rrv);
1587 if (!arg) {
1588 // special case is for the Gamma where one might define the global observable n and you have a Gamma(b, n+1, ...._
1589 // 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
1590 // so in case of the Gamma ignore this test
1591 if ( cClass != RooGamma::Class() ) {
1592 oocoutE(nullptr, Generation)
1593 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1594 << cterm->GetName() << " has no direct dependence on global observable- cannot generate it " << std::endl;
1595 continue;
1596 }
1597 }
1598
1599 // loop on the server of the constraint term
1600 // need to treat the Gamma as a special case
1601 // the mode of the Gamma is (k-1)*theta where theta is the inverse of the rate parameter.
1602 // 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
1603 RooAbsReal * thetaGamma = nullptr;
1604 if ( cClass == RooGamma::Class() ) {
1605 for (RooAbsArg *a2 : cterm->servers()) {
1606 if (TString(a2->GetName()).Contains("theta") ) {
1607 thetaGamma = dynamic_cast<RooAbsReal*>(a2);
1608 break;
1609 }
1610 }
1611 if (thetaGamma == nullptr) {
1612 oocoutI(nullptr, Generation)
1613 << "AsymptoticCalculator::MakeAsimovData:constraint term "
1614 << cterm->GetName() << " is a Gamma distribution and no server named theta is found. Assume that the Gamma scale is 1 " << std::endl;
1615 }
1616 else if (verbose>2) {
1617 oocoutI(nullptr,Generation) << "Gamma constraint has a scale " << thetaGamma->GetName() << " = " << thetaGamma->getVal() << std::endl;
1618 }
1619 }
1620 for (RooAbsArg *a2 : cterm->servers()) {
1621 RooAbsReal * rrv2 = dynamic_cast<RooAbsReal *>(a2);
1622 if (verbose > 2) oocoutI(nullptr,Generation) << "Loop on constraint server term " << a2->GetName() << std::endl;
1623 if (rrv2 && rrv2->dependsOn(nuis) ) {
1624
1625
1626 // found server depending on nuisance
1627 if (foundServer) {
1628 oocoutE(nullptr,Generation) << "AsymptoticCalculator::MakeAsimovData:constraint term "
1629 << cterm->GetName() << " constraint term has more server depending on nuisance- cannot generate it " <<
1630 std::endl;
1631 foundServer = false;
1632 break;
1633 }
1634 if (thetaGamma && thetaGamma->getVal() > 0) {
1635 rrv.setVal( rrv2->getVal() / thetaGamma->getVal() );
1636 } else {
1637 rrv.setVal(rrv2->getVal());
1638 }
1639 foundServer = true;
1640
1641 if (verbose > 2) {
1642 oocoutI(nullptr,Generation) << "setting global observable " << rrv.GetName() << " to value " << rrv.getVal()
1643 << " which comes from " << rrv2->GetName() << std::endl;
1644 }
1645 }
1646 }
1647
1648 if (!foundServer) {
1649 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;
1650 oocoutE(nullptr,Generation) << "Parameters: " << std::endl;
1651 cpars->Print("V");
1652 oocoutE(nullptr,Generation) << "Observables: " << std::endl;
1653 cgobs->Print("V");
1654 }
1655 }
1656
1657 // make a snapshot of global observables
1658 // needed this ?? (LM)
1659
1660 asimovGlobObs.removeAll();
1661 SetAllConstant(gobs, true);
1662 gobs.snapshot(asimovGlobObs);
1663
1664 // revert global observables to the data value
1665 gobs.assign(snapGlobalObsData);
1666
1667 if (verbose>0) {
1668 oocoutI(nullptr,Generation) << "Generated Asimov data for global observables ";
1669 if (verbose == 1) gobs.Print();
1670 }
1671
1672 if (verbose > 1) {
1673 oocoutI(nullptr,Generation) << "\nGlobal observables for data: " << std::endl;
1674 gobs.Print("V");
1675 oocoutI(nullptr,Generation) << "\nGlobal observables for asimov: " << std::endl;
1676 asimovGlobObs.Print("V");
1677 }
1678
1679
1680 }
1681
1682 return asimov;
1683
1684}
#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.
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:55
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: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
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
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:67
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)