Skip to content

Commit e97bbeb

Browse files
authored
[PWGLF] Add K0s to the He3 correlation analysis (#18192)
1 parent 8d78807 commit e97bbeb

3 files changed

Lines changed: 197 additions & 26 deletions

File tree

‎PWGLF/DataModel/LFSlimHeLambda.h‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,18 @@ DECLARE_SOA_COLUMN(DCAPVProton, dcaPVProton, float);
5454
DECLARE_SOA_COLUMN(DCAPVPion, dcaPVPion, float);
5555
DECLARE_SOA_COLUMN(V0Radius, v0Radius, float);
5656
DECLARE_SOA_COLUMN(Sign, sign, int8_t);
57+
DECLARE_SOA_COLUMN(Ct, ct, float);
58+
DECLARE_SOA_COLUMN(DCAPVPos, dcaPVPos, float);
59+
DECLARE_SOA_COLUMN(DCAPVNeg, dcaPVNeg, float);
60+
DECLARE_SOA_COLUMN(NsigmaTPCPosPion, nSigmaTPCPosPion, float);
61+
DECLARE_SOA_COLUMN(NsigmaTPCNegPion, nSigmaTPCNegPion, float);
5762
} // namespace lfv0he3
5863
DECLARE_SOA_TABLE_VERSIONED(LFHe3_000, "AOD", "LFHE3V0", 0, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::DCAxy, lfv0he3::DCAz, lfv0he3::TPCnCls, lfv0he3::ITSClusterSizes, lfv0he3::NsigmaTPC, lfv0he3::Sign);
5964
DECLARE_SOA_TABLE_VERSIONED(LFLambda_000, "AOD", "LFLAMBDA", 0, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVProton, lfv0he3::DCAPVPion, lfv0he3::V0Radius, lfv0he3::Sign);
6065

6166
DECLARE_SOA_TABLE_VERSIONED(LFHe3_001, "AOD", "LFHE3V0", 1, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::DCAxy, lfv0he3::DCAz, lfv0he3::TPCnCls, lfv0he3::TPCnClsPID, lfv0he3::ITSClusterSizes, lfv0he3::NsigmaTPC, lfv0he3::Sign);
6267
DECLARE_SOA_TABLE_VERSIONED(LFLambda_001, "AOD", "LFLAMBDA", 1, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVProton, lfv0he3::DCAPVPion, lfv0he3::V0Radius, lfv0he3::NsigmaTPCProton, lfv0he3::NsigmaTPCPion, lfv0he3::Sign);
68+
DECLARE_SOA_TABLE(LFK0s, "AOD", "LFK0S", lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::Ct, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVPos, lfv0he3::DCAPVNeg, lfv0he3::V0Radius, lfv0he3::NsigmaTPCPosPion, lfv0he3::NsigmaTPCNegPion);
6369
} // namespace o2::aod
6470

