In [1]:
import ROOT
%jsroot on
ROOT.RooMsgService.instance().setGlobalKillBelow(5)
from matplotlib import pyplot
%matplotlib inline
Welcome to JupyROOT 6.07/07

Preselection Workspace

First we retrieve the workspace created in ExploringData

In [2]:
infile = ROOT.TFile.Open("output/Preselection.root")
w = infile.Get("w")
mc = w.obj("ModelConfig")
data = w.data("data")
x = w.var("x")
mc.LoadSnapshot()

We create a model. From the distributions that we looked at before creating this workspace we know that the background follows a Breit Wigner distribution so let us fit a function to this.

This function is built into RooFit and can be defined as:

In [3]:
mean = ROOT.RooRealVar("mean","Mean of Gaussian",91,0,200)
sigma = ROOT.RooRealVar("sigma","Width of Gaussian",40,0,200)
ztautau = ROOT.RooBreitWigner("ztautau","Breit-Wigner(x,mean,sigma)",x,mean,sigma)

However is a pdf. We want to use the extended likelihood formalism (adding the normlisation).

First we retrieve the number of background events from the workspace.

In [4]:
nbkg = w.var("n_bkg")
n_bkg_true = nbkg.getVal()

And now we extend the pdf.

In [5]:
background = ROOT.RooExtendPdf("background","background distribution",ztautau,nbkg)

now we can fit to the data!

In [6]:
background.fitTo(data,ROOT.RooFit.Range(0,200),ROOT.RooFit.PrintLevel(-1))
Out[6]:
<ROOT.RooFitResult object at 0x(nil)>
In [7]:
c = ROOT.TCanvas()
plot = x.frame(ROOT.RooFit.Title("Reconstructed Mass"))
plot.SetTitle("")
plot.GetYaxis().SetTitleOffset(1.)
plot.GetYaxis().SetTitleSize(0.05)
plot.GetXaxis().SetTitleSize(0.05)
plot.SetXTitle("MMC mass (GeV)")
data.plotOn(plot,ROOT.RooFit.Name("data"))
background.plotOn(plot,ROOT.RooFit.Name("ztautau"))

l = ROOT.TLegend( 0.1, 0.6, 0.4, 0.9)
dataobj = plot.findObject("data")
zobj = plot.findObject("ztautau")

l.AddEntry( dataobj , "Data", "pl" )
l.AddEntry( zobj , "{0:0.0f}GeV Z mass ".format(mean.getVal()), "l"  )
l.SetTextSizePixels(400)
plot.Draw()
l.Draw()
c.Draw()

VBF workspace

This process can be repeated (almost) identically to before.

In [8]:
infile = ROOT.TFile.Open("output/VBFselection.root")
w = infile.Get("w")
mc = w.obj("ModelConfig")
data = w.data("data")
mc.LoadSnapshot()
x = w.var("x")

This time we don't assume that the Z peak is the only background contributing. A poloynomial is added to approximate the fake multijet background.

