File indexing completed on 2024-04-06 12:23:27
0001 from builtins import range
0002 from PhysicsTools.Heppy.physicsobjects.PhysicsObject import *
0003 from PhysicsTools.HeppyCore.utils.deltar import deltaPhi
0004 import math
0005
0006 loose_WP = [
0007 (0, 2.5, -0.8),
0008 (2.5, 2.75, -0.74),
0009 (2.75, 3.0, -0.68),
0010 (3.0, 5.0, -0.77),
0011 ]
0012
0013
0014 loose_53X_WP = [
0015 (0, 2.5, -0.63),
0016 (2.5, 2.75, -0.60),
0017 (2.75, 3.0, -0.55),
0018 (3.0, 5.2, -0.45),
0019 ]
0020
0021 _btagWPs = {
0022 "TCHEL": ("pfTrackCountingHighEffBJetTags", 1.7),
0023 "TCHEM": ("pfTrackCountingHighEffBJetTags", 3.3),
0024 "TCHPT": ("pfTrackCountingHighPurBJetTags", 3.41),
0025 "JPL": ("pfJetProbabilityBJetTags", 0.275),
0026 "JPM": ("pfJetProbabilityBJetTags", 0.545),
0027 "JPT": ("pfJetProbabilityBJetTags", 0.790),
0028 "CSVL": ("combinedSecondaryVertexBJetTags", 0.244),
0029 "CSVM": ("combinedSecondaryVertexBJetTags", 0.679),
0030 "CSVT": ("combinedSecondaryVertexBJetTags", 0.898),
0031
0032 "CMVAL": ("pfCombinedMVABJetTags", 0.630),
0033 "CMVAM": ("pfCombinedMVABJetTags", 0.732),
0034 "CMVAT": ("pfCombinedMVABJetTags", 0.813),
0035 "CMVAv2M": ("pfCombinedMVAV2BJetTags", 0.185),
0036
0037 "CSVv2IVFL": ("pfCombinedInclusiveSecondaryVertexV2BJetTags", 0.460),
0038 "CSVv2IVFM": ("pfCombinedInclusiveSecondaryVertexV2BJetTags", 0.800),
0039 "CSVv2IVFT": ("pfCombinedInclusiveSecondaryVertexV2BJetTags", 0.935),
0040 "CMVAv2L": ("pfCombinedMVAV2BJetTags", -0.715),
0041 "CMVAv2M": ("pfCombinedMVAV2BJetTags", 0.185),
0042 "CMVAv2T": ("pfCombinedMVAV2BJetTags", 0.875),
0043
0044 }
0045
0046 class Jet(PhysicsObject):
0047 def __init__(self, *args, **kwargs):
0048 super(Jet, self).__init__(*args, **kwargs)
0049 self._physObjInit()
0050
0051 def _physObjInit(self):
0052 self._rawFactorMultiplier = 1.0
0053 self._recalibrated = False
0054 self._leadingTrack = None
0055 self._leadingTrackSearched = False
0056
0057 def rawEnergy(self):
0058 return self.energy() * self.rawFactor()
0059
0060
0061
0062
0063 def chargedEmEnergyFraction(self):
0064 return self.chargedEmEnergy()/self.rawEnergy()
0065
0066 def chargedHadronEnergyFraction(self):
0067 return self.chargedHadronEnergy()/self.rawEnergy()
0068
0069 def chargedMuEnergyFraction(self):
0070 return self.chargedMuEnergy()/self.rawEnergy()
0071
0072 def electronEnergyFraction(self):
0073 return self.electronEnergy()/self.rawEnergy()
0074
0075 def muonEnergyFraction(self):
0076 return self.muonEnergy()/self.rawEnergy()
0077
0078 def neutralEmEnergyFraction(self):
0079 return self.neutralEmEnergy()/self.rawEnergy()
0080
0081 def neutralHadronEnergyFraction(self):
0082 return self.neutralHadronEnergy()/self.rawEnergy()
0083
0084 def photonEnergyFraction(self):
0085 return self.photonEnergy()/self.rawEnergy()
0086
0087
0088 def HFHadronEnergyFraction(self):
0089 return self.HFHadronEnergy()/self.rawEnergy()
0090
0091 def HFEMEnergyFraction(self):
0092 return self.HFEMEnergy()/self.rawEnergy()
0093
0094 def hoEnergyFraction(self):
0095 return self.hoEnergy()/self.rawEnergy()
0096
0097
0098
0099 def jetID(self,name=""):
0100 if not self.isPFJet():
0101 raise RuntimeError("jetID implemented only for PF Jets")
0102 eta = abs(self.eta());
0103 energy = self.rawEnergy();
0104 chf = self.chargedHadronEnergy()/energy;
0105 nhf = self.neutralHadronEnergy()/energy;
0106 phf = self.neutralEmEnergy()/energy;
0107 muf = self.muonEnergy()/energy;
0108 elf = self.chargedEmEnergy()/energy;
0109 chm = self.chargedHadronMultiplicity();
0110 npr = self.chargedMultiplicity() + self.neutralMultiplicity();
0111 npn = self.neutralMultiplicity();
0112
0113
0114 if name == "POG_PFID":
0115
0116 if self.jetID("PAG_monoID_Tight") and self.jetID("POG_PFID_Tight") : return 5;
0117 if self.jetID("PAG_monoID_Loose") and self.jetID("POG_PFID_Tight") : return 4;
0118 if self.jetID("POG_PFID_Tight") : return 3;
0119
0120 elif self.jetID("POG_PFID_Loose") : return 1;
0121 else : return 0;
0122
0123
0124 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)));
0125 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));
0126 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)));
0127 if name == "VBFHBB_PFID_Loose": return (npr>1 and phf<0.99 and nhf<0.99);
0128 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);
0129 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);
0130 if name == "PAG_monoID_Loose": return (eta<3.0 and chf>0.05 and nhf<0.7 and phf<0.8);
0131 if name == "PAG_monoID_Tight": return (eta<3.0 and chf>0.2 and nhf<0.7 and phf<0.7);
0132
0133 raise RuntimeError("jetID '%s' not supported" % name)
0134
0135 def looseJetId(self):
0136 '''PF Jet ID (loose operation point) [method provided for convenience only]'''
0137 return self.jetID("POG_PFID_Loose")
0138
0139 def puMva(self, label="pileupJetId:fullDiscriminant"):
0140 if self.hasUserFloat(label):
0141 return self.userFloat(label)
0142 return -99
0143
0144 def puJetId(self, label="pileupJetId:fullDiscriminant"):
0145 '''Full mva PU jet id'''
0146
0147 puMva = self.puMva(label)
0148 wp = loose_53X_WP
0149 eta = abs(self.eta())
0150
0151 for etamin, etamax, cut in wp:
0152 if not(eta>=etamin and eta<etamax):
0153 continue
0154 return puMva>cut
0155 return -99
0156
0157 def rawFactor(self):
0158 return self.jecFactor('Uncorrected') * self._rawFactorMultiplier
0159
0160 def setRawFactor(self, factor):
0161 self._rawFactorMultiplier = factor/self.jecFactor('Uncorrected')
0162
0163 def corrFactor(self):
0164 return 1.0/self.rawFactor()
0165
0166 def setCorrP4(self,newP4):
0167 self._recalibrated = True
0168 corr = newP4.Pt() / (self.pt() * self.rawFactor())
0169 self.setP4(newP4);
0170 self.setRawFactor(1.0/corr);
0171
0172 def l1corrFactor(self):
0173 if hasattr(self, 'CorrFactor_L1'):
0174 return self.CorrFactor_L1
0175 if self._recalibrated:
0176 raise RuntimeError("The jet was recalibrated, but without calculateSeparateCorrections. L1 is not available")
0177 jecLevels = self.physObj.availableJECLevels()
0178 for level in jecLevels:
0179 if "L1" in level:
0180 return self.physObj.jecFactor(level)/self.physObj.jecFactor('Uncorrected')
0181 return 1.0
0182
0183 def btag(self,name):
0184 ret = self.bDiscriminator(name)
0185 if ret == -1000 and name.startswith("pf"):
0186 ret = self.bDiscriminator(name[2].lower()+name[3:])
0187 return ret
0188
0189 def btagWP(self,name):
0190 global _btagWPs
0191 (disc,val) = _btagWPs[name]
0192 return self.btag(disc) > val
0193
0194 def leadingTrack(self):
0195 if self._leadingTrackSearched :
0196 return self._leadingTrack
0197 self._leadingTrackSearched = True
0198 self._leadingTrack = max( self.daughterPtrVector() , key = lambda x : x.pt() if x.charge()!=0 else 0. )
0199 if self._leadingTrack.charge()==0:
0200 self._leadingTrack = None
0201 return self._leadingTrack
0202
0203 def leadTrackPt(self):
0204 lt=self.leadingTrack()
0205 if lt :
0206 return lt.pt()
0207 else :
0208 return 0.
0209 def qgl(self) :
0210 if not hasattr(self,"qgl_value") :
0211 if hasattr(self,"qgl_rho") :
0212 self.computeQGvars()
0213 self.qgl_value=self.qgl_calc(self,self.qgl_rho)
0214 else :
0215 self.qgl_value=-1.
0216
0217 return self.qgl_value
0218
0219 def computeQGvars(self):
0220
0221 if not hasattr(self,"qgl_rho") or getattr(self,"hasQGVvars",False) :
0222 return self
0223 self.hasQGvars = True
0224
0225 jet = self
0226 jet.mult = 0
0227 sum_weight = 0.
0228 sum_pt = 0.
0229 sum_deta = 0.
0230 sum_dphi = 0.
0231 sum_deta2 = 0.
0232 sum_detadphi = 0.
0233 sum_dphi2 = 0.
0234
0235
0236
0237 for ii in range(0, jet.numberOfDaughters()) :
0238
0239 part = jet.daughter(ii)
0240
0241 if part.charge() == 0 :
0242
0243 if part.pt() < 1.: continue
0244
0245 else :
0246
0247 if part.trackHighPurity()==False: continue
0248 if part.fromPV()<=1: continue
0249
0250
0251 jet.mult += 1
0252
0253 deta = part.eta() - jet.eta()
0254 dphi = deltaPhi(part.phi(), jet.phi())
0255 partPt = part.pt()
0256 weight = partPt*partPt
0257 sum_weight += weight
0258 sum_pt += partPt
0259 sum_deta += deta*weight
0260 sum_dphi += dphi*weight
0261 sum_deta2 += deta*deta*weight
0262 sum_detadphi += deta*dphi*weight
0263 sum_dphi2 += dphi*dphi*weight
0264
0265
0266
0267
0268 a = 0.
0269 b = 0.
0270 c = 0.
0271
0272 if sum_weight > 0 :
0273 jet.ptd = math.sqrt(sum_weight)/sum_pt
0274 ave_deta = sum_deta/sum_weight
0275 ave_dphi = sum_dphi/sum_weight
0276 ave_deta2 = sum_deta2/sum_weight
0277 ave_dphi2 = sum_dphi2/sum_weight
0278 a = ave_deta2 - ave_deta*ave_deta
0279 b = ave_dphi2 - ave_dphi*ave_dphi
0280 c = -(sum_detadphi/sum_weight - ave_deta*ave_dphi)
0281 else: jet.ptd = 0.
0282
0283 delta = math.sqrt(math.fabs((a-b)*(a-b)+4.*c*c))
0284
0285 if a+b-delta > 0: jet.axis2 = -math.log(math.sqrt(0.5*(a+b-delta)))
0286 else: jet.axis2 = -1.
0287 return jet
0288
0289
0290
0291 class GenJet( PhysicsObject):
0292 pass
0293