6571
struct he3Candidate {
@@ -87,4 +93,17 @@ struct lambdaCandidate {
8793
int8_t sign = 0; // Charge sign of the Lambda candidate
8894
};
8995

96+
struct k0sCandidate {
97+
ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<double>> momentum;
98+
float mass = -1.f;
99+
float ct = -1.f; // Proper decay length in cm
100+
float cosPA = -2.f;
101+
float dcaV0Daughters = -999.f;
102+
float dcaPosToPV = -999.f;
103+
float dcaNegToPV = -999.f;
104+
float v0Radius = -1.f;
105+
float posPionNSigmaTPC = -999.f;
106+
float negPionNSigmaTPC = -999.f;
107+
};
108+
90109
#endif // PWGLF_DATAMODEL_LFSLIMHELAMBDA_H_

‎PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx‎

Lines changed: 89 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ using namespace o2::framework::expressions;
5656
using namespace o2::constants::physics;
5757
namespace
5858
{
59-
constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}};
59+
constexpr std::array<double, 6> betheBlochDefault[1]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}};
6060
static const std::vector<std::string> betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"};
6161
static const std::vector<std::string> particleName{"He3"};
6262
o2::base::MatLayerCylSet* matLUT = nullptr;
@@ -101,6 +101,9 @@ struct he3LambdaAnalysis {
101101
Produces<o2::aod::LFEvents> lfHe3V0Collision;
102102
Produces<o2::aod::LFHe3_001> lfHe3;
103103
Produces<o2::aod::LFLambda_001> lfLambda;
104+
Produces<o2::aod::LFK0s> lfK0s;
105+
106+
Configurable<bool> cfgStoreK0s{"cfgStoreK0s", false, "Select and store K0s candidates, including He3-K0s events without a selected Lambda"};
104107

105108
// Configurables for event selection
106109
struct : ConfigurableGroup {
@@ -122,7 +125,7 @@ struct he3LambdaAnalysis {
122125
Configurable<float> dcazMax{"dcazMax", 0.5f, "Maximum He3 DCA z"};
123126
Configurable<int> tpcClusMin{"tpcClusMin", 100, "Minimum He3 TPC clusters"};
124127
Configurable<int> itsClusMin{"itsClusMin", 5, "Minimum He3 ITS clusters"};
125-
Configurable<LabeledArray<double>> betheBlochParams{"betheBlochParams", {betheBlochDefault[0], 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"};
128+
Configurable<LabeledArray<double>> betheBlochParams{"betheBlochParams", {betheBlochDefault[0].data(), 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"};
126129
} cfgHe3;
127130

128131
// Lambda selection criteria
@@ -131,6 +134,8 @@ struct he3LambdaAnalysis {
131134
Configurable<float> ptMin{"ptMin", 0.5f, "Minimum Lambda pT"};
132135
Configurable<float> ptMax{"ptMax", 10.0f, "Maximum Lambda pT"};
133136
Configurable<float> massWindow{"massWindow", 0.015f, "Lambda mass window"};
137+
Configurable<float> ctMin{"ctMin", 0.f, "Minimum Lambda proper decay length (cm)"};
138+
Configurable<float> ctMax{"ctMax", 30.f, "Maximum Lambda proper decay length (cm)"};
134139
Configurable<float> cosPAMin{"cosPAMin", 0.99f, "Minimum Lambda cosPA"};
135140
Configurable<float> dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum Lambda DCA V0 daughters"};
136141
Configurable<float> v0RadiusMin{"v0RadiusMin", 0.5f, "Minimum Lambda V0 radius"};
@@ -140,6 +145,22 @@ struct he3LambdaAnalysis {
140145
Configurable<float> pionNSigmaTPCMax{"pionNSigmaTPCMax", 4.0f, "Maximum pion TPC nSigma"};
141146
} cfgLambda;
142147

148+
// K0s selection criteria
149+
struct : ConfigurableGroup {
150+
std::string prefix = "cfgK0s";
151+
Configurable<float> ptMin{"ptMin", 0.5f, "Minimum K0s pT"};
152+
Configurable<float> ptMax{"ptMax", 10.f, "Maximum K0s pT"};
153+
Configurable<float> massWindow{"massWindow", 0.015f, "K0s mass window"};
154+
Configurable<float> ctMin{"ctMin", 0.f, "Minimum K0s proper decay length (cm)"};
155+
Configurable<float> ctMax{"ctMax", 20.f, "Maximum K0s proper decay length (cm)"};
156+
Configurable<float> cosPAMin{"cosPAMin", 0.99f, "Minimum K0s cosPA"};
157+
Configurable<float> dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum K0s DCA V0 daughters"};
158+
Configurable<float> v0RadiusMin{"v0RadiusMin", 0.5f, "Minimum K0s V0 radius"};
159+
Configurable<float> v0RadiusMax{"v0RadiusMax", 35.f, "Maximum K0s V0 radius"};
160+
Configurable<int> tpcNClsMin{"tpcNClsMin", 70, "Minimum TPC clusters for K0s daughters"};
161+
Configurable<float> pionNSigmaTPCMax{"pionNSigmaTPCMax", 4.f, "Maximum pion TPC nSigma"};
162+
} cfgK0s;
163+
143164
// Pair selection criteria
144165
struct : ConfigurableGroup {
145166
std::string prefix = "cfgPair";
@@ -156,7 +177,7 @@ struct he3LambdaAnalysis {
156177
Configurable<std::string> grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"};
157178
} ccdbOptions;
158179

159-
std::array<double, 6> mBBparamsHe;
180+
std::array<double, 6> mBBparamsHe = betheBlochDefault[0];
160181
float mBz = 0.0f; // Magnetic field in T
161182
HistogramRegistry mRegistry{"He3LambdaAnalysis"};
162183
int mRunNumber = 0; // Current run number
@@ -186,7 +207,7 @@ struct he3LambdaAnalysis {
186207
zorroSummary.setObject(zorro.getZorroSummary());
187208

188209
mRegistry.add("hEventSelection", "Event Selection", {HistType::kTH1L, {{6, -.5, 5.5}}});
189-
std::vector<std::string> labels{"Total Events", "Sel8 Events", "Z-Vertex OK", "Additional Event Selections", "He3 Candidates Found", "He3 and Lambda Candidates Found"};
210+
std::vector<std::string> labels{"Total Events", "Sel8 Events", "Z-Vertex OK", "Additional Event Selections", "He3 Candidates Found", "He3 and V0 Candidates Found"};
190211
for (size_t i = 1; i <= labels.size(); ++i) {
191212
mRegistry.get<TH1>(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, labels[i - 1].c_str());
192213
}
@@ -203,6 +224,8 @@ struct he3LambdaAnalysis {
203224
hArmenterosPodolanskiAll = mRegistry.add<TH2>("hArmenterosPodolanskiAll", "Armenteros-Podolanski All", {HistType::kTH2D, {{100, -1., 1.}, {100, 0., 0.5}}});
204225
hArmenterosPodolanskiSelected = mRegistry.add<TH2>("hArmenterosPodolanskiSelected", "Armenteros-Podolanski Selected", {HistType::kTH2D, {{100, -1., 1.}, {100, 0., 0.5}}});
205226

227+
mRegistry.add("hMassK0s", "Selected K0s;pT (GeV/c);mass (GeV/c^{2})", {HistType::kTH2F, {{100, 0., 10.}, {100, MassK0Short - 0.025, MassK0Short + 0.025}}});
228+
206229
constexpr double ConstituentsMass = o2::constants::physics::MassProton + o2::constants::physics::MassNeutron * 2 + o2::constants::physics::MassSigmaPlus;
207230
hInvariantMassUS = mRegistry.add<TH2>("hInvariantMassUS", "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}});
208231
hInvariantMassLS = mRegistry.add<TH2>("hInvariantMassLS", "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}});
@@ -298,16 +321,19 @@ struct he3LambdaAnalysis {
298321
}
299322
mRegistry.get<TH1>(HIST("hEventSelection"))->Fill(4); // He3 candidates found
300323

301-
// Process Lambda candidates
324+
// Fit each V0 once and evaluate the K0s and Lambda hypotheses independently.
302325
std::vector<lambdaCandidate> lambdaCandidates;
326+
std::vector<k0sCandidate> k0sCandidates;
303327
for (auto const& v0 : v0s) {
304328
if (v0.v0Type() != 1) {
305329
continue;
306330
}
307331
const auto posTrack = v0.posTrack_as<TracksFull>();
308332
const auto negTrack = v0.negTrack_as<TracksFull>();
309333

310-
if (posTrack.tpcNClsFound() < cfgLambda.tpcNClsMin || negTrack.tpcNClsFound() < cfgLambda.tpcNClsMin) {
334+
const bool lambdaTrackQuality = posTrack.tpcNClsFound() >= cfgLambda.tpcNClsMin && negTrack.tpcNClsFound() >= cfgLambda.tpcNClsMin;
335+
const bool k0sTrackQuality = cfgStoreK0s && posTrack.tpcNClsFound() >= cfgK0s.tpcNClsMin && negTrack.tpcNClsFound() >= cfgK0s.tpcNClsMin;
336+
if (!lambdaTrackQuality && !k0sTrackQuality) {
311337
continue; // Skip V0s with insufficient TPC clusters
312338
}
313339
auto trackParPos = getTrackParCov(posTrack);
@@ -332,6 +358,49 @@ struct he3LambdaAnalysis {
332358
float qt = qtAP(momV0, momPos);
333359
hArmenterosPodolanskiAll->Fill(alpha, qt);
334360

361+
const auto sv = fitter.getPCACandidate(0);
362+
const float decayLength = std::hypot(sv[0] - collVtx.x(), sv[1] - collVtx.y(), sv[2] - collVtx.z());
363+
const float momentum = std::hypot(momV0[0], momV0[1], momV0[2]);
364+
if (momentum <= 0.f || decayLength <= 0.f) {
365+
continue;
366+
}
367+
const float cosPA = ((sv[0] - collVtx.x()) * momV0[0] + (sv[1] - collVtx.y()) * momV0[1] + (sv[2] - collVtx.z()) * momV0[2]) / (decayLength * momentum);
368+
const float dcaDaughters = std::sqrt(fitter.getChi2AtPCACandidate(0));
369+
const float radius = std::hypot(sv[0], sv[1]);
370+
std::array<float, 2> dcaInfoPos{}, dcaInfoNeg{};
371+
if (!o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParPos, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoPos) ||
372+
!o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParNeg, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoNeg)) {
373+
continue;
374+
}
375+
376+
ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<float>> posPionMom4D(momPos[0], momPos[1], momPos[2], MassPionCharged);
377+
ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<float>> negPionMom4D(momNeg[0], momNeg[1], momNeg[2], MassPionCharged);
378+
const auto k0sMom4D = posPionMom4D + negPionMom4D;
379+
const float ctK0s = decayLength * MassK0Short / momentum;
380+
if (k0sTrackQuality && std::abs(posTrack.tpcNSigmaPi()) <= cfgK0s.pionNSigmaTPCMax && std::abs(negTrack.tpcNSigmaPi()) <= cfgK0s.pionNSigmaTPCMax &&
381+
std::abs(k0sMom4D.M() - MassK0Short) <= cfgK0s.massWindow && k0sMom4D.Pt() >= cfgK0s.ptMin && k0sMom4D.Pt() <= cfgK0s.ptMax &&
382+
ctK0s >= cfgK0s.ctMin && ctK0s <= cfgK0s.ctMax && cosPA >= cfgK0s.cosPAMin && dcaDaughters <= cfgK0s.dcaV0DaughtersMax &&
383+
radius >= cfgK0s.v0RadiusMin && radius <= cfgK0s.v0RadiusMax) {
384+
k0sCandidate candidate;
385+
candidate.momentum.SetCoordinates(k0sMom4D.Pt(), k0sMom4D.Eta(), k0sMom4D.Phi(), MassK0Short);
386+
candidate.mass = k0sMom4D.M();
387+
candidate.ct = ctK0s;
388+
candidate.cosPA = cosPA;
389+
candidate.dcaV0Daughters = dcaDaughters;
390+
candidate.dcaPosToPV = std::hypot(dcaInfoPos[0], dcaInfoPos[1]);
391+
candidate.dcaNegToPV = std::hypot(dcaInfoNeg[0], dcaInfoNeg[1]);
392+
candidate.v0Radius = radius;
393+
candidate.posPionNSigmaTPC = posTrack.tpcNSigmaPi();
394+
candidate.negPionNSigmaTPC = negTrack.tpcNSigmaPi();
395+
k0sCandidates.push_back(candidate);
396+
mRegistry.fill(HIST("hMassK0s"), k0sMom4D.Pt(), candidate.mass);
397+
}
398+
399+
const float ctLambda = decayLength * MassLambda0 / momentum;
400+
if (!lambdaTrackQuality || ctLambda < cfgLambda.ctMin || ctLambda > cfgLambda.ctMax || cosPA < cfgLambda.cosPAMin ||
401+
dcaDaughters > cfgLambda.dcaV0DaughtersMax || radius < cfgLambda.v0RadiusMin || radius > cfgLambda.v0RadiusMax) {
402+
continue;
403+
}
335404
bool matter = alpha > 0;
336405
const auto& protonTrack = matter ? posTrack : negTrack;
337406
const auto& pionTrack = matter ? negTrack : posTrack;
@@ -347,37 +416,30 @@ struct he3LambdaAnalysis {
347416
auto lambdaMom4D = protonMom4D + pionMom4D;
348417
float massLambda = lambdaMom4D.M();
349418

350-
if (std::abs(massLambda - o2::constants::physics::MassLambda0) > cfgLambda.massWindow) {
419+
if (std::abs(massLambda - o2::constants::physics::MassLambda0) > cfgLambda.massWindow || lambdaMom4D.Pt() < cfgLambda.ptMin || lambdaMom4D.Pt() > cfgLambda.ptMax) {
351420
continue; // Skip V0s outside mass window
352421
}
353422
hArmenterosPodolanskiSelected->Fill(alpha, qt);
354423

355-
std::array<float, 2> dcaInfoProton, dcaInfoPion;
356-
o2::base::Propagator::Instance()->propagateToDCA(collVtx, matter ? trackParPos : trackParNeg, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoProton);
357-
o2::base::Propagator::Instance()->propagateToDCA(collVtx, matter ? trackParNeg : trackParPos, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoPion);
358-
359-
const auto sv = fitter.getPCACandidate(0);
360-
424+
const auto& dcaInfoProton = matter ? dcaInfoPos : dcaInfoNeg;
425+
const auto& dcaInfoPion = matter ? dcaInfoNeg : dcaInfoPos;
361426
lambdaCandidate candidate;
362-
candidate.momentum.SetCoordinates(lambdaMom4D.Pt(), lambdaMom4D.Eta(), lambdaMom4D.Phi(), o2::constants::physics::MassLambda0);
427+
candidate.momentum.SetCoordinates(lambdaMom4D.Pt(), lambdaMom4D.Eta(), lambdaMom4D.Phi(), MassLambda0);
363428
candidate.mass = massLambda;
364-
candidate.cosPA = (sv[0] - collVtx.x()) * lambdaMom4D.Px() +
365-
(sv[1] - collVtx.y()) * lambdaMom4D.Py() +
366-
(sv[2] - collVtx.z()) * lambdaMom4D.Pz();
367-
candidate.cosPA /= std::hypot(sv[0] - collVtx.x(), sv[1] - collVtx.y(), sv[2] - collVtx.z()) * lambdaMom4D.P();
368-
candidate.dcaV0Daughters = std::sqrt(fitter.getChi2AtPCACandidate(0));
429+
candidate.cosPA = cosPA;
430+
candidate.dcaV0Daughters = dcaDaughters;
369431
candidate.dcaProtonToPV = std::hypot(dcaInfoProton[0], dcaInfoProton[1]);
370432
candidate.dcaPionToPV = std::hypot(dcaInfoPion[0], dcaInfoPion[1]);
371-
candidate.v0Radius = std::hypot(sv[0], sv[1]);
433+
candidate.v0Radius = radius;
372434
candidate.protonNSigmaTPC = protonTrack.tpcNSigmaPr();
373435
candidate.pionNSigmaTPC = pionTrack.tpcNSigmaPi();
374436
candidate.sign = matter ? 1 : -1; // Positive sign for Lambda, negative for anti-Lambda
375437
lambdaCandidates.push_back(candidate);
376438
}
377-
if (lambdaCandidates.empty()) {
378-
return; // No valid Lambda candidates found
439+
if (lambdaCandidates.empty() && (!cfgStoreK0s || k0sCandidates.empty())) {
440+
return; // Require a Lambda, or a K0s when cfgStoreK0s is enabled
379441
}
380-
mRegistry.get<TH1>(HIST("hEventSelection"))->Fill(5); // He3 and Lambda candidates found
442+
mRegistry.get<TH1>(HIST("hEventSelection"))->Fill(5); // He3 and V0 candidates found
381443
mRegistry.get<TH1>(HIST("hCentralitySelected"))->Fill(collision.centFT0C());
382444

383445
// Fill output tables
@@ -386,6 +448,10 @@ struct he3LambdaAnalysis {
386448
lfHe3(lfHe3V0Collision.lastIndex(), he3.momentum.Pt(), he3.momentum.Eta(), he3.momentum.Phi(),
387449
he3.dcaXY, he3.dcaZ, he3.tpcNClsFound, he3.tpcNClsPID, he3.itsClusterSizes, he3.nSigmaTPC, he3.sign);
388450
}
451+
for (const auto& k0s : k0sCandidates) {
452+
lfK0s(lfHe3V0Collision.lastIndex(), k0s.momentum.Pt(), k0s.momentum.Eta(), k0s.momentum.Phi(),
453+
k0s.mass, k0s.ct, k0s.cosPA, k0s.dcaV0Daughters, k0s.dcaPosToPV, k0s.dcaNegToPV, k0s.v0Radius, k0s.posPionNSigmaTPC, k0s.negPionNSigmaTPC);
454+
}
389455
for (const auto& lambda : lambdaCandidates) {
390456
lfLambda(lfHe3V0Collision.lastIndex(), lambda.momentum.Pt(), lambda.momentum.Eta(), lambda.momentum.Phi(),
391457
lambda.mass, lambda.cosPA, lambda.dcaV0Daughters, lambda.dcaProtonToPV, lambda.dcaPionToPV, lambda.v0Radius, lambda.protonNSigmaTPC, lambda.pionNSigmaTPC, lambda.sign);

0 commit comments

Comments
 (0)