def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.isData = initVars['sample'].isData() self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.systematics = self.xbbConfig.getJECuncertainties( step='VReco') + ['unclustEn'] #if self.replaceNominal: self.allVariations = ['Nominal'] #else: # self.allVariations = [] # jet and MET systematics for MC if not self.isData: self.allVariations += self.systematics for syst in self.allVariations: self.addVsystematics(syst) self.addBranch("selLeptonWln_pt") self.addBranch("selLeptonWln_eta") self.addBranch("selLeptonWln_phi") self.addBranch("selLeptonWln_mass")
def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.systematics = self.xbbConfig.getJECuncertainties(step='METXY') self.METsystematics = [x for x in self.systematics if 'jerReg' not in x] + ['unclustEn'] # load METXYCorr_Met_MetPhi from VHbb namespace VHbbNameSpace = self.config.get('VHbbNameSpace', 'library') ROOT.gSystem.Load(VHbbNameSpace) self.MET_Pt = array.array('f', [0.0]) self.MET_Phi = array.array('f', [0.0]) self.sampleTree.tree.SetBranchAddress("MET_Pt", self.MET_Pt) self.sampleTree.tree.SetBranchAddress("MET_Phi", self.MET_Phi) self.addBranch("MET_Pt_uncorrected") self.addBranch("MET_Phi_uncorrected") if self.sample.isMC(): self.MET_Pt_syst = {} self.MET_Phi_syst = {} for syst in self.METsystematics: self.MET_Pt_syst[syst] = {} self.MET_Phi_syst[syst] = {} for Q in self._variations(syst): self.MET_Pt_syst[syst][Q] = array.array('f', [0.0]) self.MET_Phi_syst[syst][Q] = array.array('f', [0.0]) self.sampleTree.tree.SetBranchAddress("MET_pt_"+syst+Q, self.MET_Pt_syst[syst][Q]) self.sampleTree.tree.SetBranchAddress("MET_phi_"+syst+Q, self.MET_Phi_syst[syst][Q]) self.addBranch("MET_pt_uncorrected_"+syst+Q) self.addBranch("MET_phi_uncorrected_"+syst+Q)
def customInit(self, initVars): self.sample = initVars['sample'] self.sampleTree = initVars['sampleTree'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.boostedCut = XbbTools.sanitizeExpression(self.config.get( 'Cuts', self.cutName), config=self.config) self.systVarCuts = {} #self.systematics = sorted(list(set(sum([eval(self.config.get('LimitGeneral', x)) for x in ['sys_cr', 'sys_BDT', 'sys_Mjj']], [])))) self.systematics = self.xbbConfig.getJECuncertainties( step='BoostedFlags') + ['jms', 'jmr', 'unclustEn'] # Nominal self.addIntegerBranch(self.branchName) self.sampleTree.addFormula(self.boostedCut) # systematic variations if self.sample.isMC(): for syst in self.systematics: for UD in self.variations: systVarBranchName = self._v(self.branchName, syst, UD) self.addIntegerBranch(systVarBranchName) self.systVarCuts[systVarBranchName] = self.getSystVarCut( self.boostedCut, syst=syst, UD=UD) self.sampleTree.addFormula( self.systVarCuts[systVarBranchName]) if self.useFlags: # CR/SR flags self.flagCuts = { k: XbbTools.sanitizeExpression(self.config.get('Cuts', k), config=self.config) for k in self.flags } self.systVarFlagCuts = {k: {} for k in self.flags} for k in self.flags: self.sampleTree.addFormula(self.flagCuts[k]) self.addIntegerBranch(k) # systematic variations if self.sample.isMC(): for k in self.flags: for syst in self.systematics: for UD in self.variations: systVarflagName = self._v(k, syst, UD) self.addIntegerBranch(systVarflagName) self.systVarFlagCuts[k][ systVarflagName] = XbbTools.sanitizeExpression( self.getSystVarCut(self.flagCuts[k], syst=syst, UD=UD), config=self.config) self.sampleTree.addFormula( self.systVarFlagCuts[k][systVarflagName])
def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.isData = initVars['sample'].isData() self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.systematics = self.xbbConfig.getJECuncertainties() self.systematicsBoosted = [ x for x in self.systematics if 'jerReg' not in x ] + ['jms', 'jmr'] self.maxnFatJet = 256 if self.sample.isMC(): self.FatJet_Msoftdrop = array.array('f', [0.0] * self.maxnFatJet) self.FatJet_msoftdrop_nom = array.array('f', [0.0] * self.maxnFatJet) self.sampleTree.tree.SetBranchAddress("FatJet_Msoftdrop", self.FatJet_Msoftdrop) self.sampleTree.tree.SetBranchAddress("FatJet_msoftdrop_nom", self.FatJet_msoftdrop_nom) #create backup branches self.addVectorBranch("FatJet_MsoftdropOld", default=0.0, branchType='f', length=self.maxnFatJet, leaflist="FatJet_MsoftdropOld[nFatJet]/F") self.addVectorBranch("FatJet_msoftdrop_nomOld", default=0.0, branchType='f', length=self.maxnFatJet, leaflist="FatJet_msoftdrop_nomOld[nFatJet]/F") self.FatJet_msoftdrop_syst = {} for syst in self.systematicsBoosted: self.FatJet_msoftdrop_syst[syst] = {} for Q in self._variations(syst): self.FatJet_msoftdrop_syst[syst][Q] = array.array( 'f', [0.0] * self.maxnFatJet) self.sampleTree.tree.SetBranchAddress( "FatJet_msoftdrop_" + syst + Q, self.FatJet_msoftdrop_syst[syst][Q]) #backup branches self.addVectorBranch( 'FatJet_msoftdrop_' + syst + Q + 'Old', default=0.0, branchType='f', length=self.maxnFatJet, leaflist='FatJet_msoftdrop_' + syst + Q + 'Old[nFatJet]/F')
def customInit(self, initVars): self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) # Branch names from config self.brJetPtReg = "Jet_PtReg" self.brJetPtNom = "Jet_Pt" self.Jet_btag = self.config.get('General', 'Jet_btag') self.tagidx = self.config.get('General', 'hJidx') if self.config.has_option('General', 'eIdx') and self.config.has_option( 'General', 'muIdx'): self.eIdx = self.config.get('General', 'eIdx') self.muIdx = self.config.get('General', 'muIdx') else: print "WARNING: eIdx and muIdx not defined in [General]! Using default lepton index: \'vLidx\' " self.eIdx = "vLidx" self.muIdx = "vLidx" self.dataset = self.config.get('General', 'dataset') self.METpt = 'MET_Pt' self.METphi = 'MET_Phi' if self.sample.isMC(): self.brJetMassNom = "Jet_mass_nom" else: self.brJetMassNom = "Jet_mass" # nominal self.systematics = [None] ########## # add JES/JER systematics ########## # only defined for nano at the moment if self.propagateJES and self.nano: self.jetSystematics = self.xbbConfig.getJECuncertainties( step='Top') + ['unclustEn'] if self.addBoostSystematics: self.jetSystematics += ['jms'] self.jetSystematics += ['jmr'] if self.sample.isMC(): self.systematics += self.jetSystematics for syst in self.systematics: for Q in self._variations(syst): self.addBranch(self._v(self.branchName, syst, Q))
def customInit(self, initVars): self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) if self.systematics is None: if not self.sample.isData(): jetSystematics= self.xbbConfig.getJECuncertainties(step='KinFit') self.systematics = [None] + [x+'_Up' for x in jetSystematics] + [x+'_Down' for x in jetSystematics] else: self.systematics = [None] print("INFO: computing the fit for", len(self.systematics), " variations.") self.bDict = {} for syst in self.systematics: self.bDict[syst] = {} for n in ['H_mass_fit', 'H_eta_fit', 'H_phi_fit', 'H_pt_fit', 'HVdPhi_fit', 'jjVPtRatio_fit', 'hJets_pt_0_fit', 'hJets_pt_1_fit', 'V_pt_fit', 'V_eta_fit', 'V_phi_fit', 'V_mass_fit', 'H_mass_sigma_fit','H_pt_sigma_fit', 'hJets_pt_0_sigma_fit', 'hJets_pt_1_sigma_fit', 'H_pt_corr_fit', 'llbb_pt_fit', 'llbb_eta_fit', 'llbb_phi_fit', 'llbb_mass_fit', 'llbbr_pt_fit', 'llbbr_eta_fit', 'llbbr_phi_fit', 'llbbr_mass_fit', 'H_mass_fit_noJetMass']: branchNameFull = self.branchName + "_" + n + ('_' + syst if not self._isnominal(syst) else '') self.bDict[syst][n] = branchNameFull self.addBranch(branchNameFull) for n in ['n_recoil_jets_fit', 'status']: branchNameFull = self.branchName + "_" + n + ('_' + syst if not self._isnominal(syst) else '') self.bDict[syst][n] = branchNameFull self.addIntegerBranch(branchNameFull)
class VReco(AddCollectionsModule): def __init__(self, debug=False, replaceNominal=False, puIdCut=6, jetIdCut=4): self.debug = debug or 'XBBDEBUG' in os.environ self.replaceNominal = replaceNominal self.puIdCut = puIdCut self.jetIdCut = jetIdCut super(VReco, self).__init__() self.version = 2 def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.isData = initVars['sample'].isData() self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.systematics = self.xbbConfig.getJECuncertainties( step='VReco') + ['unclustEn'] #if self.replaceNominal: self.allVariations = ['Nominal'] #else: # self.allVariations = [] # jet and MET systematics for MC if not self.isData: self.allVariations += self.systematics for syst in self.allVariations: self.addVsystematics(syst) self.addBranch("selLeptonWln_pt") self.addBranch("selLeptonWln_eta") self.addBranch("selLeptonWln_phi") self.addBranch("selLeptonWln_mass") def addVsystematics(self, syst): if self._isnominal(syst): # replace values from post-processor / selection if self.replaceNominal: self.addBranch("V_pt") self.addBranch("V_eta") self.addBranch("V_phi") self.addBranch("V_mass") self.addBranch("V_mt") self.addBranch("MET_sig30") self.addBranch("MET_sig30puid") else: for UD in self._variations(syst): self.addBranch(self._v("V_mt", syst, UD)) self.addBranch(self._v("V_pt", syst, UD)) self.addBranch(self._v("V_eta", syst, UD)) self.addBranch(self._v("V_phi", syst, UD)) self.addBranch(self._v("V_mass", syst, UD)) if 'jerReg' not in syst: self.addBranch(self._v("MET_sig30", syst, UD)) self.addBranch(self._v("MET_sig30puid", syst, UD)) def processEvent(self, tree): if not self.hasBeenProcessed(tree): self.markProcessed(tree) self._b("selLeptonWln_pt")[0] = -99.0 self._b("selLeptonWln_eta")[0] = -99.0 self._b("selLeptonWln_phi")[0] = -99.0 self._b("selLeptonWln_mass")[0] = -99.0 for syst in self.allVariations: directions = [''] if syst.lower() == 'nominal' else [ 'Up', 'Down' ] for UD in self._variations(syst): if not self._isnominal(syst) or self.replaceNominal: self._b(self._v("V_mt", syst, UD))[0] = -1.0 if tree.Vtype == 0 or tree.Vtype == 1: lep1 = ROOT.TLorentzVector() lep2 = ROOT.TLorentzVector() i1 = tree.vLidx[0] i2 = tree.vLidx[1] if tree.Vtype == 1: lep1.SetPtEtaPhiM(tree.Electron_pt[i1], tree.Electron_eta[i1], tree.Electron_phi[i1], tree.Electron_mass[i1]) lep2.SetPtEtaPhiM(tree.Electron_pt[i2], tree.Electron_eta[i2], tree.Electron_phi[i2], tree.Electron_mass[i2]) else: lep1.SetPtEtaPhiM(tree.Muon_pt[i1], tree.Muon_eta[i1], tree.Muon_phi[i1], tree.Muon_mass[i1]) lep2.SetPtEtaPhiM(tree.Muon_pt[i2], tree.Muon_eta[i2], tree.Muon_phi[i2], tree.Muon_mass[i2]) V = lep1 + lep2 elif tree.Vtype == 2 or tree.Vtype == 3: i1 = tree.vLidx[0] if tree.Vtype == 3: sel_lepton_pt = tree.Electron_pt[i1] sel_lepton_eta = tree.Electron_eta[i1] sel_lepton_phi = tree.Electron_phi[i1] sel_lepton_mass = tree.Electron_mass[i1] else: sel_lepton_pt = tree.Muon_pt[i1] sel_lepton_eta = tree.Muon_eta[i1] sel_lepton_phi = tree.Muon_phi[i1] sel_lepton_mass = tree.Muon_mass[i1] MET = ROOT.TLorentzVector() Lep = ROOT.TLorentzVector() if syst.lower() == 'nominal' or 'jerReg' in syst: MET.SetPtEtaPhiM(tree.MET_Pt, 0.0, tree.MET_Phi, 0.0) else: MET.SetPtEtaPhiM( getattr( tree, "MET_pt_{syst}{UD}".format(syst=syst, UD=UD)), 0.0, getattr( tree, "MET_phi_{syst}{UD}".format(syst=syst, UD=UD)), 0.0) Lep.SetPtEtaPhiM(sel_lepton_pt, sel_lepton_eta, sel_lepton_phi, sel_lepton_mass) cosPhi12 = (Lep.Px() * MET.Px() + Lep.Py() * MET.Py()) / (Lep.Pt() * MET.Pt()) if not self._isnominal(syst) or self.replaceNominal: self._b(self._v( "V_mt", syst, UD))[0] = ROOT.TMath.Sqrt( 2 * Lep.Pt() * MET.Pt() * (1 - cosPhi12)) V = MET + Lep if self._isnominal(syst): self._b("selLeptonWln_pt")[0] = Lep.Pt() self._b("selLeptonWln_eta")[0] = Lep.Eta() self._b("selLeptonWln_phi")[0] = Lep.Phi() self._b("selLeptonWln_mass")[0] = Lep.M() elif tree.Vtype == 4: MET = ROOT.TLorentzVector() if syst.lower() == 'nominal': MET.SetPtEtaPhiM(tree.MET_Pt, 0.0, tree.MET_Phi, 0.0) else: MET.SetPtEtaPhiM( getattr( tree, "MET_pt_{syst}{UD}".format(syst=syst, UD=UD)), 0.0, getattr( tree, "MET_phi_{syst}{UD}".format(syst=syst, UD=UD)), 0.0) V = MET else: V = None if (not self._isnominal(syst)) or self.replaceNominal: self._b(self._v("V_pt", syst, UD))[0] = -1.0 self._b(self._v("V_eta", syst, UD))[0] = -1.0 self._b(self._v("V_phi", syst, UD))[0] = -1.0 self._b(self._v("V_mass", syst, UD))[0] = -1.0 if V is not None: if (not self._isnominal(syst)) or self.replaceNominal: self._b(self._v("V_pt", syst, UD))[0] = V.Pt() self._b(self._v("V_eta", syst, UD))[0] = V.Eta() self._b(self._v("V_phi", syst, UD))[0] = V.Phi() self._b(self._v("V_mass", syst, UD))[0] = V.M() # MET significance (approx.) if 'jerReg' not in syst: HTsum30 = 0 HTsum30puid = 0 if syst.lower() == 'nominal' or syst == 'unclustEn': jetPt = tree.Jet_Pt else: jetPt = getattr( tree, "Jet_pt_{syst}{UD}".format(syst=syst, UD=UD)) for i in range(tree.nJet): if jetPt[i] > 30 and tree.Jet_lepFilter[ i] > 0 and tree.Jet_jetId[ i] > self.jetIdCut: HTsum30 += jetPt[i] if tree.Jet_puId[i] > self.puIdCut or jetPt[ i] > 50.0: HTsum30puid += jetPt[i] if syst.lower() == 'nominal': metPt = tree.MET_Pt else: metPt = getattr( tree, "MET_pt_{syst}{UD}".format(syst=syst, UD=UD)) self._b(self._v("MET_sig30", syst, UD))[0] = ( metPt / np.sqrt(HTsum30)) if HTsum30 > 0 else -1.0 self._b(self._v("MET_sig30puid", syst, UD))[0] = ( metPt / np.sqrt(HTsum30puid)) if HTsum30puid > 0 else -1.0
class kinFitterXbb(AddCollectionsModule): def __init__(self, year, branchName="kinFit", useMZconstraint=True, recoilPtThreshold=20.0, jetIdCut=4, puIdCut=6, hJidx="hJidx"): super(kinFitterXbb, self).__init__() self.version = 4 self.branchName = branchName self.useMZconstraint = useMZconstraint self.debug = False self.enabled = True self.year = year self.jetIdCut = jetIdCut self.puIdCut = puIdCut self.HH4B_RES_SCALE = 0.62 self.LLVV_PXY_VAR = 8.0**2 self.Z_MASS = 91.0 self.Z_WIDTH = 1.7*3 self.recoilPtThreshold = recoilPtThreshold self.hJidx = hJidx self.systematics = None ROOT.gSystem.Load("../HelperClasses/KinFitter/TAbsFitConstraint_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TAbsFitParticle_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitConstraintEp_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitConstraintMGaus_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitConstraintM_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleCart_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleECart_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleEMomDev_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleEScaledMomDev_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleESpher_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleEtEtaPhi_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleEtThetaPhi_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleMCCart_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleMCMomDev_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleMCPInvSpher_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleMCSpher_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleMomDev_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TFitParticleSpher_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TKinFitter_cc.so") ROOT.gSystem.Load("../HelperClasses/KinFitter/TSLToyGen_cc.so") self.jetResolution = JMEres(year=self.year) def customInit(self, initVars): self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) if self.systematics is None: if not self.sample.isData(): jetSystematics= self.xbbConfig.getJECuncertainties(step='KinFit') self.systematics = [None] + [x+'_Up' for x in jetSystematics] + [x+'_Down' for x in jetSystematics] else: self.systematics = [None] print("INFO: computing the fit for", len(self.systematics), " variations.") self.bDict = {} for syst in self.systematics: self.bDict[syst] = {} for n in ['H_mass_fit', 'H_eta_fit', 'H_phi_fit', 'H_pt_fit', 'HVdPhi_fit', 'jjVPtRatio_fit', 'hJets_pt_0_fit', 'hJets_pt_1_fit', 'V_pt_fit', 'V_eta_fit', 'V_phi_fit', 'V_mass_fit', 'H_mass_sigma_fit','H_pt_sigma_fit', 'hJets_pt_0_sigma_fit', 'hJets_pt_1_sigma_fit', 'H_pt_corr_fit', 'llbb_pt_fit', 'llbb_eta_fit', 'llbb_phi_fit', 'llbb_mass_fit', 'llbbr_pt_fit', 'llbbr_eta_fit', 'llbbr_phi_fit', 'llbbr_mass_fit', 'H_mass_fit_noJetMass']: branchNameFull = self.branchName + "_" + n + ('_' + syst if not self._isnominal(syst) else '') self.bDict[syst][n] = branchNameFull self.addBranch(branchNameFull) for n in ['n_recoil_jets_fit', 'status']: branchNameFull = self.branchName + "_" + n + ('_' + syst if not self._isnominal(syst) else '') self.bDict[syst][n] = branchNameFull self.addIntegerBranch(branchNameFull) def enable(self): self.enabled = True def disable(self): self.enabled = False def cart_cov(self, v, rho): jme_res = self.jetResolution.eval(v.Eta(), rho, v.Pt()) * v.Pt() cos_phi = np.cos(v.Phi()) sin_phi = np.sin(v.Phi()) cov = ROOT.TMatrixD(4, 4) cov.Zero() cov[0][0] = (jme_res*cos_phi)**2 cov[1][0] = jme_res**2 * cos_phi * sin_phi cov[0][1] = cov[1][0] cov[1][1] = (jme_res*sin_phi)**2 return cov def getResolvedJetIndicesFromTree(self, tree, syst=None, UD=None): indexNameSyst = (self.hJidx + '_' + syst + UD) if not self._isnominal(syst) else self.hJidx if hasattr(tree, indexNameSyst): self.count('_debug_resolved_idx_syst_exists') return getattr(tree, indexNameSyst) else: print("\x1b[31mDOES NOT HAVE INDEX:", indexNameSyst,"\x1b[0m") self.count('_debug_resolved_idx_fallback_nom') self.count('_debug_resolved_idx_fallback_nom_for_'+str(syst)) return getattr(tree, self.hJidx) def getInputSystFormatFromOutputSyst(self, syst): if syst.endswith('_Up'): return syst[:-3] + 'Up' elif syst.endswith('_Down'): return syst[:-5] + 'Down' return syst def processEvent(self, tree): if not self.hasBeenProcessed(tree) and self.enabled: self.markProcessed(tree) phi = tree.Jet_phi eta = tree.Jet_eta vLidx = tree.vLidx for syst in self.systematics: if not self._isnominal(syst): if syst.endswith('Up'): variation = 'Up' systBase = syst[:-2].strip('_') elif syst.endswith('Down'): variation = 'Down' systBase = syst[:-4].strip('_') else: variation = None systBase = syst else: variation = None systBase = syst hJidx = self.getResolvedJetIndicesFromTree(tree, systBase, variation) if hJidx[0] > -1 and hJidx[1] > -1: # systematic up/down variation if not self._isnominal(syst): # vary regression if syst == 'jerReg_Up': pt = tree.Jet_Pt pt_reg = tree.Jet_PtRegUp mass = tree.Jet_mass_nom elif syst == 'jerReg_Down': pt = tree.Jet_Pt pt_reg = tree.Jet_PtRegDown mass = tree.Jet_mass_nom elif syst == 'jerRegScale_Down': pt = tree.Jet_Pt pt_reg = tree.Jet_PtRegScaleDown mass = tree.Jet_mass_nom elif syst == 'jerRegScale_Up': pt = tree.Jet_Pt pt_reg = tree.Jet_PtRegScaleUp mass = tree.Jet_mass_nom elif syst == 'jerRegSmear_Down': pt = tree.Jet_Pt pt_reg = tree.Jet_PtRegSmearDown mass = tree.Jet_mass_nom elif syst == 'jerRegSmear_Up': pt = tree.Jet_Pt pt_reg = tree.Jet_PtRegSmearUp mass = tree.Jet_mass_nom # vary JEC else: pt = getattr(tree, 'Jet_pt_' + self.getInputSystFormatFromOutputSyst(syst)) # propagate JEC to regressed pt pt_reg = [tree.Jet_PtReg[i] * getattr(tree, 'Jet_pt_' + self.getInputSystFormatFromOutputSyst(syst))[i] / tree.Jet_Pt[i] for i in range(len(tree.Jet_PtReg))] mass = getattr(tree, 'Jet_mass_' + self.getInputSystFormatFromOutputSyst(syst)) # nominal else: pt = tree.Jet_Pt pt_reg = tree.Jet_PtReg if self.sample.isMC(): mass = tree.Jet_mass_nom else: mass = tree.Jet_mass # higgs jets j1 = fourvector(pt_reg[hJidx[0]], eta[hJidx[0]], phi[hJidx[0]], mass[hJidx[0]] * tree.Jet_PtReg[hJidx[0]]/tree.Jet_Pt[hJidx[0]]) j2 = fourvector(pt_reg[hJidx[1]], eta[hJidx[1]], phi[hJidx[1]], mass[hJidx[1]] * tree.Jet_PtReg[hJidx[1]]/tree.Jet_Pt[hJidx[1]]) # FSR jets fsrJets = [] fsrJidx = [] for i in range(tree.nJet): if i not in hJidx and tree.Jet_lepFilter[i] > 0 and (tree.Jet_puId[i] > self.puIdCut or tree.Jet_Pt[i] > 50) and tree.Jet_jetId[i] > self.jetIdCut and pt[i] > 20 and abs(eta[i]) < 3.0: j_fsr = fourvector(pt[i], eta[i], phi[i], mass[i]) delta_r1 = j_fsr.DeltaR(j1) delta_r2 = j_fsr.DeltaR(j2) if min(delta_r1, delta_r2) < 0.8: fsrJets.append(j_fsr) fsrJidx.append(i) #if delta_r1 < delta_r2: # j1 += j_fsr #else: # j2 += j_fsr fit_j1 = fit_jet(j1, self.HH4B_RES_SCALE) fit_j2 = fit_jet(j2, self.HH4B_RES_SCALE) fit_jets = [fit_j1, fit_j2] + [fit_jet(fsrJet, self.HH4B_RES_SCALE) for fsrJet in fsrJets] # recoil jets recoil_jets = [] for i in range(tree.nJet): if i not in hJidx and i not in fsrJidx and (tree.Jet_puId[i] > self.puIdCut or tree.Jet_Pt[i] > 50) and tree.Jet_jetId[i] > self.jetIdCut and tree.Jet_lepFilter[i] > 0 and pt[i] > self.recoilPtThreshold: recoil_jets.append(fourvector(pt[i], eta[i], phi[i], mass[i])) recoil_sum = sum(recoil_jets, ROOT.TLorentzVector()) cov_recoil = ROOT.TMatrixD(4, 4) cov_recoil.Zero() cov_recoil[0][0] = self.LLVV_PXY_VAR cov_recoil[1][1] = self.LLVV_PXY_VAR cov_recoil[2][2] = 1 cov_recoil[3][3] = 1e12 for j in recoil_jets: cov_recoil += self.cart_cov(j, tree.fixedGridRhoFastjetAll) fit_recoil = ROOT.TFitParticleECart(recoil_sum, cov_recoil) #leptons if tree.Vtype == 0: fit_l1 = fit_lepton(fourvector(abs(tree.Muon_corrected_pt[vLidx[0]]), tree.Muon_eta[vLidx[0]], tree.Muon_phi[vLidx[0]], tree.Muon_mass[vLidx[0]]), tree.Muon_ptErr[vLidx[0]]) fit_l2 = fit_lepton(fourvector(abs(tree.Muon_corrected_pt[vLidx[1]]), tree.Muon_eta[vLidx[1]], tree.Muon_phi[vLidx[1]], tree.Muon_mass[vLidx[1]]), tree.Muon_ptErr[vLidx[1]]) else: fit_l1 = fit_lepton(fourvector(abs(tree.Electron_pt[vLidx[0]]), tree.Electron_eta[vLidx[0]], tree.Electron_phi[vLidx[0]], tree.Electron_mass[vLidx[0]]), tree.Electron_energyErr[vLidx[0]]) fit_l2 = fit_lepton(fourvector(abs(tree.Electron_pt[vLidx[1]]), tree.Electron_eta[vLidx[1]], tree.Electron_phi[vLidx[1]], tree.Electron_mass[vLidx[1]]), tree.Electron_energyErr[vLidx[1]]) # constraints cons_MZ = ROOT.TFitConstraintMGaus('cons_MZ', '', None, None, self.Z_MASS, self.Z_WIDTH) cons_MZ.addParticle1(fit_l1) cons_MZ.addParticle1(fit_l2) # fit particles #fit_particles = fit_jets + [fit_l1, fit_l2] + [fit_recoil] cons_x = ROOT.TFitConstraintEp('cons_x', '', ROOT.TFitConstraintEp.pX) cons_x.addParticles(*fit_jets) cons_x.addParticles(fit_l1, fit_l2) cons_x.addParticles(fit_recoil) cons_y = ROOT.TFitConstraintEp('cons_y', '', ROOT.TFitConstraintEp.pY) cons_y.addParticles(*fit_jets) cons_y.addParticles(fit_l1, fit_l2) cons_y.addParticles(fit_recoil) # setup fitter fitter = ROOT.TKinFitter() fitter.addMeasParticles(*fit_jets) fitter.addMeasParticles(fit_l1, fit_l2) fitter.addMeasParticles(fit_recoil) if self.useMZconstraint: fitter.addConstraint(cons_MZ) fitter.addConstraint(cons_x) fitter.addConstraint(cons_y) fitter.setMaxNbIter(30) fitter.setMaxDeltaS(1e-2) fitter.setMaxF(1e-1) fitter.setVerbosity(0) # run the fit kinfit_fit = fitter.fit() + 1 # 0: not run; 1: fit converged; 2: fit didn't converge kinfit_getNDF = fitter.getNDF() kinfit_getS = fitter.getS() kinfit_getF = fitter.getF() #print("-"*10, kinfit_fit, kinfit_getNDF, kinfit_getS, kinfit_getF) # higgs jet output vectors fit_result_j1 = fitter.get4Vec(0) fit_result_j2 = fitter.get4Vec(1) fit_result_H_noJetMass = fit_result_j1 + fit_result_j2 for iFsr in range(len(fit_jets)-2): fit_result_H_noJetMass += fitter.get4Vec(2+iFsr) # add back jet masses fit_result_j1.SetPtEtaPhiM(fit_result_j1.Pt(),fit_result_j1.Eta(),fit_result_j1.Phi(), mass[hJidx[0]] * tree.Jet_PtReg[hJidx[0]]/tree.Jet_Pt[hJidx[0]]) fit_result_j2.SetPtEtaPhiM(fit_result_j2.Pt(),fit_result_j2.Eta(),fit_result_j2.Phi(), mass[hJidx[1]] * tree.Jet_PtReg[hJidx[1]]/tree.Jet_Pt[hJidx[1]]) fit_result_H = fit_result_j1 + fit_result_j2 for iFsr in range(len(fit_jets)-2): j_fsr = fitter.get4Vec(2+iFsr) j_fsr.SetPtEtaPhiM(j_fsr.Pt(),j_fsr.Eta(),j_fsr.Phi(), mass[fsrJidx[iFsr]]) fit_result_H += j_fsr nFitJets = len(fit_jets) fit_result_l1 = fitter.get4Vec(nFitJets) fit_result_l2 = fitter.get4Vec(nFitJets+1) fit_result_V = fit_result_l1 + fit_result_l2 # H + V (+ recoil) llbb = fit_result_H + fit_result_V llbbr = llbb + fitter.get4Vec(nFitJets+2) self._b(self.bDict[syst]['status'])[0] = kinfit_fit if kinfit_fit == 1 and fit_result_H.M() > 0: self.count("kinfit_success") self._b(self.bDict[syst]['H_pt_fit'])[0] = fit_result_H.Pt() self._b(self.bDict[syst]['H_eta_fit'])[0] = fit_result_H.Eta() self._b(self.bDict[syst]['H_phi_fit'])[0] = fit_result_H.Phi() self._b(self.bDict[syst]['H_mass_fit'])[0] = fit_result_H.M() self._b(self.bDict[syst]['H_mass_fit_noJetMass'])[0] = fit_result_H_noJetMass.M() self._b(self.bDict[syst]['V_pt_fit'])[0] = fit_result_V.Pt() self._b(self.bDict[syst]['V_eta_fit'])[0] = fit_result_V.Eta() self._b(self.bDict[syst]['V_phi_fit'])[0] = fit_result_V.Phi() self._b(self.bDict[syst]['V_mass_fit'])[0] = fit_result_V.M() self._b(self.bDict[syst]['HVdPhi_fit'])[0] = abs(ROOT.TVector2.Phi_mpi_pi(fit_result_H.Phi() - fit_result_V.Phi())) self._b(self.bDict[syst]['jjVPtRatio_fit'])[0] = fit_result_H.Pt()/fit_result_V.Pt() self._b(self.bDict[syst]['hJets_pt_0_fit'])[0] = fit_result_j1.Pt() self._b(self.bDict[syst]['hJets_pt_1_fit'])[0] = fit_result_j2.Pt() self._b(self.bDict[syst]['n_recoil_jets_fit'])[0] = len(recoil_jets) # higgs mass uncertainty cov_fit = fitter.getCovMatrixFit() dmH_by_dpt1 = ( (fit_result_H.X())*np.cos(fit_result_j1.Phi()) + (fit_result_H.Y())*np.sin(fit_result_j1.Phi()) )/fit_result_H.M() dmH_by_dpt2 = ( (fit_result_H.X())*np.cos(fit_result_j2.Phi()) + (fit_result_H.Y())*np.sin(fit_result_j2.Phi()) )/fit_result_H.M() self._b(self.bDict[syst]['H_mass_sigma_fit'])[0] = ( dmH_by_dpt1**2 * cov_fit(0,0) + dmH_by_dpt2**2 * cov_fit(3,3) + dmH_by_dpt1*dmH_by_dpt2 * cov_fit(0,3) )**.5 # Higgs pT uncertainty self._b(self.bDict[syst]['hJets_pt_0_sigma_fit'])[0] = cov_fit(0,0)**0.5 self._b(self.bDict[syst]['hJets_pt_1_sigma_fit'])[0] = cov_fit(3,3)**0.5 self._b(self.bDict[syst]['H_pt_corr_fit'])[0] = cov_fit(0,3) / ( (cov_fit(0,0)*cov_fit(3,3))**0.5 ) self._b(self.bDict[syst]['H_pt_sigma_fit'])[0] = (cov_fit(0,0) + cov_fit(3,3) + 2.0*cov_fit(0,3) )**0.5 self._b(self.bDict[syst]['llbb_pt_fit'])[0] = llbb.Pt() self._b(self.bDict[syst]['llbb_phi_fit'])[0] = llbb.Phi() self._b(self.bDict[syst]['llbb_eta_fit'])[0] = llbb.Eta() self._b(self.bDict[syst]['llbb_mass_fit'])[0] = llbb.M() self._b(self.bDict[syst]['llbbr_pt_fit'])[0] = llbbr.Pt() self._b(self.bDict[syst]['llbbr_phi_fit'])[0] = llbbr.Phi() self._b(self.bDict[syst]['llbbr_eta_fit'])[0] = llbbr.Eta() self._b(self.bDict[syst]['llbbr_mass_fit'])[0] = llbbr.M() else: if fit_result_H.M() <= 0: self.count("kinfit_failure_mass_negative") else: self.count("kinfit_failure_convergence") # fallback self._b(self.bDict[syst]['H_pt_fit'])[0] = tree.H_pt self._b(self.bDict[syst]['H_eta_fit'])[0] = tree.H_eta self._b(self.bDict[syst]['H_phi_fit'])[0] = tree.H_phi self._b(self.bDict[syst]['H_mass_fit'])[0] = tree.H_mass self._b(self.bDict[syst]['H_mass_fit_noJetMass'])[0] = tree.H_mass self._b(self.bDict[syst]['V_pt_fit'])[0] = tree.V_pt self._b(self.bDict[syst]['V_eta_fit'])[0] = tree.V_eta self._b(self.bDict[syst]['V_phi_fit'])[0] = tree.V_phi self._b(self.bDict[syst]['V_mass_fit'])[0] = tree.V_mass self._b(self.bDict[syst]['HVdPhi_fit'])[0] = abs(ROOT.TVector2.Phi_mpi_pi(tree.H_phi - tree.V_phi)) self._b(self.bDict[syst]['jjVPtRatio_fit'])[0] = tree.H_pt/tree.V_pt self._b(self.bDict[syst]['hJets_pt_0_fit'])[0] = pt_reg[hJidx[0]] self._b(self.bDict[syst]['hJets_pt_1_fit'])[0] = pt_reg[hJidx[1]] self._b(self.bDict[syst]['n_recoil_jets_fit'])[0] = -1 self._b(self.bDict[syst]['H_mass_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['hJets_pt_0_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['hJets_pt_1_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['H_pt_corr_fit'])[0] = -1 self._b(self.bDict[syst]['H_pt_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['llbb_pt_fit'])[0] = -99 self._b(self.bDict[syst]['llbb_phi_fit'])[0] = -99 self._b(self.bDict[syst]['llbb_eta_fit'])[0] = -99 self._b(self.bDict[syst]['llbb_mass_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_pt_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_phi_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_eta_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_mass_fit'])[0] = -99 else: # no two resolved jets self._b(self.bDict[syst]['H_pt_fit'])[0] = -1 self._b(self.bDict[syst]['H_eta_fit'])[0] = -1 self._b(self.bDict[syst]['H_phi_fit'])[0] = -1 self._b(self.bDict[syst]['H_mass_fit'])[0] = -1 self._b(self.bDict[syst]['H_mass_fit_noJetMass'])[0] = -1 self._b(self.bDict[syst]['V_pt_fit'])[0] = -1 self._b(self.bDict[syst]['V_eta_fit'])[0] = -1 self._b(self.bDict[syst]['V_phi_fit'])[0] = -1 self._b(self.bDict[syst]['V_mass_fit'])[0] = -1 self._b(self.bDict[syst]['HVdPhi_fit'])[0] = -1 self._b(self.bDict[syst]['jjVPtRatio_fit'])[0] = -1 self._b(self.bDict[syst]['hJets_pt_0_fit'])[0] = -1 self._b(self.bDict[syst]['hJets_pt_1_fit'])[0] = -1 self._b(self.bDict[syst]['n_recoil_jets_fit'])[0] = -1 self._b(self.bDict[syst]['H_mass_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['hJets_pt_0_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['hJets_pt_1_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['H_pt_corr_fit'])[0] = -1 self._b(self.bDict[syst]['H_pt_sigma_fit'])[0] = -1 self._b(self.bDict[syst]['llbb_pt_fit'])[0] = -99 self._b(self.bDict[syst]['llbb_phi_fit'])[0] = -99 self._b(self.bDict[syst]['llbb_eta_fit'])[0] = -99 self._b(self.bDict[syst]['llbb_mass_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_pt_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_phi_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_eta_fit'])[0] = -99 self._b(self.bDict[syst]['llbbr_mass_fit'])[0] = -99
def customInit(self, initVars): self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.jetSystematicsResolved = self.xbbConfig.getJECuncertainties( step='Higgs') self.jetSystematics = self.jetSystematicsResolved[:] # corrected dijet (Higgs candidate) properties self.higgsProperties = [ self.prefix + '_' + x for x in [ 'pt', 'eta', 'phi', 'mass', 'pt_noFSR', 'eta_noFSR', 'phi_noFSR', 'mass_noFSR' ] ] # included JEC and JER systematic for msoftdrop if self.addBoostSystematics: self.higgsProperties += ['FatJet_msoftdrop_sys', 'FatJet_pt_sys'] #self.higgsProperties +=['FatJet_msoftdrop_sys'] # adding mass scale and resolution systematics self.rnd = ROOT.TRandom3(12345) self.dataset = self.config.get('General', 'dataset') if self.dataset == '2016': self.jetIdCut = 2 else: self.jetIdCut = 4 # if self.addBoostSystematics: # self.boosttagidx = 'Hbb_fjidx' # self.msoftdrop = 'FatJet_msoftdrop' # if self.sample.type != 'DATA': # self.FatJet_pt= 'FatJet_pt_nom' # else: # self.FatJet_pt= 'FatJet_pt' # # get all the info for scale and smearing # self.Snom = eval(self.config.get('Sys', 'Snom')) # self.Sdown = eval(self.config.get('Sys', 'Sdown')) # self.Sup = eval(self.config.get('Sys', 'Sup')) # self.Rnom = eval(self.config.get('Sys', 'Rnom')) # self.Rdown = eval(self.config.get('Sys', 'Rdown')) # self.Rup = eval(self.config.get('Sys', 'Rup')) # # #Load .root file with resolution. # self.jetSystematics+= ['jms'] # self.jetSystematics+= ['jmr'] # self.config = initVars['config'] # wdir = self.config.get('Directories', 'vhbbpath') # filejmr = ROOT.TFile.Open(wdir+"/python/data/softdrop/puppiSoftdropResol.root","READ") # self.puppisd_resolution_cen = filejmr.Get("massResolution_0eta1v3") # self.puppisd_resolution_for = filejmr.Get("massResolution_1v3eta2v5") # # ## adding jms and jmr to FatJet pt # for syst in ['_jmr','_jms']: # for p in ['Jet_pt', 'Jet_mass']: # for q in ['Up', 'Down']: # print 'name is',p+syst+q # self.branchBuffers[p+syst+q] = array.array('f', [0.0]*self.nJetMax) # self.branches.append({'name': p+syst+q, 'formula': self.getVectorBranch, 'arguments': {'branch': p+syst+q}, 'length': self.nJetMax, 'leaflist': p+syst+q+'[nJet]/F'}) # # # they will be filled with the nominal... # for syst in ['jmr','jms','jerReg']: # for Q in ['Up', 'Down']: # self.addBranch('MET_pt_{s}{d}'.format(s=syst, d=Q)) # self.addBranch('MET_phi_{s}{d}'.format(s=syst, d=Q)) self.tagidx = self.config.get('General', 'hJidx') if self.debug: print "DEBUG: HiggsCandidateSystematics::__init__(), with idx=", self.tagidx, " prefix=", self.prefix # nominal + systematic variations self.systematicsResolved = [None] if self.sample.isMC(): self.systematicsResolved += self.jetSystematicsResolved # dijet H candidate branches for higgsProperty in self.higgsProperties: for syst in self.systematicsResolved: for Q in self._variations(syst): self.addBranch(self._v(higgsProperty, syst, Q)) self.addBranch('H_noReg_pt') self.addBranch('H_noReg_eta') self.addBranch('H_noReg_phi') self.addBranch('H_noReg_mass') # additional jet branches fBranches = [ 'hJets_0_pt_noFSR', 'hJets_1_pt_noFSR', 'hJets_0_pt_FSRrecovered', 'hJets_1_pt_FSRrecovered', 'hJets_FSRrecovered_dEta', 'hJets_FSRrecovered_dPhi' ] for syst in self.systematicsResolved: for Q in self._variations(syst): for branchName in fBranches: self.addBranch(self._v(branchName, syst, Q)) self.addIntegerBranch(self._v('nFSRrecovered', syst, Q))
class HiggsCandidateSystematics(AddCollectionsModule): def __init__(self, addSystematics=True, prefix="H", addBoostSystematics=False, addMinMax=False, puIdCut=6, jetIdCut=4): super(HiggsCandidateSystematics, self).__init__() self.version = 1 self.debug = 'XBBDEBUG' in os.environ self.nJet = -1 self.nJetMax = 100 self.addSystematics = addSystematics self.addMinMax = addMinMax self.prefix = prefix self.addBoostSystematics = addBoostSystematics self.puIdCut = puIdCut self.jetIdCut = jetIdCut def customInit(self, initVars): self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.jetSystematicsResolved = self.xbbConfig.getJECuncertainties( step='Higgs') self.jetSystematics = self.jetSystematicsResolved[:] # corrected dijet (Higgs candidate) properties self.higgsProperties = [ self.prefix + '_' + x for x in [ 'pt', 'eta', 'phi', 'mass', 'pt_noFSR', 'eta_noFSR', 'phi_noFSR', 'mass_noFSR' ] ] # included JEC and JER systematic for msoftdrop if self.addBoostSystematics: self.higgsProperties += ['FatJet_msoftdrop_sys', 'FatJet_pt_sys'] #self.higgsProperties +=['FatJet_msoftdrop_sys'] # adding mass scale and resolution systematics self.rnd = ROOT.TRandom3(12345) self.dataset = self.config.get('General', 'dataset') if self.dataset == '2016': self.jetIdCut = 2 else: self.jetIdCut = 4 # if self.addBoostSystematics: # self.boosttagidx = 'Hbb_fjidx' # self.msoftdrop = 'FatJet_msoftdrop' # if self.sample.type != 'DATA': # self.FatJet_pt= 'FatJet_pt_nom' # else: # self.FatJet_pt= 'FatJet_pt' # # get all the info for scale and smearing # self.Snom = eval(self.config.get('Sys', 'Snom')) # self.Sdown = eval(self.config.get('Sys', 'Sdown')) # self.Sup = eval(self.config.get('Sys', 'Sup')) # self.Rnom = eval(self.config.get('Sys', 'Rnom')) # self.Rdown = eval(self.config.get('Sys', 'Rdown')) # self.Rup = eval(self.config.get('Sys', 'Rup')) # # #Load .root file with resolution. # self.jetSystematics+= ['jms'] # self.jetSystematics+= ['jmr'] # self.config = initVars['config'] # wdir = self.config.get('Directories', 'vhbbpath') # filejmr = ROOT.TFile.Open(wdir+"/python/data/softdrop/puppiSoftdropResol.root","READ") # self.puppisd_resolution_cen = filejmr.Get("massResolution_0eta1v3") # self.puppisd_resolution_for = filejmr.Get("massResolution_1v3eta2v5") # # ## adding jms and jmr to FatJet pt # for syst in ['_jmr','_jms']: # for p in ['Jet_pt', 'Jet_mass']: # for q in ['Up', 'Down']: # print 'name is',p+syst+q # self.branchBuffers[p+syst+q] = array.array('f', [0.0]*self.nJetMax) # self.branches.append({'name': p+syst+q, 'formula': self.getVectorBranch, 'arguments': {'branch': p+syst+q}, 'length': self.nJetMax, 'leaflist': p+syst+q+'[nJet]/F'}) # # # they will be filled with the nominal... # for syst in ['jmr','jms','jerReg']: # for Q in ['Up', 'Down']: # self.addBranch('MET_pt_{s}{d}'.format(s=syst, d=Q)) # self.addBranch('MET_phi_{s}{d}'.format(s=syst, d=Q)) self.tagidx = self.config.get('General', 'hJidx') if self.debug: print "DEBUG: HiggsCandidateSystematics::__init__(), with idx=", self.tagidx, " prefix=", self.prefix # nominal + systematic variations self.systematicsResolved = [None] if self.sample.isMC(): self.systematicsResolved += self.jetSystematicsResolved # dijet H candidate branches for higgsProperty in self.higgsProperties: for syst in self.systematicsResolved: for Q in self._variations(syst): self.addBranch(self._v(higgsProperty, syst, Q)) self.addBranch('H_noReg_pt') self.addBranch('H_noReg_eta') self.addBranch('H_noReg_phi') self.addBranch('H_noReg_mass') # additional jet branches fBranches = [ 'hJets_0_pt_noFSR', 'hJets_1_pt_noFSR', 'hJets_0_pt_FSRrecovered', 'hJets_1_pt_FSRrecovered', 'hJets_FSRrecovered_dEta', 'hJets_FSRrecovered_dPhi' ] for syst in self.systematicsResolved: for Q in self._variations(syst): for branchName in fBranches: self.addBranch(self._v(branchName, syst, Q)) self.addIntegerBranch(self._v('nFSRrecovered', syst, Q)) # read from buffers which have been filled in processEvent() def getVectorBranch(self, event, arguments=None, destinationArray=None): self.processEvent(event) length = min(self.nJet, self.nJetMax) destinationArray[:length] = self.branchBuffers[ arguments['branch']][:length] def getResolvedJetIndicesFromTree(self, tree, syst=None, UD=None): indexNameSyst = (self.tagidx + '_' + syst + UD) if not self._isnominal(syst) else self.tagidx if hasattr(tree, indexNameSyst): self.count('_debug_resolved_idx_syst_exists') return getattr(tree, indexNameSyst) else: self.count('_debug_resolved_idx_fallback_nom') return getattr(tree, self.tagidx) def processEvent(self, tree): # if current entry has not been processed yet if not self.hasBeenProcessed(tree): self.markProcessed(tree) # ---------------------------------------------------------------------------------------------------- # RESOLVED # ---------------------------------------------------------------------------------------------------- # select branches from tree # for 2016 nano >= v5 needed! Jet_PtReg_nom = tree.Jet_PtReg Jet_pt_nom = tree.Jet_Pt Jet_phi = tree.Jet_phi Jet_eta = tree.Jet_eta Jet_puId = tree.Jet_puId Jet_jetId = tree.Jet_jetId Jet_lepFilter = tree.Jet_lepFilter nJet = tree.nJet # alias for jet mass if self.sample.isMC(): Jet_mass_nom = tree.Jet_mass_nom else: Jet_mass_nom = tree.Jet_mass for syst in self.systematicsResolved: for Q in self._variations(syst): hJ0 = ROOT.TLorentzVector() hJ1 = ROOT.TLorentzVector() # check if there are TWO resolved jets hJidx0, hJidx1 = self.getResolvedJetIndicesFromTree( tree, syst, Q) if hJidx0 > -1 and hJidx1 > -1: # Pt, Mass: with JEC, JER # PtReg, MassReg: with JEC, JER, regression+smearing if self._isnominal(syst): Jet_Pt = Jet_pt_nom Jet_PtReg = Jet_PtReg_nom Jet_Mass = Jet_mass_nom Jet_MassReg = [ Jet_Mass[i] * Jet_PtReg_nom[i] / Jet_pt_nom[i] for i in range(nJet) ] elif 'jerReg' in syst: Jet_Pt = Jet_pt_nom Jet_PtReg = getattr(tree, 'Jet_Pt' + syst[3:] + Q) Jet_Mass = Jet_mass_nom Jet_MassReg = [ Jet_Mass[i] * Jet_PtReg[i] / Jet_pt_nom[i] for i in range(nJet) ] else: Jet_Pt = getattr( tree, 'Jet_pt_{s}{d}'.format(s=syst, d=Q)) Jet_PtReg = [ Jet_Pt[i] * Jet_PtReg_nom[i] / Jet_pt_nom[i] for i in range(nJet) ] Jet_Mass = getattr( tree, 'Jet_mass_{s}{d}'.format(s=syst, d=Q)) Jet_MassReg = [ Jet_Mass[i] * Jet_PtReg_nom[i] / Jet_pt_nom[i] for i in range(nJet) ] # b-jet regression is applied to H candidate jets hJ0.SetPtEtaPhiM(Jet_PtReg[hJidx0], Jet_eta[hJidx0], Jet_phi[hJidx0], Jet_MassReg[hJidx0]) hJ1.SetPtEtaPhiM(Jet_PtReg[hJidx1], Jet_eta[hJidx1], Jet_phi[hJidx1], Jet_MassReg[hJidx1]) self._b(self._v('hJets_0_pt_noFSR', syst, Q))[0] = hJ0.Pt() self._b(self._v('hJets_1_pt_noFSR', syst, Q))[0] = hJ1.Pt() dijet_noFSR = hJ0 + hJ1 self._b(self._v(self.prefix + '_pt_noFSR', syst, Q))[0] = dijet_noFSR.Pt() self._b(self._v(self.prefix + '_eta_noFSR', syst, Q))[0] = dijet_noFSR.Eta() self._b(self._v(self.prefix + '_phi_noFSR', syst, Q))[0] = dijet_noFSR.Phi() self._b(self._v(self.prefix + '_mass_noFSR', syst, Q))[0] = dijet_noFSR.M() # save information which FSR jets have been added fsrIndices0 = [] fsrIndices1 = [] # FSR recovery for i in range(nJet): if i not in [hJidx0, hJidx1]: if Jet_Pt[i] > 20.0 and abs( Jet_eta[i] ) < 3.0 and ( Jet_puId[i] > self.puIdCut or Jet_Pt[i] > 50.0 ) and Jet_lepFilter[i] > 0 and Jet_jetId[ i] > self.jetIdCut: # b-jet regression is not applied to FSR jets FSR = ROOT.TLorentzVector() FSR.SetPtEtaPhiM(Jet_Pt[i], Jet_eta[i], Jet_phi[i], Jet_Mass[i]) deltaR0 = FSR.DeltaR(hJ0) deltaR1 = FSR.DeltaR(hJ1) if min(deltaR0, deltaR1) < 0.8: if deltaR0 < deltaR1: hJ0 = hJ0 + FSR fsrIndices0.append(i) else: hJ1 = hJ1 + FSR fsrIndices1.append(i) # H with FSR recovery dijet = hJ0 + hJ1 self._b(self._v(self.prefix + '_pt', syst, Q))[0] = dijet.Pt() self._b(self._v(self.prefix + '_eta', syst, Q))[0] = dijet.Eta() self._b(self._v(self.prefix + '_phi', syst, Q))[0] = dijet.Phi() self._b(self._v(self.prefix + '_mass', syst, Q))[0] = dijet.M() # write additional jet quantities after FSR recovery self._b(self._v('hJets_0_pt_FSRrecovered', syst, Q))[0] = hJ0.Pt() self._b(self._v('hJets_1_pt_FSRrecovered', syst, Q))[0] = hJ1.Pt() self._b(self._v('hJets_FSRrecovered_dEta', syst, Q))[0] = abs(hJ0.Eta() - hJ1.Eta()) self._b(self._v('hJets_FSRrecovered_dPhi', syst, Q))[0] = abs(hJ0.DeltaPhi(hJ1)) self._b(self._v( 'nFSRrecovered', syst, Q))[0] = len(fsrIndices0) + len(fsrIndices1) # for nominal, add pT without regression if self._isnominal(syst): hJ0.SetPtEtaPhiM(Jet_Pt[hJidx0], Jet_eta[hJidx0], Jet_phi[hJidx0], Jet_Mass[hJidx0]) hJ1.SetPtEtaPhiM(Jet_Pt[hJidx1], Jet_eta[hJidx1], Jet_phi[hJidx1], Jet_Mass[hJidx1]) # FSR recovery for i in range(nJet): if i not in [hJidx0, hJidx1]: if Jet_Pt[i] > 20.0 and abs( Jet_eta[i] ) < 3.0 and ( Jet_puId[i] > self.puIdCut or Jet_Pt[i] > 50.0 ) and Jet_lepFilter[i] > 0 and Jet_jetId[ i] > self.jetIdCut: # b-jet regression is not applied to FSR jets FSR = ROOT.TLorentzVector() FSR.SetPtEtaPhiM( Jet_Pt[i], Jet_eta[i], Jet_phi[i], Jet_Mass[i]) deltaR0 = FSR.DeltaR(hJ0) deltaR1 = FSR.DeltaR(hJ1) if min(deltaR0, deltaR1) < 0.8: if deltaR0 < deltaR1: hJ0 = hJ0 + FSR else: hJ1 = hJ1 + FSR dijet = hJ0 + hJ1 self._b('H_noReg_pt')[0] = dijet.Pt() self._b('H_noReg_eta')[0] = dijet.Eta() self._b('H_noReg_phi')[0] = dijet.Phi() self._b('H_noReg_mass')[0] = dijet.M() # jmr/jms taken from post-processor # # ---------------------------------------------------------------------------------------------------- # # BOOSTED # # ---------------------------------------------------------------------------------------------------- # # if self.addBoostSystematics: # boosttagidx = getattr(tree, self.boosttagidx) # if boosttagidx > -1: # FatJet_pt = getattr(tree, self.FatJet_pt)[boosttagidx] # msoftdrop = getattr(tree, self.msoftdrop)[boosttagidx] # self._b('FatJet_msoftdrop_sys')[0] = msoftdrop # self._b('FatJet_pt_sys')[0] = FatJet_pt # #print FatJet_pt # #print msoftdrop # #import sys # #sys.exit() # # # systematics # valueList = {x:[self.branchBuffers[x][0]] for x in self.higgsProperties} # if self.addSystematics and self.sample.type != 'DATA': # for syst in self.jetSystematics: # for Q in ['Up', 'Down']: # if self.sample.type != 'DATA': # # included JEC and JER systematic for msoftdrop # if self.addBoostSystematics and boosttagidx > -1: # if syst == 'jmr' or syst == 'jms': # pass # else: # msoftdrop_sys = msoftdrop*getattr(tree, 'FatJet_pt_{s}{d}'.format(s=syst, d=Q))[boosttagidx]/getattr(tree, 'FatJet_pt_nom')[boosttagidx] # FatJet_pt_sys = getattr(tree, 'FatJet_pt_{s}{d}'.format(s=syst, d=Q))[boosttagidx] # if tree.Hbb_fjidx > -1: # if syst == 'jmr': # self.jmr_sys = self.get_msoftdrop_smear(tree.FatJet_pt[tree.Hbb_fjidx], tree.FatJet_eta[tree.Hbb_fjidx]) # elif syst == 'jms': # pass # # if self.addBoostSystematics and boosttagidx > -1: # #print FatJet_pt # #import sys # #sys.exit() # if syst == 'jmr': # if Q == 'Up': # self.branchBuffers['FatJet_msoftdrop_sys_jmr_Down'][0] = msoftdrop*self.jmr_sys[0] # valueList['FatJet_msoftdrop_sys'].append(msoftdrop*self.jmr_sys[0]) # # # no sys variation on pT (put nominal value) # self.branchBuffers['FatJet_pt_sys_jmr_Down'][0] = FatJet_pt # valueList['FatJet_pt_sys'].append(FatJet_pt) # elif Q == 'Down': # self.branchBuffers['FatJet_msoftdrop_sys_jmr_Up'][0] = msoftdrop*self.jmr_sys[1] # valueList['FatJet_msoftdrop_sys'].append(msoftdrop*self.jmr_sys[1]) # # # no sys variation on pT (put nominal value) # self.branchBuffers['FatJet_pt_sys_jmr_Up'][0] = FatJet_pt # valueList['FatJet_pt_sys'].append(FatJet_pt) # elif syst == 'jms': # if Q == 'Up': # self.branchBuffers['FatJet_msoftdrop_sys_jms_Up'][0] = msoftdrop*self.Sup # valueList['FatJet_msoftdrop_sys'].append(msoftdrop*self.Sup) # # # no sys variation on pT (put nominal value) # self.branchBuffers['FatJet_pt_sys_jms_Up'][0] = FatJet_pt # valueList['FatJet_pt_sys'].append(FatJet_pt) # elif Q == 'Down': # self.branchBuffers['FatJet_msoftdrop_sys_jms_Down'][0] = msoftdrop*self.Sdown # valueList['FatJet_msoftdrop_sys'].append(msoftdrop*self.Sdown) # # # no sys variation on pT (put nominal value) # self.branchBuffers['FatJet_pt_sys_jms_Down'][0] = FatJet_pt # valueList['FatJet_pt_sys'].append(FatJet_pt) # else: # self.branchBuffers['FatJet_msoftdrop_sys_{s}_{d}'.format(s=syst, d=Q)][0] = msoftdrop_sys # valueList['FatJet_msoftdrop_sys'].append(msoftdrop_sys) # # ##valueList['FatJet_pt_sys'].append(getattr(tree,'FatJet_pt_{s}{d}'.format(s=syst, d=Q))[boosttagidx]) # #print 'FatJet_pt_sys', FatJet_pt_sys # #import sys # #sys.exit() # self.branchBuffers['FatJet_pt_sys_{s}_{d}'.format(s=syst, d=Q)][0] = FatJet_pt_sys # valueList['FatJet_pt_sys'].append(FatJet_pt_sys) return True def get_msoftdrop_smear(self, pt, eta): #get mass resolution massResolution = 0 # version1: added abs() wrt previous version 0 if abs(eta) <= 1.3: massResolution = self.puppisd_resolution_cen.Eval(pt) else: massResolution = self.puppisd_resolution_for.Eval(pt) ### cup = 1. cdown = 1. r = self.rnd.Gaus(0, massResolution - 1) cup = 1. + r * math.sqrt(max(self.Rup**2 - 1, 0)) cdown = 1. + r * math.sqrt(max(self.Rdown**2 - 1, 0)) return [cdown, cup]
class METXY(AddCollectionsModule): def __init__(self, year): super(METXY, self).__init__() self.debug = 'XBBDEBUG' in os.environ self.year = int(year) self.quickloadWarningShown = False def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.systematics = self.xbbConfig.getJECuncertainties(step='METXY') self.METsystematics = [x for x in self.systematics if 'jerReg' not in x] + ['unclustEn'] # load METXYCorr_Met_MetPhi from VHbb namespace VHbbNameSpace = self.config.get('VHbbNameSpace', 'library') ROOT.gSystem.Load(VHbbNameSpace) self.MET_Pt = array.array('f', [0.0]) self.MET_Phi = array.array('f', [0.0]) self.sampleTree.tree.SetBranchAddress("MET_Pt", self.MET_Pt) self.sampleTree.tree.SetBranchAddress("MET_Phi", self.MET_Phi) self.addBranch("MET_Pt_uncorrected") self.addBranch("MET_Phi_uncorrected") if self.sample.isMC(): self.MET_Pt_syst = {} self.MET_Phi_syst = {} for syst in self.METsystematics: self.MET_Pt_syst[syst] = {} self.MET_Phi_syst[syst] = {} for Q in self._variations(syst): self.MET_Pt_syst[syst][Q] = array.array('f', [0.0]) self.MET_Phi_syst[syst][Q] = array.array('f', [0.0]) self.sampleTree.tree.SetBranchAddress("MET_pt_"+syst+Q, self.MET_Pt_syst[syst][Q]) self.sampleTree.tree.SetBranchAddress("MET_phi_"+syst+Q, self.MET_Phi_syst[syst][Q]) self.addBranch("MET_pt_uncorrected_"+syst+Q) self.addBranch("MET_phi_uncorrected_"+syst+Q) def processEvent(self, tree): if not self.hasBeenProcessed(tree): self.markProcessed(tree) # backup uncorrected branches self._b('MET_Pt_uncorrected')[0] = tree.MET_Pt self._b('MET_Phi_uncorrected')[0] = tree.MET_Phi MET_Pt_corrected, MET_Phi_corrected = ROOT.VHbb.METXYCorr_Met_MetPhi(tree.MET_Pt, tree.MET_Phi, tree.run, self.year, self.sample.isMC(), tree.PV_npvs) # overwrite MET_Pt, MET_Phi branches self.MET_Pt[0] = MET_Pt_corrected self.MET_Phi[0] = MET_Phi_corrected if self.sample.isMC(): for syst in self.METsystematics: for Q in self._variations(syst): # backup uncorrected branches self._b("MET_pt_uncorrected_"+syst+Q)[0] = self.MET_Pt_syst[syst][Q][0] self._b("MET_phi_uncorrected_"+syst+Q)[0] = self.MET_Phi_syst[syst][Q][0] MET_Pt_corrected, MET_Phi_corrected = ROOT.VHbb.METXYCorr_Met_MetPhi(self.MET_Pt_syst[syst][Q][0], self.MET_Phi_syst[syst][Q][0], tree.run, self.year, self.sample.isMC(), tree.PV_npvs) # overwrite MET_Pt, MET_Phi branches self.MET_Pt_syst[syst][Q][0] = MET_Pt_corrected self.MET_Phi_syst[syst][Q][0] = MET_Phi_corrected # formulas by default reload the branch content when evaluating the first instance of the object! # SetQuickLoad(1) turns off this behavior for formulaName, treeFormula in self.sampleTree.formulas.items(): if 'MET' in formulaName: if not self.quickloadWarningShown: self.quickloadWarningShown = True print("INFO: SetQuickLoad(1) called for formula:", formulaName) print("INFO: -> EvalInstance(0) on formulas will not re-load branches but will take values from memory, which might have been modified by this module.") treeFormula.SetQuickLoad(1)
class GetTopMass(AddCollectionsModule): def __init__(self, sample=None, nano=False, propagateJES=False, METmethod=2, useHJets=0, minbTag=0.5, branchName='top_mass', addBoostSystematics=False, addMinMax=False, puIdCut=6, jetIdCut=4): super(GetTopMass, self).__init__() self.version = 2 self.nano = nano self.lastEntry = -1 self.branchName = branchName self.METmethod = METmethod #Check the getJetPtMass function for the different methods self.useHJets = useHJets # Using only H jets if useHJets == 1 self.minbTag = minbTag self.propagateJES = propagateJES self.addBoostSystematics = addBoostSystematics self.addMinMax = addMinMax self.puIdCut = puIdCut self.jetIdCut = jetIdCut def dependencies(self): return {'VHbbSelection': 5} def customInit(self, initVars): self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) # Branch names from config self.brJetPtReg = "Jet_PtReg" self.brJetPtNom = "Jet_Pt" self.Jet_btag = self.config.get('General', 'Jet_btag') self.tagidx = self.config.get('General', 'hJidx') if self.config.has_option('General', 'eIdx') and self.config.has_option( 'General', 'muIdx'): self.eIdx = self.config.get('General', 'eIdx') self.muIdx = self.config.get('General', 'muIdx') else: print "WARNING: eIdx and muIdx not defined in [General]! Using default lepton index: \'vLidx\' " self.eIdx = "vLidx" self.muIdx = "vLidx" self.dataset = self.config.get('General', 'dataset') self.METpt = 'MET_Pt' self.METphi = 'MET_Phi' if self.sample.isMC(): self.brJetMassNom = "Jet_mass_nom" else: self.brJetMassNom = "Jet_mass" # nominal self.systematics = [None] ########## # add JES/JER systematics ########## # only defined for nano at the moment if self.propagateJES and self.nano: self.jetSystematics = self.xbbConfig.getJECuncertainties( step='Top') + ['unclustEn'] if self.addBoostSystematics: self.jetSystematics += ['jms'] self.jetSystematics += ['jmr'] if self.sample.isMC(): self.systematics += self.jetSystematics for syst in self.systematics: for Q in self._variations(syst): self.addBranch(self._v(self.branchName, syst, Q)) def processEvent(self, tree): if not self.hasBeenProcessed(tree): self.markProcessed(tree) # leptons/MET treeMETpt, treeMETphi = self.getMET(tree) lep = TLorentzVector() met = TLorentzVector() if not self.nano: lep.SetPtEtaPhiM(tree.vLeptons_new_pt[0], tree.vLeptons_new_eta[0], tree.vLeptons_new_phi[0], tree.vLeptons_new_mass[0]) met.SetPtEtaPhiM(tree.met_pt, tree.met_eta, tree.met_phi, tree.met_mass) else: if tree.Vtype == 2: mu1Idx = getattr(tree, self.muIdx)[0] lep.SetPtEtaPhiM(tree.Muon_pt[mu1Idx], tree.Muon_eta[mu1Idx], tree.Muon_phi[mu1Idx], tree.Muon_mass[mu1Idx]) if tree.Vtype == 3: e1Idx = getattr(tree, self.eIdx)[0] lep.SetPtEtaPhiM(tree.Electron_pt[e1Idx], tree.Electron_eta[e1Idx], tree.Electron_phi[e1Idx], tree.Electron_mass[e1Idx]) met.SetPtEtaPhiM(treeMETpt, 0, treeMETphi, 0) # compute top mass for all variations for syst in self.systematics: for UD in self._variations(syst): # MET treeMETpt, treeMETphi = self.getMET(tree, syst, UD) met.SetPtEtaPhiM(treeMETpt, 0, treeMETphi, 0) # jets Jet_PtReg, Jet_MassReg, Jet_Pt = self.getJetPtMasses( tree, syst=syst, UD=UD) # closest jets cJidx, cHJidx = self.closestJetIdx(tree, lep, syst=syst, UD=UD, Jet_PtReg=Jet_PtReg, Jet_MassReg=Jet_MassReg, Jet_Pt=Jet_Pt) closestIdx = cJidx if self.useHJets == 0 else cHJidx if closestIdx != -1: cJet = TLorentzVector() cJet.SetPtEtaPhiM(Jet_PtReg[closestIdx], tree.Jet_eta[closestIdx], tree.Jet_phi[closestIdx], Jet_MassReg[closestIdx]) top_mass = self.computeTopMass_new( lep, met, cJet, self.METmethod) elif closestIdx == -1: top_mass = -99 self._b(self._v(self.branchName, syst, UD))[0] = top_mass return True def getResolvedJetIndicesFromTree(self, tree, syst=None, UD=None): indexNameSyst = (self.tagidx + '_' + syst + UD) if not self._isnominal(syst) else self.tagidx if hasattr(tree, indexNameSyst): self.count('_debug_resolved_idx_syst_exists') return getattr(tree, indexNameSyst) else: self.count('_debug_resolved_idx_fallback_nom') self.count('_debug_resolved_idx_fallback_nom_for_' + str(syst)) return getattr(tree, self.tagidx) ## # \Function EquationSolver: # # Solves 3rd degree equations # # \Author A. Orso M. Iorio # # # \version $Id: EquationSolver.h,v 1.1 2013/02/27 12:18:42 degrutto Exp $ # def EquationSolve(self, a, b, c, d): result = [] if (a != 0): q = (3 * a * c - b * b) / (9 * a * a) r = (9 * a * b * c - 27 * a * a * d - 2 * b * b * b) / (54 * a * a * a) Delta = q * q * q + r * r rho = 0. theta = 0. if (Delta <= 0): rho = sqrt(-(q * q * q)) theta = acos(r / rho) s = complex( sqrt(-q) * cos(theta / 3.0), sqrt(-q) * sin(theta / 3.0)) t = complex( sqrt(-q) * cos(-theta / 3.0), sqrt(-q) * sin(-theta / 3.0)) if (Delta > 0): #print r, sqrt(Delta) if (r + sqrt(Delta) > 0): s = complex(pow((r + sqrt(Delta)), (1. / 3)), 0) else: s = complex(-pow(abs((r + sqrt(Delta))), (1. / 3)), 0) if (r - sqrt(Delta) > 0): t = complex(pow((r - sqrt(Delta)), (1. / 3)), 0) else: t = complex(-pow(abs((r - sqrt(Delta))), (1. / 3)), 0) i = complex(0., 1.0) x1 = s + t + complex(-b / (3.0 * a), 0) x2 = (s + t) * complex(-0.5, 0) - complex( b / (3.0 * a), 0) + (s - t) * i * complex(sqrt(3) / 2.0, 0) x3 = (s + t) * complex(-0.5, 0) - complex( b / (3.0 * a), 0) - (s - t) * i * complex(sqrt(3) / 2.0, 0) if (abs(x1.imag) < 0.0001): result.append(x1.real) if (abs(x2.imag) < 0.0001): result.append(x2.real) if (abs(x3.imag) < 0.0001): result.append(x3.real) #print x1,x2,x3 return result else: return result return result def getNu4Momentum(self, TLepton, TMET, debug=False): branch = -1 Lepton = TLorentzVector() Lepton.SetPxPyPzE(TLepton.Px(), TLepton.Py(), TLepton.Pz(), TLepton.E()) MET = TLorentzVector() MET.SetPxPyPzE(TMET.Px(), TMET.Py(), 0., TMET.E()) mW = 80.38 result = [] MisET2 = (MET.Px() * MET.Px() + MET.Py() * MET.Py()) mu = (mW * mW) / 2 + MET.Px() * Lepton.Px() + MET.Py() * Lepton.Py() a = (mu * Lepton.Pz()) / (Lepton.Energy() * Lepton.Energy() - Lepton.Pz() * Lepton.Pz()) a2 = pow(a, 2) b = (pow(Lepton.Energy(), 2.) * (MisET2) - pow(mu, 2.)) / (pow(Lepton.Energy(), 2) - pow(Lepton.Pz(), 2)) pz1 = 0. pz2 = 0. pznu = 0. nNuSol = 0 p4nu_rec = TLorentzVector() p4W_rec = TLorentzVector() p4b_rec = TLorentzVector() p4Top_rec = TLorentzVector() p4lep_rec = TLorentzVector() p4lep_rec.SetPxPyPzE(Lepton.Px(), Lepton.Py(), Lepton.Pz(), Lepton.Energy()) #print a2,b if (a2 - b > 0): root = sqrt(a2 - b) pz1 = a + root pz2 = a - root nNuSol = 2 pznu = pz1 branch = 1 if abs(pz2) < abs(pz1): pznu = pz2 branch = 2 Enu = sqrt(MisET2 + pznu * pznu) p4nu_rec.SetPxPyPzE(MET.Px(), MET.Py(), pznu, Enu) result.append(p4nu_rec) else: ptlep = Lepton.Pt() pxlep = Lepton.Px() pylep = Lepton.Py() metpx = MET.Px() metpy = MET.Py() EquationA = 1. EquationB = -3. * pylep * mW / (ptlep) EquationC = mW * mW * (2 * pylep * pylep) / ( ptlep * ptlep) + mW * mW - 4 * pxlep * pxlep * pxlep * metpx / ( ptlep * ptlep) - 4 * pxlep * pxlep * pylep * metpy / ( ptlep * ptlep) EquationD = 4. * pxlep * pxlep * mW * metpy / ( ptlep) - pylep * mW * mW * mW / ptlep solutions = self.EquationSolve(EquationA, EquationB, EquationC, EquationD) solutions2 = self.EquationSolve(EquationA, -EquationB, EquationC, -EquationD) deltaMin = 14000 * 14000 zeroValue = -mW * mW / (4 * pxlep) minPx = 0 minPy = 0 for i in range(len(solutions)): if (solutions[i] < 0): continue p_x = (solutions[i] * solutions[i] - mW * mW) / (4 * pxlep) p_y = (mW * mW * pylep + 2 * pxlep * pylep * p_x - mW * ptlep * solutions[i]) / (2 * pxlep * pxlep) Delta2 = (p_x - metpx) * (p_x - metpx) + (p_y - metpy) * ( p_y - metpy) if (Delta2 < deltaMin and Delta2 > 0): deltaMin = Delta2 minPx = p_x minPy = p_y branch = 3 for i in range(len(solutions2)): if (solutions2[i] < 0): continue p_x = (solutions2[i] * solutions2[i] - mW * mW) / (4 * pxlep) p_y = (mW * mW * pylep + 2 * pxlep * pylep * p_x + mW * ptlep * solutions2[i]) / (2 * pxlep * pxlep) Delta2 = (p_x - metpx) * (p_x - metpx) + (p_y - metpy) * ( p_y - metpy) if (Delta2 < deltaMin and Delta2 > 0): deltaMin = Delta2 minPx = p_x minPy = p_y branch = 4 pyZeroValue = (mW * mW * pxlep + 2 * pxlep * pylep * zeroValue) delta2ZeroValue = (zeroValue - metpx) * (zeroValue - metpx) + ( pyZeroValue - metpy) * (pyZeroValue - metpy) if (deltaMin == 14000 * 14000): if debug: branch = 6 return TLorentzVector(0, 0, 0, 0), branch else: return TLorentzVector(0, 0, 0, 0) if (delta2ZeroValue < deltaMin): deltaMin = delta2ZeroValue minPx = zeroValue minPy = pyZeroValue branch = 5 mu_Minimum = (mW * mW) / 2 + minPx * pxlep + minPy * pylep a_Minimum = (mu_Minimum * Lepton.Pz()) / ( Lepton.Energy() * Lepton.Energy() - Lepton.Pz() * Lepton.Pz()) pznu = a_Minimum Enu = sqrt(minPx * minPx + minPy * minPy + pznu * pznu) p4nu_rec.SetPxPyPzE(minPx, minPy, pznu, Enu) result.append(p4nu_rec) if debug: return result[0], branch else: return result[0] # def computeTopMass(self, lep, met, jets, jetsIdx): def computeTopMass(self, lep, met, jets): #neutrino = self.getNu4Momentum(lep, met) bjet = TLorentzVector() minDR = 99 closeIdx = -1 for i, jet in enumerate(jets): if ( jet.Pt() > 30 ): # and jet.bTagCSV > CSVL and jet.puID > 0 and jet.Id > 0? how? dR = jet.DeltaR(lep) if (dR < minDR): minDR = dR bjet = jet # closeIdx = jetsIdx[i] if (bjet.Pt() <= 0): return -99 # print "Old closest idx: {}".format(closeIdx) top = lep + met + bjet return top.M() def getJetPtMasses(self, tree, syst=None, UD=None): JetPtReg = np.array(getattr(tree, self.brJetPtReg)) JetPtNom = np.array(getattr(tree, self.brJetPtNom)) JetMassNom = np.array(getattr(tree, self.brJetMassNom)) if self._isnominal(syst) or syst.startswith('unclustEn'): JetPt = JetPtReg JetMass = JetMassNom * JetPtReg / JetPtNom elif 'jerReg' in syst: JetPtSys = np.array(getattr(tree, "Jet_Pt" + syst[3:] + UD)) JetPt = JetPtSys JetMass = JetMassNom * JetPtSys / JetPtNom else: JetPtSys = np.array(getattr(tree, "Jet_pt" + "_" + syst + UD)) JetMassSys = np.array(getattr(tree, "Jet_mass" + "_" + syst + UD)) JetPt = JetPtSys * JetPtReg / JetPtNom JetMass = JetMassSys * JetPtReg / JetPtNom return JetPt, JetMass, JetPtNom # def getJetPtMass(self, tree, i, variation=None): # # JetPtReg = getattr(tree, self.brJetPtReg)[i] # JetPtNom = getattr(tree,self.brJetPtNom)[i] # JetMassNom = getattr(tree,self.brJetMassNom)[i] # # if variation is None or variation.startswith('unclustEn'): # JetPt = JetPtReg # JetMass = JetMassNom * JetPtReg /JetPtNom # # elif 'jerReg' in variation: # Q = "Up" if "Up" in variation else "Down" # JetPtSys = getattr(tree,"Jet_PtReg" + Q)[i] # # JetPt = JetPtSys # JetMass = JetMassNom * JetPtSys / JetPtNom # # else: # JetPtSys = getattr(tree,"Jet_pt" + "_" + variation)[i] # JetMassSys = getattr(tree, "Jet_mass" + "_" + variation)[i] # # JetPt = JetPtSys * JetPtReg / JetPtNom # JetMass = JetMassSys * JetPtReg / JetPtNom # print "{}: {}, {}: {}".format("Jet_pt" + "_" + variation,JetPtSys,"Jet_mass" + "_" + variation,JetMassSys) # print "JetPt {}, JetMass: {}".format(JetPt,JetMass) # return JetPt, JetMass def getMET(self, tree, syst=None, UD=None): if not self._isnominal(syst) and not syst.startswith('jerReg'): treeMETpt = getattr(tree, "MET_pt_" + syst + UD) treeMETphi = getattr(tree, "MET_phi_" + syst + UD) else: treeMETpt = getattr(tree, self.METpt) treeMETphi = getattr(tree, self.METphi) return treeMETpt, treeMETphi def closestJetIdx(self, tree, lep, syst=None, UD=None, Jet_PtReg=None, Jet_MassReg=None, Jet_Pt=None): #neutrino = self.getNu4Momentum(lep, met) minDR = 999 minHDR = 999 ClosestJIdx = -1 ClosestHJIdx = -1 # reuse pt/mass already obtained from tree if available # if one is missing, recompute them again if Jet_PtReg is None or Jet_MassReg is None or Jet_Pt is None: Jet_PtReg_r, Jet_MassReg_r, Jet_Pt_r = self.getJetPtMasses( tree, syst, UD) Jet_PtReg = Jet_PtReg_r if Jet_PtReg is None else Jet_PtReg Jet_MassReg = Jet_MassReg_r if Jet_MassReg is None else Jet_MassReg Jet_Pt = Jet_Pt_r if Jet_Pt is None else Jet_Pt # b-tagger jetBtags = getattr(tree, self.Jet_btag) Jet_lepFilter = tree.Jet_lepFilter Jet_jetId = tree.Jet_jetId Jet_puId = tree.Jet_puId Jet_eta = tree.Jet_eta Jet_phi = tree.Jet_phi nJet = tree.nJet # selected jet indices hJidx0, hJidx1 = self.getResolvedJetIndicesFromTree(tree, syst, UD) for i in range(nJet): #if temPt < 30 or tembTag < self.minbTag or not (tree.Jet_lepFilter): continue if Jet_PtReg[i] >= 30 and jetBtags[ i] >= self.minbTag and tree.Jet_lepFilter[ i] and tree.Jet_jetId[i] > self.jetIdCut and ( tree.Jet_puId[i] > self.puIdCut or Jet_Pt[i] > 50.0): tempJet = TLorentzVector() tempJet.SetPtEtaPhiM(Jet_PtReg[i], tree.Jet_eta[i], tree.Jet_phi[i], Jet_MassReg[i]) dR = tempJet.DeltaR(lep) # print "Jetidx: {}, dR = {}".format(i,dR) if dR < minDR: minDR = dR ClosestJIdx = i if (i == hJidx0 or i == hJidx1) and dR < minHDR: minHDR = dR ClosestHJIdx = i # print "hJidx0 = {}, hJidx1 = {}".format(self.hJidx0,self.hJidx1) return ClosestJIdx, ClosestHJIdx def computeTopMass_new(self, lep, met, jet, METmethod): #neutrino = self.getNu4Momentum(lep, met) new_top = TLorentzVector() jet_transverse = TLorentzVector() lep_transverse = TLorentzVector() if METmethod == 1: jet_transverse.SetPxPyPzE(jet.Px(), jet.Py(), 0, sqrt((jet.M())**2 + (jet.Pt())**2)) lep_transverse.SetPxPyPzE(lep.Px(), lep.Py(), 0, sqrt((lep.M())**2 + (lep.Pt())**2)) new_top = jet_transverse + lep_transverse + met elif METmethod == 2: neutrino = TLorentzVector() neutrino = self.getNu4Momentum(lep, met) new_top = lep + jet + neutrino elif METmethod == 3: new_top = lep + jet + met return new_top.M()
class mSD_scale_res_shift(AddCollectionsModule): def __init__(self, year=None): super(mSD_scale_res_shift, self).__init__() self.debug = 'XBBDEBUG' in os.environ self.year = year if type(year) == str else str(year) self.scale_params = { '2018': [0.9, 0.01, 0.9, 0.01], } if self.year not in self.scale_params.keys(): raise Exception( 'Please specify the year correspoding to the correction!') self.scale, self.scale_err, self.res, self.res_err = self.scale_params[ self.year] self.scale_up = self.scale + self.scale_err self.scale_down = self.scale - self.scale_err self.res_up = self.res + self.res_err self.res_down = self.res - self.res_err def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.isData = initVars['sample'].isData() self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.systematics = self.xbbConfig.getJECuncertainties() self.systematicsBoosted = [ x for x in self.systematics if 'jerReg' not in x ] + ['jms', 'jmr'] self.maxnFatJet = 256 if self.sample.isMC(): self.FatJet_Msoftdrop = array.array('f', [0.0] * self.maxnFatJet) self.FatJet_msoftdrop_nom = array.array('f', [0.0] * self.maxnFatJet) self.sampleTree.tree.SetBranchAddress("FatJet_Msoftdrop", self.FatJet_Msoftdrop) self.sampleTree.tree.SetBranchAddress("FatJet_msoftdrop_nom", self.FatJet_msoftdrop_nom) #create backup branches self.addVectorBranch("FatJet_MsoftdropOld", default=0.0, branchType='f', length=self.maxnFatJet, leaflist="FatJet_MsoftdropOld[nFatJet]/F") self.addVectorBranch("FatJet_msoftdrop_nomOld", default=0.0, branchType='f', length=self.maxnFatJet, leaflist="FatJet_msoftdrop_nomOld[nFatJet]/F") self.FatJet_msoftdrop_syst = {} for syst in self.systematicsBoosted: self.FatJet_msoftdrop_syst[syst] = {} for Q in self._variations(syst): self.FatJet_msoftdrop_syst[syst][Q] = array.array( 'f', [0.0] * self.maxnFatJet) self.sampleTree.tree.SetBranchAddress( "FatJet_msoftdrop_" + syst + Q, self.FatJet_msoftdrop_syst[syst][Q]) #backup branches self.addVectorBranch( 'FatJet_msoftdrop_' + syst + Q + 'Old', default=0.0, branchType='f', length=self.maxnFatJet, leaflist='FatJet_msoftdrop_' + syst + Q + 'Old[nFatJet]/F') def processEvent(self, tree): if not self.hasBeenProcessed(tree) and self.sample.isMC(): self.markProcessed(tree) nFatJet = tree.nFatJet if self.sample.isMC(): for i in range(nFatJet): #fill backup branches self._b( "FatJet_MsoftdropOld")[i] = self.FatJet_Msoftdrop[i] self._b("FatJet_msoftdrop_nomOld" )[i] = self.FatJet_msoftdrop_nom[i] #overwrite branches self.FatJet_Msoftdrop[i] = self._b( 'FatJet_MsoftdropOld')[i] * self.scale self.FatJet_msoftdrop_nom[i] = self._b( "FatJet_msoftdrop_nomOld")[i] * self.scale for syst in self.systematicsBoosted: for Q in self._variations(syst): # fill backup branches self._b("FatJet_msoftdrop_" + syst + Q + 'Old')[ i] = self.FatJet_msoftdrop_syst[syst][Q][i] # overwrite branches if syst == 'jms': if Q == 'Up': self.FatJet_msoftdrop_syst[syst][Q][ i] = self._b("FatJet_msoftdrop_nomOld" )[i] * self.scale_up else: self.FatJet_msoftdrop_syst[syst][Q][ i] = self._b("FatJet_msoftdrop_nomOld" )[i] * self.scale_down elif syst == 'jmr': self.FatJet_msoftdrop_syst[syst][Q][ i] = self._b("FatJet_msoftdrop_" + syst + Q + 'Old')[i] * self.res else: self.FatJet_msoftdrop_syst[syst][Q][ i] = self._b("FatJet_msoftdrop_" + syst + Q + 'Old')[i] * self.scale
def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.isData = initVars['sample'].isData() self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) # settings # originally Electron_mvaFall17V1Iso_WP80 was used for 2017, which was called Electron_mvaFall17Iso_WP80 # consistently available for all 3 years: Electron_mvaFall17V2Iso self.electronID = { 1: { "2018": "Electron_mvaFall17V2Iso_WP80", "2017": "Electron_mvaFall17V2Iso_WP80", #"2016": "Electron_mvaSpring16GP_WP80", "2016": "Electron_mvaFall17V2Iso_WP80", }, 2: { "2018": "Electron_mvaFall17V2Iso_WP90", "2017": "Electron_mvaFall17V2Iso_WP90", #"2016": "Electron_mvaSpring16GP_WP90", "2016": "Electron_mvaFall17V2Iso_WP90", } } # default lepton IDs for backward compatibility if self.idWen == "default": self.idWen = self.electronID[1][self.year] if self.idZee == "default": self.idZee = self.electronID[2][self.year] if self.idWmn == "default": # cut-based muon ID self.idWmn = "Muon_tightId" if self.idZmm == "default": self.idZmm = None # updated to july 2018 Jet/MET recommendations # reference: https://twiki.cern.ch/twiki/bin/viewauth/CMS/MissingETOptionalFiltersRun2 if self.year == "2016": self.metFilters = [ "Flag_goodVertices", "Flag_globalSuperTightHalo2016Filter", "Flag_HBHENoiseFilter", "Flag_HBHENoiseIsoFilter", "Flag_EcalDeadCellTriggerPrimitiveFilter", "Flag_BadPFMuonFilter" ] elif self.year in ["2017", "2018"]: self.metFilters = [ "Flag_goodVertices", "Flag_globalSuperTightHalo2016Filter", "Flag_HBHENoiseFilter", "Flag_HBHENoiseIsoFilter", "Flag_EcalDeadCellTriggerPrimitiveFilter", "Flag_BadPFMuonFilter", "Flag_ecalBadCalibFilter" ] if self.isData: self.metFilters.append("Flag_eeBadScFilter") # main tagger (-> hJidx) self.taggerName = self.config.get('General', 'Jet_btag') self.jetDefinitions = [ { 'taggerName': self.taggerName }, ] self.btagWPs = { "2018": { 'Jet_btagDeepB': { 'loose': 0.1241, 'medium': 0.4184, 'tight': 0.7527, 'none': -1.0, }, 'Jet_btagDeepFlavB': { 'loose': 0.0494, 'medium': 0.2770, 'tight': 0.7264, 'none': -1.0, }, }, "2017": { 'Jet_btagDeepB': { 'loose': 0.1522, 'medium': 0.4941, 'tight': 0.8001, 'none': -1.0, }, 'Jet_btagDeepFlavB': { 'loose': 0.0521, 'medium': 0.3033, 'tight': 0.7489, 'none': -1.0, }, }, "2016": { 'Jet_btagDeepB': { 'loose': 0.2217, 'medium': 0.6321, 'tight': 0.8953, 'none': -1.0, }, 'Jet_btagDeepFlavB': { 'loose': 0.0614, 'medium': 0.3093, 'tight': 0.7221, 'none': -1.0, }, }, } # for main tagger, for others use self.btagWPs below self.btagWP = self.btagWPs[self.year][self.taggerName] if self.year == "2018": self.HltPaths = { 'Znn': ['HLT_PFMET120_PFMHT120_IDTight'], 'Wln': ['HLT_Ele32_WPTight_Gsf', 'HLT_IsoMu24'], 'Zll': [ 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass3p8', 'HLT_Ele23_Ele12_CaloIdL_TrackIdL_IsoVL' ], } elif self.year == "2017": self.HltPaths = { 'Znn': [ 'HLT_PFMET120_PFMHT120_IDTight', 'HLT_PFMET120_PFMHT120_IDTight_PFHT60' ], 'Wln': ['HLT_Ele32_WPTight_Gsf_L1DoubleEG', 'HLT_IsoMu27'], 'Zll': [ 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass3p8', 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass8', 'HLT_Ele23_Ele12_CaloIdL_TrackIdL_IsoVL' ], } elif self.year == "2016": self.HltPaths = { 'Znn': [ 'HLT_PFMET110_PFMHT110_IDTight', 'HLT_PFMET120_PFMHT120_IDTight', 'HLT_PFMET170_NoiseCleaned', 'HLT_PFMET170_HBHECleaned', 'HLT_PFMET170_HBHE_BeamHaloCleaned' ], 'Wln': ['HLT_Ele27_WPTight_Gsf', 'HLT_IsoMu24', 'HLT_IsoTkMu24'], 'Zll': [ 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL', 'HLT_Mu17_TrkIsoVVL_TkMu8_TrkIsoVVL', 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ', 'HLT_Mu17_TrkIsoVVL_TkMu8_TrkIsoVVL_DZ', 'HLT_Ele23_Ele12_CaloIdL_TrackIdL_IsoVL_DZ' ], } else: raise Execption("unknown year") # Vtype cut on datasets self.leptonFlav = { 'DoubleMuon': 0, 'DoubleEG': 1, 'SingleMuon': 2, 'SingleElectron': 3, 'MET': 4, } if self.year == '2018': if "Zll" in self.channels: self.leptonFlav['EGamma'] = 1 elif "Wlv" in self.channels: self.leptonFlav['EGamma'] = 3 self.systematics = self.xbbConfig.getJECuncertainties( step='Preselection') self.METsystematics = [ x for x in self.systematics if 'jerReg' not in x ] + ['unclustEn'] self.systematicsBoosted = [ x for x in self.systematics if 'jerReg' not in x ] + ['jms', 'jmr'] self.cutFlow = [0] * 16 # new branches to write self.addIntegerBranch("isZee") self.addIntegerBranch("isZmm") self.addIntegerBranch("isWmunu") self.addIntegerBranch("isWenu") self.addIntegerBranch("isZnn") # selected lepton indices self.addIntegerVectorBranch("vLidx", default=-1, length=2) # selected jet indices defaultJetDefinitions = [ x for x in self.jetDefinitions if 'indexName' not in x or x['indexName'] == '' ] assert (len(defaultJetDefinitions) == 1) if not self.skipJetSelection: for jetDefinition in self.jetDefinitions: indexName = jetDefinition[ 'indexName'] if 'indexName' in jetDefinition else '' self.addIntegerVectorBranch( "hJidx{suffix}".format(suffix=indexName), default=-1, length=2) if self.sample.isMC(): for syst in self.systematics: for UD in ['Up', 'Down']: self.addIntegerVectorBranch( "hJidx{suffix}_{syst}{UD}".format( suffix=indexName, syst=syst, UD=UD), default=-1, length=2) # selected fatjet index self.addIntegerBranch("Hbb_fjidx") if self.sample.isMC(): for syst in self.systematicsBoosted: for UD in ['Up', 'Down']: self.addIntegerBranch("Hbb_fjidx_{syst}{UD}".format( syst=syst, UD=UD)) self.addBranch("lepMetDPhi") self.addBranch("V_mt") self.addBranch("V_pt") self.addBranch("V_eta") self.addBranch("V_phi") self.addBranch("V_mass") print "DEBUG: sample identifier:", self.sample.identifier, " lep flav", self.leptonFlav, " -> ", self.leptonFlav[ self.sample. identifier] if self.sample.identifier in self.leptonFlav else "UNDEFINED LEPTON FLAVOR!!"
class VHbbSelection(AddCollectionsModule): # original 2017: puIdCut=0, jetIdCut=-1 # now: puIdCut=6, jetIdCut=4 def __init__(self, debug=False, year="none", channels=["Wln", "Zll", "Znn"], puIdCut=6, jetIdCut=4, debugEvents=[], isoWen=0.06, isoWmn=0.06, isoZmm=0.25, isoZee=0.15, recomputeVtype=False, btagMaxCut=None, idWmn="default", idWmnCut=1, idWen="default", idWenCut=1, idZmm="default", idZmmCut=1, idZee="default", idZeeCut=1, skipJetSelection=False, vpt0lep=170.0, vpt1lep=150.0, vpt2lep=75.0): super(VHbbSelection, self).__init__() self.debug = debug or 'XBBDEBUG' in os.environ self.version = 7 self.skipJetSelection = skipJetSelection self.stats = {} self.year = year self.channels = channels self.debugEvents = debugEvents self.puIdCut = puIdCut self.jetIdCut = jetIdCut self.isoWen = isoWen self.isoWmn = isoWmn self.isoZee = isoZee self.isoZmm = isoZmm self.idWmn = idWmn self.idWmnCut = idWmnCut self.idWen = idWen self.idWenCut = idWenCut self.idZmm = idZmm self.idZmmCut = idZmmCut self.idZee = idZee self.idZeeCut = idZeeCut self.vpt0lep = vpt0lep self.vpt1lep = vpt1lep self.vpt2lep = vpt2lep self.recomputeVtype = recomputeVtype self.btagMaxCut = btagMaxCut # only use puId below this pT: self.puIdMaxPt = 50.0 # run QCD estimation analysis with inverted isolation cuts (CAREFUL!) if self.recomputeVtype: print("\x1b[45m\x1b[37m" + "-" * 160 + "\x1b[0m") print("\x1b[45m\x1b[37m" + "-" * 160 + "\x1b[0m") print( "\x1b[45m\x1b[37m RECOMPUTE Vtype, custom definitions might be used!\x1b[0m" ) print("\x1b[45m\x1b[37m" + "-" * 160 + "\x1b[0m") print("\x1b[45m\x1b[37m" + "-" * 160 + "\x1b[0m") def customInit(self, initVars): self.sampleTree = initVars['sampleTree'] self.isData = initVars['sample'].isData() self.sample = initVars['sample'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) # settings # originally Electron_mvaFall17V1Iso_WP80 was used for 2017, which was called Electron_mvaFall17Iso_WP80 # consistently available for all 3 years: Electron_mvaFall17V2Iso self.electronID = { 1: { "2018": "Electron_mvaFall17V2Iso_WP80", "2017": "Electron_mvaFall17V2Iso_WP80", #"2016": "Electron_mvaSpring16GP_WP80", "2016": "Electron_mvaFall17V2Iso_WP80", }, 2: { "2018": "Electron_mvaFall17V2Iso_WP90", "2017": "Electron_mvaFall17V2Iso_WP90", #"2016": "Electron_mvaSpring16GP_WP90", "2016": "Electron_mvaFall17V2Iso_WP90", } } # default lepton IDs for backward compatibility if self.idWen == "default": self.idWen = self.electronID[1][self.year] if self.idZee == "default": self.idZee = self.electronID[2][self.year] if self.idWmn == "default": # cut-based muon ID self.idWmn = "Muon_tightId" if self.idZmm == "default": self.idZmm = None # updated to july 2018 Jet/MET recommendations # reference: https://twiki.cern.ch/twiki/bin/viewauth/CMS/MissingETOptionalFiltersRun2 if self.year == "2016": self.metFilters = [ "Flag_goodVertices", "Flag_globalSuperTightHalo2016Filter", "Flag_HBHENoiseFilter", "Flag_HBHENoiseIsoFilter", "Flag_EcalDeadCellTriggerPrimitiveFilter", "Flag_BadPFMuonFilter" ] elif self.year in ["2017", "2018"]: self.metFilters = [ "Flag_goodVertices", "Flag_globalSuperTightHalo2016Filter", "Flag_HBHENoiseFilter", "Flag_HBHENoiseIsoFilter", "Flag_EcalDeadCellTriggerPrimitiveFilter", "Flag_BadPFMuonFilter", "Flag_ecalBadCalibFilter" ] if self.isData: self.metFilters.append("Flag_eeBadScFilter") # main tagger (-> hJidx) self.taggerName = self.config.get('General', 'Jet_btag') self.jetDefinitions = [ { 'taggerName': self.taggerName }, ] self.btagWPs = { "2018": { 'Jet_btagDeepB': { 'loose': 0.1241, 'medium': 0.4184, 'tight': 0.7527, 'none': -1.0, }, 'Jet_btagDeepFlavB': { 'loose': 0.0494, 'medium': 0.2770, 'tight': 0.7264, 'none': -1.0, }, }, "2017": { 'Jet_btagDeepB': { 'loose': 0.1522, 'medium': 0.4941, 'tight': 0.8001, 'none': -1.0, }, 'Jet_btagDeepFlavB': { 'loose': 0.0521, 'medium': 0.3033, 'tight': 0.7489, 'none': -1.0, }, }, "2016": { 'Jet_btagDeepB': { 'loose': 0.2217, 'medium': 0.6321, 'tight': 0.8953, 'none': -1.0, }, 'Jet_btagDeepFlavB': { 'loose': 0.0614, 'medium': 0.3093, 'tight': 0.7221, 'none': -1.0, }, }, } # for main tagger, for others use self.btagWPs below self.btagWP = self.btagWPs[self.year][self.taggerName] if self.year == "2018": self.HltPaths = { 'Znn': ['HLT_PFMET120_PFMHT120_IDTight'], 'Wln': ['HLT_Ele32_WPTight_Gsf', 'HLT_IsoMu24'], 'Zll': [ 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass3p8', 'HLT_Ele23_Ele12_CaloIdL_TrackIdL_IsoVL' ], } elif self.year == "2017": self.HltPaths = { 'Znn': [ 'HLT_PFMET120_PFMHT120_IDTight', 'HLT_PFMET120_PFMHT120_IDTight_PFHT60' ], 'Wln': ['HLT_Ele32_WPTight_Gsf_L1DoubleEG', 'HLT_IsoMu27'], 'Zll': [ 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass3p8', 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass8', 'HLT_Ele23_Ele12_CaloIdL_TrackIdL_IsoVL' ], } elif self.year == "2016": self.HltPaths = { 'Znn': [ 'HLT_PFMET110_PFMHT110_IDTight', 'HLT_PFMET120_PFMHT120_IDTight', 'HLT_PFMET170_NoiseCleaned', 'HLT_PFMET170_HBHECleaned', 'HLT_PFMET170_HBHE_BeamHaloCleaned' ], 'Wln': ['HLT_Ele27_WPTight_Gsf', 'HLT_IsoMu24', 'HLT_IsoTkMu24'], 'Zll': [ 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL', 'HLT_Mu17_TrkIsoVVL_TkMu8_TrkIsoVVL', 'HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ', 'HLT_Mu17_TrkIsoVVL_TkMu8_TrkIsoVVL_DZ', 'HLT_Ele23_Ele12_CaloIdL_TrackIdL_IsoVL_DZ' ], } else: raise Execption("unknown year") # Vtype cut on datasets self.leptonFlav = { 'DoubleMuon': 0, 'DoubleEG': 1, 'SingleMuon': 2, 'SingleElectron': 3, 'MET': 4, } if self.year == '2018': if "Zll" in self.channels: self.leptonFlav['EGamma'] = 1 elif "Wlv" in self.channels: self.leptonFlav['EGamma'] = 3 self.systematics = self.xbbConfig.getJECuncertainties( step='Preselection') self.METsystematics = [ x for x in self.systematics if 'jerReg' not in x ] + ['unclustEn'] self.systematicsBoosted = [ x for x in self.systematics if 'jerReg' not in x ] + ['jms', 'jmr'] self.cutFlow = [0] * 16 # new branches to write self.addIntegerBranch("isZee") self.addIntegerBranch("isZmm") self.addIntegerBranch("isWmunu") self.addIntegerBranch("isWenu") self.addIntegerBranch("isZnn") # selected lepton indices self.addIntegerVectorBranch("vLidx", default=-1, length=2) # selected jet indices defaultJetDefinitions = [ x for x in self.jetDefinitions if 'indexName' not in x or x['indexName'] == '' ] assert (len(defaultJetDefinitions) == 1) if not self.skipJetSelection: for jetDefinition in self.jetDefinitions: indexName = jetDefinition[ 'indexName'] if 'indexName' in jetDefinition else '' self.addIntegerVectorBranch( "hJidx{suffix}".format(suffix=indexName), default=-1, length=2) if self.sample.isMC(): for syst in self.systematics: for UD in ['Up', 'Down']: self.addIntegerVectorBranch( "hJidx{suffix}_{syst}{UD}".format( suffix=indexName, syst=syst, UD=UD), default=-1, length=2) # selected fatjet index self.addIntegerBranch("Hbb_fjidx") if self.sample.isMC(): for syst in self.systematicsBoosted: for UD in ['Up', 'Down']: self.addIntegerBranch("Hbb_fjidx_{syst}{UD}".format( syst=syst, UD=UD)) self.addBranch("lepMetDPhi") self.addBranch("V_mt") self.addBranch("V_pt") self.addBranch("V_eta") self.addBranch("V_phi") self.addBranch("V_mass") print "DEBUG: sample identifier:", self.sample.identifier, " lep flav", self.leptonFlav, " -> ", self.leptonFlav[ self.sample. identifier] if self.sample.identifier in self.leptonFlav else "UNDEFINED LEPTON FLAVOR!!" def HighestPtGoodElectronsOppCharge(self, tree, min_pt, max_rel_iso, idcut, etacut, isOneLepton, electronID=None): indices = [] for i in range(tree.nElectron): passIso = tree.Electron_pfRelIso03_all[i] < max_rel_iso passID = getattr( tree, electronID)[i] >= idcut if electronID is not None else True passAcceptance = abs( tree.Electron_eta[i]) < etacut and tree.Electron_pt[i] > min_pt if passAcceptance and passIso and passID: if len(indices) < 1: indices.append(i) if isOneLepton: break else: if tree.Electron_charge[i] * tree.Electron_charge[ indices[0]] < 0: indices.append(i) break return indices def HighestPtGoodMuonsOppCharge(self, tree, min_pt, max_rel_iso, idcut, etacut, isOneLepton, muonID=None): indices = [] for i in range(tree.nMuon): passIso = tree.Muon_pfRelIso04_all[i] < max_rel_iso passID = getattr( tree, muonID)[i] >= idcut if muonID is not None else True passAcceptance = abs( tree.Muon_eta[i]) < etacut and tree.Muon_pt[i] > min_pt if passAcceptance and passIso and passID: if len(indices) < 1: indices.append(i) if isOneLepton: break else: if tree.Muon_charge[i] * tree.Muon_charge[indices[0]] < 0: indices.append(i) break return indices def HighestTaggerValueFatJet(self, tree, ptCut, msdCut, etaCut, taggerName, systList=None, Vphi=None, Vphi_syst=None): fatJetMaxTagger = [] Hbb_fjidx = [] Pt = [] Msd = [] systematics = systList if systList is not None else [None] nSystematics = len(systematics) Pt_nom = tree.FatJet_Pt Msd_nom = tree.FatJet_Msoftdrop eta = tree.FatJet_eta phi = tree.FatJet_phi lepFilter = tree.FatJet_lepFilter tagger = getattr(tree, taggerName) for syst in systematics: Hbb_fjidx.append(-1) fatJetMaxTagger.append(-999.9) if syst is None: Pt.append(Pt_nom) Msd.append(Msd_nom) elif syst in ['jmrUp', 'jmrDown', 'jmsUp', 'jmsDown']: # for jms,jmr the branches contain the mass itself Pt.append(Pt_nom) Msd.append(getattr(tree, "FatJet_msoftdrop_" + syst)) else: # for all other variations, the branches contain a multiplicative factor... duh Pt_scale = getattr(tree, "FatJet_pt_{syst}".format(syst=syst)) Pt.append( [Pt_nom[i] * Pt_scale[i] for i in range(len(Pt_nom))]) Msd_scale = getattr( tree, "FatJet_msoftdrop_{syst}".format(syst=syst)) Msd.append( [Msd_nom[i] * Msd_scale[i] for i in range(len(Msd_nom))]) for i in range(tree.nFatJet): for j in range(nSystematics): selectedVphi = Vphi_syst[systematics[j]] if ( Vphi_syst is not None and systematics[j] in Vphi_syst) else Vphi #if Pt[j][i] > ptCut and abs(eta[i]) < etaCut and Msd[j][i] > msdCut and lepFilter[i]: if Pt[j][i] > ptCut and abs( eta[i]) < etaCut and Msd[j][i] > msdCut: if selectedVphi is None or abs( ROOT.TVector2.Phi_mpi_pi(selectedVphi - phi[i])) > 1.57: if tagger[i] > fatJetMaxTagger[j]: fatJetMaxTagger[j] = tagger[i] Hbb_fjidx[j] = i # return list for systematic variations given and scalar otherwise if systList is not None: return Hbb_fjidx else: return Hbb_fjidx[0] # returns indices of the two second highest b-tagged jets passing the selection, if at least two exist # indices are sorted by b-tagger, descending def HighestTaggerValueBJets(self, tree, j1ptCut, j2ptCut, taggerName, puIdCut=0, jetIdCut=-1, maxJetPtCut=0, systList=None): jets = [] indices = [] nJet = tree.nJet systematics = systList if systList is not None else [None] jetTagger = getattr(tree, taggerName) Eta = tree.Jet_eta jetId = tree.Jet_jetId lepFilter = tree.Jet_lepFilter puId = tree.Jet_puId PtReg_nom = tree.Jet_PtReg Pt_nom = tree.Jet_Pt # momenta with sys variations applied PtReg = [] Pt = [] nSystematics = len(systematics) for syst in systematics: indices.append([]) if syst is None: PtReg.append(PtReg_nom) Pt.append(Pt_nom) elif syst == 'jerRegUp': PtReg.append(tree.Jet_PtRegUp) Pt.append(Pt_nom) elif syst == 'jerRegDown': PtReg.append(tree.Jet_PtRegDown) Pt.append(Pt_nom) elif syst in [ 'jerRegScaleUp', 'jerRegScaleDown', 'jerRegSmearUp', 'jerRegSmearDown' ]: PtReg.append(self._r('Jet_Pt' + syst[3:])) Pt.append(Pt_nom) else: Pt_syst = getattr(tree, "Jet_pt_" + syst) PtReg_syst = [ PtReg_nom[i] * Pt_syst[i] / Pt_nom[i] for i in range(nJet) ] Pt.append(Pt_syst) PtReg.append(PtReg_syst) for i in range(nJet): for j in range(nSystematics): pass_acceptance = PtReg[j][i] > j1ptCut and abs(Eta[i]) < 2.5 pass_jetIDandPUIDlepFilter = ( puId[i] > puIdCut or Pt[j][i] > self.puIdMaxPt ) and jetId[i] > jetIdCut and lepFilter[i] if pass_acceptance and pass_jetIDandPUIDlepFilter: if len(indices[j]) < 1: indices[j].append(i) else: if jetTagger[i] > jetTagger[indices[j][0]]: indices[j][0] = i for i in range(nJet): for j in range(nSystematics): if len(indices[j]) < 1 or i == indices[j][0]: continue pass_acceptance = PtReg[j][i] > j2ptCut and abs(Eta[i]) < 2.5 pass_jetIDandPUIDlepFilter = ( puId[i] > puIdCut or Pt[j][i] > self.puIdMaxPt ) and jetId[i] > jetIdCut and lepFilter[i] if pass_acceptance and pass_jetIDandPUIDlepFilter: if len(indices[j]) < 2: indices[j].append(i) else: if jetTagger[i] > jetTagger[indices[j][1]]: indices[j][1] = i for j in range(nSystematics): if len(indices[j]) > 1: if jetTagger[indices[j][1]] > jetTagger[indices[j][0]]: indices = [indices[j][1], indices[j][0]] if len(indices[j]) == 2 and max( PtReg[j][indices[j][0]], PtReg[j][indices[j][1]]) < maxJetPtCut: indices[j] = [] if systList is not None: return indices else: return indices[0] def processEvent(self, tree): if not self.hasBeenProcessed(tree): self.markProcessed(tree) for n in ["isZmm", "isZee", "isWenu", "isWmunu", "isZnn"]: self._b(n)[0] = 0 self._b("lepMetDPhi")[0] = -99.0 self._b("V_mt")[0] = -99.0 self._b("V_pt")[0] = -99.0 self._b("V_eta")[0] = -99.0 self._b("V_phi")[0] = -99.0 self._b("V_mass")[0] = -99.0 self._b("vLidx")[0] = -1 self._b("vLidx")[1] = -1 if not self.skipJetSelection: self._b("hJidx")[0] = -1 self._b("hJidx")[1] = -1 self.cutFlow[0] += 1 debugEvent = [tree.run, tree.event] in self.debugEvents if debugEvent: print "DEBUG-EVENT:", tree.run, tree.event # TRIGGER triggerPassed = { k: any([getattr(tree, x) for x in v if hasattr(tree, x)]) for k, v in self.HltPaths.items() } #print("------------------------------------") #for k,v in self.HltPaths.items(): # print(k,v) # for x in v: # print(x, hasattr(tree,x)) # if hasattr(tree,x): # print(getattr(tree,x)) #print(triggerPassed, "triggerPassed") #print(self.channels, "self.channels") #if not ((triggerPassed['0-lep'] and "Znn" in self.channels) or (triggerPassed['1-lep'] and "Wln" in self.channels) or (triggerPassed['2-lep'] and "Zll" in self.channels)): if debugEvent: print "triggers:", triggerPassed Vtype = tree.Vtype if self.recomputeVtype: leptonSelector = vLeptonSelector(tree, config=self.config, isoZmm=self.isoZmm, isoZee=self.isoZee, isoWmn=self.isoWmn, isoWen=self.isoWen) customVtype = leptonSelector.getVtype() if customVtype != Vtype: self.count("recomputeVtype_mismatch") else: self.count("recomputeVtype_match") self.count("recomputeVtype_Vtype%d" % customVtype) Vtype = customVtype isZnn = Vtype == 4 and triggerPassed['Znn'] isWln = Vtype in [2, 3] and triggerPassed['Wln'] isZll = Vtype in [0, 1] and triggerPassed['Zll'] if not any([isZll, isWln, isZnn]): return False self.cutFlow[1] += 1 # LEPTONS if self.sample.identifier not in self.leptonFlav or self.leptonFlav[ self.sample.identifier] == Vtype: if Vtype == 0: good_muons_2lep = self.HighestPtGoodMuonsOppCharge( tree, min_pt=20.0, max_rel_iso=self.isoZmm, idcut=self.idZmmCut, etacut=2.4, isOneLepton=False, muonID=self.idZmm) if len(good_muons_2lep) > 1: self._b("isZmm")[0] = 1 self._b("vLidx")[0] = good_muons_2lep[0] self._b("vLidx")[1] = good_muons_2lep[1] elif debugEvent: print "DEBUG-EVENT: 2 mu event, but less than 2 good muons -> discard" elif Vtype == 1: good_elecs_2lep = self.HighestPtGoodElectronsOppCharge( tree, min_pt=20.0, max_rel_iso=self.isoZee, idcut=self.idZeeCut, etacut=2.5, isOneLepton=False, electronID=self.idZee) if len(good_elecs_2lep) > 1: self._b("isZee")[0] = 1 self._b("vLidx")[0] = good_elecs_2lep[0] self._b("vLidx")[1] = good_elecs_2lep[1] elif debugEvent: print "DEBUG-EVENT: 2 e event, but less than 2 good electrons -> discard" elif Vtype == 2: good_muons_1lep = self.HighestPtGoodMuonsOppCharge( tree, min_pt=25.0, max_rel_iso=self.isoWmn, idcut=self.idWmnCut, etacut=2.4, isOneLepton=True, muonID=self.idWmn) if len(good_muons_1lep) > 0: self._b("isWmunu")[0] = 1 self._b("vLidx")[0] = good_muons_1lep[0] self._b("vLidx")[1] = -1 elif debugEvent: print "DEBUG-EVENT: 1 mu event, but no good muon found" elif Vtype == 3: good_elecs_1lep = self.HighestPtGoodElectronsOppCharge( tree, min_pt=30.0, max_rel_iso=self.isoWen, idcut=self.idWenCut, etacut=2.5, isOneLepton=True, electronID=self.idWen) if len(good_elecs_1lep) > 0: self._b("isWenu")[0] = 1 self._b("vLidx")[0] = good_elecs_1lep[0] self._b("vLidx")[1] = -1 elif debugEvent: print "DEBUG-EVENT: 1 e event, but no good electron found" elif Vtype == 4: passMetFilters = all( [getattr(tree, x) for x in self.metFilters]) if tree.MET_Pt > self.vpt0lep and passMetFilters: self._b("isZnn")[0] = 1 else: if debugEvent: print "DEBUG-EVENT: 0 lep event, but MET criteria not passed!" return False else: return False else: return False self.cutFlow[2] += 1 # CHANNEL if (self._b("isZmm")[0] or self._b("isZee")[0]) and not ("Zll" in self.channels): return False #elif (self._b("isWmunu")[0] or self._b("isWenu")[0]) and not ("Wln" in self.channels or "Znn" in self.channels): # update: now 1-lepton events are only needed for 1-lepton channel (before they were also needed for 0-lepton channel for tt CR) elif (self._b("isWmunu")[0] or self._b("isWenu")[0]) and not ("Wln" in self.channels): return False elif (self._b("isZnn")[0]) and not ("Znn" in self.channels): return False self.cutFlow[3] += 1 # VECTOR BOSON Vphi_syst = {} any_v_sysvar_passes = False if self._b("isZee")[0] or self._b("isZmm")[0]: lep1 = ROOT.TLorentzVector() lep2 = ROOT.TLorentzVector() i1 = self._b("vLidx")[0] i2 = self._b("vLidx")[1] if self._b("isZee")[0]: lep1.SetPtEtaPhiM(tree.Electron_pt[i1], tree.Electron_eta[i1], tree.Electron_phi[i1], tree.Electron_mass[i1]) lep2.SetPtEtaPhiM(tree.Electron_pt[i2], tree.Electron_eta[i2], tree.Electron_phi[i2], tree.Electron_mass[i2]) elif self._b("isZmm")[0]: lep1.SetPtEtaPhiM(tree.Muon_pt[i1], tree.Muon_eta[i1], tree.Muon_phi[i1], tree.Muon_mass[i1]) lep2.SetPtEtaPhiM(tree.Muon_pt[i2], tree.Muon_eta[i2], tree.Muon_phi[i2], tree.Muon_mass[i2]) V = lep1 + lep2 elif self._b("isWenu")[0] or self._b("isWmunu")[0]: i1 = self._b("vLidx")[0] if self._b("isWenu")[0]: sel_lepton_pt = tree.Electron_pt[i1] sel_lepton_eta = tree.Electron_eta[i1] sel_lepton_phi = tree.Electron_phi[i1] sel_lepton_mass = tree.Electron_mass[i1] elif self._b("isWmunu")[0]: sel_lepton_pt = tree.Muon_pt[i1] sel_lepton_eta = tree.Muon_eta[i1] sel_lepton_phi = tree.Muon_phi[i1] sel_lepton_mass = tree.Muon_mass[i1] self._b("lepMetDPhi")[0] = abs( ROOT.TVector2.Phi_mpi_pi(sel_lepton_phi - tree.MET_Phi)) #if self._b("lepMetDPhi")[0] > 2.0: # return False MET = ROOT.TLorentzVector() Lep = ROOT.TLorentzVector() MET.SetPtEtaPhiM(tree.MET_Pt, 0.0, tree.MET_Phi, 0.0) Lep.SetPtEtaPhiM(sel_lepton_pt, sel_lepton_eta, sel_lepton_phi, sel_lepton_mass) cosPhi12 = (Lep.Px() * MET.Px() + Lep.Py() * MET.Py()) / (Lep.Pt() * MET.Pt()) self._b("V_mt")[0] = ROOT.TMath.Sqrt(2 * Lep.Pt() * MET.Pt() * (1 - cosPhi12)) V = MET + Lep if self.sample.isMC(): MET_syst = ROOT.TLorentzVector() for syst in self.METsystematics: for UD in self._variations(syst): MET_syst.SetPtEtaPhiM( self._r('MET_pt_' + syst + UD), 0.0, self._r('MET_phi_' + syst + UD), 0.0) V_syst = MET_syst + Lep Vphi_syst[syst + UD] = V_syst.Phi() if V_syst.Pt() > self.vpt1lep: any_v_sysvar_passes = True elif self._b("isZnn")[0]: MET = ROOT.TLorentzVector() MET.SetPtEtaPhiM(tree.MET_Pt, 0.0, tree.MET_Phi, 0.0) if self.sample.isMC(): for syst in self.METsystematics: for UD in self._variations(syst): Vphi_syst[syst + UD] = self._r('MET_phi_' + syst + UD) if self._r('MET_pt_' + syst + UD) > self.vpt0lep: any_v_sysvar_passes = True V = MET else: self.count("fail_lepton_selection") return False self.cutFlow[4] += 1 self._b("V_pt")[0] = V.Pt() self._b("V_eta")[0] = V.Eta() self._b("V_phi")[0] = V.Phi() self._b("V_mass")[0] = V.M() if (self._b("isZee")[0] or self._b("isZmm")[0]) and self._b("V_pt")[0] < self.vpt2lep: return False elif self._b("isZnn")[0] and self._b( "V_pt")[0] < self.vpt0lep and not any_v_sysvar_passes: return False elif (self._b("isWenu")[0] or self._b("isWmunu")[0]) and (self._b("V_pt")[0] < self.vpt1lep and not any_v_sysvar_passes): return False self.cutFlow[5] += 1 if self.skipJetSelection: self.cutFlow[7] += 1 return True # JETS if self._b("isZnn")[0]: j1ptCut = 35.0 j2ptCut = 35.0 maxJetPtCut = 60.0 j1BtagName = 'loose' elif self._b("isWmunu")[0] or self._b("isWenu")[0]: j1ptCut = 25.0 j2ptCut = 25.0 maxJetPtCut = 0.0 j1BtagName = 'loose' elif self._b("isZmm")[0] or self._b("isZee")[0]: j1ptCut = 20.0 j2ptCut = 20.0 maxJetPtCut = 0.0 j1BtagName = 'none' else: return False j2BtagName = 'none' # btagMaxCut can overwrite the default b-tag max cut if self.btagMaxCut is not None and len(self.btagMaxCut) > 0: j1BtagName = self.btagMaxCut any_taggerPassed_syst = False for jetDefinition in self.jetDefinitions: indexName = jetDefinition[ 'indexName'] if 'indexName' in jetDefinition else '' taggerName = jetDefinition['taggerName'] j1Btag = self.btagWPs[self.year][taggerName][j1BtagName] j2Btag = self.btagWPs[self.year][taggerName][j2BtagName] jetTagger = getattr(tree, taggerName) taggerSelection = lambda x: (len(x) == 2 and jetTagger[x[ 0]] >= j1Btag and jetTagger[x[1]] >= j2Btag) # -> nominal selectedJets = self.HighestTaggerValueBJets( tree, j1ptCut, j2ptCut, taggerName, puIdCut=self.puIdCut, jetIdCut=self.jetIdCut, maxJetPtCut=maxJetPtCut, systList=None) taggerPassed = taggerSelection(selectedJets) if taggerPassed: self._b("hJidx" + indexName)[0] = selectedJets[0] self._b("hJidx" + indexName)[1] = selectedJets[1] any_taggerPassed_syst = True self.count("pass_tagger_" + taggerName) else: if debugEvent: print("DEBUG-EVENT: did not pass jet-selection.") print("DEBUG-EVENT: selected jets:", selectedJets) print("DEBUG-EVENT: passed btag cuts:", taggerPassed) self._b("hJidx" + indexName)[0] = -1 self._b("hJidx" + indexName)[1] = -1 # -> systematic variations if self.sample.isMC(): systList = [ "".join(x) for x in itertools.product( self.systematics, ["Up", "Down"]) ] nSystematics = len(systList) # this returns a list of lists of jet indices for all systematic variations selectedJets = self.HighestTaggerValueBJets( tree, j1ptCut, j2ptCut, taggerName, puIdCut=self.puIdCut, jetIdCut=self.jetIdCut, maxJetPtCut=maxJetPtCut, systList=systList) # apply pre-selection on tagger for j in range(nSystematics): hJidxName_syst = "hJidx{suffix}_{syst}".format( suffix=indexName, syst=systList[j]) if taggerSelection(selectedJets[j]): self._b(hJidxName_syst)[0] = selectedJets[j][0] self._b(hJidxName_syst)[1] = selectedJets[j][1] any_taggerPassed_syst = True else: self._b(hJidxName_syst)[0] = -1 self._b(hJidxName_syst)[1] = -1 #print tree.Hbb_fjidx,tree.FatJet_pt[tree.Hbb_fjidx] if(tree.Hbb_fjidx>-1) else "outside",V.Pt() # BOOSTED JET selection any_boostedJet_syst = False # nominal Hbb_fjidx = self.HighestTaggerValueFatJet( tree, ptCut=250.0, msdCut=50.0, etaCut=2.5, taggerName='FatJet_deepTagMD_bbvsLight', systList=None, Vphi=V.Phi()) self._b("Hbb_fjidx")[0] = Hbb_fjidx if Hbb_fjidx > -1: any_boostedJet_syst = True # systematics if self.sample.isMC(): systList = [ "".join(x) for x in itertools.product( self.systematicsBoosted, ["Up", "Down"]) ] nSystematics = len(systList) # return list of jet indices for systematic variations Hbb_fjidx_syst = self.HighestTaggerValueFatJet( tree, ptCut=250.0, msdCut=50.0, etaCut=2.5, taggerName='FatJet_deepTagMD_bbvsLight', systList=systList, Vphi=V.Phi(), Vphi_syst=Vphi_syst) for j in range(nSystematics): fJidxName_syst = "Hbb_fjidx_{syst}".format( syst=systList[j]) self._b(fJidxName_syst)[0] = Hbb_fjidx_syst[j] if Hbb_fjidx_syst[j] > -1: any_boostedJet_syst = True #boostedPass = (tree.Hbb_fjidx>-1 and tree.FatJet_Pt[tree.Hbb_fjidx]>250 and V.Pt()>250) #AC: selection for boosted analysis boostedPass = (any_boostedJet_syst and V.Pt() > 250) if boostedPass: self.count("pass_boosted") # discard event if none of the jet selections finds two Higgs candidate jets #if not (boostedPass or defaultTaggerPassed or any([jets['isSelected'] for jets in self.jetDefinitions])): if not (boostedPass or any_taggerPassed_syst): return False self.cutFlow[6] += 1 # yield in the end self.cutFlow[7] += 1 if debugEvent: print "DEBUG-EVENT: event passed!!!" return True def afterProcessing(self): super(VHbbSelection, self).afterProcessing() print "cut-flow:" print " beginning ", self.cutFlow[0] print " HLT ", self.cutFlow[1] print " Leptons ", self.cutFlow[2] print " Channel ", self.cutFlow[3] print " Vector boson ", self.cutFlow[4] print " Vpt ", self.cutFlow[5] print " Jets ", self.cutFlow[6] print " end ", self.cutFlow[7] print "efficiency:", (1.0 * self.cutFlow[7] / self.cutFlow[0]) if self.cutFlow[0] > 0 else "-"
class isBoosted(AddCollectionsModule): def __init__(self, branchName='isBoosted', cutName='all_BOOST', useFlags=False, flags=None): super(isBoosted, self).__init__() self.branchName = branchName self.cutName = cutName self.version = 4 self.useFlags = useFlags self.flags = ['resolvedCR', 'resolvedSR', 'boostedCR', 'boostedSR' ] if flags is None else flags self.variations = self._variations("isBoosted") # returns cut string with variables replaced by their systematic variations def getSystVarCut(self, cut, syst, UD): replacementRulesList = XbbTools.getReplacementRulesList( self.config, syst) systVarCut = XbbTools.getSystematicsVariationTemplate( cut, replacementRulesList) systVarCut = systVarCut.replace('{syst}', syst).replace('{UD}', UD) return systVarCut def customInit(self, initVars): self.sample = initVars['sample'] self.sampleTree = initVars['sampleTree'] self.config = initVars['config'] self.xbbConfig = XbbConfigTools(self.config) self.boostedCut = XbbTools.sanitizeExpression(self.config.get( 'Cuts', self.cutName), config=self.config) self.systVarCuts = {} #self.systematics = sorted(list(set(sum([eval(self.config.get('LimitGeneral', x)) for x in ['sys_cr', 'sys_BDT', 'sys_Mjj']], [])))) self.systematics = self.xbbConfig.getJECuncertainties( step='BoostedFlags') + ['jms', 'jmr', 'unclustEn'] # Nominal self.addIntegerBranch(self.branchName) self.sampleTree.addFormula(self.boostedCut) # systematic variations if self.sample.isMC(): for syst in self.systematics: for UD in self.variations: systVarBranchName = self._v(self.branchName, syst, UD) self.addIntegerBranch(systVarBranchName) self.systVarCuts[systVarBranchName] = self.getSystVarCut( self.boostedCut, syst=syst, UD=UD) self.sampleTree.addFormula( self.systVarCuts[systVarBranchName]) if self.useFlags: # CR/SR flags self.flagCuts = { k: XbbTools.sanitizeExpression(self.config.get('Cuts', k), config=self.config) for k in self.flags } self.systVarFlagCuts = {k: {} for k in self.flags} for k in self.flags: self.sampleTree.addFormula(self.flagCuts[k]) self.addIntegerBranch(k) # systematic variations if self.sample.isMC(): for k in self.flags: for syst in self.systematics: for UD in self.variations: systVarflagName = self._v(k, syst, UD) self.addIntegerBranch(systVarflagName) self.systVarFlagCuts[k][ systVarflagName] = XbbTools.sanitizeExpression( self.getSystVarCut(self.flagCuts[k], syst=syst, UD=UD), config=self.config) self.sampleTree.addFormula( self.systVarFlagCuts[k][systVarflagName]) def processEvent(self, tree): # if current entry has not been processed yet if not self.hasBeenProcessed(tree): self.markProcessed(tree) # Nominal b = int(self.sampleTree.evaluate(self.boostedCut)) self._b(self._v(self.branchName))[0] = 1 if b > 0 else 0 # systematic variations if self.sample.isMC(): for syst in self.systematics: for UD in self.variations: systVarBranchName = self._v(self.branchName, syst, UD) b = int( self.sampleTree.evaluate( self.systVarCuts[systVarBranchName])) self._b(systVarBranchName)[0] = 1 if b > 0 else 0 if self.useFlags: # CR/SR flags for k in self.flags: b = int(self.sampleTree.evaluate(self.flagCuts[k])) self._b(self._v(k))[0] = 1 if b > 0 else 0 if self.sample.isMC(): for k in self.flags: for syst in self.systematics: for UD in self.variations: systVarflagName = self._v(k, syst, UD) b = int( self.sampleTree.evaluate( self.systVarFlagCuts[k] [systVarflagName])) self._b(systVarflagName)[0] = 1 if b > 0 else 0