From 35dfe12cad122bb41d5f6319c440c74d6ccf1640 Mon Sep 17 00:00:00 2001 From: Michel De Cian <michel.de.cian@cern.ch> Date: Fri, 31 Jan 2025 10:23:33 +0100 Subject: [PATCH] Fix MuonUT truthmatching in PrTrackAssociator --- Pr/PrMCTools/src/PrTrackAssociator.cpp | 57 ++++++++++++++++++-------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/Pr/PrMCTools/src/PrTrackAssociator.cpp b/Pr/PrMCTools/src/PrTrackAssociator.cpp index 563248b1df6..c252f30602a 100644 --- a/Pr/PrMCTools/src/PrTrackAssociator.cpp +++ b/Pr/PrMCTools/src/PrTrackAssociator.cpp @@ -37,7 +37,7 @@ namespace { unsigned int nT{ 0 }; unsigned int nMuon{ 0 }; unsigned int seniority{ 0 }; - unsigned int nMeasurements() const { return nVelo + nTT + nT; }; + unsigned int nMeasurements() const { return nVelo + nTT + nT + nMuon; }; }; TruthCounter& getCounter( const LHCb::MCParticle* part, std::vector<TruthCounter>& truthCounters ) { @@ -60,7 +60,8 @@ namespace { std::tuple<TruthCounter, std::vector<TruthCounter>> match_track( LHCb::span<LHCb::LHCbID const> lhcbIDs, const LHCb::MCParticles& mcParts, - const LHCb::LinksByKey& idlinks ) { + const LHCb::LinksByKey& idlinks, + const bool matchMuon ) { /// total number of measurements TruthCounter total; /// vector of counters of associated MC particles @@ -86,7 +87,7 @@ namespace { auto* part = static_cast<const LHCb::MCParticle*>( mcParts.containedObject( mcPartKey ) ); if ( part && &mcParts == part->parent() ) incrementT( part, truthCounters ); } ); - } else if ( ids.isMuon() ) { + } else if ( matchMuon && ids.isMuon() ) { ++total.nMuon; // Count number of Muon hits idlinks.applyToLinks( ids.lhcbID(), [&mcParts, &truthCounters]( unsigned int, unsigned int mcPartKey, float ) { auto* part = static_cast<const LHCb::MCParticle*>( mcParts.containedObject( mcPartKey ) ); @@ -175,22 +176,26 @@ namespace { if ( fractionOK <= ratio ) { tOK = true; } } - bool ttOK = ( counter.nTT + 2 > total.nTT ); + // -- The following is identical to + // -- bool ttOK = ( counter.nTT + 2 > total.nTT ) + // -- as it was implemented before + // -- but more consistently formulated + // -- compared to the other criteria + bool ttOK = true; + if ( total.nTT > 1 ) { + ttOK = ( counter.nTT + 2 > total.nTT ); // for most cases means: 3 out of 4 correctly matched + } + // -- We match long tracks even if the UT match is wrong if ( 2 < total.nVelo && 2 < total.nT ) { ttOK = true; } - bool MuonOK = ( total.nMuon > 2 && total.nMuon < counter.nMuon + 2 ); - - // for standalone Muon/ VeloMuon /MuonUT match for tracking efficiency study - if ( total.nMeasurements() == 0 && MuonOK ) { return (double)( counter.nMuon ) / total.nMuon; } - if ( total.nTT == 0 && total.nT == 0 && veloOK && MuonOK ) { - return (double)( counter.nMuon + counter.nVelo ) / ( total.nVelo + total.nMuon ); + bool muonOK = true; + if ( total.nMuon > 1 ) { + muonOK = ( counter.nMuon + 2 > total.nMuon ); // for most cases means: 3 out of 4 correctly matched } - if ( total.nVelo == 0 && total.nT == 0 && ttOK && MuonOK ) { - return (double)( counter.nMuon + counter.nTT ) / ( total.nTT + total.nMuon ); - } - - if ( veloOK && tOK && ttOK && ( 0 < total.nMeasurements() ) ) { - return (double)( counter.nVelo + counter.nTT + counter.nT ) / total.nMeasurements(); + // this should work for all track types, as xyOK is always true if the track type does not have hits of that + // detector + if ( veloOK && tOK && ttOK && muonOK && ( 0 < total.nMeasurements() ) ) { + return (double)( counter.nVelo + counter.nTT + counter.nT + counter.nMuon ) / total.nMeasurements(); } return {}; @@ -234,6 +239,9 @@ public: KeyValue{ "MCVerticesInput", LHCb::MCVertexLocation::Default }, KeyValue{ "SingleContainer", "" }, KeyValue{ "LinkerLocationID", "Link/Pr/LHCbID" } }, KeyValue{ "OutputLocation", "" } ){}; + + using TrackType = LHCb::Event::Enum::Track::Type; + LHCb::LinksByKey operator()( const LHCb::MCParticles& mcParts, const LHCb::MCVertices& /* */, const Tracks& tracks, const LHCb::LinksByKey& idlinks ) const override { // Create the Linker table from Track to MCParticle @@ -245,9 +253,17 @@ public: // Loop over the Tracks for ( auto const& [index, tr] : LHCb::range::enumerate( tracks ) ) { + + // -- Muon hits are not treated consistently, we therefore need to explicitly list the track types + // -- where they should be taken into account + const bool matchMuon = + std::any_of( m_trackTypesWithMuonMatch.begin(), m_trackTypesWithMuonMatch.end(), + [&tr]( TrackType type ) { return type == Gaudi::Functional::details::deref( tr ).type(); } ); + /// total number of measurements and /// vector of counters of associated MC particles - auto [total, truthCounters] = match_track( Gaudi::Functional::details::deref( tr ).lhcbIDs(), mcParts, idlinks ); + auto [total, truthCounters] = + match_track( Gaudi::Functional::details::deref( tr ).lhcbIDs(), mcParts, idlinks, matchMuon ); bool is_associated = false; unsigned int n_mcparticles = 0; @@ -277,7 +293,12 @@ public: }; private: - Gaudi::Property<double> m_fractionOK{ this, "FractionOK", 0.70, "minimal good matching fraction" }; + Gaudi::Property<double> m_fractionOK{ this, "FractionOK", 0.70, "minimal good matching fraction" }; + Gaudi::Property<std::vector<TrackType>> m_trackTypesWithMuonMatch{ + this, + "TrackTypesWithMuonMatch", + { TrackType::Muon, TrackType::VeloMuon, TrackType::MuonUT }, + "track types that use muon hits for matching" }; mutable Gaudi::Accumulators::BinomialCounter<> m_efficiency{ this, "Efficiency" }; mutable Gaudi::Accumulators::AveragingCounter<> m_mcparticles_per_track{ this, "MC particles per track" }; }; -- GitLab