@@ -269,21 +269,24 @@ struct Lambda1520pbpb {
269269 histos.add (" QAafter/Kaon/h2d_Kapr_nsigma_tof_p" , " Kaons proton" , kTH2F , {axisPpid, axisTOFNsigma});
270270 histos.add (" QAafter/Kaon/h2d_ka_nsigma_tof_vs_tpc" , " n#sigma(TOF) vs n#sigma(TPC) Kaons" , kTH2F , {axisTPCNsigma, axisTOFNsigma});
271271
272- // Analysis
273- if (!doprocessMC) {
274- int nActiveFrames = static_cast <int >(cActivateHelicityFrame) +
275- static_cast <int >(cActivateCollinsSoperFrame) +
276- static_cast <int >(cActivateProductionFrame) +
277- static_cast <int >(cActivateBeamAxisFrame) +
278- static_cast <int >(cActivateRandomFrame);
279-
280- bool polActive = nActiveFrames > 0 ;
272+ // ── Polarization-frame activation (shared by data and MC booking) ───────
273+ int nActiveFrames = static_cast <int >(cActivateHelicityFrame) +
274+ static_cast <int >(cActivateCollinsSoperFrame) +
275+ static_cast <int >(cActivateProductionFrame) +
276+ static_cast <int >(cActivateBeamAxisFrame) +
277+ static_cast <int >(cActivateRandomFrame);
278+
279+ bool polActive = nActiveFrames > 0 ;
280+
281+ if (nActiveFrames > 1 ) {
282+ LOG (fatal) << " Multiple polarization frames activated, but axisPolFrame was removed! "
283+ << " Please activate only ONE frame at a time to prevent data mixing in the 4D sparse." ;
284+ }
281285
282- if (nActiveFrames > 1 ) {
283- LOG (fatal) << " Multiple polarization frames activated, but axisPolFrame was removed! "
284- << " Please activate only ONE frame at a time to prevent data mixing in the 4D sparse." ;
285- }
286+ const AxisSpec axisCosTheta{cCosThetaBins, " cos#theta*" };
286287
288+ // Analysis
289+ if (!doprocessMC) {
287290 if (!polActive) {
288291 histos.add (" Analysis/h4d_lstar_invm_US_PM" , " THn #Lambda(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisOccupancy});
289292 histos.add (" Analysis/h4d_lstar_invm_US_MP" , " THn #bar #Lambda(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisOccupancy});
@@ -305,8 +308,6 @@ struct Lambda1520pbpb {
305308
306309 // ── 4D Polarization / cosThetaStar histograms ──────────────────────────
307310 if (polActive) {
308- const AxisSpec axisCosTheta{cCosThetaBins, " cos#theta*" };
309-
310311 histos.add (" Analysis/h4d_pol_US_PM" , " cos#theta* #Lambda(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
311312 histos.add (" Analysis/h4d_pol_US_MP" , " cos#theta* #bar{#Lambda}(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
312313 histos.add (" Analysis/h4d_pol_LS_PP" , " cos#theta* Like Signs p K^{+}" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
@@ -340,6 +341,20 @@ struct Lambda1520pbpb {
340341 histos.add (" Analysis/h3d_rec_lstar_MP" , " Reconstructed #bar{#Lambda}(1520) p_{T}" , kTHnSparseF , {axisInvM, axisPt, axisCent});
341342 histos.add (" Analysis/h3d_reso_lstar_PM" , " Resolution #Lambda(1520) p_{T}" , kTHnSparseF , {{200 , -0.05 , 0.05 }, axisPt, axisCent});
342343 histos.add (" Analysis/h3d_reso_lstar_MP" , " Resolution #bar{#Lambda}(1520) p_{T}" , kTHnSparseF , {{200 , -0.05 , 0.05 }, axisPt, axisCent});
344+
345+ if (polActive) {
346+ const AxisSpec axisMassRes{200 , -0.05 , 0.05 , " M_{rec} - M_{gen} (GeV/#it{c}^{2})" };
347+
348+ histos.add (" Analysis/h4d_pol_rec_PM" , " cos#theta* Reconstructed (truth-matched) #Lambda(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
349+ histos.add (" Analysis/h4d_pol_rec_MP" , " cos#theta* Reconstructed (truth-matched) #bar{#Lambda}(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
350+ histos.add (" Analysis/h4d_pol_reso_PM" , " cos#theta* vs mass resolution #Lambda(1520)" , kTHnSparseF , {axisMassRes, axisPt, axisCent, axisCosTheta});
351+ histos.add (" Analysis/h4d_pol_reso_MP" , " cos#theta* vs mass resolution #bar{#Lambda}(1520)" , kTHnSparseF , {axisMassRes, axisPt, axisCent, axisCosTheta});
352+ }
353+ }
354+
355+ if (doprocessMCGenPol && polActive) {
356+ histos.add (" Analysis/h4d_pol_gen_PM" , " cos#theta* Generated (truth) #Lambda(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
357+ histos.add (" Analysis/h4d_pol_gen_MP" , " cos#theta* Generated (truth) #bar{#Lambda}(1520)" , kTHnSparseF , {axisInvM, axisPt, axisCent, axisCosTheta});
343358 }
344359
345360 if (doprocessMCGen) {
@@ -591,7 +606,10 @@ struct Lambda1520pbpb {
591606 Rotated,
592607 Mixed,
593608 LikeSign,
594- LikeSignMixed };
609+ LikeSignMixed,
610+ McTrue,
611+ McTrueRes,
612+ GenTrue };
595613
596614 template <PolBkgMode Mode>
597615 void fillPolarization (float candMass, float candPt,
@@ -629,6 +647,21 @@ struct Lambda1520pbpb {
629647 histos.fill (HIST (" Analysis/h4d_pol_LS_PP_mix" ), candMass, candPt, mult, cosTheta);
630648 else
631649 histos.fill (HIST (" Analysis/h4d_pol_LS_MM_mix" ), candMass, candPt, mult, cosTheta);
650+ } else if constexpr (Mode == PolBkgMode::McTrue) {
651+ if (protonIsPositive)
652+ histos.fill (HIST (" Analysis/h4d_pol_rec_PM" ), candMass, candPt, mult, cosTheta);
653+ else
654+ histos.fill (HIST (" Analysis/h4d_pol_rec_MP" ), candMass, candPt, mult, cosTheta);
655+ } else if constexpr (Mode == PolBkgMode::McTrueRes) {
656+ if (protonIsPositive)
657+ histos.fill (HIST (" Analysis/h4d_pol_reso_PM" ), candMass, candPt, mult, cosTheta);
658+ else
659+ histos.fill (HIST (" Analysis/h4d_pol_reso_MP" ), candMass, candPt, mult, cosTheta);
660+ } else if constexpr (Mode == PolBkgMode::GenTrue) {
661+ if (protonIsPositive)
662+ histos.fill (HIST (" Analysis/h4d_pol_gen_PM" ), candMass, candPt, mult, cosTheta);
663+ else
664+ histos.fill (HIST (" Analysis/h4d_pol_gen_MP" ), candMass, candPt, mult, cosTheta);
632665 } else {
633666 if (protonIsPositive)
634667 histos.fill (HIST (" Analysis/h4d_pol_US_PM" ), candMass, candPt, mult, cosTheta);
@@ -975,6 +1008,17 @@ struct Lambda1520pbpb {
9751008 histos.fill (HIST (" Analysis/h3d_rec_lstar_MP" ), candMass, candPt, mult);
9761009 histos.fill (HIST (" Analysis/h3d_reso_lstar_MP" ), candMassRes, candPt, mult);
9771010 }
1011+
1012+ if (polActive) {
1013+ float eProton = std::sqrt (pxPr * pxPr + pyPr * pyPr + pzPr * pzPr + MassProton * MassProton);
1014+ float eKaon = std::sqrt (pxKa * pxKa + pyKa * pyKa + pzKa * pzKa + MassKaonCharged * MassKaonCharged);
1015+ std::array<float , 3 > protonP = {pxPr, pyPr, pzPr};
1016+ std::array<float , 3 > kaonP = {pxKa, pyKa, pzKa};
1017+ std::array<float , 3 > motherP = {pxPr + pxKa, pyPr + pyKa, pzPr + pzKa};
1018+ float motherE = eProton + eKaon;
1019+ fillPolarization<PolBkgMode::McTrue>(candMass, candPt, motherP, motherE, protonP, eProton, kaonP, eKaon, mult, trkPr.motherPDG () > 0 );
1020+ fillPolarization<PolBkgMode::McTrueRes>(candMassRes, candPt, motherP, motherE, protonP, eProton, kaonP, eKaon, mult, trkPr.motherPDG () > 0 );
1021+ }
9781022 }
9791023 }
9801024 }
@@ -1073,6 +1117,56 @@ struct Lambda1520pbpb {
10731117 }
10741118 PROCESS_SWITCH (Lambda1520pbpb, processMC, " Process Event for MC" , false );
10751119
1120+ void processMCGenPol (ResoMCCols::iterator const & collision, aod::ResoMCParents const & resoParents, aod::McParticles const & mcParticles)
1121+ {
1122+ auto mult = collision.cent ();
1123+ bool polActive = static_cast <bool >(cActivateHelicityFrame) ||
1124+ static_cast <bool >(cActivateCollinsSoperFrame) ||
1125+ static_cast <bool >(cActivateProductionFrame) ||
1126+ static_cast <bool >(cActivateBeamAxisFrame) ||
1127+ static_cast <bool >(cActivateRandomFrame);
1128+ if (!polActive)
1129+ return ;
1130+
1131+ for (auto const & part : resoParents) {
1132+ if (std::abs (part.pdgCode ()) != lambda1520id)
1133+ continue ;
1134+ float yshift = std::abs (part.y ()) - cfgRapidityShift;
1135+ if (std::abs (yshift) > cfgRapidityCut)
1136+ continue ;
1137+
1138+ bool pass1 = std::abs (part.daughterPDG1 ()) == kProton || std::abs (part.daughterPDG2 ()) == kProton ;
1139+ bool pass2 = std::abs (part.daughterPDG1 ()) == kKPlus || std::abs (part.daughterPDG2 ()) == kKPlus ;
1140+ if (!pass1 || !pass2)
1141+ continue ;
1142+
1143+ std::array<float , 3 > pvec = {part.px (), part.py (), part.pz ()};
1144+ float mass = RecoDecay::m (pvec, part.e ());
1145+
1146+ auto motherMc = mcParticles.iteratorAt (part.mcParticleId ());
1147+ bool foundProton = false , foundKaon = false ;
1148+ std::array<float , 3 > protonP{}, kaonP{};
1149+ float protonE = 0 .f , kaonE = 0 .f ;
1150+ for (auto const & dau : motherMc.daughters_as <aod::McParticles>()) {
1151+ if (!foundProton && std::abs (dau.pdgCode ()) == kProton ) {
1152+ protonP = {dau.px (), dau.py (), dau.pz ()};
1153+ protonE = dau.e ();
1154+ foundProton = true ;
1155+ } else if (!foundKaon && std::abs (dau.pdgCode ()) == kKPlus ) {
1156+ kaonP = {dau.px (), dau.py (), dau.pz ()};
1157+ kaonE = dau.e ();
1158+ foundKaon = true ;
1159+ }
1160+ }
1161+ if (!foundProton || !foundKaon)
1162+ continue ;
1163+
1164+ std::array<float , 3 > motherP = {part.px (), part.py (), part.pz ()};
1165+ fillPolarization<PolBkgMode::GenTrue>(mass, part.pt (), motherP, part.e (), protonP, protonE, kaonP, kaonE, mult, part.pdgCode () > 0 );
1166+ }
1167+ }
1168+ PROCESS_SWITCH (Lambda1520pbpb, processMCGenPol, " Standalone generator-level polarization pass (run separately from processMC)" , false );
1169+
10761170 void processMCGen (ResoMCCols::iterator const & collision, aod::ResoMCParents const & resoParents)
10771171 {
10781172 float centrality = collision.cent ();
0 commit comments