Investigations Into Particular Systematics

In [1]:
import ROOT
ROOT.RooMsgService.instance().setGlobalKillBelow(5)
%jsroot on
Welcome to JupyROOT 6.08/02
In [2]:
filename = "HistFactoryCombinedWorkspace.root"
file = ROOT.TFile.Open("./output/"+filename)
ws = file.Get("HistFactoryWorkspace")
data = ws.data("obsData")
mc = ws.obj("ModelConfig")
pdf = mc.GetPdf()

Here we take the standard Systematic workspace and look at the nominal fit (Maximum Likelihood with Minuit).

In [3]:
fit_result = pdf.fitTo(data,ROOT.RooFit.Save())
 **********
 **    1 **SET PRINT           1
 **********
 **********
 **    2 **SET NOGRAD
 **********
 PARAMETER DEFINITIONS:
    NO.   NAME         VALUE      STEP SIZE      LIMITS
     1 SigXsecOverSM   1.00000e+00  3.00000e-01    0.00000e+00  3.00000e+00
     2 alpha_background_shape   0.00000e+00  1.00000e+00   -5.00000e+00  5.00000e+00
     3 alpha_background_uncertainty   0.00000e+00  1.00000e+00   -5.00000e+00  5.00000e+00
     4 alpha_signal_norm_uncertainty   0.00000e+00  1.00000e+00   -5.00000e+00  5.00000e+00
     5 alpha_signal_shape   0.00000e+00  1.00000e+00   -5.00000e+00  5.00000e+00
 **********
 **    3 **SET ERR         0.5
 **********
 **********
 **    4 **SET PRINT           1
 **********
 **********
 **    5 **SET STR           1
 **********
 NOW USING STRATEGY  1: TRY TO BALANCE SPEED AGAINST RELIABILITY
 **********
 **    6 **MIGRAD        2500           1
 **********
 FIRST CALL TO USER FUNCTION AT NEW START POINT, WITH IFLAG=4.
 START MIGRAD MINIMIZATION.  STRATEGY  1.  CONVERGENCE WHEN EDM .LT. 1.00e-03
 FCN=-8405.29 FROM MIGRAD    STATUS=INITIATE       16 CALLS          17 TOTAL
                     EDM= unknown      STRATEGY= 1      NO ERROR MATRIX       
  EXT PARAMETER               CURRENT GUESS       STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  SigXsecOverSM   1.00000e+00   3.00000e-01   2.14402e-01   3.06055e-04
   2  alpha_background_shape   0.00000e+00   1.00000e+00   2.01358e-01   3.00009e-03
   3  alpha_background_uncertainty   0.00000e+00   1.00000e+00   2.01358e-01   1.34364e-03
   4  alpha_signal_norm_uncertainty   0.00000e+00   1.00000e+00   2.01358e-01   1.83238e-04
   5  alpha_signal_shape   0.00000e+00   1.00000e+00   2.01358e-01   4.83836e-04
                               ERR DEF= 0.5
 MIGRAD MINIMIZATION HAS CONVERGED.
 MIGRAD WILL VERIFY CONVERGENCE AND ERROR MATRIX.
 COVARIANCE MATRIX CALCULATED SUCCESSFULLY
 FCN=-8405.29 FROM MIGRAD    STATUS=CONVERGED      73 CALLS          74 TOTAL
                     EDM=2.34185e-12    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  SigXsecOverSM   1.00000e+00   1.72952e-01   4.85665e-03  -1.67792e-05
   2  alpha_background_shape  -5.18222e-08   6.99456e-01   1.20382e-03  -6.55969e-05
   3  alpha_background_uncertainty  -2.36705e-08   7.02405e-01   1.21572e-03  -6.71619e-05
   4  alpha_signal_norm_uncertainty  -2.38327e-07   9.97475e-01   1.04460e-02  -5.61794e-06
   5  alpha_signal_shape  -6.35070e-07   9.98324e-01   1.04938e-02  -6.60640e-06
                               ERR DEF= 0.5
 EXTERNAL ERROR MATRIX.    NDIM=  25    NPAR=  5    ERR DEF=0.5
  3.006e-02 -9.272e-03 -1.426e-03 -6.518e-02 -7.524e-02 
 -9.272e-03  4.925e-01 -4.866e-01 -8.143e-03 -1.038e-02 
 -1.426e-03 -4.866e-01  4.967e-01 -5.391e-03  1.059e-02 
 -6.518e-02 -8.143e-03 -5.391e-03  1.008e+00  5.699e-03 
 -7.524e-02 -1.038e-02  1.059e-02  5.699e-03  1.010e+00 
 PARAMETER  CORRELATION COEFFICIENTS  
       NO.  GLOBAL      1      2      3      4      5
        1  0.78007   1.000 -0.076 -0.012 -0.374 -0.432
        2  0.99078  -0.076  1.000 -0.984 -0.012 -0.015
        3  0.99068  -0.012 -0.984  1.000 -0.008  0.015
        4  0.57017  -0.374 -0.012 -0.008  1.000  0.006
        5  0.56576  -0.432 -0.015  0.015  0.006  1.000
 **********
 **    7 **SET ERR         0.5
 **********
 **********
 **    8 **SET PRINT           1
 **********
 **********
 **    9 **HESSE        2500
 **********
 COVARIANCE MATRIX CALCULATED SUCCESSFULLY
 FCN=-8405.29 FROM HESSE     STATUS=OK             37 CALLS         111 TOTAL
                     EDM=2.62561e-12    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                INTERNAL      INTERNAL  
  NO.   NAME      VALUE            ERROR       STEP SIZE       VALUE   
   1  SigXsecOverSM   1.00000e+00   1.71370e-01   1.94266e-04  -3.39837e-01
   2  alpha_background_shape  -5.18222e-08   6.31019e-01   4.81528e-05  -1.03644e-08
   3  alpha_background_uncertainty  -2.36705e-08   6.33966e-01   4.86287e-05  -4.73410e-09
   4  alpha_signal_norm_uncertainty  -2.38327e-07   9.92991e-01   4.17841e-04  -4.76655e-08
   5  alpha_signal_shape  -6.35070e-07   9.91578e-01   4.19752e-04  -1.27014e-07
                               ERR DEF= 0.5
 EXTERNAL ERROR MATRIX.    NDIM=  25    NPAR=  5    ERR DEF=0.5
  2.951e-02 -8.286e-03 -2.373e-03 -6.308e-02 -7.221e-02 
 -8.286e-03  4.003e-01 -3.942e-01 -7.864e-03 -7.830e-03 
 -2.373e-03 -3.942e-01  4.041e-01 -6.049e-03  7.234e-03 
 -6.308e-02 -7.864e-03 -6.049e-03  9.993e-01  7.902e-04 
 -7.221e-02 -7.830e-03  7.234e-03  7.902e-04  9.964e-01 
 PARAMETER  CORRELATION COEFFICIENTS  
       NO.  GLOBAL      1      2      3      4      5
        1  0.77538   1.000 -0.076 -0.022 -0.367 -0.421
        2  0.98865  -0.076  1.000 -0.980 -0.012 -0.012
        3  0.98853  -0.022 -0.980  1.000 -0.010  0.011
        4  0.56473  -0.367 -0.012 -0.010  1.000  0.001
        5  0.55737  -0.421 -0.012  0.011  0.001  1.000

