test
CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
LeptonAnalyzer.py
Go to the documentation of this file.
1 from PhysicsTools.Heppy.analyzers.core.Analyzer import Analyzer
2 from PhysicsTools.Heppy.analyzers.core.AutoHandle import AutoHandle
3 from PhysicsTools.Heppy.physicsobjects.Electron import Electron
4 from PhysicsTools.Heppy.physicsobjects.Muon import Muon
5 #from CMGTools.TTHAnalysis.tools.EfficiencyCorrector import EfficiencyCorrector
6 
7 from PhysicsTools.HeppyCore.utils.deltar import bestMatch
8 from PhysicsTools.Heppy.physicsutils.RochesterCorrections import rochcor
9 from PhysicsTools.Heppy.physicsutils.MuScleFitCorrector import MuScleFitCorr
10 from PhysicsTools.Heppy.physicsutils.ElectronCalibrator import EmbeddedElectronCalibrator
11 #from CMGTools.TTHAnalysis.electronCalibrator import ElectronCalibrator
12 import PhysicsTools.HeppyCore.framework.config as cfg
15 
16 
17 from ROOT import heppy
18 cmgMuonCleanerBySegments = heppy.CMGMuonCleanerBySegmentsAlgo()
19 
20 class LeptonAnalyzer( Analyzer ):
21 
22 
23  def __init__(self, cfg_ana, cfg_comp, looperName ):
24  super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName)
25  if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none":
26  if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]:
27  raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"'
28  rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections)
29  sync = ("sync" in self.cfg_ana.doMuScleFitCorrections)
30  self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync)
31  if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections:
32  raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!"
33  else:
34  self.cfg_ana.doMuScleFitCorrections = False
35  #FIXME: only Embedded works
36  self.electronEnergyCalibrator = EmbeddedElectronCalibrator()
37 # if hasattr(cfg_comp,'efficiency'):
38 # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency)
39  # Isolation cut
40  if hasattr(cfg_ana, 'loose_electron_isoCut'):
41  self.eleIsoCut = cfg_ana.loose_electron_isoCut
42  else:
43  self.eleIsoCut = lambda ele : (
44  ele.relIso03 <= self.cfg_ana.loose_electron_relIso and
45  ele.absIso03 < getattr(self.cfg_ana,'loose_electron_absIso',9e99))
46  if hasattr(cfg_ana, 'loose_muon_isoCut'):
47  self.muIsoCut = cfg_ana.loose_muon_isoCut
48  else:
49  self.muIsoCut = lambda mu : (
50  mu.relIso03 <= self.cfg_ana.loose_muon_relIso and
51  mu.absIso03 < getattr(self.cfg_ana,'loose_muon_absIso',9e99))
52 
53 
54 
55  self.eleEffectiveArea = getattr(cfg_ana, 'ele_effectiveAreas', "Spring15_25ns_v1")
56  self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Spring15_25ns_v1")
57  # MiniIsolation
58  self.doMiniIsolation = getattr(cfg_ana, 'doMiniIsolation', False)
59  if self.doMiniIsolation:
60  self.miniIsolationPUCorr = self.cfg_ana.miniIsolationPUCorr
61  self.miniIsolationVetoLeptons = self.cfg_ana.miniIsolationVetoLeptons
62  if self.miniIsolationVetoLeptons not in [ None, 'any', 'inclusive' ]:
63  raise RuntimeError, "miniIsolationVetoLeptons should be None, or 'any' (all reco leptons), or 'inclusive' (all inclusive leptons)"
64  if self.miniIsolationPUCorr == "weights":
65  self.IsolationComputer = heppy.IsolationComputer(0.4)
66  else:
67  self.IsolationComputer = heppy.IsolationComputer()
68 
69  self.doIsoAnnulus = getattr(cfg_ana, 'doIsoAnnulus', False)
70  if self.doIsoAnnulus:
71  if not self.doMiniIsolation:
72  self.IsolationComputer = heppy.IsolationComputer()
73 
74  self.doIsolationScan = getattr(cfg_ana, 'doIsolationScan', False)
75  if self.doIsolationScan:
76  if self.doMiniIsolation:
77  assert (self.miniIsolationPUCorr!="weights")
78  assert (self.miniIsolationVetoLeptons==None)
79  else:
80  self.IsolationComputer = heppy.IsolationComputer()
81 
82 
83  #----------------------------------------
84  # DECLARATION OF HANDLES OF LEPTONS STUFF
85  #----------------------------------------
86 
87 
88  def declareHandles(self):
89  super(LeptonAnalyzer, self).declareHandles()
90 
91  #leptons
92  self.handles['muons'] = AutoHandle(self.cfg_ana.muons,"std::vector<pat::Muon>")
93  self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons,"std::vector<pat::Electron>")
94 
95  #rho for muons
96  self.handles['rhoMu'] = AutoHandle( self.cfg_ana.rhoMuon, 'double')
97  #rho for electrons
98  self.handles['rhoEle'] = AutoHandle( self.cfg_ana.rhoElectron, 'double')
99 
100  if self.doMiniIsolation or self.doIsolationScan:
101  self.handles['packedCandidates'] = AutoHandle( self.cfg_ana.packedCandidates, 'std::vector<pat::PackedCandidate>')
102  def beginLoop(self, setup):
103  super(LeptonAnalyzer,self).beginLoop(setup)
104  self.counters.addCounter('events')
105  count = self.counters.counter('events')
106  count.register('all events')
107 
108  #------------------
109  # MAKE LEPTON LISTS
110  #------------------
111 
112 
113  def makeLeptons(self, event):
114  ### inclusive leptons = all leptons that could be considered somewhere in the analysis, with minimal requirements (used e.g. to match to MC)
115  event.inclusiveLeptons = []
116  ### selected leptons = subset of inclusive leptons passing some basic id definition and pt requirement
117  ### other leptons = subset of inclusive leptons failing some basic id definition and pt requirement
118  event.selectedLeptons = []
119  event.selectedMuons = []
120  event.selectedElectrons = []
121  event.otherLeptons = []
122 
123  if self.doMiniIsolation or self.doIsolationScan:
124  self.IsolationComputer.setPackedCandidates(self.handles['packedCandidates'].product())
125  if self.doMiniIsolation:
126  if self.miniIsolationVetoLeptons == "any":
127  for lep in self.handles['muons'].product():
128  self.IsolationComputer.addVetos(lep)
129  for lep in self.handles['electrons'].product():
130  self.IsolationComputer.addVetos(lep)
131 
132  #muons
133  allmuons = self.makeAllMuons(event)
134 
135  #electrons
136  allelectrons = self.makeAllElectrons(event)
137 
138  #make inclusive leptons
139  inclusiveMuons = []
140  inclusiveElectrons = []
141  for mu in allmuons:
142  if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and
143  mu.pt()>self.cfg_ana.inclusive_muon_pt and abs(mu.eta())<self.cfg_ana.inclusive_muon_eta and
144  abs(mu.dxy())<self.cfg_ana.inclusive_muon_dxy and abs(mu.dz())<self.cfg_ana.inclusive_muon_dz):
145  inclusiveMuons.append(mu)
146  for ele in allelectrons:
147  if ( ele.electronID(self.cfg_ana.inclusive_electron_id) and
148  ele.pt()>self.cfg_ana.inclusive_electron_pt and abs(ele.eta())<self.cfg_ana.inclusive_electron_eta and
149  abs(ele.dxy())<self.cfg_ana.inclusive_electron_dxy and abs(ele.dz())<self.cfg_ana.inclusive_electron_dz and
150  ele.lostInner()<=self.cfg_ana.inclusive_electron_lostHits ):
151  inclusiveElectrons.append(ele)
152  event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons
153 
154  if self.doMiniIsolation:
155  if self.miniIsolationVetoLeptons == "inclusive":
156  for lep in event.inclusiveLeptons:
157  self.IsolationComputer.addVetos(lep.physObj)
158  for lep in event.inclusiveLeptons:
159  self.attachMiniIsolation(lep)
160 
161  if self.doIsoAnnulus:
162  for lep in event.inclusiveLeptons:
163  self.attachIsoAnnulus04(lep)
164 
165  if self.doIsolationScan:
166  for lep in event.inclusiveLeptons:
167  self.attachIsolationScan(lep)
168 
169  # make loose leptons (basic selection)
170  for mu in inclusiveMuons:
171  if (mu.muonID(self.cfg_ana.loose_muon_id) and
172  mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and
173  abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and
174  self.muIsoCut(mu)):
175  mu.looseIdSusy = True
176  event.selectedLeptons.append(mu)
177  event.selectedMuons.append(mu)
178  else:
179  mu.looseIdSusy = False
180  event.otherLeptons.append(mu)
181  looseMuons = event.selectedLeptons[:]
182  for ele in inclusiveElectrons:
183  if (ele.electronID(self.cfg_ana.loose_electron_id) and
184  ele.pt()>self.cfg_ana.loose_electron_pt and abs(ele.eta())<self.cfg_ana.loose_electron_eta and
185  abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz())<self.cfg_ana.loose_electron_dz and
186  self.eleIsoCut(ele) and
187  ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and
188  ( True if getattr(self.cfg_ana,'notCleaningElectrons',False) else (bestMatch(ele, looseMuons)[1] > (self.cfg_ana.min_dr_electron_muon**2)) )):
189  event.selectedLeptons.append(ele)
190  event.selectedElectrons.append(ele)
191  ele.looseIdSusy = True
192  else:
193  event.otherLeptons.append(ele)
194  ele.looseIdSusy = False
195 
196  event.otherLeptons.sort(key = lambda l : l.pt(), reverse = True)
197  event.selectedLeptons.sort(key = lambda l : l.pt(), reverse = True)
198  event.selectedMuons.sort(key = lambda l : l.pt(), reverse = True)
199  event.selectedElectrons.sort(key = lambda l : l.pt(), reverse = True)
200  event.inclusiveLeptons.sort(key = lambda l : l.pt(), reverse = True)
201 
202  for lepton in event.selectedLeptons:
203  if hasattr(self,'efficiency'):
204  self.efficiency.attachToObject(lepton)
205 
206  def makeAllMuons(self, event):
207  """
208  make a list of all muons, and apply basic corrections to them
209  """
210  # Start from all muons
211  allmuons = map( Muon, self.handles['muons'].product() )
212 
213  # Muon scale and resolution corrections (if enabled)
214  if self.cfg_ana.doMuScleFitCorrections:
215  for mu in allmuons:
216  self.muscleCorr.correct(mu, event.run)
217  elif self.cfg_ana.doRochesterCorrections:
218  for mu in allmuons:
219  corp4 = rochcor.corrected_p4(mu, event.run)
220  mu.setP4( corp4 )
221 
222  # Clean up dulicate muons (note: has no effect unless the muon id is removed)
223  if self.cfg_ana.doSegmentBasedMuonCleaning:
224  isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product() )
225  newmu = []
226  for i,mu in enumerate(allmuons):
227  if isgood[i]: newmu.append(mu)
228  allmuons = newmu
229 
230  # Attach EAs for isolation:
231  for mu in allmuons:
232  mu.rho = float(self.handles['rhoMu'].product()[0])
233  if self.muEffectiveArea == "Data2012":
234  if aeta < 1.0 : mu.EffectiveArea03 = 0.382;
235  elif aeta < 1.47 : mu.EffectiveArea03 = 0.317;
236  elif aeta < 2.0 : mu.EffectiveArea03 = 0.242;
237  elif aeta < 2.2 : mu.EffectiveArea03 = 0.326;
238  elif aeta < 2.3 : mu.EffectiveArea03 = 0.462;
239  else : mu.EffectiveArea03 = 0.372;
240  if aeta < 1.0 : mu.EffectiveArea04 = 0.674;
241  elif aeta < 1.47 : mu.EffectiveArea04 = 0.565;
242  elif aeta < 2.0 : mu.EffectiveArea04 = 0.442;
243  elif aeta < 2.2 : mu.EffectiveArea04 = 0.515;
244  elif aeta < 2.3 : mu.EffectiveArea04 = 0.821;
245  else : mu.EffectiveArea04 = 0.660;
246  elif self.muEffectiveArea == "Phys14_25ns_v1":
247  aeta = abs(mu.eta())
248  if aeta < 0.800: mu.EffectiveArea03 = 0.0913
249  elif aeta < 1.300: mu.EffectiveArea03 = 0.0765
250  elif aeta < 2.000: mu.EffectiveArea03 = 0.0546
251  elif aeta < 2.200: mu.EffectiveArea03 = 0.0728
252  else: mu.EffectiveArea03 = 0.1177
253  if aeta < 0.800: mu.EffectiveArea04 = 0.1564
254  elif aeta < 1.300: mu.EffectiveArea04 = 0.1325
255  elif aeta < 2.000: mu.EffectiveArea04 = 0.0913
256  elif aeta < 2.200: mu.EffectiveArea04 = 0.1212
257  else: mu.EffectiveArea04 = 0.2085
258  elif self.muEffectiveArea == "Spring15_25ns_v1":
259  aeta = abs(mu.eta())
260  if aeta < 0.800: mu.EffectiveArea03 = 0.0735
261  elif aeta < 1.300: mu.EffectiveArea03 = 0.0619
262  elif aeta < 2.000: mu.EffectiveArea03 = 0.0465
263  elif aeta < 2.200: mu.EffectiveArea03 = 0.0433
264  else: mu.EffectiveArea03 = 0.0577
265  mu.EffectiveArea04 = 0 # not computed
266  else: raise RuntimeError, "Unsupported value for mu_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_25ns_v1 or Spring15_25ns_v1 (rho: fixedGridRhoFastjetAll)"
267  # Attach the vertex to them, for dxy/dz calculation
268  for mu in allmuons:
269  mu.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0]
270  mu.setTrackForDxyDz(self.cfg_ana.muon_dxydz_track)
271 
272  # Set tight id if specified
273  if hasattr(self.cfg_ana, "mu_tightId"):
274  for mu in allmuons:
275  mu.tightIdResult = mu.muonID(self.cfg_ana.mu_tightId)
276 
277  # Compute relIso in 0.3 and 0.4 cones
278  for mu in allmuons:
279  if self.cfg_ana.mu_isoCorr=="rhoArea" :
280  mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.rho * mu.EffectiveArea03,0.0))
281  mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.rho * mu.EffectiveArea04,0.0))
282  elif self.cfg_ana.mu_isoCorr=="deltaBeta" :
283  mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt/2,0.0))
284  mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt/2,0.0))
285  else :
286  raise RuntimeError, "Unsupported mu_isoCorr name '" + str(self.cfg_ana.mu_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported."
287  mu.relIso03 = mu.absIso03/mu.pt()
288  mu.relIso04 = mu.absIso04/mu.pt()
289  return allmuons
290 
291  def makeAllElectrons(self, event):
292  """
293  make a list of all electrons, and apply basic corrections to them
294  """
295  allelectrons = map( Electron, self.handles['electrons'].product() )
296 
297  ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases)
298  allelenodup = []
299  for e in allelectrons:
300  dup = False
301  for e2 in allelenodup:
302  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():
303  dup = True
304  break
305  if not dup: allelenodup.append(e)
306  allelectrons = allelenodup
307 
308  # fill EA for rho-corrected isolation
309  for ele in allelectrons:
310  ele.rho = float(self.handles['rhoEle'].product()[0])
311  if self.eleEffectiveArea == "Data2012":
312  # https://twiki.cern.ch/twiki/bin/viewauth/CMS/EgammaEARhoCorrection?rev=14
313  SCEta = abs(ele.superCluster().eta())
314  if SCEta < 1.0 : ele.EffectiveArea03 = 0.13 # 0.130;
315  elif SCEta < 1.479: ele.EffectiveArea03 = 0.14 # 0.137;
316  elif SCEta < 2.0 : ele.EffectiveArea03 = 0.07 # 0.067;
317  elif SCEta < 2.2 : ele.EffectiveArea03 = 0.09 # 0.089;
318  elif SCEta < 2.3 : ele.EffectiveArea03 = 0.11 # 0.107;
319  elif SCEta < 2.4 : ele.EffectiveArea03 = 0.11 # 0.110;
320  else : ele.EffectiveArea03 = 0.14 # 0.138;
321  if SCEta < 1.0 : ele.EffectiveArea04 = 0.208;
322  elif SCEta < 1.479: ele.EffectiveArea04 = 0.209;
323  elif SCEta < 2.0 : ele.EffectiveArea04 = 0.115;
324  elif SCEta < 2.2 : ele.EffectiveArea04 = 0.143;
325  elif SCEta < 2.3 : ele.EffectiveArea04 = 0.183;
326  elif SCEta < 2.4 : ele.EffectiveArea04 = 0.194;
327  else : ele.EffectiveArea04 = 0.261;
328  elif self.eleEffectiveArea == "Phys14_25ns_v1":
329  aeta = abs(ele.eta())
330  if aeta < 0.800: ele.EffectiveArea03 = 0.1013
331  elif aeta < 1.300: ele.EffectiveArea03 = 0.0988
332  elif aeta < 2.000: ele.EffectiveArea03 = 0.0572
333  elif aeta < 2.200: ele.EffectiveArea03 = 0.0842
334  else: ele.EffectiveArea03 = 0.1530
335  if aeta < 0.800: ele.EffectiveArea04 = 0.1830
336  elif aeta < 1.300: ele.EffectiveArea04 = 0.1734
337  elif aeta < 2.000: ele.EffectiveArea04 = 0.1077
338  elif aeta < 2.200: ele.EffectiveArea04 = 0.1565
339  else: ele.EffectiveArea04 = 0.2680
340  elif self.eleEffectiveArea == "Spring15_50ns_v1":
341  SCEta = abs(ele.superCluster().eta())
342  ## ----- https://github.com/ikrav/cmssw/blob/egm_id_747_v2/RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_50ns.txt
343  if SCEta < 0.800: ele.EffectiveArea03 = 0.0973
344  elif SCEta < 1.300: ele.EffectiveArea03 = 0.0954
345  elif SCEta < 2.000: ele.EffectiveArea03 = 0.0632
346  elif SCEta < 2.200: ele.EffectiveArea03 = 0.0727
347  else: ele.EffectiveArea03 = 0.1337
348  # warning: EAs not computed for cone DR=0.4 yet. Do not correct
349  ele.EffectiveArea04 = 0.0
350  elif self.eleEffectiveArea == "Spring15_25ns_v1":
351  SCEta = abs(ele.superCluster().eta())
352  ## ----- https://github.com/ikrav/cmssw/blob/egm_id_747_v2/RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_25ns.txt
353  if SCEta < 1.000: ele.EffectiveArea03 = 0.1752
354  elif SCEta < 1.479: ele.EffectiveArea03 = 0.1862
355  elif SCEta < 2.000: ele.EffectiveArea03 = 0.1411
356  elif SCEta < 2.200: ele.EffectiveArea03 = 0.1534
357  elif SCEta < 2.300: ele.EffectiveArea03 = 0.1903
358  elif SCEta < 2.400: ele.EffectiveArea03 = 0.2243
359  else: ele.EffectiveArea03 = 0.2687
360  # warning: EAs not computed for cone DR=0.4 yet. Do not correct
361  ele.EffectiveArea04 = 0.0
362  else: raise RuntimeError, "Unsupported value for ele_effectiveAreas: can only use Data2012 (rho: ?), Phys14_v1 and Spring15_v1 (rho: fixedGridRhoFastjetAll)"
363 
364  # Electron scale calibrations
365  if self.cfg_ana.doElectronScaleCorrections:
366  for ele in allelectrons:
367  self.electronEnergyCalibrator.correct(ele, event.run)
368 
369  # Attach the vertex
370  for ele in allelectrons:
371  ele.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0]
372 
373  # Compute relIso with R=0.3 and R=0.4 cones
374  for ele in allelectrons:
375  if self.cfg_ana.ele_isoCorr=="rhoArea" :
376  ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max(ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3)-ele.rho*ele.EffectiveArea03,0))
377  ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max(ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4)-ele.rho*ele.EffectiveArea04,0))
378  elif self.cfg_ana.ele_isoCorr=="deltaBeta" :
379  ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max( ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3) - ele.puChargedHadronIsoR(0.3)/2, 0.0))
380  ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max( ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4) - ele.puChargedHadronIsoR(0.4)/2, 0.0))
381  else :
382  raise RuntimeError, "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported."
383  ele.relIso03 = ele.absIso03/ele.pt()
384  ele.relIso04 = ele.absIso04/ele.pt()
385 
386  # Set tight MVA id
387  for ele in allelectrons:
388  if self.cfg_ana.ele_tightId=="MVA" :
389  ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5")
390  elif self.cfg_ana.ele_tightId=="Cuts_2012" :
391  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")
392  elif self.cfg_ana.ele_tightId=="Cuts_PHYS14_25ns_v1_ConvVetoDxyDz" :
393  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")
394 
395  else :
396  try:
397  ele.tightIdResult = ele.electronID(self.cfg_ana.ele_tightId)
398  except RuntimeError:
399  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."
400 
401 
402  return allelectrons
403 
404  def attachMiniIsolation(self, mu):
405  mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200)
406  # -- version with increasing cone at low pT, gives slightly better performance for tight cuts and low pt leptons
407  # mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) if mu.pt() > 20 else 4.0/min(max(mu.pt(),10),20)
408  what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE")
409  if what == "mu":
410  mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0);
411  else:
412  mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0,self.IsolationComputer.selfVetoNone);
413 
414  if self.miniIsolationPUCorr == None: puCorr = self.cfg_ana.mu_isoCorr if what=="mu" else self.cfg_ana.ele_isoCorr
415  else: puCorr = self.miniIsolationPUCorr
416 
417  if puCorr == "weights":
418  if what == "mu":
419  mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.01, 0.5);
420  else:
421  mu.miniAbsIsoNeutral = ( self.IsolationComputer.photonAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) +
422  self.IsolationComputer.neutralHadAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) )
423  else:
424  if what == "mu":
425  mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.01, 0.5);
426  else:
427  mu.miniAbsIsoPho = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone)
428  mu.miniAbsIsoNHad = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone)
429  mu.miniAbsIsoNeutral = mu.miniAbsIsoPho + mu.miniAbsIsoNHad
430  # -- version relying on PF candidate vetos; apparently less performant, and the isolation computed at RECO level doesn't have them
431  #mu.miniAbsIsoPhoSV = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.0, 0.0)
432  #mu.miniAbsIsoNHadSV = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0)
433  #mu.miniAbsIsoNeutral = mu.miniAbsIsoPhoSV + mu.miniAbsIsoNHadSV
434  if puCorr == "rhoArea":
435  mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - mu.rho * mu.EffectiveArea03 * (mu.miniIsoR/0.3)**2)
436  elif puCorr == "deltaBeta":
437  if what == "mu":
438  mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.01, 0.5);
439  else:
440  mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.015 if what == "eleE" else 0.0, 0.0,self.IsolationComputer.selfVetoNone);
441  mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - 0.5*mu.miniAbsIsoPU)
442  elif puCorr != 'raw':
443  raise RuntimeError, "Unsupported miniIsolationCorr name '" + puCorr + "'! For now only 'rhoArea', 'deltaBeta', 'raw', 'weights' are supported (and 'weights' is not tested)."
444 
445  mu.miniAbsIso = mu.miniAbsIsoCharged + mu.miniAbsIsoNeutral
446  mu.miniRelIso = mu.miniAbsIso/mu.pt()
447 
448 
449  def attachIsoAnnulus04(self, mu): # annulus isolation with outer cone of 0.4 and delta beta PU correction
450  mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200)
451  mu.absIsoAnCharged = self.IsolationComputer.chargedAbsIso (mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone)
452  mu.absIsoAnPho = self.IsolationComputer.photonAbsIsoRaw (mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone)
453  mu.absIsoAnNHad = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone)
454  mu.absIsoAnPU = self.IsolationComputer.puAbsIso (mu.physObj, 0.4, mu.miniIsoR, 0.0, self.IsolationComputer.selfVetoNone)
455  mu.absIsoAnNeutral = max(0.0, mu.absIsoAnPho + mu.absIsoAnNHad - 0.5*mu.absIsoAnPU)
456 
457  mu.absIsoAn04 = mu.absIsoAnCharged + mu.absIsoAnNeutral
458  mu.relIsoAn04 = mu.absIsoAn04/mu.pt()
459 
460 
461  def attachIsolationScan(self, mu):
462 
463  what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE")
464  vetoreg = {"mu":0.0001,"eleB":0,"eleE":0.015}[what]
465 
466  if what=="mu":
467  mu.ScanAbsIsoCharged005 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.05, vetoreg, 0.0)
468  mu.ScanAbsIsoCharged01 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.1, vetoreg, 0.0)
469  mu.ScanAbsIsoCharged02 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.2, vetoreg, 0.0)
470  mu.ScanAbsIsoCharged03 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.3, vetoreg, 0.0)
471  mu.ScanAbsIsoCharged04 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.4, vetoreg, 0.0)
472  else:
473  mu.ScanAbsIsoCharged005 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.05, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)
474  mu.ScanAbsIsoCharged01 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.1, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)
475  mu.ScanAbsIsoCharged02 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.2, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)
476  mu.ScanAbsIsoCharged03 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.3, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)
477  mu.ScanAbsIsoCharged04 = self.IsolationComputer.chargedAbsIso(mu.physObj, 0.4, vetoreg, 0.0, self.IsolationComputer.selfVetoNone)
478 
479  if what=="mu":
480  mu.ScanAbsIsoNeutral005 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.05, 0.01, 0.5)
481  mu.ScanAbsIsoNeutral01 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.1, 0.01, 0.5)
482  mu.ScanAbsIsoNeutral02 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.2, 0.01, 0.5)
483  mu.ScanAbsIsoNeutral03 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.3, 0.01, 0.5)
484  mu.ScanAbsIsoNeutral04 = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, 0.4, 0.01, 0.5)
485  else:
486  vetoreg = {"eleB":0.0,"eleE":0.08}[what]
487  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)
488  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)
489  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)
490  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)
491  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)
492 
493 
494  def matchLeptons(self, event):
495  def plausible(rec,gen):
496  if abs(rec.pdgId()) == 11 and abs(gen.pdgId()) != 11: return False
497  if abs(rec.pdgId()) == 13 and abs(gen.pdgId()) != 13: return False
498  dr = deltaR(rec.eta(),rec.phi(),gen.eta(),gen.phi())
499  if dr < 0.3: return True
500  if rec.pt() < 10 and abs(rec.pdgId()) == 13 and gen.pdgId() != rec.pdgId(): return False
501  if dr < 0.7: return True
502  if min(rec.pt(),gen.pt())/max(rec.pt(),gen.pt()) < 0.3: return False
503  return True
504 
505  leps = event.inclusiveLeptons if self.cfg_ana.match_inclusiveLeptons else event.selectedLeptons
506  match = matchObjectCollection3(leps,
507  event.genleps + event.gentauleps,
508  deltaRMax = 1.2, filter = plausible)
509  for lep in leps:
510  gen = match[lep]
511  lep.mcMatchId = (gen.sourceId if gen != None else 0)
512  lep.mcMatchTau = (gen in event.gentauleps if gen else -99)
513  lep.mcLep=gen
514 
515  def isFromB(self,particle,bid=5, done={}):
516  for i in xrange( particle.numberOfMothers() ):
517  mom = particle.mother(i)
518  momid = abs(mom.pdgId())
519  if momid / 1000 == bid or momid / 100 == bid or momid == bid:
520  return True
521  elif mom.status() == 2 and self.isFromB(mom, done=done):
522  return True
523  return False
524 
525  def matchAnyLeptons(self, event):
526  event.anyLeptons = [ x for x in event.genParticles if x.status() == 1 and abs(x.pdgId()) in [11,13] ]
527  leps = event.inclusiveLeptons if hasattr(event, 'inclusiveLeptons') else event.selectedLeptons
528  match = matchObjectCollection3(leps, event.anyLeptons, deltaRMax = 0.3, filter = lambda x,y : abs(x.pdgId()) == abs(y.pdgId()))
529  for lep in leps:
530  gen = match[lep]
531  lep.mcMatchAny_gp = gen
532  if gen:
533  if self.isFromB(gen): lep.mcMatchAny = 5 # B (inclusive of B->D)
534  elif self.isFromB(gen,bid=4): lep.mcMatchAny = 4 # Charm
535  else: lep.mcMatchAny = 1
536  else:
537  lep.mcMatchAny = 0
538  # fix case where the matching with the only prompt leptons failed, but we still ended up with a prompt match
539  if gen != None and hasattr(lep,'mcMatchId') and lep.mcMatchId == 0:
540  if isPromptLepton(gen, False): lep.mcMatchId = 100
541  elif not hasattr(lep,'mcMatchId'):
542  lep.mcMatchId = 0
543  if not hasattr(lep,'mcMatchTau'): lep.mcMatchTau = 0
544 
545  def process(self, event):
546  self.readCollections( event.input )
547  self.counters.counter('events').inc('all events')
548 
549  #call the leptons functions
550  self.makeLeptons(event)
551 
552  if self.cfg_comp.isMC and self.cfg_ana.do_mc_match:
553  self.matchLeptons(event)
554  self.matchAnyLeptons(event)
555 
556  return True
557 
558 #A default config
559 setattr(LeptonAnalyzer,"defaultConfig",cfg.Analyzer(
560  verbose=False,
561  class_object=LeptonAnalyzer,
562  # input collections
563  muons='slimmedMuons',
564  electrons='slimmedElectrons',
565  rhoMuon= 'fixedGridRhoFastjetAll',
566  rhoElectron = 'fixedGridRhoFastjetAll',
567 ## photons='slimmedPhotons',
568  # energy scale corrections and ghost muon suppression (off by default)
569  doMuScleFitCorrections=False, # "rereco"
570  doRochesterCorrections=False,
571  doElectronScaleCorrections=False, # "embedded" in 5.18 for regression
572  doSegmentBasedMuonCleaning=False,
573  # inclusive very loose muon selection
574  inclusive_muon_id = "POG_ID_Loose",
575  inclusive_muon_pt = 3,
576  inclusive_muon_eta = 2.4,
577  inclusive_muon_dxy = 0.5,
578  inclusive_muon_dz = 1.0,
579  muon_dxydz_track = "muonBestTrack",
580  # loose muon selection
581  loose_muon_id = "POG_ID_Loose",
582  loose_muon_pt = 5,
583  loose_muon_eta = 2.4,
584  loose_muon_dxy = 0.05,
585  loose_muon_dz = 0.2,
586  loose_muon_relIso = 0.4,
587  # loose_muon_isoCut = lambda muon :muon.miniRelIso < 0.2
588  # inclusive very loose electron selection
589  inclusive_electron_id = "",
590  inclusive_electron_pt = 5,
591  inclusive_electron_eta = 2.5,
592  inclusive_electron_dxy = 0.5,
593  inclusive_electron_dz = 1.0,
594  inclusive_electron_lostHits = 1.0,
595  # loose electron selection
596  loose_electron_id = "", #POG_MVA_ID_NonTrig_full5x5",
597  loose_electron_pt = 7,
598  loose_electron_eta = 2.4,
599  loose_electron_dxy = 0.05,
600  loose_electron_dz = 0.2,
601  loose_electron_relIso = 0.4,
602  # loose_electron_isoCut = lambda electron : electron.miniRelIso < 0.1
603  loose_electron_lostHits = 1.0,
604  # muon isolation correction method (can be "rhoArea" or "deltaBeta")
605  mu_isoCorr = "rhoArea" ,
606  mu_effectiveAreas = "Spring15_25ns_v1", #(can be 'Data2012' or 'Phys14_25ns_v1' or 'Spring15_25ns_v1')
607  mu_tightId = "POG_ID_Tight" ,
608  # electron isolation correction method (can be "rhoArea" or "deltaBeta")
609  ele_isoCorr = "rhoArea" ,
610  ele_effectiveAreas = "Spring15_25ns_v1" , #(can be 'Data2012' or 'Phys14_25ns_v1', or 'Spring15_50ns_v1' or 'Spring15_25ns_v1')
611  ele_tightId = "Cuts_2012" ,
612  # minimum deltaR between a loose electron and a loose muon (on overlaps, discard the electron)
613  min_dr_electron_muon = 0.02,
614  # Mini-isolation, with pT dependent cone: will fill in the miniRelIso, miniRelIsoCharged, miniRelIsoNeutral variables of the leptons (see https://indico.cern.ch/event/368826/ )
615  doMiniIsolation = False, # off by default since it requires access to all PFCandidates
616  packedCandidates = 'packedPFCandidates',
617  miniIsolationPUCorr = 'rhoArea', # Allowed options: 'rhoArea' (EAs for 03 cone scaled by R^2), 'deltaBeta', 'raw' (uncorrected), 'weights' (delta beta weights; not validated)
618  # Choose None to just use the individual object's PU correction
619  miniIsolationVetoLeptons = None, # use 'inclusive' to veto inclusive leptons and their footprint in all isolation cones
620  # Activity Annulus
621  doIsoAnnulus = False, # off by default since it requires access to all PFCandidates
622  # do MC matching
623  do_mc_match = True, # note: it will in any case try it only on MC, not on data
624  match_inclusiveLeptons = False, # match to all inclusive leptons
625  )
626 )
def bestMatch
Definition: deltar.py:139
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
T min(T a, T b)
Definition: MathUtil.h:58
double deltaR(double eta1, double eta2, double phi1, double phi2)
Definition: TreeUtility.cc:17
eleEffectiveArea
Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5...
miniIsolationVetoLeptons
inclusive leptons = all leptons that could be considered somewhere in the analysis, with minimal requirements (used e.g.
def isPromptLepton
Definition: genutils.py:49
def matchObjectCollection3
Definition: deltar.py:41