Skip to content

Commit b757395

Browse files
author
Sushanta Tripathy
committed
Updating PID and track selection criteria
1 parent 2a807a7 commit b757395

1 file changed

Lines changed: 150 additions & 39 deletions

File tree

PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx

Lines changed: 150 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,14 @@ struct Nucleibalance {
8686
O2_DEFINE_CONFIGURABLE(cfgCutMCPt, float, 0.5f, "Minimal pT for MC particles (AO2D-MC mode)")
8787
O2_DEFINE_CONFIGURABLE(cfgCutMCEta, float, 0.8f, "Eta range for MC particles (AO2D-MC mode)")
8888
O2_DEFINE_CONFIGURABLE(cfgUseFT0M, int, 1, "Use FT0M centrality (0-100) as multiplicity axis (1=ON, 0=use Ntracks/multiplicity())")
89-
// Track-quality options (AO2D mode). Default selection corresponds to global tracks.
90-
O2_DEFINE_CONFIGURABLE(cfgTPCNClsMin, int, 70, "Minimum number of TPC clusters (tpcNClsFound) in AO2D mode")
91-
O2_DEFINE_CONFIGURABLE(cfgDcaXYMax, float, 0.1f, "Max |DCA_{xy}| to PV (cm) in AO2D mode")
92-
O2_DEFINE_CONFIGURABLE(cfgDcaZMax, float, 0.2f, "Max |DCA_{z}| to PV (cm) in AO2D mode")
93-
O2_DEFINE_CONFIGURABLE(chi2pertpccluster, float, 2.5f, "Maximum Chi2/cluster for the TPC track segment in AO2D mode")
94-
O2_DEFINE_CONFIGURABLE(chi2peritscluster, float, 36.f, "Maximum Chi2/cluster for the ITS track segment in AO2D mode")
95-
O2_DEFINE_CONFIGURABLE(itsnclusters, int, 5, "Minimum number of ITS clusters in AO2D mode")
89+
// Track-quality options. Default selection corresponds to global tracks.
90+
O2_DEFINE_CONFIGURABLE(cfgTPCNClsMin, int, 70, "Minimum number of TPC clusters (tpcNClsFound)")
91+
O2_DEFINE_CONFIGURABLE(cfgDcaXYMax, float, 0.1f, "Max |DCA_{xy}| to PV (cm)")
92+
O2_DEFINE_CONFIGURABLE(cfgDcaZMax, float, 0.2f, "Max |DCA_{z}| to PV (cm)")
93+
O2_DEFINE_CONFIGURABLE(cfgRequirePrimaryTrack, int, 1, "Require isPrimaryTrack()= true (1=ON, 0=OFF)")
94+
O2_DEFINE_CONFIGURABLE(chi2pertpccluster, float, 2.5f, "Maximum Chi2/cluster for the TPC track segment")
95+
O2_DEFINE_CONFIGURABLE(chi2peritscluster, float, 36.f, "Maximum Chi2/cluster for the ITS track segment")
96+
O2_DEFINE_CONFIGURABLE(itsnclusters, int, 1, "Minimum number of ITS clusters")
9697

9798
O2_DEFINE_CONFIGURABLE(cfgPtOrder, int, 1, "Only consider pairs for which pT,1 < pT,2 (0 = OFF, 1 = ON)");
9899
O2_DEFINE_CONFIGURABLE(cfgTriggerCharge, int, 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative");
@@ -343,6 +344,15 @@ struct Nucleibalance {
343344
return false;
344345
}
345346
}
347+
// Match the standard Lambda(1520) task option `cfgPrimaryTrack`:
348+
// require primary tracks when the corresponding selection column is available.
349+
if (cfgRequirePrimaryTrack.value != 0) {
350+
if constexpr (requires { trk.isPrimaryTrack(); }) {
351+
if (!trk.isPrimaryTrack()) {
352+
return false;
353+
}
354+
}
355+
}
346356

347357
if constexpr (requires { trk.itsNCls(); }) {
348358
if (itsnclusters.value > 0 && trk.itsNCls() < itsnclusters.value) {
@@ -1680,7 +1690,7 @@ struct Lambdastarproxy {
16801690
// PID strategy values
16811691
static constexpr int PidStrategyRectangular = 0;
16821692
static constexpr int PidStrategyCircularTPCAndTOF = 1;
1683-
static constexpr int PidStrategyTOFOnly = 2;
1693+
static constexpr int PidStrategyNucleiDeuteronTPC = 2;
16841694
// Basic configuration for event and track selection
16851695
Configurable<float> lstarCutVertex{"lstarCutVertex", float{CutVertexDefault}, "Accepted z-vertex range (cm)"};
16861696
Configurable<float> lstarCutPtMin{"lstarCutPtMin", float{CutPtMinDefault}, "Minimal pT for tracks (GeV/c)"};
@@ -1700,16 +1710,26 @@ struct Lambdastarproxy {
17001710
Configurable<float> lstarCutNsigmaTOFKaon{"lstarCutNsigmaTOFKaon", float{NsigmaTOFDefault}, "|nSigma^{TOF}_{K}| cut"};
17011711
Configurable<float> lstarCutNsigmaTPCDe{"lstarCutNsigmaTPCDe", float{NsigmaTPCDefault}, "|nSigma^{TPC}_{d}| cut"};
17021712
Configurable<float> lstarCutNsigmaTOFDe{"lstarCutNsigmaTOFDe", float{NsigmaTOFDefault}, "|nSigma^{TOF}_{d}| cut"};
1713+
// Optional deuteron-only TOF auxiliary selections.
1714+
// Defaults are OFF, so strategy 2 remains TPC nSigma only for deuterons.
1715+
Configurable<int> lstarEnableBetaCutDe{"lstarEnableBetaCutDe", 0, "Enable deuteron-only TOF beta cut using beta() > lstarBetaCutDe"};
1716+
Configurable<float> lstarBetaCutDe{"lstarBetaCutDe", 0.4f, "Minimum TOF beta for deuteron-only beta cut"};
1717+
Configurable<int> lstarEnableExpSignalTOFDe{"lstarEnableExpSignalTOFDe", 0, "Enable deuteron-only TOF expected-signal-difference cut when lstarTOFExpSignalDiffDeMax > 0"};
1718+
Configurable<float> lstarTOFExpSignalDiffDeMax{"lstarTOFExpSignalDiffDeMax", -1.f, "Maximum |tofExpSignalDiffDe| for deuterons; <=0 disables the numeric cut"};
1719+
17031720
// PID strategy for final K/p/d candidate selection.
1704-
// 0 = rectangular cuts: |TPC| < cut and, if TOF exists, |TOF| < cut
1721+
// 0 = pT-ref dependent rectangular cuts:
1722+
// pT < pTref: require |TPC| < TPC cut only
1723+
// pT >= pTref and TOF exists: require |TPC| < TPC cut and |TOF| < TOF cut
1724+
// pT >= pTref and TOF missing: reject
17051725
// 1 = pT-ref dependent circular cut:
17061726
// pT < pTref: require |TPC| < TPC cut only
17071727
// pT >= pTref and TOF exists: require sqrt(TPC^2 + TOF^2) < circular cut
17081728
// 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"};
1729+
// 2 = hybrid official-like PID:
1730+
// deuterons: require |TPC_d| < TPC cut only
1731+
// kaons/protons: use the Lambda(1520)-like pT-ref circular TPC+TOF logic
1732+
Configurable<int> lstarPidStrategy{"lstarPidStrategy", int{PidStrategyRectangular}, "PID strategy: 0=pTref rectangular TPC/TOF, 1=pTref circular TPC+TOF, 2=hybrid: K/p circular, d TPC-only"};
17131733

17141734
Configurable<float> lstarPidCircularCutKaon{"lstarPidCircularCutKaon", 2.0f, "Circular PID cut sqrt(nSigmaTPC_K^2+nSigmaTOF_K^2) for kaons"};
17151735
Configurable<float> lstarPidCircularCutPr{"lstarPidCircularCutPr", 2.0f, "Circular PID cut sqrt(nSigmaTPC_p^2+nSigmaTOF_p^2) for protons"};
@@ -1720,8 +1740,12 @@ struct Lambdastarproxy {
17201740
Configurable<float> lstarPidPtRefDe{"lstarPidPtRefDe", 0.8f, "pT reference for deuteron PID strategy"};
17211741

17221742
// Track quality
1743+
Configurable<int> lstarRequireINELgt0{"lstarRequireINELgt0", 1, "Require INEL>0 event selection using isInelGt0() when available; fallback to multNTracksPVeta1()/numContrib()"};
17231744
Configurable<bool> lstarRequireGlobalTrack{"lstarRequireGlobalTrack", bool{RequireGlobalTrackDefault}, "Require global tracks (default)"};
1724-
Configurable<int> lstarTPCNClsMin{"lstarTPCNClsMin", int{TPCNClsMinDefault}, "Minimum number of TPC clusters (tpcNClsFound)"};
1745+
Configurable<int> lstarRequirePrimaryTrack{"lstarRequirePrimaryTrack", 1, "Require isPrimaryTrack() for Lambda* proxy candidates when the column is available"};
1746+
Configurable<int> lstarOnlyGlobalTrackCuts{"lstarOnlyGlobalTrackCuts", 0, "If enabled, apply only the global-track plus primary-track requirements and skip additional ITS/TPC/DCA/chi2 track-quality cuts"};
1747+
Configurable<int> lstarTPCNClsMin{"lstarTPCNClsMin", int{TPCNClsMinDefault}, "Minimum number of TPC crossed rows (tpcNClsCrossedRows)"};
1748+
Configurable<float> lstarTPCCrossedRowsOverFindableMin{"lstarTPCCrossedRowsOverFindableMin", 0.8f, "Minimum TPC crossed rows over findable clusters"};
17251749
Configurable<float> lstarDcaXYMax{"lstarDcaXYMax", float{DcaXYMaxDefault}, "Max |DCA_{xy}| to PV (cm)"};
17261750
Configurable<float> lstarDcaZMax{"lstarDcaZMax", float{DcaZMaxDefault}, "Max |DCA_{z}| to PV (cm)"};
17271751
Configurable<float> lstarChi2PerTPCCluster{"lstarChi2PerTPCCluster", float{Chi2PerTPCClusterDefault}, "Maximum Chi2/cluster for the TPC track segment"};
@@ -1790,6 +1814,22 @@ struct Lambdastarproxy {
17901814
template <typename TCollision>
17911815
bool keepCollisionAO2D(TCollision const& collision) const
17921816
{
1817+
// Prefer the official event-selection flag when available.
1818+
if (lstarRequireINELgt0.value != 0) {
1819+
bool isINELgt0 = true;
1820+
1821+
if constexpr (requires { collision.isInelGt0(); }) {
1822+
isINELgt0 = collision.isInelGt0();
1823+
} else if constexpr (requires { collision.multNTracksPVeta1(); }) {
1824+
isINELgt0 = collision.multNTracksPVeta1() > 0;
1825+
} else if constexpr (requires { collision.numContrib(); }) {
1826+
isINELgt0 = collision.numContrib() > 0;
1827+
}
1828+
1829+
if (!isINELgt0) {
1830+
return false;
1831+
}
1832+
}
17931833
if (lstarCfgTrigger.value == TriggerNone) {
17941834
return true;
17951835
} else if (lstarCfgTrigger.value == TriggerSel8) {
@@ -1903,14 +1943,40 @@ struct Lambdastarproxy {
19031943
}
19041944
}
19051945

1946+
// Always require primary tracks
1947+
if (lstarRequirePrimaryTrack.value != 0) {
1948+
if constexpr (requires { trk.isPrimaryTrack(); }) {
1949+
if (!trk.isPrimaryTrack()) {
1950+
return false;
1951+
}
1952+
}
1953+
}
1954+
1955+
// Optional official-baseline mode: use only the O2 global-track and primary-track definitions.
1956+
// This bypasses the extra explicit ITS/TPC/DCA/chi2 cuts below.
1957+
if (lstarOnlyGlobalTrackCuts.value != 0) {
1958+
return true;
1959+
}
1960+
19061961
if constexpr (requires { trk.itsNCls(); }) {
19071962
if (lstarITSNClusters.value > 0 && trk.itsNCls() < lstarITSNClusters.value) {
19081963
return false;
19091964
}
19101965
}
19111966

1912-
if constexpr (requires { trk.tpcNClsFound(); }) {
1913-
if (lstarTPCNClsMin.value > 0 && trk.tpcNClsFound() < lstarTPCNClsMin.value) {
1967+
if constexpr (requires { trk.tpcNClsCrossedRows(); }) {
1968+
if (lstarTPCNClsMin.value > 0 && trk.tpcNClsCrossedRows() < lstarTPCNClsMin.value) {
1969+
return false;
1970+
}
1971+
} else if constexpr (requires { trk.tpcNClsFindable(); trk.tpcCrossedRowsOverFindableCls(); }) {
1972+
if (lstarTPCNClsMin.value > 0 && trk.tpcNClsFindable() * trk.tpcCrossedRowsOverFindableCls() < lstarTPCNClsMin.value) {
1973+
return false;
1974+
}
1975+
}
1976+
1977+
if constexpr (requires { trk.tpcCrossedRowsOverFindableCls(); }) {
1978+
if (lstarTPCCrossedRowsOverFindableMin.value > 0.f &&
1979+
trk.tpcCrossedRowsOverFindableCls() < lstarTPCCrossedRowsOverFindableMin.value) {
19141980
return false;
19151981
}
19161982
}
@@ -2327,14 +2393,48 @@ struct Lambdastarproxy {
23272393
return true; // fallback: if column not present, assume available
23282394
}
23292395

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
2396+
template <typename TTrack>
2397+
bool passOptionalDeuteronTOFExtras(const TTrack& trk) const
2398+
{
2399+
const bool needTOF =
2400+
(lstarEnableBetaCutDe.value != 0) ||
2401+
(lstarEnableExpSignalTOFDe.value != 0 && lstarTOFExpSignalDiffDeMax.value > 0.f);
2402+
2403+
if (needTOF) {
2404+
if constexpr (requires { trk.hasTOF(); }) {
2405+
if (!trk.hasTOF()) {
2406+
return false;
2407+
}
2408+
}
2409+
}
2410+
2411+
if (lstarEnableBetaCutDe.value != 0) {
2412+
if constexpr (requires { trk.beta(); }) {
2413+
if (trk.beta() <= lstarBetaCutDe.value) {
2414+
return false;
2415+
}
2416+
} else {
2417+
return false;
2418+
}
2419+
}
2420+
2421+
if (lstarEnableExpSignalTOFDe.value != 0 &&
2422+
lstarTOFExpSignalDiffDeMax.value > 0.f) {
2423+
if constexpr (requires { trk.tofExpSignalDiffDe(); }) {
2424+
if (std::abs(trk.tofExpSignalDiffDe()) > lstarTOFExpSignalDiffDeMax.value) {
2425+
return false;
2426+
}
2427+
} else {
2428+
return false;
2429+
}
2430+
}
2431+
2432+
return true;
2433+
}
2434+
2435+
bool passFinalCandidatePID(float pt, float nsTPC, float nsTOF, bool hasTof,
2436+
float tpcCut, float tofCut, float circularCut,
2437+
float ptRef, bool isDeuteron = false) const
23382438
{
23392439
// Strategy 1: analysis-note style circular TPC+TOF cut
23402440
if (lstarPidStrategy.value == PidStrategyCircularTPCAndTOF) {
@@ -2349,8 +2449,14 @@ struct Lambdastarproxy {
23492449
return std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF) < circularCut;
23502450
}
23512451

2352-
// Strategy 2: TOF-only above pTref
2353-
if (lstarPidStrategy.value == PidStrategyTOFOnly) {
2452+
if (lstarPidStrategy.value == PidStrategyNucleiDeuteronTPC) {
2453+
// For deuterons, follow the default idea of the official nuclei task:
2454+
// use TPC nσ as the main hard PID selection.
2455+
if (isDeuteron) {
2456+
return std::abs(nsTPC) < tpcCut;
2457+
}
2458+
2459+
// For kaons/protons, use the Lambda(1520)-like pT-ref circular TPC+TOF logic.
23542460
if (pt < ptRef) {
23552461
return std::abs(nsTPC) < tpcCut;
23562462
}
@@ -2359,11 +2465,18 @@ struct Lambdastarproxy {
23592465
return false;
23602466
}
23612467

2362-
return std::abs(nsTOF) < tofCut;
2468+
return std::sqrt(nsTPC * nsTPC + nsTOF * nsTOF) < circularCut;
23632469
}
23642470

2365-
// Strategy 0: old rectangular logic
2366-
return (std::abs(nsTPC) < tpcCut) && (!hasTof || (std::abs(nsTOF) < tofCut));
2471+
// Strategy 0: pT-ref dependent rectangular TPC+TOF cut.
2472+
// Below pTref use TPC only; above pTref require TOF and apply both TPC and TOF cuts.
2473+
if (pt < ptRef) {
2474+
return std::abs(nsTPC) < tpcCut;
2475+
}
2476+
if (!hasTof) {
2477+
return false;
2478+
}
2479+
return (std::abs(nsTPC) < tpcCut) && (std::abs(nsTOF) < tofCut);
23672480
}
23682481

23692482
// Return: 0=#pi, 1=K, 2=p, 3=d, -1=unclassified
@@ -2650,14 +2763,12 @@ struct Lambdastarproxy {
26502763
const float nsTPCDe = trkD.tpcNSigmaDe();
26512764
const float nsTOFDe = trkD.tofNSigmaDe();
26522765
const bool hasTofDe = hasTOFMatch(trkD);
2653-
const bool isDeuteron = passFinalCandidatePID(ptD,
2654-
nsTPCDe,
2655-
nsTOFDe,
2656-
hasTofDe,
2657-
lstarCutNsigmaTPCDe.value,
2658-
lstarCutNsigmaTOFDe.value,
2659-
lstarPidCircularCutDe.value,
2660-
lstarPidPtRefDe.value);
2766+
if (!passOptionalDeuteronTOFExtras(trkD)) {
2767+
continue;
2768+
}
2769+
const bool isDeuteron = passFinalCandidatePID(trkD.pt(), trkD.tpcNSigmaDe(), nsTOFDe, hasTofDe,
2770+
lstarCutNsigmaTPCDe.value, lstarCutNsigmaTOFDe.value,
2771+
lstarPidCircularCutDe.value, lstarPidPtRefDe.value, true);
26612772
if (!isDeuteron) {
26622773
continue;
26632774
}
@@ -2724,7 +2835,7 @@ struct Lambdastarproxy {
27242835
lstarCutNsigmaTPCPr.value,
27252836
lstarCutNsigmaTOFPr.value,
27262837
lstarPidCircularCutPr.value,
2727-
lstarPidPtRefPr.value);
2838+
lstarPidPtRefPr.value, false);
27282839
if (!isProton) {
27292840
continue;
27302841
}
@@ -2786,7 +2897,7 @@ struct Lambdastarproxy {
27862897
lstarCutNsigmaTPCKaon.value,
27872898
lstarCutNsigmaTOFKaon.value,
27882899
lstarPidCircularCutKaon.value,
2789-
lstarPidPtRefKaon.value);
2900+
lstarPidPtRefKaon.value, false);
27902901
if (!isKaon) {
27912902
continue;
27922903
}

0 commit comments

Comments
 (0)