@@ -1739,24 +1739,26 @@ struct Lambdastarproxy {
17391739 // Helpers for invariant-mass kinematics
17401740 static float phiFromPxPy (float px, float py)
17411741 {
1742- return std::atan2 (py, px);
1742+ return RecoDecay::constrainAngle ( std::atan2 (py, px), -o2::constants::math::PI );
17431743 }
17441744
1745- static float rapidityFromEPz ( double e, double pz )
1745+ static float ptFromPxPy ( float px, float py )
17461746 {
1747- const double num = e + pz;
1748- const double den = e - pz;
1749- if (num <= 0.0 || den <= 0.0 ) {
1750- return 0 .f ;
1751- }
1752- return static_cast <float >(Half * std::log (num / den));
1747+ return RecoDecay::pt (std::array{px, py});
1748+ }
1749+
1750+ static float rapidityFromMomentumAndMass (float px, float py, float pz, double mass)
1751+
1752+ {
1753+ return RecoDecay::y (std::array{px, py, pz}, mass);
17531754 }
17541755
17551756 // Mixed-event pool entry for pK / proxy background (AO2D only)
17561757 struct LStarMixEventEntry {
17571758 float mult = 0 .f;
17581759 float zvtx = 0 .f;
17591760 std::vector<KaonCand> kaons;
1761+ std::vector<ProtonCand> protons;
17601762 std::vector<ProxyCand> proxies;
17611763 };
17621764
@@ -1966,56 +1968,44 @@ struct Lambdastarproxy {
19661968 " pK invariant mass (like-sign);M_{pK} (GeV/c^{2});Counts" ,
19671969 HistType::kTH1F , {massAxis});
19681970
1969- // Invariant-mass vs pair pT (use p_{T} of pK system)
1970- histos.add (" hInvMassPKUnlikeVsPt" ,
1971- " pK invariant mass vs p_{T} (unlike-sign);M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);Counts" ,
1972- HistType::kTH2F , {massAxis, ptAxis});
1973- histos.add (" hInvMassPKLikeVsPt" ,
1974- " pK invariant mass vs p_{T} (like-sign);M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);Counts" ,
1975- HistType::kTH2F , {massAxis, ptAxis});
1976-
1977- // THnSparse for invariant-mass analysis (mass, pT, y, phi)
1971+ // THnSparse for invariant-mass analysis (mass, pT, multiplicity/centrality)
19781972 if (lstarEnableSparse.value != 0 ) {
19791973 histos.add (" hLambdaStarPKUnlikeSparse" ,
1980- " #Lambda^{*}(1520) pK unlike-sign candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);y_{pK};#varphi_{pK} " ,
1974+ " #Lambda^{*}(1520) pK unlike-sign candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);multiplicity/centrality " ,
19811975 HistType::kTHnSparseF ,
1982- {AxisSpec{400 , 1.3 , 1.9 , " M_{pK} (GeV/c^{2})" },
1983- AxisSpec{100 , 0 ., 10 ., " p_{T}^{pK} (GeV/c)" },
1984- AxisSpec{60 , -1.5 , 1.5 , " y_{pK}" },
1985- AxisSpec{64 , -3.2 , 3.2 , " #varphi_{pK}" }, centAxis});
1976+ {AxisSpec{400 , 1.4 , 1.8 , " M_{pK} (GeV/c^{2})" },
1977+ AxisSpec{100 , 0 ., 10 ., " p_{T}^{pK} (GeV/c)" }, centAxis});
19861978
19871979 histos.add (" hLambdaStarPKLikeSparse" ,
1988- " #Lambda^{*}(1520) pK like-sign candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);y_{pK};#varphi_{pK} " ,
1980+ " #Lambda^{*}(1520) pK like-sign candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);multiplicity/centrality " ,
19891981 HistType::kTHnSparseF ,
1990- {AxisSpec{400 , 1.3 , 1.9 , " M_{pK} (GeV/c^{2})" },
1991- AxisSpec{100 , 0 ., 10 ., " p_{T}^{pK} (GeV/c)" },
1992- AxisSpec{60 , -1.5 , 1.5 , " y_{pK}" },
1993- AxisSpec{64 , -3.2 , 3.2 , " #varphi_{pK}" }, centAxis});
1982+ {AxisSpec{400 , 1.4 , 1.8 , " M_{pK} (GeV/c^{2})" },
1983+ AxisSpec{100 , 0 ., 10 ., " p_{T}^{pK} (GeV/c)" }, centAxis});
19941984
19951985 histos.add (" hLambdaStarPKMixedSparse" ,
1996- " #Lambda^{*}(1520) pK mixed-event candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);y_{pK};#varphi_{pK} " ,
1986+ " #Lambda^{*}(1520) pK mixed-event candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);multiplicity/centrality " ,
19971987 HistType::kTHnSparseF ,
1998- {AxisSpec{400 , 1.3 , 1.9 , " M_{pK} (GeV/c^{2})" },
1999- AxisSpec{100 , 0 ., 10 ., " p_{T}^{pK} (GeV/c)" },
2000- AxisSpec{60 , -1.5 , 1.5 , " y_{pK}" },
2001- AxisSpec{64 , -3.2 , 3.2 , " #varphi_{pK}" }, centAxis});
1988+ {AxisSpec{400 , 1.4 , 1.8 , " M_{pK} (GeV/c^{2})" },
1989+ AxisSpec{100 , 0 ., 10 ., " p_{T}^{pK} (GeV/c)" }, centAxis});
20021990
2003- // THnSparse for deuteron-proxy invariant-mass analysis (mass, pT, y, phi )
1991+ // THnSparse for deuteron-proxy invariant-mass analysis (mass, pT, multiplicity/centrality )
20041992 histos.add (" hLambdaStarProxySparse" ,
2005- " #Lambda^{*}(1520) deuteron-proxy candidates;M_{p_{proxy}K} (GeV/c^{2});p_{T}^{p_{proxy}K} (GeV/c);y_{p_{proxy}K};#varphi_{p_{proxy}K}" ,
1993+ " #Lambda^{*}(1520) deuteron-proxy candidates;M_{p_{proxy}K} (GeV/c^{2});p_{T}^{p_{proxy}K} (GeV/c);multiplicity/centrality" ,
1994+ HistType::kTHnSparseF ,
1995+ {AxisSpec{400 , 1.4 , 1.8 , " M_{p_{proxy}K} (GeV/c^{2})" },
1996+ AxisSpec{100 , 0 ., 10 ., " p_{T}^{p_{proxy}K} (GeV/c)" }, centAxis});
1997+
1998+ histos.add (" hLambdaStarProxyLikeSparse" ,
1999+ " #Lambda^{*}(1520) deuteron-proxy like-sign candidates;M_{p_{proxy}K} (GeV/c^{2});p_{T}^{p_{proxy}K} (GeV/c);multiplicity/centrality" ,
20062000 HistType::kTHnSparseF ,
2007- {AxisSpec{400 , 1.3 , 1.9 , " M_{p_{proxy}K} (GeV/c^{2})" },
2008- AxisSpec{100 , 0 ., 10 ., " p_{T}^{p_{proxy}K} (GeV/c)" },
2009- AxisSpec{60 , -1.5 , 1.5 , " y_{p_{proxy}K}" },
2010- AxisSpec{64 , -3.2 , 3.2 , " #varphi_{p_{proxy}K}" }, centAxis});
2001+ {AxisSpec{400 , 1.4 , 1.8 , " M_{p_{proxy}K} (GeV/c^{2})" },
2002+ AxisSpec{100 , 0 ., 10 ., " p_{T}^{p_{proxy}K} (GeV/c)" }, centAxis});
20112003
20122004 histos.add (" hLambdaStarProxyMixedSparse" ,
2013- " #Lambda^{*}(1520) deuteron-proxy mixed-event candidates;M_{p_{proxy}K} (GeV/c^{2});p_{T}^{p_{proxy}K} (GeV/c);y_{p_{proxy}K};#varphi_{p_{proxy}K} " ,
2005+ " #Lambda^{*}(1520) deuteron-proxy mixed-event candidates;M_{p_{proxy}K} (GeV/c^{2});p_{T}^{p_{proxy}K} (GeV/c);multiplicity/centrality " ,
20142006 HistType::kTHnSparseF ,
2015- {AxisSpec{400 , 1.3 , 1.9 , " M_{p_{proxy}K} (GeV/c^{2})" },
2016- AxisSpec{100 , 0 ., 10 ., " p_{T}^{p_{proxy}K} (GeV/c)" },
2017- AxisSpec{60 , -1.5 , 1.5 , " y_{p_{proxy}K}" },
2018- AxisSpec{64 , -3.2 , 3.2 , " #varphi_{p_{proxy}K}" }, centAxis});
2007+ {AxisSpec{400 , 1.4 , 1.8 , " M_{p_{proxy}K} (GeV/c^{2})" },
2008+ AxisSpec{100 , 0 ., 10 ., " p_{T}^{p_{proxy}K} (GeV/c)" }, centAxis});
20192009 }
20202010
20212011 // Deuteron-proxy invariant mass (p_{proxy} from d/2 combined with K)
@@ -2317,15 +2307,9 @@ struct Lambdastarproxy {
23172307 static double invariantMass (float px1, float py1, float pz1, double m1,
23182308 float px2, float py2, float pz2, double m2)
23192309 {
2320- const double e1 = std::sqrt (m1 * m1 + px1 * px1 + py1 * py1 + pz1 * pz1);
2321- const double e2 = std::sqrt (m2 * m2 + px2 * px2 + py2 * py2 + pz2 * pz2);
2322- const double ex = px1 + px2;
2323- const double ey = py1 + py2;
2324- const double ez = pz1 + pz2;
2325- const double eTot = e1 + e2 ;
2326- const double p2Tot = ex * ex + ey * ey + ez * ez;
2327- const double m2Tot = eTot * eTot - p2Tot;
2328- return m2Tot > 0 . ? std::sqrt (m2Tot) : 0 .;
2310+ return RecoDecay::m (std::array{std::array{px1, py1, pz1},
2311+ std::array{px2, py2, pz2}},
2312+ std::array{m1, m2});
23292313 }
23302314
23312315 void process (FilteredCollisions::iterator const & collision, FilteredTracks const & tracks)
@@ -2635,12 +2619,15 @@ struct Lambdastarproxy {
26352619 kaonCands.push_back (KaonCand{pxK, pyK, pzK, static_cast <int >(trkK.sign ()), static_cast <int >(trkK.globalIndex ())});
26362620 }
26372621
2638- if (proxyCands.empty () || kaonCands.empty ()) {
2639- // still update mixing buffer so that later events can mix with this one
2622+ if (kaonCands.empty ()) {
2623+ // Still update mixing buffer so that later events can mix with this one.
2624+ // The pK mixed-event background needs stored protons, while the proxy background
2625+ // needs stored proxy candidates. Therefore, do not require proxy candidates here.
26402626 LStarMixEventEntry entry;
26412627 entry.mult = eventMult;
26422628 entry.zvtx = collision.posZ ();
26432629 entry.kaons = std::move (kaonCands);
2630+ entry.protons = std::move (protonCands);
26442631 entry.proxies = std::move (proxyCands);
26452632 mLStarMixEvents .push_front (std::move (entry));
26462633 if (mLStarMixEvents .size () > static_cast <size_t >(lstarNoMixedEvents.value )) {
@@ -2649,7 +2636,11 @@ struct Lambdastarproxy {
26492636 return ;
26502637 }
26512638
2639+ const bool hasProtonCandidates = !protonCands.empty ();
2640+ const bool hasProxyCandidates = !proxyCands.empty ();
2641+
26522642 // --- SAME-EVENT: genuine pK #Lambda^{*} candidates ---
2643+ if (hasProtonCandidates) {
26532644 for (auto const & pr : protonCands) {
26542645 for (auto const & k : kaonCands) {
26552646 if (pr.tid == k.tid ) {
@@ -2661,12 +2652,10 @@ struct Lambdastarproxy {
26612652 const float pxTot = pr.px + k.px ;
26622653 const float pyTot = pr.py + k.py ;
26632654 const float pzTot = pr.pz + k.pz ;
2664- const float ptPair = std::sqrt (pxTot * pxTot + pyTot * pyTot);
2655+ const float ptPair = ptFromPxPy (pxTot, pyTot);
26652656 const float phiPair = phiFromPxPy (pxTot, pyTot);
26662657
2667- const double eTot = std::sqrt (mass * mass + static_cast <double >(pxTot) * pxTot +
2668- static_cast <double >(pyTot) * pyTot + static_cast <double >(pzTot) * pzTot);
2669- const float yPair = rapidityFromEPz (eTot, pzTot);
2658+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
26702659
26712660 if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
26722661 continue ;
@@ -2675,21 +2664,21 @@ struct Lambdastarproxy {
26752664 const bool unlikeSignPK = (pr.charge * k.charge ) < 0 ;
26762665 if (unlikeSignPK) {
26772666 histos.fill (HIST (" hInvMassPKUnlike" ), mass);
2678- histos.fill (HIST (" hInvMassPKUnlikeVsPt" ), mass, ptPair);
26792667 if (lstarEnableSparse.value != 0 ) {
2680- histos.fill (HIST (" hLambdaStarPKUnlikeSparse" ), mass, ptPair, yPair, phiPair, eventMult);
2668+ histos.fill (HIST (" hLambdaStarPKUnlikeSparse" ), mass, ptPair, eventMult);
26812669 }
26822670 } else {
26832671 histos.fill (HIST (" hInvMassPKLike" ), mass);
2684- histos.fill (HIST (" hInvMassPKLikeVsPt" ), mass, ptPair);
26852672 if (lstarEnableSparse.value != 0 ) {
2686- histos.fill (HIST (" hLambdaStarPKLikeSparse" ), mass, ptPair, yPair, phiPair, eventMult);
2673+ histos.fill (HIST (" hLambdaStarPKLikeSparse" ), mass, ptPair, eventMult);
26872674 }
26882675 }
26892676 }
26902677 }
2678+ }
26912679
26922680 // --- SAME-EVENT: proxy (d/2) + K ---
2681+ if (hasProxyCandidates) {
26932682 for (auto const & pr : proxyCands) {
26942683 for (auto const & k : kaonCands) {
26952684 if (pr.tid == k.tid )
@@ -2699,53 +2688,101 @@ struct Lambdastarproxy {
26992688 const float pxTot = pr.px + k.px ;
27002689 const float pyTot = pr.py + k.py ;
27012690 const float pzTot = pr.pz + k.pz ;
2702- const float ptPair = std::sqrt (pxTot * pxTot + pyTot * pyTot);
2691+ const float ptPair = ptFromPxPy (pxTot, pyTot);
27032692 const float phiPair = phiFromPxPy (pxTot, pyTot);
27042693
2705- const double eTot = std::sqrt (mass * mass + static_cast <double >(pxTot) * pxTot + static_cast <double >(pyTot) * pyTot + static_cast <double >(pzTot) * pzTot);
2706- const float yPair = rapidityFromEPz (eTot, pzTot);
2694+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
27072695
27082696 // Inclusive invariant-mass spectrum for the #Lambda^{*} proxy (d/2 + K)
27092697 histos.fill (HIST (" hDeuteronProxyMass" ), mass);
27102698 if (lstarEnableSparse.value != 0 ) {
2711- histos.fill (HIST (" hLambdaStarProxySparse" ), mass, ptPair, yPair, phiPair, eventMult);
2699+ histos.fill (HIST (" hLambdaStarProxySparse" ), mass, ptPair, eventMult);
2700+
2701+ // Like-sign proxy background: proxy and kaon have the same charge sign.
2702+ // Here the proxy charge follows the original deuteron-candidate charge.
2703+ if ((pr.charge * k.charge ) > 0 ) {
2704+ histos.fill (HIST (" hLambdaStarProxyLikeSparse" ), mass, ptPair, eventMult);
2705+ }
27122706 }
27132707 }
27142708 }
2709+ }
27152710
2716- // --- MIXED-EVENT: current proxies + previous-event kaons ---
2711+ // --- MIXED-EVENT: current kaons + previous-event real protons ---
2712+ // This fills the standard pK mixed-event background.
27172713 for (auto const & prev : mLStarMixEvents ) {
2718- if (std::abs (prev.zvtx - collision.posZ ()) > lstarMixZvtxMax.value )
2714+ if (std::abs (prev.zvtx - collision.posZ ()) > lstarMixZvtxMax.value ) {
27192715 continue ;
2720- if (std::abs (prev.mult - eventMult) > lstarMixMultMax.value )
2716+ }
2717+ if (std::abs (prev.mult - eventMult) > lstarMixMultMax.value ) {
27212718 continue ;
2722- if (prev.kaons .empty ()) {
2719+ }
2720+ if (prev.protons .empty ()) {
27232721 continue ;
27242722 }
27252723
2726- for (auto const & pr : proxyCands ) {
2727- for (auto const & k : prev. kaons ) {
2728- // convention: mix for unlike -sign only (resonance background)
2724+ for (auto const & pr : prev. protons ) {
2725+ for (auto const & k : kaonCands ) {
2726+ // Unlike -sign pK mixed-event background.
27292727 if ((pr.charge * k.charge ) >= 0 ) {
27302728 continue ;
27312729 }
2732- if (pr.tid == k.tid )
2733- continue ; // sanity check: should never match, but just in case of bug in candidate-building logic
2734-
2735- const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton, k.px , k.py , k.pz , MassKaonCharged);
27362730
2731+ const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton,
2732+ k.px , k.py , k.pz , MassKaonCharged);
27372733 const float pxTot = pr.px + k.px ;
27382734 const float pyTot = pr.py + k.py ;
27392735 const float pzTot = pr.pz + k.pz ;
2740- const float ptPair = std::sqrt (pxTot * pxTot + pyTot * pyTot);
2741- const float phiPair = phiFromPxPy (pxTot, pyTot);
2736+ const float ptPair = ptFromPxPy (pxTot, pyTot);
27422737
2743- const double eTot = std::sqrt (mass * mass + static_cast <double >(pxTot) * pxTot + static_cast <double >(pyTot) * pyTot + static_cast <double >(pzTot) * pzTot);
2744- const float yPair = rapidityFromEPz (eTot, pzTot);
2738+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
2739+ if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
2740+ continue ;
2741+ }
27452742
2746- // Fill mixed-event THnSparse (proxy only)
27472743 if (lstarEnableSparse.value != 0 ) {
2748- histos.fill (HIST (" hLambdaStarProxyMixedSparse" ), mass, ptPair, yPair, phiPair, eventMult);
2744+ histos.fill (HIST (" hLambdaStarPKMixedSparse" ), mass, ptPair, eventMult);
2745+ }
2746+ }
2747+ }
2748+ }
2749+
2750+ // --- MIXED-EVENT: current proxies + previous-event kaons ---
2751+ // This fills the deuteron-proxy mixed-event background.
2752+ if (hasProxyCandidates) {
2753+ for (auto const & prev : mLStarMixEvents ) {
2754+ if (std::abs (prev.zvtx - collision.posZ ()) > lstarMixZvtxMax.value ) {
2755+ continue ;
2756+ }
2757+ if (std::abs (prev.mult - eventMult) > lstarMixMultMax.value ) {
2758+ continue ;
2759+ }
2760+ if (prev.kaons .empty ()) {
2761+ continue ;
2762+ }
2763+
2764+ for (auto const & pr : proxyCands) {
2765+ for (auto const & k : prev.kaons ) {
2766+ // Unlike-sign proxy-K mixed-event background.
2767+ if ((pr.charge * k.charge ) >= 0 ) {
2768+ continue ;
2769+ }
2770+
2771+ const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton,
2772+ k.px , k.py , k.pz , MassKaonCharged);
2773+ const float pxTot = pr.px + k.px ;
2774+ const float pyTot = pr.py + k.py ;
2775+ const float pzTot = pr.pz + k.pz ;
2776+ const float ptPair = ptFromPxPy (pxTot, pyTot);
2777+
2778+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
2779+ if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
2780+ continue ;
2781+ }
2782+
2783+ if (lstarEnableSparse.value != 0 ) {
2784+ histos.fill (HIST (" hLambdaStarProxyMixedSparse" ), mass, ptPair, eventMult);
2785+ }
27492786 }
27502787 }
27512788 }
@@ -2756,6 +2793,7 @@ struct Lambdastarproxy {
27562793 entry.mult = eventMult;
27572794 entry.zvtx = collision.posZ ();
27582795 entry.kaons = std::move (kaonCands);
2796+ entry.protons = std::move (protonCands);
27592797 entry.proxies = std::move (proxyCands);
27602798
27612799 mLStarMixEvents .push_front (std::move (entry));
0 commit comments