Since we will take many different fits this nominal fit with the parameters as they are should be our baseline

In [4]:
minNLL_hat = fit_result.minNll()
ws.saveSnapshot('Start', pdf.getParameters(data))
print minNLL_hat
-8405.28557497

Now we want to look at what happens when we fit each nuisance parameter to a fixed given value. Let's see which NPs exist in this workspace.

In [5]:
nuisance_params = mc.GetNuisanceParameters()
it = nuisance_params.createIterator()
var = it.Next()
while var:
    print var.GetName()
    var = it.Next()
alpha_background_shape
alpha_background_uncertainty
alpha_signal_norm_uncertainty
alpha_signal_shape

The basic idea is to take each NP, this can be selected from the list of all parameters by it's name using the find command. In this first iteration we set it's value to 0. and then fix it there.

In [6]:
np_name = "alpha_background_shape"
nuis = nuisance_params.find(np_name)
ws.loadSnapshot('Start')
nuis.setVal(0.)
nuis.setConstant(1)

Now we look at the minimum of the log likelihood fit here.

In [7]:
result = pdf.fitTo(data,ROOT.RooFit.Save(),ROOT.RooFit.PrintLevel(-1))
result.minNll()
Out[7]:
-8405.285574974294

This NP is sort of unique though, it has an interesting range stated as 0-50 however the NLL is poorly behaved outside of 0-2.

In [8]:
nuis.Print("v")
--- RooAbsArg ---
  Value State: clean
  Shape State: clean
  Attributes:  [Constant,SnapShot_ExtRefClone] 
  Address: 0x5b95450
  Clients: 
    (0x5b95c20,V-) RooGaussian::alpha_background_shapeConstraint "alpha_background_shapeConstraint"
    (0x59aa310,V-) PiecewiseInterpolation::background_CR_Hist_alpha ""
    (0x5b8c540,V-) PiecewiseInterpolation::background_SR_Hist_alpha ""
    (0x6057150,V-) RooRealIntegral::CR_model_Int[obs_x_CR] "Integral of CR_model"
    (0x6057ef0,V-) RooRealIntegral::SR_model_Int[obs_x_SR] "Integral of SR_model"
    (0x620b7f0,-S) RooRealIntegral::alpha_background_shapeConstraint_Int[alpha_background_shape] "Integral of alpha_background_shapeConstraint"
  Servers: 
  Proxies: 
