def SumExpSyst(self, syst=''): if syst == '': syst = self.GetExpSyst() if self.verbose >= 2: print 'Including systematics: ', syst if ',' in syst: self.SumExpSyst(syst.replace(' ', '').split(',')) return if isinstance(syst, list): for s in syst: self.SumExpSyst(s) return self.SetSyst(syst) hnom = self.GetAllBkg() hvar = self.GetAllBkg(syst) nbins = hnom.GetNbinsX() if not hasattr(self, 'sysup'): self.sysup = [0] * nbins self.sysdo = [0] * nbins d = [ hvar.GetBinContent(i) - hnom.GetBinContent(i) for i in range(1, nbins + 1) ] if average(d) >= 0: self.sysup = [sqrt(a * a + b * b) for a, b in zip(self.sysup, d)] else: self.sysdo = [sqrt(a * a + b * b) for a, b in zip(self.sysdo, d)]
def GetPDFuncHisto(nom, pdfvars, alphasvar=[], prName='tt', year=2018): # Using PDF4LHC15_nlo_nf4_30_pdfas, 1+30+2 weights, see Table 6 in # https://arxiv.org/pdf/1510.03865.pdf # Eq [20] for PDF unc: 0.01 (0.45 %) # Eq [27] for alpha_S: 0.00 (0.15 %) nom.SetName(prName) nbins = nom.GetNbinsX() + 1 up = nom.Clone(prName + '_PDFUp') do = nom.Clone(prName + '_PDFDown') unc = [0] * nbins alphaunc = [0] * nbins for var in pdfvars: for i in range(0, nbins): n = nom.GetBinContent(i) v = var.GetBinContent(i) unc[i] += (n - v) * (n - v) unc = [sqrt((x if year != 2016 else x / 100)) for x in unc] if len(alphasvar) == 2: for i in range(0, nbins): vu = alphasvar[0].GetBinContent(i) vd = alphasvar[1].GetBinContent(i) alphaunc[i] = (vu - vd) / 2 unc = [sqrt(x * x + y * y) for x, y in zip(unc, alphaunc)] for i in range(0, nbins): n = nom.GetBinContent(i) up.SetBinContent(i, n + unc[i]) do.SetBinContent(i, n - unc[i]) return [nom, up, do]
def AddSystFromHistos(self): if not hasattr(self, 'sysup'): self.ResetSyst() for pr in self.systSamples: name = pr.GetName() hvar = pr.histo() hnom = self.GetProcess(name).histo() nbins = hnom.GetNbinsX() d = [hvar.GetBinContent(i) - hnom.GetBinContent(i) for i in range(1, nbins+1)] if average(d) > 0: self.sysup = [sqrt(a*a+b*b) for a,b in zip(self.sysup, d)] else: self.sysdo = [sqrt(a*a+b*b) for a,b in zip(self.sysdo, d)]
def AddStatUnc(self): if self.verbose >= 2: print 'Setting MC stat uncertainties...' if self.IncludedStatUnc: return self.IncludedStatUnc = True hnom = self.GetAllBkg() nbins = hnom.GetNbinsX() if not hasattr(self, 'sysup'): self.ResetSyst() du = [hnom.GetBinError(i) for i in range(1, nbins+1)] dd = [-hnom.GetBinError(i) for i in range(1, nbins+1)] self.sysup = [sqrt(a*a+b*b) for a,b in zip(self.sysup, du)] self.sysdo = [sqrt(a*a+b*b) for a,b in zip(self.sysdo, dd)]
def GetPrefireProbability(self, Map, eta, pt, maxpt): bin = Map.FindBin(eta, min(pt, maxpt - 0.01)) pref_prob = Map.GetBinContent(bin) stat = Map.GetBinError(bin) # bin statistical uncertainty syst = 0.2 * pref_prob # 20% of prefire rate if self.variation == 1: pref_prob = min(pref_prob + sqrt(stat * stat + syst * syst), 1.0) if self.variation == -1: pref_prob = max(pref_prob - sqrt(stat * stat + syst * syst), 0.0) return pref_prob
def GetPDFunc(self): ''' Eq [20] in: https://arxiv.org/pdf/1510.03865.pdf Weights 2, to 31, using 1 as nominal ''' delta = sum([self.GetRelUncPDF(i)*self.GetRelUncPDF(i) for i in range(2,32)]) return sqrt(delta)
def GetSum2Unc(self, lsyst='', includeStat=True): ''' From a list of uncertainties, get a list of per-bin unc w.r.t. nominal histo lsyst is a list of uncertainty names, not labels ''' if lsyst == '': lsyst = self.systname[:] elif isinstance(lsyst, str) and ',' in lsyst: lsyst = lsyst.replace(' ', '').split(',') elif not isinstance(lsyst, list): lsyst = [syst] if includeStat and not 'stat' in lsyst: lsyst.append('stat') #sum2.append(self.GetStatUnc()) unc = [] systExist = lambda x: x in self.systlabels for s in lsyst: listOfGoodSyst = filter(systExist, self.GetListOfCandNames(s)) if s == 'stat': listOfHistos = [self.GetStatHisto()] elif len(listOfGoodSyst) == 0: print 'WARNING: no systematic found for label %s!' % s continue else: listOfHistos = [self.sumdic[s] for s in listOfGoodSyst] unc.append(self.GetDifUnc(self.sumdic[''], listOfHistos)) sum2 = [] nlen = len(unc[0]) for i in range(nlen): v = 0 for iunc in unc: v += iunc[i] * iunc[i] v = sqrt(v) sum2.append(v) return sum2
def GetSFfromTGraph(self, name, var): ''' Reads a TGraphAsymmetricErrors and returs value ''' if ',' in name: return self.GetSFfromTGraph( [x.replace(' ', '') for x in name.split(',')], var) if isinstance(name, list): s = 1 e = 0 for n in name: sf, err = self.GetSFfromTGraph(n, var) s *= sf e += err * err return s, sqrt(e) g = self.inputs[name] n = g.GetN() x = array('f', g.GetX()) y = array('f', g.GetY()) # Below minimum if var < x[0] - g.GetErrorXlow(0): return [y[0], (g.GetErrorYlow(0) + g.GetErrorYhigh(0)) / 2] for i in range(n): xmin = x[i] - g.GetErrorXlow(i) xmax = x[i] + g.GetErrorXhigh(i) SF = y[i] SFerr = (g.GetErrorYlow(i) + g.GetErrorYhigh(i)) / 2 #print '[%1.1f - %1.1f] %1.2f +/- %1.2f'%(xmin, xmax, SF, SFerr) if var > xmin and var < xmax: return [SF, SFerr] # Above maximum return [y[-1], (g.GetErrorYlow(n - 1) + g.GetErrorYhigh(n - 1)) / 2]
def GetSFandErr(self, name, var1, var2=''): ''' Get SF and SF error from an input hitogram ''' if ',' in name: return self.GetSFandErr( [x.replace(' ', '') for x in name.split(',')], var1, var2) if isinstance(name, list): s = 1 e = 0 for n in name: sf, err = self.GetSFandErr(n, var1, var2) s *= sf e += err * err return s, sqrt(e) nx = self.inputs[name].GetNbinsX() maxx = self.inputs[name].GetXaxis().GetBinUpEdge(nx) maxxm1 = self.inputs[name].GetXaxis().GetBinUpEdge(nx - 1) if var1 > maxx: var1 = (maxx + maxxm1) / 2 if var2 != '': ny = self.inputs[name].GetNbinsY() maxy = self.inputs[name].GetYaxis().GetBinUpEdge(ny) maxym1 = self.inputs[name].GetYaxis().GetBinUpEdge(ny - 1) if var2 > maxy: var2 = (maxy + maxym1) / 2 ibin = self.inputs[name].FindBin( var1) if var2 == '' else self.inputs[name].FindBin(var1, var2, 1) sf = self.inputs[name].GetBinContent(ibin) sferr = self.inputs[name].GetBinError(ibin) return sf, sferr
def GetNamedHisto(self, name, pr = '', rebin = -1): ''' Load an histo from process pr ''' if pr != '': self.SetProcess(pr) if rebin != -1: self.rebin = rebin pr = self.process if ',' in self.process: self.process = self.process.replace(' ', '').split(',') if isinstance(self.process, list): listOfProcess = self.process h = self.GetNamedHisto(name, listOfProcess[0], rebin) for p in listOfProcess[1:]: while p[0] == ' ': p = p[1:] while p[-1] == ' ': p = p[:-1] h.Add(self.GetNamedHisto(name, p, rebin)) return h if ',' in name: listOfNames = name.replace(' ', '').split(',') h = self.GetNamedHisto(listOfNames[0], pr, rebin) for n in listOfNames[1:]: while n[0 ] == ' ': n = n[1:] while n[-1] == ' ': n = n[:-1] h.Add(self.GetNamedHisto(n, pr, rebin)) return h filename = self.path + pr + '.root' if self.verbose: print ' >> Opening file: ' + filename f = TFile.Open(filename) if self.verbose: print ' >> Looking for histo: ' + name if not hasattr(f, name): if name == self.GetHistoName() and self.syst != '': hnosyst = self.var + '_' + self.chan + '_' + self.level if hasattr(f, hnosyst): print 'WARNING: no systematic %s for histo %s in process %s!! Returning nominal...'%(self.syst, hnosyst, pr) return else: print 'ERROR: not found histogram ' + name + ' in file: ' + filename return h = f.Get(name) h.Rebin(self.rebin) nb = h.GetNbinsX() if self.doStackOverflow: h.SetBinContent(nb, h.GetBinContent(nb) + h.GetBinContent(n+2)) h.SetBinContent(nb+2, 0) if not self.IsData: h.Scale(self.lumi) h.SetLineColor(1); h.SetFillStyle(0) h.SetLineWidth(2); h.SetStats(0) h.SetTitle(''); h.GetXaxis().SetTitle('') h.GetYaxis().SetTitle('') h.SetDirectory(0) ### This is a patch, the bin-by-bin stat unc are (whatever the reason) not well calculated... ### This is a temporary solution nbins = h.GetNbinsX() integral = h.Integral() if h.Integral() > 0 else 0 entries = h.GetEntries() for i in range(1,nbins+1): bc = h.GetBinContent(i) if h.GetBinContent(i) > 0 else 0 h.SetBinError(i, sqrt(bc*integral/entries) if entries != 0 else 0) return h
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 GetAccWithUnc(sample, chan, level): h = thr.GetNamedHisto('FiduEvents_%s'%chan, processDic[('tt_'if sample !='tt' else '') +sample]) nEv = h.GetBinContent(lev[level]) genEv = GetGenEv(sample) nEvUnc = sqrt(nEv) acc = nEv/genEv unc = abs(acc - (nEv+nEvUnc)/genEv) return acc, unc
def GetTotRelUnc(self): norm = self.GetNormUnc() # relative syst = self.GetUnc() # relative stat = self.GetStatUnc() # Absolute y = self.GetYield() stat = stat/y if y != 0 else 0 e = norm*norm + syst*syst + stat*stat return sqrt(e)
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 GetPDFunc(self): ''' For 33 weights Eq [20] in: https://arxiv.org/pdf/1510.03865.pdf Weights 2, to 31, using 1 as nominal For 100 weights: ''' val = 0 delta = sum([ self.GetRelUncPDF(i) * self.GetRelUncPDF(i) for i in range(2, 32) ]) if self.nPDFweights == 33: val = sqrt(delta) elif self.nPDFweights == 100: rms = sqrt(delta / 100) #val = sqrt(rms*rms + ((v110-v111)*0.75/2)*((v110-v111)*0.75/2)); val = rms return val
def GetGAandUnc(sname, chan): nom, uncnom = GetAccWithUnc('tt', chan, l) var, uncvar = GetAccWithUnc(sname, chan, l) syst = (var - nom)/nom nomup = nom+uncnom varup = var+uncvar systup1 = (var-nomup)/nomup systup2 = (varup-nom)/nom systunc = sqrt( (syst-systup1)*(syst-systup1) + (syst-systup2)*(syst-systup2) ) return [nom, uncnom, var, uncvar, syst, systunc]
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 GetUnc(self, pr = '', ch = '', ilev = '', s = ''): ''' Return a systematic uncertainty (relative) ''' nom = self.GetYield(pr, ch, ilev) if isinstance(s, list): err = 0 for u in s: e = self.GetUnc(pr, ch, ilev, u) err += e*e return sqrt(err) else: if not s.endswith('Up') and not s.endswith('Down'): varUp = self.GetYield(pr, ch, ilev, s+'Up') varDo = self.GetYield(pr, ch, ilev, s+'Down') return max(abs(nom-varUp)/nom if nom!=0 else 0, abs(nom-varDo)/nom if nom != 0 else 0)
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 == 'ElEl' or chan == 'MuMu': 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('ElEl') m, mr = self.GetScaleFactor('MuMu') SF = sqrt(e*m) err = SF*SumSquare([er/e, mr/m]) return SF,err
def GetUnc(self, name = ''): if name == '': if self.SystUnc != -999: return self.SystUnc else: unc = 0 y = self.GetYield() normUnc = self.GetNormUnc() for val in self.ModUnc.values(): unc += val*val for val in self.ExpUnc.values(): unc += val*val val += y*y*normUnc*normUnc return sqrt(unc) else: for key in self.ModUnc.keys(): if key == name: return self.ModUnc[key] for key in self.ExpUnc.keys(): if key == name: return self.ExpUnc[key] print 'WARNING: not found systematic uncertainty \'%d\'... returning 0'%name return 0
def GetXsecSystUnc(self): ''' Returns the xsec syst unc on cross section ''' effunc = self.GetEffUnc() accunc = self.GetAccUnc() return sqrt(effunc * effunc + accunc * accunc)
def GetEffUnc(self): ''' Return the syst unc on efficiency ''' err = 0 for a in self.effUnc.values(): err += a * a return sqrt(err)
def GetAccUnc(self): ''' Return the syst unc on acceptance ''' err = 0 for a in self.accUnc.values(): err += a * a return sqrt(err)
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 DrawStack(self, histo = '', xtit = '', ytit = '', rebin = 1): ''' Draws a stack plot ''' # Set the canvas and pads self.t.SetRebin(rebin) if histo != '': self.SetHisto(histo) if xtit != '': self.axisXtit = xtit if ytit != '': self.axisYtit = ytit c = TCanvas('c', 'c', 10, 10, 800, 600) c.Divide(1,2) plot = c.GetPad(1) ratio = c.GetPad(2) plot.SetPad( self.hpadx0, self.hpady0, self.hpadx1, self.hpady1) plot.SetMargin(self.hpadMleft, self.hpadMright, self.hpadMbottom, self.hpadMtop) ratio.SetPad(self.rpadx0, self.rpady0, self.rpadx1, self.rpady1) ratio.SetMargin(self.rpadMleft, self.rpadMright, self.rpadMbottom, self.rpadMtop) # Draw the text texcms = self.DrawTextCMS() texmod = self.DrawTextCMSmode() texlum = self.DrawTextLumi() #self.DrawTextChan() texcms.Draw() texmod.Draw() texlum.Draw() # Stack processes and draw stack and data plot.cd() hStack = THStack('stack', '') for pr in self.pr: hStack.Add(pr.histo()) hStack.Draw('hist') datamax = -999 if hasattr(self, 'data'): data = self.data.histo() data.Draw(self.data.GetDrawStyle()) datamax = data.GetMaximum() bkg = hStack.GetStack().Last().Clone('AllBkg') dmax = max(datamax, bkg.GetMaximum()) if isinstance(self.PlotMaximum, float): hStack.SetMaximum(self.PlotMaximum) else: hStack.SetMaximum(dmax*self.PlotMaxScale) if isinstance(self.PlotMinimum, float): hStack.SetMinimum(self.PlotMinimum) hRatio = data.Clone() if hasattr(self, 'data') else bkg.Clone() nbins = hRatio.GetNbinsX() for i in range(nbins+1): b = bkg. GetBinContent(i) d = data.GetBinContent(i) if hasattr(self, 'data') else b if b == 0: b = 1 e = 0 if d == 0 else d/b*(sqrt(d)/d) hRatio.SetBinContent(i, d/b) hRatio.SetBinError(i, e) # Set titles... TGaxis.SetMaxDigits(3) hStack.GetYaxis().SetTitle(self.axisYtit) hStack.GetYaxis().SetTitleSize(self.axisYsize) hStack.GetYaxis().SetTitleOffset(self.axisYoffset) hStack.GetYaxis().SetLabelSize(self.axisYlabSize) hStack.GetYaxis().SetNdivisions(self.axisYnDiv) hStack.GetYaxis().CenterTitle() hStack.GetXaxis().SetTitle("") hStack.GetXaxis().SetLabelSize(0) hRatio.GetXaxis().SetTitle(self.axisXtit) hRatio.GetXaxis().SetTitleSize(self.axisXsize) hRatio.GetXaxis().SetTitleOffset(self.axisXoffset) hRatio.GetXaxis().SetLabelSize(self.axisXlabSize) hRatio.GetXaxis().SetNdivisions(self.axisXnDiv) hRatio.GetYaxis().SetTitle(self.axisRtit) hRatio.GetYaxis().SetTitleSize(self.axisRsize) hRatio.GetYaxis().SetTitleOffset(self.axisRoffset) hRatio.GetYaxis().SetLabelSize(self.axisRlabSize) hRatio.GetYaxis().SetNdivisions(self.axisRnDiv) hRatio.GetYaxis().CenterTitle() if len(self.binLabels) > 0: for i in range(len(self.binLabels)): hRatio.GetXaxis().SetBinLabel(i+1,self.binLabels[i]) # Set syst histo self.AddStatUnc() self.SumExpSyst() bkg.SetFillStyle(3444); bkg.SetFillColor(kGray+2); nbins = bkg.GetNbinsX() for i in range(1, self.nbins+1): err = (abs(self.sysup[i-1]) + abs(self.sysdo[i-1]))/2 #if not err == err: err = 0 bkg.SetBinError(i, err) bkg.Draw("same,e2") # Legend legend = self.SetLegend() for pr in self.pr: legend.AddEntry(pr.histo(), pr.GetName(), 'f') if hasattr(self, 'data'): legend.AddEntry(self.data.histo(), 'Data', 'pe') legend.Draw() # Ratio ratio.cd() hRatio.SetMaximum(self.PlotRatioMax) hRatio.SetMinimum(self.PlotRatioMin) if hasattr(self, 'data'): hRatio.Draw(self.data.GetDrawStyle()) else: hRatio.Draw('lsame') hRatioErr = bkg.Clone("hratioerr") for i in range(1, self.nbins+2): hRatioErr.SetBinContent(i, 1) val = bkg.GetBinContent(i) err = bkg.GetBinError(i) hRatioErr.SetBinError(i, err/val if val != 0 else 0) hRatioErr.Draw("same,e2") # Save if not os.path.isdir(self.GetOutPath()): os.makedirs(self.GetOutPath()) c.Print(self.GetOutName()+'.png', 'png') c.Print(self.GetOutName()+'.pdf', 'pdf')
def GetPDFandAlphaSunc(self): ''' Quadratic sum of both ''' pdfunc = self.GetPDFunc() alphas = self.GetAlphaSunc() return sqrt(pdfunc*pdfunc + alphas*alphas)
def GetSystAbsUnc(self): y = self.GetYield() norm = self.GetNormUnc()*y # relative syst = self.GetUnc()*y # relative e = norm*norm + syst*syst return sqrt(e)
def SetData(self, n): ''' Number of observed events ''' self.data = n self.dataunc = sqrt(n)
def insideLoop(self, t): # This is called for each event and has the meaty part of the analysis self.resetObjects() FidR = self.selFRLep TotR = self.selTRLep ### Lepton selection ########################################### if not self.isData: nGenLep = t.nGenDressedLepton ##### Fiducial Region Leptons if self.doFiducialAndTotalRegion: Fid1 = True for i in range(t.nGenPart): Fid0 = True p = TLorentzVector() p.SetPtEtaPhiM(t.GenPart_pt[i], t.GenPart_eta[i], t.GenPart_phi[i], t.GenPart_mass[i]) if not (abs(t.GenPart_pdgId[i]) == 11 or abs(t.GenPart_pdgId[i]) == 13): Fid0 = False pdg = abs(t.GenPart_pdgId[i]) charge = 1 if t.GenPart_pdgId[i] > 0: charge = -1 if t.GenPart_status[i] != 1: Fid0 = False if p.Pt() < 5 or abs(p.Eta()) > 2.5: Fid0 = False if Fid0 == True: self.selFRLeptons.append(lepton(p, charge, pdg)) #######XXX nFRLep = len(self.selFRLeptons) FRleps = self.selFRLeptons FRpts = [lep.Pt() for lep in FRleps] FRpdgs = [lep.GetPDGid() for lep in FRleps] # Order leptons by pT self.selFRLeptons = [lep for _, lep in sorted(zip(FRpts, FRleps))] if nFRLep < 3: Fid1 = False if Fid1 == True: l0 = self.selFRLeptons[nFRLep - 1] l1 = self.selFRLeptons[nFRLep - 2] l2 = self.selFRLeptons[nFRLep - 3] totId = l0.GetPDGid() + l1.GetPDGid() + l2.GetPDGid() ich = -1 if totId == 33: ich = ch.eee elif totId == 35: ich = ch.mee elif totId == 37: ich = ch.emm elif totId == 39: ich = ch.mmm mz = [ CheckZpair(l0, l1), CheckZpair(l0, l2), CheckZpair(l1, l2) ] mzdif = [abs(x - 91) for x in mz] minmzdif = min(mzdif) if minmzdif == mzdif[0]: lZ1 = dc(l0) lZ2 = dc(l1) lW = dc(l2) elif minmzdif == mzdif[1]: lZ1 = dc(l0) lZ2 = dc(l2) lW = dc(l1) elif minmzdif == mzdif[2]: lZ1 = dc(l1) lZ2 = dc(l2) lW = dc(l0) zFRleps = [lZ1, lZ2] if abs(InvMass(zFRleps) - 91.) > 30.: Fid1 = False FidR = FidR + 1 if Fid1 == True: self.GetHisto('YieldsFid', ich).Fill(FidR, 1) #### Total Region Leptons Tot1 = True for i in range(t.nGenPart): Tot0 = True p = TLorentzVector() p.SetPtEtaPhiM(t.GenPart_pt[i], t.GenPart_eta[i], t.GenPart_phi[i], t.GenPart_mass[i]) if not (abs(t.GenPart_pdgId[i]) == 11 or abs(t.GenPart_pdgId[i]) == 13): Tot0 = False pdg = abs(t.GenPart_pdgId[i]) charge = 1 if t.GenPart_pdgId[i] > 0: charge = -1 if t.GenPart_status[i] != 1: Tot0 = False if Tot0 == True: self.selTRLeptons.append(lepton(p, charge, pdg)) #######XXX nTRLep = len(self.selTRLeptons) TRleps = self.selTRLeptons TRpts = [lep.Pt() for lep in TRleps] TRpdgs = [lep.GetPDGid() for lep in TRleps] # Order leptons by pT self.selTRLeptons = [lep for _, lep in sorted(zip(TRpts, TRleps))] if nTRLep < 3: Tot1 = False if Tot1 == True: l0 = self.selTRLeptons[nTRLep - 1] l1 = self.selTRLeptons[nTRLep - 2] l2 = self.selTRLeptons[nTRLep - 3] totId = l0.GetPDGid() + l1.GetPDGid() + l2.GetPDGid() ich = -1 if totId == 33: ich = ch.eee elif totId == 35: ich = ch.mee elif totId == 37: ich = ch.emm elif totId == 39: ich = ch.mmm mz = [ CheckZpair(l0, l1), CheckZpair(l0, l2), CheckZpair(l1, l2) ] mzdif = [abs(x - 91) for x in mz] minmzdif = min(mzdif) if minmzdif == mzdif[0]: lZ1 = dc(l0) lZ2 = dc(l1) lW = dc(l2) elif minmzdif == mzdif[1]: lZ1 = dc(l0) lZ2 = dc(l2) lW = dc(l1) elif minmzdif == mzdif[2]: lZ1 = dc(l1) lZ2 = dc(l2) lW = dc(l0) zTRleps = [lZ1, lZ2] if abs(InvMass(zTRleps) - 91.) > 30.: Tot1 = False TotR = TotR + 1 if Tot1 == True: self.GetHisto('YieldsTot', ich).Fill(TotR, 1) #print t.event ##### Muons for i in range(t.nMuon): p = TLorentzVector() p.SetPtEtaPhiM(t.Muon_pt[i], t.Muon_eta[i], t.Muon_phi[i], t.Muon_mass[i]) charge = t.Muon_charge[i] # Loose (analysis) ID == MediumPrompt POG ID if not t.Muon_mediumPromptId[i]: continue # Loose ISO #if not t.Muon_miniIsoId[i] >= 2: continue if not (t.Muon_miniPFRelIso_all[i] < 0.4): continue if not t.Muon_sip3d[i] < 5: continue # Loose IP dxy = abs(t.Muon_dxy[i]) dz = abs(t.Muon_dz[i]) if dxy > 0.05 or dz > 0.1: continue # Acceptance cuts; Momentum cut to respect trigger requirements if abs(p.Eta()) > 2.4: continue # Now the tight (analysis) ID (leptonMVA + tighter miniIso) passTightID = True passbtag = True if t.Muon_mvaTTH[i] < 0.55: passTightID = False #if t.Muon_miniIsoId[i] < 4: passTightID = False if (t.Muon_miniPFRelIso_all[i] > 0.325): passTightID = False if t.Muon_jetIdx[i] >= 0: if t.Jet_btagDeepB[t.Muon_jetIdx[i]] > 0.1522: passbtag = False self.selLeptons.append( lepton(p, charge, 13, t.Muon_genPartFlav[i] if not (self.isData) else "\0", passTightID, passbtag)) ##### Electrons for i in range(t.nElectron): p = TLorentzVector() p.SetPtEtaPhiM(t.Electron_pt[i], t.Electron_eta[i], t.Electron_phi[i], t.Electron_mass[i]) charge = t.Electron_charge[i] etaSC = abs(p.Eta()) convVeto = t.Electron_convVeto[i] passTightID = True passbtag = True dxy = abs(t.Electron_dxy[i]) dz = abs(t.Electron_dz[i]) # Loose (analysis) ID is POG MVALoose WP `miniIso if dxy > 0.05 or dz > 0.1: continue # Acceptance cuts (tighter lepton pt cut due to trigger) if abs(p.Eta()) > 2.5: continue if ord(t.Electron_lostHits[i]) > 0: continue if not (t.Electron_mvaFall17V2Iso_WPL[i]): continue if not (t.Electron_miniPFRelIso_all[i] < 0.4): continue if not (t.Electron_convVeto[i]): continue # Tight (analysis) ID is leptonMVA + tighter miniIso if not (t.Electron_sip3d[i] < 8): passTightID = False if (t.Electron_mvaTTH[i] < 0.125): passTightID = False if (t.Electron_miniPFRelIso_all[i] > 0.085): passTightID = False if t.Electron_jetIdx[i] >= 0: if t.Jet_btagDeepB[t.Electron_jetIdx[i]] > 0.1522: passbtag = False self.selLeptons.append( lepton( p, charge, 11, t.Electron_genPartFlav[i] if not (self.isData) else "\0", passTightID, passbtag)) leps = self.selLeptons pts = [lep.Pt() for lep in leps] pdgs = [lep.GetPDGid() for lep in leps] # Order leptons by pT self.selLeptons = [lep for _, lep in sorted(zip(pts, leps))] ### Set trilepton channel nLep = len(self.selLeptons) # >= 3 leptons for WZ, != 4 to decrease ZZ if nLep != 3: return False ### And look for OSSF and classify the channel l0 = self.selLeptons[0] l1 = self.selLeptons[1] l2 = self.selLeptons[2] totId = l0.GetPDGid() + l1.GetPDGid() + l2.GetPDGid() ich = -1 if totId == 33: ich = ch.eee if not (pts[0] >= 15 and pts[1] >= 10 and pts[2] >= 8): return False elif totId == 35: ich = ch.mee if not (pts[0] >= 12 and pts[1] >= 10 and pts[2] >= 8): return False elif totId == 37: ich = ch.emm if not (pts[0] >= 12 and pts[1] >= 12 and pts[2] >= 8): return False elif totId == 39: ich = ch.mmm if not (pts[0] >= 12 and pts[1] >= 10 and pts[2] >= 10): return False #if totId != 33 and totId != 37: return # lW, lZ1, lZ2 assignation (same as 13 TeV) mz = [CheckZpair(l0, l1), CheckZpair(l0, l2), CheckZpair(l1, l2)] #if mz[0]<12 or mz[1]<12 or mz[2]<12: return False #if max(mz) == 0: return False # +++, --- mzdif = [abs(x - 91) for x in mz] minmzdif = min(mzdif) #if minmzdif == 0: return False # This made no sense here, we would be filtering exactly on peak Zs! if minmzdif == mzdif[0]: lZ1 = dc(l0) lZ2 = dc(l1) lW = dc(l2) elif minmzdif == mzdif[1]: lZ1 = dc(l0) lZ2 = dc(l2) lW = dc(l1) elif minmzdif == mzdif[2]: lZ1 = dc(l1) lZ2 = dc(l2) lW = dc(l0) zleps = [lZ1, lZ2] tleps = [lW, lZ1, lZ2] wleps = [lW, lZ1, lZ2] #If Wpt > 20 this is not needed any more #if max([x.p.Pt() for x in tleps]) < 20: return False if CheckSign(tleps[0], tleps[2]) == 1: tleps = [lW, lZ2, lZ1] # On Z-peak if abs(InvMass(zleps) - 91.) > 30.: return False if not (InvMass(l0, l1) > 12 and InvMass(l0, l2) > 12 and InvMass(l1, l2) > 12): return False ### Trigger ########################################### trigger = { ch.eee: t.HLT_HIEle20_WPLoose_Gsf or t.HLT_HIEle17_WPLoose_Gsf or t.HLT_HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ or t.HLT_HIEle15_Ele8_CaloIdL_TrackIdL_IsoVL, #ch.mee:t.HLT_HIL3Mu20 or t.HLT_HIEle20_WPLoose_Gsf or t.HLT_HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ, ch.mee: t.HLT_HIL3Mu20 or t.HLT_HIL3Mu12 or t.HLT_HIEle20_Ele12_CaloIdL_TrackIdL_IsoVL_DZ or t.HLT_HIEle15_Ele8_CaloIdL_TrackIdL_IsoVL or t.HLT_HIEle17_WPLoose_Gsf or t.HLT_HIEle20_WPLoose_Gsf, #ch.emm:t.HLT_HIL3Mu20 or t.HLT_HIEle20_WPLoose_Gsf or t.HLT_HIL3DoubleMu0 or t.HLT_HIL3DoubleMu10, ch.emm: t.HLT_HIL3Mu20 or t.HLT_HIL3Mu12 or t.HLT_HIEle17_WPLoose_Gsf or t.HLT_HIEle20_WPLoose_Gsf or t.HLT_HIL3DoubleMu10, #ch.mmm:t.HLT_HIL3Mu20 or t.HLT_HIL3DoubleMu0 or t.HLT_HIL3DoubleMu10, ch.mmm: t.HLT_HIL3Mu20 or t.HLT_HIL3Mu12 or t.HLT_HIL3DoubleMu10, } passTrig = trigger[ich] ### Remove overlap events in datasets # In tt @ 5.02 TeV, if self.isData: if self.sampleDataset == datasets.SingleElec: if ich == ch.eee: passTrig = trigger[ch.eee] elif ich == ch.mee: passTrig = trigger[ch.eee] elif ich == ch.emm: passTrig = trigger[ch.eee] and not trigger[ch.mmm] else: passTrig = False elif self.sampleDataset == datasets.SingleMuon: if ich == ch.mee: passTrig = trigger[ch.mmm] and not trigger[ch.eee] elif ich == ch.emm: passTrig = trigger[ch.mmm] elif ich == ch.mmm: passTrig = trigger[ch.mmm] else: passTrig = False # Lepton SF self.SFelec = 1 self.SFmuon = 1 self.SFelecErr = 0 self.SFmuonErr = 0 if not self.isData: for lep in self.selLeptons: if lep.IsMuon(): sf, err = self.GetSFandErr('MuonIsoSF, MuonIdSF', max(21, lep.Pt()), TMath.Abs(lep.Eta())) self.SFmuon *= sf self.SFmuonErr += err * err # stat + syst from TnP self.SFmuonErr += 0.005 * 0.005 # Iso phase space extrapolation else: elecsf = 'ElecEB' if lep.Eta() < 1.479 else 'ElecEE' recosf = 'RecoEB' if lep.Eta() < 1.479 else 'RecoEE' ssf, serr = self.GetSFfromTGraph(elecsf, lep.Pt()) rsf, rerr = self.GetSFfromTGraph(recosf, lep.Pt()) sf = (1. / ssf) * rsf if rerr > 0.05: rerr = 0.01 # XXX TEMPORARY CORRECTION TO AVOID WRONG SF UNCERTAINTIES if serr > 0.05: serr = 0.01 # XXX TEMPORARY CORRECTION TO AVOID WRONG SF UNCERTAINTIES self.SFelec *= sf self.SFelecErr += serr * serr + rerr * rerr self.SFelecErr = sqrt(self.SFelecErr) self.SFmuonErr = sqrt(self.SFmuonErr) ### Jet selection ########################################### for i in range(t.nJet): p = TLorentzVector() jetpt = getattr(t, self.jetptvar)[i] p.SetPtEtaPhiM(jetpt, t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass[i]) csv = t.Jet_btagCSVV2[i] deepcsv = t.Jet_btagDeepB[i] deepflav = t.Jet_btagDeepFlavB[i] jid = t.Jet_jetId[i] flav = t.Jet_hadronFlavour[i] if not self.isData else -999999 # Jet ID > 1, tight Id if not jid > 1: continue # |eta| < 2.5 if abs(p.Eta()) > 2.5: continue j = jet(p, csv, flav, jid, deepcsv, deepflav) if csv >= 0.8484: j.SetBtag() ### Misssing CSVv2 SFs !!!! if not j.IsClean(self.selLeptons, 0.4): continue if p.Pt() >= self.JetPtCut: self.selJets.append(j) if not self.isData and self.doSyst: if self.doJECunc: pJESUp = TLorentzVector() pJERUp = TLorentzVector() pJESDo = TLorentzVector() pJERDo = TLorentzVector() pJESUp.SetPtEtaPhiM(t.Jet_pt_jesTotalUp[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jesTotalUp[i]) pJESDo.SetPtEtaPhiM(t.Jet_pt_jesTotalDown[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jesTotalDown[i]) pJERUp.SetPtEtaPhiM(t.Jet_pt_jerUp[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jerUp[i]) pJERDo.SetPtEtaPhiM(t.Jet_pt_jerDown[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jerDown[i]) jJESUp = jet(pJESUp, csv, flav, jid, deepcsv) jJESDo = jet(pJESDo, csv, flav, jid, deepcsv) jJERUp = jet(pJERUp, csv, flav, jid, deepcsv) jJERDo = jet(pJERDo, csv, flav, jid, deepcsv) if csv >= 0.8484: jJESUp.SetBtag() jJESDo.SetBtag() jJERUp.SetBtag() jJERDo.SetBtag() if pJESUp.Pt() >= self.JetPtCut: self.selJetsJESUp.append(jJESUp) if pJESDo.Pt() >= self.JetPtCut: self.selJetsJESDo.append(jJESDo) if pJERUp.Pt() >= self.JetPtCut: self.selJetsJERUp.append(jJERUp) if pJERDo.Pt() >= self.JetPtCut: self.selJetsJERDo.append(jJERDo) self.selJets = SortByPt(self.selJets) if not self.isData and self.doSyst: self.selJetsJESUp = SortByPt(self.selJetsJESUp) self.selJetsJESDo = SortByPt(self.selJetsJESDo) self.selJetsJERUp = SortByPt(self.selJetsJERUp) self.selJetsJERDo = SortByPt(self.selJetsJERDo) ##### MET #met = getattr(t, self.metptvar) #self.pmet.SetPtEtaPhiM(met, 0, t.MET_phi, 0) self.pmet.SetPtEtaPhiM(t.MET_pt, 0, t.MET_phi, 0) if not self.isData and self.doSyst: self.pmetJESUp.SetPtEtaPhiM(t.MET_pt_jesTotalUp, 0, t.MET_phi_jesTotalUp, 0) self.pmetJESDo.SetPtEtaPhiM(t.MET_pt_jesTotalDown, 0, t.MET_phi_jesTotalDown, 0) self.pmetJERUp.SetPtEtaPhiM(t.MET_pt_jerUp, 0, t.MET_phi_jerUp, 0) self.pmetJERDo.SetPtEtaPhiM(t.MET_pt_jerDown, 0, t.MET_phi_jerDown, 0) nJets = len(self.selJets) nBtag = GetNBtags(self.selJets) wpt = lW.Pt() Z1pt = lZ1.Pt() Z2pt = lZ2.Pt() m3l = (lW.P() + lZ1.P() + lZ2.P()).M() if nJets > 1: htmiss = (lW.P() + lZ1.P() + lZ2.P() + TLorentzVector(self.selJets[0].P()) + TLorentzVector(self.selJets[1].P())).Pt() elif nJets > 0: htmiss = (lW.P() + lZ1.P() + lZ2.P() + TLorentzVector(self.selJets[0].P())).Pt() else: htmiss = (lW.P() + lZ1.P() + lZ2.P()).Pt() ### Event weight and othe global variables ########################################### self.nvtx = t.PV_npvs self.PUSF = 1 self.PUUpSF = 1 self.PUDoSF = 1 if not self.isData: self.PUSF = self.PUweight.GetWeight(t.Pileup_nPU) self.PUUpSF = self.PUweight.GetWeightUp(t.Pileup_nPU) self.PUDoSF = self.PUweight.GetWeightDown(t.Pileup_nPU) else: self.PUSF = 1 self.PUUpSF = 1 self.PUDoSF = 1 self.prefWeight = 1 self.prefWeightUp = 1 self.prefWeightDo = 1 if not self.isData: self.prefWeight = self.PrefCorr.GetWeight(t) self.prefWeightUp = self.PrefCorr.GetWeightUp(t) self.prefWeightDo = self.PrefCorr.GetWeightDown(t) ### Event selection ########################################### self.SetWeight(systematic.nom) weight = self.weight # Better require the trigger properly if not passTrig: return #print systlabel.keys() # And now fill all histograms for each variation for isyst in systlabel.keys(): if not self.doSyst and isyst != systematic.nom: continue if self.isData and isyst != systematic.nom: continue leps, jets, pmet = self.SetVariables(isyst) nJets = len(jets) nBtag = GetNBtags(jets) wmt = MT(lW, pmet) if isyst != systematic.JESUp or isyst != systematic.JESDo or isyst != systematic.JERUp or isyst != systematic.JERDo: leps = tleps self.FillAll(ich, lev.lep, isyst, leps, jets, pmet) self.GetHisto('YieldsLep', ich, '', isyst).Fill(lev.lep, self.weight) #self.OriginLeptons(pts, ich, lev.lep, isyst) if tleps[0].passTightID and tleps[1].passTightID and tleps[ 2].passTightID and tleps[0].passbtag and tleps[ 1].passbtag and tleps[2].passbtag: self.FillAll(ich, lev.met, isyst, leps, jets, pmet) #self.OriginLeptons(pts, ich, lev.met, isyst) if tleps[0].passTightID and tleps[1].passTightID and tleps[ 0].passbtag and tleps[1].passbtag and wpt > 20: self.FillAll(ich, lev.wpt, isyst, leps, jets, pmet) if wpt > 20 and Z1pt > 10 and Z2pt > 10: self.FillAll(ich, lev.zpt, isyst, leps, jets, pmet) if tleps[0].passTightID and tleps[0].passbtag: self.FillAll(ich, lev.m3l, isyst, leps, jets, pmet) if tleps[0].passTightID and tleps[0].passbtag: self.FillAll(ich, lev.htmiss, isyst, leps, jets, pmet) if tleps[0].passTightID and tleps[1].passTightID and tleps[ 0].passbtag and tleps[1].passbtag: self.FillAll(ich, lev.sr, isyst, leps, jets, pmet) # if tleps[0].passTightID and wpt > 20 and htmiss > 15 and m3l > 100: # self.FillAll(ich, lev.srtight, isyst, leps, jets, pmet) if tleps[0].passTightID and tleps[1].passTightID and tleps[ 0].passbtag and tleps[1].passbtag and m3l > 100: self.FillAll(ich, lev.srtight, isyst, leps, jets, pmet) if tleps[0].passTightID and tleps[1].passTightID and tleps[ 0].passbtag and tleps[ 1].passbtag and m3l > 100 and wpt > 20: self.FillAll(ich, lev.tight, isyst, leps, jets, pmet) return True
def insideLoop(self, t): self.resetObjects() ### Lepton selection ########################################### if not self.isData: nGenLep = t.nGenDressedLepton if self.isTT and not self.doTTbarSemilep and nGenLep < 2: return if self.doTTbarSemilep and nGenLep >= 2: return if self.isTT: genLep = [] for i in range(nGenLep): p = TLorentzVector() p.SetPtEtaPhiM(t.GenDressedLepton_pt[i], t.GenDressedLepton_eta[i], t.GenDressedLepton_phi[i], t.GenDressedLepton_mass[i]) pdgid = abs(t.GenDressedLepton_pdgId[i]) if p.Pt() < 12 or abs(p.Eta()) > 2.4: continue genLep.append(lepton(p, 0, pdgid)) pts = [lep.Pt() for lep in genLep] genLep = [lep for _, lep in sorted(zip(pts, genLep))] if len(genLep) >= 2: genChan = 0 l0 = genLep[0] l1 = genLep[1] totId = l0.GetPDGid() + l1.GetPDGid() if totId == 24: genChan = ch.ElMu elif totId == 22: genChan = ch.ElEl elif totId == 26: genChan = ch.MuMu genMll = InvMass(l0, l1) genMET = t.GenMET_pt genJets = [] ngenJet = 0 ngenBJet = 0 for i in range(t.nGenJet): p = TLorentzVector() p.SetPtEtaPhiM(t.GenJet_pt[i], t.GenJet_eta[i], t.GenJet_phi[i], t.GenJet_mass[i]) if p.Pt() < 25 or abs(p.Eta()) > 2.4: continue pdgid = abs(t.GenJet_partonFlavour[i]) j = jet(p) #if not j.IsClean(genLep, 0.4): continue genJets.append(j) ngenJet += 1 if pdgid == 5: ngenBJet += 1 # Fill fidu yields histo if genMll >= 20 and genLep[0].Pt() >= 20: self.obj['FiduEvents'].Fill(lev.dilepton) if genChan == ch.ElEl or genChan == ch.MuMu: if abs(genMll - 90) > 15: self.obj['FiduEvents'].Fill(lev.ZVeto) if genMET > 35: self.obj['FiduEvents'].Fill(lev.MET) if ngenJet >= 2: self.obj['FiduEvents'].Fill(lev.jets2) if ngenBJet >= 1: self.obj['FiduEvents'].Fill(lev.btag1) else: self.obj['FiduEvents'].Fill(lev.ZVeto) self.obj['FiduEvents'].Fill(lev.MET) if ngenJet >= 2: self.obj['FiduEvents'].Fill(lev.jets2) if ngenBJet >= 1: self.obj['FiduEvents'].Fill(lev.btag1) ##### Muons for i in range(t.nMuon): p = TLorentzVector() p.SetPtEtaPhiM(t.Muon_pt[i], t.Muon_eta[i], t.Muon_phi[i], t.Muon_mass[i]) charge = t.Muon_charge[i] # Tight ID #if not t.Muon_tightId[i]: continue # Tight ISO, RelIso04 < 0.15 if not t.Muon_pfRelIso04_all[i] < 0.15: continue # Tight IP dxy = abs(t.Muon_dxy[i]) dz = abs(t.Muon_dz[i]) if dxy > 0.05 or dz > 0.1: continue # pT < 12 GeV, |eta| < 2.4 if p.Pt() < 12 or abs(p.Eta()) > 2.4: continue self.selLeptons.append(lepton(p, charge, 13)) ##### Electrons for i in range(t.nElectron): p = TLorentzVector() pt = t.Electron_pt[i] eta = t.Electron_eta[i] ecorr = t.Electron_eCorr[i] if not self.isData else 1 ptcorr = GetElecPt(pt, eta, ecorr, self.isData) ptcorr = GetElecPtSmear(ptcorr, eta, self.isData) p.SetPtEtaPhiM(ptcorr, eta, t.Electron_phi[i], t.Electron_mass[i]) charge = t.Electron_charge[i] etaSC = abs(p.Eta()) dEtaSC = t.Electron_deltaEtaSC[i] convVeto = t.Electron_convVeto[i] R9 = t.Electron_r9[i] # Tight cut-based Id if not t.Electron_cutBased[i] >= 2: continue # 4 Tightcut-based Id if not convVeto: continue # Isolation (RelIso03) tight --> Included in nanoAOD cutbased bit!! relIso03 = t.Electron_pfRelIso03_all[i] #if etaSC <= 1.479 and relIso03 > 0.0361: continue #elif etaSC > 1.479 and relIso03 > 0.094: continue # Tight IP dxy = abs(t.Electron_dxy[i]) dz = abs(t.Electron_dz[i]) if dxy > 0.05 or dz > 0.1: continue # pT > 12 GeV, |eta| < 2.4 if p.Pt() < 12 or abs(p.Eta()) > 2.4: continue self.selLeptons.append(lepton(p, charge, 11)) leps = self.selLeptons pts = [lep.Pt() for lep in leps] self.selLeptons = [lep for _, lep in sorted(zip(pts, leps))] self.selLeptons.reverse() # Lepton SF self.SFelec = 1 self.SFmuon = 1 self.SFelecErr = 0 self.SFmuonErr = 0 self.TrigSF = 1 self.TrigSFerr = 0 self.TrigSFUp = 1 self.TrigSFDo = 1 if not self.isData: for lep in self.selLeptons: if lep.IsMuon(): sf, err = self.GetSFandErr('MuonIsoSF, MuonIdSF', lep.Pt(), TMath.Abs(lep.Eta())) self.SFmuon *= sf self.SFmuonErr += err * err # stat + syst from TnP self.SFmuonErr += 0.005 * 0.005 # Iso phase space extrapolation else: #sf, err = self.GetSFandErr('ElecSF', lep.Eta(), lep.Pt()) elecsf = 'ElecEB' if lep.Eta() < 1.479 else 'ElecEE' recosf = 'RecoEB' if lep.Eta() < 1.479 else 'RecoEE' ssf, serr = self.GetSFfromTGraph(elecsf, lep.Pt()) rsf, rerr = self.GetSFfromTGraph(recosf, lep.Pt()) sf = (1. / ssf) * rsf if rerr > 0.05: rerr = 0.01 # XXX TEMPORARY CORRECTION TO AVOID WRONG SF UNCERTAINTIES if serr > 0.05: serr = 0.01 # XXX TEMPORARY CORRECTION TO AVOID WRONG SF UNCERTAINTIES self.SFelec *= sf self.SFelecErr += serr * serr + rerr * rerr self.SFelecErr = sqrt(self.SFelecErr) self.SFmuonErr = sqrt(self.SFmuonErr) self.SFmuon = 1 ### Jet selection ########################################### for i in range(t.nJet): p = TLorentzVector() jetpt = getattr(t, self.jetptvar)[i] jetmass = getattr(t, self.jetmassvar)[i] p.SetPtEtaPhiM(jetpt, t.Jet_eta[i], t.Jet_phi[i], jetmass) csv = t.Jet_btagCSVV2[i] deepcsv = t.Jet_btagDeepB[i] deepflav = t.Jet_btagDeepFlavB[i] jid = t.Jet_jetId[i] flav = t.Jet_hadronFlavour[i] if not self.isData else -999999 # Jet ID > 1, tight Id if not jid > 1: continue # |eta| < 2.4 if abs(p.Eta()) > 2.4: continue j = jet(p, csv, flav, jid, deepcsv, deepflav) #if csv >= 0.8484 : j.SetBtag() ### Misssing CSVv2 SFs !!!! if not j.IsClean(self.selLeptons, 0.4): continue if p.Pt() >= self.JetPtCut: self.selJets.append(j) if not self.isData and self.doSyst and self.doJECunc: pJESUp = TLorentzVector() pJERUp = TLorentzVector() pJESDo = TLorentzVector() pJERDo = TLorentzVector() pJESUp.SetPtEtaPhiM(t.Jet_pt_jesTotalUp[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jesTotalUp[i]) pJESDo.SetPtEtaPhiM(t.Jet_pt_jesTotalDown[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jesTotalDown[i]) pJERUp.SetPtEtaPhiM(t.Jet_pt_jerUp[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jerUp[i]) pJERDo.SetPtEtaPhiM(t.Jet_pt_jerDown[i], t.Jet_eta[i], t.Jet_phi[i], t.Jet_mass_jerDown[i]) jJESUp = jet(pJESUp, csv, flav, jid, deepcsv, deepflav) jJESDo = jet(pJESDo, csv, flav, jid, deepcsv, deepflav) jJERUp = jet(pJERUp, csv, flav, jid, deepcsv, deepflav) jJERDo = jet(pJERDo, csv, flav, jid, deepcsv, deepflav) if pJESUp.Pt() >= self.JetPtCut: self.selJetsJESUp.append(jJESUp) if pJESDo.Pt() >= self.JetPtCut: self.selJetsJESDo.append(jJESDo) if pJERUp.Pt() >= self.JetPtCut: self.selJetsJERUp.append(jJERUp) if pJERDo.Pt() >= self.JetPtCut: self.selJetsJERDo.append(jJERDo) self.selJets = SortByPt(self.selJets) if not self.isData and self.doSyst and self.doJECunc: self.selJetsJESUp = SortByPt(self.selJetsJESUp) self.selJetsJESDo = SortByPt(self.selJetsJESDo) self.selJetsJERUp = SortByPt(self.selJetsJERUp) self.selJetsJERDo = SortByPt(self.selJetsJERDo) ##### MET self.pmet.SetPtEtaPhiE(t.MET_pt, 0, t.MET_phi, 0) #met = getattr(t, self.metptvar) #self.pmet.SetPtEtaPhiM(met, 0, t.MET_phi, 0) if not self.isData and self.doSyst and self.doJECunc: self.pmetJESUp.SetPtEtaPhiM(t.MET_pt_jesTotalUp, 0, t.MET_phi_jesTotalUp, 0) self.pmetJESDo.SetPtEtaPhiM(t.MET_pt_jesTotalDown, 0, t.MET_phi_jesTotalDown, 0) self.pmetJERUp.SetPtEtaPhiM(t.MET_pt_jerUp, 0, t.MET_phi_jerUp, 0) self.pmetJERDo.SetPtEtaPhiM(t.MET_pt_jerDown, 0, t.MET_phi_jerDown, 0) nJets = len(self.selJets) nBtag = self.GetNBtagJets(self.selJets) ### Set dilepton channel nLep = len(self.selLeptons) if nLep < 2: return l0 = self.selLeptons[0] l1 = self.selLeptons[1] totId = l0.GetPDGid() + l1.GetPDGid() ich = -1 if totId == 24: ich = ch.ElMu elif totId == 22: ich = ch.ElEl elif totId == 26: ich = ch.MuMu ### Trigger ########################################### trigger = { ch.Elec: t.HLT_HIEle20_WPLoose_Gsf, ch.Muon: t.HLT_HIL3Mu20, ch.ElMu: t.HLT_HIL3Mu20 or t. HLT_HIEle20_WPLoose_Gsf, #t.HLT_HIL3Mu20 or t.HLT_HIEle20_WPLoose_Gsf, ch.ElEl: t.HLT_HIEle20_WPLoose_Gsf, ch.MuMu: t.HLT_HIL3Mu20 # or t.HLT_HIL3DoubleMu0 } passTrig = trigger[ich] # TrigerSF if not self.isData: if ich == ch.MuMu: self.TrigSF, self.TrigSFerr = GetMuonTrigSF( l0.Pt(), l0.Eta(), l1.Pt(), l1.Eta()) self.TrigSFUp = self.TrigSF + self.TrigSFerr self.TrigSFDo = self.TrigSF - self.TrigSFerr elif ich == ch.Muon: self.TrigSF, self.TrigSFerr = GetMuonTrigSF(mu.Pt(), mu.Eta()) self.TrigSFUp = self.TrigSF + self.TrigSFerr self.TrigSFDo = self.TrigSF - self.TrigSFerr elif ich == ch.Elec: self.TrigSF = self.GetElecTrigSF(el.pt(), el.eta(), sys=0) self.TrigSFUp = self.GetElecTrigSF(el.pt(), el.eta(), sys=1) self.TrigSFDo = self.GetElecTrigSF(el.pt(), el.eta(), sys=-1) elif ich == ch.ElEl: self.TrigSF = self.GetElecTrigSF(l0.Pt(), l0.Eta(), l1.Pt(), l1.Eta(), 0) self.TrigSFUp = self.GetElecTrigSF(l0.Pt(), l0.Eta(), l1.Pt(), l1.Eta(), 1) self.TrigSFDo = self.GetElecTrigSF(l0.Pt(), l0.Eta(), l1.Pt(), l1.Eta(), -1) elif ich == ch.ElMu: mu = l0 if l0.IsMuon() else l1 el = l1 if l0.IsMuon() else l0 self.TrigSF = self.GetEMuTrigSF(el.Pt(), el.Eta(), mu.Pt(), mu.Eta(), sys=0) self.TrigSFUp = self.GetEMuTrigSF(el.Pt(), el.Eta(), mu.Pt(), mu.Eta(), sys=1) self.TrigSFDo = self.GetEMuTrigSF(el.Pt(), el.Eta(), mu.Pt(), mu.Eta(), sys=-1) ### Remove overlap events in datasets # In tt @ 5.02 TeV, if self.isData: if self.sampleDataset == datasets.SingleElec: if ich == ch.ElEl: passTrig = trigger[ch.ElEl] elif ich == ch.ElMu: passTrig = trigger[ch.Elec] and not trigger[ch.Muon] else: passTrig = False elif self.sampleDataset == datasets.SingleMuon: if ich == ch.MuMu: passTrig = trigger[ch.MuMu] elif ich == ch.ElMu: passTrig = trigger[ch.ElMu] else: passTrig = False elif self.sampleDataset == datasets.DoubleMuon: if ich == ch.MuMu: passTrig = trigger[ich] else: passTrig = False ### Event weight and othe global variables ########################################### self.nvtx = t.PV_npvs self.PUSF = 1 self.PUUpSF = 1 self.PUDoSF = 1 #if not self.isData and self.doPU: # self.PUSF = t.puWeight # self.PUUpSF = t.puWeightUp # self.PUDoSF = t.puWeightDown #if not self.isData: # self.PUSF = self.PUweight.GetWeight(t) # self.PUUpSF = self.PUweight.GetWeightUp(t) # self.PUDoSF = self.PUweight.GetWeightDown(t) self.obj['PUWeights'].Fill(self.PUSF) self.prefWeight = 1 self.prefWeightUp = 1 self.prefWeightDo = 1 if not self.isData: self.prefWeight = self.PrefCorr.GetWeight(t) self.prefWeightUp = self.PrefCorr.GetWeightUp(t) self.prefWeightDo = self.PrefCorr.GetWeightDown(t) self.fsrUp = 1 self.fsrDo = 1 self.isrUp = 1 self.isrDo = 1 if self.doIFSR: self.isrDo = t.PSWeight[0] self.fsrDo = t.PSWeight[1] self.isrUp = t.PSWeight[2] self.fsrUp = t.PSWeight[3] ### Event selection ########################################### self.SetWeight(systematic.nom) weight = self.weight if not passTrig: return self.SS = l0.charge * l1.charge > 0 for isyst in systlabel.keys(): if not self.doSyst and isyst != systematic.nom: continue if self.isData and isyst != systematic.nom: continue leps, jets, pmet = self.SetVariables(isyst) nJets = len(jets) nBtag = self.GetNBtagJets(jets, isyst) if not len(leps) >= 2: continue l0 = leps[0] l1 = leps[1] ### Dilepton pair if l0.Pt() < 20: continue if InvMass(l0, l1) < 20: continue self.FillAll(ich, lev.dilepton, isyst, leps, jets, pmet) if self.isTTnom and isyst == systematic.nom: self.FillLHEweights(t, ich, lev.dilepton) # >> Fill the DY histograms if (self.isData or self.isDY) and isyst == systematic.nom: self.FillDYHistos(self.selLeptons, ich, lev.dilepton) if self.pmet.Pt() > 35: self.FillDYHistos(self.selLeptons, ich, lev.MET) if nJets == 1: self.FillDYHistos(self.selLeptons, ich, 'eq1jet') elif nJets == 2: self.FillDYHistos(self.selLeptons, ich, 'eq2jet') elif nJets >= 3: self.FillDYHistos(self.selLeptons, ich, 'geq3jet') if nJets >= 2: self.FillDYHistos(self.selLeptons, ich, lev.jets2) if nBtag >= 1: self.FillDYHistos(self.selLeptons, ich, lev.btag1) if nBtag >= 2: self.FillDYHistos(self.selLeptons, ich, '2btag') if nJets == 1: self.FillDYHistosElMu(self.selLeptons, ich, 'eq1jet') elif nJets == 2: self.FillDYHistosElMu(self.selLeptons, ich, 'eq2jet') elif nJets >= 3: self.FillDYHistosElMu(self.selLeptons, ich, 'geq3jet') if nJets >= 2: self.FillDYHistosElMu(self.selLeptons, ich, lev.jets2) if nBtag >= 1: self.FillDYHistosElMu(self.selLeptons, ich, lev.btag1) if nBtag >= 2: self.FillDYHistosElMu(self.selLeptons, ich, '2btag') ### WW selec if (l1.p + l0.p).Pt() > 20 and nJets == 0 and pmet.Pt() > 25: self.FillAll(ich, lev.ww, isyst, leps, jets, pmet) ### Z Veto + MET cut if ich == ch.MuMu or ich == ch.ElEl: if abs(InvMass(l0, l1) - 91) < 15: continue self.FillAll(ich, lev.ZVeto, isyst, leps, jets, pmet) if self.isTTnom and isyst == systematic.nom: self.FillLHEweights(t, ich, lev.ZVeto) if pmet.Pt() < 35: continue self.FillAll(ich, lev.MET, isyst, leps, jets, pmet) if self.isTTnom and isyst == systematic.nom: self.FillLHEweights(t, ich, lev.MET) ### 2 jets if nJets < 2: continue self.FillAll(ich, lev.jets2, isyst, leps, jets, pmet) if self.isTTnom and isyst == systematic.nom: self.FillLHEweights(t, ich, lev.jets2) ### 1 b-tag, CSVv2 Medium if nBtag < 1: continue self.FillAll(ich, lev.btag1, isyst, leps, jets, pmet) if self.isTTnom and isyst == systematic.nom: self.FillLHEweights(t, ich, lev.btag1)