CMS 3D CMS Logo

Jet.py
Go to the documentation of this file.
2 from PhysicsTools.HeppyCore.utils.deltar import deltaPhi
3 import math
4 
5 loose_WP = [
6  (0, 2.5, -0.8),
7  (2.5, 2.75, -0.74),
8  (2.75, 3.0, -0.68),
9  (3.0, 5.0, -0.77),
10  ]
11 
12 # Working point 2 May 2013 (Phil via H2tau list)
13 loose_53X_WP = [
14  (0, 2.5, -0.63),
15  (2.5, 2.75, -0.60),
16  (2.75, 3.0, -0.55),
17  (3.0, 5.2, -0.45),
18  ]
19 
20 _btagWPs = {
21  "TCHEL": ("pfTrackCountingHighEffBJetTags", 1.7),
22  "TCHEM": ("pfTrackCountingHighEffBJetTags", 3.3),
23  "TCHPT": ("pfTrackCountingHighPurBJetTags", 3.41),
24  "JPL": ("pfJetProbabilityBJetTags", 0.275),
25  "JPM": ("pfJetProbabilityBJetTags", 0.545),
26  "JPT": ("pfJetProbabilityBJetTags", 0.790),
27  "CSVL": ("combinedSecondaryVertexBJetTags", 0.244),
28  "CSVM": ("combinedSecondaryVertexBJetTags", 0.679),
29  "CSVT": ("combinedSecondaryVertexBJetTags", 0.898),
30 ###https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation74X50ns
31  "CMVAL": ("pfCombinedMVABJetTags", 0.630), # for same b-jet efficiency of CSVv2IVFL on ttbar MC, jet pt > 30
32  "CMVAM": ("pfCombinedMVABJetTags", 0.732), # for same b-jet efficiency of CSVv2IVFM on ttbar MC, jet pt > 30
33  "CMVAT": ("pfCombinedMVABJetTags", 0.813), # for same b-jet efficiency of CSVv2IVFT on ttbar MC, jet pt > 30
34  "CMVAv2M": ("pfCombinedMVAV2BJetTags", 0.185), # for same b-jet efficiency of CSVv2IVFM on ttbar MC, jet pt > 30
35 ###https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation80X
36  "CSVv2IVFL": ("pfCombinedInclusiveSecondaryVertexV2BJetTags", 0.460),
37  "CSVv2IVFM": ("pfCombinedInclusiveSecondaryVertexV2BJetTags", 0.800),
38  "CSVv2IVFT": ("pfCombinedInclusiveSecondaryVertexV2BJetTags", 0.935),
39  "CMVAv2L": ("pfCombinedMVAV2BJetTags", -0.715), # for same b-jet efficiency of CSVv2IVFL on ttbar MC, jet pt > 30
40  "CMVAv2M": ("pfCombinedMVAV2BJetTags", 0.185), # for same b-jet efficiency of CSVv2IVFM on ttbar MC, jet pt > 30
41  "CMVAv2T": ("pfCombinedMVAV2BJetTags", 0.875), # for same b-jet efficiency of CSVv2IVFT on ttbar MC, jet pt > 30
42 
43 }
44 
46  def __init__(self, *args, **kwargs):
47  super(Jet, self).__init__(*args, **kwargs)
48  self._physObjInit()
49 
50  def _physObjInit(self):
52  self._recalibrated = False
53  self._leadingTrack = None
54  self._leadingTrackSearched = False
55 
56  def rawEnergy(self):
57  return self.energy() * self.rawFactor()
58 
59  # these energy fraction methods need to be redefined here
60  # because the pat::Jet's currentJECLevel data member cannot be update easily by the calibrator
61  # and then the C++ methods would be broken when new jet corrections are applied in Heppy
63  return self.chargedEmEnergy()/self.rawEnergy()
64 
66  return self.chargedHadronEnergy()/self.rawEnergy()
67 
69  return self.chargedMuEnergy()/self.rawEnergy()
70 
72  return self.electronEnergy()/self.rawEnergy()
73 
74  def muonEnergyFraction(self):
75  return self.muonEnergy()/self.rawEnergy()
76 
78  return self.neutralEmEnergy()/self.rawEnergy()
79 
81  return self.neutralHadronEnergy()/self.rawEnergy()
82 
84  return self.photonEnergy()/self.rawEnergy()
85 
86 
88  return self.HFHadronEnergy()/self.rawEnergy()
89 
90  def HFEMEnergyFraction(self):
91  return self.HFEMEnergy()/self.rawEnergy()
92 
93  def hoEnergyFraction(self):
94  return self.hoEnergy()/self.rawEnergy()
95 
96 
97 
98  def jetID(self,name=""):
99  if not self.isPFJet():
100  raise RuntimeError("jetID implemented only for PF Jets")
101  eta = abs(self.eta());
102  energy = self.rawEnergy();
103  chf = self.chargedHadronEnergy()/energy;
104  nhf = self.neutralHadronEnergy()/energy;
105  phf = self.neutralEmEnergy()/energy;
106  muf = self.muonEnergy()/energy;
107  elf = self.chargedEmEnergy()/energy;
108  chm = self.chargedHadronMultiplicity();
109  npr = self.chargedMultiplicity() + self.neutralMultiplicity();
110  npn = self.neutralMultiplicity();
111  #if npr != self.nConstituents():
112  # import pdb; pdb.set_trace()
113  if name == "POG_PFID":
114 
115  if self.jetID("PAG_monoID_Tight") and self.jetID("POG_PFID_Tight") : return 5;
116  if self.jetID("PAG_monoID_Loose") and self.jetID("POG_PFID_Tight") : return 4;
117  if self.jetID("POG_PFID_Tight") : return 3;
118  #elif self.jetID("POG_PFID_Medium") : return 2; commented this line because this working point doesn't exist anymore (as 12/05/15)
119  elif self.jetID("POG_PFID_Loose") : return 1;
120  else : return 0;
121 
122  # jetID from here: https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetID#Recommendations_for_13_TeV_data
123  if name == "POG_PFID_Loose": return ((eta<3.0 and ((npr>1 and phf<0.99 and nhf<0.99) and (eta>2.4 or (elf<0.99 and chf>0 and chm>0)))) or (eta>3.0 and (phf<0.90 and npn>10)));
124  if name == "POG_PFID_Medium": return (npr>1 and phf<0.95 and nhf<0.95 and muf < 0.8) and (eta>2.4 or (elf<0.99 and chf>0 and chm>0));
125  if name == "POG_PFID_Tight": return ((eta<3.0 and ((npr>1 and phf<0.90 and nhf<0.90) and (eta>2.4 or (elf<0.99 and chf>0 and chm>0)))) or (eta>3.0 and (phf<0.90 and npn>10)));
126  if name == "VBFHBB_PFID_Loose": return (npr>1 and phf<0.99 and nhf<0.99);
127  if name == "VBFHBB_PFID_Medium": return (npr>1 and phf<0.99 and nhf<0.99) and ((eta<=2.4 and nhf<0.9 and phf<0.9 and elf<0.99 and muf<0.99 and chf>0 and chm>0) or eta>2.4);
128  if name == "VBFHBB_PFID_Tight": return (npr>1 and phf<0.99 and nhf<0.99) and ((eta<=2.4 and nhf<0.9 and phf<0.9 and elf<0.70 and muf<0.70 and chf>0 and chm>0) or eta>2.4);
129  if name == "PAG_monoID_Loose": return (eta<3.0 and chf>0.05 and nhf<0.7 and phf<0.8);
130  if name == "PAG_monoID_Tight": return (eta<3.0 and chf>0.2 and nhf<0.7 and phf<0.7);
131 
132  raise RuntimeError("jetID '%s' not supported" % name)
133 
134  def looseJetId(self):
135  '''PF Jet ID (loose operation point) [method provided for convenience only]'''
136  return self.jetID("POG_PFID_Loose")
137 
138  def puMva(self, label="pileupJetId:fullDiscriminant"):
139  if self.hasUserFloat(label):
140  return self.userFloat(label)
141  return -99
142 
143  def puJetId(self, label="pileupJetId:fullDiscriminant"):
144  '''Full mva PU jet id'''
145 
146  puMva = self.puMva(label)
147  wp = loose_53X_WP
148  eta = abs(self.eta())
149 
150  for etamin, etamax, cut in wp:
151  if not(eta>=etamin and eta<etamax):
152  continue
153  return puMva>cut
154  return -99
155 
156  def rawFactor(self):
157  return self.jecFactor('Uncorrected') * self._rawFactorMultiplier
158 
159  def setRawFactor(self, factor):
160  self._rawFactorMultiplier = factor/self.jecFactor('Uncorrected')
161 
162  def corrFactor(self):
163  return 1.0/self.rawFactor()
164 
165  def setCorrP4(self,newP4):
166  self._recalibrated = True
167  corr = newP4.Pt() / (self.pt() * self.rawFactor())
168  self.setP4(newP4);
169  self.setRawFactor(1.0/corr);
170 
171  def l1corrFactor(self):
172  if hasattr(self, 'CorrFactor_L1'):
173  return self.CorrFactor_L1
174  if self._recalibrated:
175  raise RuntimeError("The jet was recalibrated, but without calculateSeparateCorrections. L1 is not available")
176  jecLevels = self.physObj.availableJECLevels()
177  for level in jecLevels:
178  if "L1" in level:
179  return self.physObj.jecFactor(level)/self.physObj.jecFactor('Uncorrected')
180  return 1.0 # Jet does not have any L1 correction
181 
182  def btag(self,name):
183  ret = self.bDiscriminator(name)
184  if ret == -1000 and name.startswith("pf"):
185  ret = self.bDiscriminator(name[2].lower()+name[3:])
186  return ret
187 
188  def btagWP(self,name):
189  global _btagWPs
190  (disc,val) = _btagWPs[name]
191  return self.btag(disc) > val
192 
193  def leadingTrack(self):
194  if self._leadingTrackSearched :
195  return self._leadingTrack
196  self._leadingTrackSearched = True
197  self._leadingTrack = max( self.daughterPtrVector() , key = lambda x : x.pt() if x.charge()!=0 else 0. )
198  if self._leadingTrack.charge()==0: #in case of "all neutral"
199  self._leadingTrack = None
200  return self._leadingTrack
201 
202  def leadTrackPt(self):
203  lt=self.leadingTrack()
204  if lt :
205  return lt.pt()
206  else :
207  return 0.
208  def qgl(self) :
209  if not hasattr(self,"qgl_value") :
210  if hasattr(self,"qgl_rho") : #check if qgl calculator is configured
211  self.computeQGvars()
212  self.qgl_value=self.qgl_calc(self,self.qgl_rho)
213  else :
214  self.qgl_value=-1. #if no qgl calculator configured
215 
216  return self.qgl_value
217 
218  def computeQGvars(self):
219  #return immediately if qgvars already computed or if qgl is disabled
220  if not hasattr(self,"qgl_rho") or getattr(self,"hasQGVvars",False) :
221  return self
222  self.hasQGvars = True
223 
224  jet = self
225  jet.mult = 0
226  sum_weight = 0.
227  sum_pt = 0.
228  sum_deta = 0.
229  sum_dphi = 0.
230  sum_deta2 = 0.
231  sum_detadphi = 0.
232  sum_dphi2 = 0.
233 
234 
235 
236  for ii in range(0, jet.numberOfDaughters()) :
237 
238  part = jet.daughter(ii)
239 
240  if part.charge() == 0 : # neutral particles
241 
242  if part.pt() < 1.: continue
243 
244  else : # charged particles
245 
246  if part.trackHighPurity()==False: continue
247  if part.fromPV()<=1: continue
248 
249 
250  jet.mult += 1
251 
252  deta = part.eta() - jet.eta()
253  dphi = deltaPhi(part.phi(), jet.phi())
254  partPt = part.pt()
255  weight = partPt*partPt
256  sum_weight += weight
257  sum_pt += partPt
258  sum_deta += deta*weight
259  sum_dphi += dphi*weight
260  sum_deta2 += deta*deta*weight
261  sum_detadphi += deta*dphi*weight
262  sum_dphi2 += dphi*dphi*weight
263 
264 
265 
266 
267  a = 0.
268  b = 0.
269  c = 0.
270 
271  if sum_weight > 0 :
272  jet.ptd = math.sqrt(sum_weight)/sum_pt
273  ave_deta = sum_deta/sum_weight
274  ave_dphi = sum_dphi/sum_weight
275  ave_deta2 = sum_deta2/sum_weight
276  ave_dphi2 = sum_dphi2/sum_weight
277  a = ave_deta2 - ave_deta*ave_deta
278  b = ave_dphi2 - ave_dphi*ave_dphi
279  c = -(sum_detadphi/sum_weight - ave_deta*ave_dphi)
280  else: jet.ptd = 0.
281 
282  delta = math.sqrt(math.fabs((a-b)*(a-b)+4.*c*c))
283 
284  if a+b-delta > 0: jet.axis2 = -math.log(math.sqrt(0.5*(a+b-delta)))
285  else: jet.axis2 = -1.
286  return jet
287 
288 
289 
291  pass
292 
def puJetId(self, label="pileupJetId:fullDiscriminant")
Definition: Jet.py:143
def electronEnergyFraction(self)
Definition: Jet.py:71
def _physObjInit(self)
Definition: Jet.py:50
def HFHadronEnergyFraction(self)
Definition: Jet.py:87
_leadingTrack
Definition: Jet.py:53
_recalibrated
Definition: Jet.py:52
_rawFactorMultiplier
Definition: Jet.py:51
def neutralEmEnergyFraction(self)
Definition: Jet.py:77
def __init__(self, args, kwargs)
Definition: Jet.py:46
qgl_value
Definition: Jet.py:212
def chargedEmEnergyFraction(self)
Definition: Jet.py:62
def jetID(self, name="")
Definition: Jet.py:98
def setCorrP4(self, newP4)
Definition: Jet.py:165
def chargedMuEnergyFraction(self)
Definition: Jet.py:68
def hoEnergyFraction(self)
Definition: Jet.py:93
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
def btag(self, name)
Definition: Jet.py:182
def rawFactor(self)
Definition: Jet.py:156
def btagWP(self, name)
Definition: Jet.py:188
def l1corrFactor(self)
Definition: Jet.py:171
def neutralHadronEnergyFraction(self)
Definition: Jet.py:80
def computeQGvars(self)
Definition: Jet.py:218
def leadTrackPt(self)
Definition: Jet.py:202
hasQGvars
Definition: Jet.py:222
def looseJetId(self)
Definition: Jet.py:134
def puMva(self, label="pileupJetId:fullDiscriminant")
Definition: Jet.py:138
def setRawFactor(self, factor)
Definition: Jet.py:159
_leadingTrackSearched
Definition: Jet.py:54
def leadingTrack(self)
Definition: Jet.py:193
def HFEMEnergyFraction(self)
Definition: Jet.py:90
def qgl(self)
Definition: Jet.py:208
def photonEnergyFraction(self)
Definition: Jet.py:83
https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation74X50ns
Definition: Jet.py:45
def rawEnergy(self)
Definition: Jet.py:56
def corrFactor(self)
Definition: Jet.py:162
def chargedHadronEnergyFraction(self)
Definition: Jet.py:65
def muonEnergyFraction(self)
Definition: Jet.py:74