CMS 3D CMS Logo

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Electron.py
Go to the documentation of this file.
1 from PhysicsTools.Heppy.physicsobjects.Lepton import Lepton
3 import ROOT
4 
5 class Electron( Lepton ):
6 
7  def __init__(self, *args, **kwargs):
8  '''Initializing tightIdResult to None. The user is responsible
9  for setting this attribute externally if he wants to use the tightId
10  function.'''
11  super(Electron, self).__init__(*args, **kwargs)
12  self._physObjInit()
13 
14  def _physObjInit(self):
15  self.tightIdResult = None
16  self.associatedVertex = None
17  self.rho = None
18  self._mvaNonTrigV0 = {True:None, False:None}
19  self._mvaTrigV0 = {True:None, False:None}
20  self._mvaTrigNoIPV0 = {True:None, False:None}
21  self._mvaRun2 = {}
22 
23  def electronID( self, id, vertex=None, rho=None ):
24  if id is None or id == "": return True
25  if vertex == None and hasattr(self,'associatedVertex') and self.associatedVertex != None: vertex = self.associatedVertex
26  if rho == None and hasattr(self,'rho') and self.rho != None: rho = self.rho
27  if id == "POG_MVA_ID_NonTrig": return self.mvaIDLoose()
28  elif id == "POG_MVA_ID_Trig": return self.mvaIDTight()
29  elif id == "POG_MVA_ID_NonTrig_full5x5": return self.mvaIDLoose(full5x5=True)
30  elif id == "POG_MVA_ID_Trig_full5x5": return self.mvaIDTight(full5x5=True)
31  elif id == "POG_MVA_ID_Run2_NonTrig_Loose": return self.mvaIDRun2("NonTrigPhys14","Loose")
32  elif id == "POG_MVA_ID_Run2_NonTrig_Tight": return self.mvaIDRun2("NonTrigPhys14","Tight")
33  elif id.startswith("POG_Cuts_ID_"):
34  return self.cutBasedId(id.replace("POG_Cuts_ID_","POG_"))
35  for ID in self.electronIDs():
36  if ID.first == id:
37  return ID.second
38  raise RuntimeError, "Electron id '%s' not yet implemented in Electron.py" % id
39 
40  def cutBasedId(self, wp, showerShapes="auto"):
41  if "_full5x5" in wp:
42  showerShapes = "full5x5"
43  wp = wp.replace("_full5x5","")
44  elif showerShapes == "auto":
45  if "POG_CSA14_25ns_v1" in wp or "POG_CSA14_50ns_v1" in wp or "POG_PHYS14_25ns_v1" in wp:
46  showerShapes = "full5x5"
47  vars = {
48  'dEtaIn' : abs(self.physObj.deltaEtaSuperClusterTrackAtVtx()),
49  'dPhiIn' : abs(self.physObj.deltaPhiSuperClusterTrackAtVtx()),
50  'sigmaIEtaIEta' : self.physObj.full5x5_sigmaIetaIeta() if showerShapes == "full5x5" else self.physObj.sigmaIetaIeta(),
51  'H/E' : self.physObj.hadronicOverEm(),
52  #'1/E-1/p' : abs(1.0/self.physObj.ecalEnergy() - self.physObj.eSuperClusterOverP()/self.physObj.ecalEnergy()),
53  '1/E-1/p' : abs(1.0/self.physObj.ecalEnergy() - self.physObj.eSuperClusterOverP()/self.physObj.ecalEnergy()) if self.physObj.ecalEnergy()>0. else 9e9,
54  'conversionVeto' : self.physObj.passConversionVeto(),
55  'missingHits' : self.physObj.gsfTrack().hitPattern().numberOfHits(ROOT.reco.HitPattern.MISSING_INNER_HITS), # http://cmslxr.fnal.gov/source/DataFormats/TrackReco/interface/HitPattern.h?v=CMSSW_7_2_3#0153
56  }
57  WP = {
58  ## ------- https://twiki.cern.ch/twiki/bin/viewauth/CMS/EgammaCutBasedIdentification?rev=31
59  'POG_2012_Veto' : [('dEtaIn', [0.007, 0.01]), ('dPhiIn', [0.8, 0.7 ]), ('sigmaIEtaIEta', [0.01, 0.03]), ('H/E', [0.15, 9e9]), ('1/E-1/p', [9e9, 9e9])],
60  'POG_2012_Loose' : [('dEtaIn', [0.007, 0.009]), ('dPhiIn', [0.15, 0.1 ]), ('sigmaIEtaIEta', [0.01, 0.03]), ('H/E', [0.12, 0.1]), ('1/E-1/p', [0.05, 0.05])],
61  'POG_2012_Medium' : [('dEtaIn', [0.004, 0.007]), ('dPhiIn', [0.06, 0.03]), ('sigmaIEtaIEta', [0.01, 0.03]), ('H/E', [0.12, 0.1]), ('1/E-1/p', [0.05, 0.05])],
62  'POG_2012_Tight' : [('dEtaIn', [0.004, 0.005]), ('dPhiIn', [0.03, 0.02]), ('sigmaIEtaIEta', [0.01, 0.03]), ('H/E', [0.12, 0.1]), ('1/E-1/p', [0.05, 0.05])],
63  # RIC: in the EG POG WPs, isolation is included too. Here only the pure ID part.
64  # dz and d0 cuts are excluded here as well.
65  ## ------- https://twiki.cern.ch/twiki/bin/viewauth/CMS/CutBasedElectronIdentificationRun2#Working_points_for_CSA14_samples?rev=13
66  'POG_CSA14_25ns_v1_Veto' : [('dEtaIn', [0.017938, 0.014569]), ('dPhiIn', [0.182958, 0.230914]), ('sigmaIEtaIEta', [0.012708, 0.036384]), ('H/E', [0.335015, 0.200792]), ('1/E-1/p', [0.198287, 0.146856])],
67  'POG_CSA14_25ns_v1_Loose' : [('dEtaIn', [0.014928, 0.013045]), ('dPhiIn', [0.141050, 0.149017]), ('sigmaIEtaIEta', [0.011304, 0.035536]), ('H/E', [0.127690, 0.107898]), ('1/E-1/p', [0.097806, 0.102261])],
68  'POG_CSA14_25ns_v1_Medium' : [('dEtaIn', [0.013071, 0.010006]), ('dPhiIn', [0.132113, 0.052321]), ('sigmaIEtaIEta', [0.010726, 0.032882]), ('H/E', [0.109761, 0.101755]), ('1/E-1/p', [0.032639, 0.041427])],
69  'POG_CSA14_25ns_v1_Tight' : [('dEtaIn', [0.012671, 0.008823]), ('dPhiIn', [0.025218, 0.027286]), ('sigmaIEtaIEta', [0.010061, 0.030222]), ('H/E', [0.065085, 0.090710]), ('1/E-1/p', [0.027873, 0.019404])],
70  'POG_CSA14_50ns_v1_Veto' : [('dEtaIn', [0.021, 0.028]), ('dPhiIn', [0.25 , 0.23 ]), ('sigmaIEtaIEta', [0.012, 0.035]), ('H/E', [0.24 , 0.19 ]), ('1/E-1/p', [0.32 , 0.13 ])],
71  'POG_CSA14_50ns_v1_Loose' : [('dEtaIn', [0.016, 0.025]), ('dPhiIn', [0.080, 0.097]), ('sigmaIEtaIEta', [0.012, 0.032]), ('H/E', [0.15 , 0.12 ]), ('1/E-1/p', [0.11 , 0.11 ])],
72  'POG_CSA14_50ns_v1_Medium' : [('dEtaIn', [0.015, 0.023]), ('dPhiIn', [0.051, 0.056]), ('sigmaIEtaIEta', [0.010, 0.030]), ('H/E', [0.10 , 0.099]), ('1/E-1/p', [0.053, 0.11 ])],
73  'POG_CSA14_50ns_v1_Tight' : [('dEtaIn', [0.012, 0.019]), ('dPhiIn', [0.024, 0.043]), ('sigmaIEtaIEta', [0.010, 0.029]), ('H/E', [0.074, 0.080]), ('1/E-1/p', [0.026, 0.076])],
74  ## ------- https://twiki.cern.ch/twiki/bin/viewauth/CMS/CutBasedElectronIdentificationRun2#Working_points_for_PHYS14_sample?rev=13
75  'POG_PHYS14_25ns_v1_Veto' : [('dEtaIn', [0.016315, 0.010671]), ('dPhiIn', [0.252044, 0.245263]), ('sigmaIEtaIEta', [0.011100 , 0.033987]), ('H/E', [0.345843, 0.134691]), ('1/E-1/p', [0.248070, 0.157160])],
76  'POG_PHYS14_25ns_v1_Loose' : [('dEtaIn', [0.012442, 0.010654]), ('dPhiIn', [0.072624, 0.145129]), ('sigmaIEtaIEta', [0.010557 , 0.032602]), ('H/E', [0.121476, 0.131862]), ('1/E-1/p', [0.221803, 0.142283])],
77  'POG_PHYS14_25ns_v1_Medium' : [('dEtaIn', [0.007641, 0.009285]), ('dPhiIn', [0.032643, 0.042447]), ('sigmaIEtaIEta', [0.010399 , 0.029524]), ('H/E', [0.060662, 0.104263]), ('1/E-1/p', [0.153897, 0.137468])],
78  'POG_PHYS14_25ns_v1_Tight' : [('dEtaIn', [0.006574, 0.005681]), ('dPhiIn', [0.022868, 0.032046]), ('sigmaIEtaIEta', [0.010181 , 0.028766]), ('H/E', [0.037553, 0.081902]), ('1/E-1/p', [0.131191, 0.106055])],
79  }
80  WP_conversion_veto = {
81  # missing Hits incremented by 1 because we return False if >=, note the '='
82  ## ------- https://twiki.cern.ch/twiki/bin/viewauth/CMS/CutBasedElectronIdentificationRun2#Working_points_for_CSA14_samples?rev=13
83  'POG_CSA14_25ns_v1_ConvVeto_Veto' : WP['POG_CSA14_25ns_v1_Veto' ]+[('conversionVeto', [True, True]), ('missingHits', [3, 4])],
84  'POG_CSA14_25ns_v1_ConvVeto_Loose' : WP['POG_CSA14_25ns_v1_Loose' ]+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
85  'POG_CSA14_25ns_v1_ConvVeto_Medium' : WP['POG_CSA14_25ns_v1_Medium']+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
86  'POG_CSA14_25ns_v1_ConvVeto_Tight' : WP['POG_CSA14_25ns_v1_Tight' ]+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
87  'POG_CSA14_50ns_v1_ConvVeto_Veto' : WP['POG_CSA14_50ns_v1_Veto' ]+[('conversionVeto', [True, True]), ('missingHits', [3, 4])],
88  'POG_CSA14_50ns_v1_ConvVeto_Loose' : WP['POG_CSA14_50ns_v1_Loose' ]+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
89  'POG_CSA14_50ns_v1_ConvVeto_Medium' : WP['POG_CSA14_50ns_v1_Medium']+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
90  'POG_CSA14_50ns_v1_ConvVeto_Tight' : WP['POG_CSA14_50ns_v1_Tight' ]+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
91  ## ------- https://twiki.cern.ch/twiki/bin/viewauth/CMS/CutBasedElectronIdentificationRun2#Working_points_for_PHYS14_sample?rev=13
92  'POG_PHYS14_25ns_v1_ConvVeto_Veto' : WP['POG_PHYS14_25ns_v1_Veto' ]+[('conversionVeto', [True, True]), ('missingHits', [3, 4])],
93  'POG_PHYS14_25ns_v1_ConvVeto_Loose' : WP['POG_PHYS14_25ns_v1_Loose' ]+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
94  'POG_PHYS14_25ns_v1_ConvVeto_Medium' : WP['POG_PHYS14_25ns_v1_Medium']+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
95  'POG_PHYS14_25ns_v1_ConvVeto_Tight' : WP['POG_PHYS14_25ns_v1_Tight' ]+[('conversionVeto', [True, True]), ('missingHits', [2, 2])],
96  }
97 
98  WP.update(WP_conversion_veto)
99 
100  if wp not in WP:
101  raise RuntimeError, "Working point '%s' not yet implemented in Electron.py" % wp
102  for (cut_name,(cut_eb,cut_ee)) in WP[wp]:
103  if cut_name == 'conversionVeto':
104  return vars[cut_name] == (cut_eb if self.physObj.isEB() else cut_ee)
105  elif vars[cut_name] >= (cut_eb if self.physObj.isEB() else cut_ee):
106  return False
107  return True
108 
109  def absEffAreaIso(self,rho,effectiveAreas):
110  '''MIKE, missing doc.
111  Should have the same name as the function in the mother class.
112  Can call the mother class function with super.
113  '''
114  return self.absIsoFromEA(rho,self.superCluster().eta(),effectiveAreas.eGamma)
115 
116  def mvaId( self ):
117  return self.mvaNonTrigV0()
118 
119  def tightId( self ):
120  return self.tightIdResult
121 
122  def mvaNonTrigV0( self, full5x5=False, debug = False ):
123  if self._mvaNonTrigV0[full5x5] == None:
124  if self.associatedVertex == None: raise RuntimeError, "You need to set electron.associatedVertex before calling any MVA"
125  if self.rho == None: raise RuntimeError, "You need to set electron.rho before calling any MVA"
126  self._mvaNonTrigV0[full5x5] = ElectronMVAID_NonTrig(self.physObj, self.associatedVertex, self.rho, full5x5, debug)
127  return self._mvaNonTrigV0[full5x5]
128 
129  def mvaTrigV0( self, full5x5=False, debug = False ):
130  if self._mvaTrigV0[full5x5] == None:
131  if self.associatedVertex == None: raise RuntimeError, "You need to set electron.associatedVertex before calling any MVA"
132  if self.rho == None: raise RuntimeError, "You need to set electron.rho before calling any MVA"
133  self._mvaTrigV0[full5x5] = ElectronMVAID_Trig(self.physObj, self.associatedVertex, self.rho, full5x5, debug)
134  return self._mvaTrigV0[full5x5]
135 
136  def mvaTrigNoIPV0( self, full5x5=False, debug = False ):
137  if self._mvaTrigNoIPV0[full5x5] == None:
138  if self.associatedVertex == None: raise RuntimeError, "You need to set electron.associatedVertex before calling any MVA"
139  if self.rho == None: raise RuntimeError, "You need to set electron.rho before calling any MVA"
140  self._mvaTrigNoIPV0[full5x5] = ElectronMVAID_TrigNoIP(self.physObj, self.associatedVertex, self.rho, full5x5, debug)
141  return self._mvaTrigNoIPV0[full5x5]
142 
143  def mvaRun2( self, name, debug = False ):
144  if name not in self._mvaRun2:
145  if name not in ElectronMVAID_ByName: raise RuntimeError, "Unknown electron run2 mva id %s (known ones are: %s)\n" % (name, ElectronMVAID_ByName.keys())
146  if self.associatedVertex == None: raise RuntimeError, "You need to set electron.associatedVertex before calling any MVA"
147  if self.rho == None: raise RuntimeError, "You need to set electron.rho before calling any MVA"
148  self._mvaRun2[name] = ElectronMVAID_ByName[name](self.physObj, self.associatedVertex, self.rho, True, debug)
149  return self._mvaRun2[name]
150 
151  def mvaIDTight(self, full5x5=False):
152  eta = abs(self.superCluster().eta())
153  if self.pt() < 20:
154  if (eta < 0.8) : return self.mvaTrigV0(full5x5) > +0.00;
155  elif (eta < 1.479): return self.mvaTrigV0(full5x5) > +0.10;
156  else : return self.mvaTrigV0(full5x5) > +0.62;
157  else:
158  if (eta < 0.8) : return self.mvaTrigV0(full5x5) > +0.94;
159  elif (eta < 1.479): return self.mvaTrigV0(full5x5) > +0.85;
160  else : return self.mvaTrigV0(full5x5) > +0.92;
161 
162  def mvaIDLoose(self, full5x5=False):
163  eta = abs(self.superCluster().eta())
164  if self.pt() < 10:
165  if (eta < 0.8) : return self.mvaNonTrigV0(full5x5) > +0.47;
166  elif (eta < 1.479): return self.mvaNonTrigV0(full5x5) > +0.004;
167  else : return self.mvaNonTrigV0(full5x5) > +0.295;
168  else:
169  if (eta < 0.8) : return self.mvaNonTrigV0(full5x5) > -0.34;
170  elif (eta < 1.479): return self.mvaNonTrigV0(full5x5) > -0.65;
171  else : return self.mvaNonTrigV0(full5x5) > +0.60;
172 
173  def mvaIDRun2(self, name, wp):
174  eta = abs(self.superCluster().eta())
175  if name == "NonTrigPhys14":
176  if wp=="Loose":
177  if (eta < 0.8) : return self.mvaRun2(name) > +0.35;
178  elif (eta < 1.479): return self.mvaRun2(name) > +0.20;
179  else : return self.mvaRun2(name) > -0.52;
180  elif wp=="Tight":
181  if (eta < 0.8) : return self.mvaRun2(name) > 0.73;
182  elif (eta < 1.479): return self.mvaRun2(name) > 0.57;
183  else : return self.mvaRun2(name) > 0.05;
184  else: raise RuntimeError, "Ele MVA ID Working point not found"
185  else: raise RuntimeError, "Ele MVA ID type not found"
186 
187 
188  def mvaIDZZ(self):
189  return self.mvaIDLoose() and (self.gsfTrack().trackerExpectedHitsInner().numberOfLostHits()<=1)
190 
191  def chargedHadronIsoR(self,R=0.4):
192  if R == 0.3: return self.physObj.pfIsolationVariables().sumChargedHadronPt
193  elif R == 0.4: return self.physObj.chargedHadronIso()
194  raise RuntimeError, "Electron chargedHadronIso missing for R=%s" % R
195 
196  def neutralHadronIsoR(self,R=0.4):
197  if R == 0.3: return self.physObj.pfIsolationVariables().sumNeutralHadronEt
198  elif R == 0.4: return self.physObj.neutralHadronIso()
199  raise RuntimeError, "Electron neutralHadronIso missing for R=%s" % R
200 
201  def photonIsoR(self,R=0.4):
202  if R == 0.3: return self.physObj.pfIsolationVariables().sumPhotonEt
203  elif R == 0.4: return self.physObj.photonIso()
204  raise RuntimeError, "Electron photonIso missing for R=%s" % R
205 
206  def chargedAllIsoR(self,R=0.4):
207  if R == 0.3: return self.physObj.pfIsolationVariables().sumChargedParticlePt
208  raise RuntimeError, "Electron chargedAllIso missing for R=%s" % R
209 
210  def chargedAllIso(self):
211  raise RuntimeError, "Electron chargedAllIso missing"
212 
213  def puChargedHadronIsoR(self,R=0.4):
214  if R == 0.3: return self.physObj.pfIsolationVariables().sumPUPt
215  elif R == 0.4: return self.physObj.puChargedHadronIso()
216  raise RuntimeError, "Electron chargedHadronIso missing for R=%s" % R
217 
218  def dxy(self, vertex=None):
219  '''Returns dxy.
220  Computed using vertex (or self.associatedVertex if vertex not specified),
221  and the gsf track.
222  '''
223  if vertex is None:
224  vertex = self.associatedVertex
225  return self.gsfTrack().dxy( vertex.position() )
226 
227  def edxy(self):
228  '''returns the uncertainty on dxy (from gsf track)'''
229  return self.gsfTrack().dxyError()
230 
231  def p4(self):
232  return ROOT.reco.Candidate.p4(self.physObj)
233 
234 # def p4(self):
235 # return self.physObj.p4(self.physObj.candidateP4Kind()) # if kind == None else kind)
236 
237  def dz(self, vertex=None):
238  '''Returns dz.
239  Computed using vertex (or self.associatedVertex if vertex not specified),
240  and the gsf track.
241  '''
242  if vertex is None:
243  vertex = self.associatedVertex
244  return self.gsfTrack().dz( vertex.position() )
245 
246  def edz(self):
247  '''returns the uncertainty on dxz (from gsf track)'''
248  return self.gsfTrack().dzError()
249 
250 
251  def lostInner(self) :
252  if hasattr(self.gsfTrack(),"trackerExpectedHitsInner") :
253  return self.gsfTrack().trackerExpectedHitsInner().numberOfLostHits()
254  else :
255  return self.gsfTrack().hitPattern().numberOfHits(ROOT.reco.HitPattern.MISSING_INNER_HITS)
256 
tuple ElectronMVAID_NonTrig
tuple ElectronMVAID_TrigNoIP
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
def puChargedHadronIsoR
Definition: Electron.py:213
Definition: Lepton.py:1
tuple ElectronMVAID_Trig