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