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
13 
14 from ROOT import heppy
15 cmgMuonCleanerBySegments = heppy.CMGMuonCleanerBySegmentsAlgo()
16 
18 
19 
20  def __init__(self, cfg_ana, cfg_comp, looperName ):
21  super(LeptonAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName)
22  if self.cfg_ana.doMuScleFitCorrections and self.cfg_ana.doMuScleFitCorrections != "none":
23  if self.cfg_ana.doMuScleFitCorrections not in [ "none", "prompt", "prompt-sync", "rereco", "rereco-sync" ]:
24  raise RuntimeError, 'doMuScleFitCorrections must be one of "none", "prompt", "prompt-sync", "rereco", "rereco-sync"'
25  rereco = ("prompt" not in self.cfg_ana.doMuScleFitCorrections)
26  sync = ("sync" in self.cfg_ana.doMuScleFitCorrections)
27  self.muscleCorr = MuScleFitCorr(cfg_comp.isMC, rereco, sync)
28  if hasattr(self.cfg_ana, "doRochesterCorrections") and self.cfg_ana.doRochesterCorrections:
29  raise RuntimeError, "You can't run both Rochester and MuScleFit corrections!"
30  else:
31  self.cfg_ana.doMuScleFitCorrections = False
32  #FIXME: only Embedded works
33  self.electronEnergyCalibrator = EmbeddedElectronCalibrator()
34 # if hasattr(cfg_comp,'efficiency'):
35 # self.efficiency= EfficiencyCorrector(cfg_comp.efficiency)
36  #----------------------------------------
37  # DECLARATION OF HANDLES OF LEPTONS STUFF
38  #----------------------------------------
39 
40 
41  def declareHandles(self):
42  super(LeptonAnalyzer, self).declareHandles()
43 
44  #leptons
45  self.handles['muons'] = AutoHandle(self.cfg_ana.muons,"std::vector<pat::Muon>")
46  self.handles['electrons'] = AutoHandle(self.cfg_ana.electrons,"std::vector<pat::Electron>")
47 
48  #rho for muons
49  self.handles['rhoMu'] = AutoHandle( self.cfg_ana.rhoMuon, 'double')
50  #rho for electrons
51  self.handles['rhoEle'] = AutoHandle( self.cfg_ana.rhoElectron, 'double')
52 
53  def beginLoop(self):
54  super(LeptonAnalyzer,self).beginLoop()
55  self.counters.addCounter('events')
56  count = self.counters.counter('events')
57  count.register('all events')
58 
59  #------------------
60  # MAKE LEPTON LISTS
61  #------------------
62 
63 
64  def makeLeptons(self, event):
65  ### inclusive leptons = all leptons that could be considered somewhere in the analysis, with minimal requirements (used e.g. to match to MC)
66  event.inclusiveLeptons = []
67  ### selected leptons = subset of inclusive leptons passing some basic id definition and pt requirement
68  ### other leptons = subset of inclusive leptons failing some basic id definition and pt requirement
69  event.selectedLeptons = []
70  event.selectedMuons = []
71  event.selectedElectrons = []
72  event.otherLeptons = []
73 
74  #muons
75  allmuons = self.makeAllMuons(event)
76 
77  for mu in allmuons:
78  # inclusive, very loose, selection
79  if (mu.track().isNonnull() and mu.muonID(self.cfg_ana.inclusive_muon_id) and
80  mu.pt()>self.cfg_ana.inclusive_muon_pt and abs(mu.eta())<self.cfg_ana.inclusive_muon_eta and
81  abs(mu.dxy())<self.cfg_ana.inclusive_muon_dxy and abs(mu.dz())<self.cfg_ana.inclusive_muon_dz):
82  event.inclusiveLeptons.append(mu)
83  # basic selection
84  if (mu.muonID(self.cfg_ana.loose_muon_id) and
85  mu.pt() > self.cfg_ana.loose_muon_pt and abs(mu.eta()) < self.cfg_ana.loose_muon_eta and
86  abs(mu.dxy()) < self.cfg_ana.loose_muon_dxy and abs(mu.dz()) < self.cfg_ana.loose_muon_dz and
87  mu.relIso03 < self.cfg_ana.loose_muon_relIso and
88  mu.absIso03 < (self.cfg_ana.loose_muon_absIso if hasattr(self.cfg_ana,'loose_muon_absIso') else 9e99)):
89  mu.looseIdSusy = True
90  event.selectedLeptons.append(mu)
91  event.selectedMuons.append(mu)
92  else:
93  mu.looseIdSusy = False
94  event.otherLeptons.append(mu)
95 
96  #electrons
97  allelectrons = self.makeAllElectrons(event)
98 
99  looseMuons = event.selectedLeptons[:]
100  for ele in allelectrons:
101  ## remove muons if muForEleCrossCleaning is not empty
102  ## apply selection
103  if ( ele.electronID(self.cfg_ana.inclusive_electron_id) and
104  ele.pt()>self.cfg_ana.inclusive_electron_pt and abs(ele.eta())<self.cfg_ana.inclusive_electron_eta and
105  abs(ele.dxy())<self.cfg_ana.inclusive_electron_dxy and abs(ele.dz())<self.cfg_ana.inclusive_electron_dz and
106  ele.lostInner()<=self.cfg_ana.inclusive_electron_lostHits ):
107  event.inclusiveLeptons.append(ele)
108  # basic selection
109  if (ele.electronID(self.cfg_ana.loose_electron_id) and
110  ele.pt()>self.cfg_ana.loose_electron_pt and abs(ele.eta())<self.cfg_ana.loose_electron_eta and
111  abs(ele.dxy()) < self.cfg_ana.loose_electron_dxy and abs(ele.dz())<self.cfg_ana.loose_electron_dz and
112  ele.relIso03 <= self.cfg_ana.loose_electron_relIso and
113  ele.absIso03 < (self.cfg_ana.loose_electron_absIso if hasattr(self.cfg_ana,'loose_electron_absIso') else 9e99) and
114  ele.lostInner() <= self.cfg_ana.loose_electron_lostHits and
115  ( True if (hasattr(self.cfg_ana,'notCleaningElectrons') and self.cfg_ana.notCleaningElectrons) else (bestMatch(ele, looseMuons)[1] > self.cfg_ana.min_dr_electron_muon) )):
116  event.selectedLeptons.append(ele)
117  event.selectedElectrons.append(ele)
118  ele.looseIdSusy = True
119  else:
120  event.otherLeptons.append(ele)
121  ele.looseIdSusy = False
122 
123  event.otherLeptons.sort(key = lambda l : l.pt(), reverse = True)
124  event.selectedLeptons.sort(key = lambda l : l.pt(), reverse = True)
125  event.selectedMuons.sort(key = lambda l : l.pt(), reverse = True)
126  event.selectedElectrons.sort(key = lambda l : l.pt(), reverse = True)
127  event.inclusiveLeptons.sort(key = lambda l : l.pt(), reverse = True)
128 
129  for lepton in event.selectedLeptons:
130  if hasattr(self,'efficiency'):
131  self.efficiency.attachToObject(lepton)
132 
133  def makeAllMuons(self, event):
134  """
135  make a list of all muons, and apply basic corrections to them
136  """
137  # Start from all muons
138  allmuons = map( Muon, self.handles['muons'].product() )
139 
140  # Muon scale and resolution corrections (if enabled)
141  if self.cfg_ana.doMuScleFitCorrections:
142  for mu in allmuons:
143  self.muscleCorr.correct(mu, event.run)
144  elif self.cfg_ana.doRochesterCorrections:
145  for mu in allmuons:
146  corp4 = rochcor.corrected_p4(mu, event.run)
147  mu.setP4( corp4 )
148 
149  # Clean up dulicate muons (note: has no effect unless the muon id is removed)
150  if self.cfg_ana.doSegmentBasedMuonCleaning:
151  isgood = cmgMuonCleanerBySegments.clean( self.handles['muons'].product() )
152  newmu = []
153  for i,mu in enumerate(allmuons):
154  if isgood[i]: newmu.append(mu)
155  allmuons = newmu
156 
157  # Attach the vertex to them, for dxy/dz calculation
158  for mu in allmuons:
159  mu.associatedVertex = event.goodVertices[0]
160 
161  # Compute relIso in 0.3 and 0.4 cones
162  for mu in allmuons:
163  mu.absIso03 = (mu.pfIsolationR03().sumChargedHadronPt + max( mu.pfIsolationR03().sumNeutralHadronEt + mu.pfIsolationR03().sumPhotonEt - mu.pfIsolationR03().sumPUPt/2,0.0))
164  mu.absIso04 = (mu.pfIsolationR04().sumChargedHadronPt + max( mu.pfIsolationR04().sumNeutralHadronEt + mu.pfIsolationR04().sumPhotonEt - mu.pfIsolationR04().sumPUPt/2,0.0))
165  mu.relIso03 = mu.absIso03/mu.pt()
166  mu.relIso04 = mu.absIso04/mu.pt()
167 
168  return allmuons
169 
170  def makeAllElectrons(self, event):
171  """
172  make a list of all electrons, and apply basic corrections to them
173  """
174  allelectrons = map( Electron, self.handles['electrons'].product() )
175 
176  ## Duplicate removal for fast sim (to be checked if still necessary in latest greatest 5.3.X releases)
177  allelenodup = []
178  for e in allelectrons:
179  dup = False
180  for e2 in allelenodup:
181  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():
182  dup = True
183  break
184  if not dup: allelenodup.append(e)
185  allelectrons = allelenodup
186 
187  # fill EA for rho-corrected isolation
188  for ele in allelectrons:
189  ele.rho = float(self.handles['rhoEle'].product()[0])
190  SCEta = abs(ele.superCluster().eta())
191  if (abs(SCEta) >= 0.0 and abs(SCEta) < 1.0 ) : ele.EffectiveArea = 0.13 # 0.130;
192  if (abs(SCEta) >= 1.0 and abs(SCEta) < 1.479 ) : ele.EffectiveArea = 0.14 # 0.137;
193  if (abs(SCEta) >= 1.479 and abs(SCEta) < 2.0 ) : ele.EffectiveArea = 0.07 # 0.067;
194  if (abs(SCEta) >= 2.0 and abs(SCEta) < 2.2 ) : ele.EffectiveArea = 0.09 # 0.089;
195  if (abs(SCEta) >= 2.2 and abs(SCEta) < 2.3 ) : ele.EffectiveArea = 0.11 # 0.107;
196  if (abs(SCEta) >= 2.3 and abs(SCEta) < 2.4 ) : ele.EffectiveArea = 0.11 # 0.110;
197  if (abs(SCEta) >= 2.4) : ele.EffectiveArea = 0.14 # 0.138;
198 
199  # Electron scale calibrations
200  if self.cfg_ana.doElectronScaleCorrections:
201  for ele in allelectrons:
202  self.electronEnergyCalibrator.correct(ele, event.run)
203 
204  # Attach the vertex
205  for ele in allelectrons:
206  ele.associatedVertex = event.goodVertices[0]
207 
208  # Compute relIso with R=0.3 and R=0.4 cones
209  for ele in allelectrons:
210  if self.cfg_ana.ele_isoCorr=="rhoArea" :
211  ele.absIso03 = (ele.chargedHadronIso(0.3) + max(ele.neutralHadronIso(0.3)+ele.photonIso(0.3)-ele.rho*ele.EffectiveArea,0))
212  ele.absIso04 = (ele.chargedHadronIso(0.4) + max(ele.neutralHadronIso(0.4)+ele.photonIso(0.4)-ele.rho*ele.EffectiveArea,0))
213  elif self.cfg_ana.ele_isoCorr=="deltaBeta" :
214  ele.absIso03 = (ele.pfIsolationVariables().sumChargedHadronPt + max( ele.pfIsolationVariables().sumNeutralHadronEt + ele.pfIsolationVariables().sumPhotonEt - ele.pfIsolationVariables().sumPUPt/2,0.0))
215  ele.absIso04 = 0.
216  else :
217  raise RuntimeError, "Unsupported ele_isoCorr name '" + str(self.cfg_ana.ele_isoCorr) + "'! For now only 'rhoArea' and 'deltaBeta' are supported."
218  ele.relIso03 = ele.absIso03/ele.pt()
219  ele.relIso04 = ele.absIso04/ele.pt()
220 
221  # Set tight MVA id
222  for ele in allelectrons:
223  if self.cfg_ana.ele_tightId=="MVA" :
224  ele.tightIdResult = ele.electronID("POG_MVA_ID_Trig_full5x5")
225  elif self.cfg_ana.ele_tightId=="Cuts_2012" :
226  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")
227  else :
228  raise RuntimeError, "Unsupported ele_tightId name '" + str(self.cfg_ana.ele_tightId) + "'! For now only 'MVA' and 'Cuts_2012' are supported."
229 
230 
231  return allelectrons
232 
233  def process(self, event):
234  self.readCollections( event.input )
235  self.counters.counter('events').inc('all events')
236 
237  #call the leptons functions
238  self.makeLeptons(event)
239 
240  return True
241 
242 #A default config
243 setattr(LeptonAnalyzer,"defaultConfig",cfg.Analyzer(
244  verbose=False,
245  class_object=LeptonAnalyzer,
246  # input collections
247  muons='slimmedMuons',
248  electrons='slimmedElectrons',
249  rhoMuon= 'fixedGridRhoFastjetAll',
250  rhoElectron = 'fixedGridRhoFastjetAll',
251 ## photons='slimmedPhotons',
252  # energy scale corrections and ghost muon suppression (off by default)
253  doMuScleFitCorrections=False, # "rereco"
254  doRochesterCorrections=False,
255  doElectronScaleCorrections=False, # "embedded" in 5.18 for regression
256  doSegmentBasedMuonCleaning=False,
257  # inclusive very loose muon selection
258  inclusive_muon_id = "POG_ID_Loose",
259  inclusive_muon_pt = 3,
260  inclusive_muon_eta = 2.4,
261  inclusive_muon_dxy = 0.5,
262  inclusive_muon_dz = 1.0,
263  # loose muon selection
264  loose_muon_id = "POG_ID_Loose",
265  loose_muon_pt = 5,
266  loose_muon_eta = 2.4,
267  loose_muon_dxy = 0.05,
268  loose_muon_dz = 0.2,
269  loose_muon_relIso = 0.4,
270  # inclusive very loose electron selection
271  inclusive_electron_id = "",
272  inclusive_electron_pt = 5,
273  inclusive_electron_eta = 2.5,
274  inclusive_electron_dxy = 0.5,
275  inclusive_electron_dz = 1.0,
276  inclusive_electron_lostHits = 1.0,
277  # loose electron selection
278  loose_electron_id = "", #POG_MVA_ID_NonTrig_full5x5",
279  loose_electron_pt = 7,
280  loose_electron_eta = 2.4,
281  loose_electron_dxy = 0.05,
282  loose_electron_dz = 0.2,
283  loose_electron_relIso = 0.4,
284  loose_electron_lostHits = 1.0,
285  # electron isolation correction method (can be "rhoArea" or "deltaBeta")
286  ele_isoCorr = "rhoArea" ,
287  ele_tightId = "MVA" ,
288  # minimum deltaR between a loose electron and a loose muon (on overlaps, discard the electron)
289  min_dr_electron_muon = 0.02
290  )
291 )
def bestMatch
Definition: deltar.py:85
T eta() const
Abs< T >::type abs(const T &t)
Definition: Abs.h:22