From f80000df9006d0657260d85c900a4418f6ccf6c0 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Wed, 8 Jul 2026 15:51:17 +0200 Subject: [PATCH 1/2] Feat: speed up event mixing in triplet tasks --- PWGCF/Femto/Core/tripletProcessHelpers.h | 62 +++++++++++++++++------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/PWGCF/Femto/Core/tripletProcessHelpers.h b/PWGCF/Femto/Core/tripletProcessHelpers.h index 4d02566c120..04e604e79bb 100644 --- a/PWGCF/Femto/Core/tripletProcessHelpers.h +++ b/PWGCF/Femto/Core/tripletProcessHelpers.h @@ -459,20 +459,34 @@ void processMixedEvent(T1 const& Collisions, T10& CtrManager, T11& TcManager) { - int64_t lastCollisionIndex = -1; + int64_t lastCollisionIndex1 = -1; + int64_t lastCollisionIndex2 = -1; int windowSizeRaw = 0; int windowSizeEffective = 0; + // collision1 stays fixed across the outer mixing window, and collision2 stays fixed across each inner sub-window (it only advances once collision3 wraps + // back to its start Both slices are therefore materialized once per window/sub-window and reused, instead of being re-sliced, i.e. a fresh arrow Slice + selection copy + std::optionalsliceByCached(o2::aod::femtobase::stored::fColId, 0, cache))> sliceParticle1; + std::optionalsliceByCached(o2::aod::femtobase::stored::fColId, 0, cache))> sliceParticle2; + for (auto const& [collision1, collision2, collision3] : o2::soa::selfCombinations(policy, depth, -1, Collisions, Collisions, Collisions)) { - // --- new window --- - if (collision1.globalIndex() != lastCollisionIndex) { - if (lastCollisionIndex != -1) { + // outer window + if (collision1.globalIndex() != lastCollisionIndex1) { + if (lastCollisionIndex1 != -1) { TripletHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective); } windowSizeRaw = 0; windowSizeEffective = 0; - lastCollisionIndex = collision1.globalIndex(); + lastCollisionIndex1 = collision1.globalIndex(); + lastCollisionIndex2 = -1; // force sliceParticle2 to refresh below + sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache)); + } + + // inner sub-window + if (collision2.globalIndex() != lastCollisionIndex2) { + lastCollisionIndex2 = collision2.globalIndex(); + sliceParticle2.emplace(Partition2->sliceByCached(o2::aod::femtobase::stored::fColId, collision2.globalIndex(), cache)); } ++windowSizeRaw; @@ -486,13 +500,11 @@ void processMixedEvent(T1 const& Collisions, CtrManager.setMagField(collision1.magField()); - auto sliceParticle1 = Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache); - auto sliceParticle2 = Partition2->sliceByCached(o2::aod::femtobase::stored::fColId, collision2.globalIndex(), cache); auto sliceParticle3 = Partition3->sliceByCached(o2::aod::femtobase::stored::fColId, collision3.globalIndex(), cache); TripletHistManager.resetTrackedParticlesPerEvent(); - if (sliceParticle1.size() == 0 || sliceParticle2.size() == 0 || sliceParticle3.size() == 0) { + if (sliceParticle1->size() == 0 || sliceParticle2->size() == 0 || sliceParticle3.size() == 0) { TripletHistManager.fillMixingQaMePerEvent(); continue; } @@ -500,7 +512,7 @@ void processMixedEvent(T1 const& Collisions, bool hasValidTriplet = false; TripletHistManager.fillMixingQaMe(collision1, collision2, collision3); - for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(sliceParticle1, sliceParticle2, sliceParticle3))) { + for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(*sliceParticle1, *sliceParticle2, sliceParticle3))) { // pair cleaning if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable)) { continue; @@ -528,7 +540,7 @@ void processMixedEvent(T1 const& Collisions, TripletHistManager.fillMixingQaMePerEvent(); } - // --- final window --- + // final window if (windowSizeRaw > 0) { TripletHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective); } @@ -563,19 +575,34 @@ void processMixedEvent(T1 const& Collisions, T12& CtrManager, T13& TcManager) { - int64_t lastCollisionIndex = -1; + int64_t lastCollisionIndex1 = -1; + int64_t lastCollisionIndex2 = -1; int windowSizeRaw = 0; int windowSizeEffective = 0; + // collision1 stays fixed across the outer mixing window, and collision2 stays fixed across each inner sub-window (it only advances once collision3 wraps + // back to its start Both slices are therefore materialized once per window/sub-window and reused, instead of being re-sliced, i.e. a fresh arrow Slice + selection copy + std::optionalsliceByCached(o2::aod::femtobase::stored::fColId, 0, cache))> sliceParticle1; + std::optionalsliceByCached(o2::aod::femtobase::stored::fColId, 0, cache))> sliceParticle2; + for (auto const& [collision1, collision2, collision3] : o2::soa::selfCombinations(policy, depth, -1, Collisions, Collisions, Collisions)) { - if (collision1.globalIndex() != lastCollisionIndex) { - if (lastCollisionIndex != -1) { + // outer window + if (collision1.globalIndex() != lastCollisionIndex1) { + if (lastCollisionIndex1 != -1) { TripletHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective); } windowSizeRaw = 0; windowSizeEffective = 0; - lastCollisionIndex = collision1.globalIndex(); + lastCollisionIndex1 = collision1.globalIndex(); + lastCollisionIndex2 = -1; // force sliceParticle2 to refresh below + sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache)); + } + + // inner sub-window + if (collision2.globalIndex() != lastCollisionIndex2) { + lastCollisionIndex2 = collision2.globalIndex(); + sliceParticle2.emplace(Partition2->sliceByCached(o2::aod::femtobase::stored::fColId, collision2.globalIndex(), cache)); } ++windowSizeRaw; @@ -589,13 +616,11 @@ void processMixedEvent(T1 const& Collisions, CtrManager.setMagField(collision1.magField()); - auto sliceParticle1 = Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache); - auto sliceParticle2 = Partition2->sliceByCached(o2::aod::femtobase::stored::fColId, collision2.globalIndex(), cache); auto sliceParticle3 = Partition3->sliceByCached(o2::aod::femtobase::stored::fColId, collision3.globalIndex(), cache); TripletHistManager.resetTrackedParticlesPerEvent(); - if (sliceParticle1.size() == 0 || sliceParticle2.size() == 0 || sliceParticle3.size() == 0) { + if (sliceParticle1->size() == 0 || sliceParticle2->size() == 0 || sliceParticle3.size() == 0) { TripletHistManager.fillMixingQaMePerEvent(); continue; } @@ -603,7 +628,7 @@ void processMixedEvent(T1 const& Collisions, bool hasValidTriplet = false; TripletHistManager.fillMixingQaMe(collision1, collision2, collision3); - for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(sliceParticle1, sliceParticle2, sliceParticle3))) { + for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(*sliceParticle1, *sliceParticle2, sliceParticle3))) { // pair cleaning if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable)) { continue; @@ -631,6 +656,7 @@ void processMixedEvent(T1 const& Collisions, TripletHistManager.fillMixingQaMePerEvent(); } + // --- final window --- if (windowSizeRaw > 0) { TripletHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective); } From 8a144cdddab1aab3cd7093b5906511a04e104afc Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Wed, 8 Jul 2026 16:22:39 +0200 Subject: [PATCH 2/2] Fix: add missing include --- PWGCF/Femto/Core/tripletProcessHelpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGCF/Femto/Core/tripletProcessHelpers.h b/PWGCF/Femto/Core/tripletProcessHelpers.h index 04e604e79bb..92a674e12fd 100644 --- a/PWGCF/Femto/Core/tripletProcessHelpers.h +++ b/PWGCF/Femto/Core/tripletProcessHelpers.h @@ -23,6 +23,7 @@ #include #include +#include namespace o2::analysis::femto::tripletprocesshelpers {