diff --git a/Configuration/PyReleaseValidation/python/relval_pileup.py b/Configuration/PyReleaseValidation/python/relval_pileup.py
index be7d1e352a108..1b2ce2e5bd18a 100644
--- a/Configuration/PyReleaseValidation/python/relval_pileup.py
+++ b/Configuration/PyReleaseValidation/python/relval_pileup.py
@@ -40,6 +40,8 @@
workflows[25202.1]=['',['TTbar_13','DIGIUP15APVSimu_PU25','RECOUP15_PU25','HARVESTUP15_PU25']]
workflows[25202.2]=['',['TTbar_13','DIGIUP15APVSimu_PU25','RECOUP15_PU25_HIPM','HARVESTUP15_PU25']]
workflows[25202.15]=['',['TTbar_13','DIGIUP15_PU25','RECOUP15_PU25','HARVESTUP15_PU25','NANOUP15MC_PU25_JME']]
+workflows[25202.16]=['',['TTbar_13','DIGIUP15_PU25','RECOUP15_PU25','HARVESTUP15_PU25','NANOUP15MC_PU25_JMEAK8PF']]
+workflows[25202.17]=['',['TTbar_13','DIGIUP15_PU25','RECOUP15_PU25','HARVESTUP15_PU25','NANOUP15MC_PU25_JMEPF']]
workflows[25203]=['',['H125GGgluonfusion_13','DIGIUP15_PU25','RECOUP15_PU25','HARVESTUP15_PU25','NANOUP15_PU25']]
workflows[25204]=['',['QQH1352T_13','DIGIUP15_PU25','RECOUP15_PU25','HARVESTUP15_PU25']]
workflows[25205]=['',['ZTT_13','DIGIUP15_PU25','RECOUP15_PU25','HARVESTUP15_PU25','NANOUP15_PU25']]
diff --git a/Configuration/PyReleaseValidation/python/relval_steps.py b/Configuration/PyReleaseValidation/python/relval_steps.py
index 48f983da0ea1b..f3efa69f26e51 100644
--- a/Configuration/PyReleaseValidation/python/relval_steps.py
+++ b/Configuration/PyReleaseValidation/python/relval_steps.py
@@ -3135,6 +3135,10 @@ def gen2021HiMix(fragment,howMuch):
steps['NANOUP15Had']=merge([{'--filein':'file:step4_inMINIAODSIM.root'},steps['NANOUP15']])
steps['NANOUP15MC_PU25_JME']=merge([{'--customise':'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomNanoAOD_MC'},steps['NANOUP15']])
steps['NANOUP15Data_PU25_JME']=merge([{'--customise':'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomNanoAOD_Data','--data':''},steps['NANOUP15']])
+steps['NANOUP15MC_PU25_JMEAK8PF']=merge([{'--customise':'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomAK8PFNanoAOD_MC'},steps['NANOUP15']])
+steps['NANOUP15Data_PU25_JMEAK8PF']=merge([{'--customise':'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomAK8PFNanoAOD_Data','--data':''},steps['NANOUP15']])
+steps['NANOUP15MC_PU25_JMEPF']=merge([{'--customise':'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomPFNanoAOD_MC'},steps['NANOUP15']])
+steps['NANOUP15Data_PU25_JMEPF']=merge([{'--customise':'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomPFNanoAOD_Data','--data':''},steps['NANOUP15']])
steps['NANOUP17Had']=merge([{'--filein':'file:step4_inMINIAODSIM.root'},steps['NANOUP17']])
steps['NANOUP18'] = merge([{'--conditions': 'auto:phase1_2018_realistic', '--era': 'Run2_2018','-n':'10', '--filein':'file:step3_inMINIAODSIM.root', '--nThreads':'2'}, stepNanoEDMMCProd ])
steps['NANOUP18Had']=merge([{'--filein':'file:step4_inMINIAODSIM.root'},steps['NANOUP18']])
diff --git a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
index 416152297f093..7747f954b9794 100644
--- a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
+++ b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
@@ -1,3 +1,4 @@
+
from copy import deepcopy
from collections import OrderedDict
import six
@@ -646,6 +647,36 @@ def condition(self, fragment, stepList, key, hasHarvest):
offset = 0.15,
)
+class UpgradeWorkflow_JMEAK8PFNano(UpgradeWorkflow):
+ def setup_(self, step, stepName, stepDict, k, properties):
+ if 'Nano' in step:
+ stepDict[stepName][k] = merge([{'--customise': 'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomAK8PFNanoAOD_MC'}, stepDict[step][k]])
+ def condition(self, fragment, stepList, key, hasHarvest):
+ return fragment=="TTbar_13" and ('2017' in key or '2018' in key)
+upgradeWFs['JMEAK8PFNano'] = UpgradeWorkflow_JMEAK8PFNano(
+ steps = [
+ 'Nano',
+ ],
+ PU = [],
+ suffix = '_JMEAK8PFNano',
+ offset = 0.16,
+)
+
+class UpgradeWorkflow_JMEPFNano(UpgradeWorkflow):
+ def setup_(self, step, stepName, stepDict, k, properties):
+ if 'Nano' in step:
+ stepDict[stepName][k] = merge([{'--customise': 'PhysicsTools/NanoAOD/custom_jme_cff.PrepJMECustomPFNanoAOD_MC'}, stepDict[step][k]])
+ def condition(self, fragment, stepList, key, hasHarvest):
+ return fragment=="TTbar_13" and ('2017' in key or '2018' in key)
+upgradeWFs['JMEPFNano'] = UpgradeWorkflow_JMEPFNano(
+ steps = [
+ 'Nano',
+ ],
+ PU = [],
+ suffix = '_JMEPFNano',
+ offset = 0.17,
+)
+
# common operations for aging workflows
class UpgradeWorkflowAging(UpgradeWorkflow):
diff --git a/PhysicsTools/NanoAOD/plugins/BuildFile.xml b/PhysicsTools/NanoAOD/plugins/BuildFile.xml
index 8d4e3269834b9..7706af7b2c9d5 100644
--- a/PhysicsTools/NanoAOD/plugins/BuildFile.xml
+++ b/PhysicsTools/NanoAOD/plugins/BuildFile.xml
@@ -8,6 +8,8 @@
+
+
diff --git a/PhysicsTools/NanoAOD/plugins/JetConstituentTableProducer.cc b/PhysicsTools/NanoAOD/plugins/JetConstituentTableProducer.cc
new file mode 100644
index 0000000000000..0a618bb15774b
--- /dev/null
+++ b/PhysicsTools/NanoAOD/plugins/JetConstituentTableProducer.cc
@@ -0,0 +1,255 @@
+#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/VertexReco/interface/VertexFwd.h"
+
+#include "DataFormats/PatCandidates/interface/Jet.h"
+#include "DataFormats/PatCandidates/interface/PackedCandidate.h"
+
+#include "DataFormats/Candidate/interface/CandidateFwd.h"
+
+#include "RecoBTag/FeatureTools/interface/TrackInfoBuilder.h"
+#include "TrackingTools/Records/interface/TransientTrackRecord.h"
+
+#include "DataFormats/BTauReco/interface/TrackIPTagInfo.h"
+#include "DataFormats/BTauReco/interface/SecondaryVertexTagInfo.h"
+#include "RecoBTag/FeatureTools/interface/deep_helpers.h"
+#include "DataFormats/Candidate/interface/VertexCompositePtrCandidate.h"
+using namespace btagbtvdeep;
+
+#include "CommonTools/Utils/interface/StringCutObjectSelector.h"
+#include "DataFormats/NanoAOD/interface/FlatTable.h"
+#include "DataFormats/NanoAOD/interface/MergeableCounterTable.h"
+
+template
+class JetConstituentTableProducer : public edm::stream::EDProducer<> {
+public:
+ explicit JetConstituentTableProducer(const edm::ParameterSet &);
+ ~JetConstituentTableProducer() override;
+
+ static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
+
+private:
+ void produce(edm::Event &, const edm::EventSetup &) override;
+
+ typedef reco::VertexCollection VertexCollection;
+ //=====
+ typedef reco::VertexCompositePtrCandidateCollection SVCollection;
+
+ //const std::string name_;
+ const std::string name_;
+ const std::string nameSV_;
+ const bool readBtag_;
+ const double jet_radius_;
+
+ edm::EDGetTokenT> jet_token_;
+ edm::EDGetTokenT vtx_token_;
+ edm::EDGetTokenT cand_token_;
+ edm::EDGetTokenT sv_token_;
+
+ edm::Handle vtxs_;
+ edm::Handle cands_;
+ edm::Handle svs_;
+ edm::ESHandle track_builder_;
+
+ const reco::Vertex *pv_ = nullptr;
+};
+
+//
+// constructors and destructor
+//
+template
+JetConstituentTableProducer::JetConstituentTableProducer(const edm::ParameterSet &iConfig)
+ : //name_(iConfig.getParameter("name")),
+ name_(iConfig.getParameter("name")),
+ nameSV_(iConfig.getParameter("nameSV")),
+ readBtag_(iConfig.getParameter("readBtag")),
+ jet_radius_(iConfig.getParameter("jet_radius")),
+ jet_token_(consumes>(iConfig.getParameter("jets"))),
+ vtx_token_(consumes(iConfig.getParameter("vertices"))),
+ cand_token_(consumes(iConfig.getParameter("candidates"))),
+ sv_token_(consumes(iConfig.getParameter("secondary_vertices"))) {
+ //produces(name_);
+ produces(name_);
+ produces(nameSV_);
+ produces>();
+}
+
+template
+JetConstituentTableProducer::~JetConstituentTableProducer() {}
+
+template
+void JetConstituentTableProducer::produce(edm::Event &iEvent, const edm::EventSetup &iSetup) {
+ // elements in all these collections must have the same order!
+ auto outCands = std::make_unique>();
+ auto outSVs = std::make_unique>();
+ std::vector jetIdx_pf, jetIdx_sv, candIdx;
+ //std::vector jetIdx, candIdx;
+ // PF Cands
+ std::vector btagEtaRel, btagPtRatio, btagPParRatio, btagSip3dVal, btagSip3dSig, btagJetDistVal;
+ // Secondary vertices
+ std::vector sv_mass, sv_pt, sv_ntracks, sv_chi2, sv_normchi2, sv_dxy, sv_dxysig, sv_d3d, sv_d3dsig,
+ sv_costhetasvpv;
+ std::vector sv_ptrel, sv_phirel, sv_deltaR, sv_enratio;
+
+ auto jets = iEvent.getHandle(jet_token_);
+ iEvent.getByToken(vtx_token_, vtxs_);
+ iEvent.getByToken(cand_token_, cands_);
+ iEvent.getByToken(sv_token_, svs_);
+
+ if (readBtag_) {
+ iSetup.get().get("TransientTrackBuilder", track_builder_);
+ }
+
+ for (unsigned i_jet = 0; i_jet < jets->size(); ++i_jet) {
+ const auto &jet = jets->at(i_jet);
+ math::XYZVector jet_dir = jet.momentum().Unit();
+ GlobalVector jet_ref_track_dir(jet.px(), jet.py(), jet.pz());
+
+ pv_ = &vtxs_->at(0);
+ //////////////////////
+ // Secondary Vertices
+ 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_);
+ });
+
+ for (const auto &sv : jetSVs) {
+ outSVs->push_back(sv);
+ jetIdx_sv.push_back(i_jet);
+ if (readBtag_ && !vtxs_->empty()) {
+ // Jet independent
+ sv_mass.push_back(sv->mass());
+ sv_pt.push_back(sv->pt());
+
+ sv_ntracks.push_back(sv->numberOfDaughters());
+ sv_chi2.push_back(sv->vertexChi2());
+ sv_normchi2.push_back(catch_infs_and_bound(sv->vertexChi2() / sv->vertexNdof(), 1000, -1000, 1000));
+ const auto &dxy_meas = vertexDxy(*sv, *pv_);
+ sv_dxy.push_back(dxy_meas.value());
+ sv_dxysig.push_back(catch_infs_and_bound(dxy_meas.value() / dxy_meas.error(), 0, -1, 800));
+ const auto &d3d_meas = vertexD3d(*sv, *pv_);
+ sv_d3d.push_back(d3d_meas.value());
+ sv_d3dsig.push_back(catch_infs_and_bound(d3d_meas.value() / d3d_meas.error(), 0, -1, 800));
+ sv_costhetasvpv.push_back(vertexDdotP(*sv, *pv_));
+ // Jet related
+ sv_ptrel.push_back(sv->pt() / jet.pt());
+ sv_phirel.push_back(reco::deltaPhi(*sv, jet));
+ sv_deltaR.push_back(catch_infs_and_bound(std::fabs(reco::deltaR(*sv, jet_dir)) - 0.5, 0, -2, 0));
+ sv_enratio.push_back(sv->energy() / jet.energy());
+ }
+ }
+
+ // PF Cands
+ std::vector const &daughters = jet.daughterPtrVector();
+
+ for (const auto &cand : daughters) {
+ auto candPtrs = cands_->ptrs();
+ auto candInNewList = std::find(candPtrs.begin(), candPtrs.end(), cand);
+ if (candInNewList == candPtrs.end()) {
+ //std::cout << "Cannot find candidate : " << cand.id() << ", " << cand.key() << ", pt = " << cand->pt() << std::endl;
+ continue;
+ }
+ outCands->push_back(cand);
+ jetIdx_pf.push_back(i_jet);
+ candIdx.push_back(candInNewList - candPtrs.begin());
+ if (readBtag_ && !vtxs_->empty()) {
+ if (cand.isNull())
+ continue;
+ auto const *packedCand = dynamic_cast(cand.get());
+ if (packedCand == nullptr)
+ continue;
+ if (packedCand && packedCand->hasTrackDetails()) {
+ btagbtvdeep::TrackInfoBuilder trkinfo(track_builder_);
+ trkinfo.buildTrackInfo(&(*packedCand), jet_dir, jet_ref_track_dir, vtxs_->at(0));
+ btagEtaRel.push_back(trkinfo.getTrackEtaRel());
+ btagPtRatio.push_back(trkinfo.getTrackPtRatio());
+ btagPParRatio.push_back(trkinfo.getTrackPParRatio());
+ btagSip3dVal.push_back(trkinfo.getTrackSip3dVal());
+ btagSip3dSig.push_back(trkinfo.getTrackSip3dSig());
+ btagJetDistVal.push_back(trkinfo.getTrackJetDistVal());
+ } else {
+ btagEtaRel.push_back(0);
+ btagPtRatio.push_back(0);
+ btagPParRatio.push_back(0);
+ btagSip3dVal.push_back(0);
+ btagSip3dSig.push_back(0);
+ btagJetDistVal.push_back(0);
+ }
+ }
+ } // end jet loop
+ }
+
+ auto candTable = std::make_unique(outCands->size(), name_, false);
+ // We fill from here only stuff that cannot be created with the SimpleFlatTableProducer
+ candTable->addColumn("candIdx", candIdx, "Index in the candidate list");
+ candTable->addColumn("jetIdx", jetIdx_pf, "Index of the parent jet");
+ if (readBtag_) {
+ candTable->addColumn("btagEtaRel", btagEtaRel, "btagEtaRel", 10);
+ candTable->addColumn("btagPtRatio", btagPtRatio, "btagPtRatio", 10);
+ candTable->addColumn("btagPParRatio", btagPParRatio, "btagPParRatio", 10);
+ candTable->addColumn("btagSip3dVal", btagSip3dVal, "btagSip3dVal", 10);
+ candTable->addColumn("btagSip3dSig", btagSip3dSig, "btagSip3dSig", 10);
+ candTable->addColumn("btagJetDistVal", btagJetDistVal, "btagJetDistVal", 10);
+ }
+ iEvent.put(std::move(candTable), name_);
+
+ // SV table
+ auto svTable = std::make_unique(outSVs->size(), nameSV_, false);
+ // We fill from here only stuff that cannot be created with the SimpleFlatTnameableProducer
+ svTable->addColumn("jetIdx", jetIdx_sv, "Index of the parent jet");
+ if (readBtag_) {
+ svTable->addColumn("mass", sv_mass, "SV mass", 10);
+ svTable->addColumn("pt", sv_pt, "SV pt", 10);
+ svTable->addColumn("ntracks", sv_ntracks, "Number of trakcs associated to SV", 10);
+ svTable->addColumn("chi2", sv_chi2, "chi2", 10);
+ svTable->addColumn("normchi2", sv_normchi2, "chi2/ndof", 10);
+ svTable->addColumn("dxy", sv_dxy, "", 10);
+ svTable->addColumn("dxysig", sv_dxysig, "", 10);
+ svTable->addColumn("d3d", sv_d3d, "", 10);
+ svTable->addColumn("d3dsig", sv_d3dsig, "", 10);
+ svTable->addColumn("costhetasvpv", sv_costhetasvpv, "", 10);
+ // Jet related
+ svTable->addColumn("phirel", sv_phirel, "DeltaPhi(sv, jet)", 10);
+ svTable->addColumn("ptrel", sv_ptrel, "pT relative to parent jet", 10);
+ svTable->addColumn("deltaR", sv_deltaR, "dR from parent jet", 10);
+ svTable->addColumn("enration", sv_enratio, "energy relative to parent jet", 10);
+ }
+ iEvent.put(std::move(svTable), nameSV_);
+
+ iEvent.put(std::move(outCands));
+}
+
+template
+void JetConstituentTableProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
+ edm::ParameterSetDescription desc;
+ desc.add("name", "JetPFCands");
+ desc.add("nameSV", "JetSV");
+ desc.add("jet_radius", true);
+ desc.add("readBtag", true);
+ desc.add("jets", edm::InputTag("slimmedJetsAK8"));
+ desc.add("vertices", edm::InputTag("offlineSlimmedPrimaryVertices"));
+ desc.add("candidates", edm::InputTag("packedPFCandidates"));
+ desc.add("secondary_vertices", edm::InputTag("slimmedSecondaryVertices"));
+ descriptions.addWithDefaultLabel(desc);
+}
+
+typedef JetConstituentTableProducer PatJetConstituentTableProducer;
+typedef JetConstituentTableProducer GenJetConstituentTableProducer;
+
+DEFINE_FWK_MODULE(PatJetConstituentTableProducer);
+DEFINE_FWK_MODULE(GenJetConstituentTableProducer);
diff --git a/PhysicsTools/NanoAOD/python/addBTV_cff.py b/PhysicsTools/NanoAOD/python/addBTV_cff.py
new file mode 100644
index 0000000000000..fdd823d1a4797
--- /dev/null
+++ b/PhysicsTools/NanoAOD/python/addBTV_cff.py
@@ -0,0 +1,251 @@
+import FWCore.ParameterSet.Config as cms
+# from PhysicsTools.NanoAOD.common_cff import *
+from PhysicsTools.NanoAOD.common_cff import Var
+from PhysicsTools.NanoAOD.jets_cff import jetTable, fatJetTable, subJetTable
+from PhysicsTools.PatAlgos.tools.jetTools import updateJetCollection
+
+
+def update_jets_AK4(process):
+ # Based on ``nanoAOD_addDeepInfo``
+ # in https://github.com/cms-sw/cmssw/blob/master/PhysicsTools/NanoAOD/python/nano_cff.py
+ _btagDiscriminators = [
+ 'pfJetProbabilityBJetTags',
+ 'pfDeepCSVJetTags:probb',
+ 'pfDeepCSVJetTags:probc',
+ 'pfDeepCSVJetTags:probbb',
+ 'pfDeepCSVJetTags:probudsg',
+ ]
+ updateJetCollection(
+ process,
+ jetSource=cms.InputTag('slimmedJets'),
+ jetCorrections=('AK4PFchs',
+ cms.vstring(
+ ['L1FastJet', 'L2Relative', 'L3Absolute',
+ 'L2L3Residual']), 'None'),
+ btagDiscriminators=_btagDiscriminators,
+ postfix='WithDeepInfo',
+ )
+ process.load("Configuration.StandardSequences.MagneticField_cff")
+ process.jetCorrFactorsNano.src = "selectedUpdatedPatJetsWithDeepInfo"
+ process.updatedJets.jetSource = "selectedUpdatedPatJetsWithDeepInfo"
+ return process
+
+
+def update_jets_AK8(process):
+ # Based on ``nanoAOD_addDeepInfoAK8``
+ # in https://github.com/cms-sw/cmssw/blob/master/PhysicsTools/NanoAOD/python/nano_cff.py
+ _btagDiscriminators = [
+ 'pfJetProbabilityBJetTags',
+ 'pfDeepCSVJetTags:probb',
+ 'pfDeepCSVJetTags:probc',
+ 'pfDeepCSVJetTags:probbb',
+ 'pfDeepCSVJetTags:probudsg',
+ 'pfMassIndependentDeepDoubleBvLV2JetTags:probHbb',
+ 'pfMassIndependentDeepDoubleCvLV2JetTags:probHcc',
+ 'pfMassIndependentDeepDoubleCvBV2JetTags:probHcc',
+ ]
+ updateJetCollection(
+ process,
+ jetSource=cms.InputTag('slimmedJetsAK8'),
+ pvSource=cms.InputTag('offlineSlimmedPrimaryVertices'),
+ svSource=cms.InputTag('slimmedSecondaryVertices'),
+ rParam=0.8,
+ jetCorrections=('AK8PFPuppi',
+ cms.vstring([
+ 'L1FastJet', 'L2Relative', 'L3Absolute',
+ 'L2L3Residual'
+ ]), 'None'),
+ btagDiscriminators=_btagDiscriminators,
+ postfix='AK8WithDeepInfo',
+ # this should work but doesn't seem to enable the tag info with addTagInfos
+ # btagInfos=['pfDeepDoubleXTagInfos'],
+ printWarning=False)
+ process.jetCorrFactorsAK8.src = "selectedUpdatedPatJetsAK8WithDeepInfo"
+ process.updatedJetsAK8.jetSource = "selectedUpdatedPatJetsAK8WithDeepInfo"
+ # add DeepDoubleX taginfos
+ process.updatedPatJetsTransientCorrectedAK8WithDeepInfo.tagInfoSources.append(cms.InputTag("pfDeepDoubleXTagInfosAK8WithDeepInfo"))
+ process.updatedPatJetsTransientCorrectedAK8WithDeepInfo.addTagInfos = cms.bool(True)
+ return process
+
+
+def update_jets_AK8_subjet(process):
+ # Based on ``nanoAOD_addDeepInfoAK8``
+ # in https://github.com/cms-sw/cmssw/blob/master/PhysicsTools/NanoAOD/python/nano_cff.py
+ # and https://github.com/alefisico/RecoBTag-PerformanceMeasurements/blob/10_2_X_boostedCommissioning/test/runBTagAnalyzer_cfg.py
+ _btagDiscriminators = [
+ 'pfJetProbabilityBJetTags',
+ 'pfDeepCSVJetTags:probb',
+ 'pfDeepCSVJetTags:probc',
+ 'pfDeepCSVJetTags:probbb',
+ 'pfDeepCSVJetTags:probudsg',
+ ]
+ updateJetCollection(
+ process,
+ labelName='SoftDropSubjetsPF',
+ jetSource=cms.InputTag("slimmedJetsAK8PFPuppiSoftDropPacked", "SubJets"),
+ jetCorrections=('AK4PFPuppi',
+ ['L2Relative', 'L3Absolute'], 'None'),
+ btagDiscriminators=list(_btagDiscriminators),
+ explicitJTA=True, # needed for subjet b tagging
+ svClustering=False, # needed for subjet b tagging (IMPORTANT: Needs to be set to False to disable ghost-association which does not work with slimmed jets)
+ fatJets=cms.InputTag('slimmedJetsAK8'), # needed for subjet b tagging
+ rParam=0.8, # needed for subjet b tagging
+ postfix='AK8SubjetsWithDeepInfo')
+
+ process.subJetTable.src = 'updatedPatJetsTransientCorrectedSoftDropSubjetsPFAK8SubjetsWithDeepInfo' ### VERY LONG NAME!!! :P
+ return process
+
+
+def get_DDX_vars():
+ # retreive 27 jet-level features used in double-b and deep double-x taggers
+ # defiend in arXiv:1712.07158
+
+ DDXVars = cms.PSet(
+ DDX_jetNTracks = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.jetNTracks", int, doc="number of tracks associated with the jet"),
+ DDX_jetNSecondaryVertices = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.jetNSecondaryVertices", int, doc="number of SVs associated with the jet"),
+ DDX_tau1_trackEtaRel_0 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_trackEtaRel_0", float, doc="1st smallest track pseudorapidity, relative to the jet axis, associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau1_trackEtaRel_1 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_trackEtaRel_1", float, doc="2nd smallest track pseudorapidity, relative to the jet axis, associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau1_trackEtaRel_2 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_trackEtaRel_2", float, doc="3rd smallest track pseudorapidity, relative to the jet axis, associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau2_trackEtaRel_0 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_trackEtaRel_0", float, doc="1st smallest track pseudorapidity, relative to the jet axis, associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_tau2_trackEtaRel_1 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_trackEtaRel_1", float, doc="2nd smallest track pseudorapidity, relative to the jet axis, associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_tau2_trackEtaRel_3 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_trackEtaRel_2", float, doc="3rd smallest track pseudorapidity, relative to the jet axis, associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_tau1_flightDistance2dSig = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_flightDistance2dSig", float, doc="transverse distance significance between primary and secondary vertex associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau2_flightDistance2dSig = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_flightDistance2dSig", float, doc="transverse distance significance between primary and secondary vertex associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_tau1_vertexDeltaR = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_vertexDeltaR", float, doc="deltaR between the 1st N-subjettiness axis and secondary vertex direction", precision=10),
+ DDX_tau1_vertexEnergyRatio = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_vertexEnergyRatio", float, doc="ratio of energy at secondary vertex over total energy associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau2_vertexEnergyRatio = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_vertexEnergyRatio", float, doc="ratio of energy at secondary vertex over total energy associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_tau1_vertexMass = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_vertexMass", float, doc="mass of track sum at secondary vertex associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau2_vertexMass = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_vertexMass", float, doc="mass of track sum at secondary vertex associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_trackSip2dSigAboveBottom_0 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip2dSigAboveBottom_0", float, doc="track 2D signed impact parameter significance of 1st track lifting mass above bottom", precision=10),
+ DDX_trackSip2dSigAboveBottom_1 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip2dSigAboveBottom_1", float, doc="track 2D signed impact parameter significance of 2nd track lifting mass above bottom", precision=10),
+ DDX_trackSip2dSigAboveCharm = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip2dSigAboveCharm", float, doc="track 2D signed impact parameter significance of 1st track lifting mass above charm", precision=10),
+ DDX_trackSip3dSig_0 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip3dSig_0", float, doc="1st largest track 3D signed impact parameter significance", precision=10),
+ DDX_tau1_trackSip3dSig_0 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_trackSip3dSig_0", float, doc="1st largest track 3D signed impact parameter significance associated to the 1st N-subjettiness axis", precision=10),
+ DDX_tau1_trackSip3dSig_1 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau1_trackSip3dSig_1", float, doc="2nd largest track 3D signed impact parameter significance associated to the 1st N-subjettiness axis", precision=10),
+ DDX_trackSip3dSig_1 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip3dSig_1", float, doc="2nd largest track 3D signed impact parameter significance", precision=10),
+ DDX_tau2_trackSip3dSig_0 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_trackSip3dSig_0", float, doc="1st largest track 3D signed impact parameter significance associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_tau2_trackSip3dSig_1 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.tau2_trackSip3dSig_1", float, doc="2nd largest track 3D signed impact parameter significance associated to the 2nd N-subjettiness axis", precision=10),
+ DDX_trackSip3dSig_2 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip3dSig_2", float, doc="3rd largest track 3D signed impact parameter significance", precision=10),
+ DDX_trackSip3dSig_3 = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.trackSip3dSig_3", float, doc="4th largest track 3D signed impact parameter significance", precision=10),
+ DDX_z_ratio = Var("tagInfo(\'pfDeepDoubleX\').features().tag_info_features.z_ratio", float, doc="z = deltaR(SV0,SV1)*pT(SV1)/m(SV0,SV1), defined in Eq. 7 of arXiv:1712.07158", precision=10)
+ )
+
+ return DDXVars
+
+
+def addBTV(process, runOnMC=False, onlyAK4=False, onlyAK8=False):
+ addAK4 = not onlyAK8
+ addAK8 = not onlyAK4
+
+ if addAK4:
+ process = update_jets_AK4(process)
+ if addAK8:
+ process = update_jets_AK8(process)
+ process = update_jets_AK8_subjet(process)
+
+ process.customizeJetTask = cms.Task()
+ process.schedule.associate(process.customizeJetTask)
+
+ CommonVars = cms.PSet(
+ Proba=Var("bDiscriminator('pfJetProbabilityBJetTags')",
+ float,
+ doc="Jet Probability (Usage:BTV)",
+ precision=10),
+ nBHadrons=Var("jetFlavourInfo().getbHadrons().size()",
+ int,
+ doc="number of b-hadrons"),
+ nCHadrons=Var("jetFlavourInfo().getcHadrons().size()",
+ int,
+ doc="number of c-hadrons"),
+ btagDeepB_b=Var("bDiscriminator('pfDeepCSVJetTags:probb')",
+ float,
+ doc="DeepCSV b tag discriminator",
+ precision=10),
+ btagDeepB_bb=Var("bDiscriminator('pfDeepCSVJetTags:probbb')",
+ float,
+ doc="DeepCSV bb tag discriminator",
+ precision=10),
+ btagDeepL=Var("bDiscriminator('pfDeepCSVJetTags:probudsg')",
+ float,
+ doc="DeepCSV light btag discriminator",
+ precision=10),
+ )
+
+ # AK4
+ process.customJetExtTable = cms.EDProducer(
+ "SimpleCandidateFlatTableProducer",
+ src=jetTable.src,
+ cut=jetTable.cut,
+ name=jetTable.name,
+ doc=jetTable.doc,
+ singleton=cms.bool(False), # the number of entries is variable
+ extension=cms.bool(True), # this is the extension table for Jets
+ variables=cms.PSet(
+ CommonVars,
+ ))
+
+ # AK8
+ process.customFatJetExtTable = cms.EDProducer(
+ "SimpleCandidateFlatTableProducer",
+ src=fatJetTable.src,
+ cut=fatJetTable.cut,
+ name=fatJetTable.name,
+ doc=fatJetTable.doc,
+ singleton=cms.bool(False), # the number of entries is variable
+ extension=cms.bool(True), # this is the extension table for FatJets
+ variables=cms.PSet(
+ CommonVars,
+ cms.PSet(
+ btagDDBvLV2 = Var("bDiscriminator('pfMassIndependentDeepDoubleBvLV2JetTags:probHbb')",float,doc="DeepDoubleX V2 discriminator for H(Z)->bb vs QCD",precision=10),
+ btagDDCvLV2 = Var("bDiscriminator('pfMassIndependentDeepDoubleCvLV2JetTags:probHcc')",float,doc="DeepDoubleX V2 discriminator for H(Z)->cc vs QCD",precision=10),
+ btagDDCvBV2 = Var("bDiscriminator('pfMassIndependentDeepDoubleCvBV2JetTags:probHcc')",float,doc="DeepDoubleX V2 discriminator for H(Z)->cc vs H(Z)->bb",precision=10),
+ ),
+ get_DDX_vars(),
+ ))
+
+ # Subjets
+ process.customSubJetExtTable = cms.EDProducer(
+ "SimpleCandidateFlatTableProducer",
+ src=subJetTable.src,
+ cut=subJetTable.cut,
+ name=subJetTable.name,
+ doc=subJetTable.doc,
+ singleton=cms.bool(False), # the number of entries is variable
+ extension=cms.bool(True), # this is the extension table for FatJets
+ variables=cms.PSet(
+ CommonVars,
+ # Proba=Var("bDiscriminator('pfJetProbabilityBJetTags')",
+ # float,
+ # doc="Jet Probability (Usage:BTV)",
+ # precision=10),
+ btagDeepC = Var("bDiscriminator('pfDeepCSVJetTags:probc')",
+ float,
+ doc="DeepCSV charm btag discriminator",
+ precision=10),
+
+ ))
+
+ process.customSubJetMCExtTable = cms.EDProducer(
+ "SimpleCandidateFlatTableProducer",
+ src = subJetTable.src,
+ cut = subJetTable.cut,
+ name = subJetTable.name,
+ doc=subJetTable.doc,
+ singleton = cms.bool(False),
+ extension = cms.bool(True),
+ variables = cms.PSet(
+ subGenJetAK8Idx = Var("?genJetFwdRef().backRef().isNonnull()?genJetFwdRef().backRef().key():-1",
+ int,
+ doc="index of matched gen Sub jet"),
+ )
+ )
+
+ if addAK4:
+ process.customizeJetTask.add(process.customJetExtTable)
+ if addAK8:
+ process.customizeJetTask.add(process.customFatJetExtTable)
+ process.customizeJetTask.add(process.customSubJetExtTable)
+ if runOnMC and addAK8:
+ process.customizeJetTask.add(process.customSubJetMCExtTable)
+
+ return process
diff --git a/PhysicsTools/NanoAOD/python/addPFCands_cff.py b/PhysicsTools/NanoAOD/python/addPFCands_cff.py
new file mode 100644
index 0000000000000..2370f31cb0f48
--- /dev/null
+++ b/PhysicsTools/NanoAOD/python/addPFCands_cff.py
@@ -0,0 +1,137 @@
+import FWCore.ParameterSet.Config as cms
+from PhysicsTools.NanoAOD.common_cff import *
+
+def addPFCands(process, runOnMC=False, allPF = False, onlyAK4=False, onlyAK8=False):
+ process.customizedPFCandsTask = cms.Task( )
+ process.schedule.associate(process.customizedPFCandsTask)
+
+ process.finalJetsAK8Constituents = cms.EDProducer("PatJetConstituentPtrSelector",
+ src = cms.InputTag("finalJetsAK8"),
+ cut = cms.string("")
+ )
+ process.finalJetsAK4Constituents = cms.EDProducer("PatJetConstituentPtrSelector",
+ src = cms.InputTag("finalJets"),
+ cut = cms.string("")
+ )
+ if allPF:
+ candInput = cms.InputTag("packedPFCandidates")
+ elif onlyAK4:
+ candList = cms.VInputTag(cms.InputTag("finalJetsAK4Constituents", "constituents"))
+ process.customizedPFCandsTask.add(process.finalJetsAK4Constituents)
+ process.finalJetsConstituents = cms.EDProducer("PackedCandidatePtrMerger", src = candList, skipNulls = cms.bool(True), warnOnSkip = cms.bool(True))
+ candInput = cms.InputTag("finalJetsConstituents")
+ elif onlyAK8:
+ candList = cms.VInputTag(cms.InputTag("finalJetsAK8Constituents", "constituents"))
+ process.customizedPFCandsTask.add(process.finalJetsAK8Constituents)
+ process.finalJetsConstituents = cms.EDProducer("PackedCandidatePtrMerger", src = candList, skipNulls = cms.bool(True), warnOnSkip = cms.bool(True))
+ candInput = cms.InputTag("finalJetsConstituents")
+ else:
+ candList = cms.VInputTag(cms.InputTag("finalJetsAK4Constituents", "constituents"), cms.InputTag("finalJetsAK8Constituents", "constituents"))
+ process.customizedPFCandsTask.add(process.finalJetsAK4Constituents)
+ process.customizedPFCandsTask.add(process.finalJetsAK8Constituents)
+ process.finalJetsConstituents = cms.EDProducer("PackedCandidatePtrMerger", src = candList, skipNulls = cms.bool(True), warnOnSkip = cms.bool(True))
+ candInput = cms.InputTag("finalJetsConstituents")
+
+ process.customConstituentsExtTable = cms.EDProducer("SimpleCandidateFlatTableProducer",
+ src = candInput, #stores PFcands based on chosen inputs (all PF candidates, only those belonging to the FatJet collection, etc...)
+ cut = cms.string(""), #we should not filter after pruning
+ name = cms.string("PFCands"),
+ doc = cms.string("Interesting particles from chosen candidate collection."),
+ singleton = cms.bool(False), # the number of entries is variable
+ extension = cms.bool(False),
+ variables = cms.PSet(CandVars,
+ puppiWeight = Var("puppiWeight()", float, doc="Puppi weight",precision=10),
+ puppiWeightNoLep = Var("puppiWeightNoLep()", float, doc="Puppi weight removing leptons",precision=10),
+ vtxChi2 = Var("?hasTrackDetails()?vertexChi2():-1", float, doc="vertex chi2",precision=10),
+ trkChi2 = Var("?hasTrackDetails()?pseudoTrack().normalizedChi2():-1", float, doc="normalized trk chi2", precision=10),
+ dz = Var("?hasTrackDetails()?dz():-1", float, doc="pf dz", precision=10),
+ dzErr = Var("?hasTrackDetails()?dzError():-1", float, doc="pf dz err", precision=10),
+ d0 = Var("?hasTrackDetails()?dxy():-1", float, doc="pf d0", precision=10),
+ d0Err = Var("?hasTrackDetails()?dxyError():-1", float, doc="pf d0 err", precision=10),
+ pvAssocQuality = Var("pvAssociationQuality()", int, doc="primary vertex association quality"),
+ lostInnerHits = Var("lostInnerHits()", int, doc="lost inner hits"),
+ trkQuality = Var("?hasTrackDetails()?pseudoTrack().qualityMask():0", int, doc="track quality mask"),
+ )
+ )
+
+ # AK8 PF PUPPI Jet table (FetJet in NanoAOD)
+ process.customAK8ConstituentsTable = cms.EDProducer("PatJetConstituentTableProducer",
+ candidates = candInput,
+ jets = cms.InputTag("finalJetsAK8"),
+ jet_radius = cms.double(0.8),
+ name = cms.string("FatJetPFCands"),
+ nameSV = cms.string("FatJetSVs"))
+ # AK4 PF CHS Jet table (Jet in NanoAOD)
+ process.customAK4ConstituentsTable = cms.EDProducer("PatJetConstituentTableProducer",
+ candidates = candInput,
+ jets = cms.InputTag("finalJets"),
+ jet_radius = cms.double(0.4),
+ name = cms.string("JetPFCands"),
+ nameSV = cms.string("JetSVs"))
+ if not allPF:
+ process.customizedPFCandsTask.add(process.finalJetsConstituents)
+ process.customizedPFCandsTask.add(process.customConstituentsExtTable)
+ process.customizedPFCandsTask.add(process.customAK8ConstituentsTable)
+ process.customizedPFCandsTask.add(process.customAK4ConstituentsTable)
+
+ if runOnMC:
+
+ process.genJetsAK8Constituents = cms.EDProducer("GenJetPackedConstituentPtrSelector",
+ src = cms.InputTag("slimmedGenJetsAK8"),
+ cut = cms.string("pt > 80")
+ )
+
+
+ process.genJetsAK4Constituents = process.genJetsAK8Constituents.clone(
+ src = cms.InputTag("slimmedGenJets"),
+ cut = cms.string("pt > 20")
+ )
+ if allPF:
+ genCandInput = cms.InputTag("packedGenParticles")
+ elif onlyAK4:
+ genCandList = cms.VInputTag(cms.InputTag("genJetsAK4Constituents", "constituents"))
+ genCandInput = cms.InputTag("genJetsConstituents")
+ process.genJetsConstituents = cms.EDProducer("PackedGenParticlePtrMerger", src = genCandList, skipNulls = cms.bool(True), warnOnSkip = cms.bool(True))
+ elif onlyAK8:
+ genCandList = cms.VInputTag(cms.InputTag("genJetsAK8Constituents", "constituents"))
+ genCandInput = cms.InputTag("genJetsConstituents")
+ process.genJetsConstituents = cms.EDProducer("PackedGenParticlePtrMerger", src = genCandList, skipNulls = cms.bool(True), warnOnSkip = cms.bool(True))
+ else:
+ genCandList = cms.VInputTag(cms.InputTag("genJetsAK4Constituents", "constituents"), cms.InputTag("genJetsAK8Constituents", "constituents"))
+ genCandInput = cms.InputTag("genJetsConstituents")
+ process.genJetsConstituents = cms.EDProducer("PackedGenParticlePtrMerger", src = genCandList, skipNulls = cms.bool(True), warnOnSkip = cms.bool(True))
+
+ process.genJetsParticleTable = cms.EDProducer("SimpleCandidateFlatTableProducer",
+ src = genCandInput,
+ cut = cms.string(""), #we should not filter after pruning
+ name= cms.string("GenParticles"),
+ doc = cms.string("Interesting gen particles from entire candidate collection."),
+ singleton = cms.bool(False), # the number of entries is variable
+ extension = cms.bool(False), # this is the main table for the AK8 constituents
+ variables = cms.PSet(CandVars
+ )
+ )
+
+ # AK4 Gen Jet table (GenJet in NanoAOD)
+ process.genAK8ConstituentsTable = cms.EDProducer("GenJetConstituentTableProducer",
+ candidates = genCandInput,
+ jets = cms.InputTag("genJetsAK8Constituents"), # Note: The name has "Constituents" in it, but these are the jets
+ name = cms.string("GenJetAK8Particles"),
+ nameSV = cms.string("GenJetAK8SVs"),
+ readBtag = cms.bool(False))
+ # AK8 Gen Jet table (GenJetAK8 in NanoAOD)
+ process.genAK4ConstituentsTable = cms.EDProducer("GenJetConstituentTableProducer",
+ candidates = genCandInput,
+ jets = cms.InputTag("genJetsAK4Constituents"), # Note: The name has "Constituents" in it, but these are the jets
+ name = cms.string("GenJetParticles"),
+ nameSV = cms.string("GenJetSVs"),
+ readBtag = cms.bool(False))
+ process.customizedPFCandsTask.add(process.genJetsAK4Constituents) #Note: For gen need to add jets to the process to keep pt cuts.
+ process.customizedPFCandsTask.add(process.genJetsAK8Constituents)
+ if not allPF:
+ process.customizedPFCandsTask.add(process.genJetsConstituents)
+ process.customizedPFCandsTask.add(process.genJetsParticleTable)
+ process.customizedPFCandsTask.add(process.genAK8ConstituentsTable)
+ process.customizedPFCandsTask.add(process.genAK4ConstituentsTable)
+
+ return process
diff --git a/PhysicsTools/NanoAOD/python/custom_jme_cff.py b/PhysicsTools/NanoAOD/python/custom_jme_cff.py
index f00cfc3fd275c..963468398a09c 100644
--- a/PhysicsTools/NanoAOD/python/custom_jme_cff.py
+++ b/PhysicsTools/NanoAOD/python/custom_jme_cff.py
@@ -16,6 +16,9 @@
from PhysicsTools.PatAlgos.tools.jetTools import supportedJetAlgos
from PhysicsTools.PatAlgos.tools.jetTools import updateJetCollection
+from PhysicsTools.NanoAOD.addPFCands_cff import addPFCands
+from PhysicsTools.NanoAOD.addBTV_cff import addBTV
+
import copy
bTagCSVV2 = ['pfDeepCSVJetTags:probb','pfDeepCSVJetTags:probbb','pfDeepCSVJetTags:probc']
@@ -887,3 +890,29 @@ def PrepJMECustomNanoAOD_MC(process):
def PrepJMECustomNanoAOD_Data(process):
PrepJMECustomNanoAOD(process,runOnMC=False)
return process
+
+#### Add AK8 PFCands and BTV info
+def PrepJMECustomAK8PFNanoAOD_MC(process):
+ PrepJMECustomNanoAOD(process, runOnMC=True)
+ addPFCands(process, runOnMC = True, onlyAK8 = True)
+ addBTV(process, runOnMC = True, onlyAK8 = True)
+ return process
+
+def PrepJMECustomAK8PFNanoAOD_Data(process):
+ PrepJMECustomNanoAOD(process, runOnMC=False)
+ addPFCands(process, runOnMC = False, onlyAK8 = True)
+ addBTV(process, runOnMC = False, onlyAK8 = True)
+ return process
+
+#### All PFCands and BTV info
+def PrepJMECustomPFNanoAOD_MC(process):
+ PrepJMECustomNanoAOD(process, runOnMC=True)
+ addPFCands(process, runOnMC = True, allPF = True)
+ addBTV(process, runOnMC = True)
+ return process
+
+def PrepJMECustomPFNanoAOD_Data(process):
+ PrepJMECustomNanoAOD(process, runOnMC=False)
+ addPFCands(process, runOnMC = False, allPF = True)
+ addBTV(process, runOnMC = False)
+ return process