diff --git a/PhysicsTools/NanoAOD/python/custom_jme_cff.py b/PhysicsTools/NanoAOD/python/custom_jme_cff.py index 28aca19965ff3..fa6f47da2fa13 100644 --- a/PhysicsTools/NanoAOD/python/custom_jme_cff.py +++ b/PhysicsTools/NanoAOD/python/custom_jme_cff.py @@ -1298,9 +1298,11 @@ def RecomputePuppiWeightsMETAK8(proc): from RecoBTag.ONNXRuntime.pfParticleNet_cff import _pfParticleNetMassRegressionOutputs as pfParticleNetMassRegressionOutputs from RecoBTag.ONNXRuntime.pfParticleNet_cff import _pfParticleNetMassCorrelatedJetTagsAll as pfParticleNetMassCorrelatedJetTagsAll from RecoBTag.ONNXRuntime.pfParticleNetFromMiniAODAK8_cff import _pfParticleNetFromMiniAODAK8JetTagsAll as pfParticleNetFromMiniAODAK8JetTagsAll + from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import _pfGlobalParticleTransformerAK8JetTagsAll as pfGlobalParticleTransformerAK8JetTagsAll btagDiscriminatorsAK8 = cms.PSet(names = cms.vstring( pfParticleNetMassCorrelatedJetTagsAll+ + pfGlobalParticleTransformerAK8JetTagsAll+ pfParticleNetFromMiniAODAK8JetTagsAll+ pfParticleNetJetTagsAll+ pfParticleNetMassRegressionOutputs diff --git a/PhysicsTools/NanoAOD/python/jetsAK8_cff.py b/PhysicsTools/NanoAOD/python/jetsAK8_cff.py index 3915ba356dd0b..ca1b924b8f407 100644 --- a/PhysicsTools/NanoAOD/python/jetsAK8_cff.py +++ b/PhysicsTools/NanoAOD/python/jetsAK8_cff.py @@ -56,6 +56,28 @@ n2b1 = Var("?hasUserFloat('nb1AK8PuppiSoftDrop:ecfN2')?userFloat('nb1AK8PuppiSoftDrop:ecfN2'):-99999.", float, doc="N2 with beta=1 (for jets with raw pT>250 GeV)", precision=10), n3b1 = Var("?hasUserFloat('nb1AK8PuppiSoftDrop:ecfN3')?userFloat('nb1AK8PuppiSoftDrop:ecfN3'):-99999.", float, doc="N3 with beta=1 (for jets with raw pT>250 GeV)", precision=10), msoftdrop = Var("groomedMass('SoftDropPuppi')",float, doc="Corrected soft drop mass with PUPPI",precision=10), + globalParT3_Xbb = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXbb')",float,doc="Mass-decorrelated GlobalParT-3 X->bb score. Note: For sig vs bkg (e.g. bkg=QCD) tagging, use sig/(sig+bkg) to construct the discriminator",precision=10), + globalParT3_Xcc = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXcc')",float,doc="Mass-decorrelated GlobalParT-3 X->cc score",precision=10), + globalParT3_Xcs = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXcs')",float,doc="Mass-decorrelated GlobalParT-3 X->cs score",precision=10), + globalParT3_Xqq = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXqq')",float,doc="Mass-decorrelated GlobalParT-3 X->qq (ss/dd/uu) score",precision=10), + globalParT3_Xtauhtaue = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXtauhtaue')",float,doc="Mass-decorrelated GlobalParT-3 X->tauhtaue score",precision=10), + globalParT3_Xtauhtaum = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXtauhtaum')",float,doc="Mass-decorrelated GlobalParT-3 X->tauhtaum score",precision=10), + globalParT3_Xtauhtauh = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXtauhtauh')",float,doc="Mass-decorrelated GlobalParT-3 X->tauhtauh score",precision=10), + globalParT3_XWW4q = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXWW4q')",float,doc="Mass-decorrelated GlobalParT-3 X->WW4q score",precision=10), + globalParT3_XWW3q = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXWW3q')",float,doc="Mass-decorrelated GlobalParT-3 X->WW3q score",precision=10), + globalParT3_XWWqqev = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXWWqqev')",float,doc="Mass-decorrelated GlobalParT-3 X->WWqqev score",precision=10), + globalParT3_XWWqqmv = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probXWWqqmv')",float,doc="Mass-decorrelated GlobalParT-3 X->WWqqmv score",precision=10), + globalParT3_TopbWqq = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probTopbWqq')",float,doc="Mass-decorrelated GlobalParT-3 Top->bWqq score",precision=10), + globalParT3_TopbWq = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probTopbWq')",float,doc="Mass-decorrelated GlobalParT-3 Top->bWq score",precision=10), + globalParT3_TopbWev = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probTopbWev')",float,doc="Mass-decorrelated GlobalParT-3 Top->bWev score",precision=10), + globalParT3_TopbWmv = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probTopbWmv')",float,doc="Mass-decorrelated GlobalParT-3 Top->bWmv score",precision=10), + globalParT3_TopbWtauhv = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probTopbWtauhv')",float,doc="Mass-decorrelated GlobalParT-3 Top->bWtauhv score",precision=10), + globalParT3_QCD = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probQCD')",float,doc="Mass-decorrelated GlobalParT-3 QCD score.",precision=10), + globalParT3_massCorrX2p = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:massCorrX2p')",float,doc="GlobalParT-3 mass regression corrector with respect to the original jet mass, optimised for resonance 2-prong (bb/cc/cs/ss/qq) jets. Use (massCorrX2p * mass * (1 - rawFactor)) to get the regressed mass",precision=10), + globalParT3_massCorrGeneric = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:massCorrGeneric')",float,doc="GlobalParT-3 mass regression corrector with respect to the original jet mass, optimised for generic jet cases. Use (massCorrGeneric * mass * (1 - rawFactor)) to get the regressed mass",precision=10), + globalParT3_withMassTopvsQCD = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probWithMassTopvsQCD')",float,doc="GlobalParT-3 tagger (w/mass) Top vs QCD discriminator",precision=10), + globalParT3_withMassWvsQCD = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probWithMassWvsQCD')",float,doc="GlobalParT-3 tagger (w/mass) W vs QCD discriminator",precision=10), + globalParT3_withMassZvsQCD = Var("bDiscriminator('pfGlobalParticleTransformerAK8JetTags:probWithMassZvsQCD')",float,doc="GlobalParT-3 tagger (w/mass) Z vs QCD discriminator",precision=10), particleNetWithMass_QCD = Var("bDiscriminator('pfParticleNetJetTags:probQCDbb')+bDiscriminator('pfParticleNetJetTags:probQCDcc')+bDiscriminator('pfParticleNetJetTags:probQCDb')+bDiscriminator('pfParticleNetJetTags:probQCDc')+bDiscriminator('pfParticleNetJetTags:probQCDothers')",float,doc="ParticleNet tagger (w/ mass) QCD(bb,cc,b,c,others) sum",precision=10), particleNetWithMass_TvsQCD = Var("bDiscriminator('pfParticleNetDiscriminatorsJetTags:TvsQCD')",float,doc="ParticleNet tagger (w/ mass) top vs QCD discriminator",precision=10), particleNetWithMass_WvsQCD = Var("bDiscriminator('pfParticleNetDiscriminatorsJetTags:WvsQCD')",float,doc="ParticleNet tagger (w/ mass) W vs QCD discriminator",precision=10), @@ -147,7 +169,7 @@ ## - To be used in nanoAOD_customizeCommon() in nano_cff.py ############################################################### from PhysicsTools.PatAlgos.tools.jetTools import updateJetCollection -def nanoAOD_addDeepInfoAK8(process, addDeepBTag, addDeepBoostedJet, addDeepDoubleX, addDeepDoubleXV2, addParticleNetMassLegacy, addParticleNet, jecPayload): +def nanoAOD_addDeepInfoAK8(process, addDeepBTag, addDeepBoostedJet, addDeepDoubleX, addDeepDoubleXV2, addParticleNetMassLegacy, addParticleNet, addGlobalParT, jecPayload): _btagDiscriminators=[] if addDeepBTag: print("Updating process to run DeepCSV btag to AK8 jets") @@ -156,6 +178,10 @@ def nanoAOD_addDeepInfoAK8(process, addDeepBTag, addDeepBoostedJet, addDeepDoubl print("Updating process to run DeepBoostedJet on datasets before 103X") from RecoBTag.ONNXRuntime.pfDeepBoostedJet_cff import _pfDeepBoostedJetTagsAll as pfDeepBoostedJetTagsAll _btagDiscriminators += pfDeepBoostedJetTagsAll + if addGlobalParT: + print("Updating process to run GlobalParT") + from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import _pfGlobalParticleTransformerAK8JetTagsAll as pfGlobalParticleTransformerAK8JetTagsAll + _btagDiscriminators += pfGlobalParticleTransformerAK8JetTagsAll if addParticleNet: print("Updating process to run ParticleNet joint classification and mass regression") from RecoBTag.ONNXRuntime.pfParticleNetFromMiniAODAK8_cff import _pfParticleNetFromMiniAODAK8JetTagsAll as pfParticleNetFromMiniAODAK8JetTagsAll @@ -200,16 +226,18 @@ def nanoAOD_addDeepInfoAK8(process, addDeepBTag, addDeepBoostedJet, addDeepDoubl nanoAOD_addDeepDoubleXV2_switch = cms.untracked.bool(False), nanoAOD_addParticleNetMassLegacy_switch = cms.untracked.bool(False), nanoAOD_addParticleNet_switch = cms.untracked.bool(False), + nanoAOD_addGlobalParT_switch = cms.untracked.bool(False), jecPayload = cms.untracked.string('AK8PFPuppi') ) # ParticleNet legacy jet tagger is already in 106Xv2 MINIAOD, -# add ParticleNet legacy mass regression and new combined tagger + mass regression +# add ParticleNet legacy mass regression, new combined tagger + mass regression, and GlobalParT run2_nanoAOD_106Xv2.toModify( nanoAOD_addDeepInfoAK8_switch, nanoAOD_addParticleNetMassLegacy_switch = True, nanoAOD_addParticleNet_switch = True, + nanoAOD_addGlobalParT_switch = True, ) ################################################ diff --git a/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py b/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py index b15fb41f11c4d..c83e77ef43025 100644 --- a/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py +++ b/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py @@ -179,6 +179,28 @@ plots = cms.VPSet( Count1D('_size', 6, -0.5, 5.5, 'slimmedJetsAK8, i.e. ak8 fat jets for boosted analysis'), Plot1D('area', 'area', 20, 2, 4, 'jet catchment area, for JECs'), + Plot1D('globalParT3_Xbb', 'globalParT3_Xbb', 20, -1, 1, 'GlobalParT-3 X->bb score'), + Plot1D('globalParT3_Xcc', 'globalParT3_Xcc', 20, -1, 1, 'GlobalParT-3 X->cc score'), + Plot1D('globalParT3_Xcs', 'globalParT3_Xcs', 20, -1, 1, 'GlobalParT-3 X->cs score'), + Plot1D('globalParT3_Xqq', 'globalParT3_Xqq', 20, -1, 1, 'GlobalParT-3 X->qq (ss/dd/uu) score'), + Plot1D('globalParT3_Xtauhtaue', 'globalParT3_Xtauhtaue', 20, -1, 1, 'GlobalParT-3 X->tauhtaue score'), + Plot1D('globalParT3_Xtauhtaum', 'globalParT3_Xtauhtaum', 20, -1, 1, 'GlobalParT-3 X->tauhtaum score'), + Plot1D('globalParT3_Xtauhtauh', 'globalParT3_Xtauhtauh', 20, -1, 1, 'GlobalParT-3 X->tauhtauh score'), + Plot1D('globalParT3_XWW4q', 'globalParT3_XWW4q', 20, -1, 1, 'GlobalParT-3 X->WW4q score'), + Plot1D('globalParT3_XWW3q', 'globalParT3_XWW3q', 20, -1, 1, 'GlobalParT-3 X->WW3q score'), + Plot1D('globalParT3_XWWqqev', 'globalParT3_XWWqqev', 20, -1, 1, 'GlobalParT-3 X->WWqqev score'), + Plot1D('globalParT3_XWWqqmv', 'globalParT3_XWWqqmv', 20, -1, 1, 'GlobalParT-3 X->WWqqmv score'), + Plot1D('globalParT3_TopbWqq', 'globalParT3_TopbWqq', 20, -1, 1, 'GlobalParT-3 Top->bWqq score'), + Plot1D('globalParT3_TopbWq', 'globalParT3_TopbWq', 20, -1, 1, 'GlobalParT-3 Top->bWq score'), + Plot1D('globalParT3_TopbWev', 'globalParT3_TopbWev', 20, -1, 1, 'GlobalParT-3 Top->bWev score'), + Plot1D('globalParT3_TopbWmv', 'globalParT3_TopbWmv', 20, -1, 1, 'GlobalParT-3 Top->bWmv score'), + Plot1D('globalParT3_TopbWtauhv', 'globalParT3_TopbWtauhv', 20, -1, 1, 'GlobalParT-3 Top->bWtauhv score'), + Plot1D('globalParT3_QCD', 'globalParT3_QCD', 20, -1, 1, 'GlobalParT-3 QCD score'), + Plot1D('globalParT3_massCorrX2p', 'globalParT3_massCorrX2p', 20, -1, 2, 'GlobalParT-3 mass regression corrector (for X->2-prong jets)'), + Plot1D('globalParT3_massCorrGeneric', 'globalParT3_massCorrGeneric', 20, -1, 2, 'GlobalParT-3 mass regression corrector (for generic cases)'), + Plot1D('globalParT3_withMassTopvsQCD', 'globalParT3_withMassTopvsQCD', 20, -1, 1, 'GlobalParT-3 tagger (mass-correlated) Top vs QCD discriminator'), + Plot1D('globalParT3_withMassWvsQCD', 'globalParT3_withMassWvsQCD', 20, -1, 1, 'GlobalParT-3 tagger (mass-correlated) W vs QCD discriminator'), + Plot1D('globalParT3_withMassZvsQCD', 'globalParT3_withMassZvsQCD', 20, -1, 1, 'GlobalParT-3 tagger (mass-correlated) Z vs QCD discriminator'), Plot1D('particleNetWithMass_QCD', 'particleNetWithMass_QCD', 20, -1, 1, 'ParticleNet (mass-correlated) QCD score'), Plot1D('particleNetWithMass_TvsQCD', 'particleNetWithMass_TvsQCD', 20, 0, 1, 'ParticleNet (mass-correlated) top vs. QCD score'), Plot1D('particleNetWithMass_WvsQCD', 'particleNetWithMass_WvsQCD', 20, 0, 1, 'ParticleNet (mass-correlated) W vs. QCD score'), diff --git a/PhysicsTools/NanoAOD/python/nano_cff.py b/PhysicsTools/NanoAOD/python/nano_cff.py index bfbac52ed933d..5e55613bfb41d 100644 --- a/PhysicsTools/NanoAOD/python/nano_cff.py +++ b/PhysicsTools/NanoAOD/python/nano_cff.py @@ -233,6 +233,7 @@ def nanoAOD_customizeCommon(process): addDeepDoubleXV2=nanoAOD_addDeepInfoAK8_switch.nanoAOD_addDeepDoubleXV2_switch, addParticleNetMassLegacy=nanoAOD_addDeepInfoAK8_switch.nanoAOD_addParticleNetMassLegacy_switch, addParticleNet=nanoAOD_addDeepInfoAK8_switch.nanoAOD_addParticleNet_switch, + addGlobalParT=nanoAOD_addDeepInfoAK8_switch.nanoAOD_addGlobalParT_switch, jecPayload=nanoAOD_addDeepInfoAK8_switch.jecPayload ) diff --git a/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py b/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py index 85a42935ff06e..1fe7e05b37bf5 100644 --- a/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py +++ b/PhysicsTools/PatAlgos/python/recoLayer0/bTagging_cff.py @@ -45,6 +45,8 @@ , 'pfParticleTransformerAK4TagInfos' # UnifiedParticleTransformerAK4 tag infos , 'pfUnifiedParticleTransformerAK4TagInfos' + # GlobalParticleTransformerAK8 tag infos + , 'pfGlobalParticleTransformerAK8TagInfos' # DeepDoubleB/C tag infos , 'pfDeepDoubleXTagInfos' # DeepBoostedJet tag infos @@ -379,5 +381,15 @@ # update supportedBtagDiscr for disc in _pfNegativeUnifiedParticleTransformerAK4JetTagsProbs: supportedBtagDiscr[disc] = [["pfNegativeUnifiedParticleTransformerAK4TagInfos"]] +# ----------------------------------- - +# ----------------------------------- +# setup GlobalParticleTransformer AK8 +from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import _pfGlobalParticleTransformerAK8JetTagsProbs, _pfGlobalParticleTransformerAK8JetTagsMetaDiscrs +# update supportedBtagDiscr +for disc in _pfGlobalParticleTransformerAK8JetTagsProbs: + supportedBtagDiscr[disc] = [["pfGlobalParticleTransformerAK8TagInfos"]] +# update supportedMetaDiscr +for disc in _pfGlobalParticleTransformerAK8JetTagsMetaDiscrs: + supportedMetaDiscr[disc] = _pfGlobalParticleTransformerAK8JetTagsProbs +# ----------------------------------- diff --git a/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py b/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py index 4dbf849bd3e26..615f98bcab8ea 100644 --- a/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py +++ b/PhysicsTools/PatAlgos/python/slimming/applyDeepBtagging_cff.py @@ -80,11 +80,12 @@ def applyDeepBtagging(process, postfix=""): from RecoBTag.ONNXRuntime.pfParticleNet_cff import _pfParticleNetMassRegressionOutputs as pfParticleNetMassRegressionOutputs from RecoBTag.ONNXRuntime.pfParticleNet_cff import _pfParticleNetMassCorrelatedJetTagsAll as pfParticleNetMassCorrelatedJetTagsAll from RecoBTag.ONNXRuntime.pfParticleNetFromMiniAODAK8_cff import _pfParticleNetFromMiniAODAK8JetTagsAll as pfParticleNetFromMiniAODAK8JetTagsAll + from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import _pfGlobalParticleTransformerAK8JetTagsAll as pfGlobalParticleTransformerAK8JetTagsAll # update slimmed jets to include particle-based deep taggers (keep same name) # make clone for DeepTags-less slimmed AK8 jets, so output name is preserved addToProcessAndTask('slimmedJetsAK8NoDeepTags', slimmedJetsAK8.clone(), process, task) - _btagDiscriminatorsAK8 = cms.PSet(names = cms.vstring(pfParticleNetMassCorrelatedJetTagsAll+pfParticleNetFromMiniAODAK8JetTagsAll+pfParticleNetJetTagsAll+pfParticleNetMassRegressionOutputs)) + _btagDiscriminatorsAK8 = cms.PSet(names = cms.vstring(pfParticleNetMassCorrelatedJetTagsAll+pfGlobalParticleTransformerAK8JetTagsAll+pfParticleNetFromMiniAODAK8JetTagsAll+pfParticleNetJetTagsAll+pfParticleNetMassRegressionOutputs)) updateJetCollection( process, jetSource = cms.InputTag('slimmedJetsAK8NoDeepTags'), diff --git a/PhysicsTools/PatAlgos/python/tools/jetTools.py b/PhysicsTools/PatAlgos/python/tools/jetTools.py index b7809bd209a47..dc38df71f1489 100644 --- a/PhysicsTools/PatAlgos/python/tools/jetTools.py +++ b/PhysicsTools/PatAlgos/python/tools/jetTools.py @@ -786,7 +786,7 @@ def setupBTagging(process, jetSource, pfCandidates, explicitJTA, pvSource, svSou ), process, task) - if btagInfo == 'pfParticleNetTagInfos': + if btagInfo == 'pfParticleNetTagInfos' or btagInfo == 'pfGlobalParticleTransformerAK8TagInfos': if pfCandidates.value() == 'packedPFCandidates': # case 1: running over jets whose daughters are PackedCandidates (only via updateJetCollection for now) vertex_associator = "" @@ -797,7 +797,7 @@ def setupBTagging(process, jetSource, pfCandidates, explicitJTA, pvSource, svSou else: raise ValueError("Invalid pfCandidates collection: %s." % pfCandidates.value()) addToProcessAndTask(btagPrefix+btagInfo+labelName+postfix, - btag.pfParticleNetTagInfos.clone( + getattr(btag, btagInfo).clone( jets = jetSource, vertices = pvSource, secondary_vertices = svSource, diff --git a/PhysicsTools/PatAlgos/python/tools/puppiJetMETReclusteringFromMiniAOD_cff.py b/PhysicsTools/PatAlgos/python/tools/puppiJetMETReclusteringFromMiniAOD_cff.py index 5772dafc56560..ceb9c648b8f90 100644 --- a/PhysicsTools/PatAlgos/python/tools/puppiJetMETReclusteringFromMiniAOD_cff.py +++ b/PhysicsTools/PatAlgos/python/tools/puppiJetMETReclusteringFromMiniAOD_cff.py @@ -44,8 +44,10 @@ def puppiJetMETReclusterFromMiniAOD(process, runOnMC, useExistingWeights=False, from RecoBTag.ONNXRuntime.pfParticleNet_cff import _pfParticleNetMassRegressionOutputs as pfParticleNetMassRegressionOutputs from RecoBTag.ONNXRuntime.pfParticleNet_cff import _pfParticleNetMassCorrelatedJetTagsAll as pfParticleNetMassCorrelatedJetTagsAll from RecoBTag.ONNXRuntime.pfParticleNetFromMiniAODAK8_cff import _pfParticleNetFromMiniAODAK8JetTagsAll as pfParticleNetFromMiniAODAK8JetTagsAll + from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import _pfGlobalParticleTransformerAK8JetTagsAll as pfGlobalParticleTransformerAK8JetTagsAll btagDiscriminatorsAK8 = cms.PSet(names = cms.vstring( pfParticleNetMassCorrelatedJetTagsAll+ + pfGlobalParticleTransformerAK8JetTagsAll+ pfParticleNetFromMiniAODAK8JetTagsAll+ pfParticleNetJetTagsAll+ pfParticleNetMassRegressionOutputs diff --git a/RecoBTag/Configuration/python/RecoBTag_cff.py b/RecoBTag/Configuration/python/RecoBTag_cff.py index 006fc1db7d30e..5625168f08d66 100644 --- a/RecoBTag/Configuration/python/RecoBTag_cff.py +++ b/RecoBTag/Configuration/python/RecoBTag_cff.py @@ -15,6 +15,7 @@ from RecoBTag.ONNXRuntime.pfParticleNetAK4_cff import * from RecoBTag.ONNXRuntime.pfParticleTransformerAK4_cff import * from RecoBTag.ONNXRuntime.pfUnifiedParticleTransformerAK4_cff import * +from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import * from RecoVertex.AdaptiveVertexFinder.inclusiveVertexing_cff import * from RecoBTag.PixelCluster.pixelClusterTagInfos_cfi import * diff --git a/RecoBTag/FeatureTools/plugins/GlobalParticleTransformerAK8TagInfoProducer.cc b/RecoBTag/FeatureTools/plugins/GlobalParticleTransformerAK8TagInfoProducer.cc new file mode 100644 index 0000000000000..80035fbef446a --- /dev/null +++ b/RecoBTag/FeatureTools/plugins/GlobalParticleTransformerAK8TagInfoProducer.cc @@ -0,0 +1,742 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/StreamID.h" + +#include "DataFormats/Candidate/interface/Candidate.h" + +#include "DataFormats/PatCandidates/interface/Jet.h" +#include "DataFormats/PatCandidates/interface/PackedCandidate.h" + +#include "RecoBTag/FeatureTools/interface/TrackInfoBuilder.h" +#include "RecoBTag/FeatureTools/interface/deep_helpers.h" +#include "RecoBTag/FeatureTools/interface/sorting_modules.h" +#include "TrackingTools/Records/interface/TransientTrackRecord.h" + +#include "DataFormats/Candidate/interface/VertexCompositePtrCandidate.h" +#include "DataFormats/VertexReco/interface/VertexFwd.h" + +#include "DataFormats/BTauReco/interface/DeepBoostedJetTagInfo.h" + +#include "Math/PtEtaPhiE4D.h" +#include "Math/LorentzVector.h" + +using namespace btagbtvdeep; + +class GlobalParticleTransformerAK8TagInfoProducer : public edm::stream::EDProducer<> { +public: + explicit GlobalParticleTransformerAK8TagInfoProducer(const edm::ParameterSet &); + ~GlobalParticleTransformerAK8TagInfoProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions); + +private: + typedef std::vector DeepBoostedJetTagInfoCollection; + typedef reco::VertexCompositePtrCandidateCollection SVCollection; + typedef reco::VertexCollection VertexCollection; + typedef edm::View CandidateView; + + void beginStream(edm::StreamID) override {} + void produce(edm::Event &, const edm::EventSetup &) override; + void endStream() override {} + + void fillJetFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet); + void fillParticleFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet); + void fillSVFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet); + + const double jet_radius_; + const double min_jet_pt_; + const double max_jet_eta_; + const double min_pt_for_track_properties_; + const bool use_puppiP4_; + const bool include_neutrals_; + const bool sort_by_sip2dsig_; + const double min_puppi_wgt_; + const bool flip_ip_sign_; + const double max_sip3dsig_; + + edm::EDGetTokenT> jet_token_; + edm::EDGetTokenT vtx_token_; + edm::EDGetTokenT sv_token_; + edm::EDGetTokenT pfcand_token_; + edm::EDGetTokenT lt_token_; + + bool use_puppi_value_map_; + bool use_pvasq_value_map_; + + edm::EDGetTokenT> puppi_value_map_token_; + edm::EDGetTokenT> pvasq_value_map_token_; + edm::EDGetTokenT> pvas_token_; + edm::ESGetToken track_builder_token_; + + edm::Handle vtxs_; + edm::Handle svs_; + edm::Handle pfcands_; + edm::Handle lts_; + edm::ESHandle track_builder_; + edm::Handle> puppi_value_map_; + edm::Handle> pvasq_value_map_; + edm::Handle> pvas_; + + const static std::vector jet_features_; + const static std::vector charged_particle_features_; + const static std::vector neutral_particle_features_; + const static std::vector sv_features_; + const reco::Vertex *pv_ = nullptr; +}; + +const std::vector GlobalParticleTransformerAK8TagInfoProducer::jet_features_{ + "jet_pt_log", + "jet_eta", + "jet_mass_log", + "jet_energy_log", +}; +const std::vector GlobalParticleTransformerAK8TagInfoProducer::charged_particle_features_{ + "cpfcandlt_puppiw", + "cpfcandlt_hcalFrac", + "cpfcandlt_VTX_ass", + "cpfcandlt_lostInnerHits", + "cpfcandlt_quality", + "cpfcandlt_charge", + "cpfcandlt_isEl", + "cpfcandlt_isMu", + "cpfcandlt_isChargedHad", + "cpfcandlt_phirel", + "cpfcandlt_etarel", + "cpfcandlt_deltaR", + "cpfcandlt_abseta", + "cpfcandlt_ptrel_log", + "cpfcandlt_erel_log", + "cpfcandlt_pt_log", + "cpfcandlt_drminsv", + "cpfcandlt_drsubjet1", + "cpfcandlt_drsubjet2", + "cpfcandlt_normchi2", + "cpfcandlt_dz", + "cpfcandlt_dzsig", + "cpfcandlt_dxy", + "cpfcandlt_dxysig", + "cpfcandlt_dptdpt", + "cpfcandlt_detadeta", + "cpfcandlt_dphidphi", + "cpfcandlt_dxydxy", + "cpfcandlt_dzdz", + "cpfcandlt_dxydz", + "cpfcandlt_dphidxy", + "cpfcandlt_dlambdadz", + "cpfcandlt_btagEtaRel", + "cpfcandlt_btagPtRatio", + "cpfcandlt_btagPParRatio", + "cpfcandlt_btagSip2dVal", + "cpfcandlt_btagSip2dSig", + "cpfcandlt_btagSip3dVal", + "cpfcandlt_btagSip3dSig", + "cpfcandlt_btagJetDistVal", + "cpfcandlt_mask", + "cpfcandlt_pt_log_nopuppi", + "cpfcandlt_e_log_nopuppi", + "cpfcandlt_ptrel", + "cpfcandlt_erel", + "cpfcandlt_isLostTrack", + "cpfcandlt_pixelBarrelLayersWithMeasurement", + "cpfcandlt_pixelEndcapLayersWithMeasurement", + "cpfcandlt_stripTECLayersWithMeasurement", + "cpfcandlt_stripTIBLayersWithMeasurement", + "cpfcandlt_stripTIDLayersWithMeasurement", + "cpfcandlt_stripTOBLayersWithMeasurement", + "cpfcandlt_px", + "cpfcandlt_py", + "cpfcandlt_pz", + "cpfcandlt_energy"}; + +const std::vector GlobalParticleTransformerAK8TagInfoProducer::neutral_particle_features_{ + "npfcand_puppiw", + "npfcand_hcalFrac", + "npfcand_isGamma", + "npfcand_isNeutralHad", + "npfcand_phirel", + "npfcand_etarel", + "npfcand_deltaR", + "npfcand_abseta", + "npfcand_ptrel_log", + "npfcand_erel_log", + "npfcand_pt_log", + "npfcand_mask", + "npfcand_pt_log_nopuppi", + "npfcand_e_log_nopuppi", + "npfcand_ptrel", + "npfcand_erel", + "npfcand_px", + "npfcand_py", + "npfcand_pz", + "npfcand_energy"}; + +const std::vector GlobalParticleTransformerAK8TagInfoProducer::sv_features_{ + "sv_mask", "sv_ptrel", "sv_erel", "sv_phirel", "sv_etarel", "sv_deltaR", + "sv_abseta", "sv_mass", "sv_ptrel_log", "sv_erel_log", "sv_pt_log", "sv_pt", + "sv_ntracks", "sv_normchi2", "sv_dxy", "sv_dxysig", "sv_d3d", "sv_d3dsig", + "sv_costhetasvpv", "sv_px", "sv_py", "sv_pz", "sv_energy"}; + +GlobalParticleTransformerAK8TagInfoProducer::GlobalParticleTransformerAK8TagInfoProducer( + const edm::ParameterSet &iConfig) + : jet_radius_(iConfig.getParameter("jet_radius")), + min_jet_pt_(iConfig.getParameter("min_jet_pt")), + max_jet_eta_(iConfig.getParameter("max_jet_eta")), + min_pt_for_track_properties_(iConfig.getParameter("min_pt_for_track_properties")), + use_puppiP4_(iConfig.getParameter("use_puppiP4")), + include_neutrals_(iConfig.getParameter("include_neutrals")), + sort_by_sip2dsig_(iConfig.getParameter("sort_by_sip2dsig")), + min_puppi_wgt_(iConfig.getParameter("min_puppi_wgt")), + flip_ip_sign_(iConfig.getParameter("flip_ip_sign")), + max_sip3dsig_(iConfig.getParameter("sip3dSigMax")), + jet_token_(consumes>(iConfig.getParameter("jets"))), + vtx_token_(consumes(iConfig.getParameter("vertices"))), + sv_token_(consumes(iConfig.getParameter("secondary_vertices"))), + pfcand_token_(consumes(iConfig.getParameter("pf_candidates"))), + lt_token_(consumes(iConfig.getParameter("lost_tracks"))), + use_puppi_value_map_(false), + use_pvasq_value_map_(false), + track_builder_token_( + esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))) { + const auto &puppi_value_map_tag = iConfig.getParameter("puppi_value_map"); + if (!puppi_value_map_tag.label().empty()) { + puppi_value_map_token_ = consumes>(puppi_value_map_tag); + use_puppi_value_map_ = true; + } + + const auto &pvas_tag = iConfig.getParameter("vertex_associator"); + if (!pvas_tag.label().empty()) { + pvasq_value_map_token_ = consumes>(pvas_tag); + pvas_token_ = consumes>(pvas_tag); + use_pvasq_value_map_ = true; + } + + produces(); +} + +GlobalParticleTransformerAK8TagInfoProducer::~GlobalParticleTransformerAK8TagInfoProducer() {} + +void GlobalParticleTransformerAK8TagInfoProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) { + // pfGlobalParticleTransformerAK8TagInfos + edm::ParameterSetDescription desc; + desc.add("jet_radius", 0.8); + desc.add("min_jet_pt", 150); + desc.add("max_jet_eta", 99); + desc.add("min_pt_for_track_properties", -1); + desc.add("use_puppiP4", true); + desc.add("include_neutrals", true); + desc.add("sort_by_sip2dsig", false); + desc.add("min_puppi_wgt", 0.01); + desc.add("flip_ip_sign", false); + desc.add("sip3dSigMax", -1); + desc.add("vertices", edm::InputTag("offlinePrimaryVertices")); + desc.add("secondary_vertices", edm::InputTag("inclusiveCandidateSecondaryVertices")); + desc.add("pf_candidates", edm::InputTag("particleFlow")); + desc.add("lost_tracks", edm::InputTag("lostTracks")); + desc.add("jets", edm::InputTag("ak8PFJetsPuppi")); + desc.add("puppi_value_map", edm::InputTag("puppi")); + desc.add("vertex_associator", edm::InputTag("primaryVertexAssociation", "original")); + descriptions.add("pfGlobalParticleTransformerAK8TagInfos", desc); +} + +void GlobalParticleTransformerAK8TagInfoProducer::produce(edm::Event &iEvent, const edm::EventSetup &iSetup) { + auto output_tag_infos = std::make_unique(); + + auto jets = iEvent.getHandle(jet_token_); + + iEvent.getByToken(vtx_token_, vtxs_); + if (vtxs_->empty()) { + // produce empty TagInfos in case no primary vertex + iEvent.put(std::move(output_tag_infos)); + return; // exit event + } + // primary vertex + pv_ = &vtxs_->at(0); + + iEvent.getByToken(sv_token_, svs_); + iEvent.getByToken(pfcand_token_, pfcands_); + iEvent.getByToken(lt_token_, lts_); + + track_builder_ = iSetup.getHandle(track_builder_token_); + + if (use_puppi_value_map_) { + iEvent.getByToken(puppi_value_map_token_, puppi_value_map_); + } + + if (use_pvasq_value_map_) { + iEvent.getByToken(pvasq_value_map_token_, pvasq_value_map_); + iEvent.getByToken(pvas_token_, pvas_); + } + + for (std::size_t jet_n = 0; jet_n < jets->size(); jet_n++) { + const auto &jet = (*jets)[jet_n]; + edm::RefToBase jet_ref(jets, jet_n); + + // create jet features + DeepBoostedJetFeatures features; + // declare all the feature variables (init as empty vector) + for (const auto &name : jet_features_) { + features.add(name); + } + for (const auto &name : charged_particle_features_) { + features.add(name); + } + for (const auto &name : neutral_particle_features_) { + features.add(name); + } + for (const auto &name : sv_features_) { + features.add(name); + } + + // fill values only if above pt threshold and has daughters, otherwise left + // empty + bool fill_vars = true; + if (jet.pt() < min_jet_pt_ || std::abs(jet.eta()) > max_jet_eta_) + fill_vars = false; + if (jet.numberOfDaughters() == 0) + fill_vars = false; + + if (fill_vars) { + fillJetFeatures(features, jet); + fillParticleFeatures(features, jet); + fillSVFeatures(features, jet); + + features.check_consistency(charged_particle_features_); + features.check_consistency(neutral_particle_features_); + features.check_consistency(sv_features_); + } + + // this should always be done even if features are not filled + output_tag_infos->emplace_back(features, jet_ref); + } + + iEvent.put(std::move(output_tag_infos)); +} + +void GlobalParticleTransformerAK8TagInfoProducer::fillJetFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet) { + // reserve space + for (const auto &name : jet_features_) { + fts.reserve(name, 1); + } + fts.fill("jet_pt_log", std::log(jet.pt())); + fts.fill("jet_eta", jet.eta()); + fts.fill("jet_mass_log", std::log(jet.mass())); + fts.fill("jet_energy_log", std::log(jet.energy())); +} + +void GlobalParticleTransformerAK8TagInfoProducer::fillParticleFeatures(DeepBoostedJetFeatures &fts, + const reco::Jet &jet) { + // require the input to be a pat::Jet + const auto *patJet = dynamic_cast(&jet); + if (!patJet) { + throw edm::Exception(edm::errors::InvalidReference) << "Input is not a pat::Jet."; + } + + // do nothing if jet does not have constituents + if (jet.numberOfDaughters() == 0) + return; + + // some jet properties + math::XYZVector jet_dir = jet.momentum().Unit(); + GlobalVector jet_ref_track_dir(jet.px(), jet.py(), jet.pz()); + const float etasign = jet.eta() > 0 ? 1 : -1; + + TrackInfoBuilder trkinfo(track_builder_); + + std::map puppi_wgt_cache; + auto puppiWgt = [&](const reco::CandidatePtr &cand) { + const auto *pack_cand = dynamic_cast(&(*cand)); + const auto *reco_cand = dynamic_cast(&(*cand)); + float wgt = 1.; + if (pack_cand) { + wgt = pack_cand->puppiWeight(); + } else if (reco_cand) { + if (use_puppi_value_map_) { + wgt = (*puppi_value_map_)[cand]; + } else { + throw edm::Exception(edm::errors::InvalidReference) << "Puppi value map is missing"; + } + } else { + throw edm::Exception(edm::errors::InvalidReference) << "Cannot convert to either pat::PackedCandidate or " + "reco::PFCandidate"; + } + puppi_wgt_cache[cand] = wgt; + return wgt; + }; + + std::vector cpfPtrs, npfPtrs; + std::map isLostTrackMap; + + for (const auto &dau : jet.daughterPtrVector()) { + // remove particles w/ extremely low puppi weights + // [Note] use jet daughters here to get the puppiWgt correctly + if ((puppiWgt(dau)) < min_puppi_wgt_) + continue; + // from here: get the original reco/packed candidate not scaled by the puppi weight + auto cand = pfcands_->ptrAt(dau.key()); + // charged candidate selection (for Higgs Interaction Net) + if (!include_neutrals_ && (cand->charge() == 0 || cand->pt() < min_pt_for_track_properties_)) + continue; + // only when computing the nagative tagger: remove charged candidates with high sip3d + if (flip_ip_sign_ && cand->charge()) { + trkinfo.buildTrackInfo(&(*cand), jet_dir, jet_ref_track_dir, *pv_); + if (trkinfo.getTrackSip3dSig() > max_sip3dsig_) + continue; + } + if (cand->charge() != 0) { + cpfPtrs.push_back(cand); + isLostTrackMap[cand] = false; + } else { + npfPtrs.push_back(cand); + } + } + // lost tracks: fill to cpfcands + for (size_t i = 0; i < lts_->size(); ++i) { + auto cand = lts_->ptrAt(i); + if (reco::deltaR(*cand, jet) < jet_radius_) { + cpfPtrs.push_back(cand); + isLostTrackMap[cand] = true; + puppi_wgt_cache[cand] = 1.; // set puppi weight to 1 for lost tracks + } + } + + std::vector> c_sorted; + if (sort_by_sip2dsig_) { + // sort charged pf candidates by 2d impact parameter significance + for (const auto &cand : cpfPtrs) { + trkinfo.buildTrackInfo(&(*cand), jet_dir, jet_ref_track_dir, *pv_); + c_sorted.emplace_back(cand, + trkinfo.getTrackSip2dSig(), + -btagbtvdeep::mindrsvpfcand(*svs_, &(*cand), jet_radius_), + cand->pt() / jet.pt()); + std::sort(c_sorted.begin(), c_sorted.end(), btagbtvdeep::SortingClass::compareByABCInv); + } + for (unsigned int i = 0; i < c_sorted.size(); i++) { + const auto &c = c_sorted.at(i); + const auto &cand = c.get(); + cpfPtrs.at(i) = cand; + } + } else { + if (use_puppiP4_) { + // sort by Puppi-weighted pt + std::sort( + cpfPtrs.begin(), cpfPtrs.end(), [&puppi_wgt_cache](const reco::CandidatePtr &a, const reco::CandidatePtr &b) { + return puppi_wgt_cache.at(a) * a->pt() > puppi_wgt_cache.at(b) * b->pt(); + }); + std::sort( + npfPtrs.begin(), npfPtrs.end(), [&puppi_wgt_cache](const reco::CandidatePtr &a, const reco::CandidatePtr &b) { + return puppi_wgt_cache.at(a) * a->pt() > puppi_wgt_cache.at(b) * b->pt(); + }); + } else { + // sort by original pt (not Puppi-weighted) + std::sort(cpfPtrs.begin(), cpfPtrs.end(), [](const auto &a, const auto &b) { return a->pt() > b->pt(); }); + std::sort(npfPtrs.begin(), npfPtrs.end(), [](const auto &a, const auto &b) { return a->pt() > b->pt(); }); + } + } + + // reserve space + for (const auto &name : charged_particle_features_) { + fts.reserve(name, cpfPtrs.size()); + } + + auto useTrackProperties = [&](const reco::PFCandidate *reco_cand) { + const auto *trk = reco_cand->bestTrack(); + return trk != nullptr && trk->pt() > min_pt_for_track_properties_; + }; + + for (const auto &cand : cpfPtrs) { + const auto *packed_cand = dynamic_cast(&(*cand)); + const auto *reco_cand = dynamic_cast(&(*cand)); + + if (!include_neutrals_ && + ((packed_cand && !packed_cand->hasTrackDetails()) || (reco_cand && !useTrackProperties(reco_cand)))) + continue; + + const float ip_sign = flip_ip_sign_ ? -1 : 1; + + auto candP4 = use_puppiP4_ ? puppi_wgt_cache.at(cand) * cand->p4() : cand->p4(); + if (packed_cand) { + float hcal_fraction = 0.; + if (packed_cand->pdgId() == 1 || packed_cand->pdgId() == 130) { + hcal_fraction = packed_cand->hcalFraction(); + } else if (packed_cand->isIsolatedChargedHadron()) { + hcal_fraction = packed_cand->rawHcalFraction(); + } + + fts.fill("cpfcandlt_hcalFrac", hcal_fraction); + fts.fill("cpfcandlt_VTX_ass", packed_cand->pvAssociationQuality()); + fts.fill("cpfcandlt_lostInnerHits", packed_cand->lostInnerHits()); + fts.fill("cpfcandlt_quality", packed_cand->bestTrack() ? packed_cand->bestTrack()->qualityMask() : 0); + + fts.fill("cpfcandlt_charge", packed_cand->charge()); + fts.fill("cpfcandlt_isEl", std::abs(packed_cand->pdgId()) == 11); + fts.fill("cpfcandlt_isMu", std::abs(packed_cand->pdgId()) == 13); + fts.fill("cpfcandlt_isChargedHad", std::abs(packed_cand->pdgId()) == 211); + fts.fill("cpfcandlt_isLostTrack", isLostTrackMap[cand]); + + // impact parameters + fts.fill("cpfcandlt_dz", ip_sign * packed_cand->dz()); + fts.fill("cpfcandlt_dxy", ip_sign * packed_cand->dxy()); + fts.fill("cpfcandlt_dzsig", packed_cand->bestTrack() ? ip_sign * packed_cand->dz() / packed_cand->dzError() : 0); + fts.fill("cpfcandlt_dxysig", + packed_cand->bestTrack() ? ip_sign * packed_cand->dxy() / packed_cand->dxyError() : 0); + + } else if (reco_cand) { + // get vertex association quality + int pv_ass_quality = 0; // fallback value + float vtx_ass = 0; + if (use_pvasq_value_map_) { + pv_ass_quality = (*pvasq_value_map_)[cand]; + const reco::VertexRef &PV_orig = (*pvas_)[cand]; + vtx_ass = vtx_ass_from_pfcand(*reco_cand, pv_ass_quality, PV_orig); + } else { + throw edm::Exception(edm::errors::InvalidReference) << "Vertex association missing"; + } + + fts.fill("cpfcandlt_hcalFrac", reco_cand->hcalEnergy() / (reco_cand->ecalEnergy() + reco_cand->hcalEnergy())); + fts.fill("cpfcandlt_VTX_ass", vtx_ass); + fts.fill("cpfcandlt_lostInnerHits", useTrackProperties(reco_cand) ? lost_inner_hits_from_pfcand(*reco_cand) : 0); + fts.fill("cpfcandlt_quality", useTrackProperties(reco_cand) ? quality_from_pfcand(*reco_cand) : 0); + + fts.fill("cpfcandlt_charge", reco_cand->charge()); + fts.fill("cpfcandlt_isEl", std::abs(reco_cand->pdgId()) == 11); + fts.fill("cpfcandlt_isMu", std::abs(reco_cand->pdgId()) == 13); + fts.fill("cpfcandlt_isChargedHad", std::abs(reco_cand->pdgId()) == 211); + fts.fill("cpfcandlt_isLostTrack", isLostTrackMap[cand]); + + // impact parameters + const auto *trk = reco_cand->bestTrack(); + float dz = trk ? ip_sign * trk->dz(pv_->position()) : 0; + float dxy = trk ? ip_sign * trk->dxy(pv_->position()) : 0; + fts.fill("cpfcandlt_dz", dz); + fts.fill("cpfcandlt_dzsig", trk ? dz / trk->dzError() : 0); + fts.fill("cpfcandlt_dxy", dxy); + fts.fill("cpfcandlt_dxysig", trk ? dxy / trk->dxyError() : 0); + } + + // basic kinematics + fts.fill("cpfcandlt_px", candP4.px()); + fts.fill("cpfcandlt_py", candP4.py()); + fts.fill("cpfcandlt_pz", candP4.pz()); + fts.fill("cpfcandlt_energy", candP4.energy()); + + fts.fill("cpfcandlt_puppiw", puppi_wgt_cache.at(cand)); + fts.fill("cpfcandlt_phirel", reco::deltaPhi(candP4, jet)); + fts.fill("cpfcandlt_etarel", etasign * (candP4.eta() - jet.eta())); + fts.fill("cpfcandlt_deltaR", reco::deltaR(candP4, jet)); + fts.fill("cpfcandlt_abseta", std::abs(candP4.eta())); + + fts.fill("cpfcandlt_ptrel_log", std::log(candP4.pt() / jet.pt())); + fts.fill("cpfcandlt_ptrel", candP4.pt() / jet.pt()); + fts.fill("cpfcandlt_erel_log", std::log(candP4.energy() / jet.energy())); + fts.fill("cpfcandlt_erel", candP4.energy() / jet.energy()); + fts.fill("cpfcandlt_pt_log", std::log(candP4.pt())); + + fts.fill("cpfcandlt_mask", 1); + fts.fill("cpfcandlt_pt_log_nopuppi", std::log(cand->pt())); + fts.fill("cpfcandlt_e_log_nopuppi", std::log(cand->energy())); + + float drminpfcandsv = btagbtvdeep::mindrsvpfcand(*svs_, &(*cand), std::numeric_limits::infinity()); + fts.fill("cpfcandlt_drminsv", drminpfcandsv); + + // subjets + if (patJet->nSubjetCollections() > 0) { + auto subjets = patJet->subjets(); + std::sort(subjets.begin(), subjets.end(), [](const edm::Ptr &p1, const edm::Ptr &p2) { + return p1->pt() > p2->pt(); + }); // sort by pt + fts.fill("cpfcandlt_drsubjet1", !subjets.empty() ? reco::deltaR(*cand, *subjets.at(0)) : -1); + fts.fill("cpfcandlt_drsubjet2", subjets.size() > 1 ? reco::deltaR(*cand, *subjets.at(1)) : -1); + } else { + fts.fill("cpfcandlt_drsubjet1", -1); + fts.fill("cpfcandlt_drsubjet2", -1); + } + + const reco::Track *trk = nullptr; + if (packed_cand) { + trk = packed_cand->bestTrack(); + } else if (reco_cand && useTrackProperties(reco_cand)) { + trk = reco_cand->bestTrack(); + } + if (trk) { + fts.fill("cpfcandlt_normchi2", std::floor(trk->normalizedChi2())); + + // track covariance + auto cov = [&](unsigned i, unsigned j) { return trk->covariance(i, j); }; + fts.fill("cpfcandlt_dptdpt", cov(0, 0)); + fts.fill("cpfcandlt_detadeta", cov(1, 1)); + fts.fill("cpfcandlt_dphidphi", cov(2, 2)); + fts.fill("cpfcandlt_dxydxy", cov(3, 3)); + fts.fill("cpfcandlt_dzdz", cov(4, 4)); + fts.fill("cpfcandlt_dxydz", cov(3, 4)); + fts.fill("cpfcandlt_dphidxy", cov(2, 3)); + fts.fill("cpfcandlt_dlambdadz", cov(1, 4)); + + trkinfo.buildTrackInfo(&(*cand), jet_dir, jet_ref_track_dir, *pv_); + fts.fill("cpfcandlt_btagEtaRel", trkinfo.getTrackEtaRel()); + fts.fill("cpfcandlt_btagPtRatio", trkinfo.getTrackPtRatio()); + fts.fill("cpfcandlt_btagPParRatio", trkinfo.getTrackPParRatio()); + fts.fill("cpfcandlt_btagSip2dVal", ip_sign * trkinfo.getTrackSip2dVal()); + fts.fill("cpfcandlt_btagSip2dSig", ip_sign * trkinfo.getTrackSip2dSig()); + fts.fill("cpfcandlt_btagSip3dVal", ip_sign * trkinfo.getTrackSip3dVal()); + fts.fill("cpfcandlt_btagSip3dSig", ip_sign * trkinfo.getTrackSip3dSig()); + fts.fill("cpfcandlt_btagJetDistVal", trkinfo.getTrackJetDistVal()); + + fts.fill("cpfcandlt_pixelBarrelLayersWithMeasurement", trk->hitPattern().pixelBarrelLayersWithMeasurement()); + fts.fill("cpfcandlt_pixelEndcapLayersWithMeasurement", trk->hitPattern().pixelEndcapLayersWithMeasurement()); + fts.fill("cpfcandlt_stripTIBLayersWithMeasurement", trk->hitPattern().stripTIBLayersWithMeasurement()); + fts.fill("cpfcandlt_stripTIDLayersWithMeasurement", trk->hitPattern().stripTIDLayersWithMeasurement()); + fts.fill("cpfcandlt_stripTOBLayersWithMeasurement", trk->hitPattern().stripTOBLayersWithMeasurement()); + fts.fill("cpfcandlt_stripTECLayersWithMeasurement", trk->hitPattern().stripTECLayersWithMeasurement()); + + } else { + fts.fill("cpfcandlt_normchi2", 999); + + fts.fill("cpfcandlt_dptdpt", 0); + fts.fill("cpfcandlt_detadeta", 0); + fts.fill("cpfcandlt_dphidphi", 0); + fts.fill("cpfcandlt_dxydxy", 0); + fts.fill("cpfcandlt_dzdz", 0); + fts.fill("cpfcandlt_dxydz", 0); + fts.fill("cpfcandlt_dphidxy", 0); + fts.fill("cpfcandlt_dlambdadz", 0); + + fts.fill("cpfcandlt_btagEtaRel", 0); + fts.fill("cpfcandlt_btagPtRatio", 0); + fts.fill("cpfcandlt_btagPParRatio", 0); + fts.fill("cpfcandlt_btagSip2dVal", 0); + fts.fill("cpfcandlt_btagSip2dSig", 0); + fts.fill("cpfcandlt_btagSip3dVal", 0); + fts.fill("cpfcandlt_btagSip3dSig", 0); + fts.fill("cpfcandlt_btagJetDistVal", 0); + + fts.fill("cpfcandlt_pixelBarrelLayersWithMeasurement", 0); + fts.fill("cpfcandlt_pixelEndcapLayersWithMeasurement", 0); + fts.fill("cpfcandlt_stripTIBLayersWithMeasurement", 0); + fts.fill("cpfcandlt_stripTIDLayersWithMeasurement", 0); + fts.fill("cpfcandlt_stripTOBLayersWithMeasurement", 0); + fts.fill("cpfcandlt_stripTECLayersWithMeasurement", 0); + } + + // pixel hits pattern variables + } + + // fill neutral candidate features + for (const auto &cand : npfPtrs) { + const auto *packed_cand = dynamic_cast(&(*cand)); + const auto *reco_cand = dynamic_cast(&(*cand)); + + if (!include_neutrals_ && + ((packed_cand && !packed_cand->hasTrackDetails()) || (reco_cand && !useTrackProperties(reco_cand)))) + continue; + + auto candP4 = use_puppiP4_ ? puppi_wgt_cache.at(cand) * cand->p4() : cand->p4(); + if (packed_cand) { + float hcal_fraction = 0.; + if (packed_cand->pdgId() == 1 || packed_cand->pdgId() == 130) { + hcal_fraction = packed_cand->hcalFraction(); + } else if (packed_cand->isIsolatedChargedHadron()) { + hcal_fraction = packed_cand->rawHcalFraction(); + } + + fts.fill("npfcand_hcalFrac", hcal_fraction); + + fts.fill("npfcand_isGamma", std::abs(packed_cand->pdgId()) == 22); + fts.fill("npfcand_isNeutralHad", std::abs(packed_cand->pdgId()) == 130); + + } else if (reco_cand) { + fts.fill("npfcand_hcalFrac", reco_cand->hcalEnergy() / (reco_cand->ecalEnergy() + reco_cand->hcalEnergy())); + + fts.fill("npfcand_isGamma", std::abs(reco_cand->pdgId()) == 22); + fts.fill("npfcand_isNeutralHad", std::abs(reco_cand->pdgId()) == 130); + } + + // basic kinematics + fts.fill("npfcand_px", candP4.px()); + fts.fill("npfcand_py", candP4.py()); + fts.fill("npfcand_pz", candP4.pz()); + fts.fill("npfcand_energy", candP4.energy()); + + fts.fill("npfcand_puppiw", puppi_wgt_cache.at(cand)); + fts.fill("npfcand_phirel", reco::deltaPhi(candP4, jet)); + fts.fill("npfcand_etarel", etasign * (candP4.eta() - jet.eta())); + fts.fill("npfcand_deltaR", reco::deltaR(candP4, jet)); + fts.fill("npfcand_abseta", std::abs(candP4.eta())); + + fts.fill("npfcand_ptrel_log", std::log(candP4.pt() / jet.pt())); + fts.fill("npfcand_ptrel", candP4.pt() / jet.pt()); + fts.fill("npfcand_erel_log", std::log(candP4.energy() / jet.energy())); + fts.fill("npfcand_erel", candP4.energy() / jet.energy()); + fts.fill("npfcand_pt_log", std::log(candP4.pt())); + + fts.fill("npfcand_mask", 1); + fts.fill("npfcand_pt_log_nopuppi", std::log(cand->pt())); + fts.fill("npfcand_e_log_nopuppi", std::log(cand->energy())); + } +} + +void GlobalParticleTransformerAK8TagInfoProducer::fillSVFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet) { + std::vector jetSVs; + for (const auto &sv : *svs_) { + if (reco::deltaR2(sv, jet) < jet_radius_ * jet_radius_) { + jetSVs.push_back(&sv); + } + } + // sort by dxy significance + std::sort(jetSVs.begin(), + jetSVs.end(), + [&](const reco::VertexCompositePtrCandidate *sva, const reco::VertexCompositePtrCandidate *svb) { + return sv_vertex_comparator(*sva, *svb, *pv_); + }); + + // reserve space + for (const auto &name : sv_features_) { + fts.reserve(name, jetSVs.size()); + } + + const float etasign = jet.eta() > 0 ? 1 : -1; + + for (const auto *sv : jetSVs) { + // basic kinematics + fts.fill("sv_mask", 1); + + fts.fill("sv_px", sv->px()); + fts.fill("sv_py", sv->py()); + fts.fill("sv_pz", sv->pz()); + fts.fill("sv_energy", sv->energy()); + + fts.fill("sv_phirel", reco::deltaPhi(*sv, jet)); + fts.fill("sv_etarel", etasign * (sv->eta() - jet.eta())); + fts.fill("sv_deltaR", reco::deltaR(*sv, jet)); + fts.fill("sv_abseta", std::abs(sv->eta())); + fts.fill("sv_mass", sv->mass()); + + fts.fill("sv_ptrel_log", std::log(sv->pt() / jet.pt())); + fts.fill("sv_ptrel", sv->pt() / jet.pt()); + fts.fill("sv_erel_log", std::log(sv->energy() / jet.energy())); + fts.fill("sv_erel", sv->energy() / jet.energy()); + fts.fill("sv_pt_log", std::log(sv->pt())); + fts.fill("sv_pt", sv->pt()); + + // sv properties + fts.fill("sv_ntracks", sv->numberOfDaughters()); + fts.fill("sv_normchi2", sv->vertexNormalizedChi2()); + + const auto &dxy = vertexDxy(*sv, *pv_); + fts.fill("sv_dxy", dxy.value()); + fts.fill("sv_dxysig", dxy.significance()); + + const auto &d3d = vertexD3d(*sv, *pv_); + fts.fill("sv_d3d", d3d.value()); + fts.fill("sv_d3dsig", d3d.significance()); + + fts.fill("sv_costhetasvpv", (flip_ip_sign_ ? -1.f : 1.f) * vertexDdotP(*sv, *pv_)); + } +} + +// define this as a plug-in +DEFINE_FWK_MODULE(GlobalParticleTransformerAK8TagInfoProducer); diff --git a/RecoBTag/ONNXRuntime/python/pfGlobalParticleTransformerAK8_cff.py b/RecoBTag/ONNXRuntime/python/pfGlobalParticleTransformerAK8_cff.py new file mode 100644 index 0000000000000..eb63294dccbf5 --- /dev/null +++ b/RecoBTag/ONNXRuntime/python/pfGlobalParticleTransformerAK8_cff.py @@ -0,0 +1,34 @@ +import FWCore.ParameterSet.Config as cms + +from RecoBTag.FeatureTools.pfGlobalParticleTransformerAK8TagInfos_cfi import pfGlobalParticleTransformerAK8TagInfos as _pfGlobalParticleTransformerAK8TagInfos +from RecoBTag.ONNXRuntime.boostedJetONNXJetTagsProducer_cfi import boostedJetONNXJetTagsProducer + +pfGlobalParticleTransformerAK8TagInfos = _pfGlobalParticleTransformerAK8TagInfos.clone( + use_puppiP4 = False +) + +pfGlobalParticleTransformerAK8JetTags = boostedJetONNXJetTagsProducer.clone( + src = 'pfGlobalParticleTransformerAK8TagInfos', + preprocess_json = 'RecoBTag/Combined/data/GlobalParticleTransformerAK8/PUPPI/V03/preprocess.json', + model_path = 'RecoBTag/Combined/data/GlobalParticleTransformerAK8/PUPPI/V03/model.onnx', + flav_names = [ + 'probXbb', 'probXcc', 'probXcs', 'probXqq', 'probXtauhtaue', 'probXtauhtaum', 'probXtauhtauh', 'probXWW4q', 'probXWW3q', 'probXWWqqev', 'probXWWqqmv', 'probTopbWqq', 'probTopbWq', 'probTopbWev', 'probTopbWmv', 'probTopbWtauhv', 'probQCD', 'massCorrX2p', 'massCorrGeneric', 'probWithMassTopvsQCD', 'probWithMassWvsQCD', 'probWithMassZvsQCD' + ] + ['hidNeuron' + str(i).zfill(3) for i in range(256)], + debugMode = False, +) + +from CommonTools.PileupAlgos.Puppi_cff import puppi +from CommonTools.RecoAlgos.primaryVertexAssociation_cfi import primaryVertexAssociation + +# This task is not used, useful only if we run it from RECO jets (RECO/AOD) +pfGlobalParticleTransformerAK8Task = cms.Task(puppi, primaryVertexAssociation, pfGlobalParticleTransformerAK8TagInfos, pfGlobalParticleTransformerAK8JetTags) + +# declare all the discriminators + +# probs +_pfGlobalParticleTransformerAK8JetTagsProbs = ['pfGlobalParticleTransformerAK8JetTags:' + flav_name for flav_name in pfGlobalParticleTransformerAK8JetTags.flav_names] + +# meta-taggers +_pfGlobalParticleTransformerAK8JetTagsMetaDiscrs = [] + +_pfGlobalParticleTransformerAK8JetTagsAll = _pfGlobalParticleTransformerAK8JetTagsProbs + _pfGlobalParticleTransformerAK8JetTagsMetaDiscrs diff --git a/RecoBTag/ONNXRuntime/test/test_globalpart_cfg.py b/RecoBTag/ONNXRuntime/test/test_globalpart_cfg.py new file mode 100644 index 0000000000000..a2a2fc28d32ed --- /dev/null +++ b/RecoBTag/ONNXRuntime/test/test_globalpart_cfg.py @@ -0,0 +1,70 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.PatAlgos.tools.helpers import getPatAlgosToolsTask + +from FWCore.ParameterSet.VarParsing import VarParsing +options = VarParsing('analysis') +options.inputFiles = '/store/mc/Run3Summer23BPixMiniAODv4/TTtoLNu2Q_TuneCP5_13p6TeV_powheg-pythia8/MINIAODSIM/130X_mcRun3_2023_realistic_postBPix_v2-v3/2520000/00488681-4f49-4bdc-89e6-198da9e42a17.root' +options.maxEvents = 10 +options.parseArguments() + +process = cms.Process('PATtest') + +## MessageLogger +process.load("FWCore.MessageLogger.MessageLogger_cfi") +process.MessageLogger.cerr.FwkReport.reportEvery = 1 + + +## Options and Output Report +process.options = cms.untracked.PSet( wantSummary = cms.untracked.bool(True) ) + +## Source +process.source = cms.Source("PoolSource", + fileNames=cms.untracked.vstring(options.inputFiles) +) +## Maximal Number of Events +process.maxEvents = cms.untracked.PSet(input=cms.untracked.int32(options.maxEvents)) + +## Geometry and Detector Conditions (needed for a few patTuple production steps) +process.load("Configuration.Geometry.GeometryRecoDB_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:phase1_2023_realistic') +process.load("Configuration.StandardSequences.MagneticField_cff") + +## Output Module Configuration (expects a path 'p') +from PhysicsTools.PatAlgos.patEventContent_cff import patEventContentNoCleaning +process.out = cms.OutputModule("PoolOutputModule", + fileName = cms.untracked.string('patTuple.root'), + ## save only events passing the full path + #SelectEvents = cms.untracked.PSet( SelectEvents = cms.vstring('p') ), + ## save PAT output; you need a '*' to unpack the list of commands + ## 'patEventContent' + outputCommands = cms.untracked.vstring('drop *', *patEventContentNoCleaning ) + ) + +patAlgosToolsTask = getPatAlgosToolsTask(process) +process.outpath = cms.EndPath(process.out, patAlgosToolsTask) + +## and add them to the event content +from PhysicsTools.PatAlgos.tools.jetTools import updateJetCollection +from RecoBTag.ONNXRuntime.pfGlobalParticleTransformerAK8_cff import _pfGlobalParticleTransformerAK8JetTagsProbs as pfGlobalParticleTransformerAK8JetTagsProbs + +updateJetCollection( + process, + jetSource = cms.InputTag('slimmedJetsAK8'), + pvSource = cms.InputTag('offlineSlimmedPrimaryVertices'), + svSource = cms.InputTag('slimmedSecondaryVertices'), + rParam = 0.8, + jetCorrections = ('AK8PFPuppi', cms.vstring(['L2Relative', 'L3Absolute']), 'None'), + btagDiscriminators = pfGlobalParticleTransformerAK8JetTagsProbs + ) + +from Configuration.EventContent.EventContent_cff import MINIAODSIMEventContent +process.out.outputCommands.append('keep *_slimmedJetsAK8*_*_*') +process.out.outputCommands.append('keep *_offlineSlimmedPrimaryVertices*_*_*') +process.out.outputCommands.append('keep *_slimmedSecondaryVertices*_*_*') +process.out.outputCommands.append('keep *_selectedPatJets*_*_*') +process.out.outputCommands.append('keep *_selectedUpdatedPatJets*_*_*') +process.out.outputCommands.append('keep *_updatedPatJets*_*_*') + +process.out.fileName = 'test_globalpart_MINIAODSIM_noragged.root'