diff --git a/HLTrigger/JetMET/plugins/HLTL1TMatchedCaloJetsVBFFilter.cc b/HLTrigger/JetMET/plugins/HLTL1TMatchedCaloJetsVBFFilter.cc new file mode 100644 index 0000000000000..9391c8d32d7b3 --- /dev/null +++ b/HLTrigger/JetMET/plugins/HLTL1TMatchedCaloJetsVBFFilter.cc @@ -0,0 +1,7 @@ +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "HLTL1TMatchedJetsVBFFilter.h" +#include "DataFormats/JetReco/interface/CaloJet.h" + +typedef HLTL1TMatchedJetsVBFFilter HLTL1TMatchedCaloJetsVBFFilter; +DEFINE_FWK_MODULE(HLTL1TMatchedCaloJetsVBFFilter); diff --git a/HLTrigger/JetMET/plugins/HLTL1TMatchedJetsVBFFilter.h b/HLTrigger/JetMET/plugins/HLTL1TMatchedJetsVBFFilter.h new file mode 100644 index 0000000000000..3c1f0c606a5ee --- /dev/null +++ b/HLTrigger/JetMET/plugins/HLTL1TMatchedJetsVBFFilter.h @@ -0,0 +1,305 @@ +#ifndef HLTrigger_JetMET_HLTL1TMatchedJetsVBFFilter_h +#define HLTrigger_JetMET_HLTL1TMatchedJetsVBFFilter_h + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "DataFormats/Common/interface/Ref.h" +#include "DataFormats/HLTReco/interface/TriggerFilterObjectWithRefs.h" +#include "DataFormats/HLTReco/interface/TriggerTypeDefs.h" +#include "DataFormats/Math/interface/deltaR.h" +#include "HLTrigger/HLTcore/interface/HLTFilter.h" + +#include +#include +#include + +template +class HLTL1TMatchedJetsVBFFilter : public HLTFilter { +public: + explicit HLTL1TMatchedJetsVBFFilter(const edm::ParameterSet&); + ~HLTL1TMatchedJetsVBFFilter() override = default; + + bool hltFilter(edm::Event& iEvent, + const edm::EventSetup& iSetup, + trigger::TriggerFilterObjectWithRefs& filterproduct) const override; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + +private: + auto logTrace() const { + auto const moduleName = moduleDescription().moduleName(); + return LogTrace(moduleName) << "[" << moduleName << "] "; + } + + enum Algorithm { VBF = 0, VBFPlus2CentralJets = 1 }; + + Algorithm getAlgorithmFromString(std::string const& str) const; + void fillJetIndices(std::vector& outputJetIndices, + std::vector const& jets, + std::vector const& jetIndices, + double const pt1, + double const pt3, + double const mjj) const; + + // input HLT jets + edm::InputTag const jetTag_; + edm::EDGetTokenT> const jetToken_; + + // matching with L1T jets by delta-R distance + bool const matchJetsByDeltaR_; + double const maxJetDeltaR_, maxJetDeltaR2_; + edm::EDGetTokenT const l1tJetRefsToken_; + + // selection of HLT jets compatible with the VBF topology (see fillJetIndices) + Algorithm const algorithm_; + double const minPt1_; + double const minPt2_; + double const minPt3_; + double const minInvMass_; + + // min/max number of selected jets, and triggerType of output triggerRefs + int const minNJets_; + int const maxNJets_; + int const triggerType_; +}; + +template +void HLTL1TMatchedJetsVBFFilter::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + makeHLTFilterDescription(desc); + desc.add("src", edm::InputTag("hltJets"))->setComment("InputTag of input HLT jets"); + + desc.add("matchJetsByDeltaR", true) + ->setComment("Enable delta-R matching between HLT jets ('src') and L1T jets ('l1tJetRefs')"); + desc.add("maxJetDeltaR", 0.5) + ->setComment( + "Maximum delta-R distance to match HLT jets ('src') and L1T jets ('l1tJetRefs'), " + "used only if 'matchJetsByDeltaR == true'."); + desc.add("l1tJetRefs", edm::InputTag("hltL1sJetSeed")) + ->setComment("InputTag of references to L1T jets"); + + desc.add("algorithm", "VBF") + ->setComment("Keyword to choose the algorithm used to select jets compatible with the VBF topology"); + desc.add("minPt1", 110.)->setComment("Minimum pT of pT-leading jet"); + desc.add("minPt2", 35.)->setComment("Minimum pT of 2nd pT-leading jet"); + desc.add("minPt3", 110.)->setComment("Minimum pT of 3rd pT-leading jet"); + desc.add("minInvMass", 650.)->setComment("Minimum jet invariant mass"); + + desc.add("minNJets", 0)->setComment("Minimum number of output jets to accept the event (ignored if negative)"); + desc.add("maxNJets", -1)->setComment("Maximum number of output jets to accept the event (ignored if negative)"); + + desc.add("triggerType", trigger::TriggerJet); + + descriptions.setComment( + "This HLTFilter selects events with HLT jets compatible with the VBF topology. " + "These HLT jets can be required to be matched in delta-R to L1T jets."); + descriptions.addWithDefaultLabel(desc); +} + +template +HLTL1TMatchedJetsVBFFilter::HLTL1TMatchedJetsVBFFilter(const edm::ParameterSet& iConfig) + : HLTFilter(iConfig), + jetTag_(iConfig.getParameter("src")), + jetToken_(consumes(jetTag_)), + matchJetsByDeltaR_(iConfig.getParameter("matchJetsByDeltaR")), + maxJetDeltaR_(iConfig.getParameter("maxJetDeltaR")), + maxJetDeltaR2_(maxJetDeltaR_ * maxJetDeltaR_), + l1tJetRefsToken_(matchJetsByDeltaR_ ? consumes( + iConfig.getParameter("l1tJetRefs")) + : edm::EDGetTokenT()), + algorithm_(getAlgorithmFromString(iConfig.getParameter("algorithm"))), + minPt1_(iConfig.getParameter("minPt1")), + minPt2_(iConfig.getParameter("minPt2")), + minPt3_(iConfig.getParameter("minPt3")), + minInvMass_(iConfig.getParameter("minInvMass")), + minNJets_(iConfig.getParameter("minNJets")), + maxNJets_(iConfig.getParameter("maxNJets")), + triggerType_(iConfig.getParameter("triggerType")) { + // delta-R matching + if (matchJetsByDeltaR_ and maxJetDeltaR_ < 0) { + throw cms::Exception("InvalidConfigurationParameter") + << "invalid value for parameter \"maxJetDeltaR\" (must be > 0): " << maxJetDeltaR_; + } + + // values of minPt{1,2,3} thresholds + if (minPt2_ > minPt1_) { + throw cms::Exception("InvalidConfigurationParameter") + << "minPt1 (" << minPt1_ << ") must be larger than minPt2 (" << minPt2_ << ")"; + } else if (minPt3_ > minPt1_) { + throw cms::Exception("InvalidConfigurationParameter") + << "minPt1 (" << minPt1_ << ") must be larger than minPt3 (" << minPt3_ << ")"; + } else if (minPt2_ > minPt3_) { + throw cms::Exception("InvalidConfigurationParameter") + << "minPt3 (" << minPt3_ << ") must be larger than minPt2 (" << minPt2_ << ")"; + } +} + +template +typename HLTL1TMatchedJetsVBFFilter::Algorithm HLTL1TMatchedJetsVBFFilter::getAlgorithmFromString( + std::string const& str) const { + if (str == "VBF") { + return Algorithm::VBF; + } else if (str == "VBFPlus2CentralJets") { + return Algorithm::VBFPlus2CentralJets; + } + + throw cms::Exception("HLTL1TMatchedJetsVBFFilterInvalidAlgorithmName") + << "invalid value for argument of getAlgorithmFromString method: " << str + << " (valid values are \"VBF\" and \"VBFPlus2CentralJets\")"; +} + +template +void HLTL1TMatchedJetsVBFFilter::fillJetIndices(std::vector& outputJetIndices, + std::vector const& jets, + std::vector const& jetIndices, + double const pt1, + double const pt3, + double const mjj) const { + // reset output jet indices + outputJetIndices.clear(); + + // find dijet pair with highest Mjj + int i1 = -1; + int i2 = -1; + double m2jj_max = -1; + + for (unsigned int i = 0; i < jetIndices.size() - 1; i++) { + auto const& jet1 = jets[jetIndices[i]]; + + for (unsigned int j = i + 1; j < jetIndices.size(); j++) { + auto const& jet2 = jets[jetIndices[j]]; + + double const m2jj_tmp = (jet1.p4() + jet2.p4()).M2(); + + if (m2jj_tmp > m2jj_max) { + m2jj_max = m2jj_tmp; + i1 = jetIndices[i]; + i2 = jetIndices[j]; + } + } + } + + // only proceed if highest-Mjj dijet pair was found + if (i1 >= 0 and i2 >= 0) { + unsigned int const j1 = i1; + unsigned int const j2 = i2; + + auto const& jet1 = jets[j1]; + double const m2jj = (mjj >= 0. ? mjj * mjj : -1.); + + // algorithm: "VBF" + if (algorithm_ == Algorithm::VBF) { + if (m2jj_max > m2jj) { + if (jet1.pt() >= pt1) { + outputJetIndices = {j1, j2}; + } else if (jet1.pt() < pt3 and jets[jetIndices[0]].pt() > pt3) { + outputJetIndices = {j1, j2, jetIndices[0]}; + } + } + + } else if (algorithm_ == Algorithm::VBFPlus2CentralJets) { + if (jetIndices.size() > 3 and m2jj_max > m2jj) { + // indices of additional jets + std::vector idx_jets; + idx_jets.reserve(jetIndices.size() - 2); + + for (auto const idx : jetIndices) { + if (idx == j1 or idx == j2) + continue; + idx_jets.emplace_back(idx); + } + + if (jet1.pt() >= pt3) { + outputJetIndices.emplace_back(j1); + outputJetIndices.emplace_back(j2); + + for (auto const idx : idx_jets) { + if (outputJetIndices.size() > 3) + break; + outputJetIndices.emplace_back(idx); + } + } else if (idx_jets.size() >= 3) { + outputJetIndices.emplace_back(j1); + outputJetIndices.emplace_back(j2); + outputJetIndices.emplace_back(idx_jets[0]); + outputJetIndices.emplace_back(idx_jets[1]); + outputJetIndices.emplace_back(idx_jets[2]); + + if (idx_jets.size() > 3) { + outputJetIndices.emplace_back(idx_jets[3]); + } + } + } + } + } +} + +template +bool HLTL1TMatchedJetsVBFFilter::hltFilter(edm::Event& iEvent, + const edm::EventSetup&, + trigger::TriggerFilterObjectWithRefs& filterproduct) const { + if (saveTags()) + filterproduct.addCollectionTag(jetTag_); + + // handle to input HLT jets + auto const& jetsHandle = iEvent.getHandle(jetToken_); + + // indices of input HLT jets satisfying delta-R matching requirements + std::vector jetIndices; + + if (matchJetsByDeltaR_) { + // refs to L1T jets used for delta-R matching + l1t::JetVectorRef l1tJetRefs; + iEvent.get(l1tJetRefsToken_).getObjects(trigger::TriggerL1Jet, l1tJetRefs); + + jetIndices.reserve(jetsHandle->size()); + for (unsigned int iJet = 0; iJet < jetsHandle->size(); ++iJet) { + auto const& jet = (*jetsHandle)[iJet]; + + if (jet.pt() <= minPt2_) + continue; + + for (unsigned int l1tJetIdx = 0; l1tJetIdx < l1tJetRefs.size(); ++l1tJetIdx) { + if (reco::deltaR2(jet.p4(), l1tJetRefs[l1tJetIdx]->p4()) < maxJetDeltaR2_) { + jetIndices.emplace_back(iJet); + break; + } + } + } + } else { + jetIndices.reserve(jetsHandle->size()); + for (unsigned int iJet = 0; iJet < jetsHandle->size(); ++iJet) { + auto const& jet = (*jetsHandle)[iJet]; + + if (jet.pt() <= minPt2_) + continue; + + jetIndices.emplace_back(iJet); + } + } + + // order jet indices by jet pT (highest pT first) + std::sort(jetIndices.begin(), jetIndices.end(), [&jetsHandle](unsigned int const i1, unsigned int const i2) { + return (*jetsHandle)[i1].pt() > (*jetsHandle)[i2].pt(); + }); + + // indices of jets identified as compatible with the VBF topology + std::vector outputJetIndices; + fillJetIndices(outputJetIndices, *jetsHandle, jetIndices, minPt1_, minPt3_, minInvMass_); + + // add selected jets to trigger::TriggerFilterObjectWithRefs + for (auto const idx : outputJetIndices) { + filterproduct.addObject(triggerType_, edm::Ref>(jetsHandle, idx)); + } + + // accept event only if minNJets and maxNJets requirements are satisfied + return ((minNJets_ < 0 or outputJetIndices.size() >= (unsigned int)minNJets_) and + (maxNJets_ < 0 or outputJetIndices.size() <= (unsigned int)maxNJets_)); +} + +#endif diff --git a/HLTrigger/JetMET/plugins/HLTL1TMatchedPFJetsVBFFilter.cc b/HLTrigger/JetMET/plugins/HLTL1TMatchedPFJetsVBFFilter.cc new file mode 100644 index 0000000000000..a32dc1ceb2d98 --- /dev/null +++ b/HLTrigger/JetMET/plugins/HLTL1TMatchedPFJetsVBFFilter.cc @@ -0,0 +1,7 @@ +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "HLTL1TMatchedJetsVBFFilter.h" +#include "DataFormats/JetReco/interface/PFJet.h" + +typedef HLTL1TMatchedJetsVBFFilter HLTL1TMatchedPFJetsVBFFilter; +DEFINE_FWK_MODULE(HLTL1TMatchedPFJetsVBFFilter);