From ef97f864cc31a6df73b0de76174165c3ac17aded Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Wed, 13 May 2026 12:42:42 +0200 Subject: [PATCH 1/3] [PWGDQ] disabled ML matching in tableMaker The interface for the ML-based matching has changed and requires additional tables for the tracks and collision, which are not yet included in the tableMaker code. Since the ML-based matching is still experimental and not intended for physics analysis, the skimming code based on the ML output is disabled for the moment, waiting for a proper fix for the missing tables. --- PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx | 14 ++++++++++---- PWGDQ/TableProducer/tableMaker_withAssoc.cxx | 8 +++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx index 39cee24788c..add0162e4f9 100644 --- a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx @@ -1041,12 +1041,16 @@ struct TableMakerMC { if (static_cast(muon.trackType()) < 2) { auto muonID = muon.matchMCHTrackId(); auto chi2 = muon.chi2MatchMCHMFT(); + /* TODO: the getInputFeaturesTest() fuction has been removed + * Moreover, it is not foreseen to run ML models using only the information + * from the global muon track. + * Can this part be safely removed? if (fConfigVariousOptions.fUseML.value) { std::vector output; std::vector inputML = matchingMlResponse.getInputFeaturesTest(muon); matchingMlResponse.isSelectedMl(inputML, 0, output); chi2 = output[0]; - } + }*/ if (mCandidates.find(muonID) == mCandidates.end()) { mCandidates[muonID] = {chi2, muon.globalIndex()}; } else { @@ -1062,8 +1066,10 @@ struct TableMakerMC { } template - void skimBestMuonMatchesML(TMuons const& muons, TMFTTracks const& /*mfttracks*/, TMFTCovs const& mfCovs, TEvent const& collision) + void skimBestMuonMatchesML(TMuons const& /*muons*/, TMFTTracks const& /*mfttracks*/, TMFTCovs const& /*mfCovs*/, TEvent const& /*collision*/) { + return; + /* TODO: add missing tables in the tracks and events definitions std::unordered_map> mCandidates; for (const auto& muon : muons) { if (static_cast(muon.trackType()) < 2) { @@ -1078,7 +1084,7 @@ struct TableMakerMC { muonprop = VarManager::PropagateMuon(muontrack, collision, VarManager::kToMatching); } std::vector output; - std::vector inputML = matchingMlResponse.getInputFeaturesGlob(muon, muonprop, mftprop, collision); + std::vector inputML = matchingMlResponse.getInputFeatures(muon, mfttrack, muontrack, mftprop, muonprop, collision); matchingMlResponse.isSelectedMl(inputML, 0, output); float score = output[0]; if (mCandidates.find(muonID) == mCandidates.end()) { @@ -1092,7 +1098,7 @@ struct TableMakerMC { } for (auto& pairCand : mCandidates) { fBestMatch[pairCand.second.second] = true; - } + }*/ } template diff --git a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx index 1ae278c9301..4ee073547ec 100644 --- a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx @@ -1478,8 +1478,10 @@ struct TableMaker { } template - void skimBestMuonMatchesML(TMuons const& muons, TMFTTracks const& /*mfttracks*/, TMFTCovs const& mfCovs, TEvent const& collision) + void skimBestMuonMatchesML(TMuons const& /*muons*/, TMFTTracks const& /*mfttracks*/, TMFTCovs const& /*mfCovs*/, TEvent const& /*collision*/) { + return; + /* TODO: add missing tables in the tracks and events definitions std::unordered_map> mCandidates; for (const auto& muon : muons) { if (static_cast(muon.trackType()) < 2) { @@ -1494,7 +1496,7 @@ struct TableMaker { muonprop = VarManager::PropagateMuon(muontrack, collision, VarManager::kToMatching); } std::vector output; - std::vector inputML = matchingMlResponse.getInputFeaturesGlob(muon, muonprop, mftprop, collision); + std::vector inputML = matchingMlResponse.getInputFeatures(muon, mfttrack, muontrack, mftprop, muonprop, collision); matchingMlResponse.isSelectedMl(inputML, 0, output); float score = output[0]; if (mCandidates.find(muonID) == mCandidates.end()) { @@ -1508,7 +1510,7 @@ struct TableMaker { } for (auto& pairCand : mCandidates) { fBestMatch[pairCand.second.second] = true; - } + }*/ } template From 055f746c365d42805f538e2bc5d11179d448186a Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Thu, 14 May 2026 18:57:45 +0200 Subject: [PATCH 2/3] [PWGDQ] make some ML input features optional Some of the input features supported by the DQ MLResponse class are optional by checking the availability of the corresponding getter function at compile time. If the getter is unavailable because the corresponding dynamic table is not joined, the feature is set to zero. --- PWGDQ/Core/MuonMatchingMlResponse.h | 73 +++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/PWGDQ/Core/MuonMatchingMlResponse.h b/PWGDQ/Core/MuonMatchingMlResponse.h index dc029cc796a..6fd756f5819 100644 --- a/PWGDQ/Core/MuonMatchingMlResponse.h +++ b/PWGDQ/Core/MuonMatchingMlResponse.h @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -35,13 +36,47 @@ // Check if the index of mCachedIndices (index associated to a FEATURE) // matches the entry in EnumInputFeatures associated to this FEATURE // if so, the inputFeatures vector is filled with the FEATURE's value -// by calling the corresponding GETTER=FEATURE from track +// by calling the corresponding GETTER expression #define CHECK_AND_FILL_FEATURE(FEATURE, GETTER) \ case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ inputFeature = (GETTER); \ break; \ } +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, and if OBJECT.GETTER() is a valid function invocation, +// the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER function +#define CHECK_AND_FILL_FEATURE_OPTIONAL_NO_EXPR(FEATURE, OBJECT, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + if constexpr (requires(decltype(OBJECT) t) { { t.GETTER() } -> std::convertible_to; }) { \ + inputFeature = (OBJECT.GETTER()); \ + } else { \ + inputFeature = 0; \ + } \ + break; \ + } + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, and if OBJECT.FUNC() is a valid function invocation, +// the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER expression +#define CHECK_AND_FILL_FEATURE_OPTIONAL_WITH_EXPR(FEATURE, OBJECT, FUNC, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + if constexpr (requires(decltype(OBJECT) t) { { t.FUNC() } -> std::convertible_to; }) { \ + inputFeature = (GETTER); \ + } else { \ + inputFeature = 0; \ + } \ + break; \ + } + +#define __EXPAND(x) x +#define __GET_MACRO(_1, _2, _3, _4, name, ...) name +#define CHECK_AND_FILL_FEATURE_OPTIONAL(...) __EXPAND(__GET_MACRO(__VA_ARGS__, CHECK_AND_FILL_FEATURE_OPTIONAL_WITH_EXPR, CHECK_AND_FILL_FEATURE_OPTIONAL_NO_EXPR)(__VA_ARGS__)) + namespace o2::analysis { // possible input features for ML @@ -287,27 +322,27 @@ class MlResponseMFTMuonMatch : public MlResponse CHECK_AND_FILL_FEATURE(posX, collision.posX()); CHECK_AND_FILL_FEATURE(posY, collision.posY()); CHECK_AND_FILL_FEATURE(posZ, collision.posZ()); - CHECK_AND_FILL_FEATURE(numContrib, collision.numContrib()); - CHECK_AND_FILL_FEATURE(trackOccupancyInTimeRange, collision.trackOccupancyInTimeRange()); - CHECK_AND_FILL_FEATURE(ft0cOccupancyInTimeRange, collision.ft0cOccupancyInTimeRange()); - CHECK_AND_FILL_FEATURE(multMFT, collision.mftNtracks()); - CHECK_AND_FILL_FEATURE(multFT0A, collision.multFT0A()); - CHECK_AND_FILL_FEATURE(multFT0C, collision.multFT0C()); - CHECK_AND_FILL_FEATURE(multNTracksPV, collision.multNTracksPV()); - CHECK_AND_FILL_FEATURE(multNTracksPVeta1, collision.multNTracksPVeta1()); - CHECK_AND_FILL_FEATURE(multNTracksPVetaHalf, collision.multNTracksPVetaHalf()); - CHECK_AND_FILL_FEATURE(isInelGt0, collision.isInelGt0()); - CHECK_AND_FILL_FEATURE(isInelGt1, collision.isInelGt1()); - CHECK_AND_FILL_FEATURE(multFT0M, collision.multFT0M()); - CHECK_AND_FILL_FEATURE(centFT0M, collision.centFT0M()); - CHECK_AND_FILL_FEATURE(centFT0A, collision.centFT0A()); - CHECK_AND_FILL_FEATURE(centFT0C, collision.centFT0C()); + CHECK_AND_FILL_FEATURE_OPTIONAL(numContrib, collision, numContrib); + CHECK_AND_FILL_FEATURE_OPTIONAL(trackOccupancyInTimeRange, collision, trackOccupancyInTimeRange); + CHECK_AND_FILL_FEATURE_OPTIONAL(ft0cOccupancyInTimeRange, collision, ft0cOccupancyInTimeRange); + CHECK_AND_FILL_FEATURE_OPTIONAL(multMFT, collision, mftNtracks); + CHECK_AND_FILL_FEATURE_OPTIONAL(multFT0A, collision, multFT0A); + CHECK_AND_FILL_FEATURE_OPTIONAL(multFT0C, collision, multFT0C); + CHECK_AND_FILL_FEATURE_OPTIONAL(multNTracksPV, collision, multNTracksPV); + CHECK_AND_FILL_FEATURE_OPTIONAL(multNTracksPVeta1, collision, multNTracksPVeta1); + CHECK_AND_FILL_FEATURE_OPTIONAL(multNTracksPVetaHalf, collision, multNTracksPVetaHalf); + CHECK_AND_FILL_FEATURE_OPTIONAL(isInelGt0, collision, isInelGt0); + CHECK_AND_FILL_FEATURE_OPTIONAL(isInelGt1, collision, isInelGt1); + CHECK_AND_FILL_FEATURE_OPTIONAL(multFT0M, collision, multFT0M); + CHECK_AND_FILL_FEATURE_OPTIONAL(centFT0M, collision, centFT0M); + CHECK_AND_FILL_FEATURE_OPTIONAL(centFT0A, collision, centFT0A); + CHECK_AND_FILL_FEATURE_OPTIONAL(centFT0C, collision, centFT0C); // global forward track parameters CHECK_AND_FILL_FEATURE(chi2MCHMFT, muon.chi2MatchMCHMFT()); CHECK_AND_FILL_FEATURE(chi2GlobMUON, muon.chi2()); - CHECK_AND_FILL_FEATURE(dcaX, muon.fwdDcaX()); - CHECK_AND_FILL_FEATURE(dcaY, muon.fwdDcaX()); - CHECK_AND_FILL_FEATURE(isAmbig, (muon.compatibleCollIds().size() == 1) ? 0 : 1); + CHECK_AND_FILL_FEATURE_OPTIONAL(dcaX, muon, fwdDcaX); + CHECK_AND_FILL_FEATURE_OPTIONAL(dcaY, muon, fwdDcaX); + CHECK_AND_FILL_FEATURE_OPTIONAL(isAmbig, muon, compatibleCollIds, (muon.compatibleCollIds().size() == 1) ? 0 : 1); } return inputFeature; } From 84d64864db215fadc3ccb5487e0b842a7efdf7e3 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 14 May 2026 16:59:02 +0000 Subject: [PATCH 3/3] Please consider the following formatting changes --- PWGDQ/Core/MuonMatchingMlResponse.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGDQ/Core/MuonMatchingMlResponse.h b/PWGDQ/Core/MuonMatchingMlResponse.h index 6fd756f5819..90e0da301e4 100644 --- a/PWGDQ/Core/MuonMatchingMlResponse.h +++ b/PWGDQ/Core/MuonMatchingMlResponse.h @@ -50,7 +50,7 @@ // by calling the corresponding GETTER function #define CHECK_AND_FILL_FEATURE_OPTIONAL_NO_EXPR(FEATURE, OBJECT, GETTER) \ case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ - if constexpr (requires(decltype(OBJECT) t) { { t.GETTER() } -> std::convertible_to; }) { \ + if constexpr (requires(decltype(OBJECT) t) { { t.GETTER() } -> std::convertible_to; }) { \ inputFeature = (OBJECT.GETTER()); \ } else { \ inputFeature = 0; \ @@ -65,7 +65,7 @@ // by calling the corresponding GETTER expression #define CHECK_AND_FILL_FEATURE_OPTIONAL_WITH_EXPR(FEATURE, OBJECT, FUNC, GETTER) \ case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ - if constexpr (requires(decltype(OBJECT) t) { { t.FUNC() } -> std::convertible_to; }) { \ + if constexpr (requires(decltype(OBJECT) t) { { t.FUNC() } -> std::convertible_to; }) { \ inputFeature = (GETTER); \ } else { \ inputFeature = 0; \