In [9]:
mean = ROOT.RooRealVar("mean","Mean of Gaussian",0,200)
sigma = ROOT.RooRealVar("sigma","Width of Gaussian",40,0,200)
ztautau = ROOT.RooBreitWigner("ztautau","Breit-Wigner(x,mean,sigma)",x,mean,sigma)
coef0 = ROOT.RooRealVar("c0","coefficient #0",1.0,-1.,1)
coef1 = ROOT.RooRealVar("c1","coefficient #1",0.1,-1.,1)
coef2 = ROOT.RooRealVar("c2","coefficient #2",-0.1,-1.,1)
fake = ROOT.RooChebychev("fake","background p.d.f.",x,ROOT.RooArgList(coef0,coef1,coef2))
fbkg = ROOT.RooRealVar("fbkg","background fraction",0.9,0.,1.)
model = ROOT.RooAddPdf('prod','prod',ROOT.RooArgList(ztautau,fake),ROOT.RooArgList(fbkg))
mean.setVal(91.1876)
In [10]:
nbkg = w.var("n_bkg")
background = ROOT.RooExtendPdf("background","background distribution",model,nbkg)
In [11]:
background.fitTo(data,ROOT.RooFit.Range(0,200),ROOT.RooFit.PrintLevel(-1))
Out[11]:
<ROOT.RooFitResult object at 0x(nil)>
 MINUIT WARNING IN MIGrad    
 ============== VARIABLE1 IS AT ITS UPPER ALLOWED LIMIT.
 EIGENVALUES OF SECOND-DERIVATIVE MATRIX:
        -7.9556e-06  5.2046e-01  7.3021e-01  1.0000e+00  1.0851e+00  1.4406e+00  2.2236e+00
 MINUIT WARNING IN MIGRAD  
 ============== MATRIX FORCED POS-DEF BY ADDING 0.002232 TO DIAGONAL.
 EIGENVALUES OF SECOND-DERIVATIVE MATRIX:
        -9.1957e-01 -3.0093e-08  2.6145e-01  5.2983e-01  9.8704e-01  1.0000e+00  5.1413e+00
 MINUIT WARNING IN MIGRAD  
 ============== MATRIX FORCED POS-DEF BY ADDING 0.924710 TO DIAGONAL.
 MINUIT WARNING IN MIGRAD  
 ============== Negative diagonal element 2 in Error Matrix
 MINUIT WARNING IN MIGRAD  
 ============== Negative diagonal element 3 in Error Matrix
 MINUIT WARNING IN MIGRAD  
 ============== Negative diagonal element 4 in Error Matrix
 MINUIT WARNING IN MIGRAD  
 ============== Negative diagonal element 7 in Error Matrix
 MINUIT WARNING IN MIGRAD  
 ============== 1.02358 added to diagonal of error matrix
 EIGENVALUES OF SECOND-DERIVATIVE MATRIX:
        -1.3075e-01  3.1334e-01  8.4666e-01  9.9998e-01  1.0000e+00  1.7153e+00  2.2555e+00
 MINUIT WARNING IN HESSE   
 ============== MATRIX FORCED POS-DEF BY ADDING 0.133010 TO DIAGONAL.
 EIGENVALUES OF SECOND-DERIVATIVE MATRIX:
        -1.2247e-01  7.5853e-01  9.9997e-01  1.0000e+00  1.0000e+00  1.1127e+00  2.2513e+00
 MINUIT WARNING IN HESSE   
 ============== MATRIX FORCED POS-DEF BY ADDING 0.124720 TO DIAGONAL.
In [12]:
c = ROOT.TCanvas()
plot = x.frame(ROOT.RooFit.Title("Reconstructed Mass"))
plot.SetTitle("")
plot.GetYaxis().SetTitleOffset(1.)
plot.GetYaxis().SetTitleSize(0.05)
plot.GetXaxis().SetTitleSize(0.05)
plot.SetXTitle("MMC mass (GeV)")
data.plotOn(plot,ROOT.RooFit.Name("data"))
background.plotOn(plot,ROOT.RooFit.Name("ztautau"))
background.plotOn(plot,ROOT.RooFit.Components("fake"),ROOT.RooFit.Name("fake"), ROOT.RooFit.LineStyle(2) )
l = ROOT.TLegend( 0.6, 0.6, 0.9, 0.9)
dataobj = plot.findObject("data")
zobj = plot.findObject("background")
fobj = plot.findObject("fake")
l.AddEntry( dataobj , "VBF Data", "pl" )
l.AddEntry( zobj , "{0:0.0f} GeV Z mass".format(mean.getVal()), "l"  )
l.AddEntry( fobj , "fake component", "l"  )
l.SetTextSizePixels(400)
plot.Draw()
l.Draw()
c.Draw()

As can be seen the Z mass peak is much better approximated in the VBF region.

In [ ]: