CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
JetAnalyzer.py
Go to the documentation of this file.
1 import random
2 
3 from PhysicsTools.Heppy.analyzers.core.Analyzer import Analyzer
4 from PhysicsTools.Heppy.analyzers.core.AutoHandle import AutoHandle
5 from PhysicsTools.Heppy.physicsobjects.PhysicsObjects import Jet, GenJet
6 
7 from PhysicsTools.HeppyCore.utils.deltar import cleanObjectCollection, matchObjectCollection
8 from PhysicsTools.HeppyCore.statistics.counter import Counter, Counters
9 from PhysicsTools.HeppyCore.utils.deltar import deltaR2
10 
11 
12 from PhysicsTools.Heppy.physicsutils.BTagSF import BTagSF
13 from PhysicsTools.Heppy.physicsobjects.PhysicsObjects import GenParticle
14 from PhysicsTools.Heppy.utils.cmsswRelease import isNewerThan
15 
16 class JetAnalyzer( Analyzer ):
17  """Analyze jets ;-)
18 
19  This analyzer filters the jets that do not correspond to the leptons
20  stored in event.selectedLeptons, and puts in the event:
21  - jets: all jets passing the pt and eta cuts
22  - cleanJets: the collection of jets away from the leptons
23  - cleanBJets: the jets passing testBJet, and away from the leptons
24 
25  Example configuration:
26 
27  jetAna = cfg.Analyzer(
28  'JetAnalyzer',
29  jetCol = 'slimmedJets'
30  # cmg jet input collection
31  # pt threshold
32  jetPt = 30,
33  # eta range definition
34  jetEta = 5.0,
35  # seed for the btag scale factor
36  btagSFseed = 0xdeadbeef,
37  # if True, the PF and PU jet ID are not applied, and the jets get flagged
38  relaxJetId = False,
39  )
40  """
41 
42  def __init__(self, cfg_ana, cfg_comp, looperName):
43  super(JetAnalyzer,self).__init__(cfg_ana, cfg_comp, looperName)
44  self.btagSF = BTagSF (cfg_ana.btagSFseed)
45  self.is2012 = isNewerThan('CMSSW_5_2_0')
46 
47  def declareHandles(self):
48  super(JetAnalyzer, self).declareHandles()
49 
50  self.handles['jets'] = AutoHandle( self.cfg_ana.jetCol,
51  'std::vector<pat::Jet>' )
52  if self.cfg_comp.isMC:
53  # and ("BB" in self.cfg_comp.name):
54  self.mchandles['genParticles'] = AutoHandle( 'packedGenParticles',
55  'std::vector<pat::PackedGenParticle>' )
56  self.mchandles['genJets'] = AutoHandle('slimmedGenJets',
57  'std::vector<reco::GenJet>')
58 
59  def beginLoop(self, setup):
60  super(JetAnalyzer,self).beginLoop(setup)
61  self.counters.addCounter('jets')
62  count = self.counters.counter('jets')
63  count.register('all events')
64  count.register('at least 2 good jets')
65  count.register('at least 2 clean jets')
66  count.register('at least 1 b jet')
67  count.register('at least 2 b jets')
68 
69  def process(self, event):
70 
71  self.readCollections( event.input )
72  miniaodjets = self.handles['jets'].product()
73 
74  allJets = []
75  event.jets = []
76  event.bJets = []
77  event.cleanJets = []
78  event.cleanBJets = []
79 
80  leptons = []
81  if hasattr(event, 'selectedLeptons'):
82  leptons = event.selectedLeptons
83 
84  genJets = None
85  if self.cfg_comp.isMC:
86  genJets = map( GenJet, self.mchandles['genJets'].product() )
87 
88  for maodjet in miniaodjets:
89  jet = Jet( maodjet )
90  allJets.append( jet )
91  if self.cfg_comp.isMC and hasattr( self.cfg_comp, 'jetScale'):
92  scale = random.gauss( self.cfg_comp.jetScale,
93  self.cfg_comp.jetSmear )
94  jet.scaleEnergy( scale )
95  if genJets:
96  # Use DeltaR = 0.25 matching like JetMET
97  pairs = matchObjectCollection( [jet], genJets, 0.25*0.25)
98  if pairs[jet] is None:
99  pass
100  else:
101  jet.matchedGenJet = pairs[jet]
102  #Add JER correction for MC jets. Requires gen-jet matching.
103  if self.cfg_comp.isMC and hasattr(self.cfg_ana, 'jerCorr') and self.cfg_ana.jerCorr:
104  self.jerCorrection(jet)
105  #Add JES correction for MC jets.
106  if self.cfg_comp.isMC and hasattr(self.cfg_ana, 'jesCorr'):
107  self.jesCorrection(jet, self.cfg_ana.jesCorr)
108  if self.testJet( jet ):
109  event.jets.append(jet)
110  if self.testBJet(jet):
111  event.bJets.append(jet)
112 
113  self.counters.counter('jets').inc('all events')
114 
115  event.cleanJets, dummy = cleanObjectCollection( event.jets,
116  masks = leptons,
117  deltaRMin = 0.5 )
118  event.cleanBJets, dummy = cleanObjectCollection( event.bJets,
119  masks = leptons,
120  deltaRMin = 0.5 )
121 
122  pairs = matchObjectCollection( leptons, allJets, 0.5*0.5)
123  # associating a jet to each lepton
124  for lepton in leptons:
125  jet = pairs[lepton]
126  if jet is None:
127  lepton.jet = lepton
128  else:
129  lepton.jet = jet
130 
131  # associating a leg to each clean jet
132  invpairs = matchObjectCollection( event.cleanJets, leptons, 99999. )
133  for jet in event.cleanJets:
134  leg = invpairs[jet]
135  jet.leg = leg
136 
137  for jet in event.cleanJets:
138  jet.matchGenParton=999.0
139 
140  if self.cfg_comp.isMC and "BB" in self.cfg_comp.name:
141  genParticles = self.mchandles['genParticles'].product()
142  event.genParticles = map( GenParticle, genParticles)
143  for gen in genParticles:
144  if abs(gen.pdgId())==5 and gen.mother() and abs(gen.mother().pdgId())==21:
145  for jet in event.cleanJets:
146  dR=deltaR2(jet.eta(), jet.phi(), gen.eta(), gen.phi() )
147  if dR<jet.matchGenParton:
148  jet.matchGenParton=dR
149 
150  event.jets30 = [jet for jet in event.jets if jet.pt()>30]
151  event.cleanJets30 = [jet for jet in event.cleanJets if jet.pt()>30]
152  if len( event.jets30 )>=2:
153  self.counters.counter('jets').inc('at least 2 good jets')
154  if len( event.cleanJets30 )>=2:
155  self.counters.counter('jets').inc('at least 2 clean jets')
156  if len(event.cleanBJets)>0:
157  self.counters.counter('jets').inc('at least 1 b jet')
158  if len(event.cleanBJets)>1:
159  self.counters.counter('jets').inc('at least 2 b jets')
160  return True
161 
162  def jerCorrection(self, jet):
163  ''' Adds JER correction according to first method at
164  https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution
165 
166  Requires some attention when genJet matching fails.
167  '''
168  if not hasattr(jet, 'matchedGenJet'):
169  return
170  #import pdb; pdb.set_trace()
171  corrections = [0.052, 0.057, 0.096, 0.134, 0.288]
172  maxEtas = [0.5, 1.1, 1.7, 2.3, 5.0]
173  eta = abs(jet.eta())
174  for i, maxEta in enumerate(maxEtas):
175  if eta < maxEta:
176  pt = jet.pt()
177  deltaPt = (pt - jet.matchedGenJet.pt()) * corrections[i]
178  totalScale = (pt + deltaPt) / pt
179 
180  if totalScale < 0.:
181  totalScale = 0.
182  jet.scaleEnergy(totalScale)
183  break
184 
185  def jesCorrection(self, jet, scale=0.):
186  ''' Adds JES correction in number of sigmas (scale)
187  '''
188  # Do nothing if nothing to change
189  if scale == 0.:
190  return
191  unc = jet.uncOnFourVectorScale()
192  totalScale = 1. + scale * unc
193  if totalScale < 0.:
194  totalScale = 0.
195  jet.scaleEnergy(totalScale)
196 
197  def testJetID(self, jet):
198  jet.puJetIdPassed = jet.puJetId()
199  jet.pfJetIdPassed = jet.jetID("POG_PFID_Loose")
200  if self.cfg_ana.relaxJetId:
201  return True
202  else:
203  return jet.puJetIdPassed and jet.pfJetIdPassed
204 
205 
206  def testJet( self, jet ):
207  return jet.pt() > self.cfg_ana.jetPt and \
208  abs( jet.eta() ) < self.cfg_ana.jetEta and \
209  self.testJetID(jet)
210 
211  def testBJet(self, jet):
212  # medium csv working point
213  # https://twiki.cern.ch/twiki/bin/viewauth/CMS/BTagPerformanceOP#B_tagging_Operating_Points_for_3
214  jet.btagMVA = jet.btag("combinedSecondaryVertexBJetTags")
215  jet.btagFlag = self.btagSF.BTagSFcalc.isbtagged(
216  jet.pt(),
217  jet.eta(),
218  jet.btag("combinedSecondaryVertexBJetTags"),
219  abs(jet.partonFlavour()),
220  not self.cfg_comp.isMC,
221  0,0,
222  self.is2012
223  )
224  return jet.pt()>20 and \
225  abs( jet.eta() ) < 2.4 and \
226  self.testJetID(jet)
def cleanObjectCollection
Definition: deltar.py:118
def matchObjectCollection
Definition: deltar.py:151
Definition: Jet.py:1
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16