@@ -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,103 +2636,148 @@ 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 ---
2653- for (auto const & pr : protonCands) {
2654- for (auto const & k : kaonCands) {
2655- if (pr.tid == k.tid ) {
2656- continue ;
2657- }
2658- const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton,
2659- k.px , k.py , k.pz , MassKaonCharged);
2643+ if (hasProtonCandidates) {
2644+ for (auto const & pr : protonCands) {
2645+ for (auto const & k : kaonCands) {
2646+ if (pr.tid == k.tid ) {
2647+ continue ;
2648+ }
2649+ const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton,
2650+ k.px , k.py , k.pz , MassKaonCharged);
26602651
2661- const float pxTot = pr.px + k.px ;
2662- const float pyTot = pr.py + k.py ;
2663- const float pzTot = pr.pz + k.pz ;
2664- const float ptPair = std::sqrt (pxTot * pxTot + pyTot * pyTot);
2665- const float phiPair = phiFromPxPy (pxTot, pyTot);
2652+ const float pxTot = pr.px + k.px ;
2653+ const float pyTot = pr.py + k.py ;
2654+ const float pzTot = pr.pz + k.pz ;
2655+ const float ptPair = ptFromPxPy (pxTot, pyTot);
26662656
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);
2657+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
26702658
2671- if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
2672- continue ;
2673- }
2674-
2675- const bool unlikeSignPK = (pr.charge * k.charge ) < 0 ;
2676- if (unlikeSignPK) {
2677- histos.fill (HIST (" hInvMassPKUnlike" ), mass);
2678- histos.fill (HIST (" hInvMassPKUnlikeVsPt" ), mass, ptPair);
2679- if (lstarEnableSparse.value != 0 ) {
2680- histos.fill (HIST (" hLambdaStarPKUnlikeSparse" ), mass, ptPair, yPair, phiPair, eventMult);
2659+ if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
2660+ continue ;
26812661 }
2682- } else {
2683- histos.fill (HIST (" hInvMassPKLike" ), mass);
2684- histos.fill (HIST (" hInvMassPKLikeVsPt" ), mass, ptPair);
2685- if (lstarEnableSparse.value != 0 ) {
2686- histos.fill (HIST (" hLambdaStarPKLikeSparse" ), mass, ptPair, yPair, phiPair, eventMult);
2662+
2663+ const bool unlikeSignPK = (pr.charge * k.charge ) < 0 ;
2664+ if (unlikeSignPK) {
2665+ histos.fill (HIST (" hInvMassPKUnlike" ), mass);
2666+ if (lstarEnableSparse.value != 0 ) {
2667+ histos.fill (HIST (" hLambdaStarPKUnlikeSparse" ), mass, ptPair, eventMult);
2668+ }
2669+ } else {
2670+ histos.fill (HIST (" hInvMassPKLike" ), mass);
2671+ if (lstarEnableSparse.value != 0 ) {
2672+ histos.fill (HIST (" hLambdaStarPKLikeSparse" ), mass, ptPair, eventMult);
2673+ }
26872674 }
26882675 }
26892676 }
26902677 }
26912678
26922679 // --- SAME-EVENT: proxy (d/2) + K ---
2693- for (auto const & pr : proxyCands) {
2694- for (auto const & k : kaonCands) {
2695- if (pr.tid == k.tid )
2696- continue ; // sanity check: should never match, but just in case of bug in candidate-building logic
2697- const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton, k.px , k.py , k.pz , MassKaonCharged);
2698-
2699- const float pxTot = pr.px + k.px ;
2700- const float pyTot = pr.py + k.py ;
2701- const float pzTot = pr.pz + k.pz ;
2702- const float ptPair = std::sqrt (pxTot * pxTot + pyTot * pyTot);
2703- const float phiPair = phiFromPxPy (pxTot, pyTot);
2704-
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);
2707-
2708- // Inclusive invariant-mass spectrum for the #Lambda^{*} proxy (d/2 + K)
2709- histos.fill (HIST (" hDeuteronProxyMass" ), mass);
2710- if (lstarEnableSparse.value != 0 ) {
2711- histos.fill (HIST (" hLambdaStarProxySparse" ), mass, ptPair, yPair, phiPair, eventMult);
2680+ if (hasProxyCandidates) {
2681+ for (auto const & pr : proxyCands) {
2682+ for (auto const & k : kaonCands) {
2683+ if (pr.tid == k.tid )
2684+ continue ; // sanity check: should never match, but just in case of bug in candidate-building logic
2685+ const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton, k.px , k.py , k.pz , MassKaonCharged);
2686+
2687+ const float pxTot = pr.px + k.px ;
2688+ const float pyTot = pr.py + k.py ;
2689+ const float ptPair = ptFromPxPy (pxTot, pyTot);
2690+
2691+ // Inclusive invariant-mass spectrum for the #Lambda^{*} proxy (d/2 + K)
2692+ histos.fill (HIST (" hDeuteronProxyMass" ), mass);
2693+ if (lstarEnableSparse.value != 0 ) {
2694+ histos.fill (HIST (" hLambdaStarProxySparse" ), mass, ptPair, eventMult);
2695+
2696+ // Like-sign proxy background: proxy and kaon have the same charge sign.
2697+ // Here the proxy charge follows the original deuteron-candidate charge.
2698+ if ((pr.charge * k.charge ) > 0 ) {
2699+ histos.fill (HIST (" hLambdaStarProxyLikeSparse" ), mass, ptPair, eventMult);
2700+ }
2701+ }
27122702 }
27132703 }
27142704 }
27152705
2716- // --- MIXED-EVENT: current proxies + previous-event kaons ---
2706+ // --- MIXED-EVENT: current kaons + previous-event real protons ---
2707+ // This fills the standard pK mixed-event background.
27172708 for (auto const & prev : mLStarMixEvents ) {
2718- if (std::abs (prev.zvtx - collision.posZ ()) > lstarMixZvtxMax.value )
2709+ if (std::abs (prev.zvtx - collision.posZ ()) > lstarMixZvtxMax.value ) {
27192710 continue ;
2720- if (std::abs (prev.mult - eventMult) > lstarMixMultMax.value )
2711+ }
2712+ if (std::abs (prev.mult - eventMult) > lstarMixMultMax.value ) {
27212713 continue ;
2722- if (prev.kaons .empty ()) {
2714+ }
2715+ if (prev.protons .empty ()) {
27232716 continue ;
27242717 }
27252718
2726- for (auto const & pr : proxyCands ) {
2727- for (auto const & k : prev. kaons ) {
2728- // convention: mix for unlike -sign only (resonance background)
2719+ for (auto const & pr : prev. protons ) {
2720+ for (auto const & k : kaonCands ) {
2721+ // Unlike -sign pK mixed-event background.
27292722 if ((pr.charge * k.charge ) >= 0 ) {
27302723 continue ;
27312724 }
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);
27362725
2726+ const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton,
2727+ k.px , k.py , k.pz , MassKaonCharged);
27372728 const float pxTot = pr.px + k.px ;
27382729 const float pyTot = pr.py + k.py ;
27392730 const float pzTot = pr.pz + k.pz ;
2740- const float ptPair = std::sqrt (pxTot * pxTot + pyTot * pyTot);
2741- const float phiPair = phiFromPxPy (pxTot, pyTot);
2731+ const float ptPair = ptFromPxPy (pxTot, pyTot);
27422732
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);
2733+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
2734+ if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
2735+ continue ;
2736+ }
27452737
2746- // Fill mixed-event THnSparse (proxy only)
27472738 if (lstarEnableSparse.value != 0 ) {
2748- histos.fill (HIST (" hLambdaStarProxyMixedSparse" ), mass, ptPair, yPair, phiPair, eventMult);
2739+ histos.fill (HIST (" hLambdaStarPKMixedSparse" ), mass, ptPair, eventMult);
2740+ }
2741+ }
2742+ }
2743+ }
2744+
2745+ // --- MIXED-EVENT: current proxies + previous-event kaons ---
2746+ // This fills the deuteron-proxy mixed-event background.
2747+ if (hasProxyCandidates) {
2748+ for (auto const & prev : mLStarMixEvents ) {
2749+ if (std::abs (prev.zvtx - collision.posZ ()) > lstarMixZvtxMax.value ) {
2750+ continue ;
2751+ }
2752+ if (std::abs (prev.mult - eventMult) > lstarMixMultMax.value ) {
2753+ continue ;
2754+ }
2755+ if (prev.kaons .empty ()) {
2756+ continue ;
2757+ }
2758+
2759+ for (auto const & pr : proxyCands) {
2760+ for (auto const & k : prev.kaons ) {
2761+ // Unlike-sign proxy-K mixed-event background.
2762+ if ((pr.charge * k.charge ) >= 0 ) {
2763+ continue ;
2764+ }
2765+
2766+ const double mass = invariantMass (pr.px , pr.py , pr.pz , MassProton,
2767+ k.px , k.py , k.pz , MassKaonCharged);
2768+ const float pxTot = pr.px + k.px ;
2769+ const float pyTot = pr.py + k.py ;
2770+ const float pzTot = pr.pz + k.pz ;
2771+ const float ptPair = ptFromPxPy (pxTot, pyTot);
2772+
2773+ const float yPair = rapidityFromMomentumAndMass (pxTot, pyTot, pzTot, mass);
2774+ if (std::abs (yPair) > lstarLambdaAbsYMax.value ) {
2775+ continue ;
2776+ }
2777+
2778+ if (lstarEnableSparse.value != 0 ) {
2779+ histos.fill (HIST (" hLambdaStarProxyMixedSparse" ), mass, ptPair, eventMult);
2780+ }
27492781 }
27502782 }
27512783 }
@@ -2756,6 +2788,7 @@ struct Lambdastarproxy {
27562788 entry.mult = eventMult;
27572789 entry.zvtx = collision.posZ ();
27582790 entry.kaons = std::move (kaonCands);
2791+ entry.protons = std::move (protonCands);
27592792 entry.proxies = std::move (proxyCands);
27602793
27612794 mLStarMixEvents .push_front (std::move (entry));
0 commit comments