--- RooAbsReal ---

  Plot label is "alpha_background_shape"
--- RooAbsRealLValue ---
  Fit range is [ -5 , 5 ]
--- RooRealVar ---
  Error = 0.631019

We can however define a function to iterate over various possible values of this NP. Not forgetting to load the snapshot each time to make sure that the parameters are at the state that they were when they were created.

In [9]:
def get_min(ws,np_name,value):
    ws.loadSnapshot('Start')
    nuis = ws.obj("ModelConfig").GetNuisanceParameters().find(np_name)
    nuis.setRange(-50,60)
    nuis.setVal(value)
    nuis.setConstant(1)
    return ws.obj("ModelConfig").GetPdf().fitTo(ws.data("obsData"),ROOT.RooFit.Save(),ROOT.RooFit.PrintLevel(-1))

Let's test with the value that we know the result from.

In [10]:
print get_min(ws,"alpha_background_shape",0.).minNll()
-8405.2855744

Ok so now let's loop over a load of possible values for this parameter.

In [11]:
import numpy as np
In [12]:
np_values = [0.2*i for i in range(-5,5)] #range(0,2]
d_index = 0
nlls = np.empty(len(np_values))
for value in np_values:
    nlls[d_index] = get_min(ws,"alpha_background_shape",value).minNll()
    print "for value {0} we get a minNLL of {1}".format(value,nlls[d_index])
    d_index+=1
for value -1.0 we get a minNLL of -8403.81771926
for value -0.8 we get a minNLL of -8404.38522931
for value -0.6 we get a minNLL of -8404.80542331
for value -0.4 we get a minNLL of -8405.08352898
for value -0.2 we get a minNLL of -8405.23639247
for value 0.0 we get a minNLL of -8405.2855744
for value 0.2 we get a minNLL of -8405.23200585
for value 0.4 we get a minNLL of -8405.05684882
for value 0.6 we get a minNLL of -8404.75145407
for value 0.8 we get a minNLL of -8404.33778479
In [13]:
c1 = ROOT.TCanvas()
graph = ROOT.TGraph(len(np_values),np.asarray(np_values),nlls)
graph.SetTitle("alpha_background_shape")
graph.Draw()
c1.Draw()

Meaningful Y axis

In this case we want to tranlate the y axis into 2$\Delta$[-log(L)] and draw on the 1 sigma lines.

To form the translation we compute the differenice with the nominal value which we have stored in the "Start" snapshot.

In [14]:
ws.loadSnapshot('Start')
minNLL_hat = fit_result.minNll()
nominal = minNLL_hat
print nominal
-8405.28557497

It's possible to do it with the graph but since we're only interested in certain values of 2$\Delta$[-log(L)] I want to be able to put this calculation into the function directly.

In [15]:
def get_min(ws,np_name,value,nominal):
    ws.loadSnapshot('Start')
    nuis = ws.obj("ModelConfig").GetNuisanceParameters().find(np_name)
    nuis.setVal(value)
    nuis.setConstant(1)
    return 2*(ws.obj("ModelConfig").GetPdf().fitTo(ws.data("obsData"),ROOT.RooFit.Save(),ROOT.RooFit.PrintLevel(-1)).minNll() - nominal)
In [16]:
np_values = [0.2*i for i in range(-20,20)] #range(-4,4)
d_index = 0
nlls = np.empty(len(np_values))
for value in np_values:
    nlls[d_index] = get_min(ws,"alpha_background_shape",value,nominal)
    d_index+=1
In [17]:
c1.Clear()
graph = ROOT.TGraph(len(np_values),np.asarray(np_values),nlls)
graph.SetTitle("alpha_background_shape")
graph.GetYaxis().SetTitle("2#Delta[-log(L)]")

graph.Draw()

line = ROOT.TLine()
line.SetLineStyle(7)
line.SetLineWidth(2)
line.DrawLine(-4, 0, 4, 0)
line.DrawLine(-4, 10, 4, 10)
c1.Draw()

However we're only interested in the bits below 10

In [18]:
c1.Clear()
graph = ROOT.TGraph(len(np_values),np.asarray(np_values),nlls)
graph.SetTitle("alpha_background_shape")
graph.GetYaxis().SetTitle("2#Delta[-log(L)]")

graph.GetYaxis().SetRangeUser(-1,10)
graph.GetXaxis().SetRangeUser(-2,2)

graph.Draw()

line = ROOT.TLine()
line.SetLineStyle(7)
line.SetLineWidth(2)
line.DrawLine(-2, 0, 2, 0)
line.DrawLine(-2, 1, 2, 1)
c1.Draw()
In [ ]: