Skip to content

Commit f3a321d

Browse files
committed
[PWGLF] Fix collision grouping in resonance module initializer
Preserve the existing reduced-collision link schema while adding a canonical original-collision association for GroupSlicer. Add hybrid Track, V0, and cascade daughter paths that use automatic original-collision grouping and retain the current paths for comparison.
1 parent 80ea9c0 commit f3a321d

2 files changed

Lines changed: 147 additions & 23 deletions

File tree

PWGLF/DataModel/LFResonanceTables.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ DECLARE_SOA_COLUMN(ImpactParameter, impactParameter, float); //! ImpactParamete
8383
DECLARE_SOA_COLUMN(MCMultiplicity, mcMultiplicity, float); //! MC Multiplicity, o2-linter: disable=name/o2-column (pre-existing public column name kept for schema and API compatibility)
8484

8585
} // namespace resocollision
86+
87+
// Keep the established ResoCollisionColls schema above unchanged. Automatic
88+
// GroupSlicer association to aod::Collisions requires the canonical physical
89+
// column name fIndexCollisions, so the modular initializer writes this small
90+
// companion table for the optimized daughter process.
91+
namespace resocollisiongroup
92+
{
93+
DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(OriginalCollision, originalCollision, int, Collisions, "Collisions", ""); //!
94+
} // namespace resocollisiongroup
95+
8696
DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION",
8797
o2::soa::Index<>,
8898
o2::aod::mult::MultNTracksPV,
@@ -100,6 +110,10 @@ DECLARE_SOA_TABLE(ResoCollisionColls, "AOD", "RESOCOLLISIONCOL",
100110
resocollision::CollisionId);
101111
using ResoCollisionColl = ResoCollisionColls::iterator;
102112

113+
DECLARE_SOA_TABLE(ResoCollisionGroups, "AOD", "RESOCOLLGROUP",
114+
resocollisiongroup::OriginalCollisionId);
115+
using ResoCollisionGroup = ResoCollisionGroups::iterator;
116+
103117
DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOLLISION",
104118
o2::soa::Index<>,
105119
resocollision::IsVtxIn10,

PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx

Lines changed: 133 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,10 @@ struct ResonanceModuleInitializer {
8686
Service<o2::ccdb::BasicCCDBManager> ccdb; ///< CCDB manager service
8787
Service<o2::framework::O2DatabasePDG> pdg; ///< PDG database service
8888

89-
Produces<aod::ResoCollisions> resoCollisions; ///< Output table for resonance collisions
90-
Produces<aod::ResoCollisionColls> resoCollisionColls; ///< Output table for collision references
91-
Produces<aod::ResoMCCollisions> resoMCCollisions; ///< Output table for MC resonance collisions
89+
Produces<aod::ResoCollisions> resoCollisions; ///< Output table for resonance collisions
90+
Produces<aod::ResoCollisionColls> resoCollisionColls; ///< Output table for collision references
91+
Produces<aod::ResoCollisionGroups> resoCollisionGroups; ///< Canonical original-collision grouping references
92+
Produces<aod::ResoMCCollisions> resoMCCollisions; ///< Output table for MC resonance collisions
9293

9394
// CCDB options
9495
struct : ConfigurableGroup {
@@ -492,6 +493,7 @@ struct ResonanceModuleInitializer {
492493

493494
resoCollisions(collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz, isRecINELgt0);
494495
resoCollisionColls(collision.globalIndex());
496+
resoCollisionGroups(collision.globalIndex());
495497
}
496498
PROCESS_SWITCH(ResonanceModuleInitializer, processRun3, "Default process for RUN3", false);
497499

@@ -516,6 +518,7 @@ struct ResonanceModuleInitializer {
516518

517519
resoCollisions(0, 0, 0, collision.posX(), collision.posY(), collision.posZ(), centrality, dBz, 0);
518520
resoCollisionColls(collision.globalIndex());
521+
resoCollisionGroups(collision.globalIndex());
519522
}
520523
PROCESS_SWITCH(ResonanceModuleInitializer, processRun2, "process for RUN2", false);
521524

@@ -699,6 +702,7 @@ struct ResonanceDaughterInitializer {
699702
// Keep ResonanceModuleInitializer::cfgBypassCollIndexFill disabled and enable
700703
// the matching Run 2/Run 3 base event process for MC workflows.
701704
using ResoCollisionWithIndex = soa::Join<aod::ResoCollisions, aod::ResoCollisionColls>;
705+
using SelectedResoCollisions = soa::Join<aod::ResoCollisions, aod::ResoCollisionGroups>;
702706

703707
/**
704708
* @brief Initializes the task
@@ -707,25 +711,35 @@ struct ResonanceDaughterInitializer {
707711
*/
708712
void init(InitContext&)
709713
{
710-
const bool processTrackDataEnabled = doprocessData || doprocessDataWithPairGate;
714+
const bool processTrackDataEnabled = doprocessData || doprocessDataOptimized || doprocessDataHybrid || doprocessDataWithPairGate;
711715
const bool processTrackMCEnabled = doprocessMC || doprocessMCWithPairGate;
716+
const bool processV0DataEnabled = doprocessV0Data || doprocessV0DataHybrid;
717+
const bool processCascDataEnabled = doprocessCascData || doprocessCascDataHybrid;
712718
const int enabledTrackProcesses = static_cast<int>(doprocessData) +
719+
static_cast<int>(doprocessDataOptimized) +
720+
static_cast<int>(doprocessDataHybrid) +
713721
static_cast<int>(doprocessDataWithPairGate) +
714722
static_cast<int>(doprocessMC) +
715723
static_cast<int>(doprocessMCWithPairGate);
716724

717725
if (enabledTrackProcesses > 1) {
718726
LOGF(fatal, "Only one track process can be enabled in ResonanceDaughterInitializer");
719727
}
720-
if ((doprocessData || doprocessMC) &&
728+
if (static_cast<int>(doprocessV0Data) + static_cast<int>(doprocessV0DataHybrid) + static_cast<int>(doprocessV0MC) > 1) {
729+
LOGF(fatal, "Only one V0 process can be enabled in ResonanceDaughterInitializer");
730+
}
731+
if (static_cast<int>(doprocessCascData) + static_cast<int>(doprocessCascDataHybrid) + static_cast<int>(doprocessCascMC) > 1) {
732+
LOGF(fatal, "Only one cascade process can be enabled in ResonanceDaughterInitializer");
733+
}
734+
if ((doprocessData || doprocessDataOptimized || doprocessDataHybrid || doprocessMC) &&
721735
(FilterForDerivedTables.cfgBypassNoPairV0s || FilterForDerivedTables.cfgBypassNoPairCascades)) {
722-
LOGF(warn, "Pair-gate options are ignored by processData/processMC; enable the matching *WithPairGate process to apply them");
736+
LOGF(warn, "Pair-gate options are ignored by processData/processDataOptimized/processDataHybrid/processMC; enable the matching *WithPairGate process to apply them");
723737
}
724-
if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairV0s && !doprocessV0Data) {
725-
LOGF(fatal, "cfgBypassNoPairV0s requires processV0Data so an accepted V0 is written for every retained collision");
738+
if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairV0s && !processV0DataEnabled) {
739+
LOGF(fatal, "cfgBypassNoPairV0s requires processV0Data or processV0DataHybrid so an accepted V0 is written for every retained collision");
726740
}
727-
if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairCascades && !doprocessCascData) {
728-
LOGF(fatal, "cfgBypassNoPairCascades requires processCascData so an accepted cascade is written for every retained collision");
741+
if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairCascades && !processCascDataEnabled) {
742+
LOGF(fatal, "cfgBypassNoPairCascades requires processCascData or processCascDataHybrid so an accepted cascade is written for every retained collision");
729743
}
730744

731745
if (!std::isfinite(TrackCuts.cfgCutMinPt.value) ||
@@ -860,7 +874,7 @@ struct ResonanceDaughterInitializer {
860874
}
861875
}
862876

863-
if (doprocessV0Data || doprocessV0MC) {
877+
if (processV0DataEnabled || doprocessV0MC) {
864878
qaRegistry.add("QA/hGoodV0Indices", "hGoodV0Indices", kTH1D, {idxAxis});
865879
if (doprocessV0MC) {
866880
qaRegistry.add("QA/hGoodMCV0Indices", "hGoodMCV0Indices", kTH1D, {idxAxis});
@@ -871,7 +885,7 @@ struct ResonanceDaughterInitializer {
871885
qaRegistry.add("QA/hV0CosPA", "V0 CosPA", kTH1F, {cosPAAxis});
872886
}
873887

874-
if (doprocessCascData || doprocessCascMC) {
888+
if (processCascDataEnabled || doprocessCascMC) {
875889
AxisSpec radiusAxis = {100, 0.0, 200.0, "Cascade Radius"};
876890
AxisSpec cosPAAxis = {100, 0.97, 1.0, "Cascade CosPA"};
877891
qaRegistry.add("QA/hGoodCascIndices", "hGoodCascIndices", kTH1D, {idxAxis});
@@ -885,19 +899,19 @@ struct ResonanceDaughterInitializer {
885899
if (processTrackDataEnabled || processTrackMCEnabled) {
886900
LOGF(info, "ResonanceDaughterInitializer initialized with tracks");
887901
}
888-
if (doprocessV0Data || doprocessV0MC) {
902+
if (processV0DataEnabled || doprocessV0MC) {
889903
LOGF(info, "ResonanceDaughterInitializer initialized with V0s");
890904
}
891-
if (doprocessCascData || doprocessCascMC) {
905+
if (processCascDataEnabled || doprocessCascMC) {
892906
LOGF(info, "ResonanceDaughterInitializer initialized with cascades");
893907
}
894908

895909
// Check if the module is initialized with both data and MC
896-
if ((processTrackDataEnabled && processTrackMCEnabled) || (doprocessV0Data && doprocessV0MC) || (doprocessCascData && doprocessCascMC)) {
910+
if ((processTrackDataEnabled && processTrackMCEnabled) || (processV0DataEnabled && doprocessV0MC) || (processCascDataEnabled && doprocessCascMC)) {
897911
LOGF(fatal, "ResonanceDaughterInitializer initialized with both data and MC");
898912
}
899913
// Check if none of the processes are enabled
900-
if (!doprocessDummy && !processTrackDataEnabled && !processTrackMCEnabled && !doprocessV0Data && !doprocessV0MC && !doprocessCascData && !doprocessCascMC) {
914+
if (!doprocessDummy && !processTrackDataEnabled && !processTrackMCEnabled && !processV0DataEnabled && !doprocessV0MC && !processCascDataEnabled && !doprocessCascMC) {
901915
LOGF(fatal, "ResonanceDaughterInitializer not initialized, enable at least one process");
902916
}
903917
}
@@ -1874,6 +1888,25 @@ struct ResonanceDaughterInitializer {
18741888
}
18751889
PROCESS_SWITCH(ResonanceDaughterInitializer, processDummy, "Process dummy", true);
18761890

1891+
/**
1892+
* @brief Fills all enabled track tables from an already grouped track slice
1893+
*
1894+
* @tparam isMC Boolean indicating if it's MC
1895+
* @param collision Reduced collision used as the output foreign key
1896+
* @param tracks Tracks belonging to the corresponding original collision
1897+
*/
1898+
template <bool isMC, typename CollisionType, typename TrackTableType>
1899+
void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks)
1900+
{
1901+
fillTracks<isMC>(collision, tracks);
1902+
if (FilterForDerivedTables.cfgFillMicroTracks) {
1903+
fillMicroTracks<isMC>(collision, tracks);
1904+
}
1905+
if (FilterForDerivedTables.cfgFillUltraMicroTracks) {
1906+
fillUltraMicroTracks<isMC>(collision, tracks);
1907+
}
1908+
}
1909+
18771910
/**
18781911
* @brief Fills track tables for one original collision
18791912
*
@@ -1888,13 +1921,7 @@ struct ResonanceDaughterInitializer {
18881921
void fillTrackTablesForCollision(CollisionType const& collision, TrackTableType const& tracks, PresliceType const& perCollision)
18891922
{
18901923
auto tracksThisCollision = tracks.sliceBy(perCollision, collision.collisionId());
1891-
fillTracks<isMC>(collision, tracksThisCollision);
1892-
if (FilterForDerivedTables.cfgFillMicroTracks) {
1893-
fillMicroTracks<isMC>(collision, tracksThisCollision);
1894-
}
1895-
if (FilterForDerivedTables.cfgFillUltraMicroTracks) {
1896-
fillUltraMicroTracks<isMC>(collision, tracksThisCollision);
1897-
}
1924+
fillTrackTables<isMC>(collision, tracksThisCollision);
18981925
}
18991926

19001927
/**
@@ -1910,6 +1937,43 @@ struct ResonanceDaughterInitializer {
19101937
}
19111938
PROCESS_SWITCH(ResonanceDaughterInitializer, processData, "Process tracks for data", false);
19121939

1940+
/**
1941+
* @brief Processes data tracks grouped automatically by their original collision
1942+
*
1943+
* The canonical fIndexCollisions column in ResoCollisionGroups lets
1944+
* GroupSlicer associate both reduced collisions and tracks to the same
1945+
* original aod::Collision. The tracks argument is therefore already the
1946+
* selected slice for this collision and must not be sliced again.
1947+
*/
1948+
void processDataOptimized(aod::Collision const&,
1949+
soa::SmallGroups<SelectedResoCollisions> const& reducedCollisions,
1950+
soa::Filtered<aod::ResoTrackCandidates> const& tracks)
1951+
{
1952+
if (reducedCollisions.size() == 0) {
1953+
return;
1954+
}
1955+
if (reducedCollisions.size() != 1) {
1956+
LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size());
1957+
}
1958+
auto reducedCollision = reducedCollisions.begin();
1959+
fillTrackTables<false>(reducedCollision, tracks);
1960+
}
1961+
PROCESS_SWITCH(ResonanceDaughterInitializer, processDataOptimized, "Process data tracks with original-collision grouping", false);
1962+
1963+
/**
1964+
* @brief Production hybrid path using original-collision automatic grouping
1965+
*
1966+
* This named path preserves the existing optimized prototype for A/B
1967+
* compatibility while exposing the two-stage hybrid architecture explicitly.
1968+
*/
1969+
void processDataHybrid(aod::Collision const& originalCollision,
1970+
soa::SmallGroups<SelectedResoCollisions> const& reducedCollisions,
1971+
soa::Filtered<aod::ResoTrackCandidates> const& tracks)
1972+
{
1973+
processDataOptimized(originalCollision, reducedCollisions, tracks);
1974+
}
1975+
PROCESS_SWITCH(ResonanceDaughterInitializer, processDataHybrid, "Process data tracks with the two-stage hybrid grouping", false);
1976+
19131977
/**
19141978
* @brief Processes data tracks with configurable selected-V0 and selected-cascade gates
19151979
*/
@@ -1984,6 +2048,29 @@ struct ResonanceDaughterInitializer {
19842048
}
19852049
PROCESS_SWITCH(ResonanceDaughterInitializer, processV0Data, "Process V0s for data", false);
19862050

2051+
/**
2052+
* @brief Processes data V0s grouped automatically by their original collision
2053+
*
2054+
* Both V0s and tracks are already restricted to the current original
2055+
* aod::Collision by GroupSlicer. The unfiltered track table is required for
2056+
* resolving the positive and negative daughter indices.
2057+
*/
2058+
void processV0DataHybrid(aod::Collision const&,
2059+
soa::SmallGroups<SelectedResoCollisions> const& reducedCollisions,
2060+
aod::ResoV0Candidates const& v0s,
2061+
aod::ResoTrackCandidates const& tracks)
2062+
{
2063+
if (reducedCollisions.size() == 0) {
2064+
return;
2065+
}
2066+
if (reducedCollisions.size() != 1) {
2067+
LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size());
2068+
}
2069+
auto reducedCollision = reducedCollisions.begin();
2070+
fillV0s<false>(reducedCollision, v0s, tracks);
2071+
}
2072+
PROCESS_SWITCH(ResonanceDaughterInitializer, processV0DataHybrid, "Process data V0s with the two-stage hybrid grouping", false);
2073+
19872074
/**
19882075
* @brief Processes MC V0 data
19892076
*
@@ -2012,6 +2099,29 @@ struct ResonanceDaughterInitializer {
20122099
}
20132100
PROCESS_SWITCH(ResonanceDaughterInitializer, processCascData, "Process Cascades for data", false);
20142101

2102+
/**
2103+
* @brief Processes data cascades grouped automatically by their original collision
2104+
*
2105+
* Cascades and tracks arrive as original-collision groups. Keeping this as a
2106+
* separate callback from V0 processing avoids enabling either upstream input
2107+
* dependency unless its process switch is selected.
2108+
*/
2109+
void processCascDataHybrid(aod::Collision const&,
2110+
soa::SmallGroups<SelectedResoCollisions> const& reducedCollisions,
2111+
aod::ResoCascadesCandidates const& cascades,
2112+
aod::ResoTrackCandidates const& tracks)
2113+
{
2114+
if (reducedCollisions.size() == 0) {
2115+
return;
2116+
}
2117+
if (reducedCollisions.size() != 1) {
2118+
LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size());
2119+
}
2120+
auto reducedCollision = reducedCollisions.begin();
2121+
fillCascades<false>(reducedCollision, cascades, tracks);
2122+
}
2123+
PROCESS_SWITCH(ResonanceDaughterInitializer, processCascDataHybrid, "Process data cascades with the two-stage hybrid grouping", false);
2124+
20152125
/**
20162126
* @brief Processes MC cascade data
20172127
*

0 commit comments

Comments
 (0)