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', "Phys14_25ns_v1")
56  self.muEffectiveArea = getattr(cfg_ana, 'mu_effectiveAreas', "Phys14_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  # DECLARATION OF HANDLES OF LEPTONS STUFF
70  #----------------------------------------
71 
72 
73  def declareHandles(self):
74  super(LeptonAnalyzer, self).declareHandles()
75 
76  #leptons
77  self.handles['muons'] = AutoHandle(self.cfg_ana.muons,"std::vector<pat::Muon>")
78  self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons,"std::vector<pat::Electron>")
79 
80  #rho for muons
81  self.handles['rhoMu'] = AutoHandle( self.cfg_ana.rhoMuon, 'double')
82  #rho for electrons
83  self.handles['rhoEle'] = AutoHandle( self.cfg_ana.rhoElectron, 'double')
84 
85  if self.doMiniIsolation:
86  self.handles['packedCandidates'] = AutoHandle( self.cfg_ana.packedCandidates, 'std::vector<pat::PackedCandidate>')
87  def beginLoop(self, setup):
88  super(LeptonAnalyzer,self).beginLoop(setup)
89  self.counters.addCounter('events')
90  count = self.counters.counter('events')
91  count.register('all events')
92 
93  #------------------
94  # MAKE LEPTON LISTS
95  #------------------
96 
97 
98  def makeLeptons(self, event):
99  ### inclusive leptons = all leptons that could be considered somewhere in the analysis, with minimal requirements (used e.g. to match to MC)
100  event.inclusiveLeptons = []
101  ### selected leptons = subset of inclusive leptons passing some basic id definition and pt requirement
102  ### other leptons = subset of inclusive leptons failing some basic id definition and pt requirement
103  event.selectedLeptons = []
104  event.selectedMuons = []
105  event.selectedElectrons = []
106  event.otherLeptons = []
107 
108  if self.doMiniIsolation:
109  self.IsolationComputer.setPackedCandidates(self.handles['packedCandidates'].product())
110  if self.miniIsolationVetoLeptons == "any":
111  for lep in self.handles['muons'].product():
112  self.IsolationComputer.addVeto(lep)
113  for lep in self.handles['electrons'].product():
114  self.IsolationComputer.addVeto(lep)
115 
116  #muons
117  allmuons = self.makeAllMuons(event)
118 
119  #electrons
120  allelectrons = self.makeAllElectrons(event)
121 
122  #make inclusive leptons
123  inclusiveMuons = []
124  inclusiveElectrons = []
125  for mu in allmuons:
126  if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and
127  mu.pt()>self.cfg_ana.inclusive_muon_pt and abs(mu.eta())<self.cfg_ana.inclusive_muon_eta and
128  abs(mu.dxy())<self.cfg_ana.inclusive_muon_dxy and abs(mu.dz())<self.cfg_ana.inclusive_muon_dz):
129  inclusiveMuons.append(mu)
130  for ele in allelectrons:
131  if ( ele.electronID(self.cfg_ana.inclusive_electron_id) and
132  ele.pt()>self.cfg_ana.inclusive_electron_pt and abs(ele.eta())<self.cfg_ana.inclusive_electron_eta and
133  abs(ele.dxy())<self.cfg_ana.inclusive_electron_dxy and abs(ele.dz())<self.cfg_ana.inclusive_electron_dz and
134  ele.lostInner()<=self.cfg_ana.inclusive_electron_lostHits ):
135  inclusiveElectrons.append(ele)
136  event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons
137 
138  if self.doMiniIsolation:
139  if self.miniIsolationVetoLeptons == "inclusive":
140  for lep in event.inclusiveLeptons:
141  self.IsolationComputer.addVeto(lep)
142  for lep in event.inclusiveLeptons:
143  self.attachMiniIsolation(lep)
144 
145  # make loose leptons (basic selection)
146  for mu in inclusiveMuons:
147  if (mu.muonID(self.cfg_ana.loose_muon_id) and
148  mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and
149  abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and
150  self.muIsoCut(mu)):
151  mu.looseIdSusy = True
152  event.selectedLeptons.append(mu)
153  event.selectedMuons.append(mu)
154  else:
155  mu.looseIdSusy = False
156  event.otherLeptons.append(mu)
157  looseMuons = event.selectedLeptons[:]
158  for ele in inclusiveElectrons:
159  if (ele.electronID(self.cfg_ana.loose_electron_id) and
160  ele.pt()>self.cfg_ana.loose_electron_pt and abs(ele.eta())<self.cfg_ana.loose_electron_eta and
161  abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz())<self.cfg_ana.loose_electron_dz and
162  self.eleIsoCut(ele) and
163  ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and
164  ( True if getattr(self.cfg_ana,'notCleaningElectrons',False) else (bestMatch(ele, looseMuons)[1] > (self.cfg_ana.min_dr_electron_muon**2)) )):
165  event.selectedLeptons.append(ele)
166  event.selectedElectrons.append(ele)
167  ele.looseIdSusy = True
168  else:
169  event.otherLeptons.append(ele)
170  ele.looseIdSusy = False
171 
172  event.otherLeptons.sort(key = lambda l : l.pt(), reverse = True)
173  event.selectedLeptons.sort(key = lambda l : l.pt(), reverse = True)
174  event.selectedMuons.sort(key = lambda l : l.pt(), reverse = True)
175  event.selectedElectrons.sort(key = lambda l : l.pt(), reverse = True)
176  event.inclusiveLeptons.sort(key = lambda l : l.pt(), reverse = True)
177 
178  for lepton in event.selectedLeptons:
179  if hasattr(self,'efficiency'):
180  self.efficiency.attachToObject(lepton)
181 
182  def makeAllMuons(self, event):
183  """
184  make a list of all muons, and apply basic corrections to them
185  """
186  # Start from all muons
187  allmuons = map( Muon, self.handles['muons'].product() )
188 
189  # Muon scale and resolution corrections (if enabled)
190  if self.cfg_ana.doMuScleFitCorrections:
191  for mu in allmuons:
192  self.muscleCorr.correct(mu, event.run)
193  elif self.cfg_ana.doRochesterCorrections:
194  for mu in allmuons:
195  corp4 = rochcor.corrected_p4(mu, event.run)
196  mu.setP4( corp4 )
197 
198  # Clean up dulicate muons (note: has no effect unless the muon id is removed)
199  if self.cfg_ana.doSegmentBasedMuonCleaning:
200  isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product() )
201  newmu = []
202  for i,mu in enumerate(allmuons):
203  if isgood[i]: newmu.append(mu)
204  allmuons = newmu
205 
206  # Attach EAs for isolation:
207  for mu in allmuons:
208  mu.rho = float(self.handles['rhoMu'].product()[0])
209  if self.muEffectiveArea == "Data2012":
210  if aeta < 1.0 : mu.EffectiveArea03 = 0.382;
211  elif aeta < 1.47 : mu.EffectiveArea03 = 0.317;
212  elif aeta < 2.0 : mu.EffectiveArea03 = 0.242;
213  elif aeta < 2.2 : mu.EffectiveArea03 = 0.326;
214  elif aeta < 2.3 : mu.EffectiveArea03 = 0.462;
215  else : mu.EffectiveArea03 = 0.372;
216  if aeta < 1.0 : mu.EffectiveArea04 = 0.674;
217  elif aeta < 1.47 : mu.EffectiveArea04 = 0.565;
218  elif aeta < 2.0 : mu.EffectiveArea04 = 0.442;
219  elif aeta < 2.2 : mu.EffectiveArea04 = 0.515;
220  elif aeta < 2.3 : mu.EffectiveArea04 = 0.821;
221  else : mu.EffectiveArea04 = 0.660;
222  elif self.muEffectiveArea == "Phys14_25ns_v1":
223  aeta = abs(mu.eta())
224  if aeta < 0.800: mu.EffectiveArea03 = 0.0913
225  elif aeta < 1.300: mu.EffectiveArea03 = 0.0765
226  elif aeta < 2.000: mu.EffectiveArea03 = 0.0546
227  elif aeta < 2.200: mu.EffectiveArea03 = 0.0728
228  else: mu.EffectiveArea03 = 0.1177
229  if aeta < 0.800: mu.EffectiveArea04 = 0.1564
230  elif aeta < 1.300: mu.EffectiveArea04 = 0.1325
231  elif aeta < 2.000: mu.EffectiveArea04 = 0.0913
232  elif aeta < 2.200: mu.EffectiveArea04 = 0.1212
233  else: mu.EffectiveArea04 = 0.2085
234  else: raise RuntimeError, "Unsupported value for mu_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_v1 (rho: fixedGridRhoFastjetAll)"
235  # Attach the vertex to them, for dxy/dz calculation
236  for mu in allmuons:
237  mu.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0]
238  mu.setTrackForDxyDz(self.cfg_ana.muon_dxydz_track)
239 
240  # Set tight id if specified
241  if hasattr(self.cfg_ana, "mu_tightId"):
242  for mu in allmuons:
243  mu.tightIdResult = mu.muonID(self.cfg_ana.mu_tightId)
244 
245  # Compute relIso in 0.3 and 0.4 cones
246  for mu in allmuons:
247  if self.cfg_ana.mu_isoCorr=="rhoArea" :
248  mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.rho * mu.EffectiveArea03,0.0))
249  mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.rho * mu.EffectiveArea04,0.0))
250  elif self.cfg_ana.mu_isoCorr=="deltaBeta" :
251  mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt/2,0.0))
252  mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt/2,0.0))
253  else :
254  raise RuntimeError, "Unsupported mu_isoCorr name '" + str(self.cfg_ana.mu_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported."
255  mu.relIso03 = mu.absIso03/mu.pt()
256  mu.relIso04 = mu.absIso04/mu.pt()
257  return allmuons
258 
259  def makeAllElectrons(self, event):
260  """
261  make a list of all electrons, and apply basic corrections to them
262  """
263  allelectrons = map( Electron, self.handles['electrons'].product() )
264 
265  ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases)
266  allelenodup = []
267  for e in allelectrons:
268  dup = False
269  for e2 in allelenodup:
270  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():
271  dup = True
272  break
273  if not dup: allelenodup.append(e)
274  allelectrons = allelenodup
275 
276  # fill EA for rho-corrected isolation
277  for ele in allelectrons:
278  ele.rho = float(self.handles['rhoEle'].product()[0])
279  if self.eleEffectiveArea == "Data2012":
280  # https://twiki.cern.ch/twiki/bin/viewauth/CMS/EgammaEARhoCorrection?rev=14
281  SCEta = abs(ele.superCluster().eta())
282  if SCEta < 1.0 : ele.EffectiveArea03 = 0.13 # 0.130;
283  elif SCEta < 1.479: ele.EffectiveArea03 = 0.14 # 0.137;
284  elif SCEta < 2.0 : ele.EffectiveArea03 = 0.07 # 0.067;
285  elif SCEta < 2.2 : ele.EffectiveArea03 = 0.09 # 0.089;
286  elif SCEta < 2.3 : ele.EffectiveArea03 = 0.11 # 0.107;
287  elif SCEta < 2.4 : ele.EffectiveArea03 = 0.11 # 0.110;
288  else : ele.EffectiveArea03 = 0.14 # 0.138;
289  if SCEta < 1.0 : ele.EffectiveArea04 = 0.208;
290  elif SCEta < 1.479: ele.EffectiveArea04 = 0.209;
291  elif SCEta < 2.0 : ele.EffectiveArea04 = 0.115;
292  elif SCEta < 2.2 : ele.EffectiveArea04 = 0.143;
293  elif SCEta < 2.3 : ele.EffectiveArea04 = 0.183;
294  elif SCEta < 2.4 : ele.EffectiveArea04 = 0.194;
295  else : ele.EffectiveArea04 = 0.261;
296  elif self.eleEffectiveArea == "Phys14_25ns_v1":
297  aeta = abs(ele.eta())
298  if aeta < 0.800: ele.EffectiveArea03 = 0.1013
299  elif aeta < 1.300: ele.EffectiveArea03 = 0.0988
300  elif aeta < 2.000: ele.EffectiveArea03 = 0.0572
301  elif aeta < 2.200: ele.EffectiveArea03 = 0.0842
302  else: ele.EffectiveArea03 = 0.1530
303  if aeta < 0.800: ele.EffectiveArea04 = 0.1830
304  elif aeta < 1.300: ele.EffectiveArea04 = 0.1734
305  elif aeta < 2.000: ele.EffectiveArea04 = 0.1077
306  elif aeta < 2.200: ele.EffectiveArea04 = 0.1565
307  else: ele.EffectiveArea04 = 0.2680
308  else: raise RuntimeError, "Unsupported value for ele_effectiveAreas: can only use Data2012 (rho: ?) and Phys14_v1 (rho: fixedGridRhoFastjetAll)"
309 
310  # Electron scale calibrations
311  if self.cfg_ana.doElectronScaleCorrections:
312  for ele in allelectrons:
313  self.electronEnergyCalibrator.correct(ele, event.run)
314 
315  # Attach the vertex
316  for ele in allelectrons:
317  ele.associatedVertex = event.goodVertices[0] if len(event.goodVertices)>0 else event.vertices[0]
318 
319  # Compute relIso with R=0.3 and R=0.4 cones
320  for ele in allelectrons:
321  if self.cfg_ana.ele_isoCorr=="rhoArea" :
322  ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max(ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3)-ele.rho*ele.EffectiveArea03,0))
323  ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max(ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4)-ele.rho*ele.EffectiveArea04,0))
324  elif self.cfg_ana.ele_isoCorr=="deltaBeta" :
325  ele.absIso03 = (ele.chargedHadronIsoR(0.3) + max( ele.neutralHadronIsoR(0.3)+ele.photonIsoR(0.3) - ele.puChargedHadronIsoR(0.3)/2, 0.0))
326  ele.absIso04 = (ele.chargedHadronIsoR(0.4) + max( ele.neutralHadronIsoR(0.4)+ele.photonIsoR(0.4) - ele.puChargedHadronIsoR(0.4)/2, 0.0))
327  else :
328  raise RuntimeError, "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported."
329  ele.relIso03 = ele.absIso03/ele.pt()
330  ele.relIso04 = ele.absIso04/ele.pt()
331 
332  # Set tight MVA id
333  for ele in allelectrons:
334  if self.cfg_ana.ele_tightId=="MVA" :
335  ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5")
336  elif self.cfg_ana.ele_tightId=="Cuts_2012" :
337  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")
338  elif self.cfg_ana.ele_tightId=="Cuts_PHYS14_25ns_v1_ConvVetoDxyDz" :
339  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")
340 
341  else :
342  try:
343  ele.tightIdResult = ele.electronID(self.cfg_ana.ele_tightId)
344  except RuntimeError:
345  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."
346 
347 
348  return allelectrons
349 
350  def attachMiniIsolation(self, mu):
351  mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200)
352  # -- version with increasing cone at low pT, gives slightly better performance for tight cuts and low pt leptons
353  # mu.miniIsoR = 10.0/min(max(mu.pt(), 50),200) if mu.pt() > 20 else 4.0/min(max(mu.pt(),10),20)
354  what = "mu" if (abs(mu.pdgId()) == 13) else ("eleB" if mu.isEB() else "eleE")
355  if what == "mu":
356  mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0);
357  else:
358  mu.miniAbsIsoCharged = self.IsolationComputer.chargedAbsIso(mu.physObj, mu.miniIsoR, {"mu":0.0001,"eleB":0,"eleE":0.015}[what], 0.0,self.IsolationComputer.selfVetoNone);
359  if self.miniIsolationPUCorr == "weights":
360  if what == "mu":
361  mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.01, 0.5);
362  else:
363  mu.miniAbsIsoNeutral = ( self.IsolationComputer.photonAbsIsoWeighted( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone) +
364  self.IsolationComputer.neutralHadAbsIsoWeighted(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone) )
365  else:
366  if what == "mu":
367  mu.miniAbsIsoNeutral = self.IsolationComputer.neutralAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.01, 0.5);
368  else:
369  mu.miniAbsIsoPho = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.08 if what == "eleE" else 0.0, 0.0, self.IsolationComputer.selfVetoNone)
370  mu.miniAbsIsoNHad = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0, self.IsolationComputer.selfVetoNone)
371  mu.miniAbsIsoNeutral = mu.miniAbsIsoPho + mu.miniAbsIsoNHad
372  # -- version relying on PF candidate vetos; apparently less performant, and the isolation computed at RECO level doesn't have them
373  #mu.miniAbsIsoPhoSV = self.IsolationComputer.photonAbsIsoRaw( mu.physObj, mu.miniIsoR, 0.0, 0.0)
374  #mu.miniAbsIsoNHadSV = self.IsolationComputer.neutralHadAbsIsoRaw(mu.physObj, mu.miniIsoR, 0.0, 0.0)
375  #mu.miniAbsIsoNeutral = mu.miniAbsIsoPhoSV + mu.miniAbsIsoNHadSV
376  if self.miniIsolationPUCorr == "rhoArea":
377  mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - mu.rho * mu.EffectiveArea03 * (mu.miniIsoR/0.3)**2)
378  elif self.miniIsolationPUCorr == "deltaBeta":
379  if what == "mu":
380  mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.01, 0.5);
381  else:
382  mu.miniAbsIsoPU = self.IsolationComputer.puAbsIso(mu.physObj, mu.miniIsoR, 0.015 if what == "eleE" else 0.0, 0.0,self.IsolationComputer.selfVetoNone);
383  mu.miniAbsIsoNeutral = max(0.0, mu.miniAbsIsoNeutral - 0.5*mu.miniAbsIsoPU)
384  elif self.miniIsolationPUCorr != 'raw':
385  raise RuntimeError, "Unsupported miniIsolationCorr name '" + str(self.cfg_ana.miniIsolationCorr) + "'! For now only 'rhoArea', 'deltaBeta', 'raw', 'weights' are supported (and 'weights' is not tested)."
386  mu.miniAbsIso = mu.miniAbsIsoCharged + mu.miniAbsIsoNeutral
387  mu.miniRelIso = mu.miniAbsIso/mu.pt()
388 
389  def matchLeptons(self, event):
390  def plausible(rec,gen):
391  if abs(rec.pdgId()) == 11 and abs(gen.pdgId()) != 11: return False
392  if abs(rec.pdgId()) == 13 and abs(gen.pdgId()) != 13: return False
393  dr = deltaR(rec.eta(),rec.phi(),gen.eta(),gen.phi())
394  if dr < 0.3: return True
395  if rec.pt() < 10 and abs(rec.pdgId()) == 13 and gen.pdgId() != rec.pdgId(): return False
396  if dr < 0.7: return True
397  if min(rec.pt(),gen.pt())/max(rec.pt(),gen.pt()) < 0.3: return False
398  return True
399 
400  leps = event.inclusiveLeptons if self.cfg_ana.match_inclusiveLeptons else event.selectedLeptons
401  match = matchObjectCollection3(leps,
402  event.genleps + event.gentauleps,
403  deltaRMax = 1.2, filter = plausible)
404  for lep in leps:
405  gen = match[lep]
406  lep.mcMatchId = (gen.sourceId if gen != None else 0)
407  lep.mcMatchTau = (gen in event.gentauleps if gen else -99)
408  lep.mcLep=gen
409 
410  def isFromB(self,particle,bid=5, done={}):
411  for i in xrange( particle.numberOfMothers() ):
412  mom = particle.mother(i)
413  momid = abs(mom.pdgId())
414  if momid / 1000 == bid or momid / 100 == bid or momid == bid:
415  return True
416  elif mom.status() == 2 and self.isFromB(mom, done=done):
417  return True
418  return False
419 
420  def matchAnyLeptons(self, event):
421  event.anyLeptons = [ x for x in event.genParticles if x.status() == 1 and abs(x.pdgId()) in [11,13] ]
422  leps = event.inclusiveLeptons if hasattr(event, 'inclusiveLeptons') else event.selectedLeptons
423  match = matchObjectCollection3(leps, event.anyLeptons, deltaRMax = 0.3, filter = lambda x,y : abs(x.pdgId()) == abs(y.pdgId()))
424  for lep in leps:
425  gen = match[lep]
426  lep.mcMatchAny_gp = gen
427  if gen:
428  if self.isFromB(gen): lep.mcMatchAny = 5 # B (inclusive of B->D)
429  elif self.isFromB(gen,bid=4): lep.mcMatchAny = 4 # Charm
430  else: lep.mcMatchAny = 1
431  else:
432  lep.mcMatchAny = 0
433  # fix case where the matching with the only prompt leptons failed, but we still ended up with a prompt match
434  if gen != None and hasattr(lep,'mcMatchId') and lep.mcMatchId == 0:
435  if isPromptLepton(gen, False): lep.mcMatchId = 100
436  elif not hasattr(lep,'mcMatchId'):
437  lep.mcMatchId = 0
438  if not hasattr(lep,'mcMatchTau'): lep.mcMatchTau = 0
439 
440  def process(self, event):
441  self.readCollections( event.input )
442  self.counters.counter('events').inc('all events')
443 
444  #call the leptons functions
445  self.makeLeptons(event)
446 
447  if self.cfg_comp.isMC and self.cfg_ana.do_mc_match:
448  self.matchLeptons(event)
449  self.matchAnyLeptons(event)
450 
451  return True
452 
453 #A default config
454 setattr(LeptonAnalyzer,"defaultConfig",cfg.Analyzer(
455  verbose=False,
456  class_object=LeptonAnalyzer,
457  # input collections
458  muons='slimmedMuons',
459  electrons='slimmedElectrons',
460  rhoMuon= 'fixedGridRhoFastjetAll',
461  rhoElectron = 'fixedGridRhoFastjetAll',
462 ## photons='slimmedPhotons',
463  # energy scale corrections and ghost muon suppression (off by default)
464  doMuScleFitCorrections=False, # "rereco"
465  doRochesterCorrections=False,
466  doElectronScaleCorrections=False, # "embedded" in 5.18 for regression
467  doSegmentBasedMuonCleaning=False,
468  # inclusive very loose muon selection
469  inclusive_muon_id = "POG_ID_Loose",
470  inclusive_muon_pt = 3,
471  inclusive_muon_eta = 2.4,
472  inclusive_muon_dxy = 0.5,
473  inclusive_muon_dz = 1.0,
474  muon_dxydz_track = "muonBestTrack",
475  # loose muon selection
476  loose_muon_id = "POG_ID_Loose",
477  loose_muon_pt = 5,
478  loose_muon_eta = 2.4,
479  loose_muon_dxy = 0.05,
480  loose_muon_dz = 0.2,
481  loose_muon_relIso = 0.4,
482  # loose_muon_isoCut = lambda muon :muon.miniRelIso < 0.2
483  # inclusive very loose electron selection
484  inclusive_electron_id = "",
485  inclusive_electron_pt = 5,
486  inclusive_electron_eta = 2.5,
487  inclusive_electron_dxy = 0.5,
488  inclusive_electron_dz = 1.0,
489  inclusive_electron_lostHits = 1.0,
490  # loose electron selection
491  loose_electron_id = "", #POG_MVA_ID_NonTrig_full5x5",
492  loose_electron_pt = 7,
493  loose_electron_eta = 2.4,
494  loose_electron_dxy = 0.05,
495  loose_electron_dz = 0.2,
496  loose_electron_relIso = 0.4,
497  # loose_electron_isoCut = lambda electron : electron.miniRelIso < 0.1
498  loose_electron_lostHits = 1.0,
499  # muon isolation correction method (can be "rhoArea" or "deltaBeta")
500  mu_isoCorr = "rhoArea" ,
501  mu_effectiveAreas = "Phys14_25ns_v1", #(can be 'Data2012' or 'Phys14_25ns_v1')
502  mu_tightId = "POG_ID_Tight" ,
503  # electron isolation correction method (can be "rhoArea" or "deltaBeta")
504  ele_isoCorr = "rhoArea" ,
505  el_effectiveAreas = "Phys14_25ns_v1" , #(can be 'Data2012' or 'Phys14_25ns_v1')
506  ele_tightId = "Cuts_2012" ,
507  # minimum deltaR between a loose electron and a loose muon (on overlaps, discard the electron)
508  min_dr_electron_muon = 0.02,
509  # Mini-isolation, with pT dependent cone: will fill in the miniRelIso, miniRelIsoCharged, miniRelIsoNeutral variables of the leptons (see https://indico.cern.ch/event/368826/ )
510  doMiniIsolation = False, # off by default since it requires access to all PFCandidates
511  packedCandidates = 'packedPFCandidates',
512  miniIsolationPUCorr = 'rhoArea', # Allowed options: 'rhoArea' (EAs for 03 cone scaled by R^2), 'deltaBeta', 'raw' (uncorrected), 'weights' (delta beta weights; not validated)
513  miniIsolationVetoLeptons = None, # use 'inclusive' to veto inclusive leptons and their footprint in all isolation cones
514  # do MC matching
515  do_mc_match = True, # note: it will in any case try it only on MC, not on data
516  match_inclusiveLeptons = False, # match to all inclusive leptons
517  )
518 )
def bestMatch
Definition: deltar.py:139
T eta() const
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