From 4e1f0e402cc4092e7ce42e0e062c91a6d0183ea7 Mon Sep 17 00:00:00 2001 From: Andre Govinda Stahl Leiton Date: Fri, 15 Mar 2024 03:27:06 +0100 Subject: [PATCH] Add use of unsubtracted jets in b-tagger algorithms --- .../plugins/DeepBoostedJetTagInfoProducer.cc | 27 +++++-- .../plugins/DeepFlavourTagInfoProducer.cc | 26 ++++++- .../ParticleTransformerAK4TagInfoProducer.cc | 26 ++++++- RecoBTag/FeatureTools/test/BuildFile.xml | 1 + RecoBTag/FeatureTools/test/u0_cfg.py | 74 +++++++++++++++++++ RecoJets/JetProducers/plugins/JetMatcherDR.cc | 50 +++++++++++++ 6 files changed, 191 insertions(+), 13 deletions(-) create mode 100644 RecoBTag/FeatureTools/test/BuildFile.xml create mode 100644 RecoBTag/FeatureTools/test/u0_cfg.py create mode 100644 RecoJets/JetProducers/plugins/JetMatcherDR.cc diff --git a/RecoBTag/FeatureTools/plugins/DeepBoostedJetTagInfoProducer.cc b/RecoBTag/FeatureTools/plugins/DeepBoostedJetTagInfoProducer.cc index 39ec53b59e011..52b47b85c4b61 100644 --- a/RecoBTag/FeatureTools/plugins/DeepBoostedJetTagInfoProducer.cc +++ b/RecoBTag/FeatureTools/plugins/DeepBoostedJetTagInfoProducer.cc @@ -24,6 +24,7 @@ #include "DataFormats/VertexReco/interface/VertexFwd.h" #include "DataFormats/BTauReco/interface/DeepBoostedJetTagInfo.h" +#include "DataFormats/Common/interface/AssociationMap.h" using namespace btagbtvdeep; @@ -39,12 +40,13 @@ class DeepBoostedJetTagInfoProducer : public edm::stream::EDProducer<> { typedef reco::VertexCompositePtrCandidateCollection SVCollection; typedef reco::VertexCollection VertexCollection; typedef edm::View CandidateView; + typedef edm::AssociationMap> JetMatchMap; void beginStream(edm::StreamID) override {} void produce(edm::Event &, const edm::EventSetup &) override; void endStream() override {} - void fillParticleFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet); + void fillParticleFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &unsubJet, const reco::Jet &jet); void fillSVFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet); void fillParticleFeaturesHLT(DeepBoostedJetFeatures &fts, const reco::Jet &jet, const reco::VertexRefProd &PVRefProd); void fillSVFeaturesHLT(DeepBoostedJetFeatures &fts, const reco::Jet &jet); @@ -66,6 +68,7 @@ class DeepBoostedJetTagInfoProducer : public edm::stream::EDProducer<> { const bool use_hlt_features_; edm::EDGetTokenT> jet_token_; + edm::EDGetTokenT unsubjet_map_token_; edm::EDGetTokenT vtx_token_; edm::EDGetTokenT sv_token_; edm::EDGetTokenT pfcand_token_; @@ -73,6 +76,7 @@ class DeepBoostedJetTagInfoProducer : public edm::stream::EDProducer<> { bool use_puppi_value_map_; bool use_pvasq_value_map_; bool is_packed_pf_candidate_collection_; + bool use_unsubjet_map_; edm::EDGetTokenT> puppi_value_map_token_; edm::EDGetTokenT> pvasq_value_map_token_; @@ -229,6 +233,7 @@ DeepBoostedJetTagInfoProducer::DeepBoostedJetTagInfoProducer(const edm::Paramete pfcand_token_(consumes(iConfig.getParameter("pf_candidates"))), use_puppi_value_map_(false), use_pvasq_value_map_(false), + use_unsubjet_map_(false), track_builder_token_( esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))), covarianceVersion_(iConfig.getParameter("covarianceVersion")), @@ -300,6 +305,12 @@ DeepBoostedJetTagInfoProducer::DeepBoostedJetTagInfoProducer(const edm::Paramete trkPhi_value_map_token_ = consumes>(trkPhi_value_map_tag); } + const auto &unsubjet_map_tag = iConfig.getUntrackedParameter("unsubjet_map", {}); + if (!unsubjet_map_tag.label().empty()) { + unsubjet_map_token_ = consumes(unsubjet_map_tag); + use_unsubjet_map_ = true; + } + produces(); } @@ -324,6 +335,7 @@ void DeepBoostedJetTagInfoProducer::fillDescriptions(edm::ConfigurationDescripti desc.add("secondary_vertices", edm::InputTag("inclusiveCandidateSecondaryVertices")); desc.add("pf_candidates", edm::InputTag("particleFlow")); desc.add("jets", edm::InputTag("ak8PFJetsPuppi")); + desc.addUntracked("unsubjet_map", {}); desc.add("puppi_value_map", edm::InputTag("puppi")); desc.add("vertex_associator", edm::InputTag("primaryVertexAssociation", "original")); desc.add("use_scouting_features", false); @@ -347,6 +359,7 @@ void DeepBoostedJetTagInfoProducer::produce(edm::Event &iEvent, const edm::Event auto output_tag_infos = std::make_unique(); // Input jets auto jets = iEvent.getHandle(jet_token_); + auto unsubjet_map = use_unsubjet_map_ ? iEvent.getHandle(unsubjet_map_token_) : edm::Handle(); // Primary vertexes if (!use_scouting_features_) { iEvent.getByToken(vtx_token_, vtxs_); @@ -392,6 +405,8 @@ void DeepBoostedJetTagInfoProducer::produce(edm::Event &iEvent, const edm::Event 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); + const auto &unsubJet = + (use_unsubjet_map_ && (*unsubjet_map)[jet_ref].isNonnull()) ? *(*unsubjet_map)[jet_ref] : jet; // create jet features DeepBoostedJetFeatures features; @@ -421,13 +436,13 @@ void DeepBoostedJetTagInfoProducer::produce(edm::Event &iEvent, const edm::Event if (jet.pt() < min_jet_pt_ or std::abs(jet.eta()) > max_jet_eta_) { fill_vars = false; } - if (jet.numberOfDaughters() == 0 and !use_scouting_features_) { + if (unsubJet.numberOfDaughters() == 0 and !use_scouting_features_) { fill_vars = false; } // fill features if (fill_vars) { - fillParticleFeatures(features, jet); + fillParticleFeatures(features, unsubJet, jet); if (!use_scouting_features_) { fillSVFeatures(features, jet); } @@ -475,7 +490,9 @@ bool DeepBoostedJetTagInfoProducer::useTrackProperties(const reco::PFCandidate * return track != nullptr and track->pt() > min_pt_for_track_properties_; }; -void DeepBoostedJetTagInfoProducer::fillParticleFeatures(DeepBoostedJetFeatures &fts, const reco::Jet &jet) { +void DeepBoostedJetTagInfoProducer::fillParticleFeatures(DeepBoostedJetFeatures &fts, + const reco::Jet &unsubJet, + const reco::Jet &jet) { // some jet properties math::XYZVector jet_dir = jet.momentum().Unit(); TVector3 jet_direction(jet.momentum().Unit().x(), jet.momentum().Unit().y(), jet.momentum().Unit().z()); @@ -492,7 +509,7 @@ void DeepBoostedJetTagInfoProducer::fillParticleFeatures(DeepBoostedJetFeatures // make list of pf-candidates to be considered std::vector daughters; - for (const auto &dau : jet.daughterPtrVector()) { + for (const auto &dau : unsubJet.daughterPtrVector()) { // remove particles w/ extremely low puppi weights // [Note] use jet daughters here to get the puppiWgt correctly if ((puppiWgt(dau)) < min_puppi_wgt_) diff --git a/RecoBTag/FeatureTools/plugins/DeepFlavourTagInfoProducer.cc b/RecoBTag/FeatureTools/plugins/DeepFlavourTagInfoProducer.cc index 0bbb98b2442d5..15ff99af02bbf 100644 --- a/RecoBTag/FeatureTools/plugins/DeepFlavourTagInfoProducer.cc +++ b/RecoBTag/FeatureTools/plugins/DeepFlavourTagInfoProducer.cc @@ -57,6 +57,7 @@ class HistogramProbabilityEstimator; #include "FWCore/Framework/interface/EventSetupRecord.h" #include "FWCore/Framework/interface/EventSetupRecordImplementation.h" #include "FWCore/Framework/interface/EventSetupRecordKey.h" +#include "DataFormats/Common/interface/AssociationMap.h" class DeepFlavourTagInfoProducer : public edm::stream::EDProducer<> { public: @@ -70,6 +71,7 @@ class DeepFlavourTagInfoProducer : public edm::stream::EDProducer<> { typedef reco::VertexCompositePtrCandidateCollection SVCollection; typedef reco::VertexCollection VertexCollection; typedef edm::View ShallowTagInfoCollection; + typedef edm::AssociationMap> JetMatchMap; void beginStream(edm::StreamID) override {} void produce(edm::Event&, const edm::EventSetup&) override; @@ -80,6 +82,7 @@ class DeepFlavourTagInfoProducer : public edm::stream::EDProducer<> { const bool flip_; edm::EDGetTokenT> jet_token_; + edm::EDGetTokenT unsubjet_map_token_; edm::EDGetTokenT vtx_token_; edm::EDGetTokenT sv_token_; edm::EDGetTokenT shallow_tag_info_token_; @@ -93,6 +96,7 @@ class DeepFlavourTagInfoProducer : public edm::stream::EDProducer<> { bool use_puppi_value_map_; bool use_pvasq_value_map_; + bool use_unsubjet_map_; bool fallback_puppi_weight_; bool fallback_vertex_association_; @@ -126,6 +130,7 @@ DeepFlavourTagInfoProducer::DeepFlavourTagInfoProducer(const edm::ParameterSet& esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))), use_puppi_value_map_(false), use_pvasq_value_map_(false), + use_unsubjet_map_(false), fallback_puppi_weight_(iConfig.getParameter("fallback_puppi_weight")), fallback_vertex_association_(iConfig.getParameter("fallback_vertex_association")), run_deepVertex_(iConfig.getParameter("run_deepVertex")), @@ -154,6 +159,12 @@ DeepFlavourTagInfoProducer::DeepFlavourTagInfoProducer(const edm::ParameterSet& calib2d_token_ = esConsumes(); calib3d_token_ = esConsumes(); } + + const auto& unsubjet_map_tag = iConfig.getUntrackedParameter("unsubjet_map", {}); + if (!unsubjet_map_tag.label().empty()) { + unsubjet_map_token_ = consumes(unsubjet_map_tag); + use_unsubjet_map_ = true; + } } DeepFlavourTagInfoProducer::~DeepFlavourTagInfoProducer() {} @@ -169,6 +180,7 @@ void DeepFlavourTagInfoProducer::fillDescriptions(edm::ConfigurationDescriptions desc.add("puppi_value_map", edm::InputTag("puppi")); desc.add("secondary_vertices", edm::InputTag("inclusiveCandidateSecondaryVertices")); desc.add("jets", edm::InputTag("ak4PFJetsCHS")); + desc.addUntracked("unsubjet_map", {}); desc.add("candidates", edm::InputTag("packedPFCandidates")); desc.add("vertex_associator", edm::InputTag("primaryVertexAssociation", "original")); desc.add("fallback_puppi_weight", false); @@ -189,6 +201,10 @@ void DeepFlavourTagInfoProducer::produce(edm::Event& iEvent, const edm::EventSet edm::Handle> jets; iEvent.getByToken(jet_token_, jets); + edm::Handle unsubjet_map; + if (use_unsubjet_map_) + iEvent.getByToken(unsubjet_map_token_, unsubjet_map); + edm::Handle vtxs; iEvent.getByToken(vtx_token_, vtxs); if (vtxs->empty()) { @@ -256,6 +272,8 @@ void DeepFlavourTagInfoProducer::produce(edm::Event& iEvent, const edm::EventSet const auto* pf_jet = dynamic_cast(&jet); const auto* pat_jet = dynamic_cast(&jet); edm::RefToBase jet_ref(jets, jet_n); + const auto& unsubJet = + (use_unsubjet_map_ && (*unsubjet_map)[jet_ref].isNonnull()) ? *(*unsubjet_map)[jet_ref] : jet; // TagInfoCollection not in an associative container so search for matchs const edm::View& taginfos = *shallow_tag_infos; edm::Ptr match; @@ -316,8 +334,8 @@ void DeepFlavourTagInfoProducer::produce(edm::Event& iEvent, const edm::EventSet // unsorted reference to sv const auto& svs_unsorted = *svs; // fill collection, from DeepTNtuples plus some styling - for (unsigned int i = 0; i < jet.numberOfDaughters(); i++) { - auto cand = jet.daughter(i); + for (unsigned int i = 0; i < unsubJet.numberOfDaughters(); i++) { + auto cand = unsubJet.daughter(i); if (cand) { // candidates under 950MeV (configurable) are not considered // might change if we use also white-listing @@ -350,9 +368,9 @@ void DeepFlavourTagInfoProducer::produce(edm::Event& iEvent, const edm::EventSet features.n_pf_features.clear(); features.n_pf_features.resize(n_sorted.size()); - for (unsigned int i = 0; i < jet.numberOfDaughters(); i++) { + for (unsigned int i = 0; i < unsubJet.numberOfDaughters(); i++) { // get pointer and check that is correct - auto cand = dynamic_cast(jet.daughter(i)); + auto cand = dynamic_cast(unsubJet.daughter(i)); if (!cand) continue; // candidates under 950MeV are not considered diff --git a/RecoBTag/FeatureTools/plugins/ParticleTransformerAK4TagInfoProducer.cc b/RecoBTag/FeatureTools/plugins/ParticleTransformerAK4TagInfoProducer.cc index 1d66657ccc822..64c50e7fdbbea 100644 --- a/RecoBTag/FeatureTools/plugins/ParticleTransformerAK4TagInfoProducer.cc +++ b/RecoBTag/FeatureTools/plugins/ParticleTransformerAK4TagInfoProducer.cc @@ -56,6 +56,7 @@ class HistogramProbabilityEstimator; #include "FWCore/Framework/interface/EventSetupRecord.h" #include "FWCore/Framework/interface/EventSetupRecordImplementation.h" #include "FWCore/Framework/interface/EventSetupRecordKey.h" +#include "DataFormats/Common/interface/AssociationMap.h" class ParticleTransformerAK4TagInfoProducer : public edm::stream::EDProducer<> { public: @@ -68,6 +69,7 @@ class ParticleTransformerAK4TagInfoProducer : public edm::stream::EDProducer<> { typedef std::vector ParticleTransformerAK4TagInfoCollection; typedef reco::VertexCompositePtrCandidateCollection SVCollection; typedef reco::VertexCollection VertexCollection; + typedef edm::AssociationMap> JetMatchMap; void beginStream(edm::StreamID) override {} void produce(edm::Event&, const edm::EventSetup&) override; @@ -80,6 +82,7 @@ class ParticleTransformerAK4TagInfoProducer : public edm::stream::EDProducer<> { const edm::EDGetTokenT> jet_token_; const edm::EDGetTokenT vtx_token_; const edm::EDGetTokenT sv_token_; + edm::EDGetTokenT unsubjet_map_token_; edm::EDGetTokenT> puppi_value_map_token_; edm::EDGetTokenT> pvasq_value_map_token_; edm::EDGetTokenT> pvas_token_; @@ -87,6 +90,7 @@ class ParticleTransformerAK4TagInfoProducer : public edm::stream::EDProducer<> { const edm::ESGetToken track_builder_token_; bool use_puppi_value_map_; bool use_pvasq_value_map_; + bool use_unsubjet_map_; const bool fallback_puppi_weight_; const bool fallback_vertex_association_; @@ -109,6 +113,7 @@ ParticleTransformerAK4TagInfoProducer::ParticleTransformerAK4TagInfoProducer(con esConsumes(edm::ESInputTag("", "TransientTrackBuilder"))), use_puppi_value_map_(false), use_pvasq_value_map_(false), + use_unsubjet_map_(false), fallback_puppi_weight_(iConfig.getParameter("fallback_puppi_weight")), fallback_vertex_association_(iConfig.getParameter("fallback_vertex_association")), is_weighted_jet_(iConfig.getParameter("is_weighted_jet")), @@ -131,6 +136,12 @@ ParticleTransformerAK4TagInfoProducer::ParticleTransformerAK4TagInfoProducer(con pvas_token_ = consumes>(pvas_tag); use_pvasq_value_map_ = true; } + + const auto& unsubjet_map_tag = iConfig.getUntrackedParameter("unsubjet_map", {}); + if (!unsubjet_map_tag.label().empty()) { + unsubjet_map_token_ = consumes(unsubjet_map_tag); + use_unsubjet_map_ = true; + } } void ParticleTransformerAK4TagInfoProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { @@ -143,6 +154,7 @@ void ParticleTransformerAK4TagInfoProducer::fillDescriptions(edm::ConfigurationD desc.add("puppi_value_map", edm::InputTag("puppi")); desc.add("secondary_vertices", edm::InputTag("inclusiveCandidateSecondaryVertices")); desc.add("jets", edm::InputTag("ak4PFJetsCHS")); + desc.addUntracked("unsubjet_map", {}); desc.add("candidates", edm::InputTag("packedPFCandidates")); desc.add("vertex_associator", edm::InputTag("primaryVertexAssociation", "original")); desc.add("fallback_puppi_weight", false); @@ -158,6 +170,10 @@ void ParticleTransformerAK4TagInfoProducer::produce(edm::Event& iEvent, const ed edm::Handle> jets; iEvent.getByToken(jet_token_, jets); + edm::Handle unsubjet_map; + if (use_unsubjet_map_) + iEvent.getByToken(unsubjet_map_token_, unsubjet_map); + edm::Handle vtxs; iEvent.getByToken(vtx_token_, vtxs); if (vtxs->empty()) { @@ -204,6 +220,8 @@ void ParticleTransformerAK4TagInfoProducer::produce(edm::Event& iEvent, const ed const auto* pf_jet = dynamic_cast(&jet); const auto* pat_jet = dynamic_cast(&jet); edm::RefToBase jet_ref(jets, jet_n); + const auto& unsubJet = + (use_unsubjet_map_ && (*unsubjet_map)[jet_ref].isNonnull()) ? *(*unsubjet_map)[jet_ref] : jet; if (features.is_filled) { math::XYZVector jet_dir = jet.momentum().Unit(); @@ -237,8 +255,8 @@ void ParticleTransformerAK4TagInfoProducer::produce(edm::Event& iEvent, const ed // unsorted reference to sv const auto& svs_unsorted = *svs; // fill collection, from DeepTNtuples plus some styling - for (unsigned int i = 0; i < jet.numberOfDaughters(); i++) { - auto cand = jet.daughter(i); + for (unsigned int i = 0; i < unsubJet.numberOfDaughters(); i++) { + auto cand = unsubJet.daughter(i); if (cand) { // candidates under 950MeV (configurable) are not considered // might change if we use also white-listing @@ -274,9 +292,9 @@ void ParticleTransformerAK4TagInfoProducer::produce(edm::Event& iEvent, const ed features.n_pf_features.clear(); features.n_pf_features.resize(n_sorted.size()); - for (unsigned int i = 0; i < jet.numberOfDaughters(); i++) { + for (unsigned int i = 0; i < unsubJet.numberOfDaughters(); i++) { // get pointer and check that is correct - auto cand = dynamic_cast(jet.daughter(i)); + auto cand = dynamic_cast(unsubJet.daughter(i)); if (!cand) continue; // candidates under 950MeV are not considered diff --git a/RecoBTag/FeatureTools/test/BuildFile.xml b/RecoBTag/FeatureTools/test/BuildFile.xml new file mode 100644 index 0000000000000..242ea2cad997c --- /dev/null +++ b/RecoBTag/FeatureTools/test/BuildFile.xml @@ -0,0 +1 @@ + diff --git a/RecoBTag/FeatureTools/test/u0_cfg.py b/RecoBTag/FeatureTools/test/u0_cfg.py new file mode 100644 index 0000000000000..869d34a4a23e2 --- /dev/null +++ b/RecoBTag/FeatureTools/test/u0_cfg.py @@ -0,0 +1,74 @@ +# Unit test configuration file for RecoBTagInfo producers: +# Verify the use of unsubtracted jet map +# + +import FWCore.ParameterSet.Config as cms + +process = cms.Process("TEST") + +process.load('Configuration.Geometry.GeometryDB_cff') +process.load('Configuration.StandardSequences.MagneticField_38T_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') +process.load("TrackingTools.TransientTrack.TransientTrackBuilder_cfi") + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(2) +) + +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring("root://xrootd-cms.infn.it//store/hidata/HIRun2023A/HIPhysicsRawPrime0/MINIAOD/PromptReco-v2/000/375/823/00000/8158260e-df3c-45a5-a121-55345a682a23.root") +) + +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, '132X_dataRun3_Prompt_v4', '') + +from RecoJets.JetProducers.ak4PFJets_cfi import ak4PFJets +process.ak4PFJets = ak4PFJets.clone(rParam = 0.4, src = 'packedPFCandidates') + +process.unsubJets = cms.EDProducer("JetMatcherDR", + source = cms.InputTag("ak4PFJets"), + matched = cms.InputTag("ak4PFJets") +) + +from RecoBTag.FeatureTools.pfDeepFlavourTagInfos_cfi import pfDeepFlavourTagInfos +process.pfDeepFlavourTagInfos = pfDeepFlavourTagInfos.clone( + jets = "ak4PFJets", + unsubjet_map = "unsubJets", + fallback_puppi_weight = True, + fallback_vertex_association = True, + puppi_value_map = "", + secondary_vertices = "inclusiveCandidateSecondaryVertices", + shallow_tag_infos = "pfDeepCSVTagInfos", + vertex_associator = "", + vertices = "offlineSlimmedPrimaryVertices" +) + +from RecoBTag.FeatureTools.pfDeepBoostedJetTagInfos_cfi import pfDeepBoostedJetTagInfos +process.pfDeepBoostedJetTagInfos = pfDeepBoostedJetTagInfos.clone( + jets = "ak4PFJets", + unsubjet_map = "unsubJets", + use_puppiP4 = False, + puppi_value_map = "", + secondary_vertices = "inclusiveCandidateSecondaryVertices", + vertex_associator = "", + vertices = "offlineSlimmedPrimaryVertices", + pf_candidates = "packedPFCandidates" +) + +from RecoBTag.FeatureTools.pfParticleTransformerAK4TagInfos_cfi import pfParticleTransformerAK4TagInfos +process.pfParticleTransformerAK4TagInfos = pfParticleTransformerAK4TagInfos.clone( + jets = "ak4PFJets", + unsubjet_map = "unsubJets", + fallback_puppi_weight = True, + fallback_vertex_association = True, + puppi_value_map = "", + secondary_vertices = "inclusiveCandidateSecondaryVertices", + vertex_associator = "", + vertices = "offlineSlimmedPrimaryVertices" +) + +process.p = cms.Path(process.ak4PFJets * + process.unsubJets * + process.pfDeepFlavourTagInfos * + process.pfDeepBoostedJetTagInfos * + process.pfParticleTransformerAK4TagInfos) diff --git a/RecoJets/JetProducers/plugins/JetMatcherDR.cc b/RecoJets/JetProducers/plugins/JetMatcherDR.cc new file mode 100644 index 0000000000000..76c74ec78a032 --- /dev/null +++ b/RecoJets/JetProducers/plugins/JetMatcherDR.cc @@ -0,0 +1,50 @@ +/* \class JetMatcherDR + * + * Producer for association map: + * class to match two collections of jet with one-to-one matching + * All elements of class "matched" are matched to each element of class "source" minimizing DeltaR + * + */ + +#include "FWCore/Framework/interface/global/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/makeRefToBaseProdFrom.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/JetReco/interface/JetCollection.h" +#include "DataFormats/Math/interface/deltaR.h" + +class JetMatcherDR : public edm::global::EDProducer<> { +public: + typedef edm::AssociationMap > JetMatchMap; + explicit JetMatcherDR(const edm::ParameterSet& iConfig) + : sourceToken_(consumes(iConfig.getParameter("source"))), + matchedToken_(consumes(iConfig.getParameter("matched"))) { + produces(); + }; + ~JetMatcherDR() override{}; + void produce(edm::StreamID, edm::Event&, const edm::EventSetup&) const override; + +private: + const edm::EDGetTokenT sourceToken_; + const edm::EDGetTokenT matchedToken_; +}; + +void JetMatcherDR::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const { + const auto& source = iEvent.getHandle(sourceToken_); + const auto& matched = iEvent.getHandle(matchedToken_); + auto matching = std::make_unique(source, matched); + for (size_t i = 0; i < source->size(); i++) { + std::pair m(-1, 999.f); + for (size_t j = 0; j < matched->size(); j++) { + const auto dR = deltaR((*source)[i].p4(), (*matched)[j].p4()); + if (dR < m.second) + m = {j, dR}; + } + matching->insert(source->refAt(i), m.first >= 0 ? matched->refAt(m.first) : reco::JetBaseRef()); + } + iEvent.put(std::move(matching)); +} + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(JetMatcherDR);