@@ -1711,6 +1711,7 @@ struct Lambdastarproxy {
17111711 Configurable<float > lstarCutNsigmaTPCDe{" lstarCutNsigmaTPCDe" , float {NsigmaTPCDefault}, " |nSigma^{TPC}_{d}| cut" };
17121712 Configurable<float > lstarCutNsigmaTOFDe{" lstarCutNsigmaTOFDe" , float {NsigmaTOFDefault}, " |nSigma^{TOF}_{d}| cut" };
17131713 Configurable<int > lstarEnableTOFNsigmaCutDe{" lstarEnableTOFNsigmaCutDe" , 0 , " Enable deuteron-only TOF nSigma cut in PID strategy 2" };
1714+ Configurable<int > lstarProxyUseProtonPIDAsDeuteron{" lstarProxyUseProtonPIDAsDeuteron" , 0 , " Closure/control test: keep proxy candidates that pass the normal deuteron selection and are also proton-like, then build p_proxy = p_track/2" };
17141715 // Optional deuteron-only TOF auxiliary selections.
17151716 // Defaults are OFF, so strategy 2 remains TPC nSigma only for deuterons.
17161717 Configurable<int > lstarEnableBetaCutDe{" lstarEnableBetaCutDe" , 0 , " Enable deuteron-only TOF beta cut using beta() > lstarBetaCutDe" };
@@ -1763,6 +1764,9 @@ struct Lambdastarproxy {
17631764 Configurable<int > lstarNoMixedEvents{" lstarNoMixedEvents" , int {NoMixedEventsDefault}, " Number of previous events kept for mixed-event background" };
17641765 Configurable<float > lstarMixZvtxMax{" lstarMixZvtxMax" , float {MixZvtxMaxDefault}, " Max |Δzvtx| (cm) for event mixing" };
17651766 Configurable<float > lstarMixMultMax{" lstarMixMultMax" , float {MixMultMaxDefault}, " Max |Δmult| for event mixing" };
1767+ // Master switch for PID QA histogram filling.
1768+ // Inclusive PID-QA histograms are filled before final PID cuts, after event/track-quality cuts.
1769+ // Candidate-level nSigma/TOF/DCA histograms are filled after final PID cuts.
17661770 Configurable<int > lstarEnablePidQA{" lstarEnablePidQA" , 0 , " Enable PID QA histograms (dE/dx, TOF #beta, proxy invariant-mass QA, etc.): 1 = ON, 0 = OFF" };
17671771 Configurable<int > lstarEnableSparse{" lstarEnableSparse" , 1 , " Enable THnSparse invariant-mass histograms (#Lambda^{*} pK and proxy); 1 = ON, 0 = OFF" };
17681772 Configurable<float > lstarLambdaAbsYMax{" lstarLambdaAbsYMax" , 0 .5f , " Max |y_{pK}| (or y_{proxy K}) for #Lambda^{*} candidates" };
@@ -2104,6 +2108,7 @@ struct Lambdastarproxy {
21042108 " #Lambda^{*} proxy invariant mass from (d/2 + K);M_{p_{proxy}K} (GeV/c^{2});Counts" ,
21052109 HistType::kTH1F , {massAxis});
21062110
2111+ // Inclusive PID QA before final candidate PID cuts: after track-quality cuts only
21072112 // TPC dE/dx vs total momentum
21082113 histos.add (" hTPCdEdxVsP" ,
21092114 " TPC dE/dx vs p;p (GeV/c);dE/dx (arb. units);Counts" ,
@@ -2114,7 +2119,8 @@ struct Lambdastarproxy {
21142119 " TOF #beta vs p;p (GeV/c);#beta_{TOF};Counts" ,
21152120 HistType::kTH2F , {pAxis, betaAxis});
21162121
2117- // --- Per-species PID QA (tagged) ---
2122+ // --- Per-species inclusive PID QA before final candidate PID cuts ---
2123+ // Species tagging here uses classifyPidSpecies() and is meant only for QA.
21182124 histos.add (" hTPCdEdxVsP_Pi" ,
21192125 " TPC dE/dx vs p (tagged #pi);p (GeV/c);dE/dx (arb. units);Counts" ,
21202126 HistType::kTH2F , {pAxis, dEdxAxis});
@@ -2204,7 +2210,7 @@ struct Lambdastarproxy {
22042210 " TOF n#sigma_{K} vs p; p (GeV/c); n#sigma^{TOF}_{K};Counts" ,
22052211 HistType::kTH2F , {pAxis, nsAxis});
22062212
2207- // --- Additional pT-based PID QA for the final selected K/p/d candidates ---
2213+ // --- Candidate PID QA after final selected K/p/d PID cuts ---
22082214 // These histograms are needed for PID studies in the same pT intervals used by the analysis.
22092215 histos.add (" hTOFBetaVsPt_K" ,
22102216 " TOF #beta vs p_{T} for selected K;p_{T} (GeV/c);#beta_{TOF};Counts" ,
@@ -2451,16 +2457,15 @@ struct Lambdastarproxy {
24512457 }
24522458
24532459 if (lstarPidStrategy.value == PidStrategyNucleiDeuteronTPC) {
2454- // For deuterons, follow the default idea of the official nuclei task:
2455- // use TPC nσ as the main hard PID selection.
2460+ // For deuterons, use TPC nσ as the main hard PID selection.
2461+ // If the optional deuteron TOF nσ cut is enabled, apply it only when
2462+ // the track has a valid TOF match. Tracks without TOF are kept with
2463+ // the TPC-only decision, avoiding an additional TOF-matching efficiency loss.
24562464 if (isDeuteron) {
24572465 if (std::abs (nsTPC) >= tpcCut) {
24582466 return false ;
24592467 }
2460- if (lstarEnableTOFNsigmaCutDe.value != 0 ) {
2461- if (!hasTof) {
2462- return false ;
2463- }
2468+ if (lstarEnableTOFNsigmaCutDe.value != 0 && hasTof) {
24642469 return std::abs (nsTOF) < tofCut;
24652470 }
24662471 return true ;
@@ -2580,87 +2585,6 @@ struct Lambdastarproxy {
25802585 constexpr double MassProton = o2::constants::physics::MassProton;
25812586 constexpr double MassKaonCharged = o2::constants::physics::MassKaonCharged;
25822587
2583- // --- Inclusive PID QA: keep #pi/K/p/d bands in TPC dE/dx and TOF beta plots ---
2584- if (lstarEnablePidQA.value != 0 ) {
2585- for (auto const & trk : tracks) {
2586- if (trk.pt () < lstarCutPtMin.value || std::abs (trk.eta ()) > lstarCutEtaMax.value ) {
2587- continue ;
2588- }
2589- if (!passTrackQuality (trk)) {
2590- continue ;
2591- }
2592- if (trk.sign () == 0 ) {
2593- continue ;
2594- }
2595- // Inclusive PID QA
2596- fillTPCdEdxVsPIfAvailable (trk);
2597- fillTOFBetaVsPIfAvailable (trk);
2598-
2599- // Per-species PID-QA (tagged) histograms
2600- const int sp = classifyPidSpecies (trk);
2601- switch (sp) {
2602- case 0 : { // pion
2603- if constexpr (requires { trk.tpcSignal (); }) {
2604- histos.fill (HIST (" hTPCdEdxVsP_Pi" ), trk.p (), trk.tpcSignal ());
2605- }
2606- if constexpr (requires { trk.beta (); }) {
2607- const bool hasTof = hasTOFMatch (trk);
2608- const float beta = trk.beta ();
2609- if (hasTof && beta > TofBetaMin && beta < TofBetaMax) {
2610- histos.fill (HIST (" hTOFBetaVsP_Pi" ), trk.p (), beta);
2611- }
2612- }
2613- break ;
2614- }
2615-
2616- case 1 : { // kaon
2617- if constexpr (requires { trk.tpcSignal (); }) {
2618- histos.fill (HIST (" hTPCdEdxVsP_K" ), trk.p (), trk.tpcSignal ());
2619- }
2620- if constexpr (requires { trk.beta (); }) {
2621- const bool hasTof = hasTOFMatch (trk);
2622- const float beta = trk.beta ();
2623- if (hasTof && beta > TofBetaMin && beta < TofBetaMax) {
2624- histos.fill (HIST (" hTOFBetaVsP_K" ), trk.p (), beta);
2625- }
2626- }
2627- break ;
2628- }
2629-
2630- case 2 : { // proton
2631- if constexpr (requires { trk.tpcSignal (); }) {
2632- histos.fill (HIST (" hTPCdEdxVsP_P" ), trk.p (), trk.tpcSignal ());
2633- }
2634- if constexpr (requires { trk.beta (); }) {
2635- const bool hasTof = hasTOFMatch (trk);
2636- const float beta = trk.beta ();
2637- if (hasTof && beta > TofBetaMin && beta < TofBetaMax) {
2638- histos.fill (HIST (" hTOFBetaVsP_P" ), trk.p (), beta);
2639- }
2640- }
2641- break ;
2642- }
2643-
2644- case 3 : { // deuteron
2645- if constexpr (requires { trk.tpcSignal (); }) {
2646- histos.fill (HIST (" hTPCdEdxVsP_D" ), trk.p (), trk.tpcSignal ());
2647- }
2648- if constexpr (requires { trk.beta (); }) {
2649- const bool hasTof = hasTOFMatch (trk);
2650- const float beta = trk.beta ();
2651- if (hasTof && beta > TofBetaMin && beta < TofBetaMax) {
2652- histos.fill (HIST (" hTOFBetaVsP_D" ), trk.p (), beta);
2653- }
2654- }
2655- break ;
2656- }
2657-
2658- default :
2659- break ;
2660- }
2661- }
2662- }
2663-
26642588 std::vector<KaonCand> kaonCands;
26652589 std::vector<ProxyCand> proxyCands;
26662590 std::vector<ProtonCand> protonCands;
@@ -2670,7 +2594,9 @@ struct Lambdastarproxy {
26702594
26712595 float eventMultFallback = 0 .f ; // fallback mixing variable: number of selected charged tracks (after quality cuts)
26722596
2673- // Inclusive PID QA loop: count all selected charged tracks for fallback multiplicity
2597+ // Inclusive track loop before final candidate PID cuts.
2598+ // It counts selected charged tracks for fallback multiplicity and when enabled,
2599+ // fills inclusive PID QA after track-quality cuts but before final K/p/d PID cuts.
26742600 for (auto const & trk : tracks) {
26752601 if (trk.pt () < lstarCutPtMin.value || std::abs (trk.eta ()) > lstarCutEtaMax.value ) {
26762602 continue ;
@@ -2769,23 +2695,44 @@ struct Lambdastarproxy {
27692695 const float etaD = trkD.eta ();
27702696 const float phiD = trkD.phi ();
27712697
2772- // PID for deuteron candidates
2698+ // PID for proxy candidates.
2699+ // Normal mode: use the standard deuteron PID and build p_proxy = p_d / 2.
2700+ // Closure/control mode: select the subset of standard deuteron-proxy candidates
2701+ // that are also proton-like. This tests proton contamination inside the deuteron
2702+ // selection, not all proton candidates.
2703+ const bool useProtonAsProxy = (lstarProxyUseProtonPIDAsDeuteron.value != 0 );
2704+
27732705 const float nsTPCDe = trkD.tpcNSigmaDe ();
27742706 const float nsTOFDe = trkD.tofNSigmaDe ();
27752707 const bool hasTofDe = hasTOFMatch (trkD);
2708+
27762709 if (!passOptionalDeuteronTOFExtras (trkD)) {
27772710 continue ;
27782711 }
2779- const bool isDeuteron = passFinalCandidatePID (trkD.pt (), trkD.tpcNSigmaDe (), nsTOFDe, hasTofDe,
2780- lstarCutNsigmaTPCDe.value , lstarCutNsigmaTOFDe.value ,
2781- lstarPidCircularCutDe.value , lstarPidPtRefDe.value , true );
2782- if (!isDeuteron) {
2712+
2713+ const bool passesDeuteronSelection = passFinalCandidatePID (ptD, nsTPCDe, nsTOFDe, hasTofDe,
2714+ lstarCutNsigmaTPCDe.value , lstarCutNsigmaTOFDe.value ,
2715+ lstarPidCircularCutDe.value , lstarPidPtRefDe.value ,
2716+ true );
2717+ if (!passesDeuteronSelection) {
27832718 continue ;
27842719 }
27852720
2721+ if (useProtonAsProxy) {
2722+ const float nsTPCPrAsProxy = trkD.tpcNSigmaPr ();
2723+ const float nsTOFPrAsProxy = trkD.tofNSigmaPr ();
2724+ const bool passesProtonSelection = passFinalCandidatePID (ptD, nsTPCPrAsProxy, nsTOFPrAsProxy, hasTofDe,
2725+ lstarCutNsigmaTPCPr.value , lstarCutNsigmaTOFPr.value ,
2726+ lstarPidCircularCutPr.value , lstarPidPtRefPr.value ,
2727+ false );
2728+ if (!passesProtonSelection) {
2729+ continue ;
2730+ }
2731+ }
2732+
27862733 const double pD = static_cast <double >(ptD) * std::cosh (static_cast <double >(etaD));
27872734
2788- // QA histos for deuteron PID and kinematics
2735+ // Candidate QA after final deuteron PID cut
27892736 if (lstarEnablePidQA.value != 0 ) {
27902737 histos.fill (HIST (" hDeuteronProxyPt" ), ptD);
27912738 histos.fill (HIST (" hDeuteronProxyEta" ), etaD);
0 commit comments