CMS 3D CMS Logo

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