@@ -1677,6 +1677,10 @@ struct Lambdastarproxy {
16771677 static constexpr float TofBetaMin = 0 .01f ;
16781678 static constexpr float TofBetaMax = 1 .2f ;
16791679 static constexpr double Half = 0.5 ;
1680+ // PID strategy values
1681+ static constexpr int PidStrategyRectangular = 0 ;
1682+ static constexpr int PidStrategyCircularTPCAndTOF = 1 ;
1683+ static constexpr int PidStrategyTOFOnly = 2 ;
16801684 // Basic configuration for event and track selection
16811685 Configurable<float > lstarCutVertex{" lstarCutVertex" , float {CutVertexDefault}, " Accepted z-vertex range (cm)" };
16821686 Configurable<float > lstarCutPtMin{" lstarCutPtMin" , float {CutPtMinDefault}, " Minimal pT for tracks (GeV/c)" };
@@ -1696,6 +1700,24 @@ struct Lambdastarproxy {
16961700 Configurable<float > lstarCutNsigmaTOFKaon{" lstarCutNsigmaTOFKaon" , float {NsigmaTOFDefault}, " |nSigma^{TOF}_{K}| cut" };
16971701 Configurable<float > lstarCutNsigmaTPCDe{" lstarCutNsigmaTPCDe" , float {NsigmaTPCDefault}, " |nSigma^{TPC}_{d}| cut" };
16981702 Configurable<float > lstarCutNsigmaTOFDe{" lstarCutNsigmaTOFDe" , float {NsigmaTOFDefault}, " |nSigma^{TOF}_{d}| cut" };
1703+ // PID strategy for final K/p/d candidate selection.
1704+ // 0 = rectangular cuts: |TPC| < cut and, if TOF exists, |TOF| < cut
1705+ // 1 = pT-ref dependent circular cut:
1706+ // pT < pTref: require |TPC| < TPC cut only
1707+ // pT >= pTref and TOF exists: require sqrt(TPC^2 + TOF^2) < circular cut
1708+ // pT >= pTref and TOF missing: reject
1709+ // 2 = TOF-only above pTref:
1710+ // pT < pTref: require |TPC| < TPC cut only
1711+ // pT >= pTref: require TOF hit and |TOF| < TOF cut
1712+ Configurable<int > lstarPidStrategy{" lstarPidStrategy" , int {PidStrategyRectangular}, " PID strategy: 0=rectangular TPC/TOF, 1=pTref circular TPC+TOF, 2=pTref TOF-only" };
1713+
1714+ Configurable<float > lstarPidCircularCutKaon{" lstarPidCircularCutKaon" , 2 .0f , " Circular PID cut sqrt(nSigmaTPC_K^2+nSigmaTOF_K^2) for kaons" };
1715+ Configurable<float > lstarPidCircularCutPr{" lstarPidCircularCutPr" , 2 .0f , " Circular PID cut sqrt(nSigmaTPC_p^2+nSigmaTOF_p^2) for protons" };
1716+ Configurable<float > lstarPidCircularCutDe{" lstarPidCircularCutDe" , 2 .0f , " Circular PID cut sqrt(nSigmaTPC_d^2+nSigmaTOF_d^2) for deuterons" };
1717+
1718+ Configurable<float > lstarPidPtRefKaon{" lstarPidPtRefKaon" , 0 .5f , " pT reference for kaon PID strategy" };
1719+ Configurable<float > lstarPidPtRefPr{" lstarPidPtRefPr" , 0 .8f , " pT reference for proton PID strategy" };
1720+ Configurable<float > lstarPidPtRefDe{" lstarPidPtRefDe" , 0 .8f , " pT reference for deuteron PID strategy" };
16991721
17001722 // Track quality
17011723 Configurable<bool > lstarRequireGlobalTrack{" lstarRequireGlobalTrack" , bool {RequireGlobalTrackDefault}, " Require global tracks (default)" };
@@ -2305,6 +2327,45 @@ struct Lambdastarproxy {
23052327 return true ; // fallback: if column not present, assume available
23062328 }
23072329
2330+ bool passFinalCandidatePID (float pt,
2331+ float nsTPC,
2332+ float nsTOF,
2333+ bool hasTof,
2334+ float tpcCut,
2335+ float tofCut,
2336+ float circularCut,
2337+ float ptRef) const
2338+ {
2339+ // Strategy 1: analysis-note style circular TPC+TOF cut
2340+ if (lstarPidStrategy.value == PidStrategyCircularTPCAndTOF) {
2341+ if (pt < ptRef) {
2342+ return std::abs (nsTPC) < tpcCut;
2343+ }
2344+
2345+ if (!hasTof) {
2346+ return false ;
2347+ }
2348+
2349+ return std::sqrt (nsTPC * nsTPC + nsTOF * nsTOF) < circularCut;
2350+ }
2351+
2352+ // Strategy 2: TOF-only above pTref
2353+ if (lstarPidStrategy.value == PidStrategyTOFOnly) {
2354+ if (pt < ptRef) {
2355+ return std::abs (nsTPC) < tpcCut;
2356+ }
2357+
2358+ if (!hasTof) {
2359+ return false ;
2360+ }
2361+
2362+ return std::abs (nsTOF) < tofCut;
2363+ }
2364+
2365+ // Strategy 0: old rectangular logic
2366+ return (std::abs (nsTPC) < tpcCut) && (!hasTof || (std::abs (nsTOF) < tofCut));
2367+ }
2368+
23082369 // Return: 0=#pi, 1=K, 2=p, 3=d, -1=unclassified
23092370 template <typename TTrack>
23102371 int classifyPidSpecies (const TTrack& trk)
@@ -2580,20 +2641,27 @@ struct Lambdastarproxy {
25802641 continue ;
25812642 }
25822643
2644+ // Deuteron kinematics needed before PID because the PID strategy can depend on pT
2645+ const float ptD = trkD.pt ();
2646+ const float etaD = trkD.eta ();
2647+ const float phiD = trkD.phi ();
2648+
25832649 // PID for deuteron candidates
25842650 const float nsTPCDe = trkD.tpcNSigmaDe ();
25852651 const float nsTOFDe = trkD.tofNSigmaDe ();
25862652 const bool hasTofDe = hasTOFMatch (trkD);
2587- const bool isDeuteron = (std::abs (nsTPCDe) < lstarCutNsigmaTPCDe.value ) &&
2588- (!hasTofDe || (std::abs (nsTOFDe) < lstarCutNsigmaTOFDe.value ));
2653+ const bool isDeuteron = passFinalCandidatePID (ptD,
2654+ nsTPCDe,
2655+ nsTOFDe,
2656+ hasTofDe,
2657+ lstarCutNsigmaTPCDe.value ,
2658+ lstarCutNsigmaTOFDe.value ,
2659+ lstarPidCircularCutDe.value ,
2660+ lstarPidPtRefDe.value );
25892661 if (!isDeuteron) {
25902662 continue ;
25912663 }
25922664
2593- // Deuteron kinematics
2594- const float ptD = trkD.pt ();
2595- const float etaD = trkD.eta ();
2596- const float phiD = trkD.phi ();
25972665 const double pD = static_cast <double >(ptD) * std::cosh (static_cast <double >(etaD));
25982666
25992667 // QA histos for deuteron PID and kinematics
@@ -2642,18 +2710,25 @@ struct Lambdastarproxy {
26422710 continue ;
26432711 }
26442712
2713+ const float ptP = trkP.pt ();
2714+ const float etaP = trkP.eta ();
2715+ const float phiP = trkP.phi ();
2716+
26452717 const float nsTPCPr = trkP.tpcNSigmaPr ();
26462718 const float nsTOFPr = trkP.tofNSigmaPr ();
26472719 const bool hasTofPr = hasTOFMatch (trkP);
2648- const bool isProton = (std::abs (nsTPCPr) < lstarCutNsigmaTPCPr.value ) &&
2649- (!hasTofPr || (std::abs (nsTOFPr) < lstarCutNsigmaTOFPr.value ));
2720+ const bool isProton = passFinalCandidatePID (ptP,
2721+ nsTPCPr,
2722+ nsTOFPr,
2723+ hasTofPr,
2724+ lstarCutNsigmaTPCPr.value ,
2725+ lstarCutNsigmaTOFPr.value ,
2726+ lstarPidCircularCutPr.value ,
2727+ lstarPidPtRefPr.value );
26502728 if (!isProton) {
26512729 continue ;
26522730 }
26532731
2654- const float ptP = trkP.pt ();
2655- const float etaP = trkP.eta ();
2656- const float phiP = trkP.phi ();
26572732 const double pP = static_cast <double >(ptP) * std::cosh (static_cast <double >(etaP));
26582733
26592734 if (lstarEnablePidQA.value != 0 ) {
@@ -2695,20 +2770,27 @@ struct Lambdastarproxy {
26952770 continue ;
26962771 }
26972772
2773+ // Kaon kinematics needed before PID because the PID strategy can depend on pT
2774+ const float ptK = trkK.pt ();
2775+ const float etaK = trkK.eta ();
2776+ const float phiK = trkK.phi ();
2777+
26982778 // PID for kaon candidates
26992779 const float nsTPCK = trkK.tpcNSigmaKa ();
27002780 const float nsTOFK = trkK.tofNSigmaKa ();
27012781 const bool hasTofK = hasTOFMatch (trkK);
2702- const bool isKaon = (std::abs (nsTPCK) < lstarCutNsigmaTPCKaon.value ) &&
2703- (!hasTofK || (std::abs (nsTOFK) < lstarCutNsigmaTOFKaon.value ));
2782+ const bool isKaon = passFinalCandidatePID (ptK,
2783+ nsTPCK,
2784+ nsTOFK,
2785+ hasTofK,
2786+ lstarCutNsigmaTPCKaon.value ,
2787+ lstarCutNsigmaTOFKaon.value ,
2788+ lstarPidCircularCutKaon.value ,
2789+ lstarPidPtRefKaon.value );
27042790 if (!isKaon) {
27052791 continue ;
27062792 }
27072793
2708- // Kaon kinematics
2709- const float ptK = trkK.pt ();
2710- const float etaK = trkK.eta ();
2711- const float phiK = trkK.phi ();
27122794 const double pK = static_cast <double >(ptK) * std::cosh (static_cast <double >(etaK));
27132795
27142796 // Kaon QA
0 commit comments