CMS 3D CMS Logo

METAnalyzer.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.PhysicsObjects import Jet
5 from PhysicsTools.HeppyCore.statistics.counter import Counter, Counters
6 from PhysicsTools.Heppy.physicsutils.JetReCalibrator import Type1METCorrector, setFakeRawMETOnOldMiniAODs
7 import PhysicsTools.HeppyCore.framework.config as cfg
8 
9 import copy
10 import ROOT
11 from math import hypot
12 
13 from copy import deepcopy
14 
15 class METAnalyzer( Analyzer ):
16  def __init__(self, cfg_ana, cfg_comp, looperName ):
17  super(METAnalyzer,self).__init__(cfg_ana,cfg_comp,looperName)
18  self.recalibrateMET = cfg_ana.recalibrate
19  self.applyJetSmearing = cfg_comp.isMC and cfg_ana.applyJetSmearing
20  self.old74XMiniAODs = cfg_ana.old74XMiniAODs
21  self.jetAnalyzerPostFix = getattr(cfg_ana, 'jetAnalyzerPostFix', '')
22  if self.recalibrateMET in [ "type1", True ]:
23  if self.recalibrateMET == "type1":
24  self.type1METCorrector = Type1METCorrector(self.old74XMiniAODs)
25  elif self.recalibrateMET != False:
26  raise RuntimeError("Unsupported value %r for option 'recalibrate': allowed are True, False, 'type1'" % self.recalibrateMET)
27 
28  def declareHandles(self):
29  super(METAnalyzer, self).declareHandles()
30  self.handles['met'] = AutoHandle( self.cfg_ana.metCollection, 'std::vector<pat::MET>' )
31  if self.cfg_ana.doMetNoPU:
32  self.handles['nopumet'] = AutoHandle( self.cfg_ana.noPUMetCollection, 'std::vector<pat::MET>' )
33  if self.cfg_ana.doTkMet:
34  self.handles['cmgCand'] = AutoHandle( self.cfg_ana.candidates, self.cfg_ana.candidatesTypes )
35  #self.handles['vertices'] = AutoHandle( "offlineSlimmedPrimaryVertices", 'std::vector<reco::Vertex>', fallbackLabel="offlinePrimaryVertices" )
36  self.mchandles['packedGen'] = AutoHandle( 'packedGenParticles', 'std::vector<pat::PackedGenParticle>' )
37 
38  def beginLoop(self, setup):
39  super(METAnalyzer,self).beginLoop(setup)
40  self.counters.addCounter('events')
41  count = self.counters.counter('events')
42  count.register('all events')
43 
44  def applyDeltaMet(self, met, deltaMet):
45  px,py = self.met.px()+deltaMet[0], self.met.py()+deltaMet[1]
46  met.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
47 
48  def adduParaPerp(self, met, boson, postfix):
49 
50  upara = 0
51  uperp = 0
52  uX = - met.px() - boson.px()
53  uY = - met.py() - boson.py()
54  u1 = (uX*boson.px() + uY*boson.py())/boson.pt()
55  u2 = (uX*boson.py() - uY*boson.px())/boson.pt()
56 
57  setattr(met, "upara"+postfix, u1)
58  setattr(met, "uperp"+postfix, u2)
59 
60  def makeTkMETs(self, event):
61  charged = []
62  chargedchs = []
63  chargedPVLoose = []
64  chargedPVTight = []
65  dochs=getattr(self.cfg_ana,"includeTkMetCHS",True)
66  dotight=getattr(self.cfg_ana,"includeTkMetPVTight",True)
67  doloose=getattr(self.cfg_ana,"includeTkMetPVLoose",True)
68  pfcands = self.handles['cmgCand'].product()
69 
70  for pfcand in pfcands:
71 
72 ## ===> require the Track Candidate charge and with a minimum dz
73  if (pfcand.charge()!=0):
74 
75  pvflag = pfcand.fromPV()
76  pxy = pfcand.px(), pfcand.py()
77 
78  if abs(pfcand.dz())<=self.cfg_ana.dzMax:
79  charged.append(pxy)
80 
81  if dochs and pvflag>0:
82  chargedchs.append(pxy)
83 
84  if doloose and pvflag>1:
85  chargedPVLoose.append(pxy)
86 
87  if dotight and pvflag>2:
88  chargedPVTight.append(pxy)
89 
90  def sumXY(pxys):
91  px, py = sum(x[0] for x in pxys), sum(x[1] for x in pxys)
92  return ROOT.reco.Particle.LorentzVector(-px, -py, 0, hypot(px,py))
93  setattr(event, "tkMet"+self.cfg_ana.collectionPostFix, sumXY(charged))
94  setattr(event, "tkMetPVchs"+self.cfg_ana.collectionPostFix, sumXY(chargedchs))
95  setattr(event, "tkMetPVLoose"+self.cfg_ana.collectionPostFix, sumXY(chargedPVLoose))
96  setattr(event, "tkMetPVTight"+self.cfg_ana.collectionPostFix, sumXY(chargedPVTight))
97  getattr(event,"tkMet"+self.cfg_ana.collectionPostFix).sumEt = sum([hypot(x[0],x[1]) for x in charged])
98  getattr(event,"tkMetPVchs"+self.cfg_ana.collectionPostFix).sumEt = sum([hypot(x[0],x[1]) for x in chargedchs])
99  getattr(event,"tkMetPVLoose"+self.cfg_ana.collectionPostFix).sumEt = sum([hypot(x[0],x[1]) for x in chargedPVLoose])
100  getattr(event,"tkMetPVTight"+self.cfg_ana.collectionPostFix).sumEt = sum([hypot(x[0],x[1]) for x in chargedPVTight])
101 
102  if hasattr(event,'zll_p4'):
103  self.adduParaPerp(getattr(event,"tkMet"+self.cfg_ana.collectionPostFix), event.zll_p4,"_zll")
104  self.adduParaPerp(getattr(event,"tkMetPVchs"+self.cfg_ana.collectionPostFix), event.zll_p4,"_zll")
105  self.adduParaPerp(getattr(event,"tkMetPVLoose"+self.cfg_ana.collectionPostFix), event.zll_p4,"_zll")
106  self.adduParaPerp(getattr(event,"tkMetPVTight"+self.cfg_ana.collectionPostFix), event.zll_p4,"_zll")
107 
108 
109  def makeGenTkMet(self, event):
110  genCharged = [ (x.px(),x.py()) for x in self.mchandles['packedGen'].product() if x.charge() != 0 and abs(x.eta()) < 2.4 ]
111  px, py = sum(x[0] for x in genCharged), sum(x[1] for x in genCharged)
112  setattr(event,"tkGenMet"+self.cfg_ana.collectionPostFix, ROOT.reco.Particle.LorentzVector(-px , -py, 0, hypot(px,py)))
113 
114  def makeMETNoMu(self, event):
115  self.metNoMu = copy.deepcopy(self.met)
116  if self.cfg_ana.doMetNoPU: self.metNoMuNoPU = copy.deepcopy(self.metNoPU)
117 
118  mupx = 0
119  mupy = 0
120  #sum muon momentum
121  for mu in event.selectedMuons:
122  mupx += mu.px()
123  mupy += mu.py()
124 
125  #subtract muon momentum and construct met
126  px,py = self.metNoMu.px()+mupx, self.metNoMu.py()+mupy
127  self.metNoMu.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
128  px,py = self.metNoMuNoPU.px()+mupx, self.metNoMuNoPU.py()+mupy
129  self.metNoMuNoPU.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
130  setattr(event, "metNoMu"+self.cfg_ana.collectionPostFix, self.metNoMu)
131  if self.cfg_ana.doMetNoPU: setattr(event, "metNoMuNoPU"+self.cfg_ana.collectionPostFix, self.metNoMuNoPU)
132 
133 
134  def makeMETNoEle(self, event):
135  self.metNoEle = copy.deepcopy(self.met)
136  if self.cfg_ana.doMetNoPU: self.metNoEleNoPU = copy.deepcopy(self.metNoPU)
137 
138  elepx = 0
139  elepy = 0
140  #sum electron momentum
141  for ele in event.selectedElectrons:
142  elepx += ele.px()
143  elepy += ele.py()
144 
145  #subtract electron momentum and construct met
146  px,py = self.metNoEle.px()+elepx, self.metNoEle.py()+elepy
147  self.metNoEle.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
148 
149  px,py = self.metNoEleNoPU.px()+elepx, self.metNoEleNoPU.py()+elepy
150  self.metNoEleNoPU.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
151  setattr(event, "metNoEle"+self.cfg_ana.collectionPostFix, self.metNoEle)
152  if self.cfg_ana.doMetNoPU: setattr(event, "metNoEleNoPU"+self.cfg_ana.collectionPostFix, self.metNoEleNoPU)
153 
154  def makeMETNoPhoton(self, event):
155  self.metNoPhoton = copy.deepcopy(self.met)
156 
157  phopx = 0
158  phopy = 0
159  #sum photon momentum
160  for pho in event.selectedPhotons:
161  phopx += pho.px()
162  phopy += pho.py()
163 
164  #subtract photon momentum and construct met
165  px,py = self.metNoPhoton.px()+phopx, self.metNoPhoton.py()+phopy
166  self.metNoPhoton.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
167  setattr(event, "metNoPhoton"+self.cfg_ana.collectionPostFix, self.metNoPhoton)
168  if self.cfg_ana.doMetNoPU:
169  self.metNoPhotonNoPU = copy.deepcopy(self.metNoPU)
170  px,py = self.metNoPhotonNoPU.px()+phopx, self.metNoPhotonNoPU.py()+phopy
171  self.metNoPhotonNoPU.setP4(ROOT.reco.Particle.LorentzVector(px,py, 0, hypot(px,py)))
172  setattr(event, "metNoPhotonNoPU"+self.cfg_ana.collectionPostFix, self.metNoPhotonNoPU)
173 
174 
175  def makeMETs(self, event):
176  import ROOT
177  if self.cfg_ana.copyMETsByValue:
178  self.met = ROOT.pat.MET(self.handles['met'].product()[0])
179  if self.cfg_ana.doMetNoPU: self.metNoPU = ROOT.pat.MET(self.handles['nopumet'].product()[0])
180  else:
181  self.met = self.handles['met'].product()[0]
182  if self.cfg_ana.doMetNoPU: self.metNoPU = self.handles['nopumet'].product()[0]
183 
184  if self.recalibrateMET == "type1":
185  type1METCorr = getattr(event, 'type1METCorr'+self.jetAnalyzerPostFix)
186  self.type1METCorrector.correct(self.met, type1METCorr)
187  elif self.recalibrateMET == True:
188  deltaMetJEC = getattr(event, 'deltaMetFromJEC'+self.jetAnalyzerPostFix)
189  self.applyDeltaMet(self.met, deltaMetJEC)
190  if self.applyJetSmearing:
191  deltaMetSmear = getattr(event, 'deltaMetFromJetSmearing'+self.jetAnalyzerPostFix)
192  self.applyDeltaMet(self.met, deltaMetSmear)
193 
194 
195  if (not self.cfg_ana.copyMETsByValue) and getattr(self.cfg_ana, 'makeShiftedMETs', True):
196  shifts = []
197  for obj in 'JetEn', 'JetRes', 'MuonEn', 'ElectronEn', 'PhotonEn', 'TauEn', 'UnclusteredEn':
198  for sh in 'Up', 'Down':
199  shifts.append( (obj+sh, getattr(self.met,obj+sh)) )
200  shifts.append( ('NoShift', self.met.NoShift) )
201  for name,i in shifts:
202  key = i
203  m = ROOT.pat.MET(self.met)
204  if self.old74XMiniAODs:
205  if key > 12: key = 12
206  elif key <= 3: key = { 'JetEnUp':0, 'JetEnDown':1, 'JetResUp':2, 'JetResDown':3 }[name]
207  m.setP4(self.met.shiftedP4(key))
208  setattr(event, "met{0}_shifted_{1}".format(self.cfg_ana.collectionPostFix, i),m)
209  setattr(event, "met{0}_shifted_{1}".format(self.cfg_ana.collectionPostFix, name),m)
210 
211  self.met_sig = self.met.significance()
212  self.met_sumet = self.met.sumEt()
213 
214  if self.old74XMiniAODs and self.recalibrateMET != "type1":
215  oldraw = self.met.shiftedP2_74x(12,0);
216  setFakeRawMETOnOldMiniAODs( self.met, oldraw.px, oldraw.py, self.met.shiftedSumEt_74x(12,0) )
217  px, py = oldraw.px, oldraw.py
218  else:
219  px, py = self.met.uncorPx(), self.met.uncorPy()
220  self.met_raw = ROOT.reco.Particle.LorentzVector(px,py,0,hypot(px,py))
221 
222  if hasattr(event,'zll_p4'):
223  self.adduParaPerp(self.met,event.zll_p4,"_zll")
224  self.adduParaPerp(self.met_raw, event.zll_p4,"_zll")
225  setattr(event,"met_raw"+self.cfg_ana.collectionPostFix, self.met_raw)
226  setattr(event,"met_raw.upara_zll"+self.cfg_ana.collectionPostFix, self.met_raw.upara_zll)
227  setattr(event,"met_raw.uperp_zll"+self.cfg_ana.collectionPostFix, self.met_raw.uperp_zll)
228 
229  if hasattr(event,'gamma_p4'):
230  self.adduParaPerp(self.met,event.gamma_p4,"_gamma")
231  self.adduParaPerp(self.met_raw, event.gamma_p4,"_gamma")
232  setattr(event,"met_raw"+self.cfg_ana.collectionPostFix, self.met_raw)
233  setattr(event,"met_raw.upara_gamma"+self.cfg_ana.collectionPostFix, self.met_raw.upara_gamma)
234  setattr(event,"met_raw.uperp_gamma"+self.cfg_ana.collectionPostFix, self.met_raw.uperp_gamma)
235 
236  if hasattr(event,"met"+self.cfg_ana.collectionPostFix): raise RuntimeError("Event already contains met with the following postfix: "+self.cfg_ana.collectionPostFix)
237  setattr(event, "met"+self.cfg_ana.collectionPostFix, self.met)
238  if self.cfg_ana.doMetNoPU: setattr(event, "metNoPU"+self.cfg_ana.collectionPostFix, self.metNoPU)
239  setattr(event, "met_sig"+self.cfg_ana.collectionPostFix, self.met_sig)
240  setattr(event, "met_sumet"+self.cfg_ana.collectionPostFix, self.met_sumet)
241 
242  genMET = self.met.genMET()
243  if genMET:
244  setattr(event, "met_genPt"+self.cfg_ana.collectionPostFix, genMET.pt())
245  setattr(event, "met_genPhi"+self.cfg_ana.collectionPostFix, genMET.phi())
246  else:
247  setattr(event, "met_genPt"+self.cfg_ana.collectionPostFix, float('nan'))
248  setattr(event, "met_genPhi"+self.cfg_ana.collectionPostFix, float('nan'))
249 
250  if self.cfg_ana.doMetNoMu and hasattr(event, 'selectedMuons'):
251  self.makeMETNoMu(event)
252 
253  if self.cfg_ana.doMetNoEle and hasattr(event, 'selectedElectrons'):
254  self.makeMETNoEle(event)
255 
256  if self.cfg_ana.doMetNoPhoton and hasattr(event, 'selectedPhotons'):
257  self.makeMETNoPhoton(event)
258 
259  def process(self, event):
260  self.readCollections( event.input)
261  self.counters.counter('events').inc('all events')
262 
263  self.makeMETs(event)
264 
265  if self.cfg_ana.doTkMet:
266  self.makeTkMETs(event);
267 
268  if getattr(self.cfg_ana,"doTkGenMet",self.cfg_ana.doTkMet) and self.cfg_comp.isMC and hasattr(event, 'genParticles'):
269  self.makeGenTkMet(event)
270 
271  return True
272 
273 
274 setattr(METAnalyzer,"defaultConfig", cfg.Analyzer(
275  class_object = METAnalyzer,
276  metCollection = "slimmedMETs",
277  noPUMetCollection = "slimmedMETs",
278  copyMETsByValue = False,
279  recalibrate = True,
280  applyJetSmearing = True,
281  jetAnalyzerPostFix = "",
282  old74XMiniAODs = False, # need to set to True to get proper Raw MET on plain 74X MC produced with CMSSW <= 7_4_12
283  makeShiftedMETs = True,
284  doTkMet = False,
285  includeTkMetCHS = True,
286  includeTkMetPVLoose = True,
287  includeTkMetPVTight = True,
288  doMetNoPU = False, # Not existing in MiniAOD at the moment
289  doMetNoMu = False,
290  doMetNoEle = False,
291  doMetNoPhoton = False,
292  candidates='packedPFCandidates',
293  candidatesTypes='std::vector<pat::PackedCandidate>',
294  dzMax = 0.1,
295  collectionPostFix = "",
296  )
297 )
def makeMETNoMu(self, event)
Definition: METAnalyzer.py:114
def makeGenTkMet(self, event)
Definition: METAnalyzer.py:109
def makeMETs(self, event)
Definition: METAnalyzer.py:175
def makeMETNoPhoton(self, event)
Definition: METAnalyzer.py:154
def makeMETNoEle(self, event)
Definition: METAnalyzer.py:134
def adduParaPerp(self, met, boson, postfix)
Definition: METAnalyzer.py:48
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
def applyDeltaMet(self, met, deltaMet)
Definition: METAnalyzer.py:44
def setFakeRawMETOnOldMiniAODs(met, rawpx, rawpy, rawsumet)
def process(self, event)
Definition: METAnalyzer.py:259
def __init__(self, cfg_ana, cfg_comp, looperName)
Definition: METAnalyzer.py:16