CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
JetAnalyzer.py
Go to the documentation of this file.
1 import math
2 from PhysicsTools.Heppy.analyzers.core.Analyzer import Analyzer
3 from PhysicsTools.Heppy.analyzers.core.AutoHandle import AutoHandle
4 from PhysicsTools.Heppy.physicsobjects.PhysicsObjects import Jet
5 from PhysicsTools.HeppyCore.utils.deltar import deltaR2, deltaPhi, matchObjectCollection, matchObjectCollection2, bestMatch
6 from PhysicsTools.Heppy.physicsutils.JetReCalibrator import JetReCalibrator
8 
9 from PhysicsTools.Heppy.physicsutils.QGLikelihoodCalculator import QGLikelihoodCalculator
10 
11 def cleanNearestJetOnly(jets,leptons,deltaR):
12  dr2 = deltaR**2
13  good = [ True for j in jets ]
14  for l in leptons:
15  ibest, d2m = -1, dr2
16  for i,j in enumerate(jets):
17  d2i = deltaR2(l.eta(),l.phi(), j.eta(),j.phi())
18  if d2i < d2m:
19  ibest, d2m = i, d2i
20  if ibest != -1: good[ibest] = False
21  return [ j for (i,j) in enumerate(jets) if good[i] == True ]
22 
23 def cleanJetsAndLeptons(jets,leptons,deltaR,arbitration):
24  dr2 = deltaR**2
25  goodjet = [ True for j in jets ]
26  goodlep = [ True for l in leptons ]
27  for il, l in enumerate(leptons):
28  ibest, d2m = -1, dr2
29  for i,j in enumerate(jets):
30  d2i = deltaR2(l.eta(),l.phi(), j.eta(),j.phi())
31  if d2i < dr2:
32  if arbitration(j,l) == j:
33  # if the two match, and we prefer the jet, then drop the lepton and be done
34  goodlep[il] = False
35  break
36  if d2i < d2m:
37  ibest, d2m = i, d2i
38  # this lepton has been killed by a jet, then we clean the jet that best matches it
39  if not goodlep[il]: continue
40  if ibest != -1: goodjet[ibest] = False
41  return ( [ j for (i ,j) in enumerate(jets) if goodjet[i ] == True ],
42  [ l for (il,l) in enumerate(leptons) if goodlep[il] == True ] )
43 
44 
45 class JetAnalyzer( Analyzer ):
46  """Taken from RootTools.JetAnalyzer, simplified, modified, added corrections """
47  def __init__(self, cfg_ana, cfg_comp, looperName):
48  super(JetAnalyzer,self).__init__(cfg_ana, cfg_comp, looperName)
49  mcGT = cfg_ana.mcGT if hasattr(cfg_ana,'mcGT') else "PHYS14_25_V2"
50  dataGT = cfg_ana.dataGT if hasattr(cfg_ana,'dataGT') else "GR_70_V2_AN1"
51  self.shiftJEC = self.cfg_ana.shiftJEC if hasattr(self.cfg_ana, 'shiftJEC') else 0
52  self.recalibrateJets = self.cfg_ana.recalibrateJets
53  if self.recalibrateJets == "MC" : self.recalibrateJets = self.cfg_comp.isMC
54  elif self.recalibrateJets == "Data": self.recalibrateJets = not self.cfg_comp.isMC
55  elif self.recalibrateJets not in [True,False]: raise RuntimeError, "recalibrateJets must be any of { True, False, 'MC', 'Data' }, while it is %r " % self.recalibrateJets
56  self.doJEC = self.recalibrateJets or (self.shiftJEC != 0)
57  if self.doJEC:
58  if self.cfg_comp.isMC:
59  self.jetReCalibrator = JetReCalibrator(mcGT,"AK4PFchs", False,cfg_ana.jecPath)
60  else:
61  self.jetReCalibrator = JetReCalibrator(dataGT,"AK4PFchs", True,cfg_ana.jecPath)
62  self.doPuId = getattr(self.cfg_ana, 'doPuId', True)
63  self.jetLepDR = getattr(self.cfg_ana, 'jetLepDR', 0.4)
64  self.jetLepArbitration = getattr(self.cfg_ana, 'jetLepArbitration', lambda jet,lepton: lepton)
65  self.lepPtMin = getattr(self.cfg_ana, 'minLepPt', -1)
66  self.jetGammaDR = getattr(self.cfg_ana, 'jetGammaDR', 0.4)
67  if(self.cfg_ana.doQG):
68  self.qglcalc = QGLikelihoodCalculator("/afs/cern.ch/user/t/tomc/public/qgTagger/QGLikelihoodDBFiles/QGL_v1a/pdfQG_AK4chs_antib_13TeV_v1.root")
69 
70  def declareHandles(self):
71  super(JetAnalyzer, self).declareHandles()
72  self.handles['jets'] = AutoHandle( self.cfg_ana.jetCol, 'std::vector<pat::Jet>' )
73  self.handles['genJet'] = AutoHandle( 'slimmedGenJets', 'vector<reco::GenJet>' )
74  self.shiftJER = self.cfg_ana.shiftJER if hasattr(self.cfg_ana, 'shiftJER') else 0
75  self.handles['rho'] = AutoHandle( ('fixedGridRhoFastjetAll','',''), 'double' )
76 
77  def beginLoop(self, setup):
78  super(JetAnalyzer,self).beginLoop(setup)
79 
80  def process(self, event):
81  self.readCollections( event.input )
82  rho = float(self.handles['rho'].product()[0])
83  event.rho = rho
84 
85  ## Read jets, if necessary recalibrate and shift MET
86  allJets = map(Jet, self.handles['jets'].product())
87 
88  event.deltaMetFromJEC = [0.,0.]
89  if self.doJEC:
90  #print "\nCalibrating jets %s for lumi %d, event %d" % (self.cfg_ana.jetCol, event.lumi, event.eventId)
91  self.jetReCalibrator.correctAll(allJets, rho, delta=self.shiftJEC, metShift=event.deltaMetFromJEC)
92  event.allJetsUsedForMET = allJets
93 
94  if self.cfg_comp.isMC:
95  event.genJets = [ x for x in self.handles['genJet'].product() ]
96  self.matchJets(event, allJets)
97  if getattr(self.cfg_ana, 'smearJets', False):
98  self.smearJets(event, allJets)
99 
100  ##Sort Jets by pT
101  allJets.sort(key = lambda j : j.pt(), reverse = True)
102 
103  ## Apply jet selection
104  event.jets = []
105  event.jetsFailId = []
106  event.jetsAllNoID = []
107  event.jetsIdOnly = []
108  for jet in allJets:
109  if self.testJetNoID( jet ):
110  event.jetsAllNoID.append(jet)
111  if self.testJetID (jet ):
112 
113  if(self.cfg_ana.doQG):
114  self.computeQGvars(jet)
115  jet.qgl = self.qglcalc.computeQGLikelihood(jet, rho)
116 
117 
118  event.jets.append(jet)
119  event.jetsIdOnly.append(jet)
120  else:
121  event.jetsFailId.append(jet)
122  elif self.testJetID (jet ):
123  event.jetsIdOnly.append(jet)
124 
125  ## Clean Jets from leptons
126  leptons = []
127  if hasattr(event, 'selectedLeptons'):
128  leptons = [ l for l in event.selectedLeptons if l.pt() > self.lepPtMin ]
129  if self.cfg_ana.cleanJetsFromTaus and hasattr(event, 'selectedTaus'):
130  leptons = leptons[:] + event.selectedTaus
131  if self.cfg_ana.cleanJetsFromIsoTracks and hasattr(event, 'selectedIsoCleanTrack'):
132  leptons = leptons[:] + event.selectedIsoCleanTrack
133  event.cleanJetsAll, cleanLeptons = cleanJetsAndLeptons(event.jets, leptons, self.jetLepDR, self.jetLepArbitration)
134  event.cleanJets = [j for j in event.cleanJetsAll if abs(j.eta()) < self.cfg_ana.jetEtaCentral ]
135  event.cleanJetsFwd = [j for j in event.cleanJetsAll if abs(j.eta()) >= self.cfg_ana.jetEtaCentral ]
136  event.discardedJets = [j for j in event.jets if j not in event.cleanJetsAll]
137  if hasattr(event, 'selectedLeptons'):
138  event.discardedLeptons = [ l for l in leptons if l not in cleanLeptons ]
139  event.selectedLeptons = [ l for l in event.selectedLeptons if l not in event.discardedLeptons ]
140 
141  ## Clean Jets from photons
142  photons = []
143  if hasattr(event, 'selectedPhotons'):
144  if self.cfg_ana.cleanJetsFromFirstPhoton:
145  photons = event.selectedPhotons[:1]
146  else:
147  photons = [ g for g in event.selectedPhotons ]
148 
149  event.gamma_cleanJetsAll = cleanNearestJetOnly(event.cleanJetsAll, photons, self.jetGammaDR)
150  event.gamma_cleanJets = [j for j in event.gamma_cleanJetsAll if abs(j.eta()) < self.cfg_ana.jetEtaCentral ]
151  event.gamma_cleanJetsFwd = [j for j in event.gamma_cleanJetsAll if abs(j.eta()) >= self.cfg_ana.jetEtaCentral ]
152  ###
153 
154 
155  ## Associate jets to leptons
156  leptons = event.inclusiveLeptons if hasattr(event, 'inclusiveLeptons') else event.selectedLeptons
157  jlpairs = matchObjectCollection( leptons, allJets, self.jetLepDR**2)
158 
159  for jet in allJets:
160  jet.leptons = [l for l in jlpairs if jlpairs[l] == jet ]
161 
162  for lep in leptons:
163  jet = jlpairs[lep]
164  if jet is None:
165  lep.jet = lep
166  else:
167  lep.jet = jet
168  ## Associate jets to taus
169  taus = getattr(event,'selectedTaus',[])
170  jtaupairs = matchObjectCollection( taus, allJets, self.jetLepDR**2)
171 
172  for jet in allJets:
173  jet.taus = [l for l in jtaupairs if jtaupairs[l] == jet ]
174  for tau in taus:
175  tau.jet = jtaupairs[tau]
176 
177  #MC stuff
178  if self.cfg_comp.isMC:
179  event.deltaMetFromJetSmearing = [0, 0]
180  for j in event.cleanJetsAll:
181  if hasattr(j, 'deltaMetFromJetSmearing'):
182  event.deltaMetFromJetSmearing[0] += j.deltaMetFromJetSmearing[0]
183  event.deltaMetFromJetSmearing[1] += j.deltaMetFromJetSmearing[1]
184  event.cleanGenJets = cleanNearestJetOnly(event.genJets, leptons, self.jetLepDR)
185 
186  #event.nGenJets25 = 0
187  #event.nGenJets25Cen = 0
188  #event.nGenJets25Fwd = 0
189  #for j in event.cleanGenJets:
190  # event.nGenJets25 += 1
191  # if abs(j.eta()) <= 2.4: event.nGenJets25Cen += 1
192  # else: event.nGenJets25Fwd += 1
193 
194  self.jetFlavour(event)
195 
196 
197  return True
198 
199 
200 
201  def testJetID(self, jet):
202  jet.puJetIdPassed = jet.puJetId()
203  jet.pfJetIdPassed = jet.jetID('POG_PFID_Loose')
204  if self.cfg_ana.relaxJetId:
205  return True
206  else:
207  return jet.pfJetIdPassed and (jet.puJetIdPassed or not(self.doPuId))
208 
209  def testJetNoID( self, jet ):
210  # 2 is loose pile-up jet id
211  return jet.pt() > self.cfg_ana.jetPt and \
212  abs( jet.eta() ) < self.cfg_ana.jetEta;
213 
214  def computeQGvars(self, jet):
215 
216  jet.mult = 0
217  sum_weight = 0.
218  sum_pt = 0.
219  sum_deta = 0.
220  sum_dphi = 0.
221  sum_deta2 = 0.
222  sum_detadphi = 0.
223  sum_dphi2 = 0.
224 
225 
226 
227  for ii in range(0, jet.numberOfDaughters()) :
228 
229  part = jet.daughter(ii)
230 
231  if part.charge() == 0 : # neutral particles
232 
233  if part.pt() < 1.: continue
234 
235  else : # charged particles
236 
237  if part.trackHighPurity()==False: continue
238  if part.fromPV()<=1: continue
239 
240 
241  jet.mult += 1
242 
243  deta = part.eta() - jet.eta()
244  dphi = deltaPhi(part.phi(), jet.phi())
245  partPt = part.pt()
246  weight = partPt*partPt
247  sum_weight += weight
248  sum_pt += partPt
249  sum_deta += deta*weight
250  sum_dphi += dphi*weight
251  sum_deta2 += deta*deta*weight
252  sum_detadphi += deta*dphi*weight
253  sum_dphi2 += dphi*dphi*weight
254 
255 
256 
257 
258  a = 0.
259  b = 0.
260  c = 0.
261 
262  if sum_weight > 0 :
263  jet.ptd = math.sqrt(sum_weight)/sum_pt
264  ave_deta = sum_deta/sum_weight
265  ave_dphi = sum_dphi/sum_weight
266  ave_deta2 = sum_deta2/sum_weight
267  ave_dphi2 = sum_dphi2/sum_weight
268  a = ave_deta2 - ave_deta*ave_deta
269  b = ave_dphi2 - ave_dphi*ave_dphi
270  c = -(sum_detadphi/sum_weight - ave_deta*ave_dphi)
271  else: jet.ptd = 0.
272 
273  delta = math.sqrt(math.fabs((a-b)*(a-b)+4.*c*c))
274 
275  if a+b-delta > 0: jet.axis2 = -math.log(math.sqrt(0.5*(a+b-delta)))
276  else: jet.axis2 = -1.
277 
278 
279  def jetFlavour(self,event):
280  def isFlavour(x,f):
281  id = abs(x.pdgId())
282  if id > 999: return (id/1000)%10 == f
283  if id > 99: return (id/100)%10 == f
284  return id % 100 == f
285 
286 
287 
288  event.bqObjects = [ p for p in event.genParticles if (p.status() == 2 and isFlavour(p,5)) ]
289  event.cqObjects = [ p for p in event.genParticles if (p.status() == 2 and isFlavour(p,4)) ]
290 
291  event.partons = [ p for p in event.genParticles if ((p.status() == 23 or p.status() == 3) and abs(p.pdgId())>0 and (abs(p.pdgId()) in [1,2,3,4,5,21]) ) ]
292  match = matchObjectCollection2(event.cleanJetsAll,
293  event.partons,
294  deltaRMax = 0.3)
295 
296  for jet in event.cleanJetsAll:
297  parton = match[jet]
298  jet.partonId = (parton.pdgId() if parton != None else 0)
299  jet.partonMotherId = (parton.mother(0).pdgId() if parton != None and parton.numberOfMothers()>0 else 0)
300 
301  for jet in event.jets:
302  (bmatch, dr) = bestMatch(jet, event.bqObjects)
303  if dr < 0.4:
304  jet.mcFlavour = 5
305  else:
306  (cmatch, dr) = bestMatch(jet, event.cqObjects)
307  if dr < 0.4:
308  jet.mcFlavour = 4
309  else:
310  jet.mcFlavour = 0
311 
312  event.heaviestQCDFlavour = 5 if len(event.bqObjects) else (4 if len(event.cqObjects) else 1);
313 
314 
315  def matchJets(self, event, jets):
316  match = matchObjectCollection2(jets,
317  event.genbquarks + event.genwzquarks,
318  deltaRMax = 0.3)
319  for jet in jets:
320  gen = match[jet]
321  jet.mcParton = gen
322  jet.mcMatchId = (gen.sourceId if gen != None else 0)
323  jet.mcMatchFlav = (abs(gen.pdgId()) if gen != None else 0)
324 
325  match = matchObjectCollection2(jets,
326  event.genJets,
327  deltaRMax = 0.3)
328  for jet in jets:
329  jet.mcJet = match[jet]
330 
331 
332 
333  def smearJets(self, event, jets):
334  # https://twiki.cern.ch/twiki/bin/viewauth/CMS/TWikiTopRefSyst#Jet_energy_resolution
335  for jet in jets:
336  gen = jet.mcJet
337  if gen != None:
338  genpt, jetpt, aeta = gen.pt(), jet.pt(), abs(jet.eta())
339  # from https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution
340  factor = 1.052 + self.shiftJER*math.hypot(0.012,0.062);
341  if aeta > 2.3: factor = 1.288 + self.shiftJER*math.hypot(0.127,0.154)
342  elif aeta > 1.7: factor = 1.134 + self.shiftJER*math.hypot(0.035,0.066)
343  elif aeta > 1.1: factor = 1.096 + self.shiftJER*math.hypot(0.017,0.063)
344  elif aeta > 0.5: factor = 1.057 + self.shiftJER*math.hypot(0.012,0.056)
345  ptscale = max(0.0, (jetpt + (factor-1)*(jetpt-genpt))/jetpt)
346  #print "get with pt %.1f (gen pt %.1f, ptscale = %.3f)" % (jetpt,genpt,ptscale)
347  jet.deltaMetFromJetSmearing = [ -(ptscale-1)*jet.rawFactor()*jet.px(), -(ptscale-1)*jet.rawFactor()*jet.py() ]
348  if ptscale != 0:
349  jet.setP4(jet.p4()*ptscale)
350  # leave the uncorrected unchanged for sync
351  jet._rawFactorMultiplier *= (1.0/ptscale) if ptscale != 0 else 1
352  #else: print "jet with pt %.1d, eta %.2f is unmatched" % (jet.pt(), jet.eta())
353 
354 
355 
356 setattr(JetAnalyzer,"defaultConfig", cfg.Analyzer(
357  class_object = JetAnalyzer,
358  jetCol = 'slimmedJets',
359  jetPt = 25.,
360  jetEta = 4.7,
361  jetEtaCentral = 2.4,
362  jetLepDR = 0.4,
363  jetLepArbitration = (lambda jet,lepton : lepton), # you can decide which to keep in case of overlaps; e.g. if the jet is b-tagged you might want to keep the jet
364  minLepPt = 10,
365  relaxJetId = False,
366  doPuId = False, # Not commissioned in 7.0.X
367  doQG = False,
368  recalibrateJets = False,
369  shiftJEC = 0, # set to +1 or -1 to get +/-1 sigma shifts
370  smearJets = True,
371  shiftJER = 0, # set to +1 or -1 to get +/-1 sigma shifts
372  cleanJetsFromFirstPhoton = False,
373  cleanJetsFromTaus = False,
374  cleanJetsFromIsoTracks = False,
375  jecPath = ""
376  )
377 )
def bestMatch
Definition: deltar.py:136
def matchObjectCollection
Definition: deltar.py:149
def matchObjectCollection2
Definition: deltar.py:164
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double deltaR2(const T1 &t1, const T2 &t2)
Definition: deltaR.h:36
if(conf.exists("allCellsPositionCalc"))