@@ -63,7 +63,8 @@ using ROOT::Math::PtEtaPhiMVector;
6363constexpr double protonMass = o2::constants::physics::MassProton; // Assumes particle identification for daughter is perfect
6464constexpr double lambdaWeakDecayConstant = 0.749 ; // DPG 2025 update
6565constexpr double antiLambdaWeakDecayConstant = -0.758 ; // DPG 2025 update
66-
66+ constexpr double polPrefactorLambda = 3.0 /lambdaWeakDecayConstant;
67+ constexpr double polPrefactorAntiLambda = 3.0 /antiLambdaWeakDecayConstant;
6768
6869// Helper macro to avoid writing the histogram fills 4 times for about 20 histograms:
6970#define RING_OBSERVABLE_FILL_LIST (X, FOLDER ) \
@@ -150,6 +151,25 @@ constexpr double antiLambdaWeakDecayConstant = -0.758; // DPG 2025 update
150151 X(FOLDER " /h3dRingObservableSquaredDeltaPhiVsMassVsLeadJetPt" , deltaPhiJet, v0LambdaLikeMass, leadingJetPt, ringObservableSquared) \
151152 X(FOLDER " /h3dRingObservableSquaredDeltaThetaVsMassVsLeadJetPt" , deltaThetaJet, v0LambdaLikeMass, leadingJetPt, ringObservableSquared)
152153
154+ #define POLARIZATION_PROFILE_FILL_LIST (X, FOLDER ) \
155+ /* =============================== */ \
156+ /* 1D TProfiles vs v0phi */ \
157+ /* =============================== */ \
158+ X (FOLDER " /pPxStarPhi" , v0phi, PolStarX) \
159+ X(FOLDER " /pPyStarPhi" , v0phi, PolStarY) \
160+ X(FOLDER " /pPzStarPhi" , v0phi, PolStarZ) \
161+ /* =============================== */ \
162+ /* 1D TProfiles vs DeltaPhi_jet */ \
163+ /* =============================== */ \
164+ X(FOLDER " /pPxStarDeltaPhi" , deltaPhiJet, PolStarX) \
165+ X(FOLDER " /pPyStarDeltaPhi" , deltaPhiJet, PolStarY) \
166+ X(FOLDER " /pPzStarDeltaPhi" , deltaPhiJet, PolStarZ) \
167+ /* =============================== */ \
168+ /* 2D TProfiles vs DeltaPhi_jet and Lambda pT */ \
169+ /* =============================== */ \
170+ X(FOLDER " /p2dPxStarDeltaPhiVsLambdaPt" , deltaPhiJet, v0pt, PolStarX) \
171+ X(FOLDER " /p2dPyStarDeltaPhiVsLambdaPt" , deltaPhiJet, v0pt, PolStarY) \
172+ X(FOLDER " /p2dPzStarDeltaPhiVsLambdaPt" , deltaPhiJet, v0pt, PolStarZ)
153173
154174// Apply the macros (notice I had to include the semicolon (";") after the function, so you don't need to
155175// write that when calling this APPLY_HISTO_FILL. The code will look weird, but without this the compiler
@@ -183,10 +203,12 @@ struct lambdajetpolarizationionsderived {
183203 ConfigurableAxis axisDeltaPhi{" axisDeltaPhi" , {100 , -constants::math::PI, constants::math::PI}, " #Delta #phi_{jet}" };
184204
185205 // Coarser axes for signal extraction:
186- ConfigurableAxis axisPtSigExtract{" axisPtSigExtract" , {VARIABLE_WIDTH, 0 .0f , 0 .15f , 0 .3f , 0 .45f , 0 . 6f , 0 . 75f , 0 . 9f , 1 . 05f , 1 .2f , 1 .35f , 1 . 5f , 1 . 65f , 1 . 8f , 1 . 95f , 2 . 1f , 2 .25f , 2 . 4f , 2 . 6f , 2 . 8f , 3 .0f , 3 . 2f , 3 . 4f , 3 . 6f , 3 . 8f , 4 .0f , 4 . 4f , 4 . 8f , 5 . 2f , 5 . 6f , 6 .0f , 6 . 5f , 7 . 0f , 7 . 5f , 8 .0f , 9 . 0f , 10 .0f , 11 . 0f , 12 . 0f , 13 . 0f , 14 . 0f , 15 .0f , 17 .0f , 19 . 0f , 21 . 0f , 23 . 0f , 25 . 0f , 30 . 0f , 35 . 0f , 40 .0f , 50 .0f }, " pt axis for signal extraction" };
206+ ConfigurableAxis axisPtSigExtract{" axisPtSigExtract" , {VARIABLE_WIDTH, 0 .0f , 0 .25f , 0 .5f , 0 .75f , 1 . 0f , 1 .25f , 1 .5f , 2 . 0f , 2 .5f , 3 .0f , 4 .0f , 6 .0f , 8 .0f , 10 .0f , 15 .0f , 20 .0f , 30 .0f , 50 .0f }, " pt axis for signal extraction" };
187207 ConfigurableAxis axisLambdaMassSigExtract{" axisLambdaMassSigExtract" , {175 , 1 .08f , 1 .15f }, " Lambda mass in GeV/c" }; // With a sigma of 0.002 GeV/c, this has about 5 bins per sigma, so that the window is properly grasped.
188208 ConfigurableAxis axisLeadingParticlePtSigExtract{" axisLeadingParticlePtSigExtract" , {VARIABLE_WIDTH, 0 , 4 , 8 , 12 , 16 , 20 , 25 , 30 , 35 , 40 , 60 , 100 , 200 }, " Leading particle p_{T} (GeV/c)" }; // Simpler version!
189- ConfigurableAxis axisJetPtSigExtract{" axisJetPtSigExtract" , {VARIABLE_WIDTH, 0 , 4 , 8 , 12 , 16 , 20 , 25 , 30 , 35 , 40 , 60 , 100 , 200 }," Jet p_{t} (GeV)" };
209+ ConfigurableAxis axisJetPtSigExtract{" axisJetPtSigExtract" , {VARIABLE_WIDTH, 0 , 5 , 10 , 12 , 16 , 20 , 25 , 30 , 35 , 40 , 60 , 100 , 200 }," Jet p_{t} (GeV)" };
210+
211+ // (TODO: add a lambdaPt axis that is pre-selected only on the 0.5 to 1.5 Pt region)
190212 } axisConfigurations;
191213
192214
@@ -311,6 +333,27 @@ struct lambdajetpolarizationionsderived {
311333 // --- Counters ---
312334 histos.add ((folder + " /h3dDeltaPhiVsMassVsLeadJetPt" ).c_str (), " h3dDeltaPhiVsMassVsLeadJetPt" , kTH3D , {axisConfigurations.axisDeltaPhi , axisConfigurations.axisLambdaMassSigExtract , axisConfigurations.axisJetPtSigExtract });
313335 histos.add ((folder + " /h3dDeltaThetaVsMassVsLeadJetPt" ).c_str (), " h3dDeltaThetaVsMassVsLeadJetPt" , kTH3D , {axisConfigurations.axisCosTheta , axisConfigurations.axisLambdaMassSigExtract , axisConfigurations.axisJetPtSigExtract });
336+
337+ // ===============================
338+ // Polarization observable QAs
339+ // (not Ring: actual polarization!)
340+ // ===============================
341+ // Will implement these as TProfiles, as polarization is also a measure like P_\Lambda = (3/\alpha_\Lambda) * <p_{proton}>, so the error is similar
342+ // ===============================
343+ // 1D TProfiles
344+ // ===============================
345+ histos.add ((folder + " /pPxStarPhi" ).c_str (), " pPxStarPhi;#varphi_#Lambda;<P_#Lambda>_x" , kTProfile , {axisConfigurations.axisDeltaPhi });
346+ histos.add ((folder + " /pPyStarPhi" ).c_str (), " pPyStarPhi;#varphi_#Lambda;<P_#Lambda>_y" , kTProfile , {axisConfigurations.axisDeltaPhi });
347+ histos.add ((folder + " /pPzStarPhi" ).c_str (), " pPzStarPhi;#varphi_#Lambda;<P_#Lambda>_z" , kTProfile , {axisConfigurations.axisDeltaPhi });
348+ histos.add ((folder + " /pPxStarDeltaPhi" ).c_str (), " pPxStarDeltaPhi;#Delta#varphi_{jet};<P_#Lambda>_x" , kTProfile , {axisConfigurations.axisDeltaPhi });
349+ histos.add ((folder + " /pPyStarDeltaPhi" ).c_str (), " pPyStarDeltaPhi;#Delta#varphi_{jet};<P_#Lambda>_y" , kTProfile , {axisConfigurations.axisDeltaPhi });
350+ histos.add ((folder + " /pPzStarDeltaPhi" ).c_str (), " pPzStarDeltaPhi;#Delta#varphi_{jet};<P_#Lambda>_z" , kTProfile , {axisConfigurations.axisDeltaPhi });
351+ // ===============================
352+ // 2D TProfiles (Lambda correlations)
353+ // ===============================
354+ histos.add ((folder + " /p2dPxStarDeltaPhiVsLambdaPt" ).c_str (), " p2dPxStarDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};<P_#Lambda>_x" , kTProfile2D , {axisConfigurations.axisDeltaPhi , axisConfigurations.axisPtSigExtract });
355+ histos.add ((folder + " /p2dPyStarDeltaPhiVsLambdaPt" ).c_str (), " p2dPyStarDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};<P_#Lambda>_y" , kTProfile2D , {axisConfigurations.axisDeltaPhi , axisConfigurations.axisPtSigExtract });
356+ histos.add ((folder + " /p2dPzStarDeltaPhiVsLambdaPt" ).c_str (), " p2dPzStarDeltaPhiVsLambdaPt;#Delta#varphi_{jet};#it{p}_{T}^{#Lambda};<P_#Lambda>_z" , kTProfile2D , {axisConfigurations.axisDeltaPhi , axisConfigurations.axisPtSigExtract });
314357 };
315358 // Execute local lambda to register histogram families:
316359 addRingObservableFamily (" Ring" );
@@ -414,7 +457,7 @@ struct lambdajetpolarizationionsderived {
414457
415458 double ringObservable = protonLikeStarUnit3Vec.Dot (cross) / crossProductNorm;
416459 // Adding the prefactor related to the CP-violating decay (decay constants have different signs)
417- ringObservable *= (isLambda) ? 3 ./lambdaWeakDecayConstant : 3 ./antiLambdaWeakDecayConstant ;
460+ ringObservable *= (isLambda) ? polPrefactorLambda : polPrefactorAntiLambda ;
418461
419462 // Calculating error bars:
420463 double ringObservableSquared = ringObservable*ringObservable;
@@ -423,28 +466,46 @@ struct lambdajetpolarizationionsderived {
423466 double deltaPhiJet = wrapToPiFast (v0phi - leadingJetPhi); // Wrapped to [-PI, pi), for convenience
424467 double deltaThetaJet = ROOT::Math::VectorUtil::Angle (leadingJetUnitVec, lambdaLike3Vec); // 3D angular separation
425468
469+ // Calculating polarization observables (in the Lambda frame, because that is easier -- does not require boosts):
470+ // To be precise, not actually the polarization, but a part of the summand in P^*_\Lambda = (3/\alpha_\Lambda) * <p^*_{proton}>
471+ double PolStarX, PolStarY, PolStarZ;
472+ if (isLambda){ // Notice there is no need to check analyseLambda again due to previous checks.
473+ PolStarX = polPrefactorLambda * protonLikeStarUnit3Vec.X ();
474+ PolStarY = polPrefactorLambda * protonLikeStarUnit3Vec.Y ();
475+ PolStarZ = polPrefactorLambda * protonLikeStarUnit3Vec.Z ();
476+ }
477+ else if (isAntiLambda){
478+ PolStarX = polPrefactorAntiLambda * protonLikeStarUnit3Vec.X ();
479+ PolStarY = polPrefactorAntiLambda * protonLikeStarUnit3Vec.Y ();
480+ PolStarZ = polPrefactorAntiLambda * protonLikeStarUnit3Vec.Z ();
481+ }
482+
426483 // Fill ring histograms: (1D, lambda 2D correlations and jet 2D correlations):
427484 RING_OBSERVABLE_FILL_LIST (APPLY_HISTO_FILL, " Ring" ) // Notice the usage of macros! If you change the variable names, this WILL break the code!
428485 RING_OBSERVABLE_SQUARED_FILL_LIST (APPLY_HISTO_FILL, " Ring" ) // No, there should NOT be any ";" here! Read the macro definition for an explanation
486+ POLARIZATION_PROFILE_FILL_LIST (APPLY_HISTO_FILL, " Ring" )
429487
430488 // Extra kinematic criteria for Lambda candidates (removes polarization background):
431489 const bool kinematicLambdaCheck = (v0pt > 0.5 && v0pt < 1.5 ) && std::abs (lambdaRapidity) < 0.5 ;
432490 if (kinematicLambdaCheck){
433491 RING_OBSERVABLE_FILL_LIST (APPLY_HISTO_FILL, " RingKinematicCuts" )
434492 RING_OBSERVABLE_SQUARED_FILL_LIST (APPLY_HISTO_FILL, " RingKinematicCuts" )
493+ POLARIZATION_PROFILE_FILL_LIST (APPLY_HISTO_FILL, " RingKinematicCuts" )
435494 }
436495
437496 // Extra selection criteria on jet candidates:
438497 const bool kinematicJetCheck = std::abs (leadingJetEta) < 0.5 ;
439498 if (kinematicJetCheck){ // This is redundant for jets with R=0.4, but for jets with R<0.4 the leading jet may be farther in eta.
440499 RING_OBSERVABLE_FILL_LIST (APPLY_HISTO_FILL, " JetKinematicCuts" )
441500 RING_OBSERVABLE_SQUARED_FILL_LIST (APPLY_HISTO_FILL, " JetKinematicCuts" )
501+ POLARIZATION_PROFILE_FILL_LIST (APPLY_HISTO_FILL, " JetKinematicCuts" )
442502 }
443503
444504 // Extra selection criteria on both Lambda and jet candidates:
445505 if (kinematicLambdaCheck && kinematicJetCheck){
446506 RING_OBSERVABLE_FILL_LIST (APPLY_HISTO_FILL, " JetAndLambdaKinematicCuts" )
447507 RING_OBSERVABLE_SQUARED_FILL_LIST (APPLY_HISTO_FILL, " JetAndLambdaKinematicCuts" )
508+ POLARIZATION_PROFILE_FILL_LIST (APPLY_HISTO_FILL, " JetAndLambdaKinematicCuts" )
448509 }
449510 } // end v0s loop
450511 } // end collisions
0 commit comments