From 6612a6fb5f403c84c463c5c6ef6eb3fb2c9928f1 Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Wed, 24 Jun 2026 22:32:56 +0200 Subject: [PATCH 01/14] Add filling of mixed event matching candidates --- PWGDQ/Tasks/global-muon-matcher.cxx | 169 ++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index c16f2917b6e..84c246f0376 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -119,6 +119,22 @@ using SMatrix5 = o2::track::SMatrix5; constexpr std::array NDetElemCh = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; constexpr std::array SNDetElemCh = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156}; +// compute minimum difference between azimuthal angles +static float getDeltaPhi(float phi1, float phi2) +{ + float dphi = phi1 - phi2; + static constexpr float pi = TMath::Pi(); + static constexpr float twopi = pi; + if (dphi > pi) { + dphi -= twopi; + } + if (dphi < pi) { + dphi += twopi; + } + return dphi; +}; + + struct GlobalMuonMatching { static constexpr int GlobalTrackTypeMax = 2; @@ -139,6 +155,15 @@ struct GlobalMuonMatching { int matchRanking{-1}; }; + struct MchTrackInfo { + int64_t index{-1}; + int nMatchAttempts{-1}; + // vector of MFT-MCH matching candidates + std::vector matchingCandidates; + // vector of vectors of MFT-MCH matching candidates from mixed events + std::vector> mixedMatchingCandidates; + }; + //// Variables for selecting tagged muons struct : ConfigurableGroup { Configurable cfgMuonTaggingNCrossedMftPlanesLow{"cfgMuonTaggingNCrossedMftPlanesLow", 5, ""}; @@ -300,6 +325,7 @@ struct GlobalMuonMatching { std::array mLastMchAmbiguousBcSlice{}; int32_t mMatchCandidateCounter{0}; + std::unordered_map mMchTrackInfos; std::unordered_map> mMchTrackToCandidateIndices; std::unordered_map> mMchTrackMatchingCandidates; std::unordered_map mFwdTrackToGmmCandTrkIndex; @@ -1120,6 +1146,41 @@ struct GlobalMuonMatching { return std::fabs(deltaTrackTime) <= trackTimeResTot; } + template + int getMftMchMatchAttempts(EVT const& collisions, + BC const& bcs, + TMUON const& mchTrack, + TMFTS const& mftTracks) + { + if (!mchTrack.has_collision()) { + return 0; + } + const auto& collMch = collisions.rawIteratorAt(mchTrack.collisionId()); + const auto& bcMch = bcs.rawIteratorAt(collMch.bcId()); + + int attempts{0}; + for (const auto& mftTrack : mftTracks) { + if (!mftTrack.has_collision()) { + continue; + } + + const auto& collMft = collisions.rawIteratorAt(mftTrack.collisionId()); + const auto& bcMft = bcs.rawIteratorAt(collMft.bcId()); + + int64_t deltaBc = static_cast(bcMft.globalBC()) - static_cast(bcMch.globalBC()); + double deltaBcNS = o2::constants::lhc::LHCBunchSpacingNS * deltaBc; + double deltaTrackTime = mftTrack.trackTime() - mchTrack.trackTime() + deltaBcNS; + double trackTimeResTot = mftTrack.trackTimeRes() + mchTrack.trackTimeRes(); + + if (std::fabs(deltaTrackTime) > trackTimeResTot) { + continue; + } + attempts += 1; + } + + return attempts; + } + template void prepareMatchingCandidates(EVT const& collisions, BC const& bcs, @@ -1141,6 +1202,9 @@ struct GlobalMuonMatching { // initialize the MCH track parameters, which will be updated by the realignment if enabled mMchTrackPars.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); + + auto& mchTrackInfo = mMchTrackInfos[mchTrackIndex]; + mchTrackInfo.index = mchTrackIndex; } for (const auto& mftTrack : mftTracks) { @@ -1171,12 +1235,26 @@ struct GlobalMuonMatching { continue; } + auto& mchTrackInfo = mMchTrackInfos[mchTrackIndex]; + mchTrackInfo.index = mchTrackIndex; + mchTrackInfo.matchingCandidates.emplace_back(MatchingCandidate{ + .muonTrackId = muonTrack.globalIndex(), + .mftTrackId = mftTrackIndex, + .matchScore = muonTrack.matchScoreMCHMFT(), + .matchChi2 = muonTrack.chi2MatchMCHMFT()}); + mMatchingCandidates[mchTrackIndex].emplace_back(MatchingCandidate{ .muonTrackId = muonTrack.globalIndex(), .mftTrackId = mftTrackIndex, .matchScore = muonTrack.matchScoreMCHMFT(), .matchChi2 = muonTrack.chi2MatchMCHMFT()}); } + + // set the number of match attempts for this track + for (auto& mchTrackInfo : mMchTrackInfos) { + const auto& mchTrack = muonTracks.rawIteratorAt(mchTrackInfo.first); + mchTrackInfo.second.nMatchAttempts = getMftMchMatchAttempts(collisions, bcs, mchTrack, mftTracks); + } } else { // build matching candidates from all time-compatible MFT-MCH pairs for (const auto& muonTrack : muonTracks) { @@ -1192,10 +1270,20 @@ struct GlobalMuonMatching { continue; } + auto& mchTrackInfo = mMchTrackInfos[mchTrackIndex]; + mchTrackInfo.index = mchTrackIndex; + mchTrackInfo.matchingCandidates.emplace_back(MatchingCandidate{ + .mftTrackId = mftTrack.globalIndex()}); + mMatchingCandidates[mchTrackIndex].emplace_back(MatchingCandidate{ .mftTrackId = mftTrack.globalIndex()}); } } + + // set the number of match attempts for this track + for (auto& mchTrackInfo : mMchTrackInfos) { + mchTrackInfo.second.nMatchAttempts = mchTrackInfo.second.matchingCandidates.size(); + } } // sort the vectors of matching candidates in ascending order based on the matching chi2 value @@ -1208,6 +1296,85 @@ struct GlobalMuonMatching { } } + template + void prepareEventMixingMatchingCandidates(EVT const& collisions, + BC const& bcs, + TMUON const& muonTracks, + TMFT const& mftTracks, + MyMFTCovariances const& mftCovs) + { + LOGF(info, "Filling mixed matching candidate tables"); + + constexpr float deltaPhiMax = TMath::Pi() / 10; + + for (auto& [mchIndex1, mchTrackInfo1] : mMchTrackInfos) { + const auto& mchTrack1 = muonTracks.rawIteratorAt(mchIndex1); + + if (!mchTrack1.has_collision()) { + continue; + } + + const auto& collision1 = collisions.rawIteratorAt(mchTrack1.collisionId()); + const auto& bc1 = bcs.rawIteratorAt(collision1.bcId()); + + auto phi1 = std::atan2(mchTrack1.y(), mchTrack1.x()); + auto r1 = std::hypot(mchTrack1.x(), mchTrack1.y()); + + auto nAttempts1 = mchTrackInfo1.nMatchAttempts; + + auto vz1 = collision1.posZ(); + + for (const auto& [mchIndex2, mchTrackInfo2] : mMchTrackInfos) { + const auto& mchTrack2 = muonTracks.rawIteratorAt(mchIndex2); + + if (!mchTrack2.has_collision()) { + continue; + } + + const auto& collision2 = collisions.rawIteratorAt(mchTrack2.collisionId()); + const auto& bc2 = bcs.rawIteratorAt(collision2.bcId()); + + auto deltaBc = std::abs(static_cast(bc2.globalBC()) - static_cast(bc1.globalBC())); + if (deltaBc < 3564) { + continue; + } + + auto phi2 = std::atan2(mchTrack2.y(), mchTrack2.x()); + auto deltaPhi = std::fabs(getDeltaPhi(phi1, phi2)); + if (deltaPhi > deltaPhiMax) { + continue; + } + + auto r2 = std::hypot(mchTrack2.x(), mchTrack2.y()); + auto deltaR = r2 - r1; + if (deltaR > 10) { + continue; + } + + auto nAttempts2 = mchTrackInfo2.nMatchAttempts; + + float deltaAttempts = nAttempts2 - nAttempts1; + float deltaAttemptsRel = (nAttempts1 > 0) ? deltaAttempts / nAttempts1 : 0; + if (deltaAttemptsRel > 0.1) { + continue; + } + + auto vz2 = collision2.posZ(); + auto deltaZ = std::fabs(vz2 - vz1); + if (deltaZ > 1) { + continue; + } + + // add the candidates of MCH track #2 to the list of mixed candidates of track #1 + mchTrackInfo1.mixedMatchingCandidates.push_back(mchTrackInfo2.matchingCandidates); + // update the muon track index of the mixed candidates to the index of track #1 + for (auto& candidate : mchTrackInfo1.mixedMatchingCandidates.back()) { + candidate.muonTrackId = mchIndex1; + } + } + } + } + template o2::track::TrackParCovFwd transformMft(TMFT& mftTrack, TMFTCOV const& mftTrackCov) { @@ -1654,9 +1821,11 @@ struct GlobalMuonMatching { mMchTrackToCandidateIndices.clear(); mMchTrackMatchingCandidates.clear(); mFwdTrackToGmmCandTrkIndex.clear(); + mMchTrackInfos.clear(); LOGF(info, "Preparing candidates"); prepareMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); + prepareEventMixingMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); LOGF(info, "Processing candidates"); processMatchingCandidates(collisions, muonTracks, mftTracks, mftCovs, clusters); From 413cb506b74194e530731fff41f88cfe2441e368 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Tue, 30 Jun 2026 16:57:58 +0200 Subject: [PATCH 02/14] Processing candidates based on MchTrackInfo, filling table for mixed matches, filling Extras table, configurable group for mixing --- PWGDQ/Tasks/global-muon-matcher.cxx | 432 ++++++++++++++-------------- 1 file changed, 220 insertions(+), 212 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 84c246f0376..7062d7c593d 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -74,34 +74,21 @@ using namespace o2; using namespace o2::framework; using namespace o2::aod; -namespace o2::aod::globalmuonmatching -{ -DECLARE_SOA_COLUMN(MchTrackId, mchTrackId, int64_t); -DECLARE_SOA_COLUMN(MftTrackId, mftTrackId, int64_t); -DECLARE_SOA_COLUMN(MatchChi2, matchChi2, float); -DECLARE_SOA_COLUMN(MatchScore, matchScore, float); -DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); -DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); -} // namespace o2::aod::globalmuonmatching - namespace o2::aod { -DECLARE_SOA_TABLE(GlobalMuonMatchCandidates, "AOD", "GMCAND", - o2::soa::Index<>, - globalmuonmatching::MchTrackId, - globalmuonmatching::MftTrackId, - globalmuonmatching::MatchChi2, globalmuonmatching::MatchScore, globalmuonmatching::MatchRanking, - globalmuonmatching::IsTagged); - namespace globalmuonmatching { -DECLARE_SOA_ARRAY_INDEX_COLUMN(GlobalMuonMatchCandidate, globalMuonMatchCandidate); //! Array of GlobalMuonMatchCandidates indices +DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts +DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) +DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) DECLARE_SOA_INDEX_COLUMN_FULL(FwdTrackRealign, fwdTrackRealign, int, FwdTracksReAlign, ""); //! Index of ambiguous FwdTracksReAlign entry DECLARE_SOA_SLICE_INDEX_COLUMN_FULL(Bc, bc, int32_t, BCs, ""); //! BC index slice compatible with the track time window } // namespace globalmuonmatching -DECLARE_SOA_TABLE(FwdTrkMatchCands, "AOD", "FWDTRKMATCHCAND", //! Vectors of match-candidate indices stored per fwdtrack - globalmuonmatching::GlobalMuonMatchCandidateIds, o2::soa::Marker<3>); +DECLARE_SOA_TABLE(GmmCandFwdTrkExtras, "AOD", "GMMCANDEXTRA", //! Extra info joinable to FwdTracksReAlign + globalmuonmatching::IsTagged, + globalmuonmatching::MatchRanking, + globalmuonmatching::MixedGroupIndex); DECLARE_SOA_TABLE(AmbiguousFwdTracksReAlign, "AOD", "AMBIGFWDREALIGN", //! FwdTracksReAlign entries without a unique collision association o2::soa::Index<>, globalmuonmatching::FwdTrackRealignId, globalmuonmatching::BcIdSlice); @@ -153,11 +140,12 @@ struct GlobalMuonMatching { double matchScore{-1}; double matchChi2{-1}; int matchRanking{-1}; + int32_t mixedGroupIndex{-1}; }; struct MchTrackInfo { - int64_t index{-1}; int nMatchAttempts{-1}; + bool isTagged{false}; // vector of MFT-MCH matching candidates std::vector matchingCandidates; // vector of vectors of MFT-MCH matching candidates from mixed events @@ -230,6 +218,15 @@ struct GlobalMuonMatching { Configurable cfgMatchAllTracks{"cfgMatchAllTracks", false, "If true the matching is performed considering all the MFT tracks for which the covariances are available; if false the matching is performed considering only the global forward tracks stored at production"}; } configMatching; + struct : ConfigurableGroup { + Configurable cfgMixingDepth{"cfgMixingDepth", -1, "Maximum number of mixed candidate groups per MCH track (-1: no limit)"}; + Configurable cfgMinDeltaBc{"cfgMinDeltaBc", 3564, "Minimum DeltaBc between mixed collisions"}; + Configurable cfgMaxDeltaPhi{"cfgMaxDeltaPhi", static_cast(TMath::Pi() / 10), "Maximum DelptaPhi between mixed MCH tracks (rad)"}; + Configurable cfgMaxDeltaR{"cfgMaxDeltaR", 10.f, "Maximum DeltaR between mixed MCH tracks"}; + Configurable cfgMaxDeltaAttempts{"cfgMaxDeltaAttempts", 0.1f, "Maximum relative difference in match attempts"}; + Configurable cfgMaxDeltaZ{"cfgMaxDeltaZ", 1.f, "Maximum deltaZ between mixed collisions"}; + } configEventMixing; + double mBzAtMftCenter{0}; using MatchingFunc = std::function(const o2::track::TrackParCovFwd& mchtrack, const o2::track::TrackParCovFwd& mfttrack)>; @@ -271,7 +268,6 @@ struct GlobalMuonMatching { // to be sorted in descending order with respect to the matching score // the map key is the MCH(-MID) track global index using MatchingCandidates = std::map>; - std::map> mMatchingCandidates; class TrackParExt : public o2::track::TrackParCovFwd { @@ -313,10 +309,9 @@ struct GlobalMuonMatching { std::unordered_map mftTrackCovs; - Produces globalMuonMatchCandidates; - Produces fwdTrkMatchCands; Produces gmCandidateFwdTracks; Produces gmCandidateFwdTracksCov; + Produces gmCandidateFwdTrackExtras; Produces gmAmbiguousFwdTracksReAlign; int32_t mGmmCandFwdTrackRowIndex{0}; @@ -324,10 +319,8 @@ struct GlobalMuonMatching { bool mHasLastMchAmbiguousBcSlice{false}; std::array mLastMchAmbiguousBcSlice{}; - int32_t mMatchCandidateCounter{0}; std::unordered_map mMchTrackInfos; - std::unordered_map> mMchTrackToCandidateIndices; - std::unordered_map> mMchTrackMatchingCandidates; + std::unordered_map> mStoredMatchingCandidates; std::unordered_map mFwdTrackToGmmCandTrkIndex; mch::TrackFitter trackFitter; // Track fitter from MCH tracking library @@ -899,12 +892,19 @@ struct GlobalMuonMatching { rhoXY, rhoPhiY, rhoPhiX, rhoTglX, rhoTglY, rhoTglPhi, rho1PtX, rho1PtY, rho1PtPhi, rho1PtTgl); } + bool isMchTrackTagged(int64_t mchTrackIndex) const + { + const auto it = mMchTrackInfos.find(mchTrackIndex); + return it != mMchTrackInfos.end() && it->second.isTagged; + } + template void fillBaseGmmCandFwdTrack(TMCH const& track, TrackParExt const& trackPar, int32_t gmmMchTrackId, float chi2MatchMCHMFT, - float matchScoreMCHMFT) + float matchScoreMCHMFT, + bool isTagged) { const auto collisionId = track.collisionId(); bool hasBcSlice = false; @@ -943,6 +943,7 @@ struct GlobalMuonMatching { track.trackTimeRes()); storeFwdTrackCovariance(trackPar.getCovariances()); + gmCandidateFwdTrackExtras(isTagged, -1, -1); if (hasBcSlice) { gmAmbiguousFwdTracksReAlign(mGmmCandFwdTrackRowIndex, bcSlice.data()); } @@ -1024,6 +1025,7 @@ struct GlobalMuonMatching { mchTrack.trackTimeRes()); storeFwdTrackCovariance(globalMuonRefit.getCovariances()); + gmCandidateFwdTrackExtras(isMchTrackTagged(mchTrack.globalIndex()), candidate.matchRanking, candidate.mixedGroupIndex); if (hasBcSlice) { gmAmbiguousFwdTracksReAlign(mGmmCandFwdTrackRowIndex, bcSlice.data()); } @@ -1190,7 +1192,6 @@ struct GlobalMuonMatching { { mMftTrackPars.clear(); mMchTrackPars.clear(); - mMatchingCandidates.clear(); LOGF(info, "Filling matching candidate tables"); @@ -1203,8 +1204,10 @@ struct GlobalMuonMatching { // initialize the MCH track parameters, which will be updated by the realignment if enabled mMchTrackPars.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); - auto& mchTrackInfo = mMchTrackInfos[mchTrackIndex]; - mchTrackInfo.index = mchTrackIndex; + mMchTrackInfos.try_emplace(mchTrackIndex, MchTrackInfo{ + .nMatchAttempts = 0, + .matchingCandidates = std::vector(), + .mixedMatchingCandidates = std::vector>()}); } for (const auto& mftTrack : mftTracks) { @@ -1236,18 +1239,11 @@ struct GlobalMuonMatching { } auto& mchTrackInfo = mMchTrackInfos[mchTrackIndex]; - mchTrackInfo.index = mchTrackIndex; mchTrackInfo.matchingCandidates.emplace_back(MatchingCandidate{ .muonTrackId = muonTrack.globalIndex(), .mftTrackId = mftTrackIndex, .matchScore = muonTrack.matchScoreMCHMFT(), .matchChi2 = muonTrack.chi2MatchMCHMFT()}); - - mMatchingCandidates[mchTrackIndex].emplace_back(MatchingCandidate{ - .muonTrackId = muonTrack.globalIndex(), - .mftTrackId = mftTrackIndex, - .matchScore = muonTrack.matchScoreMCHMFT(), - .matchChi2 = muonTrack.chi2MatchMCHMFT()}); } // set the number of match attempts for this track @@ -1271,12 +1267,8 @@ struct GlobalMuonMatching { } auto& mchTrackInfo = mMchTrackInfos[mchTrackIndex]; - mchTrackInfo.index = mchTrackIndex; mchTrackInfo.matchingCandidates.emplace_back(MatchingCandidate{ .mftTrackId = mftTrack.globalIndex()}); - - mMatchingCandidates[mchTrackIndex].emplace_back(MatchingCandidate{ - .mftTrackId = mftTrack.globalIndex()}); } } @@ -1286,13 +1278,13 @@ struct GlobalMuonMatching { } } - // sort the vectors of matching candidates in ascending order based on the matching chi2 value - auto compareMatchingChi2 = [](const MatchingCandidate& track1, const MatchingCandidate& track2) -> bool { - return (track1.matchChi2 < track2.matchChi2); - }; - - for (auto& [mchIndex, candidatesVector] : mMatchingCandidates) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) - std::sort(candidatesVector.begin(), candidatesVector.end(), compareMatchingChi2); + std::vector taggedMuons; + getTaggedMuons(collisions, muonTracks, taggedMuons); + for (int64_t mchTrackIndex : taggedMuons) { + auto it = mMchTrackInfos.find(mchTrackIndex); + if (it != mMchTrackInfos.end()) { + it->second.isTagged = true; + } } } @@ -1305,7 +1297,12 @@ struct GlobalMuonMatching { { LOGF(info, "Filling mixed matching candidate tables"); - constexpr float deltaPhiMax = TMath::Pi() / 10; + const int mixingDepth = configEventMixing.cfgMixingDepth.value; + const int64_t minDeltaBc = configEventMixing.cfgMinDeltaBc.value; + const float maxDeltaPhi = configEventMixing.cfgMaxDeltaPhi.value; + const float maxDeltaR = configEventMixing.cfgMaxDeltaR.value; + const float maxDeltaAttemptsRel = configEventMixing.cfgMaxDeltaAttemptsRel.value; + const float maxDeltaZ = configEventMixing.cfgMaxDeltaZ.value; for (auto& [mchIndex1, mchTrackInfo1] : mMchTrackInfos) { const auto& mchTrack1 = muonTracks.rawIteratorAt(mchIndex1); @@ -1325,6 +1322,10 @@ struct GlobalMuonMatching { auto vz1 = collision1.posZ(); for (const auto& [mchIndex2, mchTrackInfo2] : mMchTrackInfos) { + if (mixingDepth >= 0 && static_cast(mchTrackInfo1.mixedMatchingCandidates.size()) >= mixingDepth) { + break; + } + const auto& mchTrack2 = muonTracks.rawIteratorAt(mchIndex2); if (!mchTrack2.has_collision()) { @@ -1335,19 +1336,19 @@ struct GlobalMuonMatching { const auto& bc2 = bcs.rawIteratorAt(collision2.bcId()); auto deltaBc = std::abs(static_cast(bc2.globalBC()) - static_cast(bc1.globalBC())); - if (deltaBc < 3564) { + if (deltaBc < minDeltaBc) { continue; } auto phi2 = std::atan2(mchTrack2.y(), mchTrack2.x()); auto deltaPhi = std::fabs(getDeltaPhi(phi1, phi2)); - if (deltaPhi > deltaPhiMax) { + if (deltaPhi > maxDeltaPhi) { continue; } auto r2 = std::hypot(mchTrack2.x(), mchTrack2.y()); auto deltaR = r2 - r1; - if (deltaR > 10) { + if (deltaR > maxDeltaR) { continue; } @@ -1355,13 +1356,13 @@ struct GlobalMuonMatching { float deltaAttempts = nAttempts2 - nAttempts1; float deltaAttemptsRel = (nAttempts1 > 0) ? deltaAttempts / nAttempts1 : 0; - if (deltaAttemptsRel > 0.1) { + if (deltaAttemptsRel > maxDeltaAttemptsRel) { continue; } auto vz2 = collision2.posZ(); auto deltaZ = std::fabs(vz2 - vz1); - if (deltaZ > 1) { + if (deltaZ > maxDeltaZ) { continue; } @@ -1493,8 +1494,8 @@ struct GlobalMuonMatching { void runChi2Matching(const std::string& funcName, float matchingPlaneZ, - const MatchingCandidates& matchingCandidates, - MatchingCandidates& newMatchingCandidates) + MatchingCandidates& newMatchingCandidates, + bool useMixedMatchingCandidates) { newMatchingCandidates.clear(); @@ -1510,50 +1511,72 @@ struct GlobalMuonMatching { } auto matchingFunc = mMatchingFunctionMap.at(funcNameEffective); - for (const auto& [mchIndex, candidatesVector] : matchingCandidates) { - + for (const auto& [mchIndex, mchTrackInfo] : mMchTrackInfos) { // get the tracks parameters, which have been updated by the realignment if enabled const auto mchTrackParIt = mMchTrackPars.find(mchIndex); if (mchTrackParIt == mMchTrackPars.end()) { continue; } - for (const auto& candidate : candidatesVector) { - auto mftTrackParIt = mMftTrackPars.find(candidate.mftTrackId); - if (mftTrackParIt == mMftTrackPars.end()) { - continue; - } + auto processGroup = [&](const std::vector& candidatesGroup, int32_t mixedGroupIndex) { + std::vector groupResults; + groupResults.reserve(candidatesGroup.size()); + + for (const auto& candidate : candidatesGroup) { + auto mftTrackParIt = mMftTrackPars.find(candidate.mftTrackId); + if (mftTrackParIt == mMftTrackPars.end()) { + continue; + } + + auto mftTrackProp = mftTrackParIt->second.asTrackParCovFwd(); + auto mchTrackProp = mchTrackParIt->second.asTrackParCovFwd(); + + if (matchingPlaneZEffective < 0.) { + mftTrackProp = propagateToZMft(mftTrackProp, matchingPlaneZ); + mchTrackProp = propagateToZMch(mchTrackProp, matchingPlaneZ); + } - auto mftTrackProp = mftTrackParIt->second.asTrackParCovFwd(); - auto mchTrackProp = mchTrackParIt->second.asTrackParCovFwd(); + auto matchResult = matchingFunc(mchTrackProp, mftTrackProp); + float matchChi2 = std::get<0>(matchResult); - if (matchingPlaneZEffective < 0.) { - mftTrackProp = propagateToZMft(mftTrackProp, matchingPlaneZ); - mchTrackProp = propagateToZMch(mchTrackProp, matchingPlaneZ); + groupResults.emplace_back(MatchingCandidate{ + .muonTrackId = candidate.muonTrackId, + .mftTrackId = candidate.mftTrackId, + .matchScore = -1, + .matchChi2 = matchChi2}); } - auto matchResult = matchingFunc(mchTrackProp, mftTrackProp); - float matchChi2 = std::get<0>(matchResult); + auto compareMatchingChi2 = [](const MatchingCandidate& track1, const MatchingCandidate& track2) -> bool { + return (track1.matchChi2 < track2.matchChi2); + }; + std::sort(groupResults.begin(), groupResults.end(), compareMatchingChi2); - newMatchingCandidates[mchIndex].emplace_back(MatchingCandidate{ - .muonTrackId = candidate.muonTrackId, - .mftTrackId = candidate.mftTrackId, - .matchScore = -1, - .matchChi2 = matchChi2}); - } - } + int ranking = 1; + for (auto& matchedCandidate : groupResults) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + matchedCandidate.matchRanking = ranking; + ranking += 1; + } - auto compareMatchingChi2 = [](const MatchingCandidate& track1, const MatchingCandidate& track2) -> bool { - return (track1.matchChi2 < track2.matchChi2); - }; + const int maxCandidates = configMatching.cfgMaxCandidatesPerMchTrack.value; + const size_t nToStore = (maxCandidates >= 0) + ? std::min(groupResults.size(), static_cast(maxCandidates)) + : groupResults.size(); - for (auto& [mchIndex, globalTracksVector] : newMatchingCandidates) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) - std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareMatchingChi2); + auto& storedCandidates = newMatchingCandidates[mchIndex]; + for (size_t i = 0; i < nToStore; ++i) { + groupResults[i].mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; + storedCandidates.push_back(std::move(groupResults[i])); + } + }; - int ranking = 1; - for (auto& candidate : globalTracksVector) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) - candidate.matchRanking = ranking; - ranking += 1; + if (useMixedMatchingCandidates) { + int32_t groupIdx = 0; + for (const auto& candidatesGroup : mchTrackInfo.mixedMatchingCandidates) { + processGroup(candidatesGroup, groupIdx); + groupIdx += 1; + } + } else { + processGroup(mchTrackInfo.matchingCandidates, -1); } } } @@ -1564,11 +1587,11 @@ struct GlobalMuonMatching { TMFT const& mftTracks, o2::analysis::MlResponseMFTMuonMatch& mlResponse, float matchingPlaneZ, - const MatchingCandidates& matchingCandidates, - MatchingCandidates& newMatchingCandidates) + MatchingCandidates& newMatchingCandidates, + bool useMixedMatchingCandidates) { newMatchingCandidates.clear(); - for (const auto& [mchIndex, candidatesVector] : matchingCandidates) { + for (const auto& [mchIndex, mchTrackInfo] : mMchTrackInfos) { auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); if (!mchTrack.has_collision()) { continue; @@ -1582,46 +1605,69 @@ struct GlobalMuonMatching { continue; } - for (const auto& candidate : candidatesVector) { - auto const& muonTrack = (candidate.muonTrackId >= 0) ? muonTracks.rawIteratorAt(candidate.muonTrackId) : mchTrack; - auto const& mftTrack = mftTracks.rawIteratorAt(candidate.mftTrackId); - auto mftTrackParIt = mMftTrackPars.find(candidate.mftTrackId); - if (mftTrackParIt == mMftTrackPars.end()) { - continue; - } + auto processGroup = [&](const std::vector& candidatesGroup, int32_t mixedGroupIndex) { + std::vector groupResults; + groupResults.reserve(candidatesGroup.size()); + + for (const auto& candidate : candidatesGroup) { + auto const& muonTrack = (candidate.muonTrackId >= 0) ? muonTracks.rawIteratorAt(candidate.muonTrackId) : mchTrack; + auto const& mftTrack = mftTracks.rawIteratorAt(candidate.mftTrackId); + auto mftTrackParIt = mMftTrackPars.find(candidate.mftTrackId); + if (mftTrackParIt == mMftTrackPars.end()) { + continue; + } - auto mftTrackProp = mftTrackParIt->second.asTrackParCovFwd(); - auto mchTrackProp = mchTrackParIt->second.asTrackParCovFwd(); + auto mftTrackProp = mftTrackParIt->second.asTrackParCovFwd(); + auto mchTrackProp = mchTrackParIt->second.asTrackParCovFwd(); - if (matchingPlaneZ < 0.) { - mftTrackProp = propagateToZMft(mftTrackProp, matchingPlaneZ); - mchTrackProp = propagateToZMch(mchTrackProp, matchingPlaneZ); + if (matchingPlaneZ < 0.) { + mftTrackProp = propagateToZMft(mftTrackProp, matchingPlaneZ); + mchTrackProp = propagateToZMch(mchTrackProp, matchingPlaneZ); + } + + std::vector output; + std::vector inputML = mlResponse.getInputFeatures(muonTrack, mftTrack, mchTrack, mftTrackProp, mchTrackProp, collision); + mlResponse.isSelectedMl(inputML, 0, output); + float matchScore = output[0]; + + groupResults.emplace_back(MatchingCandidate{ + .muonTrackId = candidate.muonTrackId, + .mftTrackId = candidate.mftTrackId, + .matchScore = matchScore, + .matchChi2 = -1}); } - std::vector output; - std::vector inputML = mlResponse.getInputFeatures(muonTrack, mftTrack, mchTrack, mftTrackProp, mchTrackProp, collision); - mlResponse.isSelectedMl(inputML, 0, output); - float matchScore = output[0]; + auto compareMatchingScore = [](const MatchingCandidate& track1, const MatchingCandidate& track2) -> bool { + return (track1.matchScore > track2.matchScore); + }; + std::sort(groupResults.begin(), groupResults.end(), compareMatchingScore); - newMatchingCandidates[mchIndex].emplace_back(MatchingCandidate{ - .muonTrackId = candidate.muonTrackId, - .mftTrackId = candidate.mftTrackId, - .matchScore = matchScore, - .matchChi2 = -1}); - } - } + int ranking = 1; + for (auto& matchedCandidate : groupResults) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + matchedCandidate.matchRanking = ranking; + ranking += 1; + } - auto compareMatchingScore = [](const MatchingCandidate& track1, const MatchingCandidate& track2) -> bool { - return (track1.matchScore > track2.matchScore); - }; + const int maxCandidates = configMatching.cfgMaxCandidatesPerMchTrack.value; + const size_t nToStore = (maxCandidates >= 0) + ? std::min(groupResults.size(), static_cast(maxCandidates)) + : groupResults.size(); - for (auto& [mchIndex, globalTracksVector] : newMatchingCandidates) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) - std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareMatchingScore); + auto& storedCandidates = newMatchingCandidates[mchIndex]; + for (size_t i = 0; i < nToStore; ++i) { + groupResults[i].mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; + storedCandidates.push_back(std::move(groupResults[i])); + } + }; - int ranking = 1; - for (auto& candidate : globalTracksVector) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) - candidate.matchRanking = ranking; - ranking += 1; + if (useMixedMatchingCandidates) { + int32_t groupIdx = 0; + for (const auto& candidatesGroup : mchTrackInfo.mixedMatchingCandidates) { + processGroup(candidatesGroup, groupIdx); + groupIdx += 1; + } + } else { + processGroup(mchTrackInfo.matchingCandidates, -1); } } } @@ -1631,7 +1677,8 @@ struct GlobalMuonMatching { TMUON const& muonTracks, TMFT const& mftTracks, CMFT const& mftCovs, - aod::FwdTrkCls const& clusters) + aod::FwdTrkCls const& clusters, + bool useMixedMatchingCandidates) { if (configMchRealign.cfgEnableMCHRealign.value) { runMuonRealignment(muonTracks, clusters); @@ -1641,66 +1688,30 @@ struct GlobalMuonMatching { runMftRealignment(mftTracks, mftCovs); } - std::vector taggedMuons; - getTaggedMuons(collisions, muonTracks, taggedMuons); - + MatchingCandidates newMatchingCandidates; if (configMatching.cfgCustomMatchingStrategy.value == 0) { if (hasActiveChi2Matching) { - MatchingCandidates newMatchingCandidates; - runChi2Matching(activeChi2FunctionName, activeChi2MatchingPlaneZ, mMatchingCandidates, newMatchingCandidates); - fillMatchingCandidates(newMatchingCandidates, taggedMuons); + runChi2Matching(activeChi2FunctionName, activeChi2MatchingPlaneZ, newMatchingCandidates, useMixedMatchingCandidates); } } else { if (hasActiveMlMatching) { - MatchingCandidates newMatchingCandidates; - runMlMatching(collisions, muonTracks, mftTracks, activeMlResponse, activeMlMatchingPlaneZ, mMatchingCandidates, newMatchingCandidates); - fillMatchingCandidates(newMatchingCandidates, taggedMuons); + runMlMatching(collisions, muonTracks, mftTracks, activeMlResponse, activeMlMatchingPlaneZ, newMatchingCandidates, useMixedMatchingCandidates); } } - } - void fillMatchingCandidates(const MatchingCandidates& matchingCandidates, - const std::vector& taggedMuons) - { - for (const auto& [mchIndex, candidates] : matchingCandidates) { + for (const auto& [mchIndex, candidates] : newMatchingCandidates) { if (candidates.empty()) { continue; } - bool isTagged = std::find(taggedMuons.begin(), taggedMuons.end(), mchIndex) != taggedMuons.end(); - - std::vector storedCandidates; - int nStored = 0; - for (const auto& candidate : candidates) { - if (configMatching.cfgMaxCandidatesPerMchTrack.value >= 0 && nStored >= configMatching.cfgMaxCandidatesPerMchTrack.value) { - break; - } - - int32_t candidateIndex = mMatchCandidateCounter; - globalMuonMatchCandidates( - mchIndex, - candidate.mftTrackId, - static_cast(candidate.matchChi2), - static_cast(candidate.matchScore), - static_cast(candidate.matchRanking), - isTagged); - mMatchCandidateCounter += 1; - - mMchTrackToCandidateIndices[mchIndex].push_back(candidateIndex); - storedCandidates.push_back(candidate); - nStored += 1; - } - - if (!storedCandidates.empty()) { - mMchTrackMatchingCandidates[mchIndex] = std::move(storedCandidates); - } + mStoredMatchingCandidates[mchIndex] = candidates; } } int32_t countStoredCandidatesForMchTrack(int64_t mchTrackIndex) const { - const auto candidateIterator = mMchTrackMatchingCandidates.find(mchTrackIndex); - if (candidateIterator == mMchTrackMatchingCandidates.end()) { + const auto candidateIterator = mStoredMatchingCandidates.find(mchTrackIndex); + if (candidateIterator == mStoredMatchingCandidates.end()) { return 0; } return static_cast(candidateIterator->second.size()); @@ -1742,18 +1753,13 @@ struct GlobalMuonMatching { const int64_t mchTrackIndex = track.globalIndex(); const int32_t gmmMchTrackId = mFwdTrackToGmmCandTrkIndex.at(mchTrackIndex); - const auto candidateIterator = mMchTrackMatchingCandidates.find(mchTrackIndex); + const auto candidateIterator = mStoredMatchingCandidates.find(mchTrackIndex); auto mchTrackParIt = mMchTrackPars.find(mchTrackIndex); - if (mchTrackParIt == mMchTrackPars.end()) { - // fill muon tracks table with original parameters - const TrackParExt trackPar{fwdtrackutils::getTrackParCovFwd(track, track)}; - fillBaseGmmCandFwdTrack(track, trackPar, gmmMchTrackId, -1.f, -1.f); - } else { - // fill muon tracks table with realignment parameters - fillBaseGmmCandFwdTrack(track, mchTrackParIt->second, gmmMchTrackId, -1.f, -1.f); - } + fillBaseGmmCandFwdTrack(track, mchTrackParIt->second, gmmMchTrackId, -1.f, -1.f, + isMchTrackTagged(mchTrackIndex)); + - if (candidateIterator != mMchTrackMatchingCandidates.end()) { + if (candidateIterator != mStoredMatchingCandidates.end()) { for (const auto& candidate : candidateIterator->second) { auto mftTrackParIt = mMftTrackPars.find(candidate.mftTrackId); if (mftTrackParIt != mMftTrackPars.end()) { @@ -1775,38 +1781,20 @@ struct GlobalMuonMatching { parExt, gmmMchTrackId, track.chi2MatchMCHMFT(), - track.matchScoreMCHMFT()); - } - } - } - - template - void fillFwdTrkMatchCands(TMUON const& muonTracks) - { - std::vector empty{}; - for (const auto& muonTrack : muonTracks) { - if (static_cast(muonTrack.trackType()) <= GlobalTrackTypeMax) { - fwdTrkMatchCands(empty); - continue; - } - - const int64_t mchTrackIndex = muonTrack.globalIndex(); - const auto matchIterator = mMchTrackToCandidateIndices.find(mchTrackIndex); - if (matchIterator == mMchTrackToCandidateIndices.end() || matchIterator->second.empty()) { - fwdTrkMatchCands(empty); - } else { - fwdTrkMatchCands(matchIterator->second); + track.matchScoreMCHMFT(), + isMchTrackTagged(track.matchMCHTrackId())); } } } - void processData(MyEvents const& collisions, - aod::BCsWithTimestamps const& bcs, - MyMuons const& muonTracks, - MyMFTs const& mftTracks, - MyMFTCovariances const& mftCovs, - aod::FwdTrkCls const& clusters, - aod::AmbiguousFwdTracks const& ambFwdTracks) + void runCandidateProcessing(MyEvents const& collisions, + aod::BCsWithTimestamps const& bcs, + MyMuons const& muonTracks, + MyMFTs const& mftTracks, + MyMFTCovariances const& mftCovs, + aod::FwdTrkCls const& clusters, + aod::AmbiguousFwdTracks const& ambFwdTracks, + bool useMixedMatchingCandidates) { auto bc = bcs.begin(); initCcdb(bc); @@ -1817,27 +1805,47 @@ struct GlobalMuonMatching { mftTrackCovs[mftTrackCov.matchMFTTrackId()] = mftTrackCov.globalIndex(); } - mMatchCandidateCounter = 0; - mMchTrackToCandidateIndices.clear(); - mMchTrackMatchingCandidates.clear(); + mStoredMatchingCandidates.clear(); mFwdTrackToGmmCandTrkIndex.clear(); mMchTrackInfos.clear(); LOGF(info, "Preparing candidates"); prepareMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); - prepareEventMixingMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); + if (useMixedMatchingCandidates) { + prepareEventMixingMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); + } LOGF(info, "Processing candidates"); - processMatchingCandidates(collisions, muonTracks, mftTracks, mftCovs, clusters); + processMatchingCandidates(collisions, muonTracks, mftTracks, mftCovs, clusters, useMixedMatchingCandidates); LOGF(info, "Filling tables"); - // fill table with track/candidates index mapping - fillFwdTrkMatchCands(muonTracks); - // fill track tables fillGmmCandidateFwdTracks(muonTracks, mftTracks, ambFwdTracks); } + void processData(MyEvents const& collisions, + aod::BCsWithTimestamps const& bcs, + MyMuons const& muonTracks, + MyMFTs const& mftTracks, + MyMFTCovariances const& mftCovs, + aod::FwdTrkCls const& clusters, + aod::AmbiguousFwdTracks const& ambFwdTracks) + { + runCandidateProcessing(collisions, bcs, muonTracks, mftTracks, mftCovs, clusters, ambFwdTracks, false); + } + + void processMixedData(MyEvents const& collisions, + aod::BCsWithTimestamps const& bcs, + MyMuons const& muonTracks, + MyMFTs const& mftTracks, + MyMFTCovariances const& mftCovs, + aod::FwdTrkCls const& clusters, + aod::AmbiguousFwdTracks const& ambFwdTracks) + { + runCandidateProcessing(collisions, bcs, muonTracks, mftTracks, mftCovs, clusters, ambFwdTracks, true); + } + PROCESS_SWITCH(GlobalMuonMatching, processData, "processData", true); + PROCESS_SWITCH(GlobalMuonMatching, processMixedData, "process event-mixed matching candidates", false); }; // Extends the fwdtracksrealign table with expression columns From 4b7eb1807c3bc4f313949d8cecbcbe68809bb856 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Tue, 30 Jun 2026 16:58:53 +0200 Subject: [PATCH 03/14] clang format --- PWGDQ/Tasks/global-muon-matcher.cxx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 7062d7c593d..99fae7f06d9 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -78,9 +78,9 @@ namespace o2::aod { namespace globalmuonmatching { -DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts -DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) -DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) +DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts +DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) +DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) DECLARE_SOA_INDEX_COLUMN_FULL(FwdTrackRealign, fwdTrackRealign, int, FwdTracksReAlign, ""); //! Index of ambiguous FwdTracksReAlign entry DECLARE_SOA_SLICE_INDEX_COLUMN_FULL(Bc, bc, int32_t, BCs, ""); //! BC index slice compatible with the track time window } // namespace globalmuonmatching @@ -1205,9 +1205,9 @@ struct GlobalMuonMatching { mMchTrackPars.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); mMchTrackInfos.try_emplace(mchTrackIndex, MchTrackInfo{ - .nMatchAttempts = 0, - .matchingCandidates = std::vector(), - .mixedMatchingCandidates = std::vector>()}); + .nMatchAttempts = 0, + .matchingCandidates = std::vector(), + .mixedMatchingCandidates = std::vector>()}); } for (const auto& mftTrack : mftTracks) { @@ -1758,7 +1758,6 @@ struct GlobalMuonMatching { fillBaseGmmCandFwdTrack(track, mchTrackParIt->second, gmmMchTrackId, -1.f, -1.f, isMchTrackTagged(mchTrackIndex)); - if (candidateIterator != mStoredMatchingCandidates.end()) { for (const auto& candidate : candidateIterator->second) { auto mftTrackParIt = mMftTrackPars.find(candidate.mftTrackId); From 9c0d1074459910b11f3df20070b3c0dc37da1729 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Tue, 30 Jun 2026 17:30:47 +0200 Subject: [PATCH 04/14] fixing typo and removing subscription to unused tables --- PWGDQ/Tasks/global-muon-matcher.cxx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 99fae7f06d9..4b293d527d7 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -1288,12 +1288,10 @@ struct GlobalMuonMatching { } } - template + template void prepareEventMixingMatchingCandidates(EVT const& collisions, BC const& bcs, - TMUON const& muonTracks, - TMFT const& mftTracks, - MyMFTCovariances const& mftCovs) + TMUON const& muonTracks) { LOGF(info, "Filling mixed matching candidate tables"); @@ -1301,7 +1299,7 @@ struct GlobalMuonMatching { const int64_t minDeltaBc = configEventMixing.cfgMinDeltaBc.value; const float maxDeltaPhi = configEventMixing.cfgMaxDeltaPhi.value; const float maxDeltaR = configEventMixing.cfgMaxDeltaR.value; - const float maxDeltaAttemptsRel = configEventMixing.cfgMaxDeltaAttemptsRel.value; + const float maxDeltaAttemptsRel = configEventMixing.cfgMaxDeltaAttempts.value; const float maxDeltaZ = configEventMixing.cfgMaxDeltaZ.value; for (auto& [mchIndex1, mchTrackInfo1] : mMchTrackInfos) { @@ -1811,7 +1809,7 @@ struct GlobalMuonMatching { LOGF(info, "Preparing candidates"); prepareMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); if (useMixedMatchingCandidates) { - prepareEventMixingMatchingCandidates(collisions, bcs, muonTracks, mftTracks, mftCovs); + prepareEventMixingMatchingCandidates(collisions, bcs, muonTracks); } LOGF(info, "Processing candidates"); From e90d37108b07969d03bc345c3d105e02cdbb2857 Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Fri, 3 Jul 2026 14:50:59 +0200 Subject: [PATCH 05/14] Fixed computation of phi angle difference --- PWGDQ/Tasks/global-muon-matcher.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 4b293d527d7..84ab766bfe1 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -111,11 +111,11 @@ static float getDeltaPhi(float phi1, float phi2) { float dphi = phi1 - phi2; static constexpr float pi = TMath::Pi(); - static constexpr float twopi = pi; + static constexpr float twopi = pi * 2.f; if (dphi > pi) { dphi -= twopi; } - if (dphi < pi) { + if (dphi < -pi) { dphi += twopi; } return dphi; From 2002ea75fdbbfe2dadde76c4f6c780f28ee7cb81 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 9 Jul 2026 12:17:38 +0000 Subject: [PATCH 06/14] Please consider the following formatting changes --- PWGDQ/Tasks/global-muon-matcher.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 84ab766bfe1..30184d3570a 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -121,7 +121,6 @@ static float getDeltaPhi(float phi1, float phi2) return dphi; }; - struct GlobalMuonMatching { static constexpr int GlobalTrackTypeMax = 2; @@ -1290,8 +1289,8 @@ struct GlobalMuonMatching { template void prepareEventMixingMatchingCandidates(EVT const& collisions, - BC const& bcs, - TMUON const& muonTracks) + BC const& bcs, + TMUON const& muonTracks) { LOGF(info, "Filling mixed matching candidate tables"); From ffece9c46ba6966507f51aa1a29f51e02bf0ec89 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Thu, 9 Jul 2026 15:06:01 +0200 Subject: [PATCH 07/14] fixing PI constants --- PWGDQ/Tasks/global-muon-matcher.cxx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 30184d3570a..e3b544fbd2f 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -17,6 +17,7 @@ #include "PWGDQ/Core/VarManager.h" #include "Common/Core/fwdtrackUtilities.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FwdTrackReAlignTables.h" #include "Tools/ML/MlResponse.h" @@ -109,17 +110,8 @@ constexpr std::array SNDetElemCh = {0, 4, 8, 12, 16, 34, 52, 78, 104, 1 // compute minimum difference between azimuthal angles static float getDeltaPhi(float phi1, float phi2) { - float dphi = phi1 - phi2; - static constexpr float pi = TMath::Pi(); - static constexpr float twopi = pi * 2.f; - if (dphi > pi) { - dphi -= twopi; - } - if (dphi < -pi) { - dphi += twopi; - } - return dphi; -}; + return RecoDecay::constrainAngle(phi1 - phi2, -o2::constants::math::PI); +} struct GlobalMuonMatching { @@ -220,7 +212,7 @@ struct GlobalMuonMatching { struct : ConfigurableGroup { Configurable cfgMixingDepth{"cfgMixingDepth", -1, "Maximum number of mixed candidate groups per MCH track (-1: no limit)"}; Configurable cfgMinDeltaBc{"cfgMinDeltaBc", 3564, "Minimum DeltaBc between mixed collisions"}; - Configurable cfgMaxDeltaPhi{"cfgMaxDeltaPhi", static_cast(TMath::Pi() / 10), "Maximum DelptaPhi between mixed MCH tracks (rad)"}; + Configurable cfgMaxDeltaPhi{"cfgMaxDeltaPhi", static_cast(o2::constants::math::PI / 10), "Maximum DelptaPhi between mixed MCH tracks (rad)"}; Configurable cfgMaxDeltaR{"cfgMaxDeltaR", 10.f, "Maximum DeltaR between mixed MCH tracks"}; Configurable cfgMaxDeltaAttempts{"cfgMaxDeltaAttempts", 0.1f, "Maximum relative difference in match attempts"}; Configurable cfgMaxDeltaZ{"cfgMaxDeltaZ", 1.f, "Maximum deltaZ between mixed collisions"}; From 9c1854f9106e69ba70c9a7d549cfb88e716042a0 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Thu, 9 Jul 2026 15:16:54 +0200 Subject: [PATCH 08/14] disabling some o2 linter --- PWGDQ/Tasks/global-muon-matcher.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index e3b544fbd2f..5a24a4b0337 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -/// \file global-muon-matcher.cxx +/// \file global-muon-matcher.cxx // o2-linter: disable=name/file-cpp,name/workflow-file /// \brief Task for analysis MFT-MCH muon matching /// \author Andrea Ferrero /// @@ -1238,7 +1238,7 @@ struct GlobalMuonMatching { } // set the number of match attempts for this track - for (auto& mchTrackInfo : mMchTrackInfos) { + for (auto& mchTrackInfo : mMchTrackInfos) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) const auto& mchTrack = muonTracks.rawIteratorAt(mchTrackInfo.first); mchTrackInfo.second.nMatchAttempts = getMftMchMatchAttempts(collisions, bcs, mchTrack, mftTracks); } @@ -1264,7 +1264,7 @@ struct GlobalMuonMatching { } // set the number of match attempts for this track - for (auto& mchTrackInfo : mMchTrackInfos) { + for (auto& mchTrackInfo : mMchTrackInfos) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) mchTrackInfo.second.nMatchAttempts = mchTrackInfo.second.matchingCandidates.size(); } } @@ -1293,7 +1293,7 @@ struct GlobalMuonMatching { const float maxDeltaAttemptsRel = configEventMixing.cfgMaxDeltaAttempts.value; const float maxDeltaZ = configEventMixing.cfgMaxDeltaZ.value; - for (auto& [mchIndex1, mchTrackInfo1] : mMchTrackInfos) { + for (auto& [mchIndex1, mchTrackInfo1] : mMchTrackInfos) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) const auto& mchTrack1 = muonTracks.rawIteratorAt(mchIndex1); if (!mchTrack1.has_collision()) { @@ -1358,7 +1358,7 @@ struct GlobalMuonMatching { // add the candidates of MCH track #2 to the list of mixed candidates of track #1 mchTrackInfo1.mixedMatchingCandidates.push_back(mchTrackInfo2.matchingCandidates); // update the muon track index of the mixed candidates to the index of track #1 - for (auto& candidate : mchTrackInfo1.mixedMatchingCandidates.back()) { + for (auto& candidate : mchTrackInfo1.mixedMatchingCandidates.back()) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) candidate.muonTrackId = mchIndex1; } } From 717fa9c1246aa4c7379e08a177729eedf8075f80 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 9 Jul 2026 13:18:57 +0000 Subject: [PATCH 09/14] Please consider the following formatting changes --- PWGDQ/Tasks/global-muon-matcher.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 5a24a4b0337..83d74cab211 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -16,8 +16,8 @@ #include "PWGDQ/Core/MuonMatchingMlResponse.h" #include "PWGDQ/Core/VarManager.h" -#include "Common/Core/fwdtrackUtilities.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/fwdtrackUtilities.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FwdTrackReAlignTables.h" #include "Tools/ML/MlResponse.h" From 6344432ee6d12f2751f3b0b4f1957c5d31e560a1 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Thu, 9 Jul 2026 15:20:36 +0200 Subject: [PATCH 10/14] further fixes --- PWGDQ/Tasks/global-muon-matcher.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 83d74cab211..82164de33fe 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -/// \file global-muon-matcher.cxx // o2-linter: disable=name/file-cpp,name/workflow-file +/// \file global-muon-matcher.cxx // o2-linter: disable=name/file-cpp,name/workflow-file (legacy workflow executable name) /// \brief Task for analysis MFT-MCH muon matching /// \author Andrea Ferrero /// @@ -1271,7 +1271,7 @@ struct GlobalMuonMatching { std::vector taggedMuons; getTaggedMuons(collisions, muonTracks, taggedMuons); - for (int64_t mchTrackIndex : taggedMuons) { + for (const auto& mchTrackIndex : taggedMuons) { auto it = mMchTrackInfos.find(mchTrackIndex); if (it != mMchTrackInfos.end()) { it->second.isTagged = true; From 7b75bac177de503095f3dc689991dc2e302b6f25 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Thu, 9 Jul 2026 15:58:41 +0200 Subject: [PATCH 11/14] code-checker fixes --- PWGDQ/Tasks/global-muon-matcher.cxx | 38 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 82164de33fe..da6eb3298a8 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -288,7 +289,10 @@ struct GlobalMuonMatching { void setRemovable() { removable = true; } [[nodiscard]] bool isRemovable() const { return removable; } - [[nodiscard]] o2::track::TrackParCovFwd asTrackParCovFwd() const { return *this; } + [[nodiscard]] o2::track::TrackParCovFwd asTrackParCovFwd() const + { + return o2::track::TrackParCovFwd(static_cast(*this)); + } private: int nClusters{-1}; @@ -957,7 +961,7 @@ struct GlobalMuonMatching { using o2::aod::fwdtrack::ForwardTrackTypeEnum; using o2::aod::fwdtrackutils::propagationPoint; - constexpr uint8_t CandidateTrackType = static_cast(ForwardTrackTypeEnum::GlobalForwardTrack); + constexpr auto CandidateTrackType = static_cast(ForwardTrackTypeEnum::GlobalForwardTrack); auto propmuonAtMft = fwdToMch(mchPar); o2::mch::TrackExtrap::extrapToVertex(propmuonAtMft, @@ -971,7 +975,7 @@ struct GlobalMuonMatching { const auto nClusters = static_cast(std::min(127, mchPar.getNClusters() + mftPar.getNClusters())); - const float chi2 = static_cast(mchTrack.chi2()); + const auto chi2 = static_cast(mchTrack.chi2()); const int32_t collisionId = mchTrack.collisionId(); bool hasBcSlice = false; std::array bcSlice{}; @@ -1547,14 +1551,16 @@ struct GlobalMuonMatching { } const int maxCandidates = configMatching.cfgMaxCandidatesPerMchTrack.value; - const size_t nToStore = (maxCandidates >= 0) - ? std::min(groupResults.size(), static_cast(maxCandidates)) - : groupResults.size(); auto& storedCandidates = newMatchingCandidates[mchIndex]; - for (size_t i = 0; i < nToStore; ++i) { - groupResults[i].mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; - storedCandidates.push_back(std::move(groupResults[i])); + size_t nStoredThisGroup = 0; + for (auto& result : groupResults) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + if (maxCandidates >= 0 && nStoredThisGroup >= static_cast(maxCandidates)) { + break; + } + result.mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; + storedCandidates.push_back(result); + ++nStoredThisGroup; } }; @@ -1638,14 +1644,16 @@ struct GlobalMuonMatching { } const int maxCandidates = configMatching.cfgMaxCandidatesPerMchTrack.value; - const size_t nToStore = (maxCandidates >= 0) - ? std::min(groupResults.size(), static_cast(maxCandidates)) - : groupResults.size(); auto& storedCandidates = newMatchingCandidates[mchIndex]; - for (size_t i = 0; i < nToStore; ++i) { - groupResults[i].mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; - storedCandidates.push_back(std::move(groupResults[i])); + size_t nStoredThisGroup = 0; + for (auto& result : groupResults) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + if (maxCandidates >= 0 && nStoredThisGroup >= static_cast(maxCandidates)) { + break; + } + result.mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; + storedCandidates.push_back(result); + ++nStoredThisGroup; } }; From 99501283f1635827a142a5d6b18c26321407bdf3 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Thu, 9 Jul 2026 16:01:05 +0200 Subject: [PATCH 12/14] fill common ambiguity table --- PWGDQ/Tasks/global-muon-matcher.cxx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index da6eb3298a8..e7e830d6861 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -83,17 +83,12 @@ namespace globalmuonmatching DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) -DECLARE_SOA_INDEX_COLUMN_FULL(FwdTrackRealign, fwdTrackRealign, int, FwdTracksReAlign, ""); //! Index of ambiguous FwdTracksReAlign entry -DECLARE_SOA_SLICE_INDEX_COLUMN_FULL(Bc, bc, int32_t, BCs, ""); //! BC index slice compatible with the track time window } // namespace globalmuonmatching DECLARE_SOA_TABLE(GmmCandFwdTrkExtras, "AOD", "GMMCANDEXTRA", //! Extra info joinable to FwdTracksReAlign globalmuonmatching::IsTagged, globalmuonmatching::MatchRanking, globalmuonmatching::MixedGroupIndex); - -DECLARE_SOA_TABLE(AmbiguousFwdTracksReAlign, "AOD", "AMBIGFWDREALIGN", //! FwdTracksReAlign entries without a unique collision association - o2::soa::Index<>, globalmuonmatching::FwdTrackRealignId, globalmuonmatching::BcIdSlice); } // namespace o2::aod using MyEvents = soa::Join; @@ -307,7 +302,7 @@ struct GlobalMuonMatching { Produces gmCandidateFwdTracks; Produces gmCandidateFwdTracksCov; Produces gmCandidateFwdTrackExtras; - Produces gmAmbiguousFwdTracksReAlign; + Produces gmAmbiguousFwdTracksReAlign; int32_t mGmmCandFwdTrackRowIndex{0}; std::unordered_map> mAmbBcSliceByFwdTrackId; From 53c8ad9beb83d45a52bbf2581334fdb8d48cccab Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 9 Jul 2026 14:02:06 +0000 Subject: [PATCH 13/14] Please consider the following formatting changes --- PWGDQ/Tasks/global-muon-matcher.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index e7e830d6861..ace8703f5c0 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -80,9 +80,9 @@ namespace o2::aod { namespace globalmuonmatching { -DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts -DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) -DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) +DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts +DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) +DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) } // namespace globalmuonmatching DECLARE_SOA_TABLE(GmmCandFwdTrkExtras, "AOD", "GMMCANDEXTRA", //! Extra info joinable to FwdTracksReAlign From 72f836bf4bdd58e608e37a8ba88a8dd139a363e3 Mon Sep 17 00:00:00 2001 From: Maurice Coquet Date: Thu, 9 Jul 2026 17:56:22 +0200 Subject: [PATCH 14/14] further code-check fixes --- PWGDQ/Tasks/global-muon-matcher.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index ace8703f5c0..390466dddc3 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -286,7 +286,7 @@ struct GlobalMuonMatching { [[nodiscard]] o2::track::TrackParCovFwd asTrackParCovFwd() const { - return o2::track::TrackParCovFwd(static_cast(*this)); + return {static_cast(*this)}; } private: @@ -1506,7 +1506,7 @@ struct GlobalMuonMatching { continue; } - auto processGroup = [&](const std::vector& candidatesGroup, int32_t mixedGroupIndex) { + auto processGroup = [&, mchIndex](const std::vector& candidatesGroup, int32_t mixedGroupIndex) { std::vector groupResults; groupResults.reserve(candidatesGroup.size()); @@ -1595,7 +1595,7 @@ struct GlobalMuonMatching { continue; } - auto processGroup = [&](const std::vector& candidatesGroup, int32_t mixedGroupIndex) { + auto processGroup = [&, mchIndex](const std::vector& candidatesGroup, int32_t mixedGroupIndex) { std::vector groupResults; groupResults.reserve(candidatesGroup.size());