def GetYield2(path, files, ch='eee', level='sr', inc=None, histopref='', filepref='', var='', isdata=False): t = TopHistoReader(path, files) t.SetLevel(level) t.SetChan(ch) t.SetHistoNamePrefix(histopref) #t.SetLumi(GetLumi(2018)*1000) #t.SetLumi(GetLumi(year)*1000) #t.SetLumi(1) t.SetFileNamePrefix(filepref) t.SetIsData(isdata) if var != '': pref = histopref + '_' if histopref != '' else '' if inc == None: h = t.GetNamedHisto(pref + var + '_' + ch) else: h = t.GetNamedHisto(pref + var + '_' + ch + '_' + inc) y = h.GetBinContent(9) else: y = t.GetYield() return y
def loadHistos(self): ''' Load the PDF and Scale histos and norm histos ''' t = TopHistoReader(self.path) t.SetHistoNamePrefix(self.histoprefix) t.SetIsData(1) n = self.GetSampleName() t.SetProcess(n) t.SetChan(self.GetChan()) t.SetLevel(self.GetLevel()) #if self.GetNgenEvents() <= 0 : self.SetNgenEvents(t.GetNGenEvents()) self.SetYield(t.GetYield() * self.GetLumi()) self.hpdf = t.GetHisto(n, self.PDFhistoName) self.hscale = t.GetHisto(n, self.scaleHistoName) #self.hPS = t.GetHisto(n,self.PShistoName) if self.pathToTrees != '' and self.motherfname != '': self.LoadTreeSumOfWeights(self.pathToTrees, self.motherfname) self.hsumpdf = t.GetNamedHisto( self.normPDFhistoName ) if self.normPDFhistoName != '' else self.GetSumPDFhistoFromSumWTree( ) self.hsumscale = t.GetNamedHisto( self.normScaleHitstoName ) if self.normScaleHitstoName != '' else self.GetSumScaleHistoFromSumWTree( ) self.SetNgenEvents(self.count) self.nPDFweights = self.hsumpdf.GetNbinsX() self.nScaleWeighs = self.hsumscale.GetNbinsX() print '>> Count : ', self.count print '>> SumOfWeights : ', self.sow
class DYDD: ### Set methods def SetPath(self, p): if not p.endswith('/'): p += '/' self.path = p def SetOutPath(self, p): self.outpath = p def SetMode(self, mode='OF', hname=''): self.doOF = True if mode in ['SF', 'Elec', 'ElEl', 'Muon', 'MuMu']: self.doOF = False if self.doOF: if hname != '': self.SetHistoNameOF(hname) self.SetZhistoName(self.hnameOF) else: if hname != '': self.SetHistoNameSF(hname) self.SetZhistoName(self.hnameSF) def SetLumi(self, l): self.lumi = l self.t.SetLumi(self.lumi) def SetHistoNameOF(self, h='DY_InvMass'): self.hnameOF = h def SetHistoNameSF(self, h='DY_SF_InvMass'): self.hnameSF = h def SetDYsamples(self, f): self.DYfiles = f def SetDataSamples(self, f): self.datafiles = f def SetChannel(self, c): self.chan = c def SetLevel(self, l): self.level = l def SetZhistoName(self, h): self.zhname = h def SetMassRange(self, minM=91 - 15, maxM=91 + 15): self.minMZ = minM self.maxMZ = maxM def SetChanAndLevel(self, chan='', level=''): ''' Manages to set chan and leve to the class and the TopHistoReader ''' if chan != '': self.SetChannel(chan) if level != '': self.SetLevel(level) self.t.SetChan(self.GetChan()) self.t.SetLevel(self.GetLevel()) return self.GetChan(), self.GetLevel() ### Get methods def GetPath(self): return self.path def GetOutPath(self): return self.outpath def GetZhistoName(self): return self.zhname def GetDYfiles(self): return self.DYfiles def GetDataFiles(self): return self.datafiles def GetLevel(self): return self.level def GetChan(self): return self.chan ### Calculate quantities... def GetDYhisto(self, chan='', level='', isData=True): # ARREGLAR PARA QUE COJA EL ADECUADO DEPENDIENDO DEL CANAL!! O HACER FUNCION PARA INDICAR CANAL EMU chan, level = self.SetChanAndLevel(chan, level) if isData: self.t.SetIsData(True) pr = self.GetDataFiles() else: self.t.SetIsData(False) pr = self.GetDYfiles() zname = self.GetZhistoName() if level == 'dilepton' and zname[-4:] == 'ElMu': zname = zname[:-4] h = self.t.GetHisto(pr, zname, chan, level) h.SetDirectory(0) return h def GetHdata(self, chan, level): return self.GetDYhisto(chan, level, True) def GetHMC(self, chan, level): return self.GetDYhisto(chan, level, False) def DYyield(self, direc='in', isData=True, chan='', level=''): h = self.GetDYhisto(chan, level, isData) b0 = h.FindBin(self.minMZ) bN = h.FindBin(self.maxMZ) nbins = h.GetNbinsX() integral = h.Integral() y = 0 err = 0 if direc == 'in' or direc == 'In' or direc == 'IN': y += h.Integral(b0, bN) else: y += h.Integral(0, b0 - 1) y += h.Integral(bN + 1, nbins + 1) if isData: err = sqrt(y) else: entries = h.GetEntries() err = sqrt((y * integral) / entries) if y < 0: # Avoid wierd numbers due to negative weights... y = 0 err = 0 return y, err def GetDataIn(self, chan='', level=''): return self.DYyield('in', True, chan, level) def GetDataOut(self, chan='', level=''): return self.DYyield('out', True, chan, level) def GetMCin(self, chan='', level=''): return self.DYyield('in', False, chan, level) def GetMCout(self, chan='', level=''): return self.DYyield('out', False, chan, level) def GetRoutin(self, chan='', level=''): ''' Returns ratio Rout/in from MC ''' rin, errin = self.GetMCin(chan, level) out, errout = self.GetMCout(chan, level) r = out / rin if rin != 0 else 0 err = r * SumSquare( [errout / out if out != 0 else 0, errin / rin if rin != 0 else 0]) return r, err def GetKfactor(self, chan='', level=''): ''' Calculate the k factor k_ee, k_mumu ''' chan, level = self.SetChanAndLevel(chan, level) rinElec, errElec = self.GetDataIn(elname, level) rinMuon, errMuon = self.GetDataIn(muname, level) k = (rinElec / rinMuon if rinMuon != 0 else 0) if chan == elname else ( rinMuon / rinElec if rinElec != 0 else 0) k = sqrt(k) kerr = k * SumSquare([ errElec / (2 * rinElec) if rinElec != 0 else 0, errMuon / (2 * rinMuon) if rinMuon != 0 else 0 ]) return k, kerr def GetDYDD(self, chan='', level='', mode=''): ''' Returns the DY estimate from data ''' chan, level = self.SetChanAndLevel(chan, level) if chan == 'ElMu': self.SetMode('ElMu') if mode != '': self.SetMode(mode) routin, routin_err = self.GetRoutin(chan, level) NemuIn, NemuIn_err = self.GetDataIn('ElMu', level) kee, keerr = self.GetKfactor(elname, level) NeeIn, NeeInerr = self.GetDataIn(elname, level) kmm, kmmrr = self.GetKfactor(muname, level) NmmIn, NmmInerr = self.GetDataIn(muname, level) est = lambda r, Nin, Nemu, k: r * (Nin - Nemu * k / 2) esterr = lambda r, Nin, Nemu, k, er, eNin, eNemu, ek: SumSquare([ est(r, Nin, Nemu, k) * (er / r if r != 0 else 0), r * eNin, r * k / 2 * eNemu, r * Nemu / 2 * ek ]) N = 0 Nerr = 0 if chan == elname: N = est(routin, NeeIn, NemuIn, kee) Nerr = esterr(routin, NeeIn, NemuIn, kee, routin_err, NeeInerr, NemuIn_err, keerr) elif chan == muname: N = est(routin, NmmIn, NemuIn, kmm) Nerr = esterr(routin, NmmIn, NemuIn, kmm, routin_err, NmmInerr, NemuIn_err, kmmrr) else: # ElMu self.t.SetIsData(False) yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu') yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu') SF, err = self.GetScaleFactor('ElMu') N = yDY * SF Nerr = N * SumSquare([ err / SF if SF != 0 else err, yDYe / yDY if yDY != 0 else yDYe ]) if N < 0: N = 0 Nerr = 0 if not Nerr == Nerr: Nerr = 0 return N, Nerr def GetScaleFactor(self, chan='', level='', mode=''): ''' Returns the data/MC ratio for the DY estimate ''' chan, level = self.SetChanAndLevel(chan, level) if chan == 'ElMu': self.SetMode('ElMu') if mode != '': self.SetMode(mode) SF = 1 err = 0 if chan == muname or chan == elname: dd, dde = self.GetDYDD(chan) mo, moe = self.GetMCout(chan) SF = dd / mo if mo != 0 else 0 err = SF * SumSquare( [dde / dd if dd != 0 else 0, moe / mo if mo != 0 else 0]) elif chan == 'ElMu': e, er = self.GetScaleFactor(elname) m, mr = self.GetScaleFactor(muname) SF = sqrt(e * m) err = SF * SumSquare( [er / e if e != 0 else 0, mr / m if m != 0 else 0]) return SF, err def DrawHisto(self, doSF=False, name='', chan='', level='', rebin=1, log=True): self.SetChanAndLevel('', level) self.SetMode('SF' if doSF else 'OF') if name == '': name = 'DYDD_%s_%s' % ('SF' if doSF else 'OF', self.GetLevel()) hData = self.GetDYhisto(chan, level, True) hMC = self.GetDYhisto(chan, level, False) hemu = self.GetDYhisto('ElMu', level, True) hData.SetMarkerStyle(20) hData.SetMarkerColor(1) hData.SetLineColor(1) hData.SetMarkerSize(1.3) hMC.SetFillStyle(1000) hMC.SetLineColor(kAzure - 8) hMC.SetFillColor(kAzure - 8) hemu.SetFillStyle(1000) hemu.SetLineColor(kGray) hemu.SetFillColor(kGray) hData.Rebin(rebin) hemu.Rebin(rebin) hMC.Rebin(rebin) ke, kee = self.GetKfactor(elname) km, kme = self.GetKfactor(muname) hemu.Scale(0.5 * (ke if chan == 'ElE' else km)) hs = THStack() hs.Add(hemu) hs.Add(hMC) lab = 'e^{#pm}e^{#mp}' if chan == 'ElEl' else '#mu^{#pm}#mu^{#mp}' rlab = 'ee' if chan == 'ElEl' else '#mu#mu' processes = [ 'Z/#gamma*#rightarrow %s' % (lab), '0.5 k_{%s} #times Data(e#mu)' % rlab ] colors = {processes[0]: kAzure - 9, processes[1]: kGray} s = Stack(doRatio=False) s.SetXtitle(size=0.06, offset=0.8, nDiv=510, labSize=0.05) s.SetTextCMS(cmstex='CMS', x=0.13, y=0.88, s=0.06) s.SetTextCMSmode(texcmsMode='Preliminary', x=0.225, y=0.875, s=0.052) s.SetLumi(304.32) s.SetTextLumi(texlumi='%2.1f pb^{-1} (5.02 TeV)', texlumiX=0.68, texlumiY=0.95, texlumiS=0.045) s.SetDataHisto(hData) s.SetColors(colors) s.SetStack(hs) s.SetOutName('DYestimate_%s%s' % (chan, level) + ('_log' if log else '')) s.SetOutPath(self.outpath) plotMinimum = 0.5 if log else 0 plotMaxScale = 10 if log else 1.3 s.SetLogY(log) s.SetPlotMaxScale(plotMaxScale) s.SetPlotMinimum(plotMinimum) maximum = hData.GetMaximum() * (5 if log else 1.2) s.AddLine(76, 0.5, 76, maximum) s.AddLine(106, 0.5, 106, maximum) s.processes = processes s.SetLegendPos(x0=0.60, y0=0.55, x1=0.93, y1=0.91, size=0.042, ncol=1) s.DrawStack('m_{%s} (GeV)' % rlab) def DrawClosureMCeff(self, level='dilepton', outpath='~/www/temp/', ratio=[0.9, 1.1]): self.SetMode('OF') self.SetChanAndLevel('', level) ke, kee = self.GetKfactor(elname) km, kme = self.GetKfactor(muname) print 'ke = %1.2f +/- %1.2f' % (ke, kee) print 'km = %1.2f +/- %1.2f' % (km, kme) hdata = TH1F('d1', 'd1', 2, 0, 2) hpred = TH1F('h1', 'h1', 2, 0, 2) err = lambda l: sqrt(sum([x * x for x in l])) ''' hee1 = self.GetDYhisto(elname, level, False) hmm1 = self.GetDYhisto(muname, level, False) ee1 = hee1.Integral(); mm1 = hmm1.Integral() hdata.SetBinContent(1, ee1); hdata.SetBinError(1, sqrt(ee1)); hdata.SetBinContent(2, mm1); hdata.SetBinError(2, sqrt(mm1)); hpred.SetBinContent(1, mm1*ke1); hpred.SetBinError(1, mm1*ke1*( err([sqrt(mm1)/mm1, kee1/ke1]) )) hpred.SetBinContent(2, ee1*km1); hpred.SetBinError(2, ee1*km1*( err([sqrt(ee1)/ee1, kme1/km1]) )) ''' sampName = 'TT' hname = 'Lep0Eta' h_emu = self.t.GetNamedHisto('%s_%s_%s' % (hname, 'ElMu', level), sampName) h_ee = self.t.GetNamedHisto( '%s_%s_%s' % (hname, 'ElEl', '2jetsnomet' if level == '2jets' else level), sampName) h_mu = self.t.GetNamedHisto( '%s_%s_%s' % (hname, 'MuMu', '2jetsnomet' if level == '2jets' else level), sampName) y_emu = h_emu.Integral() * 304.32 y_mu = h_mu.Integral() * 304.32 y_ee = h_ee.Integral() * 304.32 d_ee = 0.5 * y_emu * ke d_ee_err = d_ee * (kee / ke) d_mu = 0.5 * y_emu * km d_mu_err = d_mu * (kme / km) hdata.SetBinContent(1, y_ee) hdata.SetBinError(1, y_ee / sqrt(h_ee.GetEntries())) hdata.SetBinContent(2, y_mu) hdata.SetBinError(2, y_mu / sqrt(h_mu.GetEntries())) hpred.SetBinContent(1, d_ee) hpred.SetBinError(1, d_ee_err) hpred.SetBinContent(2, d_mu) hpred.SetBinError(2, d_mu_err) p = HistoComp(outpath, doRatio=True, doNorm=False) hdata.SetLineWidth(1) hdata.SetMarkerSize(1.2) hdata.SetMarkerColor(1) hdata.SetMarkerStyle(20) hdata.SetFillColor(0) hdata.SetFillStyle(0) hpred.SetFillStyle(3144) hpred.SetFillColor(kAzure - 8) p.SetPlotMaxScale(1.5) p.SetLumi(304.32) p.AddHisto(hpred, 'l', 'e2', '0.5 x k_{ll} x t#bar{t} e#mu MC', kAzure + 2, 2) p.AddHisto(hdata, 'pe', '', 'Same-flavor t#bar{t} MC', 1) p.SetBinLabels(['ee', '#mu#mu']) p.SetYratioTitle('Ratio') p.SetYtitle('t#bar{t} events') rmin, rmax = ratio p.SetLegendPos(0.15, 0.6, 0.5, 0.8, ncol=1) p.SetRatioMin(rmin) p.SetRatioMax(rmax) p.SetOutName('DYDDeffClosure_' + level) p.autoRatio = True p.PlotWithData = True p.Draw(0) def PrintDYestimate(self, doSF=False, name='', level=''): hee = self.GetDYhisto(elname, level, False) hmm = self.GetDYhisto(muname, level, False) self.SetChanAndLevel('', level) self.SetMode('SF' if doSF else 'OF') if name == '': name = 'DYDD_%s_%s' % ('SF' if doSF else 'OF', self.GetLevel()) t = OutText(self.GetOutPath(), name, textformat='tex') t.SetTexAlign("l c c c") t.SetSeparatorLength(20 + (3 + 22) * 3) t.SetDefaultFixOption(False) t.line('%' + 'Drell-Yan estimate for %s and level \'%s\'' % ('SF channels' if doSF else 'all channels (no MET cut) ', self.GetLevel())) t.bar() s = lambda tit, vee, vmm, vem: t.line( t.fix(tit, 20) + t.vsep() + t.fix(vee, 22, 'c') + t.vsep() + t.fix( vmm, 22, 'c') + t.vsep() + t.fix(vem, 22, 'c')) v = lambda val, err: '%1.2f' % val + t.pm() + '%1.2f' % err d = lambda val, err: '%1.0f' % val + t.pm() + '%1.2f' % err s('', 'ee', '$\mu\mu$', 'e$\mu$') t.sep() mie, miee = self.GetMCin(elname) moe, moee = self.GetMCout(elname) mim, mime = self.GetMCin(muname) mom, mome = self.GetMCout(muname) s(' $N_{in}$ (MC)', v(mie, miee), v(mim, mime), '') s(' $N_{out}$ (MC)', v(moe, moee), v(mom, mome), '') re, ree = self.GetRoutin(elname) rm, rme = self.GetRoutin(muname) s(' $R_{out/in}$ (MC)', v(re, ree), v(rm, rme), '') ke, kee = self.GetKfactor(elname) km, kme = self.GetKfactor(muname) s(' $k_{ll}$ ', v(ke, kee), v(km, kme), '') ie, ier = self.GetDataIn(elname) im, imr = self.GetDataIn(muname) iem, iemr = self.GetDataIn('ElMu') s(' $N_{in}$ (Data)', d(ie, ier), d(im, imr), d(iem, iemr)) t.sep() dde, ddee = self.GetDYDD(elname) ddm, ddme = self.GetDYDD(muname) tmc = ' DY estimate out (MC) ' if doSF else ' DY estimate (MC)' tdata = ' DY estimate out (DD) ' if doSF else ' DY estimate (DD)' if doSF: s(' DY estimate (MC)', v(moe, moee), v(mom, mome), '') s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), '') else: ddem, ddeme = self.GetDYDD('ElMu') yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu') yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu') s(' DY estimate (MC)', v(moe, moee), v(mom, mome), v(yDY, yDYe)) s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), v(ddem, ddeme)) t.sep() sfee, sfeee = self.GetScaleFactor(elname) sfmm, sfmme = self.GetScaleFactor(muname) if doSF: s(' DD/MC ratio ', v(sfee, sfeee), v(sfmm, sfmme), '') else: sfem, sfeme = self.GetScaleFactor('ElMu') s(' DD/MC ratio ', v(sfee, sfeee), v(sfmm, sfmme), v(sfem, sfeme)) t.bar() t.write() def PrintDYSFnjets(self): t = OutText(self.GetOutPath(), 'DYSF_njets') t.SetSeparatorLength(22 + (3 + 16) * 3) t.SetDefaultFixOption(False) t.line( 'Drell-Yan data/MC scale factors for different jet multiplicities') t.bar() s = lambda tit, vee, vmm, vem: t.line( t.fix(tit, 22) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix( vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c')) v = lambda val, err: '%1.2f' % val + t.pm() + '%1.2f' % err s('', elname, muname, 'ElMu') t.sep() #labels = ['Inclusive','== 1 jet', '== 2 jets', '>= 3 jets','>= 2 jets, >= 1 btag', '>= 2 btag'] #levels = ['dilepton', 'eq1jet', 'eq2jet', 'geq3jet','1btag', '2btag'] labels = ['Inclusive', '>= 2 jets', ' >= 1 btag'] levels = ['dilepton', '2jets', '1btag'] for i in range(len(labels)): if i == 4: t.sep() lab = labels[i] lev = levels[i] sfe, sfee = self.GetScaleFactor(elname, lev, 'SF') sfm, sfme = self.GetScaleFactor(muname, lev, 'SF') sfo, sfoe = self.GetScaleFactor('ElMu', lev, 'OF') s(' ' + lab, v(sfe, sfee) if sfe > 0 else '-', v(sfm, sfme) if sfm > 0 else '-', v(sfo, sfoe) if sfo > 0 else '-') t.bar() t.write() def __init__(self, path, outpath='./temp/', chan='ElMu', level='2jets', DYsamples='DYJetsToLL_M_10to50,DYJetsToLL_MLL50', DataSamples='HighEGJet,SingleMuon, DoubleMuon', lumi=304.32, massRange=[91 - 15, 91 + 15], mode='', histonameprefix='H', hname='DY_InvMass'): self.SetPath(path) self.SetOutPath(outpath) self.t = TopHistoReader(path) self.t.SetHistoNamePrefix(histonameprefix) self.SetLumi(lumi) self.SetChanAndLevel(chan, level) self.SetDYsamples(DYsamples) self.SetDataSamples(DataSamples) self.SetMassRange(massRange[0], massRange[1]) self.SetHistoNameOF() self.SetHistoNameSF() if chan == 'ElMu': if hname != '': self.SetHistoNameOF(hname) self.SetMode('OF') else: if hname != '': self.SetHistoNameSF(hname) self.SetMode('SF') if mode != '': self.SetMode(mode)
class DYDD: ### Set methods def SetPath(self, p): if not p.endswith('/'): p += '/' self.path = p def SetOutPath(self, p): self.outpath = p def SetMode(self, mode='OF', hname=''): self.doOF = True if mode in ['SF', 'Elec', 'ElEl', 'Muon', 'MuMu']: self.doOF = False if self.doOF: if hname != '': self.SetHistoNameOF(hname) self.SetZhistoName(self.hnameOF) else: if hname != '': self.SetHistoNameSF(hname) self.SetZhistoName(self.hnameSF) def SetLumi(self, l): self.lumi = l self.t.SetLumi(self.lumi) def SetHistoNameOF(self, h='DY_InvMass'): self.hnameOF = h def SetHistoNameSF(self, h='DY_SF_InvMass'): self.hnameSF = h def SetDYsamples(self, f): self.DYfiles = f def SetDataSamples(self, f): self.datafiles = f def SetChannel(self, c): self.chan = c def SetLevel(self, l): self.level = l def SetZhistoName(self, h): self.zhname = h def SetMassRange(self, minM=91 - 15, maxM=91 + 15): self.minMZ = minM self.maxMZ = maxM def SetChanAndLevel(self, chan='', level=''): ''' Manages to set chan and leve to the class and the TopHistoReader ''' if chan != '': self.SetChannel(chan) if level != '': self.SetLevel(level) self.t.SetChan(self.GetChan()) self.t.SetLevel(self.GetLevel()) return self.GetChan(), self.GetLevel() ### Get methods def GetPath(self): return self.path def GetOutPath(self): return self.outpath def GetZhistoName(self): return self.zhname def GetDYfiles(self): return self.DYfiles def GetDataFiles(self): return self.datafiles def GetLevel(self): return self.level def GetChan(self): return self.chan ### Calculate quantities... def GetDYhisto(self, chan='', level='', isData=True): # ARREGLAR PARA QUE COJA EL ADECUADO DEPENDIENDO DEL CANAL!! O HACER FUNCION PARA INDICAR CANAL EMU chan, level = self.SetChanAndLevel(chan, level) if isData: self.t.SetIsData(True) pr = self.GetDataFiles() else: self.t.SetIsData(False) pr = self.GetDYfiles() zname = self.GetZhistoName() if level == 'dilepton' and zname[-4:] == 'ElMu': zname = zname[:-4] h = self.t.GetHisto(pr, zname, chan, level) h.SetDirectory(0) return h def GetHdata(self, chan, level): return self.GetDYhisto(chan, level, True) def GetHMC(self, chan, level): return self.GetDYhisto(chan, level, False) def DYyield(self, direc='in', isData=True, chan='', level=''): h = self.GetDYhisto(chan, level, isData) b0 = h.FindBin(self.minMZ) bN = h.FindBin(self.maxMZ) nbins = h.GetNbinsX() integral = h.Integral() y = 0 err = 0 if direc == 'in' or direc == 'In' or direc == 'IN': y += h.Integral(b0, bN) else: y += h.Integral(0, b0 - 1) y += h.Integral(bN + 1, nbins + 1) if isData: err = sqrt(y) else: entries = h.GetEntries() err = sqrt((y * integral) / entries) if y < 0: # Avoid wierd numbers due to negative weights... y = 0 err = 0 return y, err def GetDataIn(self, chan='', level=''): return self.DYyield('in', True, chan, level) def GetDataOut(self, chan='', level=''): return self.DYyield('out', True, chan, level) def GetMCin(self, chan='', level=''): return self.DYyield('in', False, chan, level) def GetMCout(self, chan='', level=''): return self.DYyield('out', False, chan, level) def GetRoutin(self, chan='', level=''): ''' Returns ratio Rout/in from MC ''' rin, errin = self.GetMCin(chan, level) out, errout = self.GetMCout(chan, level) r = out / rin if rin != 0 else 0 err = r * SumSquare( [errout / out if out != 0 else 0, errin / rin if rin != 0 else 0]) return r, err def GetKfactor(self, chan='', level=''): ''' Calculate the k factor k_ee, k_mumu ''' chan, level = self.SetChanAndLevel(chan, level) rinElec, errElec = self.GetDataIn(elname, level) rinMuon, errMuon = self.GetDataIn(muname, level) k = (rinElec / rinMuon if rinMuon != 0 else 0) if chan == elname else ( rinMuon / rinElec if rinElec != 0 else 0) kerr = k * SumSquare([ errElec / (2 * rinElec) if rinElec != 0 else 0, errMuon / (2 * rinMuon) if rinMuon != 0 else 0 ]) return k, kerr def GetDYDD(self, chan='', level='', mode=''): ''' Returns the DY estimate from data ''' chan, level = self.SetChanAndLevel(chan, level) if chan == 'ElMu': self.SetMode('ElMu') if mode != '': self.SetMode(mode) routin, routin_err = self.GetRoutin(chan, level) NemuIn, NemuIn_err = self.GetDataIn('ElMu', level) kee, keerr = self.GetKfactor(elname, level) NeeIn, NeeInerr = self.GetDataIn(elname, level) kmm, kmmrr = self.GetKfactor(muname, level) NmmIn, NmmInerr = self.GetDataIn(muname, level) est = lambda r, Nin, Nemu, k: r * (Nin - Nemu * k / 2) esterr = lambda r, Nin, Nemu, k, er, eNin, eNemu, ek: SumSquare([ est(r, Nin, Nemu, k) * (er / r if r != 0 else 0), r * eNin, r * k / 2 * eNemu, r * Nemu / 2 * ek ]) N = 0 Nerr = 0 if chan == elname: N = est(routin, NeeIn, NemuIn, kee) Nerr = esterr(routin, NeeIn, NemuIn, kee, routin_err, NeeInerr, NemuIn_err, keerr) elif chan == muname: N = est(routin, NmmIn, NemuIn, kmm) Nerr = esterr(routin, NmmIn, NemuIn, kmm, routin_err, NmmInerr, NemuIn_err, kmmrr) else: # ElMu self.t.SetIsData(False) yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu') yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu') SF, err = self.GetScaleFactor('ElMu') N = yDY * SF Nerr = N * SumSquare([ err / SF if SF != 0 else err, yDYe / yDY if yDY != 0 else yDYe ]) if N < 0: N = 0 Nerr = 0 if not Nerr == Nerr: Nerr = 0 return N, Nerr def GetScaleFactor(self, chan='', level='', mode=''): ''' Returns the data/MC ratio for the DY estimate ''' chan, level = self.SetChanAndLevel(chan, level) if chan == 'ElMu': self.SetMode('ElMu') if mode != '': self.SetMode(mode) SF = 1 err = 0 if chan == muname or chan == elname: dd, dde = self.GetDYDD(chan) mo, moe = self.GetMCout(chan) SF = dd / mo if mo != 0 else 0 err = SF * SumSquare( [dde / dd if dd != 0 else 0, moe / mo if mo != 0 else 0]) elif chan == 'ElMu': e, er = self.GetScaleFactor(elname) m, mr = self.GetScaleFactor(muname) SF = sqrt(e * m) err = SF * SumSquare( [er / e if e != 0 else 0, mr / m if m != 0 else 0]) return SF, err def PrintDYestimate(self, doSF=False, name='', level=''): self.SetChanAndLevel('', level) self.SetMode('SF' if doSF else 'OF') if name == '': name = 'DYDD_%s_%s' % ('SF' if doSF else 'OF', self.GetLevel()) t = OutText(self.GetOutPath(), name) t.SetSeparatorLength(20 + (3 + 22) * 3) t.SetDefaultFixOption(False) t.line('Drell-Yan estimate for %s and level \'%s\'' % ('SF channels' if doSF else 'all channels (no MET cut) ', self.GetLevel())) t.bar() s = lambda tit, vee, vmm, vem: t.line( t.fix(tit, 20) + t.vsep() + t.fix(vee, 22, 'c') + t.vsep() + t.fix( vmm, 22, 'c') + t.vsep() + t.fix(vem, 22, 'c')) v = lambda val, err: '%1.3f' % val + t.pm() + '%1.3f' % err d = lambda val, err: '%1.0f' % val + t.pm() + '%1.2f' % err s('', elname, muname, 'ElMu') t.sep() mie, miee = self.GetMCin(elname) moe, moee = self.GetMCout(elname) mim, mime = self.GetMCin(muname) mom, mome = self.GetMCout(muname) s(' N_in (MC)', v(mie, miee), v(mim, mime), '') s(' N_out (MC)', v(moe, moee), v(mom, mome), '') re, ree = self.GetRoutin(elname) rm, rme = self.GetRoutin(muname) s(' R_(out/in) (MC)', v(re, ree), v(rm, rme), '') ke, kee = self.GetKfactor(elname) km, kme = self.GetKfactor(muname) s(' k_ll ', v(ke, kee), v(km, kme), '') ie, ier = self.GetDataIn(elname) im, imr = self.GetDataIn(muname) iem, iemr = self.GetDataIn('ElMu') s(' N_in (Data)', d(ie, ier), d(im, imr), d(iem, iemr)) t.sep() dde, ddee = self.GetDYDD(elname) ddm, ddme = self.GetDYDD(muname) tmc = ' DY estimate out (MC) ' if doSF else ' DY estimate (MC)' tdata = ' DY estimate out (DD) ' if doSF else ' DY estimate (DD)' if doSF: s(' DY estimate (MC)', v(moe, moee), v(mom, mome), '') s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), '') else: ddem, ddeme = self.GetDYDD('ElMu') yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu') yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu') s(' DY estimate (MC)', v(moe, moee), v(mom, mome), v(yDY, yDYe)) s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), v(ddem, ddeme)) t.sep() sfee, sfeee = self.GetScaleFactor(elname) sfmm, sfmme = self.GetScaleFactor(muname) if doSF: s(' DD/MC ratio ', v(sfee, sfeee), v(sfmm, sfmme), '') else: sfem, sfeme = self.GetScaleFactor('ElMu') s(' DD/MC ratio ', v(sfee, sfeee), v(sfmm, sfmme), v(sfem, sfeme)) t.bar() t.write() def PrintDYSFnjets(self): t = OutText(self.GetOutPath(), 'DYSF_njets') t.SetSeparatorLength(22 + (3 + 16) * 3) t.SetDefaultFixOption(False) t.line( 'Drell-Yan data/MC scale factors for different jet multiplicities') t.bar() s = lambda tit, vee, vmm, vem: t.line( t.fix(tit, 22) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix( vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c')) v = lambda val, err: '%1.2f' % val + t.pm() + '%1.2f' % err s('', elname, muname, 'ElMu') t.sep() #labels = ['Inclusive','== 1 jet', '== 2 jets', '>= 3 jets','>= 2 jets, >= 1 btag', '>= 2 btag'] #levels = ['dilepton', 'eq1jet', 'eq2jet', 'geq3jet','1btag', '2btag'] labels = ['Inclusive', '>= 2 jets', ' >= 1 btag'] levels = ['dilepton', '2jets', '1btag'] for i in range(len(labels)): if i == 4: t.sep() lab = labels[i] lev = levels[i] sfe, sfee = self.GetScaleFactor(elname, lev, 'SF') sfm, sfme = self.GetScaleFactor(muname, lev, 'SF') sfo, sfoe = self.GetScaleFactor('ElMu', lev, 'OF') s(' ' + lab, v(sfe, sfee) if sfe > 0 else '-', v(sfm, sfme) if sfm > 0 else '-', v(sfo, sfoe) if sfo > 0 else '-') t.bar() t.write() def __init__(self, path, outpath='./temp/', chan='ElMu', level='2jets', DYsamples='DYJetsToLL_M_10to50,DYJetsToLL_MLL50', DataSamples='HighEGJet,SingleMuon, DoubleMuon', lumi=308.54, massRange=[91 - 15, 91 + 15], mode='', histonameprefix='H', hname='DY_InvMass'): self.SetPath(path) self.SetOutPath(outpath) self.t = TopHistoReader(path) self.t.SetHistoNamePrefix(histonameprefix) self.SetLumi(lumi) self.SetChanAndLevel(chan, level) self.SetDYsamples(DYsamples) self.SetDataSamples(DataSamples) self.SetMassRange(massRange[0], massRange[1]) self.SetHistoNameOF() self.SetHistoNameSF() if chan == 'ElMu': if hname != '': self.SetHistoNameOF(hname) self.SetMode('OF') else: if hname != '': self.SetHistoNameSF(hname) self.SetMode('SF') if mode != '': self.SetMode(mode)
class CrossSection: ### Add background, signal and data numbers def AddBkg(self, name, val, normunc=0, systunc=0, statunc=0, samples=''): ''' Add a bkg process (must include yield, name, uncertainties...) ''' self.bkg.append( Process(name, Yield=val, NormUnc=normunc, SystUnc=systunc, StatUnc=statunc, samples=samples)) def SetSignal(self, name, val, statunc=0, samples=''): ''' Set the signal process (must include yield, name, uncertainties...) ''' self.signal = Process(name, Yield=val, StatUnc=statunc, samples=samples) def SetData(self, n): ''' Number of observed events ''' self.data = n self.dataunc = sqrt(n) ### Add uncertainties... experimental and modeling def AddExpUnc(self, name, val): ''' Add the uncertainty 'name' with value 'val' to the experimental uncertainties ''' self.effUnc[name] = val def AddModUnc(self, name, val=0., do=''): ''' Add the uncertainty 'name' with value 'val' to the modeling uncertainties (on acceptance) if sample names are given (up/down) the uncertainty is read from the histos in that samples ''' if isinstance(val, float): self.accUnc[name] = val else: nom = self.GetSignalYield() up = self.t.GetYield(val) do = self.t.GetYield(do) var = max(abs(up - nom), abs(do - nom)) / nom self.AddModUnc(name, var) ### Setting methods def SetTextFormat(self, textformat): ''' Set the format of the output tables (txt, tex) ''' self.textformat = textformat def SetChan(self, ch): ''' Set the channel ''' self.chan = ch def SetLevel(self, lev): ''' Set level ''' self.lev = lev def SetThXsec(self, t): ''' Set the theoretical cross section using to normalize signal events ''' self.thxsec = t def SetDoFiducial(self, val=True): ''' Boolean to activate printing the fiducial cross section ''' self.doFiducial = val def SetLumi(self, l): ''' Set the luminosity ''' self.lumi = l def SetLumiUnc(self, l): ''' Set relative lumi unc ''' self.lumiunc = l def SetFiduEvents(self, f): ''' Number of fiducual (unweighted) events ''' self.nfidu = f def SetGenEvents(self, g): ''' Number of generated events in the sample ''' self.ngen = g def SetBR(self, b): # Use relative unc ''' The branching ratio to what we consider signal ''' self.BR = b def SetOutPath(self, p): ''' Set the output path ''' self.outpath = p ### Get parameters... def GetThXsec(self): return self.thxsec def GetLumi(self): return self.lumi def GetLumiUnc(self): return self.lumiunc def GetFiduEvents(self, sys=''): return self.nfidu def GetGenEvents(self): return self.ngen def GetBR(self): return self.BR def GetLevel(self): return self.lev def GetChan(self): return self.chan def GetBkg(self, name): for b in self.bkg: if b.GetName() == name: return b print 'WARNING: not found background ' + name def GetBkgTotRelUnc(self, name): return self.GetBkg(name).GetTotRelUnc() def GetBkgTotAbsUnc(self, name): return self.GetBkgYield(name) * self.GetBkgTotRelUnc(name) def GetBkgYield(self, name, sys=''): pr = self.GetBkg(name) if sys == '': return pr.GetYield() elif IsUpSyst(sys): return pr.GetYield() * (1 + pr.GetTotRelUnc()) elif IsDownSyst(sys): return pr.GetYield() * (1 - pr.GetTotRelUnc()) else: return pr.GetYield() * (1 + pr.GetTotRelUnc()) def GetData(self): return self.data def GetDataUnc(self): return self.dataunc def GetSignal(self): return self.signal def GetSignalYield(self, sys='', d=''): y = self.signal.GetYield() if sys == '': return y u = self.GetUnc(sys) if IsDownSyst(d): return y * (1 - u) return y * (1 + u) def GetExpUnc(self, name=''): if name == '': return self.effUnc else: return self.effUnc[name] def GetModUnc(self, name=''): if name == '': return self.accUnc else: return self.accUnc[name] def GetUnc(self, name): if name in self.modUnc.keys(): return self.GetModUnc(name) elif name in self.effUnc.keys(): return self.GetEffUnc(name) else: print 'WARNING: not found uncertainty \'%d\'' % name return 0 def GetTotBkg(self, sys='', d=''): ''' Returns the total expected bkg ''' if sys != '' and sys in [x.GetName() for x in self.bkg]: y = self.GetTotBkg() var = self.GetBkgTotAbsUnc(sys) y = y - var if IsDownSyst(sys + d) else y + var else: y = sum([x.GetYield() for x in self.bkg]) return y def GetTotBkgStatUnc(self): ''' Returns the total stat unc on bkg ''' b = 0 for pr in self.bkg: b += pr.GetStatUnc() * pr.GetStatUnc() return sqrt(b) def GetTotBkgSystUnc(self): ''' Returns the total syst unc on bkg ''' b = 0 for pr in self.bkg: b += pr.GetSystAbsUnc() * pr.GetSystAbsUnc() return sqrt(b) def GetXsec(self, sys='', d=''): ''' Returns the measured cross section ''' data = self.GetData() bkg = self.GetTotBkg(sys, d) if sys in [x.GetName() for x in self.bkg ] else self.GetTotBkg() y = self.GetSignalYield(sys, d) thxsec = self.GetThXsec() return self.ComputeXsec(data, bkg, y) def GetFiduXsec(self): ''' Returns the fiducial cross section ''' # fidu = inclusive*(A) return self.ComputeXsec() * self.GetAcc() def GetAcc(self, sys=''): ''' Returns the measured acceptance ''' return self.GetFiduEvents(sys) / (self.GetGenEvents() * self.GetBR()) def GetAccUnc(self): ''' Return the syst unc on acceptance ''' err = 0 for a in self.accUnc.values(): err += a * a return sqrt(err) def GetEff(self, sys=''): ''' Returns the measured efficiency ''' y = self.GetSignalYield(sys) A = self.GetAcc() BR = self.GetBR() lum = self.GetLumi() xth = self.GetThXsec() return (y) / (A * lum * xth * BR) def GetEffUnc(self): ''' Return the syst unc on efficiency ''' err = 0 for a in self.effUnc.values(): err += a * a return sqrt(err) def GetXsecSystUnc(self): ''' Returns the xsec syst unc on cross section ''' effunc = self.GetEffUnc() accunc = self.GetAccUnc() bkgunc2 = 0 for b in [x.GetName() for x in self.bkg]: bkgunc2 += self.GetXsecBkgRelUnc(b) * self.GetXsecBkgRelUnc(b) return sqrt(effunc * effunc + accunc * accunc + bkgunc2) def GetXsecLumiUnc(self): ''' Returns the xsec lumi uncertainty on cross section ''' #return self.GetXsec()*(1/self.GetLumi() - 1/(self.GetLumi() * (1+self.GetLumiUnc()) )) r = self.GetLumiUnc() return (abs(r / (1 - r)) + abs(r / (1 + r))) / 2 def GetXsecStatUnc(self): ''' Returns the stat unc on cross section ''' xsec = self.ComputeXsec() varUp = self.ComputeXsec(self.GetData() + self.GetDataUnc(), self.GetTotBkg(), self.GetSignalYield()) varDo = self.ComputeXsec(self.GetData() - self.GetDataUnc(), self.GetTotBkg(), self.GetSignalYield()) return max([abs(xsec - varDo) / xsec, abs(xsec - varUp) / xsec]) def GetXsecBkgRelUnc(self, bkgname): ''' Returns the relative unc on the xsec due to the total unc on a bkg estimation ''' nom = self.ComputeXsec() varUp = self.ComputeXsec(self.GetData(), self.GetTotBkg(bkgname, 'Up'), self.GetSignalYield()) varDo = self.ComputeXsec(self.GetData(), self.GetTotBkg(bkgname, 'Down'), self.GetSignalYield()) return max([abs(nom - varUp) / nom, abs(nom - varDo) / nom]) ### Several printing methods! def PrintYields(self, name='yields', doStat=True, doSyst=True): t = OutText(self.outpath, name, "new", textformat=self.textformat) t.SetTexAlign("l c") nsem = 16 + 3 + 8 + (5 + 8 if doStat else 0) + (5 + 8 if doSyst else 0) t.SetSeparatorLength(nsem) t.line('%' + 'Yields for channel \'%s\' and level \'%s\'' % (self.GetChan(), self.GetLevel())) t.bar() for pr in self.bkg: name = t.fix(" %s" % pr.GetName(), 16, 'l', 0) y = t.fix("%1.2f" % pr.GetYield(), 8, 0) stat = t.fix("%1.2f" % pr.GetStatUnc(), 8, 0) syst = t.fix("%1.2f" % pr.GetSystAbsUnc(), 8, 0) t.line(name + t.vsep() + y + ((t.pm() + stat) if doStat else '') + ((t.pm() + syst) if doSyst else '')) t.sep() totbkg = t.fix("%1.2f" % self.GetTotBkg(), 8, 0) totbkgstat = t.fix("%1.2f" % self.GetTotBkgStatUnc(), 8, 0) totbkgsyst = t.fix("%1.2f" % self.GetTotBkgSystUnc(), 8, 0) t.line( t.fix(" Total bkg", 16, 'l', 0) + t.vsep() + totbkg + ((t.pm() + totbkgstat) if doStat else '') + ((t.pm() + totbkgsyst) if doSyst else '')) t.sep() y = self.GetSignalYield() signal = t.fix(" %s" % (self.GetSignal().GetName()), 16, 'l', 0) ysig = t.fix("%1.2f" % y, 8, 0) sigunc = t.fix("%1.2f" % (self.GetXsecSystUnc() * y), 8, 0) sigsta = t.fix("%1.2f" % self.GetSignal().GetStatUnc(), 8, 0) t.line(signal + t.vsep() + ysig + ((t.pm() + sigsta) if doStat else '') + ((t.pm() + sigunc) if doSyst else '')) t.sep() t.line( t.fix(" Data", 16, 'l', 0) + t.vsep() + t.fix("%i" % self.GetData(), 8, 0)) t.bar() t.write() def PrintXsec(self, name='xsec'): t = OutText(self.outpath, name, "new", textformat=self.textformat) t.SetTexAlign("l c") t.SetSeparatorLength(26 + 3 + 20 + 5) t.SetDefaultFixOption(False) t.line('%' + 'tt cross section for channel \'%s\' and level \'%s\'' % (self.GetChan(), self.GetLevel())) acc = self.GetAcc() eff = self.GetEff() t.bar() t.line( t.fix(' Acceptance', 16, 'r') + t.vsep() + t.fix("%1.4f" % acc, 6) + t.pm() + t.fix("%1.2f" % (acc * self.GetAccUnc()), 8)) t.line( t.fix(' Efficiency', 16, 'r') + t.vsep() + t.fix("%1.4f" % eff, 6) + t.pm() + t.fix("%1.2f" % (eff * self.GetEffUnc()), 8)) t.sep() t.line( t.fix(' Branching ratio', 16, 'r') + t.vsep() + t.fix("%1.4f" % self.GetBR(), 6)) t.line( t.fix(' Gen events', 16, 'r') + t.vsep() + t.fix("%d" % self.GetGenEvents(), 9)) t.line( t.fix(' Fiducial events', 16, 'r') + t.vsep() + t.fix("%d" % self.GetFiduEvents(), 9)) if self.doFiducial: t.sep() xsec = self.GetFiduXsec() stat = self.GetXsecStatUnc() syst = self.GetEffUnc() lumi = self.GetXsecLumiUnc() #t.line(t.fix(' Fiducial cross section', 26, 'r') + t.vsep() + t.fix("%1.2f"%xsec,6)) #t.line(t.fix(' +\- ', 26, 'r') + ' ' + t.fix('%1.2f (%1.2f'%(stat*xsec,stat*100) + ' %) (stat)',20, 'l')) #t.line(t.fix(' +\- ', 26, 'r') + ' ' + t.fix('%1.2f (%1.2f'%(syst*xsec,syst*100) + ' %) (syst)',20, 'l')) #t.line(t.fix(' +\- ', 26, 'r') + ' ' + t.fix('%1.2f (%1.2f'%(lumi*xsec,lumi*100) + ' %) (lumi)',20, 'l')) t.sep() xsec = self.GetXsec() stat = self.GetXsecStatUnc() syst = self.GetXsecSystUnc() lumi = self.GetXsecLumiUnc() t.line( t.fix(' Inclusive cross section', 26, 'r') + t.vsep() + t.fix("%1.2f" % xsec, 6)) t.line( t.fix(' $\pm$ ', 26, 'r') + ' ' + t.fix('%1.2f (%1.2f' % (stat * xsec, stat * 100) + ' \%) (stat)', 20, 'l') + t.vsep()) t.line( t.fix(' $\pm$ ', 26, 'r') + ' ' + t.fix('%1.2f (%1.2f' % (syst * xsec, syst * 100) + ' \%) (syst)', 20, 'l') + t.vsep()) t.line( t.fix(' $\pm$ ', 26, 'r') + ' ' + t.fix('%1.2f (%1.2f' % (lumi * xsec, lumi * 100) + ' \%) (lumi)', 20, 'l') + t.vsep()) t.bar() t.write() def AddToTxt(self, name='xsec', lab='e#mu'): t = OutText(self.outpath, name, "new", textformat=self.textformat) text = t.GetTextFromOutFile(form='txt') xsec = self.GetXsec() stat = self.GetXsecStatUnc() * xsec syst = self.GetXsecSystUnc() * xsec lum = self.GetXsecLumiUnc() * xsec isthere = False for l in text.splitlines(): if l == '' or l.replace(' ', '') == '': continue if l.startswith(lab): isthere = True t.line('%s %1.2f %1.2f %1.2f %1.2f' % (lab, xsec, stat, syst, lum)) else: t.line(l) if not isthere: t.line('%s %1.2f %1.2f %1.2f %1.2f' % (lab, xsec, stat, syst, lum)) t.write() def PrintSystTable(self, name='uncertainties'): t = OutText(self.outpath, name, "new", textformat=self.textformat) t.SetTexAlign("l c") t.SetSeparatorLength(30) t.SetDefaultFixOption(False) t.line('%Uncertainties on tt inclusive cross section \n% ' + 'for channel \'%s\' and level \'%s\'' % (self.GetChan(), self.GetLevel())) exp = self.GetExpUnc() mod = self.GetModUnc() stat = self.GetXsecStatUnc() lum = self.GetXsecLumiUnc() syst = self.GetXsecSystUnc() xsec = self.GetXsec() t.bar() t.line(t.fix(' Source', 18, 'l') + t.vsep() + fix("value (\%)", 6)) t.sep() for b in [x.GetName() for x in self.bkg]: t.line( fix(' ' + b, 18, 'r') + t.vsep() + fix('%1.2f' % (self.GetXsecBkgRelUnc(b) * 100), 6)) t.sep() for e in exp.keys(): t.line( fix(' ' + e, 18, 'l') + t.vsep() + fix('%1.2f' % (exp[e] * 100), 6)) t.sep() for e in mod.keys(): t.line( fix(' ' + e, 18, 'l') + t.vsep() + fix('%1.2f' % (mod[e] * 100), 6)) t.sep() t.line( fix(' Total systematic', 18, 'l') + t.vsep() + fix('%1.2f' % (syst * 100), 6)) t.sep() t.line( fix(' Statistics', 18, 'l') + t.vsep() + fix('%1.2f' % (stat * 100), 6)) t.sep() t.line( fix(' Luminosity', 18, 'l') + t.vsep() + fix('%1.2f' % (lum * 100), 6)) t.bar() t.write() ### Other def ComputeXsec(self, data='', bkg='', y=''): ''' Computes the xsec from data, bkg and expected yield ''' if data == '': data = self.data if bkg == '': bkg = self.GetTotBkg() if y == '': y = self.GetSignalYield() return (data - bkg) / y * self.GetThXsec() def SetPathToTrees(self, ptt): self.pathToTrees = ptt def SetMotherName(self, mn): self.motherfname = mn def GetNGenEvents(self): self.treesow = TChain('Runs', 'Runs') files = GetFiles(self.pathToTrees, self.motherfname) for f in files: self.treesow.Add(f) def ReadHistos(self, path, chan='ElMu', level='2jets', lumi=Lumi, lumiunc=0.04, bkg=[], signal=[], data='', expUnc=[], modUnc=[], histoPrefix=''): ''' Set the xsec from histos ''' if isinstance(expUnc, str): expUnc = expUnc.replace(' ', '').split(',') if isinstance(modUnc, str): modUnc = modUnc.replace(' ', '').split(',') self.SetChan(chan) self.SetLevel(level) self.t = TopHistoReader(path) self.t.SetHistoNamePrefix(histoPrefix) self.t.SetLumi(lumi) self.t.SetChan(chan) self.t.SetLevel(level) self.ss = SampleSums(self.pathToTrees, self.motherfname, 'Runs') signalName = signal[0] signalSample = signal[1] # GetFiduEvents hfiduname = 'FiduEvents' #_%s'%chan fiduEvents = self.t.GetNamedHisto( hfiduname, signalSample).GetBinContent(invlevel[level]) nGenEvents = self.ss.GetCount( 'Count') #self.GetNGenEvents(signalSample) self.SetLumiUnc(lumiunc) self.SetFiduEvents(fiduEvents) self.SetGenEvents(nGenEvents) for l in bkg: if len(l) == 3: name, pr, unc = l expunc = expUnc elif len(l) == 4: name, pr, unc, expunc = l self.AddBkg(name, self.t.GetYield(pr), unc, self.t.GetUnc(pr, chan, level, expUnc), self.t.GetYieldStatUnc(pr)) self.SetSignal(signalName, self.t.GetYield(signalSample), self.t.GetYieldStatUnc(signalSample)) self.t.SetIsData(True) self.SetData(self.t.GetYield(data)) self.t.SetIsData(False) for e in expUnc: self.AddExpUnc(e, self.t.GetUnc(signal[1], chan, level, e)) # Modeling uncertainties if 'pdf' in modUnc or 'PDF' in modUnc or 'Scale' in modUnc or 'ME' in modUnc or 'scale' in modUnc: pathToTrees = self.pathToTrees #'/pool/ciencias/userstorage/juanr/nanoAODv4/5TeV/5TeV_5sept/' motherfname = self.motherfname #'TT_TuneCP5_PSweights_5p02TeV' w = WeightReader(path, '', chan, level, sampleName='TT', pathToTrees=pathToTrees, motherfname=motherfname, PDFname='PDFweights', ScaleName='ScaleWeights', lumi=Lumi, histoprefix=histoPrefix) #w.SetSampleName(signalName) if 'pdf' in modUnc or 'PDF' in modUnc: self.AddModUnc('PDF', w.GetPDFandAlphaSunc()) if 'scale' in modUnc or 'ME' in modUnc: self.AddModUnc('Scale ME', w.GetMaxRelUncScale()) if 'ISR' in modUnc or 'isr' in modUnc: self.AddModUnc('ISR', self.t.GetUnc(signalSample, chan, level, 'ISR')) if 'FSR' in modUnc or 'fsr' in modUnc: self.AddModUnc('FSR', self.t.GetUnc(signalSample, chan, level, 'FSR')) def __init__(self, outpath='./temp/', lev='', chan='', genEvents=1, fiduEvents=1, textformat="txt"): self.SetTextFormat(textformat) self.SetThXsec(68.9) self.SetLumi(Lumi) self.SetLumiUnc(0.035) # Relative self.SetChan(chan) self.SetLevel(lev) self.SetGenEvents(genEvents) self.SetFiduEvents(fiduEvents) self.SetBR((0.108 * 3) * (0.108 * 3)) # By default, tt dilepton self.bkg = [] # List of 'Process' self.data = 0 # This is just an integer self.signal = '' # Process self.accUnc = {} # 'Name' : value self.effUnc = {} # 'Name' : value self.SetOutPath(outpath) self.doFiducial = True self.SetMotherName("TT_TuneCP5_5p02TeV") self.SetPathToTrees("")
class NonpromptDD: ### Set methods def SetPath(self, p): if not p.endswith('/'): p += '/' self.path = p def SetOutPath(self, p): self.outpath = p def SetLumi(self, l): self.lumi = l self.t.SetLumi(self.lumi) def SetChannel(self, c): self.chan = c def SetLevel(self, l): self.level = l def SetChanAndLevel(self, chan='', level=''): ''' Manages to set chan and leve to the class and the TopHistoReader ''' if chan != '': self.SetChannel(chan) if level != '': self.SetLevel(level) self.t.SetChan(self.GetChan()) self.t.SetLevel(self.GetLevel()) return self.GetChan(), self.GetLevel() ### Get methods def GetPath(self): return self.path def GetOutPath(self): return self.outpath def GetLevel(self): return self.level def GetChan(self): return self.chan ### Calculate quantities... def GetYield(self, process, chan='', level='', SS=False): if process == 'Data' or process == 'data': self.t.SetIsData(True) if process in self.process.keys(): process = self.process[process] chan, lev = self.SetChanAndLevel(chan, level) y = self.t.GetYield(process, chan, level, SS=SS) err = self.t.GetYieldStatUnc(process, chan, level, SS=SS) self.t.SetIsData(False) if y < 0: # Negative weights... y = 0 err = 0 return y, err def GetSS(self, process, chan='', level=''): return self.GetYield(process, chan, level, True) def GetROSSS(self, process, chan='', level=''): ''' Returns the OS to SS ratio for process ''' OS, OSe = self.GetYield(process, chan, level) SS, SSe = self.GetSS(process, chan, level) R = OS / SS if SS != 0 else 1 e = R * SumSquare( [OSe / OS if OS != 0 else 0, SSe / SS if SS != 0 else 0]) return R, e def GetNonpromptDD(self, chan='', level=''): chan, lev = self.SetChanAndLevel(chan, level) R, Re = self.GetROSSS( [self.process[lab] for lab in self.nonpromptProcess]) BkgSS, BkgSSe = self.GetSS( [self.process[lab] for lab in self.promptProcess]) DataSS, DataSSe = self.GetSS('data') y = R * (DataSS - BkgSS) e = y * SumSquare([ Re / R if R != 0 else 0, (DataSSe + BkgSSe) / (DataSS - BkgSS) if (DataSS - BkgSS != 0) else 0 ]) return y, e ## Print tables def PrintSSyields(self, name='', level=''): self.SetChanAndLevel('', level) if name == '': name = 'SameSign_%s' % (self.GetLevel()) t = OutText(self.GetOutPath(), name) t.SetSeparatorLength(12 + (3 + 16) * 3) t.SetDefaultFixOption(False) t.line('Same-sign yields for level of selection \'%s\'' % (self.GetLevel())) t.bar() s = lambda tit, vee, vmm, vem: t.line( t.fix(tit, 10) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix( vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c')) v = lambda L: '%1.2f' % L[0] + t.pm() + '%1.2f' % L[1] d = lambda L: '%1.0f' % L[0] + t.pm() + '%1.2f' % L[1] S = lambda tit, pr: s(tit, v(self.GetSS(pr, elecName)), v(self.GetSS(pr, muName)), v(self.GetSS(pr, 'ElMu'))) D = lambda tit, pr: s(tit, d(self.GetSS(pr, elecName)), d(self.GetSS(pr, muName)), d(self.GetSS(pr, 'ElMu'))) s('', elecName, muName, 'ElMu') t.sep() for pr in self.promptProcess: S(pr, pr) #S('tt signal', 'tt') #S('tW','tW') #S('Drell-Yan','DY') #S('Dibosons','VV') t.sep() for pr in self.nonpromptProcess: S(pr, pr) #S('W+Jets', 'WJets') #S('tt semilep', 'ttsemilep') t.sep() S('Total MC', [ self.process[lab] for lab in self.promptProcess + self.nonpromptProcess ]) t.sep() D('Data', 'data') t.bar() t.write() def PrintNonpromptEstimate(self, name='', chan='', level=''): chan, lev = self.SetChanAndLevel(chan, level) if name == '': name = 'NonpromptDD_%s_%s' % (self.GetChan(), self.GetLevel()) t = OutText(self.GetOutPath(), name) t.SetSeparatorLength(55 + 20) t.SetDefaultFixOption(False) t.line( ' Nonpromt estimate from a same-sign control retion\nfor channel \'%s\' and level of selection \'%s\'' % (chan, lev)) t.bar() s = lambda tit, vee, vmm, vem: t.line( t.fix(tit, 10) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix( vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c')) v = lambda L: '%1.2f' % L[0] + t.pm() + '%1.2f' % L[1] d = lambda L: '%1.0f' % L[0] + t.pm() + '%1.2f' % L[1] pr = [self.process[p] for p in self.nonpromptProcess] sr = [self.process[p] for p in self.promptProcess] t.line( t.fix(' MC nonprompt estimate (OS W+Jets and semilpetonic tt)', 55) + t.vsep() + v(self.GetYield(pr))) t.sep() t.line( t.fix(' MC nonprompt SS (W+Jets and semilpetonic tt)', 55) + t.vsep() + v(self.GetSS(pr))) t.line( t.fix(' R = nonpromt(OS)/nonprompt(SS)', 55) + t.vsep() + v(self.GetROSSS(pr))) t.line( t.fix(' BkgSS = MC prompt SS (other sources)', 55) + t.vsep() + v(self.GetSS(sr))) t.line( t.fix(' DataSS = Obseved data SS', 55) + t.vsep() + v(self.GetSS('data'))) t.sep() t.line( t.fix(' Nonprompt data-driven estimate = R(DataSS-BkgSS)', 55) + t.vsep() + v(self.GetNonpromptDD())) t.bar() t.write() ### Init def __init__(self, path, outpath='./temp/', chan='ElMu', level='2jets', process={}, prompt=[], nonprompt=[], lumi=304.32, histonameprefix='H', yieldsSSname='SSYields'): self.SetPath(path) self.t = TopHistoReader(self.GetPath()) self.t.SetHistoNamePrefix(histonameprefix) self.t.SetYieldsSSname(yieldsSSname) self.SetLumi(lumi) self.SetOutPath(outpath) self.SetChanAndLevel(chan, level) self.process = process self.nonpromptProcess = [] self.promptProcess = [] if prompt == [] or nonprompt == []: for pr in process.keys(): if pr in ['data', 'Data', 'DATA']: continue elif pr in [ 'fake', 'nonprompt', 'Nonprompt', 'NonPrompt', 'Fake', 'fakes', 'Fakes' ]: self.nonpromptProcess.append(pr) else: self.promptProcess.append(pr) else: self.promptProcess = prompt self.nonpromptProcess = nonprompt