From e48536fb8c6e60151ea17bb3ab6055f3c8413c66 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 20 Oct 2026 09:31:07 +0200 Subject: [PATCH] Feat: simplify daughter selection --- PWGCF/Femto/Core/partitions.h | 93 +++++++++++-------- .../trackTrackTwoPhotonResonanceBuilder.h | 13 ++- PWGCF/Femto/Core/twoTrackResonanceBuilder.h | 49 +++++++--- 3 files changed, 92 insertions(+), 63 deletions(-) diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index 6900186a342..4f03bbe7c04 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -56,25 +56,29 @@ (o2::aod::femtobase::stored::mass > (selection).massMin) && \ (o2::aod::femtobase::stored::mass < (selection).massMax) -// partition for phis and rhos, i.e. resonance that are their own antiparticle +// partition for phis and rhos, i.e. resonance that are their own antiparticle -- both daughters are +// the same species, so the selection carries a single dauMask pair applied to both stored columns // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define MAKE_RESONANCE_0_PARTITON(selection) \ - (o2::aod::femtobase::stored::pt > (selection).ptMin) && \ - (o2::aod::femtobase::stored::pt < (selection).ptMax) && \ - (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ - (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ - (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ - (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ - (o2::aod::femtobase::stored::mass > (selection).massMin) && \ - (o2::aod::femtobase::stored::mass < (selection).massMax) && \ - ifnode(o2::aod::femtotwotrackresonances::posDauHasHighMomentum, \ - ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).posDauMaskAboveThres), \ - ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).posDauMaskBelowThres)) && \ - ifnode(o2::aod::femtotwotrackresonances::negDauHasHighMomentum, \ - ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).negDauMaskAboveThres), \ - ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).negDauMaskBelowThres)) +#define MAKE_RESONANCE_0_PARTITON(selection) \ + (o2::aod::femtobase::stored::pt > (selection).ptMin) && \ + (o2::aod::femtobase::stored::pt < (selection).ptMax) && \ + (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ + (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ + (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ + (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ + (o2::aod::femtobase::stored::mass > (selection).massMin) && \ + (o2::aod::femtobase::stored::mass < (selection).massMax) && \ + ifnode(o2::aod::femtotwotrackresonances::posDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).dauMaskAboveThres), \ + ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).dauMaskBelowThres)) && \ + ifnode(o2::aod::femtotwotrackresonances::negDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).dauMaskAboveThres), \ + ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).dauMaskBelowThres)) -// partition for kstars, they have distinct antiparticle +// partition for kstars, they have distinct antiparticle -- K*0 (K+ pi-) and K*0bar (K- pi+) swap +// which physical daughter (pos/neg) is the kaon vs the pion, so the selection carries masks named by +// species (kaon/pion) and this macro resolves pos/neg <-> kaon/pion from the candidate's own +// signedPt, the same way it's reconstructed (no need for the user to reason about this downstream) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define MAKE_RESONANCE_1_PARTITON(selection) \ ifnode((selection).sign.node() != 0, \ @@ -87,12 +91,19 @@ (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ (o2::aod::femtobase::stored::mass > (selection).massMin) && \ (o2::aod::femtobase::stored::mass < (selection).massMax) && \ - ifnode(o2::aod::femtotwotrackresonances::posDauHasHighMomentum, \ - ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).posDauMaskAboveThres), \ - ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).posDauMaskBelowThres)) && \ - ifnode(o2::aod::femtotwotrackresonances::negDauHasHighMomentum, \ - ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).negDauMaskAboveThres), \ - ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).negDauMaskBelowThres)) + ifnode(o2::aod::femtobase::stored::signedPt > 0.f, \ + ifnode(o2::aod::femtotwotrackresonances::posDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).kaonDauMaskAboveThres), \ + ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).kaonDauMaskBelowThres)) && \ + ifnode(o2::aod::femtotwotrackresonances::negDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).pionDauMaskAboveThres), \ + ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).pionDauMaskBelowThres)), \ + ifnode(o2::aod::femtotwotrackresonances::posDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).pionDauMaskAboveThres), \ + ncheckbit(o2::aod::femtotwotrackresonances::maskPosDau, (selection).pionDauMaskBelowThres)) && \ + ifnode(o2::aod::femtotwotrackresonances::negDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).kaonDauMaskAboveThres), \ + ncheckbit(o2::aod::femtotwotrackresonances::maskNegDau, (selection).kaonDauMaskBelowThres))) // partition for resonances built from two photons (pi0, eta, ...): unlike MAKE_RESONANCE_0/1_PARTITON // there is no sign and no momentum-threshold PID switch, and just a single mask check -- both @@ -111,25 +122,25 @@ ncheckbit(o2::aod::femtotwophotonresonances::maskDau, (selection).dauMask) // partition for resonances built from two tracks and a two-photon resonance (e.g. omega(782) -> -// pi+ pi- pi0): same pattern as MAKE_RESONANCE_1_PARTITON (daughter masks copied onto the candidate -// at build time, systematics reselected here), just with 3 daughter masks instead of 2 -- the two -// charged daughters keep their momentum-threshold PID switch, the neutral daughter does not +// pi+ pi- pi0): same pattern as MAKE_RESONANCE_0_PARTITON (both charged daughters are the same +// species -- pions, just opposite charge, no kstar-style species swap -- so a single dauMask pair +// covers both), plus a 3rd mask for the neutral daughter (no momentum-threshold split there) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define MAKE_TRACKTRACKTWOPHOTONRESONANCE_PARTITION(selection) \ - (o2::aod::femtobase::stored::pt > (selection).ptMin) && \ - (o2::aod::femtobase::stored::pt < (selection).ptMax) && \ - (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ - (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ - (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ - (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ - (o2::aod::femtobase::stored::mass > (selection).massMin) && \ - (o2::aod::femtobase::stored::mass < (selection).massMax) && \ - ifnode(o2::aod::femtotrackstwophotonresonances::posDauHasHighMomentum, \ - ncheckbit(o2::aod::femtotrackstwophotonresonances::maskPosDau, (selection).posDauMaskAboveThres), \ - ncheckbit(o2::aod::femtotrackstwophotonresonances::maskPosDau, (selection).posDauMaskBelowThres)) && \ - ifnode(o2::aod::femtotrackstwophotonresonances::negDauHasHighMomentum, \ - ncheckbit(o2::aod::femtotrackstwophotonresonances::maskNegDau, (selection).negDauMaskAboveThres), \ - ncheckbit(o2::aod::femtotrackstwophotonresonances::maskNegDau, (selection).negDauMaskBelowThres)) && \ +#define MAKE_TRACKTRACKTWOPHOTONRESONANCE_PARTITION(selection) \ + (o2::aod::femtobase::stored::pt > (selection).ptMin) && \ + (o2::aod::femtobase::stored::pt < (selection).ptMax) && \ + (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ + (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ + (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ + (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ + (o2::aod::femtobase::stored::mass > (selection).massMin) && \ + (o2::aod::femtobase::stored::mass < (selection).massMax) && \ + ifnode(o2::aod::femtotrackstwophotonresonances::posDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotrackstwophotonresonances::maskPosDau, (selection).pionDauMaskAboveThres), \ + ncheckbit(o2::aod::femtotrackstwophotonresonances::maskPosDau, (selection).pionDauMaskBelowThres)) && \ + ifnode(o2::aod::femtotrackstwophotonresonances::negDauHasHighMomentum, \ + ncheckbit(o2::aod::femtotrackstwophotonresonances::maskNegDau, (selection).pionDauMaskAboveThres), \ + ncheckbit(o2::aod::femtotrackstwophotonresonances::maskNegDau, (selection).pionDauMaskBelowThres)) && \ ncheckbit(o2::aod::femtotrackstwophotonresonances::maskNeutralDau, (selection).neutralDauMask) // partition for lambdas diff --git a/PWGCF/Femto/Core/trackTrackTwoPhotonResonanceBuilder.h b/PWGCF/Femto/Core/trackTrackTwoPhotonResonanceBuilder.h index 2e280ea1365..dacdde4f272 100644 --- a/PWGCF/Femto/Core/trackTrackTwoPhotonResonanceBuilder.h +++ b/PWGCF/Femto/Core/trackTrackTwoPhotonResonanceBuilder.h @@ -52,9 +52,10 @@ struct ConfOmegaMesonFilters : o2::framework::ConfigurableGroup { }; // selection used downstream (QA/pairing) to re-select already produced resonances by mass window -// and daughter mask -- same pattern as the two-track resonances (TWOTRACKRESONANCE_DEFAULT_SELECTION), -// just with a 3rd mask for the neutral daughter (no momentum-threshold split there, same as -// femtotwophotonresonances' single dauMask) +// and daughter mask. both charged daughters are pions (just opposite charge, no species swap the +// way kstar's kaon/pion does), so -- same as TWOTRACKRESONANCE_SAME_SPECIES_MASK for phi/rho0 -- +// a single pair of mask thresholds is applied to both. plus a 3rd mask for the neutral daughter (no +// momentum-threshold split there, same as femtotwophotonresonances' single dauMask) template struct ConfOmegaMesonSelection : o2::framework::ConfigurableGroup { std::string prefix = Prefix; @@ -67,10 +68,8 @@ struct ConfOmegaMesonSelection : o2::framework::ConfigurableGroup { o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; o2::framework::Configurable massMin{"massMin", 0.6f, "Minimum invariant mass"}; o2::framework::Configurable massMax{"massMax", 0.95f, "Maximum invariant mass"}; - o2::framework::Configurable posDauMaskBelowThres{"posDauMaskBelowThres", 0x10u, "Bitmask for positive daughter below threshold"}; - o2::framework::Configurable posDauMaskAboveThres{"posDauMaskAboveThres", 0x8u, "Bitmask for positive daughter above threshold"}; - o2::framework::Configurable negDauMaskBelowThres{"negDauMaskBelowThres", 0x2u, "Bitmask for negative daughter below threshold"}; - o2::framework::Configurable negDauMaskAboveThres{"negDauMaskAboveThres", 0x1u, "Bitmask for negative daughter above threshold"}; + o2::framework::Configurable pionDauMaskBelowThres{"pionDauMaskBelowThres", 0x10u, "Bitmask for both pion daughters below threshold"}; + o2::framework::Configurable pionDauMaskAboveThres{"pionDauMaskAboveThres", 0x8u, "Bitmask for both pion daughters above threshold"}; o2::framework::Configurable neutralDauMask{"neutralDauMask", 0, "Bitmask required for the neutral (two-photon-resonance) daughter"}; }; diff --git a/PWGCF/Femto/Core/twoTrackResonanceBuilder.h b/PWGCF/Femto/Core/twoTrackResonanceBuilder.h index 379ea697b0a..fece3d0e06f 100644 --- a/PWGCF/Femto/Core/twoTrackResonanceBuilder.h +++ b/PWGCF/Femto/Core/twoTrackResonanceBuilder.h @@ -58,40 +58,60 @@ using ConfPhiFilters = ConfTwoTrackResonanceFilters; using ConfKstarFilters = ConfTwoTrackResonanceFilters; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define TWOTRACKRESONANCE_DEFAULT_SELECTION(defaultPdgCode, defaultMassMin, defaultMassMax) \ - o2::framework::Configurable pdgCodeAbs{"pdgCodeAbs", (defaultPdgCode), "Resonance PDG code. Set sign to minus 1 for antiparticle"}; \ - o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; \ - o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT"}; \ - o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta"}; \ - o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta"}; \ - o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; \ - o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; \ - o2::framework::Configurable massMin{"massMin", (defaultMassMin), "Minimum invariant mass for Resonance"}; \ - o2::framework::Configurable massMax{"massMax", (defaultMassMax), "Maximum invariant mass for Resonance"}; \ - o2::framework::Configurable posDauMaskBelowThres{"posDauMaskBelowThres", 0x10u, "Bitmask for positive daughter below threshold"}; \ - o2::framework::Configurable posDauMaskAboveThres{"posDauMaskAboveThres", 0x8u, "Bitmask for positive daughter above threshold"}; \ - o2::framework::Configurable negDauMaskBelowThres{"negDauMaskBelowThres", 0x2u, "Bitmask for negative daughter below threshold"}; \ - o2::framework::Configurable negDauMaskAboveThres{"negDauMaskAboveThres", 0x1u, "Bitmask for negative daughter above threshold"}; +#define TWOTRACKRESONANCE_DEFAULT_SELECTION(defaultPdgCode, defaultMassMin, defaultMassMax) \ + o2::framework::Configurable pdgCodeAbs{"pdgCodeAbs", (defaultPdgCode), "Resonance PDG code. Set sign to minus 1 for antiparticle"}; \ + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; \ + o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT"}; \ + o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta"}; \ + o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta"}; \ + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; \ + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; \ + o2::framework::Configurable massMin{"massMin", (defaultMassMin), "Minimum invariant mass for Resonance"}; \ + o2::framework::Configurable massMax{"massMax", (defaultMassMax), "Maximum invariant mass for Resonance"}; + +// phi -> K+ K-, rho0 -> pi+ pi-: both daughters are the same species, so a single pair of mask +// thresholds is enough, applied to both the positive and negative daughter alike +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define TWOTRACKRESONANCE_SAME_SPECIES_MASK \ + o2::framework::Configurable dauMaskBelowThres{"dauMaskBelowThres", 0x10u, "Bitmask for both daughters below threshold"}; \ + o2::framework::Configurable dauMaskAboveThres{"dauMaskAboveThres", 0x8u, "Bitmask for both daughters above threshold"}; struct ConfPhiSelection : o2::framework::ConfigurableGroup { std::string prefix = std::string("PhiSelection"); TWOTRACKRESONANCE_DEFAULT_SELECTION(333, 0.95f, 1.05f) + TWOTRACKRESONANCE_SAME_SPECIES_MASK o2::framework::Configurable sign{"sign", 1, "Dummy value for compatibility"}; }; struct ConfRho0Selection : o2::framework::ConfigurableGroup { std::string prefix = std::string("Rho0Selection"); TWOTRACKRESONANCE_DEFAULT_SELECTION(113, 0.7f, 0.84f) + TWOTRACKRESONANCE_SAME_SPECIES_MASK o2::framework::Configurable sign{"sign", 1, "Dummy value for compatibility"}; }; +#undef TWOTRACKRESONANCE_SAME_SPECIES_MASK + +// K*0 -> K+ pi-, K*0bar -> K- pi+: the physical pos/neg daughter's species flips with the +// candidate's charge sign, so the masks are named by species (kaon/pion) rather than by charge -- +// MAKE_RESONANCE_1_PARTITON resolves which stored column (maskPosDau/maskNegDau) each applies to +// from the candidate's own signedPt, so the user never has to reason about pos/neg <-> kaon/pion +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define TWOTRACKRESONANCE_KSTAR_MASK \ + o2::framework::Configurable kaonDauMaskBelowThres{"kaonDauMaskBelowThres", 0x10u, "Bitmask for the kaon daughter below threshold"}; \ + o2::framework::Configurable kaonDauMaskAboveThres{"kaonDauMaskAboveThres", 0x8u, "Bitmask for the kaon daughter above threshold"}; \ + o2::framework::Configurable pionDauMaskBelowThres{"pionDauMaskBelowThres", 0x2u, "Bitmask for the pion daughter below threshold"}; \ + o2::framework::Configurable pionDauMaskAboveThres{"pionDauMaskAboveThres", 0x1u, "Bitmask for the pion daughter above threshold"}; + struct ConfKstar0Selection : o2::framework::ConfigurableGroup { std::string prefix = std::string("Kstar0Selection"); o2::framework::Configurable sign{"sign", 1, "Sign (+1 for Kstar0 and -1 for Kstar0Bar) "}; TWOTRACKRESONANCE_DEFAULT_SELECTION(313, 0.8f, 1.0f) + TWOTRACKRESONANCE_KSTAR_MASK }; #undef TWOTRACKRESONANCE_DEFAULT_SELECTION +#undef TWOTRACKRESONANCE_KSTAR_MASK struct TwoTrackResonanceBuilderProducts : o2::framework::ProducesGroup { o2::framework::Produces producedPhis; @@ -182,7 +202,6 @@ class TwoTrackResonanceBuilder } auto posDaughterSlice = posDaughterPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto negDaughterSlice = negDaughterPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - // LOG(warn) << "Size: " << posDaughterSlice.size() << " " << negDaughterSlice.size(); for (auto const& [posDaughter, negDaughter] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posDaughterSlice, negDaughterSlice))) { this->fillResonance(col, posDaughter, negDaughter, resonanceProducts); }