def __init__(self, cfg_ana, cfg_comp, looperName): super(LeptonAnalyzer, self).__init__(cfg_ana, cfg_comp, looperName) if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none": if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync) if hasattr(self.cfg_ana, "doRochesterCorrections" ) and self.cfg_ana.doRochesterCorrections: raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!" else: self.cfg_ana.doMuScleFitCorrections = False #FIXME: only Embedded works self.electronEnergyCalibrator = EmbeddedElectronCalibrator() # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele: ( ele.relIso03 <= self.cfg_ana. loose_electron_relIso and ele.absIso03 < getattr( self.cfg_ana, 'loose_electron_absIso', 9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu: ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana, 'loose_muon_absIso', 9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Phys14_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Phys14_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [None, 'any', 'inclusive']: raise RuntimeError, "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)" if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer() self.doIsolationScan = getattr(cfg_ana, 'doIsolationScan', False) if self.doIsolationScan: if self.doMiniIsolation: assert (self.miniIsolationPUCorr != "weights") assert (self.miniIsolationVetoLeptons == None) else: self.IsolationComputer = heppy.IsolationComputer()
def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none": if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync) if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections: raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!" else: self.cfg_ana.doMuScleFitCorrections = False #FIXME: only Embedded works self.electronEnergyCalibrator = EmbeddedElectronCalibrator()
def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none": if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync) if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections: raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!" else: self.cfg_ana.doMuScleFitCorrections = False #FIXME: only Embedded works self.electronEnergyCalibrator = EmbeddedElectronCalibrator() # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele : ( ele.relIso03 <= self.cfg_ana.loose_electron_relIso and ele.absIso03 < getattr(self.cfg_ana,'loose_electron_absIso',9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu : ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana,'loose_muon_absIso',9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Phys14_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Phys14_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [ None, 'any', 'inclusive' ]: raise RuntimeError, "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)" if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer()
def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none": if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync) if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections: raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!" else: self.cfg_ana.doMuScleFitCorrections = False #FIXME: only Embedded works self.electronEnergyCalibrator = EmbeddedElectronCalibrator() # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Phys14_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Phys14_25ns_v1")
class LeptonAnalyzer( Analyzer ): def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none": if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync) if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections: raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!" else: self.cfg_ana.doMuScleFitCorrections = False #FIXME: only Embedded works self.electronEnergyCalibrator = EmbeddedElectronCalibrator() # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele : ( ele.relIso03 <= self.cfg_ana.loose_electron_relIso and ele.absIso03 < getattr(self.cfg_ana,'loose_electron_absIso',9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu : ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana,'loose_muon_absIso',9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Phys14_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Phys14_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [ None, 'any', 'inclusive' ]: raise RuntimeError, "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)" if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer() #---------------------------------------- # DECLARATION OF HANDLES OF LEPTONS STUFF #---------------------------------------- def declareHandles(self): super(LeptonAnalyzer, self).declareHandles() #leptons self.handles['muons'] = AutoHandle(self.cfg_ana.muons,"std::vector<pat::Muon>") self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons,"std::vector<pat::Electron>") #rho for muons self.handles['rhoMu'] = AutoHandle( self.cfg_ana.rhoMuon, 'double') #rho for electrons self.handles['rhoEle'] = AutoHandle( self.cfg_ana.rhoElectron, 'double') if self.doMiniIsolation: self.handles['packedCandidates'] = AutoHandle( self.cfg_ana.packedCandidates, 'std::vector<pat::PackedCandidate>') def beginLoop(self, setup): super(LeptonAnalyzer,self).beginLoop(setup) self.counters.addCounter('events') count = self.counters.counter('events') count.register('all events') #------------------ # MAKE LEPTON LISTS #------------------ def makeLeptons(self, event): ### 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 = [] if self.doMiniIsolation: self.IsolationComputer.setPackedCandidates(self.handles['packedCandidates'].product()) if self.miniIsolationVetoLeptons == "any": for lep in self.handles['muons'].product(): self.IsolationComputer.addVeto(lep) for lep in self.handles['electrons'].product(): self.IsolationComputer.addVeto(lep) #muons allmuons = self.makeAllMuons(event) #electrons allelectrons = self.makeAllElectrons(event) #make inclusive leptons inclusiveMuons = [] inclusiveElectrons = [] for mu in allmuons: if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and mu.pt()>self.cfg_ana.inclusive_muon_pt and abs(mu.eta())<self.cfg_ana.inclusive_muon_eta and abs(mu.dxy())<self.cfg_ana.inclusive_muon_dxy and abs(mu.dz())<self.cfg_ana.inclusive_muon_dz): inclusiveMuons.append(mu) for ele in allelectrons: if ( ele.electronID(self.cfg_ana.inclusive_electron_id) and ele.pt()>self.cfg_ana.inclusive_electron_pt and abs(ele.eta())<self.cfg_ana.inclusive_electron_eta and abs(ele.dxy())<self.cfg_ana.inclusive_electron_dxy and abs(ele.dz())<self.cfg_ana.inclusive_electron_dz and ele.lostInner()<=self.cfg_ana.inclusive_electron_lostHits ): inclusiveElectrons.append(ele) event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons if self.doMiniIsolation: if self.miniIsolationVetoLeptons == "inclusive": for lep in event.inclusiveLeptons: self.IsolationComputer.addVeto(lep) for lep in event.inclusiveLeptons: self.attachMiniIsolation(lep) # make loose leptons (basic selection) for mu in inclusiveMuons: if (mu.muonID(self.cfg_ana.loose_muon_id) and mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and self.muIsoCut(mu)): mu.looseIdSusy = True event.selectedLeptons.append(mu) event.selectedMuons.append(mu) else: mu.looseIdSusy = False event.otherLeptons.append(mu) looseMuons = event.selectedLeptons[:] for ele in inclusiveElectrons: if (ele.electronID(self.cfg_ana.loose_electron_id) and ele.pt()>self.cfg_ana.loose_electron_pt and abs(ele.eta())<self.cfg_ana.loose_electron_eta and abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz())<self.cfg_ana.loose_electron_dz and self.eleIsoCut(ele) and ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and ( True if getattr(self.cfg_ana,'notCleaningElectrons',False) else (bestMatch(ele, looseMuons)[1] > (self.cfg_ana.min_dr_electron_muon**2)) )): event.selectedLeptons.append(ele) event.selectedElectrons.append(ele) ele.looseIdSusy = True else: event.otherLeptons.append(ele) ele.looseIdSusy = False 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) for lepton in event.selectedLeptons: if hasattr(self,'efficiency'): self.efficiency.attachToObject(lepton) def makeAllMuons(self, event): """ make a list of all muons, and apply basic corrections to them """ # Start from all muons allmuons = map( Muon, self.handles['muons'].product() ) # Muon scale and resolution corrections (if enabled) if self.cfg_ana.doMuScleFitCorrections: for mu in allmuons: self.muscleCorr.correct(mu, event.run) elif self.cfg_ana.doRochesterCorrections: for mu in allmuons: corp4 = rochcor.corrected_p4(mu, event.run) mu.setP4( corp4 ) # Clean up dulicate muons (note: has no effect unless the muon id is removed) if self.cfg_ana.doSegmentBasedMuonCleaning: isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product() ) newmu = [] for i,mu in enumerate(allmuons): if isgood[i]: newmu.append(mu) allmuons = newmu # Attach EAs for isolation: for mu in allmuons: mu.rho = float(self.handles['rhoMu'].product()[0]) if self.muEffectiveArea == "Data2012": if aeta < 1.0 : mu.EffectiveArea03 = 0.382; elif aeta < 1.47 : mu.EffectiveArea03 = 0.317; elif aeta < 2.0 : mu.EffectiveArea03 = 0.242; elif aeta < 2.2 : mu.EffectiveArea03 = 0.326; elif aeta < 2.3 : mu.EffectiveArea03 = 0.462; else : mu.EffectiveArea03 = 0.372; if aeta < 1.0 : mu.EffectiveArea04 = 0.674; elif aeta < 1.47 : mu.EffectiveArea04 = 0.565; elif aeta < 2.0 : mu.EffectiveArea04 = 0.442; elif aeta < 2.2 : mu.EffectiveArea04 = 0.515; elif aeta < 2.3 : mu.EffectiveArea04 = 0.821; else : mu.EffectiveArea04 = 0.660; elif self.muEffectiveArea == "Phys14_25ns_v1": aeta = abs(mu.eta()) if aeta < 0.800: mu.EffectiveArea03 = 0.0913 elif aeta < 1.300: mu.EffectiveArea03 = 0.0765 elif aeta < 2.000: mu.EffectiveArea03 = 0.0546 elif aeta < 2.200: mu.EffectiveArea03 = 0.0728 else: mu.EffectiveArea03 = 0.1177 if aeta < 0.800: mu.EffectiveArea04 = 0.1564 elif aeta < 1.300: mu.EffectiveArea04 = 0.1325 elif aeta < 2.000: mu.EffectiveArea04 = 0.0913 elif aeta < 2.200: mu.EffectiveArea04 = 0.1212 else: mu.EffectiveArea04 = 0.2085 else: raise RuntimeError, "Unsupported value for mu_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_v1 (rho: fixedGridRhoFastjetAll)" # Attach the vertex to them, for dxy/dz calculation for mu in allmuons: mu.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0] mu.setTrackForDxyDz(self.cfg_ana.muon_dxydz_track) # Set tight id if specified if hasattr(self.cfg_ana, "mu_tightId"): for mu in allmuons: mu.tightIdResult = mu.muonID(self.cfg_ana.mu_tightId) # Compute relIso in 0.3 and 0.4 cones for mu in allmuons: if self.cfg_ana.mu_isoCorr=="rhoArea" : mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.rho * mu.EffectiveArea03,0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.rho * mu.EffectiveArea04,0.0)) elif self.cfg_ana.mu_isoCorr=="deltaBeta" : mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt/2,0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt/2,0.0)) else : raise RuntimeError, "Unsupported mu_isoCorr name '" + str(self.cfg_ana.mu_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported." mu.relIso03 = mu.absIso03/mu.pt() mu.relIso04 = mu.absIso04/mu.pt() return allmuons def makeAllElectrons(self, event): """ make a list of all electrons, and apply basic corrections to them """ allelectrons = map( Electron, self.handles['electrons'].product() ) ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases) allelenodup = [] for e in allelectrons: dup = False for e2 in allelenodup: if abs(e.pt()-e2.pt()) < 1e-6 and abs(e.eta()-e2.eta()) < 1e-6 and abs(e.phi()-e2.phi()) < 1e-6 and e.charge() == e2.charge(): dup = True break if not dup: allelenodup.append(e) allelectrons = allelenodup # fill EA for rho-corrected isolation for ele in allelectrons: ele.rho = float(self.handles['rhoEle'].product()[0]) if self.eleEffectiveArea == "Data2012": # https://twiki.cern.ch/twiki/bin/viewauth/CMS/EgammaEARhoCorrection?rev=14 SCEta = abs(ele.superCluster().eta()) if SCEta < 1.0 : ele.EffectiveArea03 = 0.13 # 0.130; elif SCEta < 1.479: ele.EffectiveArea03 = 0.14 # 0.137; elif SCEta < 2.0 : ele.EffectiveArea03 = 0.07 # 0.067; elif SCEta < 2.2 : ele.EffectiveArea03 = 0.09 # 0.089; elif SCEta < 2.3 : ele.EffectiveArea03 = 0.11 # 0.107; elif SCEta < 2.4 : ele.EffectiveArea03 = 0.11 # 0.110; else : ele.EffectiveArea03 = 0.14 # 0.138; if SCEta < 1.0 : ele.EffectiveArea04 = 0.208; elif SCEta < 1.479: ele.EffectiveArea04 = 0.209; elif SCEta < 2.0 : ele.EffectiveArea04 = 0.115; elif SCEta < 2.2 : ele.EffectiveArea04 = 0.143; elif SCEta < 2.3 : ele.EffectiveArea04 = 0.183; elif SCEta < 2.4 : ele.EffectiveArea04 = 0.194; else : ele.EffectiveArea04 = 0.261; elif self.eleEffectiveArea == "Phys14_25ns_v1": aeta = abs(ele.eta()) if aeta < 0.800: ele.EffectiveArea03 = 0.1013 elif aeta < 1.300: ele.EffectiveArea03 = 0.0988 elif aeta < 2.000: ele.EffectiveArea03 = 0.0572 elif aeta < 2.200: ele.EffectiveArea03 = 0.0842 else: ele.EffectiveArea03 = 0.1530 if aeta < 0.800: ele.EffectiveArea04 = 0.1830 elif aeta < 1.300: ele.EffectiveArea04 = 0.1734 elif aeta < 2.000: ele.EffectiveArea04 = 0.1077 elif aeta < 2.200: ele.EffectiveArea04 = 0.1565 else: ele.EffectiveArea04 = 0.2680 else: raise RuntimeError, "Unsupported value for ele_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_v1 (rho: fixedGridRhoFastjetAll)" # Electron scale calibrations if self.cfg_ana.doElectronScaleCorrections: for ele in allelectrons: self.electronEnergyCalibrator.correct(ele, event.run) # Attach the vertex for ele in allelectrons: ele.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0] # Compute relIso with R=0.3 and R=0.4 cones for ele in allelectrons: if self.cfg_ana.ele_isoCorr=="rhoArea" : ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max(ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3)-ele.rho*ele.EffectiveArea03,0)) ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max(ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4)-ele.rho*ele.EffectiveArea04,0)) elif self.cfg_ana.ele_isoCorr=="deltaBeta" : ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max( ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3) - ele.puChargedHadronIsoR(0.3)/2, 0.0)) ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max( ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4) - ele.puChargedHadronIsoR(0.4)/2, 0.0)) else : raise RuntimeError, "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported." ele.relIso03 = ele.absIso03/ele.pt() ele.relIso04 = ele.absIso04/ele.pt() # Set tight MVA id for ele in allelectrons: if self.cfg_ana.ele_tightId=="MVA" : ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5") elif self.cfg_ana.ele_tightId=="Cuts_2012" : ele.tightIdResult = -1 + 1*ele.electronID("POG_Cuts_ID_2012_Veto_full5x5") + 1*ele.electronID("POG_Cuts_ID_2012_Loose_full5x5") + 1*ele.electronID("POG_Cuts_ID_2012_Medium_full5x5") + 1*ele.electronID("POG_Cuts_ID_2012_Tight_full5x5") else : try: ele.tightIdResult = ele.electronID(self.cfg_ana.ele_tightId) except RuntimeError: raise RuntimeError, "Unsupported ele_tightId name '" + str(self.cfg_ana.ele_tightId) + "'! For now only 'MVA' and 'Cuts_2012' are supported, in addition to what provided in Electron.py." return allelectrons def attachMiniIsolation(self, mu): mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) # -- version with increasing cone at low pT, gives slightly better performance for tight cuts and low pt leptons # mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) if mu.pt() > 20 else 4.0/min(max(mu.pt(),10),20) what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE") mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0); if self.miniIsolationPUCorr == "weights": if what == "mu": mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.01, 0.5); else: mu.miniAbsIsoNeutral = ( self.IsolationComputer.photonAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) ) else: if what == "mu": mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.01, 0.5); else: mu.miniAbsIsoPho = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNHad = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNeutral = mu.miniAbsIsoPho + mu.miniAbsIsoNHad # -- version relying on PF candidate vetos; apparently less performant, and the isolation computed at RECO level doesn't have them #mu.miniAbsIsoPhoSV = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.0, 0.0) #mu.miniAbsIsoNHadSV = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0) #mu.miniAbsIsoNeutral = mu.miniAbsIsoPhoSV + mu.miniAbsIsoNHadSV if self.miniIsolationPUCorr == "rhoArea": mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - mu.rho * mu.EffectiveArea03 * (mu.miniIsoR/0.3)**2) elif self.miniIsolationPUCorr == "deltaBeta": if what == "mu": mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.01, 0.5); else: mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.015 if what == "eleE" else 0.0, 0.0); mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - 0.5*mu.miniAbsIsoPU) elif self.miniIsolationPUCorr != 'raw': raise RuntimeError, "Unsupported miniIsolationCorr name '" + str(self.cfg_ana.miniIsolationCorr) + "'! For now only 'rhoArea', 'deltaBeta', 'raw', 'weights' are supported (and 'weights' is not tested)." mu.miniAbsIso = mu.miniAbsIsoCharged + mu.miniAbsIsoNeutral mu.miniRelIso = mu.miniAbsIso/mu.pt() def matchLeptons(self, event): def plausible(rec,gen): if abs(rec.pdgId()) == 11 and abs(gen.pdgId()) != 11: return False if abs(rec.pdgId()) == 13 and abs(gen.pdgId()) != 13: return False dr = deltaR(rec.eta(),rec.phi(),gen.eta(),gen.phi()) if dr < 0.3: return True if rec.pt() < 10 and abs(rec.pdgId()) == 13 and gen.pdgId() != rec.pdgId(): return False if dr < 0.7: return True if min(rec.pt(),gen.pt())/max(rec.pt(),gen.pt()) < 0.3: return False return True leps = event.inclusiveLeptons if self.cfg_ana.match_inclusiveLeptons else event.selectedLeptons match = matchObjectCollection3(leps, event.genleps + event.gentauleps, deltaRMax = 1.2, filter = plausible) for lep in leps: gen = match[lep] lep.mcMatchId = (gen.sourceId if gen != None else 0) lep.mcMatchTau = (gen in event.gentauleps if gen else -99) lep.mcLep=gen def isFromB(self,particle,bid=5, done={}): for i in xrange( particle.numberOfMothers() ): mom = particle.mother(i) momid = abs(mom.pdgId()) if momid / 1000 == bid or momid / 100 == bid or momid == bid: return True elif mom.status() == 2 and self.isFromB(mom, done=done): return True return False def matchAnyLeptons(self, event): event.anyLeptons = [ x for x in event.genParticles if x.status() == 1 and abs(x.pdgId()) in [11,13] ] leps = event.inclusiveLeptons if hasattr(event, 'inclusiveLeptons') else event.selectedLeptons match = matchObjectCollection3(leps, event.anyLeptons, deltaRMax = 0.3, filter = lambda x,y : abs(x.pdgId()) == abs(y.pdgId())) for lep in leps: gen = match[lep] lep.mcMatchAny_gp = gen if gen: if self.isFromB(gen): lep.mcMatchAny = 5 # B (inclusive of B->D) elif self.isFromB(gen,bid=4): lep.mcMatchAny = 4 # Charm else: lep.mcMatchAny = 1 else: lep.mcMatchAny = 0 # fix case where the matching with the only prompt leptons failed, but we still ended up with a prompt match if gen != None and hasattr(lep,'mcMatchId') and lep.mcMatchId == 0: if isPromptLepton(gen, False): lep.mcMatchId = 100 elif not hasattr(lep,'mcMatchId'): lep.mcMatchId = 0 if not hasattr(lep,'mcMatchTau'): lep.mcMatchTau = 0 def process(self, event): self.readCollections( event.input ) self.counters.counter('events').inc('all events') #call the leptons functions self.makeLeptons(event) if self.cfg_comp.isMC and self.cfg_ana.do_mc_match: self.matchLeptons(event) self.matchAnyLeptons(event) return True
def __init__(self, cfg_ana, cfg_comp, looperName): super(LeptonAnalyzer, self).__init__(cfg_ana, cfg_comp, looperName) if hasattr(self.cfg_ana, 'doMuScleFitCorrections'): raise RuntimeError( "doMuScleFitCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'MuScleFit', <name> )" ) if hasattr(self.cfg_ana, 'doRochesterCorrections'): raise RuntimeError( "doRochesterCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'Rochester', <name> )" ) if self.cfg_ana.doMuonScaleCorrections: algo, options = self.cfg_ana.doMuonScaleCorrections if algo == "Kalman": corr = options['MC' if self.cfg_comp.isMC else 'Data'] self.muonScaleCorrector = KalmanMuonCorrector( corr, self.cfg_comp.isMC, options['isSync'] if 'isSync' in options else False, options['smearMode'] if 'smearMode' in options else "ebe") elif algo == "Rochester": print( "WARNING: the Rochester correction in heppy is still from Run 1" ) self.muonScaleCorrector = RochesterCorrections() elif algo == "MuScleFit": print( "WARNING: the MuScleFit correction in heppy is still from Run 1 (and probably no longer functional)" ) if options not in [ "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError( 'MuScleFit correction name must be one of [ "prompt", "prompt-sync", "rereco", "rereco-sync" ] ' ) rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muonScaleCorrector = MuScleFitCorr( cfg_comp.isMC, rereco, sync) else: raise RuntimeError("Unknown muon scale correction algorithm") else: self.muonScaleCorrector = None #FIXME: only Embedded works if self.cfg_ana.doElectronScaleCorrections: conf = cfg_ana.doElectronScaleCorrections self.electronEnergyCalibrator = Run2ElectronCalibrator( conf['data'], conf['GBRForest'], cfg_comp.isMC, conf['isSync'] if 'isSync' in conf else False, ) # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele: ( ele.relIso03 <= self.cfg_ana. loose_electron_relIso and ele.absIso03 < getattr( self.cfg_ana, 'loose_electron_absIso', 9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu: ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana, 'loose_muon_absIso', 9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Spring15_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Spring15_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [None, 'any', 'inclusive']: raise RuntimeError( "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)" ) if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer() self.doIsoAnnulus = getattr(cfg_ana, 'doIsoAnnulus', False) if self.doIsoAnnulus: if not self.doMiniIsolation: self.IsolationComputer = heppy.IsolationComputer() self.doIsolationScan = getattr(cfg_ana, 'doIsolationScan', False) if self.doIsolationScan: if self.doMiniIsolation: assert (self.miniIsolationPUCorr != "weights") assert (self.miniIsolationVetoLeptons == None) else: self.IsolationComputer = heppy.IsolationComputer() self.doMatchToPhotons = getattr(cfg_ana, 'do_mc_match_photons', False)
class LeptonAnalyzer(Analyzer): def __init__(self, cfg_ana, cfg_comp, looperName): super(LeptonAnalyzer, self).__init__(cfg_ana, cfg_comp, looperName) if hasattr(self.cfg_ana, 'doMuScleFitCorrections'): raise RuntimeError( "doMuScleFitCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'MuScleFit', <name> )" ) if hasattr(self.cfg_ana, 'doRochesterCorrections'): raise RuntimeError( "doRochesterCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'Rochester', <name> )" ) if self.cfg_ana.doMuonScaleCorrections: algo, options = self.cfg_ana.doMuonScaleCorrections if algo == "Kalman": corr = options['MC' if self.cfg_comp.isMC else 'Data'] self.muonScaleCorrector = KalmanMuonCorrector( corr, self.cfg_comp.isMC, options['isSync'] if 'isSync' in options else False, options['smearMode'] if 'smearMode' in options else "ebe") elif algo == "Rochester": print( "WARNING: the Rochester correction in heppy is still from Run 1" ) self.muonScaleCorrector = RochesterCorrections() elif algo == "MuScleFit": print( "WARNING: the MuScleFit correction in heppy is still from Run 1 (and probably no longer functional)" ) if options not in [ "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError( 'MuScleFit correction name must be one of [ "prompt", "prompt-sync", "rereco", "rereco-sync" ] ' ) rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muonScaleCorrector = MuScleFitCorr( cfg_comp.isMC, rereco, sync) else: raise RuntimeError("Unknown muon scale correction algorithm") else: self.muonScaleCorrector = None #FIXME: only Embedded works if self.cfg_ana.doElectronScaleCorrections: conf = cfg_ana.doElectronScaleCorrections self.electronEnergyCalibrator = Run2ElectronCalibrator( conf['data'], conf['GBRForest'], cfg_comp.isMC, conf['isSync'] if 'isSync' in conf else False, ) # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele: ( ele.relIso03 <= self.cfg_ana. loose_electron_relIso and ele.absIso03 < getattr( self.cfg_ana, 'loose_electron_absIso', 9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu: ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana, 'loose_muon_absIso', 9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Spring15_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Spring15_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [None, 'any', 'inclusive']: raise RuntimeError( "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)" ) if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer() self.doIsoAnnulus = getattr(cfg_ana, 'doIsoAnnulus', False) if self.doIsoAnnulus: if not self.doMiniIsolation: self.IsolationComputer = heppy.IsolationComputer() self.doIsolationScan = getattr(cfg_ana, 'doIsolationScan', False) if self.doIsolationScan: if self.doMiniIsolation: assert (self.miniIsolationPUCorr != "weights") assert (self.miniIsolationVetoLeptons == None) else: self.IsolationComputer = heppy.IsolationComputer() self.doMatchToPhotons = getattr(cfg_ana, 'do_mc_match_photons', False) #---------------------------------------- # DECLARATION OF HANDLES OF LEPTONS STUFF #---------------------------------------- def declareHandles(self): super(LeptonAnalyzer, self).declareHandles() #leptons self.handles['muons'] = AutoHandle(self.cfg_ana.muons, "std::vector<pat::Muon>") self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons, "std::vector<pat::Electron>") #rho for muons self.handles['rhoMu'] = AutoHandle(self.cfg_ana.rhoMuon, 'double') #rho for electrons self.handles['rhoEle'] = AutoHandle(self.cfg_ana.rhoElectron, 'double') if self.doMiniIsolation or self.doIsolationScan: self.handles['packedCandidates'] = AutoHandle( self.cfg_ana.packedCandidates, 'std::vector<pat::PackedCandidate>') if self.doMatchToPhotons: if self.doMatchToPhotons == "any": self.mchandles['genPhotons'] = AutoHandle( 'packedGenParticles', 'std::vector<pat::PackedGenParticle>') else: self.mchandles['genPhotons'] = AutoHandle( 'prunedGenParticles', 'std::vector<reco::GenParticle>') def beginLoop(self, setup): super(LeptonAnalyzer, self).beginLoop(setup) self.counters.addCounter('events') count = self.counters.counter('events') count.register('all events') #------------------ # MAKE LEPTON LISTS #------------------ def makeLeptons(self, event): ### 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 = [] if self.doMiniIsolation or self.doIsolationScan: self.IsolationComputer.setPackedCandidates( self.handles['packedCandidates'].product()) if self.doMiniIsolation: if self.miniIsolationVetoLeptons == "any": for lep in self.handles['muons'].product(): self.IsolationComputer.addVetos(lep) for lep in self.handles['electrons'].product(): self.IsolationComputer.addVetos(lep) #muons allmuons = self.makeAllMuons(event) #electrons allelectrons = self.makeAllElectrons(event) #make inclusive leptons inclusiveMuons = [] inclusiveElectrons = [] for mu in allmuons: if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and mu.pt() > self.cfg_ana.inclusive_muon_pt and abs(mu.eta()) < self.cfg_ana.inclusive_muon_eta and abs(mu.dxy()) < self.cfg_ana.inclusive_muon_dxy and abs(mu.dz()) < self.cfg_ana.inclusive_muon_dz): inclusiveMuons.append(mu) for ele in allelectrons: if (ele.electronID(self.cfg_ana.inclusive_electron_id) and ele.pt() > self.cfg_ana.inclusive_electron_pt and abs(ele.eta()) < self.cfg_ana.inclusive_electron_eta and abs(ele.dxy()) < self.cfg_ana.inclusive_electron_dxy and abs(ele.dz()) < self.cfg_ana.inclusive_electron_dz and ele.lostInner() <= self.cfg_ana.inclusive_electron_lostHits): inclusiveElectrons.append(ele) event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons if self.doMiniIsolation: if self.miniIsolationVetoLeptons == "inclusive": for lep in event.inclusiveLeptons: self.IsolationComputer.addVetos(lep.physObj) for lep in event.inclusiveLeptons: self.attachMiniIsolation(lep) if self.doIsoAnnulus: for lep in event.inclusiveLeptons: self.attachIsoAnnulus04(lep) if self.doIsolationScan: for lep in event.inclusiveLeptons: self.attachIsolationScan(lep) # make loose leptons (basic selection) for mu in inclusiveMuons: if (mu.muonID(self.cfg_ana.loose_muon_id) and mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and self.muIsoCut(mu)): mu.looseIdSusy = True event.selectedLeptons.append(mu) event.selectedMuons.append(mu) else: mu.looseIdSusy = False event.otherLeptons.append(mu) looseMuons = event.selectedLeptons[:] for ele in inclusiveElectrons: if (ele.electronID(self.cfg_ana.loose_electron_id) and ele.pt() > self.cfg_ana.loose_electron_pt and abs(ele.eta()) < self.cfg_ana.loose_electron_eta and abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz()) < self.cfg_ana.loose_electron_dz and self.eleIsoCut(ele) and ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and (True if getattr(self.cfg_ana, 'notCleaningElectrons', False) else (bestMatch(ele, looseMuons)[1] > (self.cfg_ana.min_dr_electron_muon**2)))): event.selectedLeptons.append(ele) event.selectedElectrons.append(ele) ele.looseIdSusy = True else: event.otherLeptons.append(ele) ele.looseIdSusy = False 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) for lepton in event.selectedLeptons: if hasattr(self, 'efficiency'): self.efficiency.attachToObject(lepton) def makeAllMuons(self, event): """ make a list of all muons, and apply basic corrections to them """ # Start from all muons allmuons = map(Muon, self.handles['muons'].product()) # Muon scale and resolution corrections (if enabled) if self.muonScaleCorrector: self.muonScaleCorrector.correct_all(allmuons, event.run) # Clean up dulicate muons (note: has no effect unless the muon id is removed) if self.cfg_ana.doSegmentBasedMuonCleaning: isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product()) newmu = [] for i, mu in enumerate(allmuons): if isgood[i]: newmu.append(mu) allmuons = newmu # Attach EAs for isolation: for mu in allmuons: mu.rho = float(self.handles['rhoMu'].product()[0]) if self.muEffectiveArea == "Data2012": if aeta < 1.0: mu.EffectiveArea03 = 0.382 elif aeta < 1.47: mu.EffectiveArea03 = 0.317 elif aeta < 2.0: mu.EffectiveArea03 = 0.242 elif aeta < 2.2: mu.EffectiveArea03 = 0.326 elif aeta < 2.3: mu.EffectiveArea03 = 0.462 else: mu.EffectiveArea03 = 0.372 if aeta < 1.0: mu.EffectiveArea04 = 0.674 elif aeta < 1.47: mu.EffectiveArea04 = 0.565 elif aeta < 2.0: mu.EffectiveArea04 = 0.442 elif aeta < 2.2: mu.EffectiveArea04 = 0.515 elif aeta < 2.3: mu.EffectiveArea04 = 0.821 else: mu.EffectiveArea04 = 0.660 elif self.muEffectiveArea == "Phys14_25ns_v1": aeta = abs(mu.eta()) if aeta < 0.800: mu.EffectiveArea03 = 0.0913 elif aeta < 1.300: mu.EffectiveArea03 = 0.0765 elif aeta < 2.000: mu.EffectiveArea03 = 0.0546 elif aeta < 2.200: mu.EffectiveArea03 = 0.0728 else: mu.EffectiveArea03 = 0.1177 if aeta < 0.800: mu.EffectiveArea04 = 0.1564 elif aeta < 1.300: mu.EffectiveArea04 = 0.1325 elif aeta < 2.000: mu.EffectiveArea04 = 0.0913 elif aeta < 2.200: mu.EffectiveArea04 = 0.1212 else: mu.EffectiveArea04 = 0.2085 elif self.muEffectiveArea == "Spring15_25ns_v1": aeta = abs(mu.eta()) if aeta < 0.800: mu.EffectiveArea03 = 0.0735 elif aeta < 1.300: mu.EffectiveArea03 = 0.0619 elif aeta < 2.000: mu.EffectiveArea03 = 0.0465 elif aeta < 2.200: mu.EffectiveArea03 = 0.0433 else: mu.EffectiveArea03 = 0.0577 mu.EffectiveArea04 = 0 # not computed else: raise RuntimeError( "Unsupported value for mu_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_25ns_v1 or Spring15_25ns_v1 (rho: fixedGridRhoFastjetAll)" ) # Attach the vertex to them, for dxy/dz calculation for mu in allmuons: mu.associatedVertex = event.goodVertices[0] if len( event.goodVertices) > 0 else event.vertices[0] mu.setTrackForDxyDz(self.cfg_ana.muon_dxydz_track) # Set tight id if specified if hasattr(self.cfg_ana, "mu_tightId"): for mu in allmuons: mu.tightIdResult = mu.muonID(self.cfg_ana.mu_tightId) # Compute relIso in 0.3 and 0.4 cones for mu in allmuons: if self.cfg_ana.mu_isoCorr == "rhoArea": mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.rho * mu.EffectiveArea03, 0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.rho * mu.EffectiveArea04, 0.0)) elif self.cfg_ana.mu_isoCorr == "deltaBeta": mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt / 2, 0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt / 2, 0.0)) else: raise RuntimeError( "Unsupported mu_isoCorr name '" + str(self.cfg_ana.mu_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported.") mu.relIso03 = mu.absIso03 / mu.pt() mu.relIso04 = mu.absIso04 / mu.pt() return allmuons def makeAllElectrons(self, event): """ make a list of all electrons, and apply basic corrections to them """ allelectrons = map(Electron, self.handles['electrons'].product()) ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases) allelenodup = [] for e in allelectrons: dup = False for e2 in allelenodup: if abs(e.pt() - e2.pt()) < 1e-6 and abs(e.eta() - e2.eta( )) < 1e-6 and abs(e.phi() - e2.phi()) < 1e-6 and e.charge( ) == e2.charge(): dup = True break if not dup: allelenodup.append(e) allelectrons = allelenodup # fill EA for rho-corrected isolation for ele in allelectrons: ele.rho = float(self.handles['rhoEle'].product()[0]) if self.eleEffectiveArea == "Data2012": # https://twiki.cern.ch/twiki/bin/viewauth/CMS/EgammaEARhoCorrection?rev=14 SCEta = abs(ele.superCluster().eta()) if SCEta < 1.0: ele.EffectiveArea03 = 0.13 # 0.130; elif SCEta < 1.479: ele.EffectiveArea03 = 0.14 # 0.137; elif SCEta < 2.0: ele.EffectiveArea03 = 0.07 # 0.067; elif SCEta < 2.2: ele.EffectiveArea03 = 0.09 # 0.089; elif SCEta < 2.3: ele.EffectiveArea03 = 0.11 # 0.107; elif SCEta < 2.4: ele.EffectiveArea03 = 0.11 # 0.110; else: ele.EffectiveArea03 = 0.14 # 0.138; if SCEta < 1.0: ele.EffectiveArea04 = 0.208 elif SCEta < 1.479: ele.EffectiveArea04 = 0.209 elif SCEta < 2.0: ele.EffectiveArea04 = 0.115 elif SCEta < 2.2: ele.EffectiveArea04 = 0.143 elif SCEta < 2.3: ele.EffectiveArea04 = 0.183 elif SCEta < 2.4: ele.EffectiveArea04 = 0.194 else: ele.EffectiveArea04 = 0.261 elif self.eleEffectiveArea == "Phys14_25ns_v1": aeta = abs(ele.eta()) if aeta < 0.800: ele.EffectiveArea03 = 0.1013 elif aeta < 1.300: ele.EffectiveArea03 = 0.0988 elif aeta < 2.000: ele.EffectiveArea03 = 0.0572 elif aeta < 2.200: ele.EffectiveArea03 = 0.0842 else: ele.EffectiveArea03 = 0.1530 if aeta < 0.800: ele.EffectiveArea04 = 0.1830 elif aeta < 1.300: ele.EffectiveArea04 = 0.1734 elif aeta < 2.000: ele.EffectiveArea04 = 0.1077 elif aeta < 2.200: ele.EffectiveArea04 = 0.1565 else: ele.EffectiveArea04 = 0.2680 elif self.eleEffectiveArea == "Spring15_50ns_v1": SCEta = abs(ele.superCluster().eta()) ## ----- https://github.com/ikrav/cmssw/blob/egm_id_747_v2/RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_50ns.txt if SCEta < 0.800: ele.EffectiveArea03 = 0.0973 elif SCEta < 1.300: ele.EffectiveArea03 = 0.0954 elif SCEta < 2.000: ele.EffectiveArea03 = 0.0632 elif SCEta < 2.200: ele.EffectiveArea03 = 0.0727 else: ele.EffectiveArea03 = 0.1337 # warning: EAs not computed for cone DR=0.4 yet. Do not correct ele.EffectiveArea04 = 0.0 elif self.eleEffectiveArea == "Spring15_25ns_v1": SCEta = abs(ele.superCluster().eta()) ## ----- https://github.com/ikrav/cmssw/blob/egm_id_747_v2/RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_25ns.txt if SCEta < 1.000: ele.EffectiveArea03 = 0.1752 elif SCEta < 1.479: ele.EffectiveArea03 = 0.1862 elif SCEta < 2.000: ele.EffectiveArea03 = 0.1411 elif SCEta < 2.200: ele.EffectiveArea03 = 0.1534 elif SCEta < 2.300: ele.EffectiveArea03 = 0.1903 elif SCEta < 2.400: ele.EffectiveArea03 = 0.2243 else: ele.EffectiveArea03 = 0.2687 # warning: EAs not computed for cone DR=0.4 yet. Do not correct ele.EffectiveArea04 = 0.0 else: raise RuntimeError( "Unsupported value for ele_effectiveAreas: can only use Data2012 (rho: ?), Phys14_v1 and Spring15_v1 (rho: fixedGridRhoFastjetAll)" ) # Electron scale calibrations if self.cfg_ana.doElectronScaleCorrections: for ele in allelectrons: self.electronEnergyCalibrator.correct(ele, event.run) # Attach the vertex for ele in allelectrons: ele.associatedVertex = event.goodVertices[0] if len( event.goodVertices) > 0 else event.vertices[0] # Compute relIso with R=0.3 and R=0.4 cones for ele in allelectrons: if self.cfg_ana.ele_isoCorr == "rhoArea": ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max( ele.neutralHadronIsoR(0.3) + ele.photonIsoR(0.3) - ele.rho * ele.EffectiveArea03, 0)) ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max( ele.neutralHadronIsoR(0.4) + ele.photonIsoR(0.4) - ele.rho * ele.EffectiveArea04, 0)) elif self.cfg_ana.ele_isoCorr == "deltaBeta": ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max( ele.neutralHadronIsoR(0.3) + ele.photonIsoR(0.3) - ele.puChargedHadronIsoR(0.3) / 2, 0.0)) ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max( ele.neutralHadronIsoR(0.4) + ele.photonIsoR(0.4) - ele.puChargedHadronIsoR(0.4) / 2, 0.0)) else: raise RuntimeError( "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported.") ele.relIso03 = ele.absIso03 / ele.pt() ele.relIso04 = ele.absIso04 / ele.pt() # Set tight MVA id for ele in allelectrons: if self.cfg_ana.ele_tightId == "MVA": ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5") elif self.cfg_ana.ele_tightId == "Cuts_2012": ele.tightIdResult = -1 + 1 * ele.electronID( "POG_Cuts_ID_2012_Veto_full5x5") + 1 * ele.electronID( "POG_Cuts_ID_2012_Loose_full5x5") + 1 * ele.electronID( "POG_Cuts_ID_2012_Medium_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_2012_Tight_full5x5") elif self.cfg_ana.ele_tightId == "Cuts_PHYS14_25ns_v1_ConvVetoDxyDz": ele.tightIdResult = -1 + 1 * ele.electronID( "POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Veto_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Loose_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Medium_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Tight_full5x5") elif self.cfg_ana.ele_tightId == "Cuts_SPRING15_25ns_v1_ConvVetoDxyDz": ele.tightIdResult = -1 + 1 * ele.electronID( "POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_Veto_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_Loose_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_Medium_full5x5" ) + 1 * ele.electronID( "POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_Tight_full5x5") else: try: ele.tightIdResult = ele.electronID( self.cfg_ana.ele_tightId) except RuntimeError: raise RuntimeError( "Unsupported ele_tightId name '" + str(self.cfg_ana.ele_tightId) + "'! For now only 'MVA' and 'Cuts_2012' are supported, in addition to what provided in Electron.py." ) return allelectrons def attachMiniIsolation(self, mu): mu.miniIsoR = 10.0 / min(max(mu.pt(), 50), 200) # -- version with increasing cone at low pT, gives slightly better performance for tight cuts and low pt leptons # mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) if mu.pt() > 20 else 4.0/min(max(mu.pt(),10),20) what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE") if what == "mu": mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso( mu.physObj, mu.miniIsoR, { "mu": 0.0001, "eleB": 0, "eleE": 0.015 }[what], 0.0) else: mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso( mu.physObj, mu.miniIsoR, { "mu": 0.0001, "eleB": 0, "eleE": 0.015 }[what], 0.0, self.IsolationComputer.selfVetoNone) if self.miniIsolationPUCorr == None: puCorr = self.cfg_ana.mu_isoCorr if what == "mu" else self.cfg_ana.ele_isoCorr else: puCorr = self.miniIsolationPUCorr if puCorr == "weights": if what == "mu": mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.01, 0.5) else: mu.miniAbsIsoNeutral = ( self.IsolationComputer.photonAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone)) else: if what == "mu": mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.01, 0.5) else: mu.miniAbsIsoPho = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNHad = self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNeutral = mu.miniAbsIsoPho + mu.miniAbsIsoNHad # -- version relying on PF candidate vetos; apparently less performant, and the isolation computed at RECO level doesn't have them #mu.miniAbsIsoPhoSV = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.0, 0.0) #mu.miniAbsIsoNHadSV = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0) #mu.miniAbsIsoNeutral = mu.miniAbsIsoPhoSV + mu.miniAbsIsoNHadSV if puCorr == "rhoArea": mu.miniAbsIsoNeutral = max( 0.0, mu.miniAbsIsoNeutral - mu.rho * mu.EffectiveArea03 * (mu.miniIsoR / 0.3)**2) elif puCorr == "deltaBeta": if what == "mu": mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso( mu.physObj, mu.miniIsoR, 0.01, 0.5) else: mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso( mu.physObj, mu.miniIsoR, 0.015 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNeutral = max( 0.0, mu.miniAbsIsoNeutral - 0.5 * mu.miniAbsIsoPU) elif puCorr != 'raw': raise RuntimeError( "Unsupported miniIsolationCorr name '" + puCorr + "'! For now only 'rhoArea', 'deltaBeta', 'raw', 'weights' are supported (and 'weights' is not tested)." ) mu.miniAbsIso = mu.miniAbsIsoCharged + mu.miniAbsIsoNeutral mu.miniRelIso = mu.miniAbsIso / mu.pt() def attachIsoAnnulus04( self, mu ): # annulus isolation with outer cone of 0.4 and delta beta PU correction mu.miniIsoR = 10.0 / min(max(mu.pt(), 50), 200) mu.absIsoAnCharged = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnPho = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnNHad = self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnPU = self.IsolationComputer.puAbsIso( mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnNeutral = max( 0.0, mu.absIsoAnPho + mu.absIsoAnNHad - 0.5 * mu.absIsoAnPU) mu.absIsoAn04 = mu.absIsoAnCharged + mu.absIsoAnNeutral mu.relIsoAn04 = mu.absIsoAn04 / mu.pt() def attachIsolationScan(self, mu): what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE") vetoreg = {"mu": 0.0001, "eleB": 0, "eleE": 0.015}[what] if what == "mu": mu.ScanAbsIsoCharged005 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.05, vetoreg, 0.0) mu.ScanAbsIsoCharged01 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.1, vetoreg, 0.0) mu.ScanAbsIsoCharged02 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.2, vetoreg, 0.0) mu.ScanAbsIsoCharged03 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.3, vetoreg, 0.0) mu.ScanAbsIsoCharged04 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.4, vetoreg, 0.0) else: mu.ScanAbsIsoCharged005 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.05, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged01 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.1, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged02 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.2, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged03 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.3, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged04 = self.IsolationComputer.chargedAbsIso( mu.physObj, 0.4, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) if what == "mu": mu.ScanAbsIsoNeutral005 = self.IsolationComputer.neutralAbsIsoRaw( mu.physObj, 0.05, 0.01, 0.5) mu.ScanAbsIsoNeutral01 = self.IsolationComputer.neutralAbsIsoRaw( mu.physObj, 0.1, 0.01, 0.5) mu.ScanAbsIsoNeutral02 = self.IsolationComputer.neutralAbsIsoRaw( mu.physObj, 0.2, 0.01, 0.5) mu.ScanAbsIsoNeutral03 = self.IsolationComputer.neutralAbsIsoRaw( mu.physObj, 0.3, 0.01, 0.5) mu.ScanAbsIsoNeutral04 = self.IsolationComputer.neutralAbsIsoRaw( mu.physObj, 0.4, 0.01, 0.5) else: vetoreg = {"eleB": 0.0, "eleE": 0.08}[what] mu.ScanAbsIsoNeutral005 = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, 0.05, vetoreg, 0.0, self.IsolationComputer. selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, 0.05, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral01 = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, 0.1, vetoreg, 0.0, self.IsolationComputer. selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, 0.1, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral02 = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, 0.2, vetoreg, 0.0, self.IsolationComputer. selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, 0.2, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral03 = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, 0.3, vetoreg, 0.0, self.IsolationComputer. selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, 0.3, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral04 = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, 0.4, vetoreg, 0.0, self.IsolationComputer. selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoRaw( mu.physObj, 0.4, 0.0, 0.0, self.IsolationComputer.selfVetoNone) def matchLeptons(self, event): def plausible(rec, gen): if abs(rec.pdgId()) == 11 and abs(gen.pdgId()) != 11: return False if abs(rec.pdgId()) == 13 and abs(gen.pdgId()) != 13: return False dr = deltaR(rec.eta(), rec.phi(), gen.eta(), gen.phi()) if dr < 0.3: return True if rec.pt() < 10 and abs( rec.pdgId()) == 13 and gen.pdgId() != rec.pdgId(): return False if dr < 0.7: return True if min(rec.pt(), gen.pt()) / max(rec.pt(), gen.pt()) < 0.3: return False return True leps = event.inclusiveLeptons if self.cfg_ana.match_inclusiveLeptons else event.selectedLeptons match = matchObjectCollection3(leps, event.genleps + event.gentauleps, deltaRMax=1.2, filter=plausible) for lep in leps: gen = match[lep] lep.mcMatchId = (gen.sourceId if gen != None else 0) lep.mcMatchTau = (gen in event.gentauleps if gen else -99) lep.mcLep = gen def isFromB(self, particle, bid=5, done={}): for i in range(particle.numberOfMothers()): mom = particle.mother(i) momid = abs(mom.pdgId()) if momid / 1000 == bid or momid / 100 == bid or momid == bid: return True elif mom.status() == 2 and self.isFromB(mom, done=done, bid=bid): return True return False def matchAnyLeptons(self, event): event.anyLeptons = [ x for x in event.genParticles if x.status() == 1 and abs(x.pdgId()) in [11, 13] ] leps = event.inclusiveLeptons if hasattr( event, 'inclusiveLeptons') else event.selectedLeptons match = matchObjectCollection3( leps, event.anyLeptons, deltaRMax=0.3, filter=lambda x, y: abs(x.pdgId()) == abs(y.pdgId())) for lep in leps: gen = match[lep] lep.mcMatchAny_gp = gen if gen: if self.isFromB(gen): lep.mcMatchAny = 5 # B (inclusive of B->D) elif self.isFromB(gen, bid=4): lep.mcMatchAny = 4 # Charm else: lep.mcMatchAny = 1 if not getattr(lep, 'mcLep', None): lep.mcLep = gen else: if not getattr(lep, 'mcLep', None): lep.mcLep = None lep.mcMatchAny = 0 # fix case where the matching with the only prompt leptons failed, but we still ended up with a prompt match if gen != None and hasattr(lep, 'mcMatchId') and lep.mcMatchId == 0: if isPromptLepton(gen, False) or ( gen.isPromptFinalState() or gen.isDirectPromptTauDecayProductFinalState()): lep.mcMatchId = 100 lep.mcLep = gen elif not hasattr(lep, 'mcMatchId'): lep.mcMatchId = 0 if not hasattr(lep, 'mcMatchTau'): lep.mcMatchTau = 0 def matchToPhotons(self, event): event.anyPho = [ x for x in self.mchandles['genPhotons'].product() if x.status() == 1 and x.pdgId() == 22 and x.pt() > 1.0 ] leps = event.inclusiveLeptons if hasattr( event, 'inclusiveLeptons') else event.selectedLeptons leps = [l for l in leps if abs(l.pdgId()) == 11] plausible = lambda rec, gen: 0.3 * gen.pt() < rec.pt() and rec.pt( ) < 1.5 * gen.pt() match = matchObjectCollection3(leps, event.anyPho, deltaRMax=0.3, filter=plausible) for lep in leps: gen = match[lep] lep.mcPho = gen if lep.mcPho and lep.mcLep: # I have both, I should keep the best one def distance(rec, gen): dr = deltaR(rec.eta(), rec.phi(), gen.eta(), gen.phi()) dptRel = abs(rec.pt() - gen.pt()) / gen.pt() return dr + 0.2 * dptRel dpho = distance(lep, lep.mcPho) dlep = distance(lep, lep.mcLep) if getattr(lep, 'mcMatchAny_gp', None) and lep.mcMatchAny_gp != lep.mcLep: dlep = min(dlep, distance(lep, lep.mcMatchAny_gp)) if dlep <= dpho: lep.mcPho = None def process(self, event): self.readCollections(event.input) self.counters.counter('events').inc('all events') #call the leptons functions self.makeLeptons(event) if self.cfg_comp.isMC and self.cfg_ana.do_mc_match: self.matchLeptons(event) self.matchAnyLeptons(event) if self.doMatchToPhotons: self.matchToPhotons(event) return True
def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if hasattr(self.cfg_ana, 'doMuScleFitCorrections'): raise RuntimeError("doMuScleFitCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'MuScleFit', <name> )") if hasattr(self.cfg_ana, 'doRochesterCorrections'): raise RuntimeError("doRochesterCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'Rochester', <name> )") if self.cfg_ana.doMuonScaleCorrections: algo, options = self.cfg_ana.doMuonScaleCorrections if algo == "Kalman": corr = options['MC' if self.cfg_comp.isMC else 'Data'] self.muonScaleCorrector = KalmanMuonCorrector(corr, self.cfg_comp.isMC, options['isSync'] if 'isSync' in options else False, options['smearMode'] if 'smearMode' in options else "ebe") elif algo == "Rochester": print "WARNING: the Rochester correction in heppy is still from Run 1" self.muonScaleCorrector = RochesterCorrections() elif algo == "MuScleFit": print "WARNING: the MuScleFit correction in heppy is still from Run 1 (and probably no longer functional)" if options not in [ "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError('MuScleFit correction name must be one of [ "prompt", "prompt-sync", "rereco", "rereco-sync" ] ') rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muonScaleCorrector = MuScleFitCorr(cfg_comp.isMC, rereco, sync) else: raise RuntimeError("Unknown muon scale correction algorithm") else: self.muonScaleCorrector = None #FIXME: only Embedded works if self.cfg_ana.doElectronScaleCorrections: conf = cfg_ana.doElectronScaleCorrections self.electronEnergyCalibrator = Run2ElectronCalibrator( conf['data'], conf['GBRForest'], cfg_comp.isMC, conf['isSync'] if 'isSync' in conf else False, ) # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele : ( ele.relIso03 <= self.cfg_ana.loose_electron_relIso and ele.absIso03 < getattr(self.cfg_ana,'loose_electron_absIso',9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu : ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana,'loose_muon_absIso',9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Spring15_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Spring15_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [ None, 'any', 'inclusive' ]: raise RuntimeError("miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)") if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer() self.doIsoAnnulus = getattr(cfg_ana, 'doIsoAnnulus', False) if self.doIsoAnnulus: if not self.doMiniIsolation: self.IsolationComputer = heppy.IsolationComputer() self.doIsolationScan = getattr(cfg_ana, 'doIsolationScan', False) if self.doIsolationScan: if self.doMiniIsolation: assert (self.miniIsolationPUCorr!="weights") assert (self.miniIsolationVetoLeptons==None) else: self.IsolationComputer = heppy.IsolationComputer() self.doMatchToPhotons = getattr(cfg_ana, 'do_mc_match_photons', False)
class LeptonAnalyzer( Analyzer ): def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if hasattr(self.cfg_ana, 'doMuScleFitCorrections'): raise RuntimeError, "doMuScleFitCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'MuScleFit', <name> )" if hasattr(self.cfg_ana, 'doRochesterCorrections'): raise RuntimeError, "doRochesterCorrections is not supported. Please set instead doMuonScaleCorrections = ( 'Rochester', <name> )" if self.cfg_ana.doMuonScaleCorrections: algo, options = self.cfg_ana.doMuonScaleCorrections if algo == "Kalman": corr = options['MC' if self.cfg_comp.isMC else 'Data'] self.muonScaleCorrector = KalmanMuonCorrector(corr, self.cfg_comp.isMC, options['isSync'] if 'isSync' in options else False, options['smearMode'] if 'smearMode' in options else "ebe") elif algo == "Rochester": print "WARNING: the Rochester correction in heppy is still from Run 1" self.muonScaleCorrector = RochesterCorrections() elif algo == "MuScleFit": print "WARNING: the MuScleFit correction in heppy is still from Run 1 (and probably no longer functional)" if options not in [ "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'MuScleFit correction name must be one of [ "prompt", "prompt-sync", "rereco", "rereco-sync" ] ' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muonScaleCorrector = MuScleFitCorr(cfg_comp.isMC, rereco, sync) else: raise RuntimeError, "Unknown muon scale correction algorithm" else: self.muonScaleCorrector = None #FIXME: only Embedded works if self.cfg_ana.doElectronScaleCorrections: conf = cfg_ana.doElectronScaleCorrections self.electronEnergyCalibrator = Run2ElectronCalibrator( conf['data'], conf['GBRForest'], cfg_comp.isMC, conf['isSync'] if 'isSync' in conf else False, ) # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) # Isolation cut if hasattr(cfg_ana, 'loose_electron_isoCut'): self.eleIsoCut = cfg_ana.loose_electron_isoCut else: self.eleIsoCut = lambda ele : ( ele.relIso03 <= self.cfg_ana.loose_electron_relIso and ele.absIso03 < getattr(self.cfg_ana,'loose_electron_absIso',9e99)) if hasattr(cfg_ana, 'loose_muon_isoCut'): self.muIsoCut = cfg_ana.loose_muon_isoCut else: self.muIsoCut = lambda mu : ( mu.relIso03 <= self.cfg_ana.loose_muon_relIso and mu.absIso03 < getattr(self.cfg_ana,'loose_muon_absIso',9e99)) self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Spring15_25ns_v1") self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Spring15_25ns_v1") # MiniIsolation self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False) if self.doMiniIsolation: self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons if self.miniIsolationVetoLeptons not in [ None, 'any', 'inclusive' ]: raise RuntimeError, "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)" if self.miniIsolationPUCorr == "weights": self.IsolationComputer = heppy.IsolationComputer(0.4) else: self.IsolationComputer = heppy.IsolationComputer() self.doIsoAnnulus = getattr(cfg_ana, 'doIsoAnnulus', False) if self.doIsoAnnulus: if not self.doMiniIsolation: self.IsolationComputer = heppy.IsolationComputer() self.doIsolationScan = getattr(cfg_ana, 'doIsolationScan', False) if self.doIsolationScan: if self.doMiniIsolation: assert (self.miniIsolationPUCorr!="weights") assert (self.miniIsolationVetoLeptons==None) else: self.IsolationComputer = heppy.IsolationComputer() self.doMatchToPhotons = getattr(cfg_ana, 'do_mc_match_photons', False) #---------------------------------------- # DECLARATION OF HANDLES OF LEPTONS STUFF #---------------------------------------- def declareHandles(self): super(LeptonAnalyzer, self).declareHandles() #leptons self.handles['muons'] = AutoHandle(self.cfg_ana.muons,"std::vector<pat::Muon>") self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons,"std::vector<pat::Electron>") #rho for muons self.handles['rhoMu'] = AutoHandle( self.cfg_ana.rhoMuon, 'double') #rho for electrons self.handles['rhoEle'] = AutoHandle( self.cfg_ana.rhoElectron, 'double') # JP/CV: add Spring15 EGamma POG electron ID MVA # ( https://twiki.cern.ch/twiki/bin/viewauth/CMS/MultivariateElectronIdentificationRun2#Recipes_for_7_4_12_Spring15_MVA ) self.handles['eleMVAIdSpring15TrigMedium'] = AutoHandle( self.cfg_ana.eleMVAIdSpring15TrigMedium, 'edm::ValueMap<bool>') self.handles['eleMVAIdSpring15TrigTight'] = AutoHandle( self.cfg_ana.eleMVAIdSpring15TrigTight, 'edm::ValueMap<bool>') self.handles['eleMVArawSpring15Trig'] = AutoHandle( self.cfg_ana.eleMVArawSpring15Trig, 'edm::ValueMap<float>') self.handles['eleMVAIdSpring15NonTrigMedium'] = AutoHandle( self.cfg_ana.eleMVAIdSpring15NonTrigMedium, 'edm::ValueMap<bool>') self.handles['eleMVAIdSpring15NonTrigTight'] = AutoHandle( self.cfg_ana.eleMVAIdSpring15NonTrigTight, 'edm::ValueMap<bool>') self.handles['eleMVArawSpring15NonTrig'] = AutoHandle( self.cfg_ana.eleMVArawSpring15NonTrig, 'edm::ValueMap<float>') if self.doMiniIsolation or self.doIsolationScan: self.handles['packedCandidates'] = AutoHandle( self.cfg_ana.packedCandidates, 'std::vector<pat::PackedCandidate>') if self.doMatchToPhotons: if self.doMatchToPhotons == "any": self.mchandles['genPhotons'] = AutoHandle( 'packedGenParticles', 'std::vector<pat::PackedGenParticle>' ) else: self.mchandles['genPhotons'] = AutoHandle( 'prunedGenParticles', 'std::vector<reco::GenParticle>' ) def beginLoop(self, setup): super(LeptonAnalyzer,self).beginLoop(setup) self.counters.addCounter('events') count = self.counters.counter('events') count.register('all events') #------------------ # MAKE LEPTON LISTS #------------------ def makeLeptons(self, event): ### 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 = [] if self.doMiniIsolation or self.doIsolationScan: self.IsolationComputer.setPackedCandidates(self.handles['packedCandidates'].product()) if self.doMiniIsolation: if self.miniIsolationVetoLeptons == "any": for lep in self.handles['muons'].product(): self.IsolationComputer.addVetos(lep) for lep in self.handles['electrons'].product(): self.IsolationComputer.addVetos(lep) #muons allmuons = self.makeAllMuons(event) #electrons allelectrons = self.makeAllElectrons(event) #make inclusive leptons inclusiveMuons = [] inclusiveElectrons = [] for mu in allmuons: if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and mu.pt()>self.cfg_ana.inclusive_muon_pt and abs(mu.eta())<self.cfg_ana.inclusive_muon_eta and abs(mu.dxy())<self.cfg_ana.inclusive_muon_dxy and abs(mu.dz())<self.cfg_ana.inclusive_muon_dz): inclusiveMuons.append(mu) for ele in allelectrons: if ( ele.electronID(self.cfg_ana.inclusive_electron_id) and ele.pt()>self.cfg_ana.inclusive_electron_pt and abs(ele.eta())<self.cfg_ana.inclusive_electron_eta and abs(ele.dxy())<self.cfg_ana.inclusive_electron_dxy and abs(ele.dz())<self.cfg_ana.inclusive_electron_dz and ele.lostInner()<=self.cfg_ana.inclusive_electron_lostHits ): inclusiveElectrons.append(ele) event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons if self.doMiniIsolation: if self.miniIsolationVetoLeptons == "inclusive": for lep in event.inclusiveLeptons: self.IsolationComputer.addVetos(lep.physObj) for lep in event.inclusiveLeptons: self.attachMiniIsolation(lep) if self.doIsoAnnulus: for lep in event.inclusiveLeptons: self.attachIsoAnnulus04(lep) if self.doIsolationScan: for lep in event.inclusiveLeptons: self.attachIsolationScan(lep) # make loose leptons (basic selection) for mu in inclusiveMuons: if (mu.muonID(self.cfg_ana.loose_muon_id) and mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and self.muIsoCut(mu)): mu.looseIdSusy = True event.selectedLeptons.append(mu) event.selectedMuons.append(mu) else: mu.looseIdSusy = False event.otherLeptons.append(mu) looseMuons = event.selectedLeptons[:] for ele in inclusiveElectrons: if (ele.electronID(self.cfg_ana.loose_electron_id) and ele.pt()>self.cfg_ana.loose_electron_pt and abs(ele.eta())<self.cfg_ana.loose_electron_eta and abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz())<self.cfg_ana.loose_electron_dz and self.eleIsoCut(ele) and ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and ( True if getattr(self.cfg_ana,'notCleaningElectrons',False) else (bestMatch(ele, looseMuons)[1] > (self.cfg_ana.min_dr_electron_muon**2)) )): event.selectedLeptons.append(ele) event.selectedElectrons.append(ele) ele.looseIdSusy = True else: event.otherLeptons.append(ele) ele.looseIdSusy = False 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) for lepton in event.selectedLeptons: if hasattr(self,'efficiency'): self.efficiency.attachToObject(lepton) def makeAllMuons(self, event): """ make a list of all muons, and apply basic corrections to them """ # Start from all muons allmuons = map( Muon, self.handles['muons'].product() ) # Muon scale and resolution corrections (if enabled) if self.muonScaleCorrector: self.muonScaleCorrector.correct_all(allmuons, event.run) # Clean up dulicate muons (note: has no effect unless the muon id is removed) if self.cfg_ana.doSegmentBasedMuonCleaning: isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product() ) newmu = [] for i,mu in enumerate(allmuons): if isgood[i]: newmu.append(mu) allmuons = newmu # Attach EAs for isolation: for mu in allmuons: mu.rho = float(self.handles['rhoMu'].product()[0]) if self.muEffectiveArea == "Data2012": if aeta < 1.0 : mu.EffectiveArea03 = 0.382; elif aeta < 1.47 : mu.EffectiveArea03 = 0.317; elif aeta < 2.0 : mu.EffectiveArea03 = 0.242; elif aeta < 2.2 : mu.EffectiveArea03 = 0.326; elif aeta < 2.3 : mu.EffectiveArea03 = 0.462; else : mu.EffectiveArea03 = 0.372; if aeta < 1.0 : mu.EffectiveArea04 = 0.674; elif aeta < 1.47 : mu.EffectiveArea04 = 0.565; elif aeta < 2.0 : mu.EffectiveArea04 = 0.442; elif aeta < 2.2 : mu.EffectiveArea04 = 0.515; elif aeta < 2.3 : mu.EffectiveArea04 = 0.821; else : mu.EffectiveArea04 = 0.660; elif self.muEffectiveArea == "Phys14_25ns_v1": aeta = abs(mu.eta()) if aeta < 0.800: mu.EffectiveArea03 = 0.0913 elif aeta < 1.300: mu.EffectiveArea03 = 0.0765 elif aeta < 2.000: mu.EffectiveArea03 = 0.0546 elif aeta < 2.200: mu.EffectiveArea03 = 0.0728 else: mu.EffectiveArea03 = 0.1177 if aeta < 0.800: mu.EffectiveArea04 = 0.1564 elif aeta < 1.300: mu.EffectiveArea04 = 0.1325 elif aeta < 2.000: mu.EffectiveArea04 = 0.0913 elif aeta < 2.200: mu.EffectiveArea04 = 0.1212 else: mu.EffectiveArea04 = 0.2085 elif self.muEffectiveArea == "Spring15_25ns_v1": aeta = abs(mu.eta()) if aeta < 0.800: mu.EffectiveArea03 = 0.0735 elif aeta < 1.300: mu.EffectiveArea03 = 0.0619 elif aeta < 2.000: mu.EffectiveArea03 = 0.0465 elif aeta < 2.200: mu.EffectiveArea03 = 0.0433 else: mu.EffectiveArea03 = 0.0577 mu.EffectiveArea04 = 0 # not computed else: raise RuntimeError, "Unsupported value for mu_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_25ns_v1 or Spring15_25ns_v1 (rho: fixedGridRhoFastjetAll)" # Attach the vertex to them, for dxy/dz calculation for mu in allmuons: mu.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0] mu.setTrackForDxyDz(self.cfg_ana.muon_dxydz_track) # Set tight id if specified if hasattr(self.cfg_ana, "mu_tightId"): for mu in allmuons: mu.tightIdResult = mu.muonID(self.cfg_ana.mu_tightId) # Compute relIso in 0.3 and 0.4 cones for mu in allmuons: if self.cfg_ana.mu_isoCorr=="rhoArea" : mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.rho * mu.EffectiveArea03,0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.rho * mu.EffectiveArea04,0.0)) elif self.cfg_ana.mu_isoCorr=="deltaBeta" : mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt/2,0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt/2,0.0)) else : raise RuntimeError, "Unsupported mu_isoCorr name '" + str(self.cfg_ana.mu_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported." mu.relIso03 = mu.absIso03/mu.pt() mu.relIso04 = mu.absIso04/mu.pt() return allmuons def makeAllElectrons(self, event): """ make a list of all electrons, and apply basic corrections to them """ allelectrons = map( Electron, self.handles['electrons'].product() ) ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases) allelenodup = [] for e in allelectrons: dup = False for e2 in allelenodup: if abs(e.pt()-e2.pt()) < 1e-6 and abs(e.eta()-e2.eta()) < 1e-6 and abs(e.phi()-e2.phi()) < 1e-6 and e.charge() == e2.charge(): dup = True break if not dup: allelenodup.append(e) allelectrons = allelenodup # fill EA for rho-corrected isolation for ele in allelectrons: ele.rho = float(self.handles['rhoEle'].product()[0]) if self.eleEffectiveArea == "Data2012": # https://twiki.cern.ch/twiki/bin/viewauth/CMS/EgammaEARhoCorrection?rev=14 SCEta = abs(ele.superCluster().eta()) if SCEta < 1.0 : ele.EffectiveArea03 = 0.13 # 0.130; elif SCEta < 1.479: ele.EffectiveArea03 = 0.14 # 0.137; elif SCEta < 2.0 : ele.EffectiveArea03 = 0.07 # 0.067; elif SCEta < 2.2 : ele.EffectiveArea03 = 0.09 # 0.089; elif SCEta < 2.3 : ele.EffectiveArea03 = 0.11 # 0.107; elif SCEta < 2.4 : ele.EffectiveArea03 = 0.11 # 0.110; else : ele.EffectiveArea03 = 0.14 # 0.138; if SCEta < 1.0 : ele.EffectiveArea04 = 0.208; elif SCEta < 1.479: ele.EffectiveArea04 = 0.209; elif SCEta < 2.0 : ele.EffectiveArea04 = 0.115; elif SCEta < 2.2 : ele.EffectiveArea04 = 0.143; elif SCEta < 2.3 : ele.EffectiveArea04 = 0.183; elif SCEta < 2.4 : ele.EffectiveArea04 = 0.194; else : ele.EffectiveArea04 = 0.261; elif self.eleEffectiveArea == "Phys14_25ns_v1": aeta = abs(ele.eta()) if aeta < 0.800: ele.EffectiveArea03 = 0.1013 elif aeta < 1.300: ele.EffectiveArea03 = 0.0988 elif aeta < 2.000: ele.EffectiveArea03 = 0.0572 elif aeta < 2.200: ele.EffectiveArea03 = 0.0842 else: ele.EffectiveArea03 = 0.1530 if aeta < 0.800: ele.EffectiveArea04 = 0.1830 elif aeta < 1.300: ele.EffectiveArea04 = 0.1734 elif aeta < 2.000: ele.EffectiveArea04 = 0.1077 elif aeta < 2.200: ele.EffectiveArea04 = 0.1565 else: ele.EffectiveArea04 = 0.2680 elif self.eleEffectiveArea == "Spring15_50ns_v1": SCEta = abs(ele.superCluster().eta()) ## ----- https://github.com/ikrav/cmssw/blob/egm_id_747_v2/RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_50ns.txt if SCEta < 0.800: ele.EffectiveArea03 = 0.0973 elif SCEta < 1.300: ele.EffectiveArea03 = 0.0954 elif SCEta < 2.000: ele.EffectiveArea03 = 0.0632 elif SCEta < 2.200: ele.EffectiveArea03 = 0.0727 else: ele.EffectiveArea03 = 0.1337 # warning: EAs not computed for cone DR=0.4 yet. Do not correct ele.EffectiveArea04 = 0.0 elif self.eleEffectiveArea == "Spring15_25ns_v1": SCEta = abs(ele.superCluster().eta()) ## ----- https://github.com/ikrav/cmssw/blob/egm_id_747_v2/RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_25ns.txt if SCEta < 1.000: ele.EffectiveArea03 = 0.1752 elif SCEta < 1.479: ele.EffectiveArea03 = 0.1862 elif SCEta < 2.000: ele.EffectiveArea03 = 0.1411 elif SCEta < 2.200: ele.EffectiveArea03 = 0.1534 elif SCEta < 2.300: ele.EffectiveArea03 = 0.1903 elif SCEta < 2.400: ele.EffectiveArea03 = 0.2243 else: ele.EffectiveArea03 = 0.2687 # warning: EAs not computed for cone DR=0.4 yet. Do not correct ele.EffectiveArea04 = 0.0 else: raise RuntimeError, "Unsupported value for ele_effectiveAreas: can only use Data2012 (rho: ?), Phys14_v1 and Spring15_v1 (rho: fixedGridRhoFastjetAll)" # Electron scale calibrations if self.cfg_ana.doElectronScaleCorrections: for ele in allelectrons: self.electronEnergyCalibrator.correct(ele, event.run) # Attach the vertex for ele in allelectrons: ele.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0] # Compute relIso with R=0.3 and R=0.4 cones for ele in allelectrons: if self.cfg_ana.ele_isoCorr=="rhoArea" : ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max(ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3)-ele.rho*ele.EffectiveArea03,0)) ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max(ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4)-ele.rho*ele.EffectiveArea04,0)) elif self.cfg_ana.ele_isoCorr=="deltaBeta" : ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max( ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3) - ele.puChargedHadronIsoR(0.3)/2, 0.0)) ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max( ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4) - ele.puChargedHadronIsoR(0.4)/2, 0.0)) else : raise RuntimeError, "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported." ele.relIso03 = ele.absIso03/ele.pt() ele.relIso04 = ele.absIso04/ele.pt() # Set tight MVA id for ele in allelectrons: if self.cfg_ana.ele_tightId=="MVA" : ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5") elif self.cfg_ana.ele_tightId=="Cuts_2012" : ele.tightIdResult = -1 + 1*ele.electronID("POG_Cuts_ID_2012_Veto_full5x5") + 1*ele.electronID("POG_Cuts_ID_2012_Loose_full5x5") + 1*ele.electronID("POG_Cuts_ID_2012_Medium_full5x5") + 1*ele.electronID("POG_Cuts_ID_2012_Tight_full5x5") elif self.cfg_ana.ele_tightId=="Cuts_PHYS14_25ns_v1_ConvVetoDxyDz" : ele.tightIdResult = -1 + 1*ele.electronID("POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Veto_full5x5") + 1*ele.electronID("POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Loose_full5x5") + 1*ele.electronID("POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Medium_full5x5") + 1*ele.electronID("POG_Cuts_ID_PHYS14_25ns_v1_ConvVetoDxyDz_Tight_full5x5") else : try: ele.tightIdResult = ele.electronID(self.cfg_ana.ele_tightId) except RuntimeError: raise RuntimeError, "Unsupported ele_tightId name '" + str(self.cfg_ana.ele_tightId) + "'! For now only 'MVA' and 'Cuts_2012' are supported, in addition to what provided in Electron.py." # JP/CV: add Spring15 EGamma POG electron ID MVA # ( https://twiki.cern.ch/twiki/bin/viewauth/CMS/MultivariateElectronIdentificationRun2#Recipes_for_7_4_12_Spring15_MVA ) if getattr(self.cfg_ana,'updateEleMVA',False) : eleMVAIdSpring15TrigMedium = self.handles['eleMVAIdSpring15TrigMedium'].product() eleMVAIdSpring15TrigTight = self.handles['eleMVAIdSpring15TrigTight'].product() eleMVArawSpring15Trig = self.handles['eleMVArawSpring15Trig'].product() eleMVAIdSpring15NonTrigMedium = self.handles['eleMVAIdSpring15NonTrigMedium'].product() eleMVAIdSpring15NonTrigTight = self.handles['eleMVAIdSpring15NonTrigTight'].product() eleMVArawSpring15NonTrig = self.handles['eleMVArawSpring15NonTrig'].product() for ie, ele in enumerate(allelectrons): ele.mvaIdSpring15TrigMedium = eleMVAIdSpring15TrigMedium.get(ie) ele.mvaIdSpring15TrigTight = eleMVAIdSpring15TrigTight.get(ie) ele.mvaRawSpring15Trig = eleMVArawSpring15Trig.get(ie) ele.mvaIdSpring15NonTrigMedium = eleMVAIdSpring15NonTrigMedium.get(ie) ele.mvaIdSpring15NonTrigTight = eleMVAIdSpring15NonTrigTight.get(ie) ele.mvaRawSpring15NonTrig = eleMVArawSpring15NonTrig.get(ie) return allelectrons def attachMiniIsolation(self, mu): mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) # -- version with increasing cone at low pT, gives slightly better performance for tight cuts and low pt leptons # mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) if mu.pt() > 20 else 4.0/min(max(mu.pt(),10),20) what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE") if what == "mu": mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0); else: mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0,self.IsolationComputer.selfVetoNone); if self.miniIsolationPUCorr == None: puCorr = self.cfg_ana.mu_isoCorr if what=="mu" else self.cfg_ana.ele_isoCorr else: puCorr = self.miniIsolationPUCorr if puCorr == "weights": if what == "mu": mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.01, 0.5); else: mu.miniAbsIsoNeutral = ( self.IsolationComputer.photonAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) + self.IsolationComputer.neutralHadAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) ) else: if what == "mu": mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.01, 0.5); else: mu.miniAbsIsoPho = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNHad = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.miniAbsIsoNeutral = mu.miniAbsIsoPho + mu.miniAbsIsoNHad # -- version relying on PF candidate vetos; apparently less performant, and the isolation computed at RECO level doesn't have them #mu.miniAbsIsoPhoSV = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.0, 0.0) #mu.miniAbsIsoNHadSV = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0) #mu.miniAbsIsoNeutral = mu.miniAbsIsoPhoSV + mu.miniAbsIsoNHadSV if puCorr == "rhoArea": mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - mu.rho * mu.EffectiveArea03 * (mu.miniIsoR/0.3)**2) elif puCorr == "deltaBeta": if what == "mu": mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.01, 0.5); else: mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.015 if what == "eleE" else 0.0, 0.0,self.IsolationComputer.selfVetoNone); mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - 0.5*mu.miniAbsIsoPU) elif puCorr != 'raw': raise RuntimeError, "Unsupported miniIsolationCorr name '" + puCorr + "'! For now only 'rhoArea', 'deltaBeta', 'raw', 'weights' are supported (and 'weights' is not tested)." mu.miniAbsIso = mu.miniAbsIsoCharged + mu.miniAbsIsoNeutral mu.miniRelIso = mu.miniAbsIso/mu.pt() def attachIsoAnnulus04(self, mu): # annulus isolation with outer cone of 0.4 and delta beta PU correction mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) mu.absIsoAnCharged = self.IsolationComputer.chargedAbsIso (mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnPho = self.IsolationComputer.photonAbsIsoRaw (mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnNHad = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnPU = self.IsolationComputer.puAbsIso (mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone) mu.absIsoAnNeutral = max(0.0, mu.absIsoAnPho + mu.absIsoAnNHad - 0.5*mu.absIsoAnPU) mu.absIsoAn04 = mu.absIsoAnCharged + mu.absIsoAnNeutral mu.relIsoAn04 = mu.absIsoAn04/mu.pt() def attachIsolationScan(self, mu): what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE") vetoreg = {"mu":0.0001,"eleB":0,"eleE":0.015}[what] if what=="mu": mu.ScanAbsIsoCharged005 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.05, vetoreg, 0.0) mu.ScanAbsIsoCharged01 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.1, vetoreg, 0.0) mu.ScanAbsIsoCharged02 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.2, vetoreg, 0.0) mu.ScanAbsIsoCharged03 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.3, vetoreg, 0.0) mu.ScanAbsIsoCharged04 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.4, vetoreg, 0.0) else: mu.ScanAbsIsoCharged005 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.05, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged01 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.1, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged02 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.2, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged03 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.3, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoCharged04 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.4, vetoreg, 0.0, self.IsolationComputer.selfVetoNone) if what=="mu": mu.ScanAbsIsoNeutral005 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.05, 0.01, 0.5) mu.ScanAbsIsoNeutral01 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.1, 0.01, 0.5) mu.ScanAbsIsoNeutral02 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.2, 0.01, 0.5) mu.ScanAbsIsoNeutral03 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.3, 0.01, 0.5) mu.ScanAbsIsoNeutral04 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.4, 0.01, 0.5) else: vetoreg = {"eleB":0.0,"eleE":0.08}[what] mu.ScanAbsIsoNeutral005 = self.IsolationComputer.photonAbsIsoRaw(mu.physObj, 0.05, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)+self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.05, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral01 = self.IsolationComputer.photonAbsIsoRaw(mu.physObj, 0.1, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)+self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.1, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral02 = self.IsolationComputer.photonAbsIsoRaw(mu.physObj, 0.2, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)+self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.2, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral03 = self.IsolationComputer.photonAbsIsoRaw(mu.physObj, 0.3, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)+self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.3, 0.0, 0.0, self.IsolationComputer.selfVetoNone) mu.ScanAbsIsoNeutral04 = self.IsolationComputer.photonAbsIsoRaw(mu.physObj, 0.4, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)+self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.4, 0.0, 0.0, self.IsolationComputer.selfVetoNone) def matchLeptons(self, event): def plausible(rec,gen): if abs(rec.pdgId()) == 11 and abs(gen.pdgId()) != 11: return False if abs(rec.pdgId()) == 13 and abs(gen.pdgId()) != 13: return False dr = deltaR(rec.eta(),rec.phi(),gen.eta(),gen.phi()) if dr < 0.3: return True if rec.pt() < 10 and abs(rec.pdgId()) == 13 and gen.pdgId() != rec.pdgId(): return False if dr < 0.7: return True if min(rec.pt(),gen.pt())/max(rec.pt(),gen.pt()) < 0.3: return False return True leps = event.inclusiveLeptons if self.cfg_ana.match_inclusiveLeptons else event.selectedLeptons match = matchObjectCollection3(leps, event.genleps + event.gentauleps, deltaRMax = 1.2, filter = plausible) for lep in leps: gen = match[lep] lep.mcMatchId = (gen.sourceId if gen != None else 0) lep.mcMatchTau = (gen in event.gentauleps if gen else -99) lep.mcLep=gen def isFromB(self,particle,bid=5, done={}): for i in xrange( particle.numberOfMothers() ): mom = particle.mother(i) momid = abs(mom.pdgId()) if momid / 1000 == bid or momid / 100 == bid or momid == bid: return True elif mom.status() == 2 and self.isFromB(mom, done=done, bid=bid): return True return False def matchAnyLeptons(self, event): event.anyLeptons = [ x for x in event.genParticles if x.status() == 1 and abs(x.pdgId()) in [11,13] ] leps = event.inclusiveLeptons if hasattr(event, 'inclusiveLeptons') else event.selectedLeptons match = matchObjectCollection3(leps, event.anyLeptons, deltaRMax = 0.3, filter = lambda x,y : abs(x.pdgId()) == abs(y.pdgId())) for lep in leps: gen = match[lep] lep.mcMatchAny_gp = gen if gen: if self.isFromB(gen): lep.mcMatchAny = 5 # B (inclusive of B->D) elif self.isFromB(gen,bid=4): lep.mcMatchAny = 4 # Charm else: lep.mcMatchAny = 1 if not getattr(lep, 'mcLep', None): lep.mcLep = gen else: if not getattr(lep, 'mcLep', None): lep.mcLep = None lep.mcMatchAny = 0 # fix case where the matching with the only prompt leptons failed, but we still ended up with a prompt match if gen != None and hasattr(lep,'mcMatchId') and lep.mcMatchId == 0: if isPromptLepton(gen, False) or (gen.isPromptFinalState() or gen.isDirectPromptTauDecayProductFinalState()): lep.mcMatchId = 100 lep.mcLep = gen elif not hasattr(lep,'mcMatchId'): lep.mcMatchId = 0 if not hasattr(lep,'mcMatchTau'): lep.mcMatchTau = 0 def matchToPhotons(self, event): event.anyPho = [ x for x in self.mchandles['genPhotons'].product() if x.status() == 1 and x.pdgId() == 22 and x.pt() > 1.0 ] leps = event.inclusiveLeptons if hasattr(event, 'inclusiveLeptons') else event.selectedLeptons leps = [ l for l in leps if abs(l.pdgId()) == 11 ] plausible = lambda rec, gen : 0.3*gen.pt() < rec.pt() and rec.pt() < 1.5*gen.pt() match = matchObjectCollection3(leps, event.anyPho, deltaRMax = 0.3, filter = plausible) for lep in leps: gen = match[lep] lep.mcPho = gen if lep.mcPho and lep.mcLep: # I have both, I should keep the best one def distance(rec,gen): dr = deltaR(rec.eta(),rec.phi(),gen.eta(),gen.phi()) dptRel = abs(rec.pt()-gen.pt())/gen.pt() return dr + 0.2*dptRel dpho = distance(lep,lep.mcPho) dlep = distance(lep,lep.mcLep) if getattr(lep,'mcMatchAny_gp',None) and lep.mcMatchAny_gp != lep.mcLep: dlep = min(dlep, distance(lep,lep.mcMatchAny_gp)) if dlep <= dpho: lep.mcPho = None def process(self, event): self.readCollections( event.input ) self.counters.counter('events').inc('all events') #call the leptons functions self.makeLeptons(event) if self.cfg_comp.isMC and self.cfg_ana.do_mc_match: self.matchLeptons(event) self.matchAnyLeptons(event) if self.doMatchToPhotons: self.matchToPhotons(event) return True
class LeptonAnalyzer( Analyzer ): def __init__(self, cfg_ana, cfg_comp, looperName ): super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName) if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none": if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]: raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"' rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections) sync = ("sync" in self.cfg_ana.doMuScleFitCorrections) self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync) if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections: raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!" else: self.cfg_ana.doMuScleFitCorrections = False #FIXME: only Embedded works self.electronEnergyCalibrator = EmbeddedElectronCalibrator() # if hasattr(cfg_comp,'efficiency'): # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency) #---------------------------------------- # DECLARATION OF HANDLES OF LEPTONS STUFF #---------------------------------------- def declareHandles(self): super(LeptonAnalyzer, self).declareHandles() #leptons self.handles['muons'] = AutoHandle(self.cfg_ana.muons,"std::vector<pat::Muon>") self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons,"std::vector<pat::Electron>") #rho for muons self.handles['rhoMu'] = AutoHandle( self.cfg_ana.rhoMuon, 'double') #rho for electrons self.handles['rhoEle'] = AutoHandle( self.cfg_ana.rhoElectron, 'double') def beginLoop(self): super(LeptonAnalyzer,self).beginLoop() self.counters.addCounter('events') count = self.counters.counter('events') count.register('all events') #------------------ # MAKE LEPTON LISTS #------------------ def makeLeptons(self, event): ### 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 = [] #muons allmuons = self.makeAllMuons(event) for mu in allmuons: # inclusive, very loose, selection if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and mu.pt()>self.cfg_ana.inclusive_muon_pt and abs(mu.eta())<self.cfg_ana.inclusive_muon_eta and abs(mu.dxy())<self.cfg_ana.inclusive_muon_dxy and abs(mu.dz())<self.cfg_ana.inclusive_muon_dz): event.inclusiveLeptons.append(mu) # basic selection if (mu.muonID(self.cfg_ana.loose_muon_id) and mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and mu.relIso03 < self.cfg_ana.loose_muon_relIso and mu.absIso03 < (self.cfg_ana.loose_muon_absIso if hasattr(self.cfg_ana,'loose_muon_absIso') else 9e99)): mu.looseIdSusy = True event.selectedLeptons.append(mu) event.selectedMuons.append(mu) else: mu.looseIdSusy = False event.otherLeptons.append(mu) #electrons allelectrons = self.makeAllElectrons(event) looseMuons = event.selectedLeptons[:] for ele in allelectrons: ## remove muons if muForEleCrossCleaning is not empty ## apply selection if ( ele.electronID(self.cfg_ana.inclusive_electron_id) and ele.pt()>self.cfg_ana.inclusive_electron_pt and abs(ele.eta())<self.cfg_ana.inclusive_electron_eta and abs(ele.dxy())<self.cfg_ana.inclusive_electron_dxy and abs(ele.dz())<self.cfg_ana.inclusive_electron_dz and ele.lostInner()<=self.cfg_ana.inclusive_electron_lostHits ): event.inclusiveLeptons.append(ele) # basic selection if (ele.electronID(self.cfg_ana.loose_electron_id) and ele.pt()>self.cfg_ana.loose_electron_pt and abs(ele.eta())<self.cfg_ana.loose_electron_eta and abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz())<self.cfg_ana.loose_electron_dz and ele.relIso03 <= self.cfg_ana.loose_electron_relIso and ele.absIso03 < (self.cfg_ana.loose_electron_absIso if hasattr(self.cfg_ana,'loose_electron_absIso') else 9e99) and ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and ( True if (hasattr(self.cfg_ana,'notCleaningElectrons') and self.cfg_ana.notCleaningElectrons) else (bestMatch(ele, looseMuons)[1] > self.cfg_ana.min_dr_electron_muon) )): event.selectedLeptons.append(ele) event.selectedElectrons.append(ele) ele.looseIdSusy = True else: event.otherLeptons.append(ele) ele.looseIdSusy = False 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) for lepton in event.selectedLeptons: if hasattr(self,'efficiency'): self.efficiency.attachToObject(lepton) def makeAllMuons(self, event): """ make a list of all muons, and apply basic corrections to them """ # Start from all muons allmuons = map( Muon, self.handles['muons'].product() ) # Muon scale and resolution corrections (if enabled) if self.cfg_ana.doMuScleFitCorrections: for mu in allmuons: self.muscleCorr.correct(mu, event.run) elif self.cfg_ana.doRochesterCorrections: for mu in allmuons: corp4 = rochcor.corrected_p4(mu, event.run) mu.setP4( corp4 ) # Clean up dulicate muons (note: has no effect unless the muon id is removed) if self.cfg_ana.doSegmentBasedMuonCleaning: isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product() ) newmu = [] for i,mu in enumerate(allmuons): if isgood[i]: newmu.append(mu) allmuons = newmu # Attach the vertex to them, for dxy/dz calculation for mu in allmuons: mu.associatedVertex = event.goodVertices[0] # Compute relIso in 0.3 and 0.4 cones for mu in allmuons: mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt/2,0.0)) mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt/2,0.0)) mu.relIso03 = mu.absIso03/mu.pt() mu.relIso04 = mu.absIso04/mu.pt() return allmuons def makeAllElectrons(self, event): """ make a list of all electrons, and apply basic corrections to them """ allelectrons = map( Electron, self.handles['electrons'].product() ) ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases) allelenodup = [] for e in allelectrons: dup = False for e2 in allelenodup: if abs(e.pt()-e2.pt()) < 1e-6 and abs(e.eta()-e2.eta()) < 1e-6 and abs(e.phi()-e2.phi()) < 1e-6 and e.charge() == e2.charge(): dup = True break if not dup: allelenodup.append(e) allelectrons = allelenodup # fill EA for rho-corrected isolation for ele in allelectrons: ele.rho = float(self.handles['rhoEle'].product()[0]) SCEta = abs(ele.superCluster().eta()) if (abs(SCEta) >= 0.0 and abs(SCEta) < 1.0 ) : ele.EffectiveArea = 0.13 # 0.130; if (abs(SCEta) >= 1.0 and abs(SCEta) < 1.479 ) : ele.EffectiveArea = 0.14 # 0.137; if (abs(SCEta) >= 1.479 and abs(SCEta) < 2.0 ) : ele.EffectiveArea = 0.07 # 0.067; if (abs(SCEta) >= 2.0 and abs(SCEta) < 2.2 ) : ele.EffectiveArea = 0.09 # 0.089; if (abs(SCEta) >= 2.2 and abs(SCEta) < 2.3 ) : ele.EffectiveArea = 0.11 # 0.107; if (abs(SCEta) >= 2.3 and abs(SCEta) < 2.4 ) : ele.EffectiveArea = 0.11 # 0.110; if (abs(SCEta) >= 2.4) : ele.EffectiveArea = 0.14 # 0.138; # Electron scale calibrations if self.cfg_ana.doElectronScaleCorrections: for ele in allelectrons: self.electronEnergyCalibrator.correct(ele, event.run) # Attach the vertex for ele in allelectrons: ele.associatedVertex = event.goodVertices[0] # Compute relIso with R=0.3 and R=0.4 cones for ele in allelectrons: if self.cfg_ana.ele_isoCorr=="rhoArea" : ele.absIso03 = (ele.chargedHadronIso(0.3) + max(ele.neutralHadronIso(0.3)+ele.photonIso(0.3)-ele.rho*ele.EffectiveArea,0)) ele.absIso04 = (ele.chargedHadronIso(0.4) + max(ele.neutralHadronIso(0.4)+ele.photonIso(0.4)-ele.rho*ele.EffectiveArea,0)) elif self.cfg_ana.ele_isoCorr=="deltaBeta" : ele.absIso03 = (ele.pfIsolationVariables().sumChargedHadronPt + max( ele.pfIsolationVariables().sumNeutralHadronEt + ele.pfIsolationVariables().sumPhotonEt - ele.pfIsolationVariables().sumPUPt/2,0.0)) ele.absIso04 = 0. else : raise RuntimeError, "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported." ele.relIso03 = ele.absIso03/ele.pt() ele.relIso04 = ele.absIso04/ele.pt() # Set tight MVA id for ele in allelectrons: if self.cfg_ana.ele_tightId=="MVA" : ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5") elif self.cfg_ana.ele_tightId=="Cuts_2012" : ele.tightIdResult = -1 + 1*ele.electronID("POG_Cuts_ID_2012_Veto") + 1*ele.electronID("POG_Cuts_ID_2012_Loose") + 1*ele.electronID("POG_Cuts_ID_2012_Medium") + 1*ele.electronID("POG_Cuts_ID_2012_Tight") else : raise RuntimeError, "Unsupported ele_tightId name '" + str(self.cfg_ana.ele_tightId) + "'! For now only 'MVA' and 'Cuts_2012' are supported." return allelectrons def process(self, event): self.readCollections( event.input ) self.counters.counter('events').inc('all events') #call the leptons functions self.makeLeptons(event) return True