Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:57:50

0001 from PhysicsTools.Heppy.physicsobjects.Lepton import Lepton
0002 from PhysicsTools.HeppyCore.utils.deltar import deltaR
0003 
0004 class Muon( Lepton ):
0005 
0006     def __init__(self, *args, **kwargs):
0007         super(Muon, self).__init__(*args, **kwargs)
0008         self._trackForDxyDz = "muonBestTrack"
0009 
0010     def setTrackForDxyDz(self,what):
0011         if not hasattr(self,what):
0012             raise RuntimeError("I don't have a track called "+what)
0013         self._trackForDxyDz = what
0014 
0015     def looseId( self ):
0016         '''Loose ID as recommended by mu POG.'''
0017         return self.physObj.isLooseMuon()
0018 
0019     def tightId( self ):
0020         '''Tight ID as recommended by mu POG 
0021         (unless redefined in the lepton analyzer).
0022 
0023         If not using the LeptonAnalyzer, make sure to set self.associatedVertex, 
0024         that is necessary for tight muon identification. 
0025         '''
0026         return getattr(self,"tightIdResult",self.muonID("POG_ID_Tight"))
0027 
0028     def muonID(self, name, vertex=None):
0029         if name == "" or name is None: 
0030             return True
0031         if name.startswith("POG_"):
0032             if name == "POG_ID_Loose": return self.physObj.isLooseMuon()
0033             if vertex is None:
0034                 vertex = getattr(self, 'associatedVertex', None)
0035             if name == "POG_ID_Tight":  return self.physObj.isTightMuon(vertex)
0036             if name == "POG_ID_HighPt": return self.physObj.isHighPtMuon(vertex)
0037             if name == "POG_ID_Soft":   return self.physObj.isSoftMuon(vertex)
0038             if name == "POG_ID_TightNoVtx":  return self.looseId() and \
0039                                                  self.isGlobalMuon() and \
0040                                                  self.globalTrack().normalizedChi2() < 10 and \
0041                                                  self.globalTrack().hitPattern().numberOfValidMuonHits() > 0 and \
0042                                                  self.numberOfMatchedStations()>1 and \
0043                                                  self.innerTrack().hitPattern().numberOfValidPixelHits()>0 and \
0044                                                  self.innerTrack().hitPattern().trackerLayersWithMeasurement() > 5
0045             if name == "POG_ID_Medium":
0046                 if not self.looseId(): return False
0047                 goodGlb = self.physObj.isGlobalMuon() and self.physObj.globalTrack().normalizedChi2() < 3 and self.physObj.combinedQuality().chi2LocalPosition < 12 and self.physObj.combinedQuality().trkKink < 20;
0048                 return self.physObj.innerTrack().validFraction() > 0.8 and self.physObj.segmentCompatibility() >= (0.303 if goodGlb else 0.451)
0049             if name == "POG_Global_OR_TMArbitrated":
0050                 return self.physObj.isGlobalMuon() or (self.physObj.isTrackerMuon() and self.physObj.numberOfMatchedStations() > 0)
0051         return self.physObj.muonID(name)
0052             
0053     def mvaId(self):
0054         '''For a transparent treatment of electrons and muons. Returns -99'''
0055         return -99
0056     
0057 
0058     def dxy(self, vertex=None):
0059         '''either pass the vertex, or set associatedVertex before calling the function.
0060         note: the function does not work with standalone muons as innerTrack
0061         is not available.
0062         '''
0063         if vertex is None:
0064             vertex = self.associatedVertex
0065         return getattr(self,self._trackForDxyDz)().dxy( vertex.position() )
0066 
0067     def edxy(self):
0068         '''returns the uncertainty on dxy (from gsf track)'''
0069         return getattr(self,self._trackForDxyDz)().dxyError()
0070  
0071 
0072     def dz(self, vertex=None):
0073         '''either pass the vertex, or set associatedVertex before calling the function.
0074         note: the function does not work with standalone muons as innerTrack
0075         is not available.
0076         '''
0077         if vertex is None:
0078             vertex = self.associatedVertex
0079         return getattr(self,self._trackForDxyDz)().dz( vertex.position() )
0080 
0081     def edz(self):
0082         '''returns the uncertainty on dxz (from gsf track)'''
0083         return getattr(self,self._trackForDxyDz)().dzError()
0084 
0085     def chargedHadronIsoR(self,R=0.4):
0086         if   R == 0.3: return self.physObj.pfIsolationR03().sumChargedHadronPt 
0087         elif R == 0.4: return self.physObj.pfIsolationR04().sumChargedHadronPt 
0088         raise RuntimeError("Muon chargedHadronIso missing for R=%s" % R)
0089 
0090     def neutralHadronIsoR(self,R=0.4):
0091         if   R == 0.3: return self.physObj.pfIsolationR03().sumNeutralHadronEt 
0092         elif R == 0.4: return self.physObj.pfIsolationR04().sumNeutralHadronEt 
0093         raise RuntimeError("Muon neutralHadronIso missing for R=%s" % R)
0094 
0095     def photonIsoR(self,R=0.4):
0096         if   R == 0.3: return self.physObj.pfIsolationR03().sumPhotonEt 
0097         elif R == 0.4: return self.physObj.pfIsolationR04().sumPhotonEt 
0098         raise RuntimeError("Muon photonIso missing for R=%s" % R)
0099 
0100     def chargedAllIsoR(self,R=0.4):
0101         if   R == 0.3: return self.physObj.pfIsolationR03().sumChargedParticlePt 
0102         elif R == 0.4: return self.physObj.pfIsolationR04().sumChargedParticlePt 
0103         raise RuntimeError("Muon chargedAllIso missing for R=%s" % R)
0104 
0105     def chargedAllIso(self):
0106         return self.chargedAllIsoR()
0107 
0108     def puChargedHadronIsoR(self,R=0.4):
0109         if   R == 0.3: return self.physObj.pfIsolationR03().sumPUPt 
0110         elif R == 0.4: return self.physObj.pfIsolationR04().sumPUPt 
0111         raise RuntimeError("Muon chargedHadronIso missing for R=%s" % R)
0112 
0113 
0114     def absIsoWithFSR(self, R=0.4, puCorr="deltaBeta", dBetaFactor=0.5):
0115         '''
0116         Calculate Isolation, subtract FSR, apply specific PU corrections" 
0117         '''
0118         photonIso = self.photonIsoR(R)
0119         if hasattr(self,'fsrPhotons'):
0120             for gamma in self.fsrPhotons:
0121                 dr = deltaR(gamma.eta(), gamma.phi(), self.physObj.eta(), self.physObj.phi())
0122                 if dr > 0.01 and dr < R:
0123                     photonIso = max(photonIso-gamma.pt(),0.0)                
0124         if puCorr == "deltaBeta":
0125             offset = dBetaFactor * self.puChargedHadronIsoR(R)
0126         elif puCorr == "rhoArea":
0127             offset = self.rho*getattr(self,"EffectiveArea"+(str(R).replace(".","")))
0128         elif puCorr in ["none","None",None]:
0129             offset = 0
0130         else:
0131              raise RuntimeError("Unsupported PU correction scheme %s" % puCorr)
0132         return self.chargedHadronIsoR(R)+max(0.,photonIso+self.neutralHadronIsoR(R)-offset)            
0133 
0134     def ptErr(self):
0135         if "_ptErr" in self.__dict__: return self.__dict__['_ptErr']
0136         return self.bestTrack().ptError()