def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName) if not self.isData: genJets = Collection(event, self.genJetBranchName) if self.doGroomed: subJets = Collection(event, self.subJetBranchName) if not self.isData: genSubJets = Collection(event, self.genSubJetBranchName) genSubJetMatcher = matchObjectCollectionMultiple(genJets, genSubJets, dRmax=0.8) if not self.isData: self.jetSmearer.setSeed(event) jets_pt_raw = [] jets_pt_nom = [] jets_mass_raw = [] jets_mass_nom = [] jets_corr_JEC = [] jets_corr_JER = [] jets_corr_JMS = [] jets_corr_JMR = [] jets_pt_jerUp = {} jets_pt_jerDown = {} jets_pt_jesUp = {} jets_pt_jesDown = {} jets_mass_jerUp = {} jets_mass_jerDown = {} jets_mass_jmrUp = [] jets_mass_jmrDown = [] jets_mass_jesUp = {} jets_mass_jesDown = {} jets_mass_jmsUp = [] jets_mass_jmsDown = [] for jerID in self.splitJERIDs: jets_pt_jerUp[jerID] = [] jets_pt_jerDown[jerID] = [] jets_mass_jerUp[jerID] = [] jets_mass_jerDown[jerID] = [] for jesUncertainty in self.jesUncertainties: jets_pt_jesUp[jesUncertainty] = [] jets_pt_jesDown[jesUncertainty] = [] jets_mass_jesUp[jesUncertainty] = [] jets_mass_jesDown[jesUncertainty] = [] if self.doGroomed: jets_msdcorr_raw = [] jets_msdcorr_nom = [] jets_msdcorr_corr_JMR = [] jets_msdcorr_corr_JMS = [] jets_msdcorr_corr_PUPPI = [] jets_msdcorr_jerUp = {} jets_msdcorr_jerDown = {} jets_msdcorr_jmrUp = [] jets_msdcorr_jmrDown = [] jets_msdcorr_jesUp = {} jets_msdcorr_jesDown = {} jets_msdcorr_jmsUp = [] jets_msdcorr_jmsDown = [] jets_msdcorr_tau21DDT_nom = [] jets_msdcorr_tau21DDT_jerUp = {} jets_msdcorr_tau21DDT_jerDown = {} jets_msdcorr_tau21DDT_jmrUp = [] jets_msdcorr_tau21DDT_jmrDown = [] jets_msdcorr_tau21DDT_jmsUp = [] jets_msdcorr_tau21DDT_jmsDown = [] for jerID in self.splitJERIDs: jets_msdcorr_jerUp[jerID] = [] jets_msdcorr_jerDown[jerID] = [] jets_msdcorr_tau21DDT_jerUp[jerID] = [] jets_msdcorr_tau21DDT_jerDown[jerID] = [] for jesUncertainty in self.jesUncertainties: jets_msdcorr_jesUp[jesUncertainty] = [] jets_msdcorr_jesDown[jesUncertainty] = [] rho = getattr(event, self.rhoBranchName) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) if not self.isData: pairs = matchObjectCollection(jets, genJets) for jet in jets: # jet pt and mass corrections jet_pt = jet.pt jet_mass = jet.mass if hasattr(jet, "rawFactor"): jet_rawpt = jet_pt * (1 - jet.rawFactor) jet_rawmass = jet_mass * (1 - jet.rawFactor) else: jet_rawpt = -1.0 * jet_pt # If factor not present factor will be saved as -1 jet_rawmass = -1.0 * jet_mass # If factor not present factor will be saved as -1 (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet, rho) jet.pt = jet_pt jet.mass = jet_mass jets_pt_raw.append(jet_rawpt) jets_mass_raw.append(jet_rawmass) jets_corr_JEC.append(jet_pt / jet_rawpt) if not self.isData: genJet = pairs[jet] # evaluate JER scale factors and uncertainties # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution ) if not self.isData: (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt( jet, genJet, rho) else: # set values to 1 for data so that jet_pt_nom is not smeared (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = (1, 1, 1) jets_corr_JER.append(jet_pt_jerNomVal) jet_pt_nom = jet_pt_jerNomVal * jet_pt if self.applySmearing else jet_pt if jet_pt_nom < 0.0: jet_pt_nom *= -1.0 jets_pt_nom.append(jet_pt_nom) # Evaluate JMS and JMR scale factors and uncertainties jmsNomVal, jmsDownVal, jmsUpVal = self.jmsVals if not self.isData else ( 1, 1, 1) if not self.isData: (jet_mass_jmrNomVal, jet_mass_jmrUpVal, jet_mass_jmrDownVal) = self.jetSmearer.getSmearValsM( jet, genJet) else: # set values to 1 for data so that jet_mass_nom is not smeared (jet_mass_jmrNomVal, jet_mass_jmrUpVal, jet_mass_jmrDownVal) = (1, 1, 1) jets_corr_JMS.append(jmsNomVal) jets_corr_JMR.append(jet_mass_jmrNomVal) jet_mass_nom = jet_pt_jerNomVal * jet_mass_jmrNomVal * \ jmsNomVal * jet_mass if self.applySmearing else jet_mass if jet_mass_nom < 0.0: jet_mass_nom *= -1.0 jets_mass_nom.append(jet_mass_nom) if not self.isData: jet_pt_jerUp = { jerID: jet_pt_nom for jerID in self.splitJERIDs } jet_pt_jerDown = { jerID: jet_pt_nom for jerID in self.splitJERIDs } jet_mass_jerUp = { jerID: jet_mass_nom for jerID in self.splitJERIDs } jet_mass_jerDown = { jerID: jet_mass_nom for jerID in self.splitJERIDs } thisJERID = self.getJERsplitID(jet_pt_nom, jet.eta) jet_pt_jerUp[thisJERID] = jet_pt_jerUpVal * jet_pt jet_pt_jerDown[thisJERID] = jet_pt_jerDownVal * jet_pt jet_mass_jerUp[thisJERID] = jet_pt_jerUpVal * \ jet_mass_jmrNomVal * jmsNomVal * jet_mass jet_mass_jerDown[thisJERID] = jet_pt_jerDownVal * \ jet_mass_jmrNomVal * jmsNomVal * jet_mass for jerID in self.splitJERIDs: jets_pt_jerUp[jerID].append(jet_pt_jerUp[jerID]) jets_pt_jerDown[jerID].append(jet_pt_jerDown[jerID]) jets_mass_jerUp[jerID].append(jet_mass_jerUp[jerID]) jets_mass_jerDown[jerID].append(jet_mass_jerDown[jerID]) jets_mass_jmrUp.append(jet_pt_jerNomVal * jet_mass_jmrUpVal * jmsNomVal * jet_mass) jets_mass_jmrDown.append(jet_pt_jerNomVal * jet_mass_jmrDownVal * jmsNomVal * jet_mass) jets_mass_jmsUp.append(jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsUpVal * jet_mass) jets_mass_jmsDown.append(jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsDownVal * jet_mass) if self.doGroomed: if not self.isData: genGroomedSubJets = genSubJetMatcher[ genJet] if genJet is not None else None genGroomedJet = genGroomedSubJets[0].p4( ) + genGroomedSubJets[1].p4( ) if genGroomedSubJets is not None and len( genGroomedSubJets) >= 2 else None else: genGroomedSubJets = None genGroomedJet = None if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0: groomedP4 = subJets[jet.subJetIdx1].p4() + subJets[ jet.subJetIdx2].p4() # check subjet jecs else: groomedP4 = None jet_msdcorr_raw = groomedP4.M( ) if groomedP4 is not None else 0.0 # raw value always stored withoud mass correction jets_msdcorr_raw.append(jet_msdcorr_raw) # LC: Apply PUPPI SD mass correction https://github.com/cms-jet/PuppiSoftdropMassCorr/ puppisd_genCorr = self.puppisd_corrGEN.Eval(jet.pt) if abs(jet.eta) <= 1.3: puppisd_recoCorr = self.puppisd_corrRECO_cen.Eval(jet.pt) else: puppisd_recoCorr = self.puppisd_corrRECO_for.Eval(jet.pt) puppisd_total = puppisd_genCorr * puppisd_recoCorr jets_msdcorr_corr_PUPPI.append(puppisd_total) if groomedP4 is not None: groomedP4.SetPtEtaPhiM(groomedP4.Perp(), groomedP4.Eta(), groomedP4.Phi(), groomedP4.M() * puppisd_total) # now apply the mass correction to the raw value jet_msdcorr_raw = groomedP4.M( ) if groomedP4 is not None else 0.0 if jet_msdcorr_raw < 0.0: jet_msdcorr_raw *= -1.0 # Evaluate JMS and JMR scale factors and uncertainties if not self.isData: (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal, jet_msdcorr_jmrDownVal) = \ (self.jetSmearer.getSmearValsM(groomedP4, genGroomedJet) if groomedP4 is not None and genGroomedJet is not None else (0., 0., 0.)) else: (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal, jet_msdcorr_jmrDownVal) = (1, 1, 1) jets_msdcorr_corr_JMS.append(jmsNomVal) jets_msdcorr_corr_JMR.append(jet_msdcorr_jmrNomVal) jet_msdcorr_nom = jet_pt_jerNomVal * \ jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw # store the nominal mass value jets_msdcorr_nom.append(jet_msdcorr_nom) if not self.isData: jet_msdcorr_jerUp = { jerID: jet_msdcorr_nom for jerID in self.splitJERIDs } jet_msdcorr_jerDown = { jerID: jet_msdcorr_nom for jerID in self.splitJERIDs } thisJERID = self.getJERsplitID(jet_pt_nom, jet.eta) jet_msdcorr_jerUp[thisJERID] = jet_pt_jerUpVal * \ jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw jet_msdcorr_jerDown[thisJERID] = jet_pt_jerDownVal * \ jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw for jerID in self.splitJERIDs: jets_msdcorr_jerUp[jerID].append( jet_msdcorr_jerUp[jerID]) jets_msdcorr_jerDown[jerID].append( jet_msdcorr_jerDown[jerID]) jets_msdcorr_jmrUp.append( jet_pt_jerNomVal * jet_msdcorr_jmrUpVal * jmsNomVal * jet_msdcorr_raw) jets_msdcorr_jmrDown.append( jet_pt_jerNomVal * jet_msdcorr_jmrDownVal * jmsNomVal * jet_msdcorr_raw) jets_msdcorr_jmsUp.append( jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsUpVal * jet_msdcorr_raw) jets_msdcorr_jmsDown.append( jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsDownVal * jet_msdcorr_raw) # Also evaluated JMS&JMR SD corr in tau21DDT region: https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetWtagging#tau21DDT_0_43 if self.era in ["2016"]: jmstau21DDTNomVal = 1.014 jmstau21DDTDownVal = 1.007 jmstau21DDTUpVal = 1.021 self.jetSmearer.jmr_vals = [1.086, 1.176, 0.996] elif self.era in ["2017"]: jmstau21DDTNomVal = 0.983 jmstau21DDTDownVal = 0.976 jmstau21DDTUpVal = 0.99 self.jetSmearer.jmr_vals = [1.080, 1.161, 0.999] elif self.era in ["2018"]: jmstau21DDTNomVal = 1.000 # tau21DDT < 0.43 WP jmstau21DDTDownVal = 0.990 jmstau21DDTUpVal = 1.010 self.jetSmearer.jmr_vals = [1.124, 1.208, 1.040] ( jet_msdcorr_tau21DDT_jmrNomVal, jet_msdcorr_tau21DDT_jmrUpVal, jet_msdcorr_tau21DDT_jmrDownVal ) = self.jetSmearer.getSmearValsM( groomedP4, genGroomedJet ) if groomedP4 is not None and genGroomedJet is not None else ( 0., 0., 0.) jet_msdcorr_tau21DDT_nom = jet_pt_jerNomVal * \ jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTNomVal * jet_msdcorr_raw jets_msdcorr_tau21DDT_nom.append(jet_msdcorr_tau21DDT_nom) jet_msdcorr_tau21DDT_jerUp = { jerID: jet_msdcorr_tau21DDT_nom for jerID in self.splitJERIDs } jet_msdcorr_tau21DDT_jerDown = { jerID: jet_msdcorr_tau21DDT_nom for jerID in self.splitJERIDs } jet_msdcorr_tau21DDT_jerUp[thisJERID] = jet_pt_jerUpVal * \ jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTNomVal * jet_msdcorr_raw jet_msdcorr_tau21DDT_jerDown[thisJERID] = jet_pt_jerDownVal * \ jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTNomVal * jet_msdcorr_raw for jerID in self.splitJERIDs: jets_msdcorr_tau21DDT_jerUp[jerID].append( jet_msdcorr_tau21DDT_jerUp[jerID]) jets_msdcorr_tau21DDT_jerDown[jerID].append( jet_msdcorr_tau21DDT_jerDown[jerID]) jets_msdcorr_tau21DDT_jmrUp.append( jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrUpVal * jmstau21DDTNomVal * jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmrDown.append( jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrDownVal * jmstau21DDTNomVal * jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmsUp.append( jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTUpVal * jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmsDown.append( jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTDownVal * jet_msdcorr_raw) # Restore original jmr_vals in jetSmearer self.jetSmearer.jmr_vals = self.jmrVals if not self.isData: # evaluate JES uncertainties jet_pt_jesUp = {} jet_pt_jesDown = {} jet_mass_jesUp = {} jet_mass_jesDown = {} jet_msdcorr_jesUp = {} jet_msdcorr_jesDown = {} for jesUncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties) # cf. https://hypernews.cern.ch/HyperNews/CMS/get/JetMET/2000.html if jesUncertainty == "HEMIssue": delta = 1. if jet_pt_nom > 15 and jet.jetId & 2 and jet.phi > -1.57 and jet.phi < -0.87: if jet.eta > -2.5 and jet.eta < -1.3: delta = 0.8 elif jet.eta <= -2.5 and jet.eta > -3: delta = 0.65 jet_pt_jesUp[jesUncertainty] = jet_pt_nom jet_pt_jesDown[jesUncertainty] = delta * jet_pt_nom jet_mass_jesUp[jesUncertainty] = jet_mass_nom jet_mass_jesDown[jesUncertainty] = delta * jet_mass_nom if self.doGroomed: jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom jet_msdcorr_jesDown[jesUncertainty] = delta * \ jet_msdcorr_nom else: self.jesUncertainty[jesUncertainty].setJetPt( jet_pt_nom) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[ jesUncertainty].getUncertainty(True) jet_pt_jesUp[jesUncertainty] = jet_pt_nom * \ (1. + delta) jet_pt_jesDown[jesUncertainty] = jet_pt_nom * \ (1. - delta) jet_mass_jesUp[jesUncertainty] = jet_mass_nom * \ (1. + delta) jet_mass_jesDown[jesUncertainty] = jet_mass_nom * \ (1. - delta) if self.doGroomed: jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom * \ (1. + delta) jet_msdcorr_jesDown[ jesUncertainty] = jet_msdcorr_nom * (1. - delta) jets_pt_jesUp[jesUncertainty].append( jet_pt_jesUp[jesUncertainty]) jets_pt_jesDown[jesUncertainty].append( jet_pt_jesDown[jesUncertainty]) jets_mass_jesUp[jesUncertainty].append( jet_mass_jesUp[jesUncertainty]) jets_mass_jesDown[jesUncertainty].append( jet_mass_jesDown[jesUncertainty]) if self.doGroomed: jets_msdcorr_jesUp[jesUncertainty].append( jet_msdcorr_jesUp[jesUncertainty]) jets_msdcorr_jesDown[jesUncertainty].append( jet_msdcorr_jesDown[jesUncertainty]) self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw) self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom) self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC) self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw) self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom) if not self.isData: self.out.fillBranch("%s_corr_JER" % self.jetBranchName, jets_corr_JER) self.out.fillBranch("%s_corr_JMS" % self.jetBranchName, jets_corr_JMS) self.out.fillBranch("%s_corr_JMR" % self.jetBranchName, jets_corr_JMR) for jerID in self.splitJERIDs: self.out.fillBranch( "%s_pt_jer%sUp" % (self.jetBranchName, jerID), jets_pt_jerUp[jerID]) self.out.fillBranch( "%s_pt_jer%sDown" % (self.jetBranchName, jerID), jets_pt_jerDown[jerID]) self.out.fillBranch( "%s_mass_jer%sUp" % (self.jetBranchName, jerID), jets_mass_jerUp[jerID]) self.out.fillBranch( "%s_mass_jer%sDown" % (self.jetBranchName, jerID), jets_mass_jerDown[jerID]) self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName, jets_mass_jmrUp) self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName, jets_mass_jmrDown) self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName, jets_mass_jmsUp) self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName, jets_mass_jmsDown) if self.doGroomed: self.out.fillBranch("%s_msoftdrop_raw" % self.jetBranchName, jets_msdcorr_raw) self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName, jets_msdcorr_nom) self.out.fillBranch("%s_msoftdrop_corr_JMS" % self.jetBranchName, jets_msdcorr_corr_JMS) self.out.fillBranch("%s_msoftdrop_corr_JMR" % self.jetBranchName, jets_msdcorr_corr_JMR) self.out.fillBranch("%s_msoftdrop_corr_PUPPI" % self.jetBranchName, jets_msdcorr_corr_PUPPI) if not self.isData: self.out.fillBranch( "%s_msoftdrop_tau21DDT_nom" % self.jetBranchName, jets_msdcorr_tau21DDT_nom) for jerID in self.splitJERIDs: self.out.fillBranch( "%s_msoftdrop_jer%sUp" % (self.jetBranchName, jerID), jets_msdcorr_jerUp[jerID]) self.out.fillBranch( "%s_msoftdrop_jer%sDown" % (self.jetBranchName, jerID), jets_msdcorr_jerDown[jerID]) self.out.fillBranch( "%s_msoftdrop_tau21DDT_jer%sUp" % (self.jetBranchName, jerID), jets_msdcorr_tau21DDT_jerUp[jerID]) self.out.fillBranch( "%s_msoftdrop_tau21DDT_jer%sDown" % (self.jetBranchName, jerID), jets_msdcorr_tau21DDT_jerDown[jerID]) self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName, jets_msdcorr_jmrUp) self.out.fillBranch( "%s_msoftdrop_jmrDown" % self.jetBranchName, jets_msdcorr_jmrDown) self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName, jets_msdcorr_jmsUp) self.out.fillBranch( "%s_msoftdrop_jmsDown" % self.jetBranchName, jets_msdcorr_jmsDown) self.out.fillBranch( "%s_msoftdrop_tau21DDT_jmrUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jmrUp) self.out.fillBranch( "%s_msoftdrop_tau21DDT_jmrDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jmrDown) self.out.fillBranch( "%s_msoftdrop_tau21DDT_jmsUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jmsUp) self.out.fillBranch( "%s_msoftdrop_tau21DDT_jmsDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jmsDown) if not self.isData: for jesUncertainty in self.jesUncertainties: self.out.fillBranch( "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_pt_jesUp[jesUncertainty]) self.out.fillBranch( "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_pt_jesDown[jesUncertainty]) self.out.fillBranch( "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_mass_jesUp[jesUncertainty]) self.out.fillBranch( "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_mass_jesDown[jesUncertainty]) if self.doGroomed: self.out.fillBranch( "%s_msoftdrop_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesUp[jesUncertainty]) self.out.fillBranch( "%s_msoftdrop_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesDown[jesUncertainty]) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" leptonSel(event) for elect in event.allelectrons: self.h_eCorr_vs_eta.Fill(elect.eCorr, elect.eta) self.h_eCorr_vs_phi.Fill(elect.eCorr, elect.phi) self.h_eCorr_vs_pt.Fill(elect.eCorr, elect.pt) Jets = Collection(event, "Jet") met = Object(event, "MET") genmet = Object(event, "GenMET") if self.isMC or self.isSig: Gen = Collection(event, "GenPart") event.genleps = [ l for l in Gen if abs(l.pdgId) == 11 or abs(l.pdgId) == 13 ] GenTau = Collection(event, "GenVisTau") event.gentauleps = [l for l in GenTau] goodLep = [l for l in event.selectedLeptons] LepOther = [l for l in event.otherLeptons] self.out.fillBranch("nLepGood", len(goodLep)) self.out.fillBranch("nLepOther", len(LepOther)) #LepOther = goodLep leps = goodLep nlep = len(leps) # adding the ST HT filter if nlep > 0: ST1 = leps[0].pt + met.pt self.out.fillBranch("ST1", ST1) HT1 = sum([j.pt for j in Jets if (j.pt > 30 and abs(j.eta) < 2.4)]) self.out.fillBranch("HT1", HT1) ### LEPTONS Selected = False if self.isMC == False and self.isSig == False: self.out.fillBranch("isData", 1) else: self.out.fillBranch("isData", 0) # selected good leptons selectedTightLeps = [] selectedTightLepsIdx = [] selectedVetoLeps = [] # anti-selected leptons antiTightLeps = [] antiTightLepsIdx = [] antiVetoLeps = [] for idx, lep in enumerate(leps): # for acceptance check lepEta = abs(lep.eta) # Pt cut if lep.pt < 10: continue # Iso cut -- to be compatible with the trigger if lep.miniPFRelIso_all > trig_miniIsoCut: continue ################### # MUONS ################### if (abs(lep.pdgId) == 13): if lepEta > 2.4: continue ## Lower ID is POG_LOOSE (see cfg) # ID, IP and Iso check: passID = False #if muID=='ICHEPmediumMuonId': passID = lep.ICHEPmediumMuonId -->> not needed any more passID = lep.mediumId passIso = lep.miniPFRelIso_all < muo_miniIsoCut passIP = lep.sip3d < goodMu_sip3d # selected muons if passID and passIso and passIP: selectedTightLeps.append(lep) selectedTightLepsIdx.append(idx) antiVetoLeps.append(lep) else: selectedVetoLeps.append(lep) # anti-selected muons if not passIso: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) ################### # ELECTRONS ################### elif (abs(lep.pdgId) == 11): if lepEta > eleEta: continue # pass variables passIso = False passConv = False if eleID == 'CB': # ELE CutBased ID eidCB = lep.cutBased passTightID = ( eidCB == 4 ) # and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1) # and lep.convVeto) passMediumID = ( eidCB >= 3 ) # and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1)# and lep.convVeto) #passLooseID = (eidCB >= 2) passVetoID = ( eidCB >= 1 ) # and abs(lep.dxy) < 0.2 and abs(lep.dz) < 0.5) # and lep.convVeto) # selected if passTightID: # all tight leptons are veto for anti antiVetoLeps.append(lep) # Iso check: if lep.miniPFRelIso_all < ele_miniIsoCut: passIso = True # conversion check elif eleID == 'CB': passConv = True #if lep.lostHits <= goodEl_lostHits and lep.convVeto and lep.sip3d < goodEl_sip3d else False # cuts already included in POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_X passPostICHEPHLTHOverE = True #if (lep.hoe < 0.04 and abs(lep.eta)>1.479) or abs(lep.eta)<=1.479 else False # fill if passIso and passConv and passPostICHEPHLTHOverE: selectedTightLeps.append(lep) selectedTightLepsIdx.append(idx) else: selectedVetoLeps.append(lep) # anti-selected elif not passMediumID: #passVetoID: # all anti leptons are veto for selected selectedVetoLeps.append(lep) # Iso check passIso = lep.miniPFRelIso_all < Lep_miniIsoCut # should be true anyway # other checks passOther = False if hasattr(lep, "hoe"): passOther = lep.hoe > 0.01 # fill if passIso and passOther: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) # Veto leptons elif passVetoID: # the rest is veto for selected and anti selectedVetoLeps.append(lep) antiVetoLeps.append(lep) # end lepton loop ################### # EXTRA Loop for lepOther -- for anti-selected leptons ################### otherleps = [ l for l in LepOther ] #(set(selectedTightLeps) or set(selectedVetoLeps) or set(antiTightLeps) or set(antiVetoLeps) )] nLepOther = len(otherleps) for idx, lep in enumerate(otherleps): # check acceptance lepEta = abs(lep.eta) if lepEta > 2.4: continue # Pt cut if lep.pt < 10: continue # Iso cut -- to be compatible with the trigger if lep.miniPFRelIso_all > trig_miniIsoCut: continue ############ # Muons if (abs(lep.pdgId) == 13): ## Lower ID is POG_LOOSE (see cfg) # ID, IP and Iso check: passIso = lep.miniPFRelIso_all > muo_miniIsoCut #if passIso and passID and passIP: if passIso: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) ############ # Electrons elif (abs(lep.pdgId) == 11): if (lepEta > eleEta): continue ## Iso selection: ele should have MiniIso < 0.4 (for trigger) if lep.miniPFRelIso_all > Lep_miniIsoCut: continue ## Set Ele IDs if eleID == 'CB': # ELE CutBased ID eidCB = lep.cutBased passMediumID = ( eidCB >= 3 ) # and lep.convVeto and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1) passVetoID = ( eidCB >= 1 ) #and lep.convVeto and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1) else: passMediumID = False passVetoID = False # Cuts for Anti-selected electrons if not passMediumID: # should always be true for LepOther # other checks passOther = False if hasattr(lep, "hoe"): passOther = lep.hoe > 0.01 #if not lep.conVeto: if passOther: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) elif passVetoID: #all Medium+ eles in LepOther antiVetoLeps.append(lep) ############# ############# # retrive and fill branches ############# # choose common lepton collection: select selected or anti lepton if len(selectedTightLeps) > 0: tightLeps = selectedTightLeps tightLepsIdx = selectedTightLepsIdx vetoLeps = selectedVetoLeps self.out.fillBranch("nTightLeps", len(tightLeps)) self.out.fillBranch( "nTightMu", sum([abs(lep.pdgId) == 13 for lep in tightLeps])) self.out.fillBranch( "nTightEl", sum([abs(lep.pdgId) == 11 for lep in tightLeps])) self.out.fillBranch("tightLepsIdx", tightLepsIdx) self.out.fillBranch("Selected", 1) # Is second leading lepton selected, too? if len(selectedTightLeps) > 1: self.out.fillBranch("Selected2", 1) else: self.out.fillBranch("Selected2", 0) elif len(antiTightLeps) > 0: tightLeps = antiTightLeps tightLepsIdx = antiTightLepsIdx vetoLeps = antiVetoLeps self.out.fillBranch("nTightLeps", 0) self.out.fillBranch("nTightMu", 0) self.out.fillBranch("nTightEl", 0) self.out.fillBranch("tightLepsIdx", []) self.out.fillBranch("Selected", -1) else: tightLeps = [] tightLepsIdx = [] vetoLeps = [] self.out.fillBranch("nTightLeps", 0) self.out.fillBranch("nTightMu", 0) self.out.fillBranch("nTightEl", 0) self.out.fillBranch("tightLepsIdx", []) self.out.fillBranch("Selected", 0) # store Tight and Veto lepton numbers self.out.fillBranch("nLep", len(tightLeps)) self.out.fillBranch("nVeto", len(vetoLeps)) # get number of tight el and mu tightEl = [lep for lep in tightLeps if abs(lep.pdgId) == 11] tightMu = [lep for lep in tightLeps if abs(lep.pdgId) == 13] VetoEl = [lep for lep in vetoLeps if abs(lep.pdgId) == 11] VetoMu = [lep for lep in vetoLeps if abs(lep.pdgId) == 13] self.out.fillBranch("nEl", len(tightEl)) self.out.fillBranch("nMu", len(tightMu)) for El in tightEl: # this branch is for investigating the electron energy calibraition self.out.fillBranch("TightEl_eCorr", El.eCorr) self.h_eCorr_vs_eta_tight.Fill(El.eCorr, El.eta) self.h_eCorr_vs_phi_tight.Fill(El.eCorr, El.phi) self.h_eCorr_vs_pt_tight.Fill(El.eCorr, El.pt) for El in VetoEl: self.h_eCorr_vs_eta_veto.Fill(El.eCorr, El.eta) self.h_eCorr_vs_phi_veto.Fill(El.eCorr, El.phi) self.h_eCorr_vs_pt_veto.Fill(El.eCorr, El.pt) # save leading lepton vars if len(tightLeps) > 0: # leading tight lep self.out.fillBranch("Lep_Idx", tightLepsIdx[0]) self.out.fillBranch("Lep_pt", tightLeps[0].pt) self.out.fillBranch("Lep_eta", tightLeps[0].eta) self.out.fillBranch("Lep_phi", tightLeps[0].phi) self.out.fillBranch("Lep_pdgId", tightLeps[0].pdgId) self.out.fillBranch("Lep_relIso", tightLeps[0].pfRelIso03_all) self.out.fillBranch("Lep_miniIso", tightLeps[0].miniPFRelIso_all) if hasattr(tightLeps[0], "hoe"): self.out.fillBranch("Lep_hOverE", tightLeps[0].hoe) if self.isMC: for tlep in tightLeps: if abs(tlep.pdgId) == 13: sf_mu = self._worker_mu.getSF(tlep.pdgId, tlep.pt, tlep.eta) self.out.fillBranch("lepSF", sf_mu) self.out.fillBranch("Muon_effSF", sf_mu) elif abs(tlep.pdgId) == 11: sf_el = self._worker_el.getSF(tlep.pdgId, tlep.pt, tlep.eta) self.out.fillBranch("lepSF", sf_el) self.out.fillBranch("Electron_effSF", sf_el) else: self.out.fillBranch("Muon_effSF", 1.0) self.out.fillBranch("Electron_effSF", 1.0) self.out.fillBranch("lepSF", 1.0) else: self.out.fillBranch("Muon_effSF", 1.0) self.out.fillBranch("Electron_effSF", 1.0) self.out.fillBranch("lepSF", 1.0) elif len(leps) > 0: # fill it with leading lepton self.out.fillBranch("Lep_Idx", 0) self.out.fillBranch("Lep_pt", leps[0].pt) self.out.fillBranch("Lep_eta", leps[0].eta) self.out.fillBranch("Lep_phi", leps[0].phi) self.out.fillBranch("Lep_pdgId", leps[0].pdgId) self.out.fillBranch("Lep_relIso", leps[0].pfRelIso03_all) self.out.fillBranch("Lep_miniIso", leps[0].miniPFRelIso_all) if hasattr(leps[0], "hoe"): self.out.fillBranch("Lep_hOverE", leps[0].hoe) # save second leading lepton vars if len(tightLeps) > 1: # 2nd tight lep self.out.fillBranch("Lep2_pt", tightLeps[1].pt) # print " Nlep : ", len(leps) , " nTightleps " , len(tightLeps), " nVetoLEp ", len(vetoLeps) ##################################################################### ##################################################################### #################Jets, BJets, METS and filters ###################### ##################################################################### ##################################################################### ######## ### Jets ######## metp4 = ROOT.TLorentzVector(0, 0, 0, 0) Genmetp4 = ROOT.TLorentzVector(0, 0, 0, 0) if self.isMC: Genmetp4.SetPtEtaPhiM(genmet.pt, 0, genmet.phi, 0) #self.out.fillBranch("MET", metp4.Pt()) Jets = Collection(event, "Jet") jets = [j for j in Jets if j.pt > 20 and abs(j.eta) < 2.4] njet = len(jets) (met_px, met_py) = (met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)) (met_px_nom, met_py_nom) = (met_px, met_py) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) if self.isMC and self.CorrMET: rho = getattr(event, "fixedGridRhoFastjetAll") genJets = Collection(event, "GenJet") pairs = matchObjectCollection(Jets, genJets) for jet in jets: genJet = pairs[jet] (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt( jet, genJet, rho) # exclude this from the JECs correction to follow the SUSY recipe, well see if it will slove the prefire issue if self.era == "2017": if jet.pt < 75 and (2.0 < abs(jet.eta) < 3.0): jet_pt = jet.pt * (1. - jet.rawFactor) else: jet_pt = self.jetReCalibrator.correct(jet, rho) else: jet_pt = jet.pt jet_pt_nom = jet_pt_jerNomVal * jet_pt if jet_pt_nom < 0.0: jet_pt_nom *= -1.0 jet_pt_jerUp = jet_pt_jerUpVal * jet_pt jet_pt_jerDown = jet_pt_jerDownVal * jet_pt # recalculate the MET after applying the JEC JER if jet_pt > 15.: jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) met_px_nom = met_px_nom - (jet_pt_nom - jet_pt) * jet_cosPhi met_py_nom = met_py_nom - (jet_pt_nom - jet_pt) * jet_sinPhi met_pt_nom = math.sqrt(met_px_nom**2 + met_py_nom**2) met_phi_nom = math.atan2(met_py_nom, met_px_nom) met.pt = met_pt_nom met.phi = met_phi_nom # JECs already applied so apply only JER jet.pt = jet_pt_jerNomVal * jet.pt if jet.pt < 0.0: jet.pt *= -1.0 metp4.SetPtEtaPhiM( met.pt, 0., met.phi, 0.) # only use met vector to derive transverse quantities) self.out.fillBranch("Met", met.pt) centralJet30 = [] centralJet30idx = [] centralJet40 = [] cleanJets25 = [] cleanJets25idx = [] cleanJets = [] cleanJetsidx = [] # fill this flage but defults to 1 and then change it after the proper selection self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 1) for i, j in enumerate(jets): # Cleaning up of fastsim jets (from "corridor" studies) https://twiki.cern.ch/twiki/bin/viewauth/CMS/SUSRecommendationsMoriond17#Cleaning_up_of_fastsim_jets_from if self.isSig: #only check for signals (see condition check above) self.out.fillBranch("isDPhiSignal", 1) genj = pairs[j] if genj is not None: if j.pt > 20 and abs( j.eta) < 2.5 and (genj.pt == 0) and j.chHEF < 0.1: self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 0) if j.pt > 25: cleanJets25.append(j) cleanJets25idx.append(j) if j.pt > 30 and abs(j.eta) < centralEta: centralJet30.append(j) centralJet30idx.append(i) if j.pt > 40 and abs(j.eta) < centralEta: centralJet40.append(j) # jets 30 (cmg cleaning only) nJetC = len(centralJet30) self.out.fillBranch("nJets", nJetC) self.out.fillBranch("nJets30", nJetC) # store indeces self.out.fillBranch("Jets30Idx", centralJet30idx) #print "nJets30:", len(centralJet30), " nIdx:", len(centralJet30idx) # jets 40 nJet40C = len(centralJet40) self.out.fillBranch("nJets40", nJet40C) ############################## ## Local cleaning from leptons ############################## cJet30Clean = [] dRminCut = 0.4 # Do cleaning a la CMG: clean max 1 jet for each lepton (the nearest) cJet30Clean = centralJet30 cleanJets30 = centralJet30 #clean selected leptons at First '''for lep in goodLep: if lep.pt < 20 : continue jNear, dRmin = None, 99 # find nearest jet for jet in centralJet30: dR = jet.p4().DeltaR(lep.p4()) if dR < dRmin: jNear, dRmin = jet, dR # remove nearest jet if dRmin < dRminCut: cJet30Clean.remove(jNear)''' #then clean other tight leptons for lep in tightLeps: # don't clean LepGood, only LepOther #if lep not in otherleps: continue jNear, dRmin = None, 99 # find nearest jet for jet in centralJet30: dR = jet.p4().DeltaR(lep.p4()) if dR < dRmin: jNear, dRmin = jet, dR # remove nearest jet if dRmin < dRminCut: cJet30Clean.remove(jNear) for ijet, jet25 in enumerate(cleanJets25): dR = jet25.p4().DeltaR(lep.p4()) if dR < dRmin: cleanJets.append(jet25) cleanJetsidx.append(ijet) # cleaned jets nJet30C = len(cJet30Clean) self.out.fillBranch("nJets30Clean", len(cJet30Clean)) if nJet30C > 0: self.out.fillBranch("Jet1_pt", cJet30Clean[0].pt) self.out.fillBranch("Jet1_eta", cJet30Clean[0].eta) if nJet30C > 1: self.out.fillBranch("Jet2_pt", cJet30Clean[1].pt) self.out.fillBranch("Jet2_eta", cJet30Clean[1].eta) # imho, use Jet2_pt > 80 instead self.out.fillBranch( "LSLjetptGT80", 1 if sum([j.pt > 80 for j in cJet30Clean]) >= 2 else 0) self.out.fillBranch("htJet30j", sum([j.pt for j in cJet30Clean])) self.out.fillBranch("htJet30ja", sum([j.pt for j in jets if j.pt > 30])) self.out.fillBranch("htJet40j", sum([j.pt for j in centralJet40])) self.out.fillBranch("HT", sum([j.pt for j in cJet30Clean])) ## B tagging WPs for CSVv2 (CSV-IVF) ## from: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBTagging#Preliminary_working_or_operating # WP defined on top btagWP = self.btag_MediumWP btag_DeepMediumWP = self.btag_DeepMediumWP btag_LooseWP = self.btag_LooseWP BJetMedium30 = [] BJetMedium40 = [] nBJetDeep = 0 for i, j in enumerate(cJet30Clean): if j.btagCSVV2 > btagWP: BJetMedium30.append(j) if (j.btagDeepB) > btag_DeepMediumWP: nBJetDeep += 1 for i, j in enumerate(centralJet40): if j.btagCSVV2 > btagWP: BJetMedium40.append(j) # using cleaned collection! self.out.fillBranch("nBJet", len(BJetMedium30)) self.out.fillBranch("nBJets30", len(BJetMedium30)) self.out.fillBranch("nBJetDeep", nBJetDeep) # using normal collection self.out.fillBranch("nBJets40", len(BJetMedium40)) ###### # MET ##### ##################################################################### ##################################################################### #################High level variables ############################### ##################################################################### ##################################################################### dPhiLepW = -999 # set default value to -999 to spot "empty" entries GendPhiLepW = -999 # set default value to -999 to spot "empty" entries # LT of lepton and MET LT = -999 GenLT = -999 Lp = -99 MT = -99 if len(tightLeps) >= 1: recoWp4 = tightLeps[0].p4() + metp4 GenrecoWp4 = tightLeps[0].p4() + Genmetp4 GendPhiLepW = tightLeps[0].p4().DeltaPhi(GenrecoWp4) GenLT = tightLeps[0].pt + Genmetp4.Pt() dPhiLepW = tightLeps[0].p4().DeltaPhi(recoWp4) LT = tightLeps[0].pt + metp4.Pt() Lp = tightLeps[0].pt / recoWp4.Pt() * math.cos(dPhiLepW) #MT = recoWp4.Mt() # doesn't work MT = math.sqrt(2 * metp4.Pt() * tightLeps[0].pt * (1 - math.cos(dPhiLepW))) self.out.fillBranch("DeltaPhiLepW", dPhiLepW) dPhi = abs(dPhiLepW) # nickname for absolute dPhiLepW self.out.fillBranch("dPhi", dPhi) self.out.fillBranch("ST", LT) self.out.fillBranch("LT", LT) self.out.fillBranch("Lp", Lp) self.out.fillBranch("MT", MT) self.out.fillBranch("GendPhi", abs(GendPhiLepW)) self.out.fillBranch("GenLT", GenLT) self.out.fillBranch("GenMET", Genmetp4.Pt()) ##################### ## SIGNAL REGION FLAG ##################### ## Signal region flag # isSR SR vs CR flag isSR = 0 # 0-B SRs -- simplified dPhi if len(BJetMedium30) == 0: # check the no. of Bjets if LT < 250: isSR = 0 elif LT > 250: isSR = dPhi > 0.75 # BLIND data if (not self.isMC) and nJet30C >= 5: isSR = -isSR # Multi-B SRs elif nJet30C < 99: if LT < 250: isSR = 0 elif LT < 350: isSR = dPhi > 1.0 elif LT < 600: isSR = dPhi > 0.75 elif LT > 600: isSR = dPhi > 0.5 # BLIND data if (not self.isMC) and nJet30C >= 6: isSR = -isSR self.out.fillBranch("isSR", isSR) ############# ## Playground ############# # di-lepton mass: opposite-sign, same flavour Mll = 0 if len(tightLeps) > 1: lep1 = tightLeps[0] id1 = lep1.pdgId for lep2 in leps[1:]: if lep2.pdgId + lep1.pdgId == 0: dilepP4 = lep1.p4() + lep2.p4() Mll = dilepP4.M() self.out.fillBranch("Mll", Mll) # RA2 proposed filter self.out.fillBranch( "RA2_muJetFilter", True ) # normally true for now # don't know how to get the Muon energy fraction from EMEF #for j in cJet30Clean: # if j.pt > 200 and j.chEmEF > 0.5 and abs(math.acos(math.cos(j.phi-metp4.Phi()))) > (math.pi - 0.4): # self.out.fillBranch("RA2_muJetFilter", False) ## MET FILTERS for data looks like the met filters are applied already for nanoAOD ##################### ## Top Tagging ------->>>>>>. to be moved to different modules keep it commented here ##################### lightJets = [j for j in cleanJets if not j.btagCSVV2 == btagWP] bjetsLoose = [j for j in cleanJets if j.btagCSVV2 == btag_LooseWP] minMWjj = 999 minMWjjPt = 0 bestMWjj = 0 bestMWjjPt = 0 bestMTopHad = 0 bestMTopHadPt = 0 for i1, j1 in enumerate(lightJets): for i2 in xrange(i1 + 1, len(lightJets)): j2 = lightJets[i2] jjp4 = j1.p4() + j2.p4() mjj = jjp4.M() if mjj > 30 and mjj < minMWjj: minMWjj = mjj minMWjjPt = jjp4.Pt() self.out.fillBranch("minMWjj", minMWjj) self.out.fillBranch("minMWjjPt", minMWjjPt) if abs(mjj - 80.4) < abs(bestMWjj - 80.4): bestMWjj = mjj bestMWjjPt = jjp4.Pt() self.out.fillBranch("bestMWjj", bestMWjj) self.out.fillBranch("bestMWjjPt", bestMWjjPt) for bj in bjetsLoose: if deltaR(bj.eta(), bj.phi(), j1.eta(), j1.phi()) < 0.1 or deltaR( bj.eta(), bj.phi(), j2.eta(), j2.phi()) < 0.1: continue tp4 = jjp4 + bj.p4() mtop = tp4.M() if abs(mtop - 172) < abs(bestMTopHad - 172): bestMTopHad = mtop bestMTopHadPt = tp4.Pt() self.out.fillBranch("bestMTopHad", bestMTopHad) self.out.fillBranch("bestMTopHadPt", bestMTopHadPt) ##################################################################### ##################################################################### #################Fill MT2 here, not point to make a separate module## ##################################################################### ##################################################################### # isolated tracks after basic selection (((pt>5 && (abs(pdgId) == 11 || abs(pdgId) == 13)) || pt > 10) && (abs(pdgId) < 15 || abs(eta) < 2.5) && abs(dxy) < 0.2 && abs(dz) < 0.1 && ((pfIsolationDR03().chargedHadronIso < 5 && pt < 25) || pfIsolationDR03().chargedHadronIso/pt < 0.2)) and lepton veto # First check is the event has the IsoTrack or not if hasattr(event, "nIsoTrack"): trks = [j for j in Collection(event, "IsoTrack", "nIsoTrack")] tp4 = ROOT.TLorentzVector(0, 0, 0, 0) # min dR between good lep and iso track minDR = 0.1 # MT2 cuts for hadronic and leptonic veto tracks hadMT2cut = 60 lepMT2cut = 80 if (len(tightLeps) >= 1) and len(trks) >= 1: for i, t in enumerate(trks): # looking for opposite charged tracks #if tightLeps[0].charge == t.charge: continue # not track charge is founded replace with the next copule of lines if t.isHighPurityTrack == False: continue #print t.miniPFRelIso_chg # not track mass is founded tp4.SetPtEtaPhiM(t.pt, t.eta, t.phi, 0.) dR = tp4.DeltaR(tightLeps[0].p4()) if minDR > dR: continue p1 = tightLeps[0].p4() p2 = tp4 a = array.array('d', [p1.M(), p1.Px(), p1.Py()]) b = array.array('d', [p2.M(), p2.Px(), p2.Py()]) c = array.array('d', [metp4.M(), metp4.Px(), metp4.Py()]) mt2obj.set_momenta(a, b, c) mt2obj.set_mn(0) self.out.fillBranch("iso_MT2", mt2obj.get_mt2()) self.out.fillBranch("iso_pt", p2.Pt()) # cuts on MT2 as defined above if abs(t.pdgId) > 10 and abs(t.pdgId) < 14: self.out.fillBranch("iso_had", 0) #leptonic cut = lepMT2cut else: self.out.fillBranch("iso_had", 1) #hadronic track cut = hadMT2cut if mt2obj.get_mt2() <= cut: self.out.fillBranch("iso_Veto", True) self.out.fillBranch("Xsec", self.xs) if 'JetHT' in self.filename: self.out.fillBranch("PD_JetHT", True) else: self.out.fillBranch("PD_JetHT", False) if 'SingleEle' in self.filename: self.out.fillBranch("PD_SingleEle", True) else: self.out.fillBranch("PD_SingleEle", False) if 'SingleMu' in self.filename: self.out.fillBranch("PD_SingleMu", True) else: self.out.fillBranch("PD_SingleMu", False) if 'MET' in self.filename: self.out.fillBranch("PD_MET", True) else: self.out.fillBranch("PD_MET", False) return True
def correctJetMET_MC(self, event): """Process event, apply corrections.""" ###print ">>> %8s "%event.event + '-'*80 ###if self.doGroomed: ### subJets = Collection(event, self.subJetBranchName ) ### genSubJets = Collection(event, self.genSubJetBranchName ) ### genSubJetMatcher = matchObjectCollectionMultiple( genJets, genSubJets, dRmax=0.8 ) jets_pt_nom = [] ###jets_mass_nom = [ ] if self.doSystematics: jets_pt_jerUp = [] jets_pt_jerDown = [] jets_pt_jesUp = {} jets_pt_jesDown = {} ###jets_mass_jerUp = [ ] ###jets_mass_jerDown = [ ] ###jets_mass_jmrUp = [ ] ###jets_mass_jmrDown = [ ] ###jets_mass_jesUp = { } ###jets_mass_jesDown = { } ###jets_mass_jmsUp = [ ] ###jets_mass_jmsDown = [ ] for uncertainty in self.jesUncertainties: jets_pt_jesUp[uncertainty] = [] jets_pt_jesDown[uncertainty] = [] ###jets_mass_jesUp[uncertainty] = [ ] ###jets_mass_jesDown[uncertainty] = [ ] if self.corrMET: met = Object(event, self.metBranchName) met_px, met_py = met.pt * cos(met.phi), met.pt * sin(met.phi) met_px_nom, met_py_nom = met_px, met_py met_px_jerUp, met_py_jerUp = met_px, met_py met_px_jerDown, met_py_jerDown = met_px, met_py met_px_jesUp, met_py_jesUp = {}, {} met_px_jesDown, met_py_jesDown = {}, {} for uncertainty in self.jesUncertainties: met_px_jesUp[uncertainty] = met_px met_py_jesUp[uncertainty] = met_py met_px_jesDown[uncertainty] = met_px met_py_jesDown[uncertainty] = met_py ###if self.doGroomed: ### jets_msdcorr_nom = [ ] ### if self.doSystematics: ### jets_msdcorr_jerUp = [ ] ### jets_msdcorr_jerDown = [ ] ### jets_msdcorr_jmrUp = [ ] ### jets_msdcorr_jmrDown = [ ] ### jets_msdcorr_jesUp = { } ### jets_msdcorr_jesDown = { } ### jets_msdcorr_jmsUp = [ ] ### jets_msdcorr_jmsDown = [ ] ### for uncertainty in self.jesUncertainties: ### jets_msdcorr_jesUp[uncertainty] = [ ] ### jets_msdcorr_jesDown[uncertainty] = [ ] # MATCH reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) jets = Collection(event, self.jetBranchName) genJets = Collection(event, self.genJetBranchName) rho = getattr(event, self.rhoBranchName) pairs = matchObjectCollection(jets, genJets) # APPLY JEC per jet for jet in jets: genJet = pairs[jet] ###if self.doGroomed: ### genGroomedSubJets = genSubJetMatcher[genJet] if genJet!=None else None ### genGroomedJet = genGroomedSubJets[0].p4() + genGroomedSubJets[1].p4() if genGroomedSubJets!=None and len(genGroomedSubJets)>=2 else None ### if jet.subJetIdx1>=0 and jet.subJetIdx2>=0: ### groomedP4 = subJets[ jet.subJetIdx1 ].p4() + subJets[ jet.subJetIdx2].p4() ### else: ### groomedP4 = None # RAW VALUES jet_pt0 = jet.pt ###jet_mass0 = jet.mass if hasattr(jet, 'rawFactor'): jet_pt_raw = jet_pt0 * (1 - jet.rawFactor) ###jet_mass_raw = jet.mass * (1 - jet.rawFactor) else: jet_pt_raw = -1.0 * jet_pt0 # if factor not present factor will be saved as -1 ###jet_mass_raw = -1.0 * jet.mass # CALIBRATE - apply JES corrections if self.redoJEC: jet_pt, jet_mass = self.jetReCalibrator.correct(jet, rho) jet.pt = jet_pt jet.mass = jet_mass else: jet_pt = jet.pt jet_mass = jet.mass # SMEAR - apply JER SF if self.doSystematics: smear_jer, smear_jerUp, smear_jerDown = self.jetSmearer.smearPt( jet, genJet, rho) else: smear_jer = self.jetSmearer.smearPt(jet, genJet, rho)[0] jet_pt_nom = smear_jer * jet_pt if jet_pt_nom < 0.0: jet_pt_nom *= -1.0 jets_pt_nom.append(jet_pt_nom) ###print "%8.4f %8.4f %8.4f %8.4f %8.4f %8.4f"%(jet_pt_raw, jet_pt0, jet_pt, jet_pt_nom, jet.rawFactor, smear_jer) #### SMEAR JMS and JMR scale factors ###jmsNomVal = self.jmsVals[0] ###jmsDownVal = self.jmsVals[1] ###jmsUpVal = self.jmsVals[2] ###smear_jmr, smear_jmrUp, smear_jmrDown = self.jetSmearer.smearMass(jet, genJet) ###jet_mass_nom = smear_jer*smear_jmr*jmsNomVal*jet.mass ###if jet_mass_nom < 0.0: ### jet_mass_nom *= -1.0 ###jets_mass_nom .append(jet_mass_nom) #### CORRECT GROOMED JETS ###if self.doGroomed: ### ( jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal, jet_msdcorr_jmrDownVal ) = self.jetSmearer.getSmearValsM(groomedP4, genGroomedJet) if groomedP4!=None and genGroomedJet!=None else (0.,0.,0.) ### jet_msdcorr_raw = groomedP4.M() if groomedP4!=None else 0.0 ### if jet_msdcorr_raw < 0.0: ### jet_msdcorr_raw *= -1.0 ### jet_msdcorr_nom = smear_jer*jet_msdcorr_jmrNomVal*jet_msdcorr_raw ### jets_msdcorr_nom .append(jet_msdcorr_nom) #### UPDATE JET in event (unreliable) ###if self.updateEvent: ### getattr(event,self.jetBranchName+'_pt')[jet._index] = jet_pt_nom ### ###getattr(event,self.jetBranchName+'_mass')[jet._index] = jet_mass_nom # EVALUATE JEC uncertainties if self.doSystematics: # EVALUATE JES uncertainties jet_pt_jesUp = {} jet_pt_jesDown = {} for uncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties ) self.jesUncertainty[uncertainty].setJetPt(jet_pt_nom) self.jesUncertainty[uncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[uncertainty].getUncertainty( True) jet_pt_jesUp[uncertainty] = jet_pt_nom * (1. + delta) jet_pt_jesDown[uncertainty] = jet_pt_nom * (1. - delta) jets_pt_jesUp[uncertainty].append( jet_pt_jesUp[uncertainty]) jets_pt_jesDown[uncertainty].append( jet_pt_jesDown[uncertainty]) ###jet_mass_jesUp [uncertainty] = jet_mass_nom*(1. + delta) ###jet_mass_jesDown [uncertainty] = jet_mass_nom*(1. - delta) ###jets_mass_jesUp [uncertainty].append(jet_mass_jesUp[uncertainty]) ###jets_mass_jesDown[uncertainty].append(jet_mass_jesDown[uncertainty]) ###if self.doGroomed: ### jet_msdcorr_jesUp [uncertainty] = jet_msdcorr_nom*(1. + delta) ### jet_msdcorr_jesDown [uncertainty] = jet_msdcorr_nom*(1. - delta) ### jets_msdcorr_jesUp [uncertainty].append(jet_msdcorr_jesUp[uncertainty]) ### jets_msdcorr_jesDown[uncertainty].append(jet_msdcorr_jesDown[uncertainty]) # EVALUATE JER uncertainties jet_pt_jerUp = smear_jerUp * jet_pt jet_pt_jerDown = smear_jerDown * jet_pt jets_pt_jerUp.append(jet_pt_jerUp) jets_pt_jerDown.append(jet_pt_jerDown) #### EVALUATE JMS and JMR uncertainties ###jet_mass_jesUp = { } ###jet_mass_jesDown = { } ###jet_mass_jmsUp = [ ] ###jet_mass_jmsDown = [ ] ###jets_mass_jerUp .append(smear_jerUp *smear_jmr *jmsNomVal *jet.mass) ###jets_mass_jerDown.append(smear_jerDown*smear_jmr *jmsNomVal *jet.mass) ###jets_mass_jmrUp .append(smear_jer *smear_jmrUp *jmsNomVal *jet.mass) ###jets_mass_jmrDown.append(smear_jer *smear_jmrDown*jmsNomVal *jet.mass) ###jets_mass_jmsUp .append(smear_jer *smear_jmr *jmsUpVal *jet.mass) ###jets_mass_jmsDown.append(smear_jer *smear_jmr *jmsDownVal*jet.mass) ###if self.doGroomed: ### jet_msdcorr_jmsUp = [ ] ### jet_msdcorr_jmsDown = [ ] ### jet_msdcorr_jesUp = { } ### jet_msdcorr_jesDown = { } ### jets_msdcorr_jerUp .append(smear_jerUp *jet_msdcorr_jmrNomVal *jmsNomVal *jet_msdcorr_raw) ### jets_msdcorr_jerDown.append(smear_jerDown*jet_msdcorr_jmrNomVal *jmsNomVal *jet_msdcorr_raw) ### jets_msdcorr_jmrUp .append(smear_jer *jet_msdcorr_jmrUpVal *jmsNomVal *jet_msdcorr_raw) ### jets_msdcorr_jmrDown.append(smear_jer *jet_msdcorr_jmrDownVal*jmsNomVal *jet_msdcorr_raw) ### jets_msdcorr_jmsUp .append(smear_jer *jet_msdcorr_jmrNomVal *jmsUpVal *jet_msdcorr_raw) ### jets_msdcorr_jmsDown.append(smear_jer *jet_msdcorr_jmrNomVal *jmsDownVal *jet_msdcorr_raw) # PROPAGATE JER and JES corrections and uncertainties to MET if self.corrMET and jet_pt_nom > self.unclEnThreshold: jet_cosPhi = cos(jet.phi) jet_sinPhi = sin(jet.phi) ###print "%8.4f - met_px_nom = met_px_nom - (jet_pt_nom - jet_pt0)*jet_cosPhi = %8.4f - (%8.4f - %8.4f)*%8.4f = %8.4f"%(jet.phi,met_px_nom,jet_pt_nom,jet_pt0,jet_cosPhi,met_px_nom-(jet_pt_nom-jet_pt0)*jet_cosPhi) met_px_nom = met_px_nom - (jet_pt_nom - jet_pt0) * jet_cosPhi ###print "%8.4f - met_py_nom = met_py_nom - (jet_pt_nom - jet_pt0)*jet_sinPhi = %8.4f - (%8.4f - %8.4f)*%8.4f = %8.4f"%(jet.phi,met_py_nom,jet_pt_nom,jet_pt0,jet_sinPhi,met_py_nom-(jet_pt_nom-jet_pt0)*jet_sinPhi) met_py_nom = met_py_nom - (jet_pt_nom - jet_pt0) * jet_sinPhi if self.doSystematics: met_px_jerUp = met_px_jerUp - (jet_pt_jerUp - jet_pt0) * jet_cosPhi met_py_jerUp = met_py_jerUp - (jet_pt_jerUp - jet_pt0) * jet_sinPhi met_px_jerDown = met_px_jerDown - (jet_pt_jerDown - jet_pt0) * jet_cosPhi met_py_jerDown = met_py_jerDown - (jet_pt_jerDown - jet_pt0) * jet_sinPhi for uncertainty in self.jesUncertainties: met_px_jesUp[uncertainty] = met_px_jesUp[ uncertainty] - (jet_pt_jesUp[uncertainty] - jet_pt0) * jet_cosPhi met_py_jesUp[uncertainty] = met_py_jesUp[ uncertainty] - (jet_pt_jesUp[uncertainty] - jet_pt0) * jet_sinPhi met_px_jesDown[uncertainty] = met_px_jesDown[ uncertainty] - (jet_pt_jesDown[uncertainty] - jet_pt0) * jet_cosPhi met_py_jesDown[uncertainty] = met_py_jesDown[ uncertainty] - (jet_pt_jesDown[uncertainty] - jet_pt0) * jet_sinPhi #### CHECKS ###print ">>> %2d: jet.pt, jet_pt, corr_factor, smear_factor = %8.3f, %8.3f, %8.4f, %8.4f"%(jet._index,jet.pt,jet_pt,jet_pt/jet_pt_raw,smear_factor) ###print ">>> %2s jet_pt_jerUp, jet_pt_nom, jet_pt_jerDown = %8.3f, %8.3f, %8.3f"%("",jet_pt_jerUp,jet_pt_nom,jet_pt_jerDown) ###print ">>> %2s jet_pt_jesUp, jet_pt_nom, jet_pt_jesDown = %8.3f, %8.3f, %8.3f"%("",jet_pt_jesUp['Total'],jet_pt_nom,jet_pt_jesDown['Total']) # PREPARE JET PT variations for return; save 'Total' as just jesUp/jesDown if self.doSystematics: jetpt_vars = { 'nom': jets_pt_nom, 'jerUp': jets_pt_jerUp, 'jerDown': jets_pt_jerDown } for uncertainty in self.jesUncertainties: jetpt_vars["jes%sUp" % uncertainty.replace( 'Total', '')] = jets_pt_jesUp[uncertainty] jetpt_vars["jes%sDown" % uncertainty.replace( 'Total', '')] = jets_pt_jesDown[uncertainty] else: jetpt_vars = { 'nom': jets_pt_nom, } if self.corrMET: # PREPARE MET for return ###print "met_px_nom = %8.4f"%(met_px_nom) ###print "met_py_nom = %8.4f"%(met_py_nom) met_vars = { 'nom': TLorentzVector(met_px_nom, met_py_nom, 0, sqrt(met_px_nom**2 + met_py_nom**2)) } #### UPDATE MET in event ###if self.updateEvent: ### setattr(event,self.metBranchName+'_pt', met_vars['nom'].Pt()) ### setattr(event,self.metBranchName+'_phi', met_vars['nom'].Phi()) if self.doSystematics: # EVALUATE UNCLUSTERED ENERGY uncertainties met_deltaPx_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaX") met_deltaPy_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaY") met_px_unclEnUp = met_px_nom + met_deltaPx_unclEn met_py_unclEnUp = met_py_nom + met_deltaPy_unclEn met_px_unclEnDown = met_px_nom - met_deltaPx_unclEn met_py_unclEnDown = met_py_nom - met_deltaPy_unclEn # PREPARE MET variations for return met_vars['jesUp'] = {} met_vars['jesDown'] = {} met_vars['jerUp'] = TLorentzVector( met_px_jerUp, met_py_jerUp, 0, sqrt(met_px_jerUp**2 + met_py_jerUp**2)) met_vars['jerDown'] = TLorentzVector( met_px_jerDown, met_py_jerDown, 0, sqrt(met_px_jerDown**2 + met_py_jerDown**2)) met_vars['unclEnUp'] = TLorentzVector( met_px_unclEnUp, met_py_unclEnUp, 0, sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2)) met_vars['unclEnDown'] = TLorentzVector( met_px_unclEnDown, met_py_unclEnDown, 0, sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2)) for uncertainty in self.jesUncertainties: met_vars["jes%sUp" % uncertainty.replace( 'Total', '')] = TLorentzVector( met_px_jesUp[uncertainty], met_py_jesUp[uncertainty], 0, sqrt(met_px_jesUp[uncertainty]**2 + met_py_jesUp[uncertainty]**2)) met_vars["jes%sDown" % uncertainty.replace( 'Total', '')] = TLorentzVector( met_px_jesDown[uncertainty], met_py_jesDown[uncertainty], 0, sqrt(met_px_jesDown[uncertainty]**2 + met_py_jesDown[uncertainty]**2)) return jetpt_vars, met_vars return jetpt_vars
def analyze(self, event): met = self.metInput(event) rho = self.rhoInput(event) jets = self.jetCollection(event) lowPtJets = self.lowPtJetCollection(event) genJets = self.genJetCollection(event) muons = self.muonCollection(event) electrons = self.electronCollection(event) for lowPtJet in lowPtJets: lowPtJet.pt = lowPtJet.rawPt #dummy values lowPtJet.rawFactor = 0 lowPtJet.mass = 0 lowPtJet.neEmEF = 0 lowPtJet.chEmEF = 0 def genjet_resolution_matching(jet, genjet): resolution = self.jerUncertaintyCalculator.getResolution(jet, rho) return abs(jet.pt - genjet.pt) < (3 * resolution * jet.pt) genjet_match = matchObjectCollection(jets, genJets, dRmax=0.2, presel=genjet_resolution_matching) genjet_lowpt_match = matchObjectCollection( lowPtJets, genJets, dRmax=0.2, presel=genjet_resolution_matching) genjet_match.update(genjet_lowpt_match) def metP4(obj): p4 = ROOT.TLorentzVector() p4.SetPtEtaPhiM(obj.pt, 0, obj.phi, 0) return p4 met.uncertainty_p4 = { 'nominal': metP4(met), 'jerUp': metP4(met), 'jerDown': metP4(met) } self.jerUncertaintyCalculator.setSeed(event) for ijet, jet in enumerate(itertools.chain(jets, lowPtJets)): jet.uncertainty_p4 = {} genJet = genjet_match[jet] jerFactor = self.jerUncertaintyCalculator.getFactor( jet, genJet, rho) jet.uncertainty_p4['nominal'] = jet.p4() * jerFactor['nominal'] jet.uncertainty_p4['jerUp'] = jet.p4() * jerFactor['up'] jet.uncertainty_p4['jerDown'] = jet.p4() * jerFactor['down'] if self.propagateJER: leptonP4 = ROOT.TLorentzVector(0, 0, 0, 0) for muon in muons: if deltaR(muon, jet) < 0.4: leptonP4 += muon.p4() for electron in electrons: if deltaR(electron, jet) < 0.4: leptonP4 += electron.p4() if (jet.uncertainty_p4['nominal'] - leptonP4).Pt( ) > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9: met.uncertainty_p4['nominal'] -= jet.p4() * ( jerFactor['nominal'] - 1.) if (jet.uncertainty_p4['jerUp'] - leptonP4).Pt( ) > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9: met.uncertainty_p4['jerUp'] -= jet.p4() * ( jerFactor['up'] - 1.) if (jet.uncertainty_p4['jerDown'] - leptonP4).Pt( ) > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9: met.uncertainty_p4['jerDown'] -= jet.p4() * ( jerFactor['down'] - 1.) for jesUncertaintyName in self.jesUncertaintyNames: jecDelta = self.jesUncertaintyCaculators[ jesUncertaintyName].getDelta(jet.uncertainty_p4['nominal']) jet.uncertainty_p4[ 'jes' + jesUncertaintyName + "Up"] = jet.uncertainty_p4['nominal'] * (1. + jecDelta) jet.uncertainty_p4[ 'jes' + jesUncertaintyName + "Down"] = jet.uncertainty_p4['nominal'] * (1. - jecDelta) for jesUncertaintyName in self.jesUncertaintyNames: for mode in ["Up", "Down"]: if self.propagateJER: met.uncertainty_p4['jes' + jesUncertaintyName + mode] = met.uncertainty_p4['nominal'] else: met.uncertainty_p4['jes' + jesUncertaintyName + mode] = metP4(met) for jet in jets: if jet.uncertainty_p4[ 'jes' + jesUncertaintyName + mode].Pt() > self.unclEnThreshold and ( jet.neEmEF + jet.chEmEF) < 0.9: met.uncertainty_p4[ 'jes' + jesUncertaintyName + mode] -= jet.uncertainty_p4[ 'jes' + jesUncertaintyName + mode] - jet.uncertainty_p4['nominal'] unclMetDelta = ROOT.TLorentzVector() unclMetDelta.SetXYZM(met.MetUnclustEnUpDeltaX, met.MetUnclustEnUpDeltaY, 0, 0) met.uncertainty_p4[ 'unclEnUp'] = met.uncertainty_p4['nominal'] + unclMetDelta met.uncertainty_p4[ 'unclEnDown'] = met.uncertainty_p4['nominal'] - unclMetDelta setattr(event, self.outputJetPrefix + "nominal", self.makeNewJetCollection(jets, "nominal")) setattr(event, self.outputMetPrefix + "nominal", self.makeNewMetObject(met, "nominal")) for jesUncertaintyName in self.jesUncertaintyNames: for mode in ["Up", "Down"]: setattr( event, self.outputJetPrefix + "jes" + jesUncertaintyName + mode, self.makeNewJetCollection( jets, "jes" + jesUncertaintyName + mode)) setattr( event, self.outputMetPrefix + "jes" + jesUncertaintyName + mode, self.makeNewMetObject(met, "jes" + jesUncertaintyName + mode)) for mode in ["Up", "Down"]: setattr(event, self.outputJetPrefix + "jer" + mode, self.makeNewJetCollection(jets, "jer" + mode)) setattr(event, self.outputMetPrefix + "jer" + mode, self.makeNewMetObject(met, "jer" + mode)) setattr(event, self.outputMetPrefix + "unclEn" + mode, self.makeNewMetObject(met, "unclEn" + mode)) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName ) genJets = Collection(event, self.genJetBranchName ) if self.doGroomed : subJets = Collection(event, self.subJetBranchName ) genSubJets = Collection(event, self.genSubJetBranchName ) genSubJetMatcher = matchObjectCollectionMultiple( genJets, genSubJets, dRmax=0.8 ) self.jetSmearer.setSeed(event) jet_L1 = [] jet_L2L3 = [] jet_LRes = [] jets_pt_raw = [] jets_pt_nom = [] jets_mass_raw = [] jets_mass_nom = [] jets_corr_JEC = [] jets_corr_JER = [] jets_corr_JMS = [] jets_corr_JMR = [] jets_pt_jerUp = [] jets_pt_jerDown = [] jets_pt_jesUp = {} jets_pt_jesDown = {} jets_mass_jerUp = [] jets_mass_jerDown = [] jets_mass_jmrUp = [] jets_mass_jmrDown = [] jets_mass_jesUp = {} jets_mass_jesDown = {} jets_mass_jmsUp = [] jets_mass_jmsDown = [] for jesUncertainty in self.jesUncertainties: jets_pt_jesUp[jesUncertainty] = [] jets_pt_jesDown[jesUncertainty] = [] jets_mass_jesUp[jesUncertainty] = [] jets_mass_jesDown[jesUncertainty] = [] if self.corrMET : met = Object(event, self.metBranchName) ( met_px, met_py ) = ( met.pt*math.cos(met.phi), met.pt*math.sin(met.phi) ) ( met_px_nom, met_py_nom ) = ( met_px, met_py ) ( met_px_jerUp, met_py_jerUp ) = ( met_px, met_py ) ( met_px_jerDown, met_py_jerDown ) = ( met_px, met_py ) ( met_px_jesUp, met_py_jesUp ) = ( {}, {} ) ( met_px_jesDown, met_py_jesDown ) = ( {}, {} ) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px met_py_jesUp[jesUncertainty] = met_py met_px_jesDown[jesUncertainty] = met_px met_py_jesDown[jesUncertainty] = met_py if self.doGroomed: jets_msdcorr_raw = [] jets_msdcorr_nom = [] jets_msdcorr_corr_JMR = [] jets_msdcorr_corr_JMS = [] jets_msdcorr_corr_PUPPI = [] jets_msdcorr_jerUp = [] jets_msdcorr_jerDown = [] jets_msdcorr_jmrUp = [] jets_msdcorr_jmrDown = [] jets_msdcorr_jesUp = {} jets_msdcorr_jesDown = {} jets_msdcorr_jmsUp = [] jets_msdcorr_jmsDown = [] jets_msdcorr_tau21DDT_nom = [] jets_msdcorr_tau21DDT_jerUp = [] jets_msdcorr_tau21DDT_jerDown = [] jets_msdcorr_tau21DDT_jmrUp = [] jets_msdcorr_tau21DDT_jmrDown = [] jets_msdcorr_tau21DDT_jmsUp = [] jets_msdcorr_tau21DDT_jmsDown = [] for jesUncertainty in self.jesUncertainties: jets_msdcorr_jesUp[jesUncertainty] = [] jets_msdcorr_jesDown[jesUncertainty] = [] rho = getattr(event, self.rhoBranchName) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) pairs = matchObjectCollection(jets, genJets) for jet in jets: #jet pt and mass corrections jet_pt=jet.pt jet_mass=jet.mass jet_L1.append(self.jetReCalibrator.getCorrection(jet,rho, corrector=self.jetReCalibrator.separateJetCorrectors["myL1"])) jet_L2L3.append(self.jetReCalibrator.getCorrection(jet,rho, corrector=self.jetReCalibrator.separateJetCorrectors["myL2L3"])) jet_LRes.append(self.jetReCalibrator.getCorrection(jet,rho, corrector=self.jetReCalibrator.separateJetCorrectors["myRes"])) #redo JECs if desired if hasattr(jet, "rawFactor"): jet_rawpt = jet_pt * (1 - jet.rawFactor) jet_rawmass = jet_mass * (1 - jet.rawFactor) else: jet_rawpt = -1.0 * jet_pt #If factor not present factor will be saved as -1 jet_rawmass = -1.0 * jet_mass #If factor not present factor will be saved as -1 if self.redoJEC : (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet,rho) jet.pt = jet_pt jet.mass = jet_mass jets_pt_raw.append(jet_rawpt) jets_mass_raw.append(jet_rawmass) jets_corr_JEC.append(jet_pt/jet_rawpt) genJet = pairs[jet] if self.doGroomed: genGroomedSubJets = genSubJetMatcher[genJet] if genJet != None else None genGroomedJet = genGroomedSubJets[0].p4() + genGroomedSubJets[1].p4() if genGroomedSubJets != None and len(genGroomedSubJets) >= 2 else None if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0 : groomedP4 = subJets[ jet.subJetIdx1 ].p4() + subJets[ jet.subJetIdx2].p4() #check subjet jecs else : groomedP4 = None # LC: Apply PUPPI SD mass correction https://github.com/cms-jet/PuppiSoftdropMassCorr/ puppisd_genCorr = self.puppisd_corrGEN.Eval(jet.pt) if abs(jet.eta) <= 1.3: puppisd_recoCorr = self.puppisd_corrRECO_cen.Eval(jet.pt) else: puppisd_recoCorr = self.puppisd_corrRECO_for.Eval(jet.pt) puppisd_total = puppisd_genCorr * puppisd_recoCorr jets_msdcorr_corr_PUPPI.append(puppisd_total) if groomedP4 != None: groomedP4.SetPtEtaPhiM(groomedP4.Perp(), groomedP4.Eta(), groomedP4.Phi(), groomedP4.M()*puppisd_total) # evaluate JER scale factors and uncertainties # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution ) ( jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal ) = self.jetSmearer.getSmearValsPt(jet, genJet, rho) jets_corr_JER.append(jet_pt_jerNomVal) jet_pt_nom = jet_pt_jerNomVal *jet_pt if jet_pt_nom < 0.0: jet_pt_nom *= -1.0 jet_pt_jerUp = jet_pt_jerUpVal *jet_pt jet_pt_jerDown = jet_pt_jerDownVal*jet_pt jets_pt_nom .append(jet_pt_nom) jets_pt_jerUp .append(jet_pt_jerUpVal*jet_pt) jets_pt_jerDown.append(jet_pt_jerDownVal*jet_pt) # evaluate JES uncertainties jet_pt_jesUp = {} jet_pt_jesDown = {} jet_mass_jesUp = {} jet_mass_jesDown = {} jet_mass_jmsUp = [] jet_mass_jmsDown = [] # Evaluate JMS and JMR scale factors and uncertainties jmsNomVal = self.jmsVals[0] jmsDownVal = self.jmsVals[1] jmsUpVal = self.jmsVals[2] ( jet_mass_jmrNomVal, jet_mass_jmrUpVal, jet_mass_jmrDownVal ) = self.jetSmearer.getSmearValsM(jet, genJet) jets_corr_JMS .append(jmsNomVal) jets_corr_JMR .append(jet_mass_jmrNomVal) jet_mass_nom = jet_pt_jerNomVal*jet_mass_jmrNomVal*jmsNomVal*jet_mass if jet_mass_nom < 0.0: jet_mass_nom *= -1.0 jets_mass_nom .append(jet_mass_nom) jets_mass_jerUp .append(jet_pt_jerUpVal *jet_mass_jmrNomVal *jmsNomVal *jet_mass) jets_mass_jerDown.append(jet_pt_jerDownVal*jet_mass_jmrNomVal *jmsNomVal *jet_mass) jets_mass_jmrUp .append(jet_pt_jerNomVal *jet_mass_jmrUpVal *jmsNomVal *jet_mass) jets_mass_jmrDown.append(jet_pt_jerNomVal *jet_mass_jmrDownVal*jmsNomVal *jet_mass) jets_mass_jmsUp .append(jet_pt_jerNomVal *jet_mass_jmrNomVal *jmsUpVal *jet_mass) jets_mass_jmsDown.append(jet_pt_jerNomVal *jet_mass_jmrNomVal *jmsDownVal *jet_mass) if self.doGroomed : # evaluate JES uncertainties jet_msdcorr_jesUp = {} jet_msdcorr_jesDown = {} # Evaluate JMS and JMR scale factors and uncertainties ( jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal, jet_msdcorr_jmrDownVal ) = self.jetSmearer.getSmearValsM(groomedP4, genGroomedJet) if groomedP4 != None and genGroomedJet != None else (0.,0.,0.) jet_msdcorr_raw = groomedP4.M() if groomedP4 != None else 0.0 jets_msdcorr_corr_JMS.append(jmsNomVal) jets_msdcorr_corr_JMR.append(jet_msdcorr_jmrNomVal) if jet_msdcorr_raw < 0.0: jet_msdcorr_raw *= -1.0 jet_msdcorr_nom = jet_pt_jerNomVal*jet_msdcorr_jmrNomVal*jmsNomVal*jet_msdcorr_raw jets_msdcorr_raw .append(jet_msdcorr_raw) #fix later so jec's not applied - LC: Current PUPPI SD mass correction implementation needs the JECs applied before looking up the correction so make sure that's accounted for if this is changed. jets_msdcorr_nom .append(jet_msdcorr_nom) jets_msdcorr_jerUp .append(jet_pt_jerUpVal *jet_msdcorr_jmrNomVal *jmsNomVal *jet_msdcorr_raw) jets_msdcorr_jerDown.append(jet_pt_jerDownVal*jet_msdcorr_jmrNomVal *jmsNomVal *jet_msdcorr_raw) jets_msdcorr_jmrUp .append(jet_pt_jerNomVal *jet_msdcorr_jmrUpVal *jmsNomVal *jet_msdcorr_raw) jets_msdcorr_jmrDown.append(jet_pt_jerNomVal *jet_msdcorr_jmrDownVal*jmsNomVal *jet_msdcorr_raw) jets_msdcorr_jmsUp .append(jet_pt_jerNomVal *jet_msdcorr_jmrNomVal *jmsUpVal *jet_msdcorr_raw) jets_msdcorr_jmsDown.append(jet_pt_jerNomVal *jet_msdcorr_jmrNomVal *jmsDownVal *jet_msdcorr_raw) #Also evaluated JMS&JMR SD corr in tau21DDT region: https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetWtagging#tau21DDT_0_43 if self.era in ["2016"]: jmstau21DDTNomVal = 1.014 jmstau21DDTDownVal = 1.007 jmstau21DDTUpVal = 1.021 self.jetSmearer.jmr_vals = [1.086,1.176,0.996] elif self.era in ["2017","2018"]: jmstau21DDTNomVal = 0.983 jmstau21DDTDownVal = 0.976 jmstau21DDTUpVal = 0.99 self.jetSmearer.jmr_vals = [1.080,1.161,0.999] ( jet_msdcorr_tau21DDT_jmrNomVal, jet_msdcorr_tau21DDT_jmrUpVal, jet_msdcorr_tau21DDT_jmrDownVal ) = self.jetSmearer.getSmearValsM(groomedP4, genGroomedJet) if groomedP4 != None and genGroomedJet != None else (0.,0.,0.) jet_msdcorr_tau21DDT_nom = jet_pt_jerNomVal*jet_msdcorr_tau21DDT_jmrNomVal*jmstau21DDTNomVal*jet_msdcorr_raw jets_msdcorr_tau21DDT_nom .append(jet_msdcorr_tau21DDT_nom) jets_msdcorr_tau21DDT_jerUp .append(jet_pt_jerUpVal *jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTNomVal *jet_msdcorr_raw) jets_msdcorr_tau21DDT_jerDown.append(jet_pt_jerDownVal*jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTNomVal *jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmrUp .append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrUpVal *jmstau21DDTNomVal *jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmrDown.append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrDownVal*jmstau21DDTNomVal *jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmsUp .append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTUpVal *jet_msdcorr_raw) jets_msdcorr_tau21DDT_jmsDown.append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTDownVal *jet_msdcorr_raw) #Restore original jmr_vals in jetSmearer self.jetSmearer.jmr_vals = self.jmrVals for jesUncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties ) self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[jesUncertainty].getUncertainty(True) jet_pt_jesUp[jesUncertainty] = jet_pt_nom*(1. + delta) jet_pt_jesDown[jesUncertainty] = jet_pt_nom*(1. - delta) jets_pt_jesUp[jesUncertainty].append(jet_pt_jesUp[jesUncertainty]) jets_pt_jesDown[jesUncertainty].append(jet_pt_jesDown[jesUncertainty]) jet_mass_jesUp [jesUncertainty] = jet_mass_nom*(1. + delta) jet_mass_jesDown [jesUncertainty] = jet_mass_nom*(1. - delta) jets_mass_jesUp [jesUncertainty].append(jet_mass_jesUp[jesUncertainty]) jets_mass_jesDown[jesUncertainty].append(jet_mass_jesDown[jesUncertainty]) if self.doGroomed : jet_msdcorr_jesUp [jesUncertainty] = jet_msdcorr_nom*(1. + delta) jet_msdcorr_jesDown [jesUncertainty] = jet_msdcorr_nom*(1. - delta) jets_msdcorr_jesUp [jesUncertainty].append(jet_msdcorr_jesUp[jesUncertainty]) jets_msdcorr_jesDown[jesUncertainty].append(jet_msdcorr_jesDown[jesUncertainty]) # propagate JER and JES corrections and uncertainties to MET if self.corrMET and jet_pt_nom > self.unclEnThreshold: jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) met_px_nom = met_px_nom - (jet_pt_nom - jet_pt)*jet_cosPhi met_py_nom = met_py_nom - (jet_pt_nom - jet_pt)*jet_sinPhi met_px_jerUp = met_px_jerUp - (jet_pt_jerUp - jet_pt_nom)*jet_cosPhi met_py_jerUp = met_py_jerUp - (jet_pt_jerUp - jet_pt_nom)*jet_sinPhi met_px_jerDown = met_px_jerDown - (jet_pt_jerDown - jet_pt_nom)*jet_cosPhi met_py_jerDown = met_py_jerDown - (jet_pt_jerDown - jet_pt_nom)*jet_sinPhi for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] - (jet_pt_jesUp[jesUncertainty] - jet_pt_nom)*jet_cosPhi met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] - (jet_pt_jesUp[jesUncertainty] - jet_pt_nom)*jet_sinPhi met_px_jesDown[jesUncertainty] = met_px_jesDown[jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_nom)*jet_cosPhi met_py_jesDown[jesUncertainty] = met_py_jesDown[jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_nom)*jet_sinPhi # propagate "unclustered energy" uncertainty to MET if self.corrMET : ( met_px_unclEnUp, met_py_unclEnUp ) = ( met_px, met_py ) ( met_px_unclEnDown, met_py_unclEnDown ) = ( met_px, met_py ) met_deltaPx_unclEn = getattr(event, self.metBranchName + "_MetUnclustEnUpDeltaX") met_deltaPy_unclEn = getattr(event, self.metBranchName + "_MetUnclustEnUpDeltaY") met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn # propagate effect of jet energy smearing to MET met_px_jerUp = met_px_jerUp + (met_px_nom - met_px) met_py_jerUp = met_py_jerUp + (met_py_nom - met_py) met_px_jerDown = met_px_jerDown + (met_px_nom - met_px) met_py_jerDown = met_py_jerDown + (met_py_nom - met_py) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] + (met_px_nom - met_px) met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] + (met_py_nom - met_py) met_px_jesDown[jesUncertainty] = met_px_jesDown[jesUncertainty] + (met_px_nom - met_px) met_py_jesDown[jesUncertainty] = met_py_jesDown[jesUncertainty] + (met_py_nom - met_py) met_px_unclEnUp = met_px_unclEnUp + (met_px_nom - met_px) met_py_unclEnUp = met_py_unclEnUp + (met_py_nom - met_py) met_px_unclEnDown = met_px_unclEnDown + (met_px_nom - met_px) met_py_unclEnDown = met_py_unclEnDown + (met_py_nom - met_py) self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw) self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom) self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC) self.out.fillBranch("%s_corr_JER" % self.jetBranchName, jets_corr_JER) self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp) self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName, jets_pt_jerDown) self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw) self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom) self.out.fillBranch("%s_corr_JMS" % self.jetBranchName, jets_corr_JMS) self.out.fillBranch("%s_corr_JMR" % self.jetBranchName, jets_corr_JMR) self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName, jets_mass_jerUp) self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName, jets_mass_jerDown) self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName, jets_mass_jmrUp) self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName, jets_mass_jmrDown) self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName, jets_mass_jmsUp) self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName, jets_mass_jmsDown) self.out.fillBranch("%s_L1" % self.jetBranchName, jet_L1) self.out.fillBranch("%s_L2L3" % self.jetBranchName, jet_L2L3) self.out.fillBranch("%s_LRes" % self.jetBranchName, jet_LRes) if self.doGroomed : self.out.fillBranch("%s_msoftdrop_raw" % self.jetBranchName, jets_msdcorr_raw) self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName, jets_msdcorr_nom) self.out.fillBranch("%s_msoftdrop_corr_JMS" % self.jetBranchName, jets_msdcorr_corr_JMS) self.out.fillBranch("%s_msoftdrop_corr_JMR" % self.jetBranchName, jets_msdcorr_corr_JMR) self.out.fillBranch("%s_msoftdrop_jerUp" % self.jetBranchName, jets_msdcorr_jerUp) self.out.fillBranch("%s_msoftdrop_jerDown" % self.jetBranchName, jets_msdcorr_jerDown) self.out.fillBranch("%s_msoftdrop_corr_PUPPI" % self.jetBranchName, jets_msdcorr_corr_PUPPI) self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName, jets_msdcorr_jmrUp) self.out.fillBranch("%s_msoftdrop_jmrDown" % self.jetBranchName, jets_msdcorr_jmrDown) self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName, jets_msdcorr_jmsUp) self.out.fillBranch("%s_msoftdrop_jmsDown" % self.jetBranchName, jets_msdcorr_jmsDown) self.out.fillBranch("%s_msoftdrop_tau21DDT_nom" % self.jetBranchName, jets_msdcorr_tau21DDT_nom) self.out.fillBranch("%s_msoftdrop_tau21DDT_jerUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jerUp) self.out.fillBranch("%s_msoftdrop_tau21DDT_jerDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jerDown) self.out.fillBranch("%s_msoftdrop_tau21DDT_jmrUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jmrUp) self.out.fillBranch("%s_msoftdrop_tau21DDT_jmrDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jmrDown) self.out.fillBranch("%s_msoftdrop_tau21DDT_jmsUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jmsUp) self.out.fillBranch("%s_msoftdrop_tau21DDT_jmsDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jmsDown) if self.corrMET : self.out.fillBranch("%s_pt_nom" % self.metBranchName, math.sqrt(met_px_nom**2 + met_py_nom**2)) self.out.fillBranch("%s_phi_nom" % self.metBranchName, math.atan2(met_py_nom, met_px_nom)) self.out.fillBranch("%s_pt_jerUp" % self.metBranchName, math.sqrt(met_px_jerUp**2 + met_py_jerUp**2)) self.out.fillBranch("%s_phi_jerUp" % self.metBranchName, math.atan2(met_py_jerUp, met_px_jerUp)) self.out.fillBranch("%s_pt_jerDown" % self.metBranchName, math.sqrt(met_px_jerDown**2 + met_py_jerDown**2)) self.out.fillBranch("%s_phi_jerDown" % self.metBranchName, math.atan2(met_py_jerDown, met_px_jerDown)) for jesUncertainty in self.jesUncertainties: self.out.fillBranch("%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_pt_jesUp[jesUncertainty]) self.out.fillBranch("%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_pt_jesDown[jesUncertainty]) self.out.fillBranch("%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_mass_jesUp[jesUncertainty]) self.out.fillBranch("%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_mass_jesDown[jesUncertainty]) if self.doGroomed : self.out.fillBranch("%s_msoftdrop_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesUp[jesUncertainty]) self.out.fillBranch("%s_msoftdrop_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesDown[jesUncertainty]) if self.corrMET: self.out.fillBranch("%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesUp[jesUncertainty]**2 + met_py_jesUp[jesUncertainty]**2)) self.out.fillBranch("%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesUp[jesUncertainty], met_px_jesUp[jesUncertainty])) self.out.fillBranch("%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesDown[jesUncertainty]**2 + met_py_jesDown[jesUncertainty]**2)) self.out.fillBranch("%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesDown[jesUncertainty], met_px_jesDown[jesUncertainty])) if self.corrMET: self.out.fillBranch("%s_pt_unclustEnUp" % self.metBranchName, math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2)) self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName, math.atan2(met_py_unclEnUp, met_px_unclEnUp)) self.out.fillBranch("%s_pt_unclustEnDown" % self.metBranchName, math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2)) self.out.fillBranch("%s_phi_unclustEnDown" % self.metBranchName, math.atan2(met_py_unclEnDown, met_px_unclEnDown)) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName) genJets = Collection(event, self.genJetBranchName) if self.doGroomed: subJets = Collection(event, self.subJetBranchName) genSubJets = Collection(event, self.genSubJetBranchName) genSubJetMatcher = matchObjectCollectionMultiple(genJets, genSubJets, dRmax=0.8) jets_pt_nom = [] jets_pt_jerUp = [] jets_pt_jerDown = [] jets_pt_jesUp = {} jets_pt_jesDown = {} jets_mass_nom = [] jets_mass_jerUp = [] jets_mass_jerDown = [] jets_mass_jmrUp = [] jets_mass_jmrDown = [] jets_mass_jesUp = {} jets_mass_jesDown = {} jets_mass_jmsUp = [] jets_mass_jmsDown = [] for jesUncertainty in self.jesUncertainties: jets_pt_jesUp[jesUncertainty] = [] jets_pt_jesDown[jesUncertainty] = [] jets_mass_jesUp[jesUncertainty] = [] jets_mass_jesDown[jesUncertainty] = [] if self.corrMET: met = Object(event, self.metBranchName) (met_px, met_py) = (met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)) (met_px_nom, met_py_nom) = (met_px, met_py) (met_px_jerUp, met_py_jerUp) = (met_px, met_py) (met_px_jerDown, met_py_jerDown) = (met_px, met_py) (met_px_jesUp, met_py_jesUp) = ({}, {}) (met_px_jesDown, met_py_jesDown) = ({}, {}) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px met_py_jesUp[jesUncertainty] = met_py met_px_jesDown[jesUncertainty] = met_px met_py_jesDown[jesUncertainty] = met_py if self.doGroomed: jets_msdcorr_nom = [] jets_msdcorr_jerUp = [] jets_msdcorr_jerDown = [] jets_msdcorr_jmrUp = [] jets_msdcorr_jmrDown = [] jets_msdcorr_jesUp = {} jets_msdcorr_jesDown = {} jets_msdcorr_jmsUp = [] jets_msdcorr_jmsDown = [] for jesUncertainty in self.jesUncertainties: jets_msdcorr_jesUp[jesUncertainty] = [] jets_msdcorr_jesDown[jesUncertainty] = [] rho = getattr(event, self.rhoBranchName) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) pairs = matchObjectCollection(jets, genJets) for jet in jets: genJet = pairs[jet] if self.doGroomed: genGroomedSubJets = genSubJetMatcher[ genJet] if genJet != None else None genGroomedJet = genGroomedSubJets[0].p4() + genGroomedSubJets[ 1].p4() if genGroomedSubJets != None and len( genGroomedSubJets) >= 2 else None if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0: groomedP4 = subJets[jet.subJetIdx1].p4() + subJets[ jet.subJetIdx2].p4() else: groomedP4 = None # evaluate JER scale factors and uncertainties # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution ) (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt( jet, genJet, rho) jet_pt = jet.pt if self.redoJEC: jet_pt = self.jetReCalibrator.correct(jet, rho) jet_pt_nom = jet_pt_jerNomVal * jet_pt if jet_pt_nom < 0.0: jet_pt_nom *= -1.0 jet_pt_jerUp = jet_pt_jerUpVal * jet_pt jet_pt_jerDown = jet_pt_jerDownVal * jet_pt jets_pt_nom.append(jet_pt_nom) jets_pt_jerUp.append(jet_pt_jerUpVal * jet_pt) jets_pt_jerDown.append(jet_pt_jerDownVal * jet_pt) # evaluate JES uncertainties jet_pt_jesUp = {} jet_pt_jesDown = {} jet_mass_jesUp = {} jet_mass_jesDown = {} jet_mass_jmsUp = [] jet_mass_jmsDown = [] # Evaluate JMS and JMR scale factors and uncertainties jmsNomVal = self.jmsVals[0] jmsDownVal = self.jmsVals[1] jmsUpVal = self.jmsVals[2] (jet_mass_jmrNomVal, jet_mass_jmrUpVal, jet_mass_jmrDownVal) = self.jetSmearer.getSmearValsM(jet, genJet) jet_mass_nom = jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsNomVal * jet.mass if jet_mass_nom < 0.0: jet_mass_nom *= -1.0 jets_mass_nom.append(jet_mass_nom) jets_mass_jerUp.append(jet_pt_jerUpVal * jet_mass_jmrNomVal * jmsNomVal * jet.mass) jets_mass_jerDown.append(jet_pt_jerDownVal * jet_mass_jmrNomVal * jmsNomVal * jet.mass) jets_mass_jmrUp.append(jet_pt_jerNomVal * jet_mass_jmrUpVal * jmsNomVal * jet.mass) jets_mass_jmrDown.append(jet_pt_jerNomVal * jet_mass_jmrDownVal * jmsNomVal * jet.mass) jets_mass_jmsUp.append(jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsUpVal * jet.mass) jets_mass_jmsDown.append(jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsDownVal * jet.mass) if self.doGroomed: # to evaluate JES uncertainties jet_msdcorr_jmsUp = [] jet_msdcorr_jmsDown = [] jet_msdcorr_jesUp = {} jet_msdcorr_jesDown = {} (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal, jet_msdcorr_jmrDownVal) = self.jetSmearer.getSmearValsM( groomedP4, genGroomedJet ) if groomedP4 != None and genGroomedJet != None else (0., 0., 0.) jet_msdcorr_raw = groomedP4.M() if groomedP4 != None else 0.0 if jet_msdcorr_raw < 0.0: jet_msdcorr_raw *= -1.0 jet_msdcorr_nom = jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jet_msdcorr_raw jets_msdcorr_nom.append(jet_msdcorr_nom) jets_msdcorr_jerUp.append(jet_pt_jerUpVal * jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw) jets_msdcorr_jerDown.append(jet_pt_jerDownVal * jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw) jets_msdcorr_jmrUp.append(jet_pt_jerNomVal * jet_msdcorr_jmrUpVal * jmsNomVal * jet_msdcorr_raw) jets_msdcorr_jmrDown.append( jet_pt_jerNomVal * jet_msdcorr_jmrDownVal * jmsNomVal * jet_msdcorr_raw) jets_msdcorr_jmsUp.append(jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsUpVal * jet_msdcorr_raw) jets_msdcorr_jmsDown.append( jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsDownVal * jet_msdcorr_raw) for jesUncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties ) self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[jesUncertainty].getUncertainty( True) jet_pt_jesUp[jesUncertainty] = jet_pt_nom * (1. + delta) jet_pt_jesDown[jesUncertainty] = jet_pt_nom * (1. - delta) jets_pt_jesUp[jesUncertainty].append( jet_pt_jesUp[jesUncertainty]) jets_pt_jesDown[jesUncertainty].append( jet_pt_jesDown[jesUncertainty]) jet_mass_jesUp[jesUncertainty] = jet_mass_nom * (1. + delta) jet_mass_jesDown[jesUncertainty] = jet_mass_nom * (1. - delta) jets_mass_jesUp[jesUncertainty].append( jet_mass_jesUp[jesUncertainty]) jets_mass_jesDown[jesUncertainty].append( jet_mass_jesDown[jesUncertainty]) if self.doGroomed: jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom * ( 1. + delta) jet_msdcorr_jesDown[jesUncertainty] = jet_msdcorr_nom * ( 1. - delta) jets_msdcorr_jesUp[jesUncertainty].append( jet_msdcorr_jesUp[jesUncertainty]) jets_msdcorr_jesDown[jesUncertainty].append( jet_msdcorr_jesDown[jesUncertainty]) # progate JER and JES corrections and uncertainties to MET if self.corrMET and jet_pt_nom > self.unclEnThreshold: jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) met_px_nom = met_px_nom - (jet_pt_nom - jet_pt) * jet_cosPhi met_py_nom = met_py_nom - (jet_pt_nom - jet_pt) * jet_sinPhi met_px_jerUp = met_px_jerUp - (jet_pt_jerUp - jet_pt_nom) * jet_cosPhi met_py_jerUp = met_py_jerUp - (jet_pt_jerUp - jet_pt_nom) * jet_sinPhi met_px_jerDown = met_px_jerDown - (jet_pt_jerDown - jet_pt_nom) * jet_cosPhi met_py_jerDown = met_py_jerDown - (jet_pt_jerDown - jet_pt_nom) * jet_sinPhi for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[ jesUncertainty] - (jet_pt_jesUp[jesUncertainty] - jet_pt_nom) * jet_cosPhi met_py_jesUp[jesUncertainty] = met_py_jesUp[ jesUncertainty] - (jet_pt_jesUp[jesUncertainty] - jet_pt_nom) * jet_sinPhi met_px_jesDown[jesUncertainty] = met_px_jesDown[ jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_nom) * jet_cosPhi met_py_jesDown[jesUncertainty] = met_py_jesDown[ jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_nom) * jet_sinPhi # propagate "unclustered energy" uncertainty to MET if self.corrMET: (met_px_unclEnUp, met_py_unclEnUp) = (met_px, met_py) (met_px_unclEnDown, met_py_unclEnDown) = (met_px, met_py) met_deltaPx_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaX") met_deltaPy_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaY") met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn # propagate effect of jet energy smearing to MET met_px_jerUp = met_px_jerUp + (met_px_nom - met_px) met_py_jerUp = met_py_jerUp + (met_py_nom - met_py) met_px_jerDown = met_px_jerDown + (met_px_nom - met_px) met_py_jerDown = met_py_jerDown + (met_py_nom - met_py) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] + ( met_px_nom - met_px) met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] + ( met_py_nom - met_py) met_px_jesDown[jesUncertainty] = met_px_jesDown[ jesUncertainty] + (met_px_nom - met_px) met_py_jesDown[jesUncertainty] = met_py_jesDown[ jesUncertainty] + (met_py_nom - met_py) met_px_unclEnUp = met_px_unclEnUp + (met_px_nom - met_px) met_py_unclEnUp = met_py_unclEnUp + (met_py_nom - met_py) met_px_unclEnDown = met_px_unclEnDown + (met_px_nom - met_px) met_py_unclEnDown = met_py_unclEnDown + (met_py_nom - met_py) self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom) self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp) self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName, jets_pt_jerDown) self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom) self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName, jets_mass_jerUp) self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName, jets_mass_jerDown) self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName, jets_mass_jmrUp) self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName, jets_mass_jmrDown) self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName, jets_mass_jmsUp) self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName, jets_mass_jmsDown) if self.doGroomed: self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName, jets_msdcorr_nom) self.out.fillBranch("%s_msoftdrop_jerUp" % self.jetBranchName, jets_msdcorr_jerUp) self.out.fillBranch("%s_msoftdrop_jerDown" % self.jetBranchName, jets_msdcorr_jerDown) self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName, jets_msdcorr_jmrUp) self.out.fillBranch("%s_msoftdrop_jmrDown" % self.jetBranchName, jets_msdcorr_jmrDown) self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName, jets_msdcorr_jmsUp) self.out.fillBranch("%s_msoftdrop_jmsDown" % self.jetBranchName, jets_msdcorr_jmsDown) if self.corrMET: self.out.fillBranch("%s_pt_nom" % self.metBranchName, math.sqrt(met_px_nom**2 + met_py_nom**2)) self.out.fillBranch("%s_phi_nom" % self.metBranchName, math.atan2(met_py_nom, met_px_nom)) self.out.fillBranch("%s_pt_jerUp" % self.metBranchName, math.sqrt(met_px_jerUp**2 + met_py_jerUp**2)) self.out.fillBranch("%s_phi_jerUp" % self.metBranchName, math.atan2(met_py_jerUp, met_px_jerUp)) self.out.fillBranch( "%s_pt_jerDown" % self.metBranchName, math.sqrt(met_px_jerDown**2 + met_py_jerDown**2)) self.out.fillBranch("%s_phi_jerDown" % self.metBranchName, math.atan2(met_py_jerDown, met_px_jerDown)) for jesUncertainty in self.jesUncertainties: self.out.fillBranch( "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_pt_jesUp[jesUncertainty]) self.out.fillBranch( "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_pt_jesDown[jesUncertainty]) self.out.fillBranch( "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_mass_jesUp[jesUncertainty]) self.out.fillBranch( "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_mass_jesDown[jesUncertainty]) if self.doGroomed: self.out.fillBranch( "%s_msoftdrop_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesUp[jesUncertainty]) self.out.fillBranch( "%s_msoftdrop_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesDown[jesUncertainty]) if self.corrMET: self.out.fillBranch( "%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesUp[jesUncertainty]**2 + met_py_jesUp[jesUncertainty]**2)) self.out.fillBranch( "%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesUp[jesUncertainty], met_px_jesUp[jesUncertainty])) self.out.fillBranch( "%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesDown[jesUncertainty]**2 + met_py_jesDown[jesUncertainty]**2)) self.out.fillBranch( "%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesDown[jesUncertainty], met_px_jesDown[jesUncertainty])) if self.corrMET: self.out.fillBranch( "%s_pt_unclustEnUp" % self.metBranchName, math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2)) self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName, math.atan2(met_py_unclEnUp, met_px_unclEnUp)) self.out.fillBranch( "%s_pt_unclustEnDown" % self.metBranchName, math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2)) self.out.fillBranch( "%s_phi_unclustEnDown" % self.metBranchName, math.atan2(met_py_unclEnDown, met_px_unclEnDown)) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName) genJets = Collection(event, self.genJetBranchName) jets_pt_smeared = [] jets_pt_jerUp = [] jets_pt_jerDown = [] jets_pt_jesUp = {} jets_pt_jesDown = {} for jesUncertainty in self.jesUncertainties: jets_pt_jesUp[jesUncertainty] = [] jets_pt_jesDown[jesUncertainty] = [] met = Object(event, self.metBranchName) (met_px, met_py) = (met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)) (met_px_smeared, met_py_smeared) = (met_px, met_py) (met_px_jerUp, met_py_jerUp) = (met_px, met_py) (met_px_jerDown, met_py_jerDown) = (met_px, met_py) (met_px_jesUp, met_py_jesUp) = ({}, {}) (met_px_jesDown, met_py_jesDown) = ({}, {}) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px met_py_jesUp[jesUncertainty] = met_py met_px_jesDown[jesUncertainty] = met_px met_py_jesDown[jesUncertainty] = met_py rho = getattr(event, self.rhoBranchName) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) pairs = matchObjectCollection(jets, genJets) for jet in jets: genJet = pairs[jet] # evaluate JER scale factors and uncertainties # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution ) (jet_pt_smeared, jet_pt_jerUp, jet_pt_jerDown) = self.jetSmearer.getSmearedJetPt( jet, genJet, rho) jet_pt_ref = None if self.applyJERCorr: jet_pt_ref = jet_pt_smeared else: jet_pt_ref = jet.pt jet_pt_jerUp = jet_pt_jerUp * jet.pt / jet_pt_smeared jet_pt_jerDown = jet_pt_jerDown * jet.pt / jet_pt_smeared jets_pt_smeared.append(jet_pt_smeared) jets_pt_jerUp.append(jet_pt_jerUp) jets_pt_jerDown.append(jet_pt_jerDown) # evaluate JES uncertainties jet_pt_jesUp = {} jet_pt_jesDown = {} for jesUncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties ) self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_ref) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[jesUncertainty].getUncertainty( True) jet_pt_jesUp[jesUncertainty] = jet_pt_ref * (1. + delta) jet_pt_jesDown[jesUncertainty] = jet_pt_ref * (1. - delta) jets_pt_jesUp[jesUncertainty].append( jet_pt_jesUp[jesUncertainty]) jets_pt_jesDown[jesUncertainty].append( jet_pt_jesDown[jesUncertainty]) # progate JER and JES corrections and uncertainties to MET if jet_pt_ref > self.unclEnThreshold: jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) if self.applyJERCorr: met_px_smeared = met_px_smeared - (jet_pt_smeared - jet.pt) * jet_cosPhi met_py_smeared = met_py_smeared - (jet_pt_smeared - jet.pt) * jet_sinPhi met_px_jerUp = met_px_jerUp - (jet_pt_jerUp - jet_pt_ref) * jet_cosPhi met_py_jerUp = met_py_jerUp - (jet_pt_jerUp - jet_pt_ref) * jet_sinPhi met_px_jerDown = met_px_jerDown - (jet_pt_jerDown - jet_pt_ref) * jet_cosPhi met_py_jerDown = met_py_jerDown - (jet_pt_jerDown - jet_pt_ref) * jet_sinPhi for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[ jesUncertainty] - (jet_pt_jesUp[jesUncertainty] - jet_pt_ref) * jet_cosPhi met_py_jesUp[jesUncertainty] = met_py_jesUp[ jesUncertainty] - (jet_pt_jesUp[jesUncertainty] - jet_pt_ref) * jet_sinPhi met_px_jesDown[jesUncertainty] = met_px_jesDown[ jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_ref) * jet_cosPhi met_py_jesDown[jesUncertainty] = met_py_jesDown[ jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_ref) * jet_sinPhi # propagate "unclustered energy" uncertainty to MET (met_px_unclEnUp, met_py_unclEnUp) = (met_px, met_py) (met_px_unclEnDown, met_py_unclEnDown) = (met_px, met_py) met_deltaPx_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaX") met_deltaPy_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaY") met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn # propagate effect of jet energy smearing to MET if self.applyJERCorr: met_px_jerUp = met_px_jerUp + (met_px_smeared - met_px) met_py_jerUp = met_py_jerUp + (met_py_smeared - met_py) met_px_jerDown = met_px_jerDown + (met_px_smeared - met_px) met_py_jerDown = met_py_jerDown + (met_py_smeared - met_py) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] + ( met_px_smeared - met_px) met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] + ( met_py_smeared - met_py) met_px_jesDown[jesUncertainty] = met_px_jesDown[ jesUncertainty] + (met_px_smeared - met_px) met_py_jesDown[jesUncertainty] = met_py_jesDown[ jesUncertainty] + (met_py_smeared - met_py) met_px_unclEnUp = met_px_unclEnUp + (met_px_smeared - met_px) met_py_unclEnUp = met_py_unclEnUp + (met_py_smeared - met_py) met_px_unclEnDown = met_px_unclEnDown + (met_px_smeared - met_px) met_py_unclEnDown = met_py_unclEnDown + (met_py_smeared - met_py) self.out.fillBranch("%s_pt_smeared" % self.jetBranchName, jets_pt_smeared) self.out.fillBranch("%s_pt_smeared" % self.metBranchName, math.sqrt(met_px_smeared**2 + met_py_smeared**2)) self.out.fillBranch("%s_phi_smeared" % self.metBranchName, math.atan2(met_py_smeared, met_px_smeared)) self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp) self.out.fillBranch("%s_pt_jerUp" % self.metBranchName, math.sqrt(met_px_jerUp**2 + met_py_jerUp**2)) self.out.fillBranch("%s_phi_jerUp" % self.metBranchName, math.atan2(met_py_jerUp, met_px_jerUp)) self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName, jets_pt_jerDown) self.out.fillBranch("%s_pt_jerDown" % self.metBranchName, math.sqrt(met_px_jerDown**2 + met_py_jerDown**2)) self.out.fillBranch("%s_phi_jerDown" % self.metBranchName, math.atan2(met_py_jerDown, met_px_jerDown)) for jesUncertainty in self.jesUncertainties: self.out.fillBranch( "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_pt_jesUp[jesUncertainty]) self.out.fillBranch( "%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesUp[jesUncertainty]**2 + met_py_jesUp[jesUncertainty]**2)) self.out.fillBranch( "%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesUp[jesUncertainty], met_px_jesUp[jesUncertainty])) self.out.fillBranch( "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_pt_jesDown[jesUncertainty]) self.out.fillBranch( "%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesDown[jesUncertainty]**2 + met_py_jesDown[jesUncertainty]**2)) self.out.fillBranch( "%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesDown[jesUncertainty], met_px_jesDown[jesUncertainty])) self.out.fillBranch("%s_pt_unclustEnUp" % self.metBranchName, math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2)) self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName, math.atan2(met_py_unclEnUp, met_px_unclEnUp)) self.out.fillBranch( "%s_pt_unclustEnDown" % self.metBranchName, math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2)) self.out.fillBranch("%s_phi_unclustEnDown" % self.metBranchName, math.atan2(met_py_unclEnDown, met_px_unclEnDown)) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName) nJet = event.nJet lowPtJets = Collection(event, "CorrT1METJet") if self.isV5NanoAOD else [] muons = Collection( event, "Muon" ) # to subtract out of the jets for proper type-1 MET corrections if not self.isData: genJets = Collection(event, self.genJetBranchName) # prepare the low pt jets (they don't have a rawFactor) for jet in lowPtJets: jet.pt = jet.rawPt jet.rawFactor = 0 jet.mass = 0 # the following dummy values should be removed once the values are kept in nanoAOD jet.neEmEF = 0 jet.chEmEF = 0 if not self.isData: self.jetSmearer.setSeed(event) jets_pt_raw = [] jets_pt_jer = [] jets_pt_nom = [] jets_mass_raw = [] jets_mass_nom = [] jets_corr_JEC = [] jets_corr_JER = [] jets_pt_jerUp = [] jets_pt_jerDown = [] jets_pt_jesUp = {} jets_pt_jesDown = {} jets_mass_jerUp = [] jets_mass_jerDown = [] jets_mass_jesUp = {} jets_mass_jesDown = {} for jesUncertainty in self.jesUncertainties: jets_pt_jesUp[jesUncertainty] = [] jets_pt_jesDown[jesUncertainty] = [] jets_mass_jesUp[jesUncertainty] = [] jets_mass_jesDown[jesUncertainty] = [] met = Object(event, self.metBranchName) rawmet = Object(event, "RawMET") if "Puppi" in self.metBranchName: rawmet = Object(event, "RawPuppiMET") defmet = Object(event, "MET") (t1met_px, t1met_py) = (met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)) (def_met_px, def_met_py) = (defmet.pt * math.cos(defmet.phi), defmet.pt * math.sin(defmet.phi)) (met_px, met_py) = (rawmet.pt * math.cos(rawmet.phi), rawmet.pt * math.sin(rawmet.phi)) (met_px_nom, met_py_nom) = (met_px, met_py) (met_px_jer, met_py_jer) = (met_px, met_py) (met_px_jerUp, met_py_jerUp) = (met_px, met_py) (met_px_jerDown, met_py_jerDown) = (met_px, met_py) (met_px_jesUp, met_py_jesUp) = ({}, {}) (met_px_jesDown, met_py_jesDown) = ({}, {}) for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px met_py_jesUp[jesUncertainty] = met_py met_px_jesDown[jesUncertainty] = met_px met_py_jesDown[jesUncertainty] = met_py # variables needed for re-applying JECs to 2017 v2 MET delta_x_T1Jet, delta_y_T1Jet = 0, 0 delta_x_rawJet, delta_y_rawJet = 0, 0 rho = getattr(event, self.rhoBranchName) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) def resolution_matching(jet, genjet): '''Helper function to match to gen based on pt difference''' params = ROOT.PyJetParametersWrapper() params.setJetEta(jet.eta) params.setJetPt(jet.pt) params.setRho(rho) resolution = self.jetSmearer.jer.getResolution(params) return abs(jet.pt - genjet.pt) < 3 * resolution * jet.pt if not self.isData: pairs = matchObjectCollection(jets, genJets, dRmax=0.2, presel=resolution_matching) lowPtPairs = matchObjectCollection(lowPtJets, genJets, dRmax=0.2, presel=resolution_matching) pairs.update(lowPtPairs) for iJet, jet in enumerate(itertools.chain(jets, lowPtJets)): #jet pt and mass corrections jet_pt = jet.pt jet_mass = jet.mass jet_pt_orig = jet_pt rawFactor = jet.rawFactor #redo JECs if desired if hasattr(jet, "rawFactor"): jet_rawpt = jet_pt * (1 - jet.rawFactor) jet_rawmass = jet_mass * (1 - jet.rawFactor) else: jet_rawpt = -1.0 * jet_pt #If factor not present factor will be saved as -1 jet_rawmass = -1.0 * jet_mass #If factor not present factor will be saved as -1 (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet, rho) (jet_pt_l1, jet_mass_l1) = self.jetReCalibratorL1.correct(jet, rho) jet.pt = jet_pt jet.mass = jet_mass # Get the JEC factors jec = jet_pt / jet_rawpt jecL1 = jet_pt_l1 / jet_rawpt if self.jetReCalibratorProd: jecProd = self.jetReCalibratorProd.correct(jet, rho)[0] / jet_rawpt jecL1Prod = self.jetReCalibratorProdL1.correct( jet, rho)[0] / jet_rawpt if not self.isData: genJet = pairs[jet] # get the jet for type-1 MET newjet = ROOT.TLorentzVector() if self.isV5NanoAOD: newjet.SetPtEtaPhiM( jet_pt_orig * (1 - jet.rawFactor) * (1 - jet.muonSubtrFactor), jet.eta, jet.phi, jet.mass) muon_pt = jet_pt_orig * (1 - jet.rawFactor) * jet.muonSubtrFactor else: newjet.SetPtEtaPhiM(jet_pt_orig * (1 - jet.rawFactor), jet.eta, jet.phi, jet.mass) muon_pt = 0 if hasattr(jet, 'muonIdx1'): if jet.muonIdx1 > -1: if muons[jet.muonIdx1].isGlobal: newjet = newjet - muons[jet.muonIdx1].p4() muon_pt += muons[jet.muonIdx1].pt if jet.muonIdx2 > -1: if muons[jet.muonIdx2].isGlobal: newjet = newjet - muons[jet.muonIdx2].p4() muon_pt += muons[jet.muonIdx2].pt # set the jet pt to the muon subtracted raw pt jet.pt = newjet.Pt() jet.rawFactor = 0 # get the proper jet pts for type-1 MET jet_pt_noMuL1L2L3 = jet.pt * jec jet_pt_noMuL1 = jet.pt * jecL1 # this step is only needed for v2 MET in 2017 when different JECs are applied compared to the nanoAOD production if self.jetReCalibratorProd: jet_pt_noMuProdL1L2L3 = jet.pt * jecProd if jet.pt * jecProd > self.unclEnThreshold else jet.pt jet_pt_noMuProdL1 = jet.pt * jecL1Prod if jet.pt * jecProd > self.unclEnThreshold else jet.pt else: jet_pt_noMuProdL1L2L3 = jet_pt_noMuL1L2L3 jet_pt_noMuProdL1 = jet_pt_noMuL1 ## setting jet back to central values jet.pt = jet_pt jet.rawFactor = rawFactor # evaluate JER scale factors and uncertainties # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution ) if not self.isData: (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt( jet, genJet, rho) else: # if you want to do something with JER in data, please add it here. (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = (1, 1, 1) # these are the important jet pt values #jet_pt_nom = jet_pt if jet_pt > 0 else 0 jet_pt_nom = jet_pt * jet_pt_jerNomVal if self.applySmearing else jet_pt jet_pt_L1L2L3 = jet_pt_noMuL1L2L3 + muon_pt jet_pt_L1 = jet_pt_noMuL1 + muon_pt # not nice, but needed for METv2 in 2017 jet_pt_prodL1L2L3 = jet_pt_noMuProdL1L2L3 + muon_pt jet_pt_prodL1 = jet_pt_noMuProdL1 + muon_pt if self.metBranchName == 'METFixEE2017': # get the delta for removing L1L2L3-L1 corrected jets (corrected with GT from nanoAOD production!!) in the EE region from the default MET branch. if jet_pt_prodL1L2L3 > self.unclEnThreshold and 2.65 < abs( jet.eta) < 3.14 and jet_rawpt < 50: delta_x_T1Jet += ( jet_pt_prodL1L2L3 - jet_pt_prodL1) * math.cos( jet.phi) + jet_rawpt * math.cos(jet.phi) delta_y_T1Jet += ( jet_pt_prodL1L2L3 - jet_pt_prodL1) * math.sin( jet.phi) + jet_rawpt * math.sin(jet.phi) # get the delta for removing raw jets in the EE region from the raw MET if jet_pt_prodL1L2L3 > self.unclEnThreshold and 2.65 < abs( jet.eta) < 3.14 and jet_rawpt < 50: delta_x_rawJet += jet_rawpt * math.cos(jet.phi) delta_y_rawJet += jet_rawpt * math.sin(jet.phi) # don't store the low pt jets in the Jet_pt_nom branch if iJet < nJet: jets_pt_raw.append(jet_rawpt) jets_pt_nom.append(jet_pt_nom) jets_mass_raw.append(jet_rawmass) jets_corr_JEC.append(jet_pt / jet_rawpt) jets_corr_JER.append( jet_pt_jerNomVal) # can be used to undo JER # no need to do this for low pt jets jet_mass_nom = jet_pt_jerNomVal * jet_mass if self.applySmearing else jet_mass if jet_mass_nom < 0.0: jet_mass_nom *= -1.0 jets_mass_nom.append(jet_mass_nom) if not self.isData: jet_pt_jerUp = jet_pt_jerUpVal * jet_pt jet_pt_jerDown = jet_pt_jerDownVal * jet_pt # evaluate JES uncertainties jet_pt_jesUp = {} jet_pt_jesDown = {} jet_pt_jesUpT1 = {} jet_pt_jesDownT1 = {} jet_mass_jesUp = {} jet_mass_jesDown = {} # don't store the low pt jets in the Jet_pt_nom branch if iJet < nJet: jets_pt_jerUp.append(jet_pt_jerUpVal * jet_pt) jets_pt_jerDown.append(jet_pt_jerDownVal * jet_pt) jets_mass_jerUp.append(jet_pt_jerUpVal * jet_mass) jets_mass_jerDown.append(jet_pt_jerDownVal * jet_mass) for jesUncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties ) self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[jesUncertainty].getUncertainty( True) jet_pt_jesUp[jesUncertainty] = jet_pt_nom * (1. + delta) jet_pt_jesDown[jesUncertainty] = jet_pt_nom * (1. - delta) if iJet < nJet: jets_pt_jesUp[jesUncertainty].append( jet_pt_jesUp[jesUncertainty]) jets_pt_jesDown[jesUncertainty].append( jet_pt_jesDown[jesUncertainty]) jet_mass_jesUp[jesUncertainty] = jet_mass_nom * (1. + delta) jet_mass_jesDown[jesUncertainty] = jet_mass_nom * ( 1. - delta) jets_mass_jesUp[jesUncertainty].append( jet_mass_jesUp[jesUncertainty]) jets_mass_jesDown[jesUncertainty].append( jet_mass_jesDown[jesUncertainty]) # redo JES variations for T1 MET self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_L1L2L3) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[jesUncertainty].getUncertainty( True) jet_pt_jesUpT1[jesUncertainty] = jet_pt_L1L2L3 * (1. + delta) jet_pt_jesDownT1[jesUncertainty] = jet_pt_L1L2L3 * (1. - delta) # progate JER and JES corrections and uncertainties to MET. Only propagate JECs to MET if the corrected pt without the muon is above the threshold if jet_pt_noMuL1L2L3 > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9: if not ( self.metBranchName == 'METFixEE2017' and 2.65 < abs(jet.eta) < 3.14 and jet.pt * (1 - jet.rawFactor) < 50 ): # do not re-correct for jets that aren't included in METv2 recipe jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) met_px_nom = met_px_nom - (jet_pt_L1L2L3 - jet_pt_L1) * jet_cosPhi met_py_nom = met_py_nom - (jet_pt_L1L2L3 - jet_pt_L1) * jet_sinPhi if not self.isData: met_px_jer = met_px_jer - ( jet_pt_L1L2L3 * jet_pt_jerNomVal - jet_pt_L1) * jet_cosPhi met_py_jer = met_py_jer - ( jet_pt_L1L2L3 * jet_pt_jerNomVal - jet_pt_L1) * jet_sinPhi met_px_jerUp = met_px_jerUp - ( jet_pt_L1L2L3 * jet_pt_jerUpVal - jet_pt_L1) * jet_cosPhi met_py_jerUp = met_py_jerUp - ( jet_pt_L1L2L3 * jet_pt_jerUpVal - jet_pt_L1) * jet_sinPhi met_px_jerDown = met_px_jerDown - ( jet_pt_L1L2L3 * jet_pt_jerDownVal - jet_pt_L1) * jet_cosPhi met_py_jerDown = met_py_jerDown - ( jet_pt_L1L2L3 * jet_pt_jerDownVal - jet_pt_L1) * jet_sinPhi for jesUncertainty in self.jesUncertainties: met_px_jesUp[jesUncertainty] = met_px_jesUp[ jesUncertainty] - ( jet_pt_jesUpT1[jesUncertainty] - jet_pt_L1) * jet_cosPhi met_py_jesUp[jesUncertainty] = met_py_jesUp[ jesUncertainty] - ( jet_pt_jesUpT1[jesUncertainty] - jet_pt_L1) * jet_sinPhi met_px_jesDown[jesUncertainty] = met_px_jesDown[ jesUncertainty] - ( jet_pt_jesDownT1[jesUncertainty] - jet_pt_L1) * jet_cosPhi met_py_jesDown[jesUncertainty] = met_py_jesDown[ jesUncertainty] - ( jet_pt_jesDownT1[jesUncertainty] - jet_pt_L1) * jet_sinPhi # propagate "unclustered energy" uncertainty to MET if self.metBranchName == 'METFixEE2017': # Remove the L1L2L3-L1 corrected jets in the EE region from the default MET branch def_met_px += delta_x_T1Jet def_met_py += delta_y_T1Jet # get unclustered energy part that is removed in the v2 recipe met_unclEE_x = def_met_px - t1met_px met_unclEE_y = def_met_py - t1met_py # finalize the v2 recipe for the rawMET by removing the unclustered part in the EE region met_px_nom += delta_x_rawJet - met_unclEE_x met_py_nom += delta_y_rawJet - met_unclEE_y if not self.isData: # apply v2 recipe correction factor also to JER central value and variations met_px_jer += delta_x_rawJet - met_unclEE_x met_py_jer += delta_y_rawJet - met_unclEE_y met_px_jerUp += delta_x_rawJet - met_unclEE_x met_py_jerUp += delta_y_rawJet - met_unclEE_y met_px_jerDown += delta_x_rawJet - met_unclEE_x met_py_jerDown += delta_y_rawJet - met_unclEE_y for jesUncertainty in self.jesUncertainties: met_px_jesUp[ jesUncertainty] += delta_x_rawJet - met_unclEE_x met_py_jesUp[ jesUncertainty] += delta_y_rawJet - met_unclEE_y met_px_jesDown[ jesUncertainty] += delta_x_rawJet - met_unclEE_x met_py_jesDown[ jesUncertainty] += delta_y_rawJet - met_unclEE_y if not self.isData: (met_px_unclEnUp, met_py_unclEnUp) = (met_px_nom, met_py_nom) (met_px_unclEnDown, met_py_unclEnDown) = (met_px_nom, met_py_nom) met_deltaPx_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaX") met_deltaPy_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaY") met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw) self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom) self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC) self.out.fillBranch("%s_corr_JER" % self.jetBranchName, jets_corr_JER) if not self.isData: self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp) self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName, jets_pt_jerDown) self.out.fillBranch("%s_pt_nom" % self.metBranchName, math.sqrt(met_px_nom**2 + met_py_nom**2)) self.out.fillBranch("%s_phi_nom" % self.metBranchName, math.atan2(met_py_nom, met_px_nom)) self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw) self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom) if not self.isData: self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName, jets_mass_jerUp) self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName, jets_mass_jerDown) if not self.isData: self.out.fillBranch("%s_pt_jer" % self.metBranchName, math.sqrt(met_px_jer**2 + met_py_jer**2)) self.out.fillBranch("%s_phi_jer" % self.metBranchName, math.atan2(met_py_jer, met_px_jer)) self.out.fillBranch("%s_pt_jerUp" % self.metBranchName, math.sqrt(met_px_jerUp**2 + met_py_jerUp**2)) self.out.fillBranch("%s_phi_jerUp" % self.metBranchName, math.atan2(met_py_jerUp, met_px_jerUp)) self.out.fillBranch( "%s_pt_jerDown" % self.metBranchName, math.sqrt(met_px_jerDown**2 + met_py_jerDown**2)) self.out.fillBranch("%s_phi_jerDown" % self.metBranchName, math.atan2(met_py_jerDown, met_px_jerDown)) for jesUncertainty in self.jesUncertainties: self.out.fillBranch( "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_pt_jesUp[jesUncertainty]) self.out.fillBranch( "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_pt_jesDown[jesUncertainty]) self.out.fillBranch( "%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesUp[jesUncertainty]**2 + met_py_jesUp[jesUncertainty]**2)) self.out.fillBranch( "%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesUp[jesUncertainty], met_px_jesUp[jesUncertainty])) self.out.fillBranch( "%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesDown[jesUncertainty]**2 + met_py_jesDown[jesUncertainty]**2)) self.out.fillBranch( "%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesDown[jesUncertainty], met_px_jesDown[jesUncertainty])) self.out.fillBranch( "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_mass_jesUp[jesUncertainty]) self.out.fillBranch( "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_mass_jesDown[jesUncertainty]) self.out.fillBranch( "%s_pt_unclustEnUp" % self.metBranchName, math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2)) self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName, math.atan2(met_py_unclEnUp, met_px_unclEnUp)) self.out.fillBranch( "%s_pt_unclustEnDown" % self.metBranchName, math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2)) self.out.fillBranch( "%s_phi_unclustEnDown" % self.metBranchName, math.atan2(met_py_unclEnDown, met_px_unclEnDown)) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName) genJets = Collection(event, self.genJetBranchName) rho = getattr(event, self.rhoBranchName) if not self.hasMass: backupJets = Collection(event, self.backupColl) def isResMatching(jet, genJet): params = ROOT.PyJetParametersWrapper() params.setJetEta(jet.eta) params.setJetPt(jet.pt) params.setRho(rho) resolution = self.jer.getResolution(params) #super return abs(jet.pt - genJet.pt) < 3 * resolution * jet.pt pairs = matchObjectCollection(jets, genJets, dRmax=0.2, presel=isResMatching) #randomize smearer self.setSeed(event) jets_pt_nom = [] jets_mass_nom = [] jets_corr_JER = [] jets_pt_JERUp = [] jets_pt_JERDown = [] jets_mass_JERUp = [] jets_mass_JERDown = [] for iJet, jet in enumerate(jets): genJet = pairs[jet] if not self.hasMass: jet.mass = backupJets[jet.jetIdx].mass if self.era == "2016" and jet.pt < 50 and abs(jet.eta) > 2.5: # Special treatment in 2016: We observed that jet horns arise in MC when applying JER to all jets in 2016 (causing data/MC disagreement) # Recipe agreed on with JetMET: Don't apply 2016 JER on low pT jets in the forward region (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = (1.0, 1.0, 1.0) else: #evaluate JER SF for central and up/down variations (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.getSmearValsPt(jet, genJet, rho) #super jet_pt_nom = jet.pt * jet_pt_jerNomVal jet_pt_JERUp = jet.pt * jet_pt_jerUpVal jet_pt_JERDown = jet.pt * jet_pt_jerDownVal if not self.hasMass: jet_mass_nom = backupJets[jet.jetIdx].mass * jet_pt_jerNomVal jet_mass_JERUp = backupJets[jet.jetIdx].mass * jet_pt_jerUpVal jet_mass_JERDown = backupJets[ jet.jetIdx].mass * jet_pt_jerDownVal else: jet_mass_nom = jet.mass * jet_pt_jerNomVal jet_mass_JERUp = jet.mass * jet_pt_jerUpVal jet_mass_JERDown = jet.mass * jet_pt_jerDownVal jets_pt_nom.append(jet_pt_nom) jets_mass_nom.append(jet_mass_nom) jets_corr_JER.append(jet_pt_jerNomVal) jets_pt_JERUp.append(jet_pt_JERUp) jets_pt_JERDown.append(jet_pt_JERDown) jets_mass_JERUp.append(jet_mass_JERUp) jets_mass_JERDown.append(jet_mass_JERDown) # Reorder # # e.g. if pt is [ 26, 24, 27 ] # you get: order = [ 2, 0, 1] # order = sorted(range(len(jets_pt_nom)), key=jets_pt_nom.__getitem__, reverse=True) #Save to updated branches to jet collection for typ in self.collBr: for bname in self.collBr[typ]: if '_pt' in bname: temp_v = [jets_pt_nom[idx] for idx in order] self.out.fillBranch(bname, temp_v) elif '_mass' in bname: temp_v = [jets_mass_nom[idx] for idx in order] self.out.fillBranch(bname, temp_v) else: temp_b = bname.replace(self.jetBranchName + '_', '') temp_v = [jets[idx][temp_b] for idx in order] self.out.fillBranch(bname, temp_v) #Save new branches to jet collection self.out.fillBranch("%s_corr_JER" % self.jetBranchName, [jets_corr_JER[idx] for idx in order]) self.out.fillBranch("%s_pt_JERUp" % self.jetBranchName, [jets_pt_JERUp[idx] for idx in order]) self.out.fillBranch("%s_pt_JERDown" % self.jetBranchName, [jets_pt_JERDown[idx] for idx in order]) self.out.fillBranch("%s_mass_JERUp" % self.jetBranchName, [jets_mass_JERUp[idx] for idx in order]) self.out.fillBranch("%s_mass_JERDown" % self.jetBranchName, [jets_mass_JERDown[idx] for idx in order]) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" jets = Collection(event, self.jetBranchName) genJets = Collection(event, self.genJetBranchName) rho = getattr(event, self.rhoBranchName) if not self.hasMass: backupJets = Collection(event, self.backupColl) def isResMatching(jet, genJet): params = ROOT.PyJetParametersWrapper() params.setJetEta(jet.eta) params.setJetPt(jet.pt) params.setRho(rho) resolution = self.jer.getResolution(params) #super return abs(jet.pt - genJet.pt) < 3 * resolution * jet.pt pairs = matchObjectCollection(jets, genJets, dRmax=0.2, presel=isResMatching) #randomize smearer self.setSeed(event) jets_pt_nom = [] jets_mass_nom = [] jets_corr_JER = [] jets_pt_JERUp = [] jets_pt_JERDown = [] jets_mass_JERUp = [] jets_mass_JERDown = [] for iJet, jet in enumerate(jets): genJet = pairs[jet] if not self.hasMass: jet.mass = backupJets[jet.jetIdx].mass #evaluate JER SF for central and up/down variations (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.getSmearValsPt(jet, genJet, rho) #super jet_pt_nom = jet.pt * jet_pt_jerNomVal jet_pt_JERUp = jet.pt * jet_pt_jerUpVal jet_pt_JERDown = jet.pt * jet_pt_jerDownVal if not self.hasMass: jet_mass_nom = backupJets[jet.jetIdx].mass * jet_pt_jerNomVal jet_mass_JERUp = backupJets[jet.jetIdx].mass * jet_pt_jerUpVal jet_mass_JERDown = backupJets[ jet.jetIdx].mass * jet_pt_jerDownVal else: jet_mass_nom = jet.mass * jet_pt_jerNomVal jet_mass_JERUp = jet.mass * jet_pt_jerUpVal jet_mass_JERDown = jet.mass * jet_pt_jerDownVal jets_pt_nom.append(jet_pt_nom) jets_mass_nom.append(jet_mass_nom) jets_corr_JER.append(jet_pt_jerNomVal) jets_pt_JERUp.append(jet_pt_JERUp) jets_pt_JERDown.append(jet_pt_JERDown) jets_mass_JERUp.append(jet_mass_JERUp) jets_mass_JERDown.append(jet_mass_JERDown) #Reorder order = [] for idx1, pt1 in enumerate(jets_pt_nom): pt_idx = 0 for idx2, pt2 in enumerate(jets_pt_nom): if pt1 < pt2 or (pt1 == pt2 and idx1 > idx2): pt_idx += 1 order.append(pt_idx) #Save to updated branches to jet collection for typ in self.collBr: for bname in self.collBr[typ]: if '_pt' in bname: temp_v = [jets_pt_nom[idx] for idx in order] self.out.fillBranch(bname, temp_v) elif '_mass' in bname: temp_v = [jets_mass_nom[idx] for idx in order] self.out.fillBranch(bname, temp_v) else: temp_b = bname.replace(self.jetBranchName + '_', '') temp_v = [jets[idx][temp_b] for idx in order] self.out.fillBranch(bname, temp_v) #Save new branches to jet collection self.out.fillBranch("%s_corr_JER" % self.jetBranchName, [jets_corr_JER[idx] for idx in order]) self.out.fillBranch("%s_pt_JERUp" % self.jetBranchName, [jets_pt_JERUp[idx] for idx in order]) self.out.fillBranch("%s_pt_JERDown" % self.jetBranchName, [jets_pt_JERDown[idx] for idx in order]) self.out.fillBranch("%s_mass_JERUp" % self.jetBranchName, [jets_mass_JERUp[idx] for idx in order]) self.out.fillBranch("%s_mass_JERDown" % self.jetBranchName, [jets_mass_JERDown[idx] for idx in order]) return True
def analyze(self, event): jets = Collection(event, self.jetBranchName) genJets = Collection(event, self.genJetBranchName) self.corrMET = True jets_pt_nom = [] jets_pt_jerUp = [] jets_pt_jerDown = [] jets_pt_jesUp = {} jets_pt_jesDown = {} for jesUncertainty in self.jesUncertainties: jets_pt_jesUp[jesUncertainty] = [] jets_pt_jesDown[jesUncertainty] = [] if self.corrMET: met = Object(event, self.metBranchName) met.px = met.pt * math.cos(met.phi) met.py = met.pt * math.sin(met.phi) met.px_jerNominal, met.py_jerNominal = met.px, met.py met.px_jerUp, met.py_jerUp = met.px, met.py met.px_jerDown, met.py_jerDown = met.px, met.py met.px_jesUp, met.py_jesUp = {}, {} met.px_jesDown, met.py_jesDown = {}, {} for jesUncertainty in self.jesUncertainties: met.px_jesUp[jesUncertainty], met.py_jesUp[ jesUncertainty] = met.px, met.py met.px_jesDown[jesUncertainty], met.py_jesDown[ jesUncertainty] = met.px, met.py rho = getattr(event, self.rhoBranchName) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) pairs = matchObjectCollection(jets, genJets) for jet in jets: #jet_jes = PhysicsObject(jet) #print jet_jes.p4().Pt() genJet = pairs[jet] # evaluate JER scale factors and uncertainties # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution ) #these are the smear factors => use for energy instead of pT!!! (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt( jet, genJet, rho) #if self.redoJEC: # jet.pt = self.jetReCalibrator.correct(jet,rho) jet.pt_jerNominal = jet_pt_jerNomVal * jet.pt if jet.pt_jerNominal < 0.0: jet.pt_jerNominal *= -1.0 jet.pt_jerUp = jet_pt_jerUpVal * jet.pt jet.pt_jerDown = jet_pt_jerDownVal * jet.pt jet.pt_jesUp = {} jet.pt_jesDown = {} for jesUncertainty in self.jesUncertainties: # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties ) self.jesUncertainty[jesUncertainty].setJetPt(jet.pt_jerNominal) self.jesUncertainty[jesUncertainty].setJetEta(jet.eta) delta = self.jesUncertainty[jesUncertainty].getUncertainty( True) jet.pt_jesUp[jesUncertainty] = jet.pt_jerNominal * (1. + delta) jet.pt_jesDown[jesUncertainty] = jet.pt_jerNominal * (1. - delta) # progate JER and JES corrections and uncertainties to MET if self.corrMET and jet.pt_jerNominal > self.unclEnThreshold: jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) #propagate nominal jet energy smearing met.px_jerNominal = met.px - (jet.pt_jerNominal - jet.pt) * jet_cosPhi met.py_jerNominal = met.py - (jet.pt_jerNominal - jet.pt) * jet_sinPhi met.px_jerUp = met.px_jerUp - (jet.pt_jerUp - jet.pt_jerNominal) * jet_cosPhi met.py_jerUp = met.py_jerUp - (jet.pt_jerUp - jet.pt_jerNominal) * jet_sinPhi met.px_jerDown = met.px_jerDown - ( jet.pt_jerDown - jet.pt_jerNominal) * jet_cosPhi met.py_jerDown = met.py_jerDown - ( jet.pt_jerDown - jet.pt_jerNominal) * jet_sinPhi for jesUncertainty in self.jesUncertainties: met.px_jesUp[jesUncertainty] = met.px_jesUp[ jesUncertainty] - (jet.pt_jesUp[jesUncertainty] - jet.pt_jerNominal) * jet_cosPhi met.py_jesUp[jesUncertainty] = met.py_jesUp[ jesUncertainty] - (jet.pt_jesUp[jesUncertainty] - jet.pt_jerNominal) * jet_sinPhi met.px_jesDown[jesUncertainty] = met.px_jesDown[ jesUncertainty] - (jet.pt_jesDown[jesUncertainty] - jet.pt_jerNominal) * jet_cosPhi met.py_jesDown[jesUncertainty] = met.py_jesDown[ jesUncertainty] - (jet.pt_jesDown[jesUncertainty] - jet.pt_jerNominal) * jet_sinPhi # propagate "unclustered energy" uncertainty to MET if self.corrMET: met.px_unclEnUp, met.py_unclEnUp = met.px, met.py met.px_unclEnDown, met.py_unclEnDown = met.px, met.py met_deltaPx_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaX") met_deltaPy_unclEn = getattr( event, self.metBranchName + "_MetUnclustEnUpDeltaY") met.px_unclEnUp = met.px_unclEnUp + met_deltaPx_unclEn met.py_unclEnUp = met.py_unclEnUp + met_deltaPy_unclEn met.px_unclEnDown = met.px_unclEnDown - met_deltaPx_unclEn met.py_unclEnDown = met.py_unclEnDown - met_deltaPy_unclEn # propagate effect of jet energy smearing to MET met.px_jerUp = met.px_jerUp + (met.px_jerNominal - met.px) met.py_jerUp = met.py_jerUp + (met.py_jerNominal - met.py) met.px_jerDown = met.px_jerDown + (met.px_jerNominal - met.px) met.py_jerDown = met.py_jerDown + (met.py_jerNominal - met.py) for jesUncertainty in self.jesUncertainties: met.px_jesUp[jesUncertainty] = met.px_jesUp[jesUncertainty] + ( met.px_jerNominal - met.px) met.py_jesUp[jesUncertainty] = met.py_jesUp[jesUncertainty] + ( met.py_jerNominal - met.py) met.px_jesDown[jesUncertainty] = met.px_jesDown[ jesUncertainty] + (met.px_jerNominal - met.px) met.py_jesDown[jesUncertainty] = met.py_jesDown[ jesUncertainty] + (met.py_jerNominal - met.py) met.px_unclEnUp = met.px_unclEnUp + (met.px_jerNominal - met.px) met.py_unclEnUp = met.py_unclEnUp + (met.py_jerNominal - met.py) met.px_unclEnDown = met.px_unclEnDown + (met.px_jerNominal - met.px) met.py_unclEnDown = met.py_unclEnDown + (met.py_jerNominal - met.py) def getJetsSyst(systName="nominal", variation=0): if variation not in [0, -1, 1]: print "Error - variation needs to be either [0,-1,1]!" sys.exit(1) systJets = [] for jet in jets: systJet = PhysicsObject(jet, pt=jet.pt, eta=jet.eta, phi=jet.phi, mass=jet.mass, nConstituents=jet.nConstituents, keys=[ "jetId", "hadronFlavour", "partonFlavour", "genJetIdx", "puId" ]) if systName == "nominal": systJet.pt = jet.pt_jerNominal elif systName == "jer": if variation == 1: systJet.pt = jet.pt_jerUp elif variation == -1: systJet.pt = jet.pt_jerDown else: print "Error - 'jer' variation needs to be either [-1,1]!" sys.exit(1) elif systName.startswith("jes"): subvariation = "Total" if systName.find(':') > 0: subvariation = systName.split(':', 1)[1] if subvariation not in self.jesUncertainties: print "Error - 'jes' subvariation with name '" + subvariation + "' has not been calculated" sys.exit(1) if variation == 1: systJet.pt = jet.pt_jesUp[subvariation] elif variation == -1: systJet.pt = jet.pt_jesDown[subvariation] else: print "Error - 'jer' variation needs to be either [-1,1]!" sys.exit(1) else: print "Error - unknown systematic '" + str(systName) + "'" sys.exit(1) systJets.append(systJet) #sort decreasing in pt systJets = sorted(systJets, key=lambda jet: -jet.pt) return systJets def getMetSyst(systName="nominal", variation=0): if variation not in [0, -1, 1]: print "Error - variation needs to be either [0,-1,1]!" sys.exit(1) systMet = PhysicsObject(met, pt=met.pt, phi=met.phi) if systName == "nominal": systMet.px = met.px_jerNominal systMet.py = met.py_jerNominal elif systName == "jer": if variation == 1: systMet.px = met.px_jerUp systMet.py = met.py_jerUp #print "sys met px var +1 is : ", systMet.px , " sys met py var + 1 is : ", systMet.py elif variation == -1: systMet.px = met.px_jerDown systMet.py = met.py_jerDown #print "sys met px var -1 is : ", systMet.px , " sys met py var -1 is : ", systMet.py else: print "Error - 'jer' variation needs to be either [-1,1]!" sys.exit(1) elif systName.startswith("jes"): subvariation = "Total" if systName.find(':') > 0: subvariation = systName.split(':', 1)[1] if variation == 1: systMet.px = met.px_jesUp[subvariation] systMet.py = met.py_jesUp[subvariation] elif variation == -1: systMet.px = met.px_jesDown[subvariation] systMet.py = met.py_jesDown[subvariation] else: print "Error - 'jer' variation needs to be either [-1,1]!" sys.exit(1) elif systName == "unclEn": if variation == 1: systMet.px = met.px_unclEnUp systMet.py = met.py_unclEnUp elif variation == -1: systMet.px = met.px_unclEnDown systMet.py = met.py_unclEnDown else: print "Error - 'jer' variation needs to be either [-1,1]!" sys.exit(1) else: print "Error - unknown systematic '" + str(systName) + "'" sys.exit(1) systMet.phi = math.atan2(systMet.py, systMet.px) systMet.pt = math.sqrt(systMet.px**2 + systMet.py**2) return systMet event.jets_nominal = getJetsSyst("nominal", 0) event.met_nominal = getMetSyst("nominal", 0) #print map(lambda j: j.pt, jets),met.pt #print map(lambda j: j.pt, event.jets_nominal),event.met_nominal.pt #print event.jets_jerUp = getJetsSyst("jer", 1) event.met_jerUp = getMetSyst("jer", 1) event.jets_jerDown = getJetsSyst("jer", -1) event.met_jerDown = getMetSyst("jer", -1) event.jets_jesUp = {} event.met_jesUp = {} event.jets_jesDown = {} event.met_jesDown = {} for jesUncertainty in self.jesUncertainties: event.jets_jesUp[jesUncertainty] = getJetsSyst( "jes:" + jesUncertainty, 1) event.met_jesUp[jesUncertainty] = getMetSyst( "jes:" + jesUncertainty, 1) event.jets_jesDown[jesUncertainty] = getJetsSyst( "jes:" + jesUncertainty, -1) event.met_jesDown[jesUncertainty] = getMetSyst( "jes:" + jesUncertainty, -1) event.met_unclEnUp = getMetSyst("unclEn", 1) event.met_unclEnDown = getMetSyst("unclEn", -1) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" # Leptons leptonSel(event) nLooseLepton = len(event.selectedLeptons) #Select good leptons (stricter than medium but not as strict as tight) selectedGoodLeptons = [] selectedVetoLeptons = [] antiIsolatedGoodLeptons = [] for lepton in event.selectedLeptons: leptonEta = abs(lepton.eta) # Pt cut if lepton.pt < 10: continue # Iso cut -- to be compatible with the trigger if lepton.miniPFRelIso_all > self.cut.trig_miniIsoCut: continue # MUONS if(abs(lepton.pdgId) == 13): if leptonEta > self.cut.muonEta: continue #passId = False passId = lepton.mediumId passIso = lepton.miniPFRelIso_all < self.cut.muo_miniIsoCut passIP = lepton.sip3d < self.cut.goodMu_sip3d # selected muons if passId and passIP and passIso: selectedGoodLeptons.append(lepton) else: selectedVetoLeptons.append(lepton) if not passIso: antiIsolatedGoodLeptons.append(lepton) # ELECTRONS elif(abs(lepton.pdgId) == 11): if leptonEta > self.cut.electronEta: continue passIso = False passGoodID = lepton.cutBased == 4 passMediumID = lepton.cutBased >= 3 passVetoID = lepton.cutBased >= 1 # selected if passGoodID: passIso = lepton.miniPFRelIso_all < self.cut.ele_miniIsoCut if passIso: selectedGoodLeptons.append(lepton) else: selectedVetoLeptons.append(lepton) # anti-selected elif not passMediumID: # all anti leptons are veto for selected selectedVetoLeptons.append(lepton) # Iso check passIso = lepton.miniPFRelIso_all < self.cut.Lep_miniIsoCut # other checks passOther = False if hasattr(lepton, "hoe"): passOther = lepton.hoe > 0.01 # fill if passIso and passOther: antiIsolatedGoodLeptons.append(lepton) # Veto leptons elif passVetoID: selectedVetoLeptons.append(lepton) for lepton in event.otherLeptons: # check acceptance leptonEta = abs(lepton.eta) if leptonEta > self.cut.electronEta: continue # Pt cut if lepton.pt < self.cut.minLeptonPt: continue # Iso cut -- to be compatible with the trigger if lepton.miniPFRelIso_all > self.cut.trig_miniIsoCut: continue # Muons if(abs(lepton.pdgId) == 13): passIso = lepton.miniPFRelIso_all > self.cut.muo_miniIsoCut if passIso: antiIsolatedGoodLeptons.append(lepton) # Electrons elif(abs(lepton.pdgId) == 11): if leptonEta > self.cut.electronEta: continue if lepton.miniPFRelIso_all > self.cut.Lep_miniIsoCut: continue passMediumID = lepton.cutBased >= 3 passVetoID = lepton.cutBased >= 1 if not passMediumID: passOther = False if hasattr(lepton, "hoe"): passOther = lepton.hoe > 0.01 if passOther: antiIsolatedGoodLeptons.append(lepton) #selectedGoodLeptons, selectedVetoLeptons, antiIsolatedGoodLeptons = self.selectGoodLeptons(event.selectedLeptons, event.otherLeptons) nGoodLepton = len(selectedGoodLeptons) nVetoLepton = len(selectedVetoLeptons) nAntiIsolatedGoodLepton = len(antiIsolatedGoodLeptons) self.out.fillBranch("nGoodLepton", nGoodLepton) self.out.fillBranch("nVetoLepton", nVetoLepton) self.out.fillBranch("nAntiIsolatedGoodLepton", nAntiIsolatedGoodLepton) if nGoodLepton > 0: self.out.fillBranch("leadingLeptonSelected", 1) if nGoodLepton > 1: self.out.fillBranch("secondLeptonSelected", 1) else: self.out.fillBranch("secondLeptonSelected", 0) elif nAntiIsolatedGoodLepton == 0: self.out.fillBranch("leadingLeptonSelected", 0) else: self.out.fillBranch("leadingLeptonSelected", -1) goodElectron = [lep for lep in selectedGoodLeptons if abs(lep.pdgId) == 11] vetoElectron = [lep for lep in selectedVetoLeptons if abs(lep.pdgId) == 11] goodMuon = [lep for lep in selectedGoodLeptons if abs(lep.pdgId) == 13] vetoMuon = [lep for lep in selectedVetoLeptons if abs(lep.pdgId) == 13] nGoodElectron = len(goodElectron) nVetoElectron = len(vetoElectron) nGoodMuon = len(goodMuon) nVetoMuon = len(vetoMuon) self.out.fillBranch("nGoodElectron", nGoodElectron) self.out.fillBranch("nVetoElectron", nVetoElectron) self.out.fillBranch("nGoodMuon", nGoodMuon) self.out.fillBranch("nVetoMuon", nVetoMuon) """ TODO investigate electron energy calibration """ for electron in goodElectron: self.out.fillBranch("goodElectronECorr", electron.eCorr) for electron in vetoElectron: self.out.fillBranch("vetoElectronECorr", electron.eCorr) if nGoodLepton > 0: self.out.fillBranch("leptonPt", selectedGoodLeptons[0].pt) self.out.fillBranch("leptonEta", selectedGoodLeptons[0].eta) self.out.fillBranch("leptonPhi", selectedGoodLeptons[0].phi) self.out.fillBranch("leptonPdgId", selectedGoodLeptons[0].pdgId) self.out.fillBranch("leptonRelIso", selectedGoodLeptons[0].pfRelIso03_all) self.out.fillBranch("leptonMiniIso", selectedGoodLeptons[0].miniPFRelIso_all) if hasattr(selectedGoodLeptons[0], "hoe"): self.out.fillBranch("leptonHOverE", selectedGoodLeptons[0].hoe) if self.isMC: for lepton in selectedGoodLeptons: if abs(lepton.pdgId) == 13: muonScaleFactor = self.workerMuon.getSF(lepton.pdgId, lepton.pt, lepton.eta) self.out.fillBranch("leptonSF", muonScaleFactor) self.out.fillBranch("MuonEffSF", muonScaleFactor) elif abs(lepton.pdgId) == 11: electronScaleFactor = self.workerElectron.getSF(lepton.pdgId, lepton.pt, lepton.eta) self.out.fillBranch("leptonSF", electronScaleFactor) self.out.fillBranch("ElectronEffSF", electronScaleFactor) else: self.out.fillBranch("MuonEffSF", 1.0) self.out.fillBranch("ElectronEffSF", 1.0) self.out.fillBranch("leptonSF", 1.0) else: self.out.fillBranch("MuonEffSF", 1.0) self.out.fillBranch("ElectronEffSF", 1.0) self.out.fillBranch("leptonSF", 1.0) if len(selectedGoodLeptons) > 1: self.out.fillBranch("secondLeptonPt", selectedGoodLeptons[1].pt) # Jets Jets = Collection(event, "Jet") jets = [j for j in Jets if j.pt > 20 and abs(j.eta) < 2.4] centralJets30 = [] centralJets40 = [] cleanJets25 = [] cleanJets = [] # fill this flag but defaults to 1 and then change it after the proper selection self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 1) for index, jet in enumerate(jets): jet.pt = event.Jet_pt_nom[index] if self.isSignal: #only check for signals (see condition check above) self.out.fillBranch("isDPhiSignal",1) genJets = Collection(event, "GenJet" ) pairs = matchObjectCollection(Jets, genJets) genJet = pairs[jet] if genJet is not None : if jet.pt > 20 and abs(jet.eta) < self.cut.jetEta and (genJet.pt == 0) and jet.chHEF < 0.1: self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 0 ) if jet.pt > 25 : cleanJets25.append(jet) if jet.pt > 30 and abs(jet.eta) < self.cut.centralEta: centralJets30.append(jet) if jet.pt > 40 and abs(jet.eta) < self.cut.centralEta: centralJets40.append(jet) nJet = len(jets) nCentralJets30 = len(centralJets30) nCentralJets40 = len(centralJets40) self.out.fillBranch("nJet", nJet) self.out.fillBranch("nJet30", nCentralJets30) self.out.fillBranch("nJet40", nCentralJets40) ############################## ## Local cleaning from leptons ############################## dRminCut = 0.4 #TODO susy cutter # Do cleaning a la CMG: clean max 1 jet for each lepton (the nearest) cleanJets30 = centralJets30 if len(selectedGoodLeptons) > 0: tightLeptons = selectedGoodLeptons elif len(antiIsolatedGoodLeptons) > 0: tightLeptons = antiIsolatedGoodLeptons else: tightLeptons = [] for lepton in tightLeptons: closestJet = None dRmin = 99 for jet in centralJets30: dR = jet.p4().DeltaR(lepton.p4()) if dR < dRmin: closestJet = jet dRmin = dR if dRmin < dRminCut: cleanJets30.remove(closestJet) dR = 99 #TODO think if this makes sense, maybe I just remove ones that are closer thant he closest for jet25 in cleanJets25: dR = jet25.p4().DeltaR(lepton.p4()) if dR < dRmin: cleanJets.append(jet25) # cleaned jets nCleanJet30 = len(cleanJets30) self.out.fillBranch("nCleanJet30", nCleanJet30) if nCleanJet30 > 0: self.out.fillBranch("jetPt", cleanJets30[0].pt) self.out.fillBranch("jetEta", cleanJets30[0].eta) if nCleanJet30 > 1: self.out.fillBranch("jetPt_2", cleanJets30[1].pt) self.out.fillBranch("jetEta_2", cleanJets30[1].eta) # imho, use Jet2_pt > 80 instead TODO why? self.out.fillBranch("LSLjetptGT80", 1 if sum([jet.pt > 80 for jet in cleanJets30]) >= 2 else 0) self.out.fillBranch("HT", sum([j.pt for j in cleanJets30])) self.out.fillBranch("cleanJetHt30", sum([j.pt for j in cleanJets30])) self.out.fillBranch("jetHt30", sum([j.pt for j in jets if j.pt>30])) #centralJetHt40 = sum([jet.pt for jet in centralJets40]) self.out.fillBranch("centralJetHt40", sum([j.pt for j in centralJets40])) #self.out.fillBranch("centralJetHt40", centralJetHt40) ## B tagging WPs for CSVv2 (CSV-IVF) ## from: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBTagging#Preliminary_working_or_operating # WP defined on top #TODO define in init function, possibly use susyCutter btagWP = self.cut.btagMediumWP btagDeepMediumWP = self.cut.btagDeepMediumWP btagLooseWP = self.cut.btagLooseWP BJetMedium30 = [] BJetMedium40 = [] nBJetDeep = 0 for jet in cleanJets30: if jet.btagCSVV2 > btagWP: BJetMedium30.append(jet) if jet.btagDeepB > btagDeepMediumWP: nBJetDeep += 1 for jet in centralJets40: if jet.btagCSVV2 > btagWP: BJetMedium40.append(jet) # using cleaned collection! self.out.fillBranch("nBJet", len(BJetMedium30)) self.out.fillBranch("nBJets30", len(BJetMedium30)) self.out.fillBranch("nBJetDeep", nBJetDeep) # using normal collection self.out.fillBranch("nBJets40", len(BJetMedium40)) #TODO store btag maybe? # High Level Variables dPhiLeptonW = -999 GendPhiLeptonW = -999 LT = -999 GenLT = -999 Lp = -999 MT = -999 metP4 = ROOT.TLorentzVector(0,0,0,0) metP4.SetPtEtaPhiM(event.MET_pt_nom, 0., event.MET_phi_nom, 0) if len(tightLeptons) > 0: #GenrecoWp4 = tightLeptons[0].p4() + GenmetP4 #this does not make sense, use genmet of leptons #GendPhiLeptonW = tightLeptons[0].p4().DeltaPhi(GenrecoWp4) #GenLT = tightLeptons[0].pt + GenmetP4.Pt() recoWp4 = tightLeptons[0].p4() + metP4 dPhiLeptonW = tightLeptons[0].p4().DeltaPhi(recoWp4) LT = tightLeptons[0].pt + metP4.Pt() Lp = tightLeptons[0].pt / recoWp4.Pt() * ROOT.TMath.Cos(dPhiLeptonW) MT = ROOT.TMath.Sqrt(2*metP4.Pt()*tightLeptons[0].pt * (1-ROOT.TMath.Cos(dPhiLeptonW))) dPhi = abs(dPhiLeptonW) self.out.fillBranch("DeltaPhiLepW", dPhiLeptonW) self.out.fillBranch("dPhi", dPhi) #self.out.fillBranch("ST", LT) #ST? What? self.out.fillBranch("LT", LT) self.out.fillBranch("Lp", Lp) self.out.fillBranch("MT", MT) #self.out.fillBranch("GendPhi", abs(GendPhiLeptonW)) #self.out.fillBranch("GenLT", GenLT) #self.out.fillBranch("GenMET", GenmetP4.Pt()) # SIGNAL REGION FLAG # isSignalRegion SR vs CR flag isSignalRegion = 0 # 0-B SRs -- simplified dPhi if len(BJetMedium30) == 0:# check the no. of Bjets if LT < 250: isSignalRegion = 0 elif LT > 250: isSignalRegion = dPhi > 0.75 # BLIND data if (not self.isMC) and nCleanJet30 >= 5: isSignalRegion = - isSignalRegion # Multi-B SRs elif nCleanJet30 < 99: if LT < 250: isSignalRegion = 0 elif LT < 350: isSignalRegion = dPhi > 1.0 elif LT < 600: isSignalRegion = dPhi > 0.75 elif LT > 600: isSignalRegion = dPhi > 0.5 # BLIND data if (not self.isMC) and nCleanJet30 >= 6: isSignalRegion = - isSignalRegion self.out.fillBranch("isSignalRegion", isSignalRegion) ############# ## Playground ############# # di-lepton mass: opposite-sign, same flavour dileptonMass = 0 if len(tightLeptons) > 1: leadingLepton = tightLeptons[0] id1 = leadingLepton.pdgId for trailingLepton in event.selectedLeptons[1:]: # TODO check if this could be tgrue for more than one pair of leptons if trailingLepton.pdgId + leadingLepton.pdgId == 0: dilepP4 = leadingLepton.p4() + trailingLepton.p4() dileptonMass = dilepP4.M() self.out.fillBranch("dileptonMass", dileptonMass) # RA2 proposed filter # TODO Learn what this is self.out.fillBranch("RA2_muJetFilter", True) # normally true for now # don't know how to get the Muon energy fraction from EMEF #for j in cJet30Clean: # if j.pt > 200 and j.chEmEF > 0.5 and abs(ROOT.TMath.ACos(ROOT.TMath.Cos(j.phi-metP4.Phi()))) > (ROOT.TMath.pi - 0.4): # self.out.fillBranch("RA2_muJetFilter", False) ## MET FILTERS for data looks like the met filters are applied already for nanoAOD #TODO check how this is done, in which module # Top Tagging lightJets = [ j for j in cleanJets if not j.btagCSVV2 == btagWP ] bjetsLoose = [ j for j in cleanJets if j.btagCSVV2== self.cut.btagLooseWP] minMWjj = -999 minMWjjPt = -999 bestMWjj = -999 bestMWjjPt = -999 bestMTopHad = -999 bestMTopHadPt = -999 for i1, j1 in enumerate(lightJets): for i2 in xrange(i1+1, len(lightJets)): j2 = lightJets[i2] jjp4 = j1.p4() + j2.p4() mjj = jjp4.M() if mjj > 30 and mjj < minMWjj: minMWjj = mjj minMWjjPt = jjp4.Pt() #self.out.fillBranch("minMWjj", minMWjj) #probably do not fill in here #self.out.fillBranch("minMWjjPt", minMWjjPt) if abs(mjj-80.4) < abs(bestMWjj-80.4): bestMWjj = mjj bestMWjjPt = jjp4.Pt() #self.out.fillBranch("bestMWjj", bestMWjj) #self.out.fillBranch("bestMWjjPt", bestMWjjPt) for bj in bjetsLoose: if deltaR(bj.eta(), bj.phi(), j1.eta(), j1.phi()) < 0.1 or deltaR(bj.eta(), bj.phi(), j2.eta(), j2.phi()) < 0.1: continue tp4 = jjp4 + bj.p4() mtop = tp4.M() if abs(mtop-172) < abs(bestMTopHad - 172): bestMTopHad = mtop bestMTopHadPt = tp4.Pt() #self.out.fillBranch("bestMTopHad", bestMTopHad) #self.out.fillBranch("bestMTopHadPt", bestMTopHadPt) self.out.fillBranch("minMWjj", minMWjj) self.out.fillBranch("minMWjjPt", minMWjjPt) self.out.fillBranch("bestMWjj", bestMWjj) self.out.fillBranch("bestMWjjPt", bestMWjjPt) self.out.fillBranch("bestMTopHad", bestMTopHad) self.out.fillBranch("bestMTopHadPt", bestMTopHadPt) # isolated tracks after basic selection (((pt>5 && (abs(pdgId) == 11 || abs(pdgId) == 13)) || pt > 10) && (abs(pdgId) < 15 || abs(eta) < self.cut.jetEta) && abs(dxy) < 0.2 && abs(dz) < 0.1 && ((pfIsolationDR03().chargedHadronIso < 5 && pt < 25) || pfIsolationDR03().chargedHadronIso/pt < 0.2)) and lepton veto # First check is the event has the IsoTrack or not if hasattr(event, "nIsoTrack"): tracks = [j for j in Collection(event, "IsoTrack", "nIsoTrack")] trackp4 = ROOT.TLorentzVector(0, 0, 0, 0) # min dR between good lep and iso track minDR = 0.1 # MT2 cuts for hadronic and leptonic veto tracks #hadMT2cut = 60 #lepMT2cut = 80 if (len(tightLeptons) > 0) and len(tracks) > 0: #for i, t in enumerate(tracks): for track in tracks: # looking for opposite charged tracks #if tightLeptons[0].charge == track.charge: continue # not track charge is founded replace with the next copule of lines if track.isHighPurityTrack == False : continue #print track.miniPFRelIso_chg # not track mass is founded trackp4.SetPtEtaPhiM(track.pt, track.eta, track.phi,0.) if trackp4.DeltaR(tightLeptons[0].p4()) < minDR: p1 = tightLeptons[0].p4() p2 = trackp4 a = array.array('d', [p1.M(), p1.Px(), p1.Py()]) b = array.array('d', [p2.M(), p2.Px(), p2.Py()]) c = array.array('d', [metP4.M(), metP4.Px(), metP4.Py()]) self.mt2obj.set_momenta(a, b, c) self.mt2obj.set_mn(0) self.out.fillBranch("iso_MT2", self.mt2obj.get_mt2()) self.out.fillBranch("iso_pt", p2.Pt()) # cuts on MT2 as defined above if abs(track.pdgId)>10 and abs(track.pdgId)<14: self.out.fillBranch("iso_had", 0) #leptonic cut = self.cut.lepMT2cut else: self.out.fillBranch("iso_had", 1) #hadronic track cut = self.cut.hadMT2cut if self.mt2obj.get_mt2() <= cut: self.out.fillBranch("iso_Veto", True) #self.out.fillBranch("Xsec", self.xs) if 'JetHT' in self.filename: self.out.fillBranch("PD_JetHT", True) else: self.out.fillBranch("PD_JetHT", False) if 'SingleEle' in self.filename: self.out.fillBranch("PD_SingleElectron", True) else: self.out.fillBranch("PD_SingleElectron", False) if 'SingleMu' in self.filename: self.out.fillBranch("PD_SingleMuon", True) else: self.out.fillBranch("PD_SingleMuon", False) if 'MET' in self.filename: self.out.fillBranch("PD_MET", True) else: self.out.fillBranch("PD_MET", False) return True
def analyze(self, event): """process event, return True (go to next module) or False (fail, go to next event)""" allelectrons = Collection(event, "Electron") allmuons = Collection(event, "Muon") Jets = Collection(event, "Jet") met = Object(event, "MET") genmet = Object(event, "GenMET") # for all leptons (veto or tight) ### inclusive leptons = all leptons that could be considered somewhere in the analysis, with minimal requirements (used e.g. to match to MC) event.inclusiveLeptons = [] ### selected leptons = subset of inclusive leptons passing some basic id definition and pt requirement ### other leptons = subset of inclusive leptons failing some basic id definition and pt requirement event.selectedLeptons = [] event.selectedMuons = [] event.selectedElectrons = [] event.otherLeptons = [] inclusiveMuons = [] inclusiveElectrons = [] for mu in allmuons: if (mu.pt > 10 and abs(mu.eta) < 2.4 and abs(mu.dxy) < 0.5 and abs(mu.dz) < 1.): inclusiveMuons.append(mu) for ele in allelectrons: if ( ele.cutBased >= 1 and ele.pt > 10 and abs(ele.eta) < 2.4 ): # and abs(ele.dxy)<0.5 and abs(ele.dz)<1. and ele.lostHits <=1.0): inclusiveElectrons.append(ele) event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons # make loose leptons (basic selection) for mu in inclusiveMuons: if (mu.pt > 10 and abs(mu.eta) < 2.4 and mu.miniPFRelIso_all < 0.4 and mu.isPFcand and abs(mu.dxy) < 0.05 and abs(mu.dz) < 0.5): event.selectedLeptons.append(mu) event.selectedMuons.append(mu) else: event.otherLeptons.append(mu) looseMuons = event.selectedLeptons[:] for ele in inclusiveElectrons: ele.looseIdOnly = ele.cutBased >= 1 if (ele.looseIdOnly and ele.pt > 10 and abs(ele.eta) < 2.4 and ele.miniPFRelIso_all < 0.4 and ele.isPFcand and ele.convVeto and # and abs(ele.dxy)<0.05 and abs(ele.dz)<0.5 and ele.lostHits <=1.0 and (bestMatch(ele, looseMuons)[1] > (0.05**2))): event.selectedLeptons.append(ele) event.selectedElectrons.append(ele) else: event.otherLeptons.append(ele) event.otherLeptons.sort(key=lambda l: l.pt, reverse=True) event.selectedLeptons.sort(key=lambda l: l.pt, reverse=True) event.selectedMuons.sort(key=lambda l: l.pt, reverse=True) event.selectedElectrons.sort(key=lambda l: l.pt, reverse=True) event.inclusiveLeptons.sort(key=lambda l: l.pt, reverse=True) goodLep = [l for l in event.selectedLeptons] LepOther = [l for l in event.otherLeptons] #LepOther = goodLep leps = goodLep nlep = len(leps) ### LEPTONS # selected good leptons selectedTightLeps = [] selectedTightLepsIdx = [] selectedVetoLeps = [] # anti-selected leptons antiTightLeps = [] antiTightLepsIdx = [] antiVetoLeps = [] for idx, lep in enumerate(leps): # for acceptance check lepEta = abs(lep.eta) # Pt cut if lep.pt < 10: continue # Iso cut -- to be compatible with the trigger if lep.miniPFRelIso_all > trig_miniIsoCut: continue ################### # MUONS ################### if (abs(lep.pdgId) == 13): if lepEta > 2.4: continue passID = lep.mediumId passIso = lep.miniPFRelIso_all < muo_miniIsoCut passIP = lep.sip3d < goodMu_sip3d # selected muons if passID and passIso and passIP: selectedTightLeps.append(lep) selectedTightLepsIdx.append(idx) antiVetoLeps.append(lep) else: selectedVetoLeps.append(lep) # anti-selected muons if not passIso: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) ################### # ELECTRONS ################### elif (abs(lep.pdgId) == 11): if lepEta > eleEta: continue # pass variables passIso = False passConv = False if eleID == 'CB': # ELE CutBased ID eidCB = lep.cutBased passTightID = (eidCB == 4) # and lep.convVeto) passMediumID = (eidCB >= 3) # and lep.convVeto) #passLooseID = (eidCB >= 2) passVetoID = (eidCB >= 1) #and lep.convVeto) elif eleID == 'MVA': # ELE MVA ID # check MVA WPs passTightID = checkEleMVA(lep, 'Tight') passLooseID = checkEleMVA(lep, 'VLoose') # selected if passTightID: # all tight leptons are veto for anti antiVetoLeps.append(lep) # Iso check: if lep.miniPFRelIso_all < ele_miniIsoCut: passIso = True # conversion check if eleID == 'MVA': if lep.lostHits <= goodEl_lostHits and lep.convVeto and lep.sip3d < goodEl_sip3d: passConv = True elif eleID == 'CB': passConv = True # cuts already included in POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_X passPostICHEPHLTHOverE = True # comment out again if (lep.hOverE < 0.04 and abs(lep.eta)>1.479) or abs(lep.eta)<=1.479 else False # fill if passIso and passConv and passPostICHEPHLTHOverE: selectedTightLeps.append(lep) selectedTightLepsIdx.append(idx) else: selectedVetoLeps.append(lep) # anti-selected elif not passMediumID: #passVetoID: # all anti leptons are veto for selected selectedVetoLeps.append(lep) # Iso check passIso = lep.miniPFRelIso_all < Lep_miniIsoCut # should be true anyway # other checks passOther = False if hasattr(lep, "hoe"): passOther = lep.hoe > 0.01 # fill if passIso and passOther: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) # Veto leptons elif passVetoID: # the rest is veto for selected and anti selectedVetoLeps.append(lep) antiVetoLeps.append(lep) # end lepton loop ################### # EXTRA Loop for lepOther -- for anti-selected leptons ################### otherleps = [l for l in LepOther] #otherleps = [] for idx, lep in enumerate(otherleps): # check acceptance lepEta = abs(lep.eta) if lepEta > 2.4: continue # Pt cut if lep.pt < 10: continue # Iso cut -- to be compatible with the trigger if lep.miniPFRelIso_all > trig_miniIsoCut: continue ############ # Muons if (abs(lep.pdgId) == 13): ## Lower ID is POG_LOOSE (see cfg) # ID, IP and Iso check: #passID = lep.mediumMuonId == 1 passIso = lep.miniPFRelIso_all > muo_miniIsoCut # cuts like for the LepGood muons #passIP = abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1 #if passIso and passID and passIP: if passIso: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) ############ # Electrons elif (abs(lep.pdgId) == 11): if (lepEta > eleEta): continue ## Iso selection: ele should have MiniIso < 0.4 (for trigger) if lep.miniPFRelIso_all > Lep_miniIsoCut: continue ## Set Ele IDs if eleID == 'CB': # ELE CutBased ID eidCB = lep.cutBased passMediumID = (eidCB >= 3 and lep.convVeto) passVetoID = (eidCB >= 1 and lep.convVeto) else: passMediumID = False passVetoID = False # Cuts for Anti-selected electrons if not passMediumID: # should always be true for LepOther # other checks passOther = False if hasattr(lep, "hoe"): passOther = lep.hoe > 0.01 #if not lep.conVeto: if passOther: antiTightLeps.append(lep) antiTightLepsIdx.append(idx) else: antiVetoLeps.append(lep) elif passVetoID: #all Medium+ eles in LepOther antiVetoLeps.append(lep) # choose common lepton collection: select selected or anti lepton if len(selectedTightLeps) > 0: tightLeps = selectedTightLeps tightLepsIdx = selectedTightLepsIdx vetoLeps = selectedVetoLeps ############# ############# # retrive and fill branches ############# # choose common lepton collection: select selected or anti lepton if len(selectedTightLeps) > 0: tightLeps = selectedTightLeps tightLepsIdx = selectedTightLepsIdx vetoLeps = selectedVetoLeps elif len(antiTightLeps) > 0: tightLeps = antiTightLeps tightLepsIdx = antiTightLepsIdx vetoLeps = antiVetoLeps else: tightLeps = [] tightLepsIdx = [] vetoLeps = [] nTightLeps = len(tightLeps) '''# Met metp4 = ROOT.TLorentzVector(0,0,0,0) if hasattr(event, 'metMuEGClean_pt'): metp4.SetPtEtaPhiM(event.metMuEGClean_pt,event.metMuEGClean_eta,event.metMuEGClean_phi,event.metMuEGClean_mass) else: metp4.SetPtEtaPhiM(met.pt,0,met.phi,0) if hasattr(event, 'metMuEGClean_pt'): pmiss =array.array('d',[event.metMuEGClean_pt * math.cos(event.metMuEGClean_phi), event.metMuEGClean_pt * math.sin(event.metMuEGClean_phi)] ) else: pmiss =array.array('d',[met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)] )''' ##################################################################### ##################################################################### #################Jets, BJets, METS and filters ###################### ##################################################################### ##################################################################### ######## ### Jets ######## metp4 = ROOT.TLorentzVector(0, 0, 0, 0) Genmetp4 = ROOT.TLorentzVector(0, 0, 0, 0) if self.isMC: Genmetp4.SetPtEtaPhiM(genmet.pt, 0, genmet.phi, 0) Jets = Collection(event, "Jet") jets = [j for j in Jets if j.pt >= 20 and abs(j.eta) < 2.4] njet = len(jets) (met_px, met_py) = (met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)) (met_px_nom, met_py_nom) = (met_px, met_py) # match reconstructed jets to generator level ones # (needed to evaluate JER scale factors and uncertainties) if self.isMC: rho = getattr(event, "fixedGridRhoFastjetAll") genJets = Collection(event, "GenJet") pairs = matchObjectCollection(Jets, genJets) for jet in jets: genJet = pairs[jet] if smearJER == True: (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt( jet, genJet, rho) jet_pt_nom = jet_pt_jerNomVal * jet.pt if jet.pt > 15.: jet_cosPhi = math.cos(jet.phi) jet_sinPhi = math.sin(jet.phi) met_px_nom = met_px_nom - (jet_pt_nom - jet.pt) * jet_cosPhi met_py_nom = met_py_nom - (jet_pt_nom - jet.pt) * jet_sinPhi met_pt_nom = math.sqrt(met_px_nom**2 + met_py_nom**2) met_phi_nom = math.atan2(met_py_nom, met_px_nom) met.pt = met_pt_nom met.phi = met_phi_nom jet.pt = jet_pt_nom metp4.SetPtEtaPhiM( met.pt, 0., met.phi, 0.) # only use met vector to derive transverse quantities) centralJet30 = [] centralJet30idx = [] centralJet40 = [] cleanJets25 = [] cleanJets25idx = [] cleanJets = [] cleanJetsidx = [] # fill this flage but defults to 1 and then change it after the proper selection for i, j in enumerate(jets): if j.pt > 25: cleanJets25.append(j) cleanJets25idx.append(j) if j.pt > 30 and abs(j.eta) < centralEta: centralJet30.append(j) centralJet30idx.append(i) if j.pt > 40 and abs(j.eta) < centralEta: centralJet40.append(j) # jets 30 (cmg cleaning only) nCentralJet30 = len(centralJet30) btagWP = btag_MediumWP BJetMedium30 = [] BJetMedium30idx = [] BJetMedium40 = [] nBJetDeep = 0 cJet30Clean = [] dRminCut = 0.4 # Do cleaning a la CMG: clean max 1 jet for each lepton (the nearest) cJet30Clean = centralJet30 cleanJets30 = centralJet30 for i, j in enumerate(cJet30Clean): if j.btagCSVV2 > btagWP: BJetMedium30.append(j) BJetMedium30idx.append(j) if (j.btagDeepB) > btag_DeepMediumWP: nBJetDeep += 1 for i, j in enumerate(centralJet40): if j.btagCSVV2 > btagWP: BJetMedium40.append(j) nBJetMedium30 = len(BJetMedium30) ################################################################## # The following variables need to be double-checked for validity # ################################################################## ## B tagging WPs for CSVv2 (CSV-IVF) ## L: 0.423, M: 0.814, T: 0.941 ## from: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBTagging#Preliminary_working_or_operating bTagWP = 0.814 # MediumWP for CSVv2 #bTagWP = 0.732 # MediumWP for CMVA # min deltaPhi between a b-jet and MET; needs to be double-checked minDPhiBMET = 100 idxMinDPhiBMET = -999 for i, jet in enumerate(centralJet30): if jet.btagCSVV2 > bTagWP: dPhiBMET = abs(jet.p4().DeltaPhi(metp4)) if dPhiBMET < minDPhiBMET: minDPhiBMET = dPhiBMET idxMinDPhiBMET = i self.out.fillBranch("idxMinDPhiBMET", idxMinDPhiBMET) self.out.fillBranch("minDPhiBMET", minDPhiBMET) # min deltaPhi between a jet (first three jets) and MET; needs to be double-checked minDPhiJMET = 100 for i, jet in enumerate(centralJet30[:3]): dPhiJMET = abs(jet.p4().DeltaPhi(metp4)) if dPhiJMET < minDPhiJMET: minDPhiJMET = dPhiJMET self.out.fillBranch("minDPhiJMET", minDPhiJMET) # transverse mass of (closest (to MET) BJet, MET), (closest (to MET) BJet, lepton), # mass of (closest (to MET) BJet, lepton); need to be double-checked mTBJetMET = -999 mTLepMET = -999 mLepBJet = -999 if (idxMinDPhiBMET >= 0): SumMetClosestBJet = jets[idxMinDPhiBMET].p4() + metp4 self.out.fillBranch("mTClBPlusMET", SumMetClosestBJet.Mt()) mTBJetMET = mt_2(centralJet30[idxMinDPhiBMET].p4(), metp4) if nTightLeps >= 1: mLepBJet = (centralJet30[idxMinDPhiBMET].p4() + tightLeps[0].p4()).M() mTLepMET = mt_2(tightLeps[0].p4(), metp4) else: self.out.fillBranch("mTClBPlusMET", -999) self.out.fillBranch("mTBJetMET", mTBJetMET) self.out.fillBranch("mTLepMET", mTLepMET) self.out.fillBranch("mLepBJet", mLepBJet) # projection of MET along (MET + lepton + (closest (to MET) BJet)) sum; needs to be double-checked... MetZ1 = -9999 MetZ2 = -9999 MTW = -9999 MW1 = -9999 MW2 = -9999 neutrino1 = ROOT.TLorentzVector(0, 0, 0, 0) neutrino2 = ROOT.TLorentzVector(0, 0, 0, 0) if (nTightLeps == 1): NeutrZList = GetZfromM(tightLeps[0].p4(), metp4, 81) MTW = NeutrZList[0] MetZ1 = NeutrZList[1] MetZ2 = NeutrZList[2] neutrino1.SetXYZM(metp4.Px(), metp4.Py(), MetZ1, 0) neutrino2.SetXYZM(metp4.Px(), metp4.Py(), MetZ2, 0) MW1 = (neutrino1 + tightLeps[0].p4()).M() MW2 = (neutrino2 + tightLeps[0].p4()).M() self.out.fillBranch("MTW", MTW) self.out.fillBranch("MW1", MW1) self.out.fillBranch("MW2", MW2) # some extra plots MTbnu = [] LepBMass = [] MTtop = [] Mtop = [] METovTop = [] METTopPhi = [] MtopDecor = [] TopEt = [] TopPt = [] if (nTightLeps == 1): for i, jet in enumerate( centralJet30): #testing all jets as b-jet in top-reco if hasattr(event, 'metMuEGClean_pt'): ThisMTnub = math.sqrt( 2 * event.metMuEGClean_pt * jet.pt * (1 - math.cos(metp4.DeltaPhi(jet.p4())))) else: ThisMTnub = math.sqrt( 2 * met.pt * jet.pt * (1 - math.cos(metp4.DeltaPhi(jet.p4())))) MTbnu.append(ThisMTnub) # lep + jet vector lepJp4 = tightLeps[0].p4() + jet.p4() ThislepBMass = lepJp4.M() LepBMass.append(ThislepBMass) # top vector: MET + lep + jet topP4 = metp4 + lepJp4 TopEt.append(topP4.Et()) TopPt.append(topP4.Pt()) ThisMTtop = math.sqrt(81. * 81. + ThislepBMass * ThislepBMass + ThisMTnub * ThisMTnub) MTtop.append(ThisMTtop) if hasattr(event, 'metMuEGClean_pt'): ThisMetovTop = event.metMuEGClean_pt / topP4.Pt() else: ThisMetovTop = met.pt / topP4.Pt() METovTop.append(ThisMetovTop) ThisMetTop = metp4.DeltaPhi(metp4 + lepJp4) METTopPhi.append(ThisMetTop) TopMass1 = (neutrino1 + lepJp4).M() TopMass2 = (neutrino2 + lepJp4).M() #take smaller mtop of the two nu pz-solutions if TopMass1 > TopMass2: Mtop.append(TopMass2) else: Mtop.append(TopMass1) ThisMtopDecor1 = math.sqrt(lepJp4.M() * lepJp4.M() + (neutrino1 + jet.p4()).M() * (neutrino1 + jet.p4()).M() + 81 * 81) ThisMtopDecor2 = math.sqrt(lepJp4.M() * lepJp4.M() + (neutrino2 + jet.p4()).M() * (neutrino2 + jet.p4()).M() + 81 * 81) if ThisMtopDecor1 > ThisMtopDecor2: MtopDecor.append(ThisMtopDecor2) else: MtopDecor.append(ThisMtopDecor1) # fill them self.out.fillBranch("MTbnu", MTbnu) self.out.fillBranch("LepBMass", LepBMass) self.out.fillBranch("MTtop", MTtop) self.out.fillBranch("Mtop", Mtop) self.out.fillBranch("METovTop", METovTop) self.out.fillBranch("METTopPhi", METTopPhi) self.out.fillBranch("MtopDecor", MtopDecor) self.out.fillBranch("TopPt", TopPt) self.out.fillBranch("TopEt", TopEt) # nearest b jet to lead lepton minDphiLepB = 100 minDphiLepBidx = -1 if nTightLeps == 1: for i, jet in enumerate(centralJet30): if jet.btagCSVV2 > bTagWP: dPhiLepB = abs(jet.p4().DeltaPhi(tightLeps[0].p4())) if dPhiLepB < minDphiLepB: minDphiLepB = dPhiLepB minDphiLepBidx = i self.out.fillBranch("minDphiLepB", minDphiLepB) self.out.fillBranch("minDphiLepBidx", minDphiLepBidx) # TopVarsJetIdx = [] TopVarsMTbnuMin = [] TopVarsLepBMassMin = [] TopVarsMTtopMin = [] TopVarsMtopMin = [] TopVarsMETovTopMin = [] TopVarsMtopDecorMin = [] TopVarsTopPtMin = [] TopVarsTopEtMin = [] iBTagDict = { i: jets[idx].btagCSVV2 for i, idx in enumerate(centralJet30idx) } sortIdsByBTag = sorted(iBTagDict.items(), key=operator.itemgetter(1), reverse=True) bTaggedJetsSorted = sortIdsByBTag[:nBJetMedium30] # print bTaggedJetsSorted bTaggedJetsPPSorted = sortIdsByBTag[:nBJetMedium30 + 1] # print bTaggedJetsPPSorted ThreeBestBTags = sortIdsByBTag[:3] # print ThreeBestBTags # print sortIdsByBTag if nTightLeps == 1 and nCentralJet30 > 0: #0: minimum of b-tagged jets TopVarsMTbnuMin.append( minValueForIdxList(MTbnu, [ids[0] for ids in bTaggedJetsSorted])) TopVarsLepBMassMin.append( minValueForIdxList(LepBMass, [ids[0] for ids in bTaggedJetsSorted])) TopVarsMTtopMin.append( minValueForIdxList(MTtop, [ids[0] for ids in bTaggedJetsSorted])) TopVarsMtopMin.append( minValueForIdxList(Mtop, [ids[0] for ids in bTaggedJetsSorted])) TopVarsMETovTopMin.append( minValueForIdxList(METovTop, [ids[0] for ids in bTaggedJetsSorted])) TopVarsMtopDecorMin.append( minValueForIdxList(MtopDecor, [ids[0] for ids in bTaggedJetsSorted])) TopVarsTopPtMin.append( minValueForIdxList(TopPt, [ids[0] for ids in bTaggedJetsSorted])) TopVarsTopEtMin.append( minValueForIdxList(TopEt, [ids[0] for ids in bTaggedJetsSorted])) #1: minimum of b-tagged jets (+ adding next-best b-disc. jet) TopVarsMTbnuMin.append( minValueForIdxList(MTbnu, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsLepBMassMin.append( minValueForIdxList(LepBMass, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsMTtopMin.append( minValueForIdxList(MTtop, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsMtopMin.append( minValueForIdxList(Mtop, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsMETovTopMin.append( minValueForIdxList(METovTop, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsMtopDecorMin.append( minValueForIdxList(MtopDecor, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsTopPtMin.append( minValueForIdxList(TopPt, [ids[0] for ids in bTaggedJetsPPSorted])) TopVarsTopEtMin.append( minValueForIdxList(TopEt, [ids[0] for ids in bTaggedJetsPPSorted])) #2: always consider the three jets with the best b-tag values (no pass of any working-point required) TopVarsMTbnuMin.append( minValueForIdxList(MTbnu, [ids[0] for ids in ThreeBestBTags])) TopVarsLepBMassMin.append( minValueForIdxList(LepBMass, [ids[0] for ids in ThreeBestBTags])) TopVarsMTtopMin.append( minValueForIdxList(MTtop, [ids[0] for ids in ThreeBestBTags])) TopVarsMtopMin.append( minValueForIdxList(Mtop, [ids[0] for ids in ThreeBestBTags])) TopVarsMETovTopMin.append( minValueForIdxList(METovTop, [ids[0] for ids in ThreeBestBTags])) TopVarsMtopDecorMin.append( minValueForIdxList(MtopDecor, [ids[0] for ids in ThreeBestBTags])) TopVarsTopPtMin.append( minValueForIdxList(TopPt, [ids[0] for ids in ThreeBestBTags])) TopVarsTopEtMin.append( minValueForIdxList(TopEt, [ids[0] for ids in ThreeBestBTags])) if hasattr(tightLeps[0], 'genPartIdx'): mcMatchIdLep = tightLeps[0].genPartIdx iCorrectJet = -999 correctJetBTagged = False if abs(mcMatchIdLep) == 6: for i, jet in enumerate(centralJet30): if abs(jet.partonFlavour ) == 5 and jet.genJetIdx == mcMatchIdLep: iCorrectJet = i if jet.btagCSVV2 > bTagWP: correctJetBTagged = True #3: value for the correct b-jet (i.e. the one matching the lepton) TopVarsMTbnuMin.append( MTbnu[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsLepBMassMin.append( LepBMass[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsMTtopMin.append( MTtop[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsMtopMin.append( Mtop[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsMETovTopMin.append( METovTop[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsMtopDecorMin.append( MtopDecor[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsTopPtMin.append( TopPt[iCorrectJet] if iCorrectJet > -999 else -999) TopVarsTopEtMin.append( TopEt[iCorrectJet] if iCorrectJet > -999 else -999) foundCorrectBJetAndIsTagged = iCorrectJet > -999 and correctJetBTagged #4: value for the correct b-jet (if actually identified as b-jet (tagged)) TopVarsMTbnuMin.append(MTbnu[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsLepBMassMin.append( LepBMass[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsMTtopMin.append(MTtop[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsMtopMin.append( Mtop[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsMETovTopMin.append( METovTop[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsMtopDecorMin.append( MtopDecor[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsTopPtMin.append(TopPt[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) TopVarsTopEtMin.append(TopEt[iCorrectJet] if foundCorrectBJetAndIsTagged else -999) #5: consider the jet closest in dphi to MET TopVarsMTbnuMin.append( MTbnu[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsLepBMassMin.append(LepBMass[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsMTtopMin.append( MTtop[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsMtopMin.append( Mtop[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsMETovTopMin.append(METovTop[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsMtopDecorMin.append(MtopDecor[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsTopPtMin.append( TopPt[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) TopVarsTopEtMin.append( TopEt[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999) #6: nearest to lepton b jet TopVarsMTbnuMin.append( MTbnu[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsLepBMassMin.append( LepBMass[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsMTtopMin.append( MTtop[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsMtopMin.append( Mtop[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsMETovTopMin.append( METovTop[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsMtopDecorMin.append( MtopDecor[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsTopPtMin.append( TopPt[minDphiLepBidx] if minDphiLepBidx > -1 else -999) TopVarsTopEtMin.append( TopEt[minDphiLepBidx] if minDphiLepBidx > -1 else -999) else: for i in range(7): TopVarsMTbnuMin.append(-999) TopVarsLepBMassMin.append(-999) TopVarsMTtopMin.append(-999) TopVarsMtopMin.append(-999) TopVarsMETovTopMin.append(-999) TopVarsMtopDecorMin.append(-999) TopVarsTopPtMin.append(-999) TopVarsTopEtMin.append(-999) self.out.fillBranch("nBMinVariantsTopVars", 7) self.out.fillBranch("TopVarsMTbnuMin", TopVarsMTbnuMin) self.out.fillBranch("TopVarsLepBMassMin", TopVarsLepBMassMin) self.out.fillBranch("TopVarsMTtopMin", TopVarsMTtopMin) self.out.fillBranch("TopVarsMtopMin", TopVarsMtopMin) self.out.fillBranch("TopVarsMETovTopMin", TopVarsMETovTopMin) self.out.fillBranch("TopVarsMtopDecorMin", TopVarsMtopDecorMin) self.out.fillBranch("TopVarsTopPtMin", TopVarsTopPtMin) self.out.fillBranch("TopVarsTopEtMin", TopVarsTopEtMin) return True