RooFit - Significance, Limits, Confidence Intervals and Other Statistical Tests

In [1]:
import ROOT
%jsroot on
Welcome to JupyROOT 6.07/07

Reading Workspaces and Recreating Models

First we read in the Combined Model From the RooStats notebook.

In [2]:
infile = ROOT.TFile.Open("output/GausExpModel.root")
w = infile.Get("w")
mc = w.obj("ModelConfig")
data = w.data("data")
mc.LoadSnapshot()
RooFit v3.60 -- Developed by Wouter Verkerke and David Kirkby 
                Copyright (C) 2000-2013 NIKHEF, University of California & Stanford University
                All rights reserved, please read http://roofit.sourceforge.net/license.txt

Profile Likelihood Calculator

Now define a ProfileLikelihood calculator and ask for the 68% interval

In [3]:
pl = ROOT.RooStats.ProfileLikelihoodCalculator(data,mc)
pl.SetConfidenceLevel(0.683)

Find parameters at this interval

In [4]:
mc.LoadSnapshot()
interval = pl.GetInterval()
[#1] INFO:Minization -- p.d.f. provides expected number of events, including extended term in likelihood.
[#0] PROGRESS:Minization -- ProfileLikelihoodCalcultor::DoGLobalFit - find MLE 
[#0] PROGRESS:Minization -- ProfileLikelihoodCalcultor::DoMinimizeNLL - using Minuit / Migrad with strategy 1
[#1] INFO:Minization -- RooMinimizer::optimizeConst: activating const optimization
[#1] INFO:Minization --  The following expressions have been identified as constant and will be precalculated and cached: (sig_pdf)
[#1] INFO:Minization --  The following expressions will be evaluated in cache-and-track mode: (bkg_pdf)
[#1] INFO:Minization -- 
  RooFitResult: minimized FCN value: -4800.92, estimated distance to minimum: 1.54389e-06
                covariance matrix quality: Full, accurate covariance matrix
                Status : MINIMIZE=0 

    Floating Parameter    FinalValue +/-  Error   
  --------------------  --------------------------
                     a   -5.0223e-01 +/-  1.73e-02
                  nbkg    1.0120e+03 +/-  3.57e+01
                  nsig    8.8058e+01 +/-  1.88e+01

find the iterval on the first Parameter of Interest

In [5]:
firstPOI = mc.GetParametersOfInterest().first()
lowerLimit = interval.LowerLimit(firstPOI)
upperLimit = interval.UpperLimit(firstPOI)
In [6]:
print "68% interval on {0} is [{1},{2}]".format(firstPOI.GetName(),lowerLimit,upperLimit)
68% interval on nsig is [69.5552216545,107.189421881]

We can also plot this.

In [7]:
plot = ROOT.RooStats.LikelihoodIntervalPlot(interval)
plot.SetRange(0,150)
#plot.SetNPoints(50)
c = ROOT.TCanvas()
ROOT.gPad.SetLogy(True)
plot.Draw()
c.Draw()
[#1] INFO:Minization -- RooProfileLL::evaluate(nll_model_data_Profile[nsig]) Creating instance of MINUIT
[#1] INFO:Minization -- RooProfileLL::evaluate(nll_model_data_Profile[nsig]) determining minimum likelihood for current configurations w.r.t all observable
[#1] INFO:Minization -- RooProfileLL::evaluate(nll_model_data_Profile[nsig]) minimum found at (nsig=88.0558)
.
[#1] INFO:Minization -- RooProfileLL::evaluate(nll_model_data_Profile[nsig]) Creating instance of MINUIT
[#1] INFO:Minization -- RooProfileLL::evaluate(nll_model_data_Profile[nsig]) determining minimum likelihood for current configurations w.r.t all observable
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name nsig is already in this set
[#1] INFO:Minization -- RooProfileLL::evaluate(nll_model_data_Profile[nsig]) minimum found at (nsig=88.0404)
..........................................................................................................................................................................................................
Error in <THistPainter::PaintInit>: log scale is requested but maximum is less or equal 0 (-1.000000)

Bayesian Markov Chain Monte Carlo Calculator

RooStats has several built in Bayesian calculators. We have the choice between using the MCMC calculator or the numerical one. We will start using the MCMC and optionally in the next exercise we will show how to use the numerical Bayesian calculator. We will use the same model used before for the Profile Likelihood calculator and repeat a similar process.

  • Read the model from the file as in the previous exercise
  • Create the MCMCCalculator class
  • Configure the calculator setting the proposal function, number of iterations, etc..
  • Call the GetInterval function to compute the desired interval. The returned MCMCInterval class will contained the resulting Markov-Chain.
  • Plot the result using the MCMCIntervalPlot class

Once the Data etc are extracted from the workspace. We also need the number of signal events.
To optimise we take a range of possible values (Truth was 100 events)

In [8]:
nsig = w.var("nsig")
nsig.setRange(0,200)

Now we define our MCMC calculator. Again looking at 68.3% confidence level.

In [9]:
mcmc = ROOT.RooStats.MCMCCalculator(data,mc)
mcmc.SetConfidenceLevel(0.683)

Now MCMC methods have various implementations and approaches. Here we must propose a function. The sequential proposal given is usually fairly robust.

In [10]:
sp = ROOT.RooStats.SequentialProposal(0.1)
mcmc.SetProposalFunction(sp)

If you're interested in this I'd recommend looking it up. Here I just define lots of parameters. SetNumIters is related to the number of iterations of the Metropolis-Hastings algorithm SetBurnInSteps concerns how many interations are needed to avoid local minima due to low stats We can construct either a one-sided Bayesian interval (SetLetSideTailFraction=0) or central bayesian interval (SetLetSideTailFraction=0.5)

In [11]:
mcmc.SetNumIters(100000)
mcmc.SetNumBurnInSteps(1000)
mcmc.SetLeftSideTailFraction(0.5)

Now we run the calculator! (may take a while depending on the number of steps)

In [12]:
interval = mcmc.GetInterval()
[#1] INFO:Minization -- p.d.f. provides expected number of events, including extended term in likelihood.
Metropolis-Hastings progress: ....................................................................................................
[#1] INFO:Eval -- Proposal acceptance rate: 10.561%
[#1] INFO:Eval -- Number of steps in chain: 10561

Now we plot and print!

In [13]:
firstPOI = mc.GetParametersOfInterest().first()

print "68% interval on {0} is : [{1},{2}]".format(firstPOI.GetName(),interval.LowerLimit(firstPOI),interval.UpperLimit(firstPOI))
68% interval on nsig is : [70.5808396437,108.270247128]
In [14]:
c = ROOT.TCanvas()
plot = ROOT.RooStats.MCMCIntervalPlot(interval)
plot.Draw()
c.Draw()

Bayesian Numerical Calculator

We can try now to use also the numerical Bayesian calculator on the same model. As before we create the class and configure it setting for example the integration type or the number of iterations. Since the numerical integration can be tricky, it is better in this case to set before a reasonable range from the nuisance parameters, which will be integrated to obtain the marginalised posterior function. A sensible choice is to use for example an interval using 10-sigma around the best fit values for the nuisance parameters.

Note that we have not defined a prior distribution for the parameter of interest (the number of signal events). If a prior is not defined in the model, it is assumed that the prior distribution for the parameter of interest is the uniform distribution in the parameter range.

define reasanable range for nuisance parameters ( +/- 10 sigma around fitted values) to facilitate the integral

In [15]:
mc.Print()
=== Using the following for ModelConfig ===
Observables:             RooArgSet:: = (x)
Parameters of Interest:  RooArgSet:: = (nsig)
Nuisance Parameters:     RooArgSet:: = (a,nbkg)
PDF:                     RooAddPdf::model[ nsig * sig_pdf + nbkg * bkg_pdf ] = 0.067079
Snapshot:                
  1) 0x6590c10 RooRealVar:: nsig = 88.2408 +/- 18.8005  L(0 - 200) B(50)  "nsig"

Unfortunately iterating over parameters is really ikky in python. Also pointers are harder to define.

In [16]:
nuisPar = mc.GetNuisanceParameters()
nuis_iter = nuisPar.createIterator()
var = nuis_iter.Next()
while var:
    var.setRange(var.getVal()-10*var.getError(), var.getVal()+10*var.getError())
    var = nuis_iter.Next()

As before, we define our calculator at 68.3% confidence level.

Again the interval can be defined but here central is default. SetLeftSideTailFraction = {0.5: central interval, 0.: upper limit, NULL:shortest}

the intergration can also be defined using integration type. Default is ADAPTIVE but also available are "VEGAS" , "MISER", "PLAIN" and "TOYMC" if using TOYMC you also need the following lines:

if "TOYMC" in integrationType: nuisPdf = ROOT.RooStats.MakeNuisancePdf(mc, "nuisance_pdf") bayesianCalc.ForceNuisancePdf(nuisPdf)

Now we compute interval by scanning the posterior function.

In [17]:
bayesianCalc = ROOT.RooStats.BayesianCalculator(data,mc)
bayesianCalc.SetConfidenceLevel(0.683)
bayesianCalc.SetLeftSideTailFraction(0.5)
bayesianCalc.SetNumIters(1000)
bayesianCalc.SetIntegrationType("") 
bayesianCalc.SetScanOfPosterior(50)

Now we compute interval by scanning the posterior function.

In [18]:
firstPOI = mc.GetParametersOfInterest().first()
In [19]:
interval = bayesianCalc.GetInterval()
[#1] INFO:Minization -- p.d.f. provides expected number of events, including extended term in likelihood.
[#1] INFO:Eval -- BayesianCalculator::GetPosteriorFunction :  nll value -4788.61 poi value = 187.384
[#1] INFO:Eval -- BayesianCalculator::GetPosteriorFunction : minimum of NLL vs POI for POI =  93.2717 min NLL = -4800.66
[#1] INFO:Eval -- BayesianCalculator - scan posterior function in nbins = 50
[#1] INFO:Eval -- BayesianCalculator::GetInterval - found a valid interval : [70.2153 , 108.02 ]
In [20]:
lowerLimit = interval.LowerLimit()
upperLimit = interval.UpperLimit()

print "68% interval on {0} is : [{1},{2}]".format(firstPOI.GetName(),lowerLimit,upperLimit)
68% interval on nsig is : [70.2152581361,108.019679291]
In [21]:
c = ROOT.TCanvas()
plot = bayesianCalc.GetPosteriorPlot()
plot.Draw()
c.Draw()

Poisson Counting Models

We create now a counting model based on Poisson Statistics. Let's suppose we observe nobs events when we expect nexp, where nexp = s+b (s is the number of signal events and b is the number of background events. The expected distribution for nexp is a Poisson : Poisson( nobs | s+b). s is the parameter we want to estimate or set a limit (the parameter of interest), while b is the nuisance parameter. b is not known exactly, but has uncertainty sigmab. The nominal value of b is = b0=. To express this uncertainty we add in the model a Gaussian constraint. We can interpret this term as having an additional measurement b0 with an uncertainty sigmab: i.e. we have a likelihood for that measurement =Gaussian( b0 | b, sigma). In case of Bayesian statistics we can interpret the constraint as a prior knowledge on the parameter b.

  • Make first the RooFit workspace using its factory syntax. Let's assume nobs=3, b0=1, sigmab=0.2.
  • Create the ModelConfig object and import in the workspace. We need to add in the ModelConfig also b0 as a "global observable". The reason is that b0 needs to be treated as an auxiliary observable in case of frequentist statistics and varied when tossing pseudo-experiments.

here we define nobs as the number of observed events, b as the number of background events, sigmab is the relative uncertainty in number of background events.

In [22]:
nobs = 3
b = 1
sigmab = 0.2 

Now we can define a new poisson model with a Gaussian constraint. The Poisson is (n | s+b)

In [23]:
w = ROOT.RooWorkspace("w")
w.factory("sum:nexp(s[3,0,15],b[1,0,10])")
w.factory("Poisson:pdf(nobs[0,50],nexp)")
w.factory("Gaussian:constraint(b0[0,10],b,sigmab[1])")
w.factory("PROD:model(pdf,constraint)")
Out[23]:
<ROOT.RooProdPdf object ("model") at 0x74e8820>

and set the values. b0 must be set constant in order to be considered as a global observable.

In [24]:
w.var("b0").setVal(b)
w.var("b0").setConstant(True)
w.var("sigmab").setVal(sigmab*b) 

We create the model config, and make sure we make a snapshot (we'll need this later for doing hypothesis testing)

In [25]:
mc = ROOT.RooStats.ModelConfig("ModelConfig",w)
mc.SetPdf(w.pdf("model"))
mc.SetParametersOfInterest(ROOT.RooArgSet(w.var("s")))
mc.SetObservables(ROOT.RooArgSet(w.var("nobs")))
mc.SetNuisanceParameters(ROOT.RooArgSet(w.var("b")))

mc.SetSnapshot(ROOT.RooArgSet(w.var("s")))
mc.SetGlobalObservables(ROOT.RooArgSet(w.var("b0")))

mc.Print()
getattr(w,'import')(mc)
Out[25]:
False
=== Using the following for ModelConfig ===
Observables:             RooArgSet:: = (nobs)
Parameters of Interest:  RooArgSet:: = (s)
Nuisance Parameters:     RooArgSet:: = (b)
Global Observables:      RooArgSet:: = (b0)
PDF:                     RooProdPdf::model[ pdf * constraint ] = 1.32946e-12
Snapshot:                
  1) 0x75fd7c0 RooRealVar:: s = 3  L(0 - 15)  "s"

make data set with the namber of observed events

In [26]:
data = ROOT.RooDataSet("data","", ROOT.RooArgSet(w.var("nobs")))
w.var("nobs").setVal(3)
data.add(ROOT.RooArgSet(w.var("nobs") ))

getattr(w,'import')(data)

w.Print()
[#1] INFO:ObjectHandling -- RooWorkspace::import(w) importing dataset data

RooWorkspace(w) w contents

variables
---------
(b,b0,nobs,s,sigmab)

p.d.f.s
-------
RooGaussian::constraint[ x=b0 mean=b sigma=sigmab ] = 1
RooProdPdf::model[ pdf * constraint ] = 0.195367
RooPoisson::pdf[ x=nobs mean=nexp ] = 0.195367

functions
--------
RooAddition::nexp[ s + b ] = 4

datasets
--------
RooDataSet::data(nobs)

parameter snapshots
-------------------
ModelConfig__snapshot = (s=3)

named sets
----------
ModelConfig_GlobalObservables:(b0)
ModelConfig_NuisParams:(b)
ModelConfig_Observables:(nobs)
ModelConfig_POI:(s)
ModelConfig__snapshot:(s)

generic objects
---------------
RooStats::ModelConfig::ModelConfig

And write to file!

In [27]:
w.writeToFile("output/CountingModel.root", True)
Out[27]:
False

95% Upper Limit Using Counting Model

In [28]:
pl = ROOT.RooStats.ProfileLikelihoodCalculator(data,mc)
pl.SetConfidenceLevel(0.95)
interval = pl.GetInterval()
firstPOI = mc.GetParametersOfInterest().first()
lowerLimit = interval.LowerLimit(firstPOI)
upperLimit = interval.UpperLimit(firstPOI)
print "95% interval on {0} is [{1},{2}]".format(firstPOI.GetName(),lowerLimit,upperLimit)
[#1] INFO:Minization --  Including the following contraint terms in minimization: (constraint)
[#0] PROGRESS:Minization -- ProfileLikelihoodCalcultor::DoGLobalFit - find MLE 
[#0] PROGRESS:Minization -- ProfileLikelihoodCalcultor::DoMinimizeNLL - using Minuit / Migrad with strategy 1
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_model_data_with_constr) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minization -- RooMinimizer::optimizeConst: activating const optimization
[#1] INFO:Minization --  The following expressions will be evaluated in cache-and-track mode: (pdf)
[#1] INFO:Minization -- 
  RooFitResult: minimized FCN value: 0.805423, estimated distance to minimum: 1.81243e-09
                covariance matrix quality: Full, accurate covariance matrix
                Status : MINIMIZE=0 

    Floating Parameter    FinalValue +/-  Error   
  --------------------  --------------------------
                     b    1.0000e+00 +/-  2.00e-01
                     s    1.9999e+00 +/-  1.71e+00

Warning: lower value for s is at limit 0
95% interval on s is [0.0,6.79156747997]
In [29]:
nuisPar = mc.GetNuisanceParameters()
nuis_iter = nuisPar.createIterator()
var = nuis_iter.Next()
while var:
    var.setRange(var.getVal()-10*var.getError(), var.getVal()+10*var.getError())
    var = nuis_iter.Next()

bayesianCalc = ROOT.RooStats.BayesianCalculator(data,mc)
bayesianCalc.SetConfidenceLevel(0.95)
bayesianCalc.SetLeftSideTailFraction(0.) # get the upperlimit
bayesianCalc.SetNumIters(1000)
bayesianCalc.SetIntegrationType("") 
bayesianCalc.SetScanOfPosterior(50)
    
interval = bayesianCalc.GetInterval()
firstPOI = mc.GetParametersOfInterest().first()
lowerLimit = interval.LowerLimit()
upperLimit = interval.UpperLimit()
print "95% interval on {0} is [{1},{2}]".format(firstPOI.GetName(),lowerLimit,upperLimit)
[#1] INFO:Minization --  Including the following contraint terms in minimization: (constraint)
[#1] INFO:Eval -- BayesianCalculator::GetPosteriorFunction :  nll value 2.02948 poi value = 0
[#1] INFO:Eval -- BayesianCalculator::GetPosteriorFunction : minimum of NLL vs POI for POI =  1.92831 min NLL = 0.870054
[#1] INFO:Eval -- BayesianCalculator - scan posterior function in nbins = 50
[#0] WARNING:Eval -- BayesianCalculator::GetInterval : 246 errors reported in evaluating log-likelihood function 
[#1] INFO:Eval -- BayesianCalculator::GetInterval - found a valid interval : [0 , 6.80149 ]
95% interval on s is [0.0,6.80148824815]
In [30]:
c = ROOT.TCanvas()
plot = bayesianCalc.GetPosteriorPlot()
plot.Draw()
c.Draw()

Compute the significance (Hypothesis Test)

The aim of this exercise is to compute the significance of observing a signal in the Gaussian plus Exponential model. It is better to re-generate the model using a lower value for the number of signal events (e.g. 50), in order not to have a too high significance, which will then be difficult to estimate if we use pseudo-experiments. To estimate the significance, we need to perform an hypothesis test. We want to disprove the null model, i.e the background only model against the alternate model, the background plus the signal. In RooStats, we do this by defining two two ModelConfig objects, one for the null model (the background only model in this case) and one for the alternate model (the signal plus background).

We have defined in the workspace saved in the ROOT file only the signal plus background model. We can create the background model from the signal plus background model by setting the value of nsig=0. We do this by cloning the S+B model and by defining a snapshot in the ModelConfig for nsig with a different value:

In [31]:
sbModel = w.obj("ModelConfig")
poi = sbModel.GetParametersOfInterest().first()
poi.setVal(50)
sbModel.SetSnapshot(ROOT.RooArgSet(poi))
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
In [32]:
bModel = sbModel.Clone()
bModel.SetName("B_only_model")
poi.setVal(0)
bModel.SetSnapshot(ROOT.RooArgSet(poi))

Using the given models plus the observed data set, we can create a RooStats hypothesis test calculator to compute the significance. We have the choice between

  • Frequentist calculator
  • Hybrid Calculator
  • Asymptotic calculator

The first two require generate pseudo-experiment, while the Asymptotic calculator, requires only a fit to the two models. For the Frequentist and the Hybrid calculators we need to choose also the test statistics. We have various choices in RooStats. Since it is faster, we will use for the exercise the Asymptotic calculator. The Asymptotic calculator it is based on the Profile Likelihood test statistics, the one used at LHC (see slides for its definition). For testing the significance, we must use the one-side test statistic (we need to configure this explicitly in the class). Summarising, we will do:

  • create the AsymptoticCalculator class using the two models and the data set;
  • run the test of hypothesis using the GetHypoTest function.
  • Look at the result obtained as a HypoTestResult object
In [33]:
infile = ROOT.TFile.Open("output/GausExpModel.root")
w = infile.Get("w")
data = w.data("data")
sbModel = w.obj("ModelConfig")
sbModel.SetName("S+B Model")
poi = sbModel.GetParametersOfInterest().first()
poi.setVal(50)
sbModel.SetSnapshot(ROOT.RooArgSet(poi))
bModel = sbModel.Clone()
bModel.SetName("B Model")
poi.setVal(0)
bModel.SetSnapshot(ROOT.RooArgSet(poi))
In [34]:
w.Print()
RooWorkspace(w) w contents

variables
---------
(a,mass,nbkg,nsig,sigma,x)

p.d.f.s
-------
RooExponential::bkg_pdf[ x=x c=a ] = 0.0810144
RooAddPdf::model[ nsig * sig_pdf + nbkg * bkg_pdf ] = 0.0810144
RooGaussian::sig_pdf[ x=x mean=mass sigma=sigma ] = 1.92875e-22

datasets
--------
RooDataSet::data(x)

parameter snapshots
-------------------
ModelConfig__snapshot = (nsig=88.2408 +/- 18.8005)
S+B Model__snapshot = (nsig=50 +/- 18.8005)
B Model__snapshot = (nsig=0 +/- 18.8005)

named sets
----------
B Model__snapshot:(nsig)
ModelConfig_NuisParams:(a,nbkg)
ModelConfig_Observables:(x)
ModelConfig_POI:(nsig)
ModelConfig__snapshot:(nsig)
S+B Model__snapshot:(nsig)
nuisParams:(a,nbkg)

generic objects
---------------
RooStats::ModelConfig::S+B Model

In [35]:
ac = ROOT.RooStats.AsymptoticCalculator(data, sbModel, bModel)
ac.SetOneSidedDiscovery(True)
[#0] PROGRESS:Eval -- AsymptoticCalculator::Initialize....
[#0] PROGRESS:Eval -- AsymptoticCalculator::Initialize - Find  best unconditional NLL on observed data
AsymptoticCalculator::EvaluateNLL  ........ using Minuit / Migrad with strategy  1 and tolerance 1
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.02626e-01  1.73349e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.01171e+03  3.57297e+01    0.00000e+00  1.00000e+04
     3 nsig         0.00000e+00  1.88005e+01    0.00000e+00  1.00000e+04
 MINUIT WARNING IN PARAM DEF
 ============== STARTING VALUE IS AT LIMIT.
 MINUIT WARNING IN PARAMETR
 ============== VARIABLE3 IS AT ITS LOWER ALLOWED LIMIT.
 MINUIT WARNING IN PARAMETR
 ============== VARIABLE3 BROUGHT BACK INSIDE LIMITS.
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1500           1
 **********
 MINUIT WARNING IN MIGrad    
 ============== VARIABLE3 IS AT ITS LOWER ALLOWED LIMIT.
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4800.92 FROM MIGRAD    STATUS=CONVERGED      60 CALLS          61 TOTAL
                     EDM=1.59488e-05    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -5.02172e-01   1.73280e-02   1.23283e-03   1.49880e-01
   2  nbkg         1.01194e+03   3.57328e+01   5.20746e-04  -7.04206e-03
   3  nsig         8.80584e+01   1.87975e+01   8.81264e-04   5.05607e-02
                               ERR DEF= 0.5
AsymptoticCalculator::EvaluateNLL -  value = -4800.92	fit time : Real time 0:00:00, CP time 0.020
[#0] PROGRESS:Eval -- Best fitted POI value = 88.0584 +/- 18.7975
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#1] INFO:InputArguments -- AsymptoticCalculator: Asimov data will be generated using fitted nuisance parameter values
MakeAsimov: Setting poi nsig to a constant value = 50
MakeAsimov: doing a conditional fit for finding best nuisance values 
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.02172e-01  1.73280e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.01194e+03  3.57328e+01    0.00000e+00  1.00000e+04
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1000           1
 **********
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4798.72 FROM MIGRAD    STATUS=CONVERGED      28 CALLS          29 TOTAL
                     EDM=6.11687e-09    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -5.01879e-01   1.70457e-02   1.21266e-03   3.64022e-04
   2  nbkg         1.04398e+03   3.30319e+01   5.16740e-04  -7.19003e-03
                               ERR DEF= 0.5
fit time Real time 0:00:00, CP time 0.010
RooDataSet::AsimovData[x,weight:binWeightAsimov] = 50 entries (1093.54 weighted)
Generated Asimov data for observables RooArgSet:: = (x)
[#0] PROGRESS:Eval -- AsymptoticCalculator::Initialize Find  best conditional NLL on ASIMOV data set for given alt POI ( nsig ) = 50
AsymptoticCalculator::EvaluateNLL  ........ using Minuit / Migrad with strategy  1 and tolerance 1
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.01879e-01  1.70457e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.04398e+03  3.30319e+01    0.00000e+00  1.00000e+04
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1000           1
 **********
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4756.23 FROM MIGRAD    STATUS=CONVERGED      23 CALLS          24 TOTAL
                     EDM=2.02301e-09    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -5.01372e-01   1.70376e-02   1.20714e-03   5.91885e-04
   2  nbkg         1.04352e+03   3.29479e+01   5.13350e-04  -3.93618e-03
                               ERR DEF= 0.5
AsymptoticCalculator::EvaluateNLL -  value = -4756.23 for poi fixed at = 50	fit time : Real time 0:00:00, CP time 0.000
[#1] INFO:InputArguments -- AsymptotiCalculator: Minimum of POI is 0 corresponds to null  snapshot   - default configuration is  one-sided discovery formulae  
In [36]:
asResult = ac.GetHypoTest()
asResult.Print()
[#1] INFO:Eval -- AsymptoticCalculator::GetHypoTest: - perform  an hypothesis test for  POI ( nsig ) = 0
[#0] PROGRESS:Eval -- AsymptoticCalculator::GetHypoTest -  Find  best conditional NLL on OBSERVED data set ..... 
AsymptoticCalculator::EvaluateNLL  ........ using Minuit / Migrad with strategy  1 and tolerance 1
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.02172e-01  1.73280e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.01194e+03  3.57328e+01    0.00000e+00  1.00000e+04
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1000           1
 **********
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4787.77 FROM MIGRAD    STATUS=CONVERGED      26 CALLS          27 TOTAL
                     EDM=4.56397e-06    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -5.01161e-01   1.65796e-02   1.17928e-03   3.63114e-04
   2  nbkg         1.09993e+03   3.31640e+01   5.06101e-04  -2.01545e-01
                               ERR DEF= 0.5
AsymptoticCalculator::EvaluateNLL -  value = -4787.77 for poi fixed at = 0	fit time : Real time 0:00:00, CP time 0.000
[#0] PROGRESS:Eval -- 	 OBSERVED DATA :  qmu   = 26.2922 condNLL = -4787.77 uncond -4800.92
[#0] PROGRESS:Eval -- AsymptoticCalculator::GetHypoTest -- Find  best conditional NLL on ASIMOV data set .... 
AsymptoticCalculator::EvaluateNLL  ........ using Minuit / Migrad with strategy  1 and tolerance 1
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.01161e-01  1.65796e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.09993e+03  3.31640e+01    0.00000e+00  1.00000e+04
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1000           1
 **********
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4751.78 FROM MIGRAD    STATUS=CONVERGED      21 CALLS          22 TOTAL
                     EDM=1.45841e-07    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -5.00373e-01   1.66106e-02   1.17769e-03  -7.84522e-04
   2  nbkg         1.09353e+03   3.30678e+01   5.05416e-04  -3.59941e-02
                               ERR DEF= 0.5
AsymptoticCalculator::EvaluateNLL -  value = -4751.78 for poi fixed at = 0	fit time : Real time 0:00:00, CP time 0.000
[#0] PROGRESS:Eval -- 	 ASIMOV data qmu_A = 8.89773 condNLL = -4751.78 uncond -4756.23
[#0] PROGRESS:Eval -- poi = 0 qmu = 26.2922 qmu_A = 8.89773 sigma = 0  CLsplusb = 1.46733e-07 CLb = 0.0159889 CLs = 108966

Results HypoTestAsymptotic_result: 
 - Null p-value = 1.46733e-07
 - Significance = 5.1276
 - CL_b: 1.46733e-07
 - CL_s+b: 0.0159889
 - CL_s: 108966

And the frequentist appproach.

This needs test statistics.

In [37]:
fc = ROOT.RooStats.FrequentistCalculator(data, sbModel, bModel)
fc.SetToys(2000,500)
profll = ROOT.RooStats.ProfileLikelihoodTestStat(sbModel.GetPdf())
profll.SetOneSidedDiscovery(True)

toymcs = ROOT.RooStats.ToyMCSampler(fc.GetTestStatSampler())
toymcs.SetTestStatistic(profll)
In [38]:
if not sbModel.GetPdf().canBeExtended():
    toymcs.SetNEventsPerToy(1)
    print 'adjusting for non-extended formalism'

Run the test!

In [39]:
fqResult = fc.GetHypoTest()
fqResult.Print()
=== Using the following for B Model ===
Observables:             RooArgSet:: = (x)
Parameters of Interest:  RooArgSet:: = (nsig)
Nuisance Parameters:     RooArgSet:: = (a,nbkg)
PDF:                     RooAddPdf::model[ nsig * sig_pdf + nbkg * bkg_pdf ] = 0.479168/1
Snapshot:                
  1) 0x7b25750 RooRealVar:: nsig = 0 +/- 18.8005  L(0 - 10000)  "nsig"


=== Using the following for S+B Model ===
Observables:             RooArgSet:: = (x)
Parameters of Interest:  RooArgSet:: = (nsig)
Nuisance Parameters:     RooArgSet:: = (a,nbkg)
PDF:                     RooAddPdf::model[ nsig * sig_pdf + nbkg * bkg_pdf ] = 0.479168/1
Snapshot:                
  1) 0x7b25750 RooRealVar:: nsig = 50 +/- 18.8005  L(0 - 10000)  "nsig"

[#0] PROGRESS:Generation -- Test Statistic on data: 10.9415
[#1] INFO:InputArguments -- Profiling conditional MLEs for Null.
[#1] INFO:InputArguments -- Using a ToyMCSampler. Now configuring for Null.
[#0] PROGRESS:Generation -- generated toys: 500 / 2000
[#0] PROGRESS:Generation -- generated toys: 1000 / 2000
[#0] PROGRESS:Generation -- generated toys: 1500 / 2000
[#1] INFO:InputArguments -- Profiling conditional MLEs for Alt.
[#1] INFO:InputArguments -- Using a ToyMCSampler. Now configuring for Alt.

Results HypoTestCalculator_result: 
 - Null p-value = 0 +/- 0
 - Significance = inf +/- -nan sigma
 - Number of Alt toys: 500
 - Number of Null toys: 2000
 - Test statistic evaluated on data: 10.9415
 - CL_b: 0 +/- 0
 - CL_s+b: 0.026 +/- 0.00711674
Error: Cannot compute CLs because CLb = 0. Returning CLs = -1
 - CL_s: -1 +/- -1

and plot!

In [40]:
c = ROOT.TCanvas()
plot = ROOT.RooStats.HypoTestPlot(fqResult)
plot.SetLogYaxis(True)
plot.Draw()
c.Draw()

Compute significance (p-value) as function of the signal mass

As an optional exercise to lear more about computing significance in RooStats, we will study the significance (or equivalent the p-value) we obtain in our Gaussian signal plus exponential background model as function of the signal mass hypothesis. For doing this we perform the test of hypothesis, using the AsymptoticCalculator, for several mass points. We can then plot the obtained p-value for the null hypothesis (p0). We will also estimate the expected significance for our given S+B model as function of its mass. The expected significance can be obtained using a dedicated function in the AsymptoticCalculator: AsymptoticCalculator::GetExpectedPValues using as input the observed p-values for the null and the alternate models. See the Asymptotic formulae paper for the details.

In [41]:
massMin = 0.5
massMax = 8.5
masses = []
p0values = []
p0valuesExpected = []
In [42]:
stepsize = (massMax-massMin)/40.0
masslist = [massMin + i*stepsize for i in range(41)]
for mass in masslist:
    w.var("mass").setVal(mass)
    ac = ROOT.RooStats.AsymptoticCalculator(data, sbModel, bModel)
    ac.SetOneSidedDiscovery(True)
    ac.SetPrintLevel(-1)
    asymCalcResult = ac.GetHypoTest()
    masses.append(mass)
    p0values.append(asymCalcResult.NullPValue())
    expectedP0 = ROOT.RooStats.AsymptoticCalculator.GetExpectedPValues(  
            asymCalcResult.NullPValue(),  asymCalcResult.AlternatePValue(), 0, False)
    p0valuesExpected.append(expectedP0)
[#0] PROGRESS:Eval -- AsymptoticCalculator::Initialize....
[#0] PROGRESS:Eval -- AsymptoticCalculator::Initialize - Find  best unconditional NLL on observed data
AsymptoticCalculator::EvaluateNLL  ........ using Minuit / Migrad with strategy  1 and tolerance 1
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.00373e-01  1.66106e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.09353e+03  3.30678e+01    0.00000e+00  1.00000e+04
     3 nsig         0.00000e+00  1.88005e+01    0.00000e+00  1.00000e+04
 MINUIT WARNING IN PARAM DEF
 ============== STARTING VALUE IS AT LIMIT.
 MINUIT WARNING IN PARAMETR
 ============== VARIABLE3 IS AT ITS LOWER ALLOWED LIMIT.
 MINUIT WARNING IN PARAMETR
 ============== VARIABLE3 BROUGHT BACK INSIDE LIMITS.
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1500           1
 **********
 MINUIT WARNING IN MIGrad    
 ============== VARIABLE3 IS AT ITS LOWER ALLOWED LIMIT.
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4787.77 FROM MIGRAD    STATUS=CONVERGED      31 CALLS          32 TOTAL
                     EDM=4.60725e-07    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -5.01158e-01   1.65799e-02   1.17987e-03   7.49659e-03
   2  nbkg         1.09998e+03   3.31661e+01   5.05480e-04  -6.15821e-02
   3  nsig         1.05804e-09   5.68587e+00   2.36570e-03** at limit **
                               ERR DEF= 0.5
AsymptoticCalculator::EvaluateNLL -  value = -4787.77	fit time : Real time 0:00:00, CP time 0.020
[#0] PROGRESS:Eval -- Best fitted POI value = 1.05804e-09 +/- 5.68587
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#1] INFO:InputArguments -- AsymptoticCalculator: Asimov data will be generated using fitted nuisance parameter values
MakeAsimov: Setting poi nsig to a constant value = 50
MakeAsimov: doing a conditional fit for finding best nuisance values 
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -5.01158e-01  1.65799e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.09998e+03  3.31661e+01    0.00000e+00  1.00000e+04
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1000           1
 **********
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4782.12 FROM MIGRAD    STATUS=CONVERGED      30 CALLS          31 TOTAL
                     EDM=1.29242e-07    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -4.84152e-01   1.67288e-02   1.21603e-03  -3.76154e-03
   2  nbkg         1.05690e+03   3.31289e+01   5.14431e-04   3.18921e-02
                               ERR DEF= 0.5
fit time Real time 0:00:00, CP time 0.010
RooDataSet::AsimovData[x,weight:binWeightAsimov] = 50 entries (1106.65 weighted)
Generated Asimov data for observables RooArgSet:: = (x)
[#0] PROGRESS:Eval -- AsymptoticCalculator::Initialize Find  best conditional NLL on ASIMOV data set for given alt POI ( nsig ) = 50
AsymptoticCalculator::EvaluateNLL  ........ using Minuit / Migrad with strategy  1 and tolerance 1
 **********
 **    1 **SET PRINT           0
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 a           -4.84152e-01  1.67288e-02   -2.00000e+00 -2.00000e-01
     2 nbkg         1.05690e+03  3.31289e+01    0.00000e+00  1.00000e+04
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           0
 **********
 **********
 **    5 **SET STR           1
 **********
 **********
 **    6 **MIGRAD        1000           1
 **********
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 FCN=-4828.61 FROM MIGRAD    STATUS=CONVERGED      19 CALLS          20 TOTAL
                     EDM=1.18933e-06    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  a           -4.83674e-01   1.67532e-02   1.22468e-03  -1.76282e-02
   2  nbkg         1.05647e+03   3.32309e+01   5.18533e-04   9.04591e-02
                               ERR DEF= 0.5
AsymptoticCalculator::EvaluateNLL -  value = -4828.61 for poi fixed at = 50	fit time : Real time 0:00:00, CP time 0.000
[#1] INFO:InputArguments -- AsymptotiCalculator: Minimum of POI is 0 corresponds to null  snapshot   - default configuration is  one-sided discovery formulae  
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
    ----> Doing a re-scan first
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
In [43]:
import numpy as np
c = ROOT.TCanvas()
graph1 = ROOT.TGraph(len(masses),np.asarray(masses),np.asarray(p0values))
graph2 = ROOT.TGraph(len(masses),np.asarray(masses),np.asarray(p0valuesExpected))
graph1.SetMarkerStyle(20)
graph1.Draw("APC")
graph2.SetLineStyle(2)
graph2.Draw("C")

graph1.GetXaxis().SetTitle("mass")
graph1.GetYaxis().SetTitle("p0 value")
graph1.SetTitle("Significance vs Mass")
graph1.SetMinimum(graph2.GetMinimum())
graph1.SetLineColor(4)
graph2.SetLineColor(2)
ROOT.gPad.SetLogy(True)
c.Draw()

Compute Limits using Hypothesis Test Inversion (CLs Limits).

In our last exercise we will compute an upper limit using the frequentist hypothesis test inversion method. We need to perform the hypothesis test for different parameter of interest points and compute the corresponding p-values. Since we are interesting in computing a limit, the test null hypothesis, that we want to disprove, is the in this case the S+B model, while the alternate hypothesis is the B only model. It is important to remember this, when we construct the hypothesis test calculator.

For doing the inversion RooStats provides an helper class, HypoTestInverter, which is constructed using one of the HypoTest calculator (Frequentist, Hybrid or Asymptotic). To compute the limit we need to do:

  • Create/read a workspace with S+B and B only model. If the B model does not exist we can create as in the previous exercise (setting the poi to zero).
  • Create an HypoTest calculator but using as null the S+B model and as alt the B only model
  • Configure the calculator if needed (set test statistics, number of toys, etc..)
  • Create the HypoTestInverter class and configure it (e.g. to set the number and range of points to scan, to use CLs for computing the limit, etc…)
  • Run the Inverter using GetInterval which returns an HypoTestInverterResult object.
  • Look at the result (e.g. limit, expected limits and bands)
  • Plot the result of the scan and the test statistic distribution obtained at every point.
In [44]:
infile = ROOT.TFile.Open("output/CountingModel.root")
w = infile.Get("w")
mc = w.obj("ModelConfig")
data = w.data("data")

sbModel = w.obj("ModelConfig")
poi = sbModel.GetParametersOfInterest().first()
bModel = sbModel.Clone()
bModel.SetName(sbModel.GetName()+"_with_poi_0")
poi.setVal(0)
bModel.SetSnapshot(ROOT.RooArgSet(poi))
In [45]:
fc = ROOT.RooStats.FrequentistCalculator(data, bModel, sbModel)
fc.SetToys(1000,500)
ac = ROOT.RooStats.AsymptoticCalculator(data, bModel, sbModel)
ac.SetOneSided(True)
ac.SetPrintLevel(-1)

calc = ROOT.RooStats.HypoTestInverter(ac)
calc.SetConfidenceLevel(0.95)
[#0] PROGRESS:Eval -- AsymptoticCalculator: Building Asimov data Set
[#1] INFO:InputArguments -- HypoTestInverter ---- Input models: 
		 using as S+B (null) model     : ModelConfig
		 using as B (alternate) model  : ModelConfig_with_poi_0

for CLS

In [46]:
calc.UseCLs(True)
calc.SetVerbose(False)
In [47]:
toymcs = calc.GetHypoTestCalculator().GetTestStatSampler()

Profile likelihood test statistics are used one sided for CLs since it's a bounded interval.

In [48]:
profll = ROOT.RooStats.ProfileLikelihoodTestStat(sbModel.GetPdf())
profll.SetOneSided(True)
toymcs.SetTestStatistic(profll)
In [49]:
if not sbModel.GetPdf().canBeExtended():
    toymcs.SetNEventsPerToy(1)
    print 'can not be extended'
can not be extended

define the number of points and some minmaxes

In [50]:
npoints = 10
poimin = poi.getMin()
poimax = poi.getMax()
In [51]:
calc.SetFixedScan(npoints,poimin,poimax)
r = calc.GetInterval()
upperLimit = r.UpperLimit()
[#1] INFO:Eval -- HypoTestInverter::GetInterval - run a fixed scan
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:InputArguments -- Minimum of POI is 0 corresponds to alt  snapshot   - using qtilde asymptotic formulae  
[#1] INFO:Eval -- Using one-sided qmu - setting qmu to zero  muHat = 2.00181 muTest = 0
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:Eval -- Using one-sided qmu - setting qmu to zero  muHat = 2.00181 muTest = 1.66667
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
[#1] INFO:ObjectHandling -- RooWorkspace::saveSnaphot(w) replacing previous snapshot with name ModelConfig__snapshot
In [52]:
plot = ROOT.RooStats.HypoTestInverterPlot("HTI_Result_Plot","HypoTest Scan Result",r)
c = ROOT.TCanvas("HypoTestInverter Scan")
c.SetLogy(False)
plot.Draw("CLb 2CL")
c.Draw()
In [ ]: