diff --git a/DQMOffline/HLTScouting/python/HLTScoutingDqmOffline_cff.py b/DQMOffline/HLTScouting/python/HLTScoutingDqmOffline_cff.py index 38d24c235f7d7..3a79a061e338c 100644 --- a/DQMOffline/HLTScouting/python/HLTScoutingDqmOffline_cff.py +++ b/DQMOffline/HLTScouting/python/HLTScoutingDqmOffline_cff.py @@ -47,6 +47,7 @@ hltScoutingDqmOffline = cms.Sequence(hltScoutingMuonDqmOffline + hltScoutingEGammaDqmOffline + hltScoutingJetDqmOffline + + run3ScoutingElectronBestTrack + hltScoutingDileptonMonitor + hltScoutingPi0Monitor + hltScoutingCollectionMonitor) diff --git a/HLTriggerOffline/Scouting/plugins/ScoutingDileptonMonitor.cc b/HLTriggerOffline/Scouting/plugins/ScoutingDileptonMonitor.cc index 18be1e8e5a0b7..2aec9560cead2 100644 --- a/HLTriggerOffline/Scouting/plugins/ScoutingDileptonMonitor.cc +++ b/HLTriggerOffline/Scouting/plugins/ScoutingDileptonMonitor.cc @@ -1,18 +1,22 @@ // system includes -#include -#include +#include #include +#include #include // user includes #include "CommonTools/Utils/interface/StringCutObjectSelector.h" #include "DQMServices/Core/interface/DQMEDAnalyzer.h" #include "DQMServices/Core/interface/DQMStore.h" +#include "DataFormats/Common/interface/Ref.h" +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/Common/interface/ValueMap.h" #include "DataFormats/Math/interface/LorentzVector.h" #include "DataFormats/Scouting/interface/Run3ScoutingElectron.h" #include "DataFormats/Scouting/interface/Run3ScoutingMuon.h" #include "FWCore/Framework/interface/Event.h" #include "FWCore/Framework/interface/MakerMacros.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" @@ -20,33 +24,56 @@ #include "ScoutingDQMUtils.h" +// --------------------------------------------------------------------------- +// Anonymous helpers +// --------------------------------------------------------------------------- namespace { bool checkScoutingID(const Run3ScoutingMuon& obj) { return scoutingDQMUtils::scoutingMuonID(obj); } - bool checkScoutingID(const Run3ScoutingElectron& obj) { return scoutingDQMUtils::scoutingElectronID(obj); } } // namespace +// --------------------------------------------------------------------------- +// scouting helpers - work on plain objects + optional ValueMap +// --------------------------------------------------------------------------- namespace scouting { - inline int charge(const Run3ScoutingMuon& mu) { return mu.charge(); } - inline int charge(const Run3ScoutingElectron& el) { return el.trkcharge()[0]; } + + // Muon: charge is a direct member + inline int chargeMu(const Run3ScoutingMuon& mu) { return mu.charge(); } + + // Electron: charge lives in the track vector; use ValueMap for best-track index when available + inline int chargeEl(const Run3ScoutingElectron& el, + const edm::ValueMap* vmBestIdx, + size_t collectionIndex, + const edm::Handle& handle) { + if (vmBestIdx) { + edm::Ref ref(handle, collectionIndex); + int idx = (*vmBestIdx)[ref]; + return el.trkcharge()[idx]; + } + return el.trkcharge()[0]; + } template math::PtEtaPhiMLorentzVector p4(const T& obj, double mass) { return math::PtEtaPhiMLorentzVector(obj.pt(), obj.eta(), obj.phi(), mass); } + } // namespace scouting +// --------------------------------------------------------------------------- +// Monitor class +// --------------------------------------------------------------------------- class ScoutingDileptonMonitor : public DQMEDAnalyzer { public: explicit ScoutingDileptonMonitor(const edm::ParameterSet&); ~ScoutingDileptonMonitor() override = default; - static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + static void fillDescriptions(edm::ConfigurationDescriptions&); void bookHistograms(DQMStore::IBooker&, edm::Run const&, edm::EventSetup const&) override; void analyze(edm::Event const&, edm::EventSetup const&) override; private: - // ---- internal structs ------------------------------------------------- + // ---- per-collection histogram set ------------------------------------- struct MassHistos { MonitorElement* full{nullptr}; MonitorElement* zwin{nullptr}; @@ -59,26 +86,30 @@ class ScoutingDileptonMonitor : public DQMEDAnalyzer { template void analyzeCollection(const edm::Event&, const edm::EDGetTokenT>&, + const edm::EDGetTokenT>*, // nullptr = no ValueMap (muons) const StringCutObjectSelector&, MassHistos&, bool doEtaSplit, bool useID); - template - void fillPairs(const std::vector&, MassHistos&, bool doEtaSplit); + void fillPairs(const std::vector& indices, + const edm::Handle>& handle, + const edm::ValueMap* /*unused*/, + MassHistos&, + bool doEtaSplit); + + void fillPairs(const std::vector& indices, + const edm::Handle>& handle, + const edm::ValueMap* vmBestIdx, + MassHistos&, + bool doEtaSplit); // ---- configuration ---------------------------------------------------- const std::string outputInternalPath_; - const double massMin_; - const double massMax_; + const double massMin_, massMax_; const int massBins_; - - const double zMin_; - const double zMax_; - - const double jpsiMin_; - const double jpsiMax_; - + const double zMin_, zMax_; + const double jpsiMin_, jpsiMax_; const double barrelEta_; // ---- muons (Vtx) ------------------------------------------------------ @@ -96,50 +127,49 @@ class ScoutingDileptonMonitor : public DQMEDAnalyzer { // ---- electrons -------------------------------------------------------- const bool doElectrons_; const edm::EDGetTokenT> electronToken_; + const edm::EDGetTokenT> vmBestTrackIndexToken_; const StringCutObjectSelector electronCut_; MassHistos electronHistos_; const bool electronID_; }; +// --------------------------------------------------------------------------- +// Constructor +// --------------------------------------------------------------------------- ScoutingDileptonMonitor::ScoutingDileptonMonitor(const edm::ParameterSet& iConfig) : outputInternalPath_{iConfig.getParameter("OutputInternalPath")}, massMin_(iConfig.getParameter("massMin")), massMax_(iConfig.getParameter("massMax")), massBins_(iConfig.getParameter("massBins")), - zMin_(iConfig.getParameter("zMassMin")), zMax_(iConfig.getParameter("zMassMax")), - jpsiMin_(iConfig.getParameter("jpsiMassMin")), jpsiMax_(iConfig.getParameter("jpsiMassMax")), - barrelEta_(iConfig.getParameter("barrelEta")), - doMuons_(iConfig.getParameter("doMuons")), muonToken_(consumes>(iConfig.getParameter("muons"))), muonCut_(iConfig.getParameter("muonCut")), muonID_(iConfig.getParameter("muonID")), - doMuonsNoVtx_(iConfig.getParameter("doMuonsNoVtx")), muonNoVtxToken_(consumes>(iConfig.getParameter("muonsNoVtx"))), - doElectrons_(iConfig.getParameter("doElectrons")), electronToken_(consumes>(iConfig.getParameter("electrons"))), + vmBestTrackIndexToken_(consumes>(iConfig.getParameter("vmBestTrackIndex"))), electronCut_(iConfig.getParameter("electronCut")), electronID_(iConfig.getParameter("electronID")) {} +// --------------------------------------------------------------------------- +// bookHistograms +// --------------------------------------------------------------------------- void ScoutingDileptonMonitor::bookHistograms(DQMStore::IBooker& ibooker, edm::Run const&, edm::EventSetup const&) { ibooker.setCurrentFolder(outputInternalPath_); auto bookSet = [&](const std::string& name, MassHistos& h, bool splitEta) { h.full = ibooker.book1D( name + "_mass", name + " opposite-charge invariant mass;M [GeV];Events", massBins_, massMin_, massMax_); - h.zwin = ibooker.book1D(name + "_zMass", name + " Z window;M [GeV];Events", massBins_, zMin_, zMax_); - h.jpsiwin = ibooker.book1D(name + "_jpsiMass", name + " J/Psi window;M [GeV];Events", massBins_, jpsiMin_, jpsiMax_); - if (splitEta) { h.barrel = ibooker.book1D(name + "_barrelMass", name + " barrel;M [GeV];Events", massBins_, massMin_, massMax_); h.endcap = ibooker.book1D(name + "_endcapMass", name + " endcap;M [GeV];Events", massBins_, massMin_, massMax_); @@ -147,115 +177,157 @@ void ScoutingDileptonMonitor::bookHistograms(DQMStore::IBooker& ibooker, edm::Ru }; if (doMuons_) - bookSet("muons", muonHistos_, false); - + bookSet("muons", muonHistos_, true); if (doMuonsNoVtx_) - bookSet("muonsNoVtx", muonNoVtxHistos_, false); - + bookSet("muonsNoVtx", muonNoVtxHistos_, true); if (doElectrons_) bookSet("electrons", electronHistos_, true); } +// --------------------------------------------------------------------------- +// analyze +// --------------------------------------------------------------------------- void ScoutingDileptonMonitor::analyze(edm::Event const& iEvent, edm::EventSetup const&) { if (doMuons_) { - edm::LogInfo("ScoutingDileptonMonitor") << "doing muons: "; - edm::LogInfo("ScoutingDileptonMonitor") << "\n"; - analyzeCollection(iEvent, muonToken_, muonCut_, muonHistos_, false, muonID_); + edm::LogInfo("ScoutingDileptonMonitor") << "doing muons"; + analyzeCollection(iEvent, muonToken_, nullptr, muonCut_, muonHistos_, true, muonID_); } - if (doMuonsNoVtx_) { edm::LogInfo("ScoutingDileptonMonitor") << "doing muons NoVtx"; - analyzeCollection(iEvent, muonNoVtxToken_, muonCut_, muonNoVtxHistos_, false, muonID_); + analyzeCollection(iEvent, muonNoVtxToken_, nullptr, muonCut_, muonNoVtxHistos_, true, muonID_); } - if (doElectrons_) { - edm::LogInfo("ScoutingDileptonMonitor") << "doing electrons: "; - analyzeCollection(iEvent, electronToken_, electronCut_, electronHistos_, true, electronID_); + edm::LogInfo("ScoutingDileptonMonitor") << "doing electrons"; + analyzeCollection( + iEvent, electronToken_, &vmBestTrackIndexToken_, electronCut_, electronHistos_, true, electronID_); } } -// ------------------------------------------------------------------------ - +// --------------------------------------------------------------------------- +// analyzeCollection +// --------------------------------------------------------------------------- template void ScoutingDileptonMonitor::analyzeCollection(const edm::Event& iEvent, const edm::EDGetTokenT>& token, + const edm::EDGetTokenT>* bestTrackIndexToken, const StringCutObjectSelector& cut, MassHistos& histos, bool doEtaSplit, bool useID) { - edm::LogInfo("ScoutingDileptonMonitor") << "IN ANALYZE COLLECTION"; - edm::Handle> handle; iEvent.getByToken(token, handle); if (!handle.isValid()) { edm::LogWarning("ScoutingDileptonMonitor") << "Invalid Handle!"; return; - } else { - edm::LogInfo("ScoutingDileptonMonitor") << "Valid Handle!"; } - std::vector selected; - selected.reserve(handle->size()); + const edm::ValueMap* vmBestIdx = nullptr; + if (bestTrackIndexToken != nullptr) + vmBestIdx = &iEvent.get(*bestTrackIndexToken); edm::LogInfo("ScoutingDileptonMonitor") << "collection size: " << handle->size(); - for (const auto& obj : *handle) { - if (!cut(obj)) { + std::vector selected; + selected.reserve(handle->size()); + for (size_t i = 0; i < handle->size(); ++i) { + const auto& obj = (*handle)[i]; + if (!cut(obj)) continue; - } - if (useID && !checkScoutingID(obj)) { + if (useID && !checkScoutingID(obj)) continue; - } - selected.push_back(&obj); + selected.push_back(i); } - fillPairs(selected, histos, doEtaSplit); + fillPairs(selected, handle, vmBestIdx, histos, doEtaSplit); } -template -void ScoutingDileptonMonitor::fillPairs(const std::vector& leptons, MassHistos& histos, bool doEtaSplit) { - const double massHypothesis = - std::is_same_v ? scoutingDQMUtils::MUON_MASS : scoutingDQMUtils::ELECTRON_MASS; +// --------------------------------------------------------------------------- +// fillPairs - muon overload +// --------------------------------------------------------------------------- +void ScoutingDileptonMonitor::fillPairs(const std::vector& indices, + const edm::Handle>& handle, + const edm::ValueMap* /*unused*/, + MassHistos& histos, + bool doEtaSplit) { + const size_t n = indices.size(); + edm::LogInfo("ScoutingDileptonMonitor") << "muon lepton size: " << n; + + for (size_t ii = 0; ii < n; ++ii) { + for (size_t jj = ii + 1; jj < n; ++jj) { + const auto& mu_i = (*handle)[indices[ii]]; + const auto& mu_j = (*handle)[indices[jj]]; + + if (scouting::chargeMu(mu_i) * scouting::chargeMu(mu_j) >= 0) + continue; - const size_t n = leptons.size(); - edm::LogInfo("ScoutingDileptonMonitor") << "lepton size: " << n; + const auto p4 = scouting::p4(mu_i, scoutingDQMUtils::MUON_MASS) + scouting::p4(mu_j, scoutingDQMUtils::MUON_MASS); + const double mass = p4.mass(); - for (size_t i = 0; i < n; ++i) { - for (size_t j = i + 1; j < n; ++j) { - if (scouting::charge(*leptons[i]) * scouting::charge(*leptons[j]) >= 0) - continue; + histos.full->Fill(mass); + if (mass > zMin_ && mass < zMax_) + histos.zwin->Fill(mass); + if (mass > jpsiMin_ && mass < jpsiMax_) + histos.jpsiwin->Fill(mass); + if (doEtaSplit) { + const bool barrel = std::abs(mu_i.eta()) < barrelEta_ && std::abs(mu_j.eta()) < barrelEta_; + (barrel ? histos.barrel : histos.endcap)->Fill(mass); + } + } + } +} - const auto p4 = scouting::p4(*leptons[i], massHypothesis) + scouting::p4(*leptons[j], massHypothesis); +// --------------------------------------------------------------------------- +// fillPairs - electron overload +// --------------------------------------------------------------------------- +void ScoutingDileptonMonitor::fillPairs(const std::vector& indices, + const edm::Handle>& handle, + const edm::ValueMap* vmBestIdx, + MassHistos& histos, + bool doEtaSplit) { + const size_t n = indices.size(); + edm::LogInfo("ScoutingDileptonMonitor") << "electron lepton size: " << n; + + for (size_t ii = 0; ii < n; ++ii) { + for (size_t jj = ii + 1; jj < n; ++jj) { + const size_t idx_i = indices[ii]; + const size_t idx_j = indices[jj]; + const auto& el_i = (*handle)[idx_i]; + const auto& el_j = (*handle)[idx_j]; + + const int q_i = scouting::chargeEl(el_i, vmBestIdx, idx_i, handle); + const int q_j = scouting::chargeEl(el_j, vmBestIdx, idx_j, handle); + if (q_i * q_j >= 0) + continue; + const auto p4 = + scouting::p4(el_i, scoutingDQMUtils::ELECTRON_MASS) + scouting::p4(el_j, scoutingDQMUtils::ELECTRON_MASS); const double mass = p4.mass(); histos.full->Fill(mass); - if (mass > zMin_ && mass < zMax_) histos.zwin->Fill(mass); - if (mass > jpsiMin_ && mass < jpsiMax_) histos.jpsiwin->Fill(mass); - if (doEtaSplit) { - const bool barrel = std::abs(leptons[i]->eta()) < barrelEta_ && std::abs(leptons[j]->eta()) < barrelEta_; - - if (barrel) - histos.barrel->Fill(mass); - else - histos.endcap->Fill(mass); + const bool barrel = std::abs(el_i.eta()) < barrelEta_ && std::abs(el_j.eta()) < barrelEta_; + (barrel ? histos.barrel : histos.endcap)->Fill(mass); } } } } +// --------------------------------------------------------------------------- +// fillDescriptions +// --------------------------------------------------------------------------- void ScoutingDileptonMonitor::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { edm::ParameterSetDescription desc; desc.add("OutputInternalPath", "HLT/ScoutingOffline/DiLepton"); desc.add("muons", edm::InputTag("hltScoutingMuonPackerVtx")); desc.add("muonsNoVtx", edm::InputTag("hltScoutingMuonPackerNoVtx")); desc.add("electrons", edm::InputTag("hltScoutingEgammaPacker")); + desc.add("vmBestTrackIndex", + edm::InputTag("run3ScoutingElectronBestTrack", "Run3ScoutingElectronBestTrackIndex")); desc.add("doMuons", true); desc.add("doMuonsNoVtx", true); desc.add("doElectrons", true); @@ -264,13 +336,10 @@ void ScoutingDileptonMonitor::fillDescriptions(edm::ConfigurationDescriptions& d desc.add("massBins", 120); desc.add("massMin", 0.0); desc.add("massMax", 200.0); - desc.add("zMassMin", 70.0); desc.add("zMassMax", 110.0); - desc.add("jpsiMassMin", 2.6); desc.add("jpsiMassMax", 3.5); - desc.add("barrelEta", 1.479); desc.add("muonID", true); desc.add("electronID", true);