Skip to content

Commit 0ffbcbb

Browse files
authored
[PWGCF] Add stride to event mixing in femto framework (#18430)
1 parent a0332c7 commit 0ffbcbb

6 files changed

Lines changed: 278 additions & 148 deletions

File tree

‎PWGCF/Femto/Core/pairBuilder.h‎

Lines changed: 109 additions & 85 deletions
Large diffs are not rendered by default.

‎PWGCF/Femto/Core/pairHistManager.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ struct ConfMixing : o2::framework::ConfigurableGroup {
195195
o2::framework::ConfigurableAxis eventPlaneAngle{"eventPlaneAngle", {10, 0.f, 1.f * o2::constants::math::TwoPI}, "Mixing bins - event plane angle"};
196196
o2::framework::Configurable<int> depth{"depth", 5, "Number of events for mixing"};
197197
o2::framework::Configurable<int> policy{"policy", 0, "Binning policy for mixing (alywas in combination with z-vertex) -> 0: multiplicity, -> 1: centrality, -> 2: multiplicity and centrality, -> 3: centrality and event plane angle"};
198+
o2::framework::Configurable<int> eventStride{"eventStride", 1, "Only use every Nth collision as a mixing anchor (1 = use every collision). Reduces mixed-event combinatorics roughly 1/eventStride."};
198199
o2::framework::Configurable<bool> sameSpecies{"sameSpecies", false, "Enable if particle 1 and particle 2 are the same"};
199200
o2::framework::Configurable<int> seed{"seed", -1, "Seed to randomize particle 1 and particle 2 (if they are identical). Set to negative value to deactivate. Set to 0 to generate unique seed in time."};
200201
o2::framework::Configurable<bool> enablePairCorrelationQa{"enablePairCorrelationQa", true, "Enable pair-level correlation QA (same-event + mixed-event)"};

‎PWGCF/Femto/Core/pairProcessHelpers.h‎

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -439,11 +439,16 @@ void processMixedEvent(T1 const& Collisions,
439439
T7 const& depth,
440440
T8& PairHistManager,
441441
T9& CprManager,
442-
T10& PcManager)
442+
T10& PcManager,
443+
int eventStride = 1)
443444
{
444445
int64_t lastCollisionIndex = -1;
445446
int windowSizeRaw = 0;
446447
int windowSizeEffective = 0;
448+
// counts actual anchor windows encountered (not raw collision IDs, which may have gaps from
449+
// upstream event selection) so "every Nth anchor" is evenly spaced regardless of such gaps
450+
int64_t windowCounter = -1;
451+
bool skipThisWindow = false;
447452

448453
// collision1 is fixed across each mixing window, so its track slice is
449454
// materialized once per window and reused for every mixing partner, instead
@@ -455,13 +460,24 @@ void processMixedEvent(T1 const& Collisions,
455460

456461
// --- new window ---
457462
if (collision1.globalIndex() != lastCollisionIndex) {
458-
if (lastCollisionIndex != -1) {
463+
if (lastCollisionIndex != -1 && !skipThisWindow) {
459464
PairHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective);
460465
}
461466
windowSizeRaw = 0;
462467
windowSizeEffective = 0;
463468
lastCollisionIndex = collision1.globalIndex();
464-
sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache));
469+
++windowCounter;
470+
// skip entire anchor windows to reduce mixed-event combinatorics without truncating any
471+
// single event's particle content -- every anchor that IS processed still gets its full
472+
// `depth` worth of mixing partners
473+
skipThisWindow = eventStride > 1 && windowCounter % eventStride != 0;
474+
if (!skipThisWindow) {
475+
sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache));
476+
}
477+
}
478+
479+
if (skipThisWindow) {
480+
continue;
465481
}
466482

