Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
HypoTestInverter.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id$
2// Author: Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
3// Contributions: Giovanni Petrucciani and Annapaola Decosa
4/*************************************************************************
5 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class RooStats::HypoTestInverter
13 \ingroup Roostats
14
15A class for performing a hypothesis test inversion by scanning
16the hypothesis test results of a HypoTestCalculator for various values of the
17parameter of interest. By looking at the confidence level curve of the result, an
18upper limit can be derived by computing the intersection of the confidence level curve with the desired confidence level.
19The class implements the RooStats::IntervalCalculator interface, and returns a
20RooStats::HypoTestInverterResult. The result is a SimpleInterval, which
21via the method UpperLimit() returns to the user the upper limit value.
22
23## Scanning options
24The HypoTestInverter implements various options for performing the scan.
25- HypoTestInverter::RunFixedScan will scan the parameter of interest using a fixed grid.
26- HypoTestInverter::SetAutoScan will perform an automatic scan to find
27optimally the curve. It will stop when the desired precision is obtained.
28- HypoTestInverter::RunOnePoint computes the confidence level at a given point.
29
30### CLs presciption
31The class can scan the CLs+b values or alternatively CLs. For the latter,
32call HypoTestInverter::UseCLs().
33*/
34
36
47
48#include "RooAbsData.h"
49#include "RooRealVar.h"
50#include "RooArgSet.h"
51#include "RooAbsPdf.h"
52#include "RooRandom.h"
53#include "RooConstVar.h"
54#include "RooMsgService.h"
55
56#include "TMath.h"
57#include "TF1.h"
58#include "TFile.h"
59#include "TH1.h"
60#include "TLine.h"
61#include "TCanvas.h"
62#include "TGraphErrors.h"
63
64#include <cassert>
65#include <cmath>
66#include <memory>
67
68
69using namespace RooStats;
70using std::endl;
71
72// static variable definitions
74unsigned int HypoTestInverter::fgNToys = 500;
75
78std::string HypoTestInverter::fgAlgo = "logSecant";
79
80// helper class to wrap the functionality of the various HypoTestCalculators
81
82template<class HypoTestType>
84
85 static void SetToys(HypoTestType * h, int toyNull, int toyAlt) { h->SetToys(toyNull,toyAlt); }
86
87};
88
89////////////////////////////////////////////////////////////////////////////////
90/// get the variable to scan
91/// try first with null model if not go to alternate model
92
94
95 RooRealVar * varToScan = nullptr;
96 const ModelConfig * mc = hc.GetNullModel();
97 if (mc) {
98 const RooArgSet * poi = mc->GetParametersOfInterest();
99 if (poi) varToScan = dynamic_cast<RooRealVar*> (poi->first() );
100 }
101 if (!varToScan) {
102 mc = hc.GetAlternateModel();
103 if (mc) {
104 const RooArgSet * poi = mc->GetParametersOfInterest();
105 if (poi) varToScan = dynamic_cast<RooRealVar*> (poi->first() );
106 }
107 }
108 return varToScan;
109}
110
111////////////////////////////////////////////////////////////////////////////////
112/// check the model given the given hypotestcalculator
113
115 const ModelConfig * modelSB = hc.GetNullModel();
116 const ModelConfig * modelB = hc.GetAlternateModel();
117 if (!modelSB || ! modelB)
118 oocoutF(nullptr,InputArguments) << "HypoTestInverter - model are not existing" << std::endl;
120
121 oocoutI(nullptr,InputArguments) << "HypoTestInverter ---- Input models: \n"
122 << "\t\t using as S+B (null) model : "
123 << modelSB->GetName() << "\n"
124 << "\t\t using as B (alternate) model : "
125 << modelB->GetName() << "\n" << std::endl;
126
127 // check if scanVariable is included in B model pdf
128 RooAbsPdf * bPdf = modelB->GetPdf();
129 const RooArgSet * bObs = modelB->GetObservables();
130 if (!bPdf || !bObs) {
131 oocoutE(nullptr,InputArguments) << "HypoTestInverter - B model has no pdf or observables defined" << std::endl;
132 return;
133 }
134 std::unique_ptr<RooArgSet> bParams{bPdf->getParameters(*bObs)};
135 if (!bParams) {
136 oocoutE(nullptr,InputArguments) << "HypoTestInverter - pdf of B model has no parameters" << std::endl;
137 return;
138 }
139 if (bParams->find(scanVariable.GetName() ) ) {
140 const RooArgSet * poiB = modelB->GetSnapshot();
141 if (!poiB || !poiB->find(scanVariable.GetName()) ||
142 (static_cast<RooRealVar *>(poiB->find(scanVariable.GetName())))->getVal() != 0) {
143 oocoutW(nullptr, InputArguments)
144 << "HypoTestInverter - using a B model with POI " << scanVariable.GetName() << " not equal to zero "
145 << " user must check input model configurations " << std::endl;
146 }
147 if (poiB) delete poiB;
148 }
149}
150
151////////////////////////////////////////////////////////////////////////////////
152/// default constructor (doesn't do anything)
153
155 fTotalToysRun(0),
156 fMaxToys(0),
157 fCalculator0(nullptr),
158 fScannedVariable(nullptr),
159 fResults(nullptr),
160 fUseCLs(false),
161 fScanLog(false),
162 fSize(0),
163 fVerbose(0),
164 fCalcType(kUndefined),
165 fNBins(0), fXmin(1), fXmax(1),
166 fNumErr(0)
167{
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// Constructor from a HypoTestCalculatorGeneric
172/// The HypoTest calculator must be a FrequentistCalculator or HybridCalculator type
173/// Other type of calculators are not supported.
174/// The calculator must be created before by using the S+B model for the null and
175/// the B model for the alt
176/// If no variable to scan are given they are assumed to be the first variable
177/// from the parameter of interests of the null model
178
180 RooRealVar* scannedVariable, double size ) :
181 fTotalToysRun(0),
182 fMaxToys(0),
183 fCalculator0(nullptr),
184 fScannedVariable(scannedVariable),
185 fResults(nullptr),
186 fUseCLs(false),
187 fScanLog(false),
188 fSize(size),
189 fVerbose(0),
190 fCalcType(kUndefined),
191 fNBins(0), fXmin(1), fXmax(1),
192 fNumErr(0)
193{
194
195 if (!fScannedVariable) {
197 }
198 if (!fScannedVariable) {
199 oocoutE(nullptr,InputArguments) << "HypoTestInverter - Cannot guess the variable to scan " << std::endl;
200 } else {
202 }
203
204 HybridCalculator * hybCalc = dynamic_cast<HybridCalculator*>(&hc);
205 if (hybCalc) {
208 return;
209 }
211 if (freqCalc) {
214 return;
215 }
217 if (asymCalc) {
220 return;
221 }
222 oocoutE(nullptr,InputArguments) << "HypoTestInverter - Type of hypotest calculator is not supported " <<std::endl;
223 fCalculator0 = &hc;
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Constructor from a reference to a HybridCalculator
228/// The calculator must be created before by using the S+B model for the null and
229/// the B model for the alt
230/// If no variable to scan are given they are assumed to be the first variable
231/// from the parameter of interests of the null model
232
234 RooRealVar* scannedVariable, double size ) :
235 fTotalToysRun(0),
236 fMaxToys(0),
237 fCalculator0(&hc),
238 fScannedVariable(scannedVariable),
239 fResults(nullptr),
240 fUseCLs(false),
241 fScanLog(false),
242 fSize(size),
243 fVerbose(0),
244 fCalcType(kHybrid),
245 fNBins(0), fXmin(1), fXmax(1),
246 fNumErr(0)
247{
248
249 if (!fScannedVariable) {
251 }
252 if (!fScannedVariable) {
253 oocoutE(nullptr,InputArguments) << "HypoTestInverter - Cannot guess the variable to scan " << std::endl;
254 } else {
256 }
257}
258
259////////////////////////////////////////////////////////////////////////////////
260/// Constructor from a reference to a FrequentistCalculator
261/// The calculator must be created before by using the S+B model for the null and
262/// the B model for the alt
263/// If no variable to scan are given they are assumed to be the first variable
264/// from the parameter of interests of the null model
265
267 RooRealVar* scannedVariable, double size ) :
268 fTotalToysRun(0),
269 fMaxToys(0),
270 fCalculator0(&hc),
271 fScannedVariable(scannedVariable),
272 fResults(nullptr),
273 fUseCLs(false),
274 fScanLog(false),
275 fSize(size),
276 fVerbose(0),
277 fCalcType(kFrequentist),
278 fNBins(0), fXmin(1), fXmax(1),
279 fNumErr(0)
280{
281
282 if (!fScannedVariable) {
284 }
285 if (!fScannedVariable) {
286 oocoutE(nullptr,InputArguments) << "HypoTestInverter - Cannot guess the variable to scan " << std::endl;
287 } else {
289 }
290}
291
292////////////////////////////////////////////////////////////////////////////////
293/// Constructor from a reference to a AsymptoticCalculator
294/// The calculator must be created before by using the S+B model for the null and
295/// the B model for the alt
296/// If no variable to scan are given they are assumed to be the first variable
297/// from the parameter of interests of the null model
298
300 RooRealVar* scannedVariable, double size ) :
301 fTotalToysRun(0),
302 fMaxToys(0),
303 fCalculator0(&hc),
304 fScannedVariable(scannedVariable),
305 fResults(nullptr),
306 fUseCLs(false),
307 fScanLog(false),
308 fSize(size),
309 fVerbose(0),
310 fCalcType(kAsymptotic),
311 fNBins(0), fXmin(1), fXmax(1),
312 fNumErr(0)
313{
314
315 if (!fScannedVariable) {
317 }
318 if (!fScannedVariable) {
319 oocoutE(nullptr,InputArguments) << "HypoTestInverter - Cannot guess the variable to scan " << std::endl;
320 } else {
322 }
323}
324
325////////////////////////////////////////////////////////////////////////////////
326/// Constructor from a model for B model and a model for S+B.
327/// An HypoTestCalculator (Hybrid of Frequentis) will be created using the
328/// S+B model as the null and the B model as the alternate
329/// If no variable to scan are given they are assumed to be the first variable
330/// from the parameter of interests of the null model
331
334 fTotalToysRun(0),
335 fMaxToys(0),
336 fCalculator0(nullptr),
337 fScannedVariable(scannedVariable),
338 fResults(nullptr),
339 fUseCLs(false),
340 fScanLog(false),
341 fSize(size),
342 fVerbose(0),
343 fCalcType(type),
344 fNBins(0), fXmin(1), fXmax(1),
345 fNumErr(0)
346{
347 if(fCalcType==kFrequentist) fHC = std::make_unique<FrequentistCalculator>(data, bModel, sbModel);
348 if(fCalcType==kHybrid) fHC = std::make_unique<HybridCalculator>(data, bModel, sbModel);
349 if(fCalcType==kAsymptotic) fHC = std::make_unique<AsymptoticCalculator>(data, bModel, sbModel);
350 fCalculator0 = fHC.get();
351 // get scanned variable
352 if (!fScannedVariable) {
354 }
355 if (!fScannedVariable) {
356 oocoutE(nullptr,InputArguments) << "HypoTestInverter - Cannot guess the variable to scan " << std::endl;
357 } else {
359 }
360}
361
362////////////////////////////////////////////////////////////////////////////////
363/// copy-constructor
364/// NOTE: this class does not copy the contained result and
365/// the HypoTestCalculator, but only the pointers
366/// It requires the original HTI to be alive
367
370 fTotalToysRun(0),
371 fCalculator0(nullptr), fScannedVariable(nullptr), // add these for Coverity
372 fResults(nullptr)
373{
374 (*this) = rhs;
375}
376
377////////////////////////////////////////////////////////////////////////////////
378/// assignment operator
379/// NOTE: this class does not copy the contained result and
380/// the HypoTestCalculator, but only the pointers
381/// It requires the original HTI to be alive
382
384 if (this == &rhs) return *this;
385 fTotalToysRun = 0;
386 fMaxToys = rhs.fMaxToys;
387 fCalculator0 = rhs.fCalculator0;
388 fScannedVariable = rhs.fScannedVariable;
389 fUseCLs = rhs.fUseCLs;
390 fScanLog = rhs.fScanLog;
391 fSize = rhs.fSize;
392 fVerbose = rhs.fVerbose;
393 fCalcType = rhs.fCalcType;
394 fNBins = rhs.fNBins;
395 fXmin = rhs.fXmin;
396 fXmax = rhs.fXmax;
397 fNumErr = rhs.fNumErr;
398
399 return *this;
400}
401
402////////////////////////////////////////////////////////////////////////////////
403/// destructor (delete the HypoTestInverterResult)
404
406{
407 if (fResults) delete fResults;
408 fCalculator0 = nullptr;
409}
410
411////////////////////////////////////////////////////////////////////////////////
412/// return the test statistic which is or will be used by the class
413
415{
418 }
419 else
420 return nullptr;
421}
422
423////////////////////////////////////////////////////////////////////////////////
424/// set the test statistic to use
425
427{
430 return true;
431 }
432 else return false;
433}
434
435////////////////////////////////////////////////////////////////////////////////
436/// delete contained result and graph
437
439 if (fResults) delete fResults;
440 fResults = nullptr;
441 fLimitPlot.reset();
442}
443
444////////////////////////////////////////////////////////////////////////////////
445/// create a new HypoTestInverterResult to hold all computed results
446
448 if (fResults == nullptr) {
449 TString results_name = "result_";
452 TString title = "HypoTestInverter Result For ";
453 title += fScannedVariable->GetName();
454 fResults->SetTitle(title);
455 }
458 // check if one or two sided scan
459 if (fCalculator0) {
460 // if asymptotic calculator
462 if (ac) {
463 fResults->fIsTwoSided = ac->IsTwoSided();
464 } else {
465 // in case of the other calculators
467 if (sampler) {
468 ProfileLikelihoodTestStat * pl = dynamic_cast<ProfileLikelihoodTestStat*>(sampler->GetTestStatistic());
469 if (pl && pl->IsTwoSided() ) fResults->fIsTwoSided = true;
470 }
471 }
472 }
473}
474
475////////////////////////////////////////////////////////////////////////////////
476/// Run a fixed scan or the automatic scan depending on the configuration.
477/// Return if needed a copy of the result object which will be managed by the user.
478
480
481 // if having a result with at least one point return it
482 if (fResults && fResults->ArraySize() >= 1) {
483 oocoutI(nullptr,Eval) << "HypoTestInverter::GetInterval - return an already existing interval " << std::endl;
484 return static_cast<HypoTestInverterResult*>(fResults->Clone());
485 }
486
487 if (fNBins > 0) {
488 oocoutI(nullptr,Eval) << "HypoTestInverter::GetInterval - run a fixed scan" << std::endl;
490 if (!ret)
491 oocoutE(nullptr,Eval) << "HypoTestInverter::GetInterval - error running a fixed scan " << std::endl;
492 }
493 else {
494 oocoutI(nullptr,Eval) << "HypoTestInverter::GetInterval - run an automatic scan" << std::endl;
495 double limit(0);
496 double err(0);
497 bool ret = RunLimit(limit,err);
498 if (!ret)
499 oocoutE(nullptr,Eval) << "HypoTestInverter::GetInterval - error running an auto scan " << std::endl;
500 }
501
502 return static_cast<HypoTestInverterResult*> (fResults->Clone());
503}
504
505////////////////////////////////////////////////////////////////////////////////
506/// Run the Hypothesis test at a previous configured point
507/// (internal function called by RunOnePoint)
508
510 //for debug
511 // std::cout << ">>>>>>>>>>> " << std::endl;
512 // std::cout << "alternate model " << std::endl;
513 // hc.GetAlternateModel()->GetNuisanceParameters()->Print("V");
514 // hc.GetAlternateModel()->GetParametersOfInterest()->Print("V");
515 // std::cout << "Null model " << std::endl;
516 // hc.GetNullModel()->GetNuisanceParameters()->Print("V");
517 // hc.GetNullModel()->GetParametersOfInterest()->Print("V");
518 // std::cout << "<<<<<<<<<<<<<<< " << std::endl;
519
520 // run the hypothesis test
521 HypoTestResult * hcResult = hc.GetHypoTest();
522 if (hcResult == nullptr) {
523 oocoutE(nullptr,Eval) << "HypoTestInverter::Eval - HypoTest failed" << std::endl;
524 return hcResult;
525 }
526
527 // since the b model is the alt need to set the flag
528 hcResult->SetBackgroundAsAlt(true);
529
530
531 // bool flipPvalue = false;
532 // if (flipPValues)
533 // hcResult->SetPValueIsRightTail(!hcResult->GetPValueIsRightTail());
534
535 // adjust for some numerical error in discrete models and == is not anymore
536 if (hcResult->GetPValueIsRightTail()) {
537 hcResult->SetTestStatisticData(hcResult->GetTestStatisticData()-fNumErr); // issue with < vs <= in discrete models
538 } else {
539 hcResult->SetTestStatisticData(hcResult->GetTestStatisticData() +
540 fNumErr); // issue with < vs <= in discrete models
541 }
542
543 double clsMid = (fUseCLs ? hcResult->CLs() : hcResult->CLsplusb());
544 double clsMidErr = (fUseCLs ? hcResult->CLsError() : hcResult->CLsplusbError());
545
546 //if (fVerbose) std::cout << (fUseCLs ? "\tCLs = " : "\tCLsplusb = ") << clsMid << " +/- " << clsMidErr << std::endl;
547
548 if (adaptive) {
549
552
553 while (clsMidErr >= fgCLAccuracy && (clsTarget == -1 || std::abs(clsMid-clsTarget) < 3*clsMidErr) ) {
554 std::unique_ptr<HypoTestResult> more(hc.GetHypoTest());
555
556 // if (flipPValues)
557 // more->SetPValueIsRightTail(!more->GetPValueIsRightTail());
558
559 hcResult->Append(more.get());
560 clsMid = (fUseCLs ? hcResult->CLs() : hcResult->CLsplusb());
561 clsMidErr = (fUseCLs ? hcResult->CLsError() : hcResult->CLsplusbError());
562 if (fVerbose) std::cout << (fUseCLs ? "\tCLs = " : "\tCLsplusb = ") << clsMid << " +/- " << clsMidErr << std::endl;
563 }
564
565 }
566 if (fVerbose ) {
567 oocoutP(nullptr,Eval) << "P values for " << fScannedVariable->GetName() << " = " <<
568 fScannedVariable->getVal() << "\n" <<
569 "\tCLs = " << hcResult->CLs() << " +/- " << hcResult->CLsError() << "\n" <<
570 "\tCLb = " << hcResult->CLb() << " +/- " << hcResult->CLbError() << "\n" <<
571 "\tCLsplusb = " << hcResult->CLsplusb() << " +/- " << hcResult->CLsplusbError() << "\n" <<
572 std::endl;
573 }
574
576 fTotalToysRun += (hcResult->GetAltDistribution()->GetSize() + hcResult->GetNullDistribution()->GetSize());
577
578 // set sampling distribution name
579 TString nullDistName = TString::Format("%s_%s_%4.2f",hcResult->GetNullDistribution()->GetName(),
581 TString altDistName = TString::Format("%s_%s_%4.2f",hcResult->GetAltDistribution()->GetName(),
583
584 hcResult->GetNullDistribution()->SetName(nullDistName);
585 hcResult->GetAltDistribution()->SetName(altDistName);
586 }
587
588 return hcResult;
589}
590
591////////////////////////////////////////////////////////////////////////////////
592/// Run a Fixed scan in npoints between min and max
593
594bool HypoTestInverter::RunFixedScan( int nBins, double xMin, double xMax, bool scanLog ) const
595{
596
598 // interpolate the limits
601
602 // safety checks
603 if ( nBins<=0 ) {
604 oocoutE(nullptr,InputArguments) << "HypoTestInverter::RunFixedScan - Please provide nBins>0\n";
605 return false;
606 }
607 if ( nBins==1 && xMin!=xMax ) {
608 oocoutW(nullptr,InputArguments) << "HypoTestInverter::RunFixedScan - nBins==1 -> I will run for xMin (" << xMin << ")\n";
609 }
610 if ( xMin==xMax && nBins>1 ) {
611 oocoutW(nullptr,InputArguments) << "HypoTestInverter::RunFixedScan - xMin==xMax -> I will enforce nBins==1\n";
612 nBins = 1;
613 }
614 if ( xMin>xMax ) {
615 oocoutE(nullptr,InputArguments) << "HypoTestInverter::RunFixedScan - Please provide xMin ("
616 << xMin << ") smaller than xMax (" << xMax << ")\n";
617 return false;
618 }
619
620 if (xMin < fScannedVariable->getMin()) {
622 oocoutW(nullptr,InputArguments) << "HypoTestInverter::RunFixedScan - xMin < lower bound, using xmin = "
623 << xMin << std::endl;
624 }
625 if (xMax > fScannedVariable->getMax()) {
627 oocoutW(nullptr,InputArguments) << "HypoTestInverter::RunFixedScan - xMax > upper bound, using xmax = "
628 << xMax << std::endl;
629 }
630
631 if (xMin <= 0. && scanLog) {
632 oocoutE(nullptr, InputArguments) << "HypoTestInverter::RunFixedScan - cannot go in log steps if xMin <= 0" << std::endl;
633 return false;
634 }
635
636 double thisX = xMin;
637 for (int i=0; i<nBins; i++) {
638
639 if (i > 0) { // avoids case of nBins = 1
640 if (scanLog) {
641 thisX = exp( log(xMin) + i*(log(xMax)-log(xMin))/(nBins-1) ); // scan in log x
642 } else {
643 thisX = xMin + i * (xMax - xMin) / (nBins - 1); // linear scan in x
644 }
645 }
646
647 const bool status = RunOnePoint(thisX);
648
649 // check if failed status
650 if ( status==false ) {
651 oocoutW(nullptr,Eval) << "HypoTestInverter::RunFixedScan - The hypo test for point " << thisX << " failed. Skipping." << std::endl;
652 }
653 }
654
655 return true;
656}
657
658////////////////////////////////////////////////////////////////////////////////
659/// run only one point at the given POI value
660
661bool HypoTestInverter::RunOnePoint( double rVal, bool adaptive, double clTarget) const
662{
663
665
666 // check if rVal is in the range specified for fScannedVariable
667 if ( rVal < fScannedVariable->getMin() ) {
668 oocoutE(nullptr,InputArguments) << "HypoTestInverter::RunOnePoint - Out of range: using the lower bound "
670 << " on the scanned variable rather than " << rVal<< "\n";
672 }
673 if ( rVal > fScannedVariable->getMax() ) {
674 // print a message when you have a significative difference since rval is computed
675 if (rVal > fScannedVariable->getMax() * (1. + 1.E-12)) {
676 oocoutE(nullptr, InputArguments) << "HypoTestInverter::RunOnePoint - Out of range: using the upper bound "
677 << fScannedVariable->getMax() << " on the scanned variable rather than "
678 << rVal << "\n";
679 }
681 }
682
683 // save old value
684 double oldValue = fScannedVariable->getVal();
685
686 // evaluate hybrid calculator at a single point
688 // need to set value of rval in hybridcalculator
689 // assume null model is S+B and alternate is B only
691 RooArgSet poi; poi.add(*sbModel->GetParametersOfInterest());
692 // set poi to right values
694 const_cast<ModelConfig*>(sbModel)->SetSnapshot(poi);
695
696 if (fVerbose > 0)
697 oocoutP(nullptr,Eval) << "Running for " << fScannedVariable->GetName() << " = " << fScannedVariable->getVal() << std::endl;
698
699 // compute the results
700 std::unique_ptr<HypoTestResult> result( Eval(*fCalculator0,adaptive,clTarget) );
701 if (!result) {
702 oocoutE(nullptr,Eval) << "HypoTestInverter - Error running point " << fScannedVariable->GetName() << " = " <<
703 fScannedVariable->getVal() << std::endl;
704 return false;
705 }
706 // in case of a dummy result
707 const double nullPV = result->NullPValue();
708 const double altPV = result->AlternatePValue();
709 if (!std::isfinite(nullPV) || nullPV < 0. || nullPV > 1. || !std::isfinite(altPV) || altPV < 0. || altPV > 1.) {
710 oocoutW(nullptr,Eval) << "HypoTestInverter - Skipping invalid result for point " << fScannedVariable->GetName() << " = " <<
711 fScannedVariable->getVal() << ". null p-value=" << nullPV << ", alternate p-value=" << altPV << std::endl;
712 return false;
713 }
714
715 double lastXtested;
717 else lastXtested = -999;
718
719 if ( (std::abs(rVal) < 1 && TMath::AreEqualAbs(rVal, lastXtested,1.E-12) ) ||
720 (std::abs(rVal) >= 1 && TMath::AreEqualRel(rVal, lastXtested,1.E-12) ) ) {
721
722 oocoutI(nullptr,Eval) << "HypoTestInverter::RunOnePoint - Merge with previous result for "
723 << fScannedVariable->GetName() << " = " << rVal << std::endl;
725 if (prevResult && prevResult->GetNullDistribution() && prevResult->GetAltDistribution()) {
726 prevResult->Append(result.get());
727 }
728 else {
729 // if it was empty we re-use it
730 oocoutI(nullptr,Eval) << "HypoTestInverter::RunOnePoint - replace previous empty result\n";
732 delete oldObj;
733
734 fResults->fYObjects.Add(result.release());
735 }
736
737 } else {
738
739 // fill the results in the HypoTestInverterResult array
740 fResults->fXValues.push_back(rVal);
741 fResults->fYObjects.Add(result.release());
742
743 }
744
746
747 return true;
748}
749
750////////////////////////////////////////////////////////////////////////////////
751/// Run an automatic scan until the desired accuracy is reached.
752/// Start by default from the full interval (min,max) of the POI and then via bisection find the line crossing
753/// the target line.
754/// Optionally, a hint can be provided and the scan will be done closer to that value.
755/// If by bisection the desired accuracy will not be reached, a fit to the points is performed.
756/// \param[out] limit The limit.
757/// \param[out] limitErr The error of the limit.
758/// \param[in] absAccuracy Desired absolute accuracy.
759/// \param[in] relAccuracy Desired relative accuracy.
760/// \param[in] hint Hint to start from or nullptr for no hint.
761
762bool HypoTestInverter::RunLimit(double &limit, double &limitErr, double absAccuracy, double relAccuracy, const double*hint) const {
763
764
765 // routine from G. Petrucciani (from HiggsCombination CMS package)
766
768
769 if ((hint != nullptr) && (*hint > r->getMin())) {
770 r->setMax(std::min<double>(3.0 * (*hint), r->getMax()));
771 r->setMin(std::max<double>(0.3 * (*hint), r->getMin()));
772 oocoutI(nullptr,InputArguments) << "HypoTestInverter::RunLimit - Use hint value " << *hint
773 << " search in interval " << r->getMin() << " , " << r->getMax() << std::endl;
774 }
775
776 // if not specified use the default values for rel and absolute accuracy
779
780 typedef std::pair<double,double> CLs_t;
781 double clsTarget = fSize;
782 CLs_t clsMin(1, 0);
783 CLs_t clsMax(0, 0);
784 CLs_t clsMid(0, 0);
785 double rMin = r->getMin();
786 double rMax = r->getMax();
787 limit = 0.5*(rMax + rMin);
788 limitErr = 0.5*(rMax - rMin);
789 bool done = false;
790
791 TF1 expoFit("expoFit","[0]*exp([1]*(x-[2]))", rMin, rMax);
792
793 fLimitPlot = std::make_unique<TGraphErrors>();
794
795 if (fVerbose > 0) std::cout << "Search for upper limit to the limit" << std::endl;
796 for (int tries = 0; tries < 6; ++tries) {
797 if (! RunOnePoint(rMax) ) {
798 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Hypotest failed at upper limit of scan range: " << rMax << std::endl;
799 rMax *= 0.95;
800 continue;
801 }
802 clsMax = std::make_pair( fResults->GetLastYValue(), fResults->GetLastYError() );
803 if (clsMax.first == 0 || clsMax.first + 3 * std::abs(clsMax.second) < clsTarget ) break;
804 rMax += rMax;
805 if (tries == 5) {
806 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Cannot determine upper limit of scan range. At " << r->GetName()
807 << " = " << rMax << " still getting "
808 << (fUseCLs ? "CLs" : "CLsplusb") << " = " << clsMax.first << std::endl;
809 return false;
810 }
811 }
812 if (fVerbose > 0) {
813 oocoutI(nullptr,Eval) << "HypoTestInverter::RunLimit - Search for lower limit to the limit" << std::endl;
814 }
815
816 if ( fUseCLs && rMin == 0 ) {
817 clsMin = CLs_t(1,0);
818 }
819 else {
820 if (! RunOnePoint(rMin) ) {
821 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Hypotest failed at lower limit of scan range: " << rMin << std::endl;
822 return false;
823 }
824 clsMin = std::make_pair( fResults->GetLastYValue(), fResults->GetLastYError() );
825 }
826 if (clsMin.first != 1 && clsMin.first - 3 * std::abs(clsMin.second) < clsTarget) {
827 if (fUseCLs) {
828 rMin = 0;
829 clsMin = CLs_t(1,0); // this is always true for CLs
830 } else {
831 rMin = -rMax / 4;
832 for (int tries = 0; tries < 6; ++tries) {
833 if (! RunOnePoint(rMin) ) {
834 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Hypotest failed at lower limit of scan range: " << rMin << std::endl;
835 rMin = rMin == 0. ? 0.1 : rMin * 1.1;
836 continue;
837 }
838 clsMin = std::make_pair( fResults->GetLastYValue(), fResults->GetLastYError() );
839 if (clsMin.first == 1 || clsMin.first - 3 * std::abs(clsMin.second) > clsTarget) break;
840 rMin += rMin;
841 if (tries == 5) {
842 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Cannot determine lower limit of scan range. At " << r->GetName()
843 << " = " << rMin << " still get " << (fUseCLs ? "CLs" : "CLsplusb")
844 << " = " << clsMin.first << std::endl;
845 return false;
846 }
847 }
848 }
849 }
850
851 if (fVerbose > 0)
852 oocoutI(nullptr,Eval) << "HypoTestInverter::RunLimit - Now doing proper bracketing & bisection" << std::endl;
853 do {
854
855 // break loop in case max toys is reached
856 if (fMaxToys > 0 && fTotalToysRun > fMaxToys ) {
857 oocoutW(nullptr,Eval) << "HypoTestInverter::RunLimit - maximum number of toys reached " << std::endl;
858 done = false; break;
859 }
860
861
862 // determine point by bisection or interpolation
863 limit = 0.5*(rMin+rMax); limitErr = 0.5*(rMax-rMin);
864 if (fgAlgo == "logSecant" && clsMax.first != 0) {
865 double logMin = log(clsMin.first);
866 double logMax = log(clsMax.first);
867 double logTarget = log(clsTarget);
868 limit = rMin + (rMax-rMin) * (logTarget - logMin)/(logMax - logMin);
869 if (clsMax.second != 0 && clsMin.second != 0) {
870 limitErr = hypot((logTarget-logMax) * (clsMin.second/clsMin.first), (logTarget-logMin) * (clsMax.second/clsMax.first));
872 }
873 }
874 r->setError(limitErr);
875
876 // exit if reached accuracy on r
877 if (limitErr < std::max(absAccuracy, relAccuracy * limit)) {
878 if (fVerbose > 1) {
879 oocoutI(nullptr, Eval) << "HypoTestInverter::RunLimit - reached accuracy " << limitErr << " below "
880 << std::max(absAccuracy, relAccuracy * limit) << std::endl;
881 }
882 done = true; break;
883 }
884
885 // evaluate point
886 if (! RunOnePoint(limit, true, clsTarget) ) {
887 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Hypo test failed at x=" << limit << " when trying to find limit." << std::endl;
888 return false;
889 }
890 clsMid = std::make_pair( fResults->GetLastYValue(), fResults->GetLastYError() );
891
892 if (clsMid.second == -1) {
893 std::cerr << "Hypotest failed" << std::endl;
894 return false;
895 }
896
897 // if sufficiently far away, drop one of the points
898 if (std::abs(clsMid.first-clsTarget) >= 2*clsMid.second) {
899 if ((clsMid.first>clsTarget) == (clsMax.first>clsTarget)) {
900 rMax = limit; clsMax = clsMid;
901 } else {
902 rMin = limit; clsMin = clsMid;
903 }
904 } else {
905 if (fVerbose > 0) std::cout << "Trying to move the interval edges closer" << std::endl;
906 double rMinBound = rMin;
907 double rMaxBound = rMax;
908 // try to reduce the size of the interval
909 while (clsMin.second == 0 || std::abs(rMin-limit) > std::max(absAccuracy, relAccuracy * limit)) {
910 rMin = 0.5*(rMin+limit);
911 if (!RunOnePoint(rMin,true, clsTarget) ) {
912 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Hypo test failed at x=" << rMin << " when trying to find limit from below." << std::endl;
913 return false;
914 }
915 clsMin = std::make_pair( fResults->GetLastYValue(), fResults->GetLastYError() );
916 if (std::abs(clsMin.first-clsTarget) <= 2*clsMin.second) break;
917 rMinBound = rMin;
918 }
919 while (clsMax.second == 0 || std::abs(rMax-limit) > std::max(absAccuracy, relAccuracy * limit)) {
920 rMax = 0.5*(rMax+limit);
921 if (!RunOnePoint(rMax,true,clsTarget) ) {
922 oocoutE(nullptr,Eval) << "HypoTestInverter::RunLimit - Hypo test failed at x=" << rMin << " when trying to find limit from above." << std::endl;
923 return false;
924 }
925 clsMax = std::make_pair( fResults->GetLastYValue(), fResults->GetLastYError() );
926 if (std::abs(clsMax.first-clsTarget) <= 2*clsMax.second) break;
927 rMaxBound = rMax;
928 }
929 expoFit.SetRange(rMinBound,rMaxBound);
930 break;
931 }
932 } while (true);
933
934 if (!done) { // didn't reach accuracy with scan, now do fit
935 if (fVerbose) {
936 oocoutI(nullptr,Eval) << "HypoTestInverter::RunLimit - Before fit --- \n";
937 std::cout << "Limit: " << r->GetName() << " < " << limit << " +/- " << limitErr << " [" << rMin << ", " << rMax << "]\n";
938 }
939
940 expoFit.FixParameter(0,clsTarget);
941 expoFit.SetParameter(1,log(clsMax.first/clsMin.first)/(rMax-rMin));
942 expoFit.SetParameter(2,limit);
943 double rMinBound;
944 double rMaxBound;
945 expoFit.GetRange(rMinBound, rMaxBound);
946 limitErr = std::max(std::abs(rMinBound-limit), std::abs(rMaxBound-limit));
947 int npoints = 0;
948
949 HypoTestInverterPlot plot("plot","plot",fResults);
950 fLimitPlot.reset(plot.MakePlot() );
951
952
953 for (int j = 0; j < fLimitPlot->GetN(); ++j) {
954 if (fLimitPlot->GetX()[j] >= rMinBound && fLimitPlot->GetX()[j] <= rMaxBound) npoints++;
955 }
956 for (int i = 0, imax = /*(readHybridResults_ ? 0 : */ 8; i <= imax; ++i, ++npoints) {
957 fLimitPlot->Sort();
958 fLimitPlot->Fit(&expoFit,(fVerbose <= 1 ? "QNR EX0" : "NR EXO"));
959 if (fVerbose) {
960 oocoutI(nullptr,Eval) << "Fit to " << npoints << " points: " << expoFit.GetParameter(2) << " +/- " << expoFit.GetParError(2) << std::endl;
961 }
962 if ((rMin < expoFit.GetParameter(2)) && (expoFit.GetParameter(2) < rMax) && (expoFit.GetParError(2) < 0.5*(rMaxBound-rMinBound))) {
963 // sanity check fit result
964 limit = expoFit.GetParameter(2);
965 limitErr = expoFit.GetParError(2);
966 if (limitErr < std::max(absAccuracy, relAccuracy * limit)) break;
967 }
968 // add one point in the interval.
970 if (i != imax) {
971 if (!RunOnePoint(rTry,true,clsTarget) ) return false;
972 //eval(w, mc_s, mc_b, data, rTry, true, clsTarget);
973 }
974
975 }
976 }
977
978//if (!plot_.empty() && fLimitPlot.get()) {
979 if (fLimitPlot.get() && fLimitPlot->GetN() > 0) {
980 //new TCanvas("c1","c1");
981 fLimitPlot->Sort();
982 fLimitPlot->SetLineWidth(2);
983 double xmin = r->getMin();
984 double xmax = r->getMax();
985 for (int j = 0; j < fLimitPlot->GetN(); ++j) {
986 if (fLimitPlot->GetY()[j] > 1.4*clsTarget || fLimitPlot->GetY()[j] < 0.6*clsTarget) continue;
987 xmin = std::min(fLimitPlot->GetX()[j], xmin);
988 xmax = std::max(fLimitPlot->GetX()[j], xmax);
989 }
990 fLimitPlot->GetXaxis()->SetRangeUser(xmin,xmax);
991 fLimitPlot->GetYaxis()->SetRangeUser(0.5*clsTarget, 1.5*clsTarget);
992 fLimitPlot->Draw("AP");
993 expoFit.Draw("SAME");
994 TLine line(fLimitPlot->GetX()[0], clsTarget, fLimitPlot->GetX()[fLimitPlot->GetN()-1], clsTarget);
996 line.DrawLine(limit, 0, limit, fLimitPlot->GetY()[0]);
998 line.DrawLine(limit-limitErr, 0, limit-limitErr, fLimitPlot->GetY()[0]);
999 line.DrawLine(limit+limitErr, 0, limit+limitErr, fLimitPlot->GetY()[0]);
1000 //c1->Print(plot_.c_str());
1001 }
1002
1003 oocoutI(nullptr,Eval) << "HypoTestInverter::RunLimit - Result: \n"
1004 << "\tLimit: " << r->GetName() << " < " << limit << " +/- " << limitErr << " @ " << (1-fSize) * 100 << "% CL\n";
1005 if (fVerbose > 1) oocoutI(nullptr,Eval) << "Total toys: " << fTotalToysRun << std::endl;
1006
1007 // set value in results
1008 fResults->fUpperLimit = limit;
1011 // lower limit are always min of p value
1015
1016 return true;
1017}
1018
1019////////////////////////////////////////////////////////////////////////////////
1020/// get the distribution of lower limit
1021/// if rebuild = false (default) it will re-use the results of the scan done
1022/// for obtained the observed limit and no extra toys will be generated
1023/// if rebuild a new set of B toys will be done and the procedure will be repeated
1024/// for each toy
1025
1027 if (!rebuild) {
1028 if (!fResults) {
1029 oocoutE(nullptr,InputArguments) << "HypoTestInverter::GetLowerLimitDistribution(false) - result not existing\n";
1030 return nullptr;
1031 }
1033 }
1034
1035 TList * clsDist = nullptr;
1036 TList * clsbDist = nullptr;
1038 else clsbDist = &fResults->fExpPValues;
1039
1041
1042}
1043
1044////////////////////////////////////////////////////////////////////////////////
1045/// get the distribution of lower limit
1046/// if rebuild = false (default) it will re-use the results of the scan done
1047/// for obtained the observed limit and no extra toys will be generated
1048/// if rebuild a new set of B toys will be done and the procedure will be repeated
1049/// for each toy
1050/// The nuisance parameter value used for rebuild is the current one in the model
1051/// so it is user responsibility to set to the desired value (nomi
1052
1054 if (!rebuild) {
1055 if (!fResults) {
1056 oocoutE(nullptr,InputArguments) << "HypoTestInverter::GetUpperLimitDistribution(false) - result not existing\n";
1057 return nullptr;
1058 }
1060 }
1061
1062 TList * clsDist = nullptr;
1063 TList * clsbDist = nullptr;
1065 else clsbDist = &fResults->fExpPValues;
1066
1068}
1069
1070////////////////////////////////////////////////////////////////////////////////
1071
1075
1076////////////////////////////////////////////////////////////////////////////////
1077/// rebuild the sampling distributions by
1078/// generating some toys and find for each of them a new upper limit
1079/// Return the upper limit distribution and optionally also the pValue distributions for Cls, Clsb and Clbxs
1080/// as a TList for each scanned point
1081/// The method uses the present parameter value. It is user responsibility to give the current parameters to rebuild the distributions
1082/// It returns a upper or lower limit distribution depending on the isUpper flag, however it computes also the lower limit distribution and it is saved in the
1083/// output file as an histogram
1084
1086
1087 if (!fScannedVariable || !fCalculator0) return nullptr;
1088 // get first background snapshot
1091 if (!bModel || ! sbModel) return nullptr;
1093 if (!sbModel->GetParametersOfInterest()) return nullptr;
1094 paramPoint.add(*sbModel->GetParametersOfInterest());
1095
1096 const RooArgSet * poibkg = bModel->GetSnapshot();
1097 if (!poibkg) {
1098 oocoutW(nullptr,InputArguments) << "HypoTestInverter::RebuildDistribution - background snapshot not existing"
1099 << " assume is for POI = 0" << std::endl;
1102 }
1103 else
1104 paramPoint.assign(*poibkg);
1105 // generate data at bkg parameter point
1106
1108 if (!toymcSampler) {
1109 oocoutE(nullptr,InputArguments) << "HypoTestInverter::RebuildDistribution - no toy MC sampler existing" << std::endl;
1110 return nullptr;
1111 }
1112 // set up test stat sampler in case of asymptotic calculator
1113 if (dynamic_cast<RooStats::AsymptoticCalculator*>(fCalculator0) ) {
1114 toymcSampler->SetObservables(*sbModel->GetObservables() );
1115 toymcSampler->SetParametersForTestStat(*sbModel->GetParametersOfInterest());
1116 toymcSampler->SetPdf(*sbModel->GetPdf());
1117 toymcSampler->SetNuisanceParameters(*sbModel->GetNuisanceParameters());
1118 if (sbModel->GetGlobalObservables() ) toymcSampler->SetGlobalObservables(*sbModel->GetGlobalObservables() );
1119 // set number of events
1120 if (!sbModel->GetPdf()->canBeExtended())
1121 toymcSampler->SetNEventsPerToy(1);
1122 }
1123
1124 // loop on data to generate
1125 int nPoints = fNBins;
1126
1127 bool storePValues = clsDist || clsbDist || clbDist;
1128 if (fNBins <=0 && storePValues) {
1129 oocoutW(nullptr,InputArguments) << "HypoTestInverter::RebuildDistribution - cannot return p values distribution with the auto scan" << std::endl;
1130 storePValues = false;
1131 nPoints = 0;
1132 }
1133
1134 if (storePValues) {
1136 if (nPoints <=0) {
1137 oocoutE(nullptr,InputArguments) << "HypoTestInverter - result is not existing and number of point to scan is not set"
1138 << std::endl;
1139 return nullptr;
1140 }
1141 }
1142
1143 if (nToys <= 0) nToys = 100; // default value
1144
1145 std::vector<std::vector<double> > CLs_values(nPoints);
1146 std::vector<std::vector<double> > CLsb_values(nPoints);
1147 std::vector<std::vector<double> > CLb_values(nPoints);
1148
1149 if (storePValues) {
1150 for (int i = 0; i < nPoints; ++i) {
1151 CLs_values[i].reserve(nToys);
1152 CLb_values[i].reserve(nToys);
1153 CLsb_values[i].reserve(nToys);
1154 }
1155 }
1156
1157 std::vector<double> limit_values; limit_values.reserve(nToys);
1158
1159 oocoutI(nullptr,InputArguments) << "HypoTestInverter - rebuilding the p value distributions by generating ntoys = "
1160 << nToys << std::endl;
1161
1162
1163 oocoutI(nullptr,InputArguments) << "Rebuilding using parameter of interest point: ";
1164 RooStats::PrintListContent(paramPoint, oocoutI(nullptr,InputArguments) );
1165 if (sbModel->GetNuisanceParameters() ) {
1166 oocoutI(nullptr,InputArguments) << "And using nuisance parameters: ";
1167 RooStats::PrintListContent(*sbModel->GetNuisanceParameters(), oocoutI(nullptr,InputArguments) );
1168 }
1169 // save all parameters to restore them later
1170 assert(bModel->GetPdf() );
1171 assert(bModel->GetObservables() );
1172 std::unique_ptr<RooArgSet> allParams{bModel->GetPdf()->getParameters( *bModel->GetObservables() )};
1174 allParams->snapshot(saveParams);
1175
1176 std::unique_ptr<TFile> fileOut{TFile::Open(outputfile,"RECREATE")};
1177 if (!fileOut) {
1178 oocoutE(nullptr,InputArguments) << "HypoTestInverter - RebuildDistributions - Error opening file " << outputfile
1179 << " - the resulting limits will not be stored" << std::endl;
1180 }
1181 // create temporary histograms to store the limit result
1182 TH1D * hL = new TH1D("lowerLimitDist","Rebuilt lower limit distribution",100,1.,0.);
1183 TH1D * hU = new TH1D("upperLimitDist","Rebuilt upper limit distribution",100,1.,0.);
1184 TH1D * hN = new TH1D("nObs","Observed events",100,1.,0.);
1185 hL->SetBuffer(2*nToys);
1186 hU->SetBuffer(2*nToys);
1187 std::vector<TH1*> hCLb;
1188 std::vector<TH1*> hCLsb;
1189 std::vector<TH1*> hCLs;
1190 if (storePValues) {
1191 for (int i = 0; i < nPoints; ++i) {
1192 hCLb.push_back(new TH1D(TString::Format("CLbDist_bin%d",i),"CLb distribution",100,1.,0.));
1193 hCLs.push_back(new TH1D(TString::Format("ClsDist_bin%d",i),"CLs distribution",100,1.,0.));
1194 hCLsb.push_back(new TH1D(TString::Format("CLsbDist_bin%d",i),"CLs+b distribution",100,1.,0.));
1195 }
1196 }
1197
1198
1199 // loop now on the toys
1200 for (int itoy = 0; itoy < nToys; ++itoy) {
1201
1202 oocoutP(nullptr,Eval) << "\nHypoTestInverter - RebuildDistributions - running toy # " << itoy << " / "
1203 << nToys << std::endl;
1204
1205
1206 std::cout << "\n\nshnapshot of s+b model \n";
1207 sbModel->GetSnapshot()->Print("v");
1208
1209 // reset parameters to initial values to be sure in case they are not reset
1210 if (itoy> 0) {
1211 allParams->assign(saveParams);
1212 }
1213
1214 // need to set th epdf to clear the cache in ToyMCSampler
1215 // pdf we must use is background pdf
1216 toymcSampler->SetPdf(*bModel->GetPdf() );
1217
1218
1219 RooAbsData * bkgdata = toymcSampler->GenerateToyData(paramPoint);
1220
1221 double nObs = bkgdata->sumEntries();
1222 // for debugging in case of number counting models
1223 if (bkgdata->numEntries() ==1 && !bModel->GetPdf()->canBeExtended()) {
1224 oocoutP(nullptr,Generation) << "Generate observables are : ";
1225 RooArgList genObs(*bkgdata->get(0));
1226 RooStats::PrintListContent(genObs, oocoutP(nullptr,Generation) );
1227 nObs = 0;
1228 for (std::size_t i = 0; i < genObs.size(); ++i) {
1229 RooRealVar * x = dynamic_cast<RooRealVar*>(&genObs[i]);
1230 if (x) nObs += x->getVal();
1231 }
1232 }
1233 hN->Fill(nObs);
1234
1235 // by copying I will have the same min/max as previous ones
1236 HypoTestInverter inverter = *this;
1237 inverter.SetData(*bkgdata);
1238
1239 // print global observables
1240 auto gobs = bModel->GetPdf()->getVariables()->selectCommon(* sbModel->GetGlobalObservables() );
1241 gobs->Print("v");
1242
1243 HypoTestInverterResult * r = inverter.GetInterval();
1244
1245 if (r == nullptr) continue;
1246
1247 double value = (isUpper) ? r->UpperLimit() : r->LowerLimit();
1248 limit_values.push_back( value );
1249 hU->Fill(r->UpperLimit() );
1250 hL->Fill(r->LowerLimit() );
1251
1252
1253 std::cout << "The computed upper limit for toy #" << itoy << " is " << value << std::endl;
1254
1255 // write every 10 toys
1256 if (itoy%10 == 0 || itoy == nToys-1) {
1257 hU->Write("",TObject::kOverwrite);
1258 hL->Write("",TObject::kOverwrite);
1259 hN->Write("",TObject::kOverwrite);
1260 }
1261
1262 if (!storePValues) continue;
1263
1264 if (nPoints < r->ArraySize()) {
1265 oocoutW(nullptr,InputArguments) << "HypoTestInverter: skip extra points" << std::endl;
1266 }
1267 else if (nPoints > r->ArraySize()) {
1268 oocoutW(nullptr,InputArguments) << "HypoTestInverter: missing some points" << std::endl;
1269 }
1270
1271
1272 for (int ipoint = 0; ipoint < nPoints; ++ipoint) {
1273 HypoTestResult * hr = r->GetResult(ipoint);
1274 if (hr) {
1275 CLs_values[ipoint].push_back( hr->CLs() );
1276 CLsb_values[ipoint].push_back( hr->CLsplusb() );
1277 CLb_values[ipoint].push_back( hr->CLb() );
1278 hCLs[ipoint]->Fill( hr->CLs() );
1279 hCLb[ipoint]->Fill( hr->CLb() );
1280 hCLsb[ipoint]->Fill( hr->CLsplusb() );
1281 }
1282 else {
1283 oocoutW(nullptr,InputArguments) << "HypoTestInverter: missing result for point: x = "
1284 << fResults->GetXValue(ipoint) << std::endl;
1285 }
1286 }
1287 // write every 10 toys
1288 if (itoy%10 == 0 || itoy == nToys-1) {
1289 for (int ipoint = 0; ipoint < nPoints; ++ipoint) {
1290 hCLs[ipoint]->Write("",TObject::kOverwrite);
1291 hCLb[ipoint]->Write("",TObject::kOverwrite);
1292 hCLsb[ipoint]->Write("",TObject::kOverwrite);
1293 }
1294 }
1295
1296
1297 delete r;
1298 delete bkgdata;
1299 }
1300
1301
1302 if (storePValues) {
1303 if (clsDist) clsDist->SetOwner(true);
1304 if (clbDist) clbDist->SetOwner(true);
1305 if (clsbDist) clsbDist->SetOwner(true);
1306
1307 oocoutI(nullptr,InputArguments) << "HypoTestInverter: storing rebuilt p values " << std::endl;
1308
1309 for (int ipoint = 0; ipoint < nPoints; ++ipoint) {
1310 if (clsDist) {
1311 TString name = TString::Format("CLs_distrib_%d",ipoint);
1313 }
1314 if (clbDist) {
1315 TString name = TString::Format("CLb_distrib_%d",ipoint);
1317 }
1318 if (clsbDist) {
1319 TString name = TString::Format("CLsb_distrib_%d",ipoint);
1321 }
1322 }
1323 }
1324
1325 else {
1326 // delete all the histograms
1327 delete hL;
1328 delete hU;
1329 for (int i = 0; i < nPoints && storePValues; ++i) {
1330 delete hCLs[i];
1331 delete hCLb[i];
1332 delete hCLsb[i];
1333 }
1334 }
1335
1336 const char * disName = (isUpper) ? "upperLimit_dist" : "lowerLimit_dist";
1338}
dim_t fSize
bool fVerbose
verbosity flag
Definition HybridPlot.h:82
#define h(i)
Definition RSha256.hxx:106
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 oocoutP(o, a)
@ kRed
Definition Rtypes.h:67
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter char TVirtualGLPainter plot
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:146
float xmin
float xmax
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...
RooAbsArg * first() const
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:56
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
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
static double uniform(TRandom *generator=randomGenerator())
Return a number uniformly distributed from (0,1)
Definition RooRandom.cxx:77
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
Hypothesis Test Calculator based on the asymptotic formulae for the profile likelihood ratio.
Does a frequentist hypothesis test.
Same purpose as HybridCalculatorOriginal, but different implementation.
Common base class for the Hypothesis Test Calculators.
const ModelConfig * GetNullModel(void) const
void SetData(RooAbsData &data) override
Set the DataSet.
const ModelConfig * GetAlternateModel(void) const
TestStatSampler * GetTestStatSampler(void) const
Returns instance of TestStatSampler.
Class to plot a HypoTestInverterResult, the output of the HypoTestInverter calculator.
HypoTestInverterResult class holds the array of hypothesis test results and compute a confidence inte...
SamplingDistribution * GetLowerLimitDistribution() const
get expected lower limit distributions implemented using interpolation The size for the sampling dist...
HypoTestResult * GetResult(int index) const
return a pointer to the i^th result object
int ArraySize() const
number of entries in the results array
void UseCLs(bool on=true)
flag to switch between using CLsb (default) or CLs as confidence level
double GetXValue(int index) const
function to return the value of the parameter of interest for the i^th entry in the results
TList fExpPValues
list of expected sampling distribution for each point
bool fIsTwoSided
two sided scan (look for lower/upper limit)
TList fYObjects
list of HypoTestResult for each point
void SetConfidenceLevel(double cl) override
set the confidence level for the interval (eg. 0.95 for a 95% Confidence Interval)
SamplingDistribution * GetUpperLimitDistribution() const
get expected upper limit distributions implemented using interpolation
A class for performing a hypothesis test inversion by scanning the hypothesis test results of a HypoT...
static void CheckInputModels(const HypoTestCalculatorGeneric &hc, const RooRealVar &scanVar)
check the model given the given hypotestcalculator
RooRealVar * fScannedVariable
pointer to the constrained variable
std::unique_ptr< HypoTestCalculatorGeneric > fHC
! pointer to the generic hypotest calculator used
bool RunLimit(double &limit, double &limitErr, double absTol=0, double relTol=0, const double *hint=nullptr) const
Run an automatic scan until the desired accuracy is reached.
void SetData(RooAbsData &) override
Set the DataSet ( add to the workspace if not already there ?)
HypoTestInverterResult * fResults
pointer to the result
SamplingDistribution * RebuildDistributions(bool isUpper=true, int nToys=100, TList *clsDist=nullptr, TList *clsbDist=nullptr, TList *clbDist=nullptr, const char *outputfile="HypoTestInverterRebuiltDist.root")
function to rebuild the distributions
int fMaxToys
maximum number of toys to run
HypoTestInverter()
default constructor (used only for I/O)
~HypoTestInverter() override
destructor
double ConfidenceLevel() const override
Get the Confidence level for the test.
bool SetTestStatistic(TestStatistic &stat)
set the test statistic
HypoTestInverterResult * GetInterval() const override
Run a fixed scan or the automatic scan depending on the configuration.
SamplingDistribution * GetUpperLimitDistribution(bool rebuild=false, int nToys=100)
get the distribution of lower limit if rebuild = false (default) it will re-use the results of the sc...
static unsigned int fgNToys
void Clear()
delete contained result and graph
TestStatistic * GetTestStatistic() const
get the test statistic
std::unique_ptr< TGraphErrors > fLimitPlot
! plot of limits
bool RunFixedScan(int nBins, double xMin, double xMax, bool scanLog=false) const
Run a fixed scan.
bool RunOnePoint(double thisX, bool adaptive=false, double clTarget=-1) const
run only one point at the given POI value
SamplingDistribution * GetLowerLimitDistribution(bool rebuild=false, int nToys=100)
get the upper/lower limit distribution
HypoTestInverter & operator=(const HypoTestInverter &rhs)
assignment
HypoTestCalculatorGeneric * fCalculator0
pointer to the calculator passed in the constructor
void CreateResults() const
create a new HypoTestInverterResult to hold all computed results
static RooRealVar * GetVariableToScan(const HypoTestCalculatorGeneric &hc)
helper functions
HypoTestResult * Eval(HypoTestCalculatorGeneric &hc, bool adaptive, double clsTarget) const
run the hybrid at a single point
HypoTestResult is a base class for results from hypothesis tests.
IntervalCalculator is an interface class for a tools which produce RooStats ConfIntervals.
< A class that holds configuration information for a model using a workspace as a store
Definition ModelConfig.h:34
ProfileLikelihoodTestStat is an implementation of the TestStatistic interface that calculates the pro...
This class simply holds a sampling distribution of some test statistic.
double fUpperLimit
upper interval limit
double fLowerLimit
lower interval limit
TestStatSampler is an interface class for a tools which produce RooStats SamplingDistributions.
virtual TestStatistic * GetTestStatistic() const =0
Get the TestStatistic.
virtual void SetTestStatistic(TestStatistic *testStatistic)=0
Set the TestStatistic (want the argument to be a function of the data & parameter points.
TestStatistic is an interface class to provide a facility for construction test statistics distributi...
ToyMCSampler is an implementation of the TestStatSampler interface.
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:46
virtual void SetLineWidth(Width_t lwidth)
Set the line width.
Definition TAttLine.h:47
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition TAttLine.h:44
1-Dim function class
Definition TF1.h:182
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3787
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:926
Use the TLine constructor to create a simple line.
Definition TLine.h:22
virtual TLine * DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Draw this line with new coordinates.
Definition TLine.cxx:102
A doubly linked list.
Definition TList.h:38
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:952
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:73
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
@ kOverwrite
overwrite existing object with same name
Definition TObject.h:101
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:290
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:2384
TLine * line
Double_t x[n]
Definition legend1.C:17
Namespace for the RooStats classes.
Definition CodegenImpl.h:65
void PrintListContent(const RooArgList &l, std::ostream &os=std::cout)
useful function to print in one line the content of a set with their values
Bool_t AreEqualRel(Double_t af, Double_t bf, Double_t relPrec)
Comparing floating points.
Definition TMath.h:429
Bool_t AreEqualAbs(Double_t af, Double_t bf, Double_t epsilon)
Comparing floating points.
Definition TMath.h:421
static void SetToys(HypoTestType *h, int toyNull, int toyAlt)