/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
DQM/TrackingMonitor/src/PrimaryVertexResolution.cc
546 строк
21 KB
Marco Musich
PrimaryVertexResolution: add protection against missing track references in input vertex
28 сен 2025, 21:58
28 сен 2025, 21:58
f88e74b
Код
Авторство
О чём код?
#include "FWCore/Framework/interface/Event.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" #include "FWCore/ParameterSet/interface/ParameterSetDescription.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "DQMServices/Core/interface/DQMEDAnalyzer.h" #include "DQMServices/Core/interface/DQMStore.h" #include "DataFormats/Common/interface/Handle.h" #include "DataFormats/VertexReco/interface/Vertex.h" #include "DataFormats/VertexReco/interface/VertexFwd.h" #include "DataFormats/BeamSpot/interface/BeamSpot.h" #include "DataFormats/Scalers/interface/LumiScalers.h" #include "DataFormats/OnlineMetaData/interface/OnlineLuminosityRecord.h" #include "TrackingTools/TransientTrack/interface/TransientTrack.h" #include "RecoVertex/VertexPrimitives/interface/TransientVertex.h" #include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h" #include "TrackingTools/Records/interface/TransientTrackRecord.h" #include "RecoVertex/AdaptiveVertexFit/interface/AdaptiveVertexFitter.h" #include <random> namespace { template <typename T, size_t N> std::array<T, N + 1> makeLogBins(const double min, const double max) { const double minLog10 = std::log10(min); const double maxLog10 = std::log10(max); const double width = (maxLog10 - minLog10) / N; std::array<T, N + 1> ret; ret[0] = std::pow(10, minLog10); const double mult = std::pow(10, width); for (size_t i = 1; i <= N; ++i) { ret[i] = ret[i - 1] * mult; } return ret; } template <typename T> T sqr(T val) { return val * val; } } // namespace class PrimaryVertexResolution : public DQMEDAnalyzer { public: PrimaryVertexResolution(const edm::ParameterSet& iConfig); ~PrimaryVertexResolution() override = default; void bookHistograms(DQMStore::IBooker&, edm::Run const&, edm::EventSetup const&) override; void analyze(const edm::Event&, const edm::EventSetup&) override; static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); private: std::vector<reco::TransientTrack> sortTracksByPt(const reco::Vertex& thePV, const TransientTrackBuilder& ttBuilder, const reco::BeamSpot& beamspot); const edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> ttbToken_; const edm::InputTag vertexInputTag_; const edm::EDGetTokenT<reco::VertexCollection> vertexSrc_; const edm::EDGetTokenT<reco::BeamSpot> beamspotSrc_; const edm::EDGetTokenT<LumiScalersCollection> lumiScalersSrc_; const edm::EDGetTokenT<OnlineLuminosityRecord> metaDataSrc_; const bool forceSCAL_; const std::string rootFolder_; bool errorPrinted_; AdaptiveVertexFitter fitter_; struct BinningY { explicit BinningY(const edm::ParameterSet& iConfig) : maxResol_(iConfig.getUntrackedParameter<double>("maxResol")), binsResol_(iConfig.getUntrackedParameter<int>("binsResol")), maxPull_(iConfig.getUntrackedParameter<double>("maxPull")), binsPull_(iConfig.getUntrackedParameter<int>("binsPull")) {} const double maxResol_; const int binsResol_; const double maxPull_; const int binsPull_; }; struct BinningX { explicit BinningX(const edm::ParameterSet& iConfig) : minNtracks_(iConfig.getUntrackedParameter<double>("minNtracks")), maxNtracks_(iConfig.getUntrackedParameter<double>("maxNtracks")), binsNtracks_(iConfig.getUntrackedParameter<int>("binsNtracks")), minNvertices_(iConfig.getUntrackedParameter<double>("minNvertices")), maxNvertices_(iConfig.getUntrackedParameter<double>("maxNvertices")), binsNvertices_(iConfig.getUntrackedParameter<int>("binsNvertices")), maxXY_(iConfig.getUntrackedParameter<double>("maxXY")), binsXY_(iConfig.getUntrackedParameter<int>("binsXY")), maxZ_(iConfig.getUntrackedParameter<double>("maxZ")), binsZ_(iConfig.getUntrackedParameter<int>("binsZ")), minPt_(iConfig.getUntrackedParameter<double>("minPt")), maxPt_(iConfig.getUntrackedParameter<double>("maxPt")), minLumi_(iConfig.getUntrackedParameter<double>("minLumi")), maxLumi_(iConfig.getUntrackedParameter<double>("maxLumi")) {} const int minNtracks_; const int maxNtracks_; const int binsNtracks_; const int minNvertices_; const int maxNvertices_; const int binsNvertices_; const double maxXY_; const int binsXY_; const double maxZ_; const int binsZ_; const double minPt_; const double maxPt_; const double minLumi_; const double maxLumi_; }; class Resolution { public: Resolution(const reco::Vertex& vertex1, const reco::Vertex& vertex2) { const double diffx = vertex1.x() - vertex2.x(); const double diffy = vertex1.y() - vertex2.y(); const double diffz = vertex1.z() - vertex2.z(); // Take into account the need to divide by sqrt(2) already in // the filling so that we can use DQMGenericClient for the // gaussian fits const double invSqrt2 = 1. / std::sqrt(2.); resx_ = diffx * invSqrt2; resy_ = diffy * invSqrt2; resz_ = diffz * invSqrt2; pullx_ = diffx / std::sqrt(sqr(vertex1.xError()) + sqr(vertex2.xError())); pully_ = diffy / std::sqrt(sqr(vertex1.yError()) + sqr(vertex2.yError())); pullz_ = diffz / std::sqrt(sqr(vertex1.zError()) + sqr(vertex2.zError())); avgx_ = (vertex1.x() + vertex2.x()) / 2.; avgy_ = (vertex1.y() + vertex2.y()) / 2.; avgz_ = (vertex1.z() + vertex2.z()) / 2.; } double resx() const { return resx_; } double resy() const { return resy_; } double resz() const { return resz_; } double pullx() const { return pullx_; } double pully() const { return pully_; } double pullz() const { return pullz_; } double avgx() const { return avgx_; } double avgy() const { return avgy_; } double avgz() const { return avgz_; } private: double resx_; double resy_; double resz_; double pullx_; double pully_; double pullz_; double avgx_; double avgy_; double avgz_; }; class DiffPlots { public: explicit DiffPlots(const std::string& postfix, const BinningY& binY) : postfix_(postfix), binningY_(binY) {} template <typename T> void bookLogX(DQMStore::IBooker& iBooker, const T& binArray) { book(iBooker, binArray.size() - 1, binArray.front(), binArray.back()); setLogX(binArray.size() - 1, binArray.data()); } template <typename... Args> void book(DQMStore::IBooker& iBooker, Args&&... args) { const auto binsResol = binningY_.binsResol_; const auto maxResol = binningY_.maxResol_; hDiffX_ = iBooker.book2D("res_x_vs_" + postfix_, "Resolution of X vs. " + postfix_, std::forward<Args>(args)..., binsResol, -maxResol, maxResol); hDiffY_ = iBooker.book2D("res_y_vs_" + postfix_, "Resolution of Y vs. " + postfix_, std::forward<Args>(args)..., binsResol, -maxResol, maxResol); hDiffZ_ = iBooker.book2D("res_z_vs_" + postfix_, "Resolution of Z vs. " + postfix_, std::forward<Args>(args)..., binsResol, -maxResol, maxResol); const auto binsPull = binningY_.binsPull_; const auto maxPull = binningY_.maxPull_; hPullX_ = iBooker.book2D("pull_x_vs_" + postfix_, "Pull of X vs. " + postfix_, std::forward<Args>(args)..., binsPull, -maxPull, maxPull); hPullY_ = iBooker.book2D("pull_y_vs_" + postfix_, "Pull of Y vs. " + postfix_, std::forward<Args>(args)..., binsPull, -maxPull, maxPull); hPullZ_ = iBooker.book2D("pull_z_vs_" + postfix_, "Pull of Z vs. " + postfix_, std::forward<Args>(args)..., binsPull, -maxPull, maxPull); } template <typename... Args> void setLogX(Args&&... args) { hDiffX_->getTH2F()->GetXaxis()->Set(std::forward<Args>(args)...); hDiffY_->getTH2F()->GetXaxis()->Set(std::forward<Args>(args)...); hDiffZ_->getTH2F()->GetXaxis()->Set(std::forward<Args>(args)...); hPullX_->getTH2F()->GetXaxis()->Set(std::forward<Args>(args)...); hPullY_->getTH2F()->GetXaxis()->Set(std::forward<Args>(args)...); hPullZ_->getTH2F()->GetXaxis()->Set(std::forward<Args>(args)...); } template <typename T> void fill(const Resolution& res, const T ref) { hDiffX_->Fill(ref, res.resx()); hDiffY_->Fill(ref, res.resy()); hDiffZ_->Fill(ref, res.resz()); hPullX_->Fill(ref, res.pullx()); hPullY_->Fill(ref, res.pully()); hPullZ_->Fill(ref, res.pullz()); } private: std::string postfix_; const BinningY& binningY_; MonitorElement* hDiffX_ = nullptr; MonitorElement* hDiffY_ = nullptr; MonitorElement* hDiffZ_ = nullptr; MonitorElement* hPullX_ = nullptr; MonitorElement* hPullY_ = nullptr; MonitorElement* hPullZ_ = nullptr; }; class Plots { public: Plots(const BinningX& binX, const BinningY& binY) : binningX_(binX), binningY_(binY), hDiff_Ntracks_("ntracks", binY), hDiff_sumPt_("sumpt", binY), hDiff_Nvertices_("nvertices", binY), hDiff_X_("X", binY), hDiff_Y_("Y", binY), hDiff_Z_("Z", binY), hDiff_instLumiScal_("instLumiScal", binY) {} void book(DQMStore::IBooker& iBooker) { const auto binsResol = binningY_.binsResol_; const auto maxResol = binningY_.maxResol_; hDiffX_ = iBooker.book1D("res_x", "Resolution of X", binsResol, -maxResol, maxResol); hDiffY_ = iBooker.book1D("res_y", "Resolution of Y", binsResol, -maxResol, maxResol); hDiffZ_ = iBooker.book1D("res_z", "Resolution of Z", binsResol, -maxResol, maxResol); const auto binsPull = binningY_.binsPull_; const auto maxPull = binningY_.maxPull_; hPullX_ = iBooker.book1D(+"pull_x", "Pull of X", binsPull, -maxPull, maxPull); hPullY_ = iBooker.book1D(+"pull_y", "Pull of Y", binsPull, -maxPull, maxPull); hPullZ_ = iBooker.book1D(+"pull_z", "Pull of Z", binsPull, -maxPull, maxPull); hDiff_Ntracks_.book(iBooker, binningX_.binsNtracks_, binningX_.minNtracks_, binningX_.maxNtracks_); hDiff_Nvertices_.book(iBooker, binningX_.binsNvertices_, binningX_.minNvertices_, binningX_.maxNvertices_); hDiff_X_.book(iBooker, binningX_.binsXY_, -binningX_.maxXY_, binningX_.maxXY_); hDiff_Y_.book(iBooker, binningX_.binsXY_, -binningX_.maxXY_, binningX_.maxXY_); hDiff_Z_.book(iBooker, binningX_.binsZ_, -binningX_.maxZ_, binningX_.maxZ_); constexpr int binsPt = 30; hDiff_sumPt_.bookLogX(iBooker, makeLogBins<float, binsPt>(binningX_.minPt_, binningX_.maxPt_)); constexpr int binsLumi = 100; hDiff_instLumiScal_.bookLogX(iBooker, makeLogBins<float, binsLumi>(binningX_.minLumi_, binningX_.maxLumi_)); } void calculateAndFillResolution(const std::vector<reco::TransientTrack>& tracks, size_t nvertices, float lumi, std::mt19937& engine, AdaptiveVertexFitter& fitter); private: const BinningX& binningX_; const BinningY& binningY_; MonitorElement* hDiffX_ = nullptr; MonitorElement* hDiffY_ = nullptr; MonitorElement* hDiffZ_ = nullptr; MonitorElement* hPullX_ = nullptr; MonitorElement* hPullY_ = nullptr; MonitorElement* hPullZ_ = nullptr; DiffPlots hDiff_Ntracks_; DiffPlots hDiff_sumPt_; DiffPlots hDiff_Nvertices_; DiffPlots hDiff_X_; DiffPlots hDiff_Y_; DiffPlots hDiff_Z_; DiffPlots hDiff_instLumiScal_; }; // Binning BinningX binningX_; BinningY binningY_; // Histograms Plots hPV_; Plots hOtherV_; std::mt19937 engine_; }; PrimaryVertexResolution::PrimaryVertexResolution(const edm::ParameterSet& iConfig) : ttbToken_(esConsumes(edm::ESInputTag("", iConfig.getUntrackedParameter<std::string>("transientTrackBuilder")))), vertexInputTag_(iConfig.getUntrackedParameter<edm::InputTag>("vertexSrc")), vertexSrc_(consumes<reco::VertexCollection>(vertexInputTag_)), beamspotSrc_(consumes<reco::BeamSpot>(iConfig.getUntrackedParameter<edm::InputTag>("beamspotSrc"))), lumiScalersSrc_(consumes<LumiScalersCollection>(iConfig.getUntrackedParameter<edm::InputTag>("lumiScalersSrc"))), metaDataSrc_(consumes<OnlineLuminosityRecord>(iConfig.getUntrackedParameter<edm::InputTag>("metaDataSrc"))), forceSCAL_(iConfig.getUntrackedParameter<bool>("forceSCAL")), rootFolder_(iConfig.getUntrackedParameter<std::string>("rootFolder")), errorPrinted_(false), binningX_(iConfig), binningY_(iConfig), hPV_(binningX_, binningY_), hOtherV_(binningX_, binningY_) {} void PrimaryVertexResolution::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { edm::ParameterSetDescription desc; desc.addUntracked<edm::InputTag>("vertexSrc", edm::InputTag("trackingDQMgoodOfflinePrimaryVertices")); desc.addUntracked<edm::InputTag>("beamspotSrc", edm::InputTag("offlineBeamSpot")); desc.addUntracked<edm::InputTag>("lumiScalersSrc", edm::InputTag("scalersRawToDigi")); desc.addUntracked<edm::InputTag>("metaDataSrc", edm::InputTag("onlineMetaDataDigis")); desc.addUntracked<bool>("forceSCAL", true); desc.addUntracked<std::string>("rootFolder", "OfflinePV/Resolution"); desc.addUntracked<std::string>("transientTrackBuilder", "TransientTrackBuilder"); // Y axes desc.addUntracked<double>("maxResol", 0.02); desc.addUntracked<int>("binsResol", 100); desc.addUntracked<double>("maxPull", 5); desc.addUntracked<int>("binsPull", 100); // X axes desc.addUntracked<double>("minNtracks", -0.5); desc.addUntracked<double>("maxNtracks", 119.5); desc.addUntracked<int>("binsNtracks", 60); desc.addUntracked<double>("minNvertices", -0.5); desc.addUntracked<double>("maxNvertices", 199.5); desc.addUntracked<int>("binsNvertices", 100); desc.addUntracked<double>("maxXY", 0.15); desc.addUntracked<int>("binsXY", 100); desc.addUntracked<double>("maxZ", 30.); desc.addUntracked<int>("binsZ", 100); desc.addUntracked<double>("minPt", 1); desc.addUntracked<double>("maxPt", 1e3); desc.addUntracked<double>("minLumi", 200.); desc.addUntracked<double>("maxLumi", 20000.); descriptions.add("primaryVertexResolution", desc); } void PrimaryVertexResolution::bookHistograms(DQMStore::IBooker& iBooker, edm::Run const&, edm::EventSetup const&) { iBooker.setCurrentFolder(rootFolder_ + "/PV"); hPV_.book(iBooker); iBooker.setCurrentFolder(rootFolder_ + "/OtherV"); hOtherV_.book(iBooker); } void PrimaryVertexResolution::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) { edm::Handle<reco::VertexCollection> hvertices = iEvent.getHandle(vertexSrc_); if (!hvertices.isValid()) { return; } const reco::VertexCollection& vertices = *hvertices; if (vertices.empty()) return; // check upfront that refs to track are (likely) to be valid { bool ok = true; for (const auto& v : vertices) { if (v.tracksSize() > 0) { const auto& ref = v.trackRefAt(0); if (ref.isNull() || !ref.isAvailable()) { if (!errorPrinted_) edm::LogWarning("PrimaryVertexResolution") << "Skipping vertex collection: " << vertexInputTag_ << " since likely the track collection the vertex has refs pointing to is missing (at least the first " "TrackBaseRef is null or not available)"; else errorPrinted_ = true; ok = false; } } } if (!ok) return; } edm::Handle<reco::BeamSpot> hbeamspot = iEvent.getHandle(beamspotSrc_); const reco::BeamSpot& beamspot = *hbeamspot; float lumi = -1.; if (forceSCAL_) { edm::Handle<LumiScalersCollection> lumiScalers = iEvent.getHandle(lumiScalersSrc_); if (lumiScalers.isValid() && !lumiScalers->empty()) { LumiScalersCollection::const_iterator scalit = lumiScalers->begin(); lumi = scalit->instantLumi(); } } else { edm::Handle<OnlineLuminosityRecord> metaData = iEvent.getHandle(metaDataSrc_); if (metaData.isValid()) lumi = metaData->instLumi(); } const TransientTrackBuilder& ttBuilder = iSetup.getData(ttbToken_); // deterministic seed from the event number // should not bias the result as the event number is already // assigned randomly-enough engine_.seed(iEvent.id().event() + (iEvent.id().luminosityBlock() << 10) + (iEvent.id().run() << 20)); // The PV auto iPV = cbegin(vertices); const reco::Vertex& thePV = *iPV; const auto nvertices = vertices.size(); if (thePV.tracksSize() >= 4) { auto sortedTracks = sortTracksByPt(thePV, ttBuilder, beamspot); hPV_.calculateAndFillResolution(sortedTracks, nvertices, lumi, engine_, fitter_); } ++iPV; // Other vertices for (auto endPV = cend(vertices); iPV != endPV; ++iPV) { if (iPV->tracksSize() >= 4) { auto sortedTracks = sortTracksByPt(*iPV, ttBuilder, beamspot); hOtherV_.calculateAndFillResolution(sortedTracks, nvertices, lumi, engine_, fitter_); } } } std::vector<reco::TransientTrack> PrimaryVertexResolution::sortTracksByPt(const reco::Vertex& thePV, const TransientTrackBuilder& ttBuilder, const reco::BeamSpot& beamspot) { std::vector<const reco::Track*> sortedTracks; sortedTracks.reserve(thePV.tracksSize()); std::transform( thePV.tracks_begin(), thePV.tracks_end(), std::back_inserter(sortedTracks), [](const reco::TrackBaseRef& ref) { return &(*ref); }); std::sort(sortedTracks.begin(), sortedTracks.end(), [](const reco::Track* a, const reco::Track* b) { return a->pt() > b->pt(); }); std::vector<reco::TransientTrack> ttracks; ttracks.reserve(sortedTracks.size()); std::transform(sortedTracks.begin(), sortedTracks.end(), std::back_inserter(ttracks), [&](const reco::Track* track) { auto tt = ttBuilder.build(track); tt.setBeamSpot(beamspot); return tt; }); return ttracks; } void PrimaryVertexResolution::Plots::calculateAndFillResolution(const std::vector<reco::TransientTrack>& tracks, size_t nvertices, float lumi, std::mt19937& engine, AdaptiveVertexFitter& fitter) { const size_t end = tracks.size() % 2 == 0 ? tracks.size() : tracks.size() - 1; std::vector<reco::TransientTrack> set1, set2; set1.reserve(end / 2); set2.reserve(end / 2); auto dis = std::uniform_int_distribution<>(0, 1); // [0, 1] double sumpt1 = 0, sumpt2 = 0; for (size_t i = 0; i < end; i += 2) { const size_t set1_i = dis(engine); const size_t set2_i = 1 - set1_i; set1.push_back(tracks[i + set1_i]); set2.push_back(tracks[i + set2_i]); sumpt1 += set1.back().track().pt(); sumpt2 += set2.back().track().pt(); } // For resolution we only fit TransientVertex vertex1 = fitter.vertex(set1); TransientVertex vertex2 = fitter.vertex(set2); Resolution res(vertex1, vertex2); hDiffX_->Fill(res.resx()); hDiffY_->Fill(res.resy()); hDiffZ_->Fill(res.resz()); hPullX_->Fill(res.pullx()); hPullY_->Fill(res.pully()); hPullZ_->Fill(res.pullz()); hDiff_Ntracks_.fill(res, set1.size()); hDiff_sumPt_.fill( res, (sumpt1 + sumpt2) / 2.0); // taking average is probably the best we can do, anyway they should be close to each other hDiff_Nvertices_.fill(res, nvertices); if (vertex1.isValid() && vertex2.isValid()) { hDiff_X_.fill(res, res.avgx()); hDiff_Y_.fill(res, res.avgy()); hDiff_Z_.fill(res, res.avgz()); } hDiff_instLumiScal_.fill(res, lumi); } #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(PrimaryVertexResolution);