Skip to content

Commit 27a41da

Browse files
authored
[PWGLF] Fix spin correlation definition (#13106)
1 parent 6dd5396 commit 27a41da

File tree

1 file changed

+97
-3
lines changed

1 file changed

+97
-3
lines changed

PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include <fairlogger/Logger.h>
3737

38+
#include <algorithm>
3839
#include <cmath> // for std::fabs
3940
#include <deque>
4041
#include <iostream>
@@ -96,6 +97,7 @@ struct lambdaspincorrderived {
9697
Configurable<float> v0eta{"v0eta", 0.8, "Eta cut on lambda"};
9798

9899
// Event Mixing
100+
Configurable<int> cosDef{"cosDef", 1, "Defination of cos"};
99101
Configurable<int> nEvtMixing{"nEvtMixing", 10, "Number of events to mix"};
100102
ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"};
101103
ConfigurableAxis CfgMultBins{"CfgMultBins", {8, 0.0, 80}, "Mixing bins - centrality"};
@@ -271,10 +273,102 @@ struct lambdaspincorrderived {
271273
auto proton1LambdaRF = boostLambda1ToCM(proton1pairCM);
272274
auto proton2LambdaRF = boostLambda2ToCM(proton2pairCM);
273275

274-
auto cosThetaDiff = -999.0;
275-
cosThetaDiff = proton1LambdaRF.Vect().Unit().Dot(proton2LambdaRF.Vect().Unit());
276+
TVector3 zhat(lambda1CM.Px(), lambda1CM.Py(), lambda1CM.Pz());
277+
if (zhat.Mag2() == 0)
278+
zhat = TVector3(0, 0, 1);
279+
zhat = zhat.Unit();
280+
281+
// pick a reference not collinear with ẑ (beam z works)
282+
TVector3 ref(0., 0., 1.);
283+
if (std::abs(zhat.Dot(ref)) > 0.999)
284+
ref = TVector3(1., 0., 0.);
285+
286+
// build transverse axes
287+
TVector3 xhat = (ref - (ref.Dot(zhat)) * zhat).Unit();
288+
TVector3 yhat = (zhat.Cross(xhat)).Unit();
289+
290+
// proton unit vectors in their Λ rest frames
291+
TVector3 n1(proton1LambdaRF.Px(), proton1LambdaRF.Py(), proton1LambdaRF.Pz());
292+
n1 = n1.Unit();
293+
TVector3 n2(proton2LambdaRF.Px(), proton2LambdaRF.Py(), proton2LambdaRF.Pz());
294+
n2 = n2.Unit();
295+
296+
// cosθ* (Λ2 measured along −ẑ)
297+
double c1 = n1.Dot(zhat);
298+
double c2 = -n2.Dot(zhat);
299+
300+
// sinθ*
301+
double s1 = std::sqrt(std::max(0.0, 1.0 - c1 * c1));
302+
double s2 = std::sqrt(std::max(0.0, 1.0 - c2 * c2));
303+
304+
// φ1*, φ2* in common convention (flip axes for Λ2)
305+
double phi1 = std::atan2(n1.Dot(yhat), n1.Dot(xhat));
306+
double phi2 = std::atan2(n2.Dot(-yhat), n2.Dot(-xhat));
307+
308+
// helicity spin-correlation
309+
double cosDelta = c1 * c2 + s1 * s2 * std::cos(phi1 - phi2);
310+
// clamp for safety
311+
if (cosDelta > 1.0)
312+
cosDelta = 1.0;
313+
if (cosDelta < -1.0)
314+
cosDelta = -1.0;
315+
316+
//
317+
// --- (B) Beam-based correlation (common z_B = beam; axes transported into each Λ rest frame) ---
318+
//
319+
TVector3 zB(0., 0., 1.); // beam axis in pair–CM coordinates
320+
321+
// x_B: projection of Λ1 direction onto plane ⟂ z_B; y_B completes RH basis
322+
TVector3 L1dir(lambda1CM.Px(), lambda1CM.Py(), lambda1CM.Pz());
323+
L1dir = L1dir.Unit();
324+
TVector3 xB = L1dir - (L1dir.Dot(zB)) * zB;
325+
if (xB.Mag2() < 1e-12)
326+
xB = TVector3(1., 0., 0.); // fallback if Λ1 ∥ beam
327+
xB = xB.Unit();
328+
TVector3 yB = (zB.Cross(xB)).Unit();
329+
330+
// helper to transport an axis into a Λ rest frame (from pair–CM)
331+
auto transport = [](const TVector3& v, const ROOT::Math::Boost& B) -> TVector3 {
332+
ROOT::Math::PxPyPzEVector a(v.X(), v.Y(), v.Z(), 0.0); // spacelike 4-vector (t=0)
333+
ROOT::Math::PxPyPzEVector ar = B(a); // boost into that Λ rest frame
334+
TVector3 out(ar.Px(), ar.Py(), ar.Pz());
335+
if (out.Mag2() == 0)
336+
return out;
337+
return out.Unit();
338+
};
339+
340+
// transport beam triad to each Λ rest frame
341+
TVector3 zB1 = transport(zB, boostLambda1ToCM);
342+
TVector3 xB1 = transport(xB, boostLambda1ToCM);
343+
TVector3 yB1 = transport(yB, boostLambda1ToCM);
344+
345+
TVector3 zB2 = transport(zB, boostLambda2ToCM);
346+
TVector3 xB2 = transport(xB, boostLambda2ToCM);
347+
TVector3 yB2 = transport(yB, boostLambda2ToCM);
348+
349+
// angles w.r.t. beam triad (same z_B convention for both Λ’s; no flips)
350+
double c1B = n1.Dot(zB1), c2B = n2.Dot(zB2);
351+
double s1B = std::sqrt(std::max(0.0, 1.0 - c1B * c1B));
352+
double s2B = std::sqrt(std::max(0.0, 1.0 - c2B * c2B));
353+
double phi1B = std::atan2(n1.Dot(yB1), n1.Dot(xB1));
354+
double phi2B = std::atan2(n2.Dot(yB2), n2.Dot(xB2));
355+
356+
// beam correlation
357+
double cosDeltaBeam = c1B * c2B + s1B * s2B * std::cos(phi1B - phi2B);
358+
if (cosDeltaBeam > 1.0)
359+
cosDeltaBeam = 1.0;
360+
if (cosDeltaBeam < -1.0)
361+
cosDeltaBeam = -1.0;
276362

277-
auto costhetaz1costhetaz2 = (proton1LambdaRF.Pz() * proton2LambdaRF.Pz()) / (proton1LambdaRF.P() * proton2LambdaRF.P());
363+
auto cosThetaDiff = -999.0;
364+
auto costhetaz1costhetaz2 = -999.0;
365+
if (cosDef == 0) {
366+
cosThetaDiff = proton1LambdaRF.Vect().Unit().Dot(proton2LambdaRF.Vect().Unit());
367+
costhetaz1costhetaz2 = (proton1LambdaRF.Pz() * proton2LambdaRF.Pz()) / (proton1LambdaRF.P() * proton2LambdaRF.P());
368+
} else {
369+
cosThetaDiff = cosDelta;
370+
costhetaz1costhetaz2 = cosDeltaBeam;
371+
}
278372

279373
double deltaPhi = std::abs(RecoDecay::constrainAngle(particle1Dummy.Phi(), 0.0F, harmonic) - RecoDecay::constrainAngle(particle2Dummy.Phi(), 0.0F, harmonic));
280374
double deltaEta = particle1Dummy.Eta() - particle2Dummy.Eta();

0 commit comments

Comments
 (0)