467483
++windowSizeRaw;
@@ -551,11 +567,16 @@ void processMixedEvent(T1 const& Collisions,
551567
T13& ParticleCleaner1,
552568
T14& ParticleCleaner2,
553569
T15& CprManager,
554-
T16& PcManager)
570+
T16& PcManager,
571+
int eventStride = 1)
555572
{
556573
int64_t lastCollisionIndex = -1;
557574
int windowSizeRaw = 0;
558575
int windowSizeEffective = 0;
576+
// counts actual anchor windows encountered (not raw collision IDs, which may have gaps from
577+
// upstream event selection) so "every Nth anchor" is evenly spaced regardless of such gaps
578+
int64_t windowCounter = -1;
579+
bool skipThisWindow = false;
559580

560581
// collision1 is fixed across each mixing window, so its track slice is
561582
// materialized once per window and reused for every mixing partner, instead
@@ -565,13 +586,24 @@ void processMixedEvent(T1 const& Collisions,
565586

566587
for (auto const& [collision1, collision2] : o2::soa::selfCombinations(policy, depth, -1, Collisions, Collisions)) {
567588
if (collision1.globalIndex() != lastCollisionIndex) {
568-
if (lastCollisionIndex != -1) {
589+
if (lastCollisionIndex != -1 && !skipThisWindow) {
569590
PairHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective);
570591
}
571592
windowSizeRaw = 0;
572593
windowSizeEffective = 0;
573594
lastCollisionIndex = collision1.globalIndex();
574-
sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache));
595+
++windowCounter;
596+
// skip entire anchor windows to reduce mixed-event combinatorics without truncating any
597+
// single event's particle content -- every anchor that IS processed still gets its full
598+
// `depth` worth of mixing partners
599+
skipThisWindow = eventStride > 1 && windowCounter % eventStride != 0;
600+
if (!skipThisWindow) {
601+
sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache));
602+
}
603+
}
604+
605+
if (skipThisWindow) {
606+
continue;
575607
}
576608

577609
++windowSizeRaw;
@@ -661,24 +693,40 @@ void processMixedEvent(T1 const& Collisions,
661693
T11& ParticleCleaner1,
662694
T12& ParticleCleaner2,
663695
T13& CprManager,
664-
T14& PcManager)
696+
T14& PcManager,
697+
int eventStride = 1)
665698
{
666699
int64_t lastCollisionIndex = -1;
667700
int windowSizeRaw = 0;
668701
int windowSizeEffective = 0;
702+
// counts actual anchor windows encountered (not raw collision IDs, which may have gaps from
703+
// upstream event selection) so "every Nth anchor" is evenly spaced regardless of such gaps
704+
int64_t windowCounter = -1;
705+
bool skipThisWindow = false;
669706

670707
std::optional<decltype(Partition1->sliceByCachedUnsorted(o2::aod::femtomcparticle::fMcColId, 0, cache))> sliceParticle1;
671708

672709
for (auto const& [collision1, collision2] : o2::soa::selfCombinations(policy, depth, -1, Collisions, Collisions)) {
673710

674711
if (collision1.globalIndex() != lastCollisionIndex) {
675-
if (lastCollisionIndex != -1) {
712+
if (lastCollisionIndex != -1 && !skipThisWindow) {
676713
PairHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective);
677714
}
678715
windowSizeRaw = 0;
679716
windowSizeEffective = 0;
680717
lastCollisionIndex = collision1.globalIndex();
681-
sliceParticle1.emplace(Partition1->sliceByCachedUnsorted(o2::aod::femtomcparticle::fMcColId, collision1.globalIndex(), cache));
718+
++windowCounter;
719+
// skip entire anchor windows to reduce mixed-event combinatorics without truncating any
720+
// single event's particle content -- every anchor that IS processed still gets its full
721+
// `depth` worth of mixing partners
722+
skipThisWindow = eventStride > 1 && windowCounter % eventStride != 0;
723+
if (!skipThisWindow) {
724+
sliceParticle1.emplace(Partition1->sliceByCachedUnsorted(o2::aod::femtomcparticle::fMcColId, collision1.globalIndex(), cache));
725+
}
726+
}
727+
728+
if (skipThisWindow) {
729+
continue;
682730
}
683731

684732
++windowSizeRaw;

0 commit comments

Comments
 (0)