@@ -56,7 +56,7 @@ using namespace o2::framework::expressions;
5656using namespace o2 ::constants::physics;
5757namespace
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 }};
6060static const std::vector<std::string> betheBlochParNames{" p0" , " p1" , " p2" , " p3" , " p4" , " resolution" };
6161static const std::vector<std::string> particleName{" He3" };
6262o2::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