@@ -72,17 +72,21 @@ struct MeanPtFlucId {
7272 Configurable<float > cfgCutNSig3{" cfgCutNSig3" , 3.0 , " nSigma cut: 3" };
7373 Configurable<float > cfgCutNSig5{" cfgCutNSig5" , 5.0 , " nSigma cut: 5" };
7474 Configurable<float > cfgCutNSigTpcTof{" cfgCutNSigTpcTof" , 3.0 , " nSigma TPC cut when TPC + TOF " };
75- Configurable<float > cfgSelCutNSigTpcPi{" cfgSelCutNSigTpcPi" , 2.0 , " nSigma TPC cut for pion selection" };
76- Configurable<float > cfgSelCutNSigTpcKa{" cfgSelCutNSigTpcKa" , 2.0 , " nSigma TPC cut for kaon selection" };
77- Configurable<float > cfgSelCutNSigTpcPr{" cfgSelCutNSigTpcPr" , 2.0 , " nSigma TPC cut for proton selection" };
78- Configurable<float > cfgSelCutNSigTofPi{" cfgSelCutNSigTofPi" , 2.0 , " nSigma TOF cut for pion selection" };
79- Configurable<float > cfgSelCutNSigTofKa{" cfgSelCutNSigTofKa" , 2.0 , " nSigma TOF cut for kaon selection" };
80- Configurable<float > cfgSelCutNSigTofPr{" cfgSelCutNSigTofPr" , 2.0 , " nSigma TOF cut for proton selection" };
75+ Configurable<float > cfgSelCutNSigTpcPi{" cfgSelCutNSigTpcPi" , 3.0 , " nSigma TPC cut for pion selection" };
76+ Configurable<float > cfgSelCutNSigTpcKa{" cfgSelCutNSigTpcKa" , 3.0 , " nSigma TPC cut for kaon selection" };
77+ Configurable<float > cfgSelCutNSigTpcPr{" cfgSelCutNSigTpcPr" , 3.0 , " nSigma TPC cut for proton selection" };
78+ Configurable<float > cfgSelCutNSigTofPi{" cfgSelCutNSigTofPi" , 3.0 , " nSigma TOF cut for pion selection" };
79+ Configurable<float > cfgSelCutNSigTofKa{" cfgSelCutNSigTofKa" , 3.0 , " nSigma TOF cut for kaon selection" };
80+ Configurable<float > cfgSelCutNSigTofPr{" cfgSelCutNSigTofPr" , 3.0 , " nSigma TOF cut for proton selection" };
81+ // Signed TOF nSigma offsets: corrected = raw - shift. Zero preserves the original PID.
82+ Configurable<float > cfgTofShiftPi{" cfgTofShiftPi" , 0 .f , " Pion TOF nSigma offset to subtract (not a time shift in ps)" };
83+ Configurable<float > cfgTofShiftKa{" cfgTofShiftKa" , 0 .f , " Kaon TOF nSigma offset to subtract (not a time shift in ps)" };
84+ Configurable<float > cfgTofShiftPr{" cfgTofShiftPr" , 0 .f , " Proton TOF nSigma offset to subtract (not a time shift in ps)" };
8185 Configurable<float > cfgCutPiPtMin{" cfgCutPiPtMin" , 0.2 , " Minimum pion p_{T} cut" };
8286 Configurable<float > cfgCutKaPtMin{" cfgCutKaPtMin" , 0.3 , " Minimum kaon p_{T} cut" };
8387 Configurable<float > cfgCutPrPtMin{" cfgCutPrPtMin" , 0.5 , " Minimum proton p_{T} cut" };
8488 Configurable<float > cfgCutPiThrsldP{" cfgCutPiThrsldP" , 0.7 , " Momentum threshold for requiring pion TOF PID" };
85- Configurable<float > cfgCutKaThrsldP{" cfgCutKaThrsldP" , 0.8 , " Momentum threshold for requiring kaon TOF PID" };
89+ Configurable<float > cfgCutKaThrsldP{" cfgCutKaThrsldP" , 0.55 , " Momentum threshold for requiring kaon TOF PID" };
8690 Configurable<float > cfgCutPrThrsldP{" cfgCutPrThrsldP" , 0.8 , " Momentum threshold for requiring proton TOF PID" };
8791 Configurable<float > cfgP0U{" cfgP0U" , 6.36269 , " p_{0} for upper cut for N_{TPC} vs N{sim}" };
8892 Configurable<float > cfgP1U{" cfgP1U" , 2.22108 , " p_{1} for upper cut for N_{TPC} vs N{sim}" };
@@ -240,6 +244,10 @@ struct MeanPtFlucId {
240244
241245 void init (InitContext const &)
242246 {
247+ if (!std::isfinite (cfgTofShiftPi.value ) || !std::isfinite (cfgTofShiftKa.value ) || !std::isfinite (cfgTofShiftPr.value )) {
248+ LOGF (fatal, " TOF nSigma shifts must be finite: pion=%g, kaon=%g, proton=%g" ,
249+ cfgTofShiftPi.value , cfgTofShiftKa.value , cfgTofShiftPr.value );
250+ }
243251
244252 if (nPtBins <= 0 || cfgCutPtMin >= cfgCutPtMax || cfgCutPiPtMin >= cfgCutPtMax ||
245253 cfgCutKaPtMin >= cfgCutPtMax || cfgCutPrPtMin >= cfgCutPtMax) {
@@ -418,7 +426,7 @@ struct MeanPtFlucId {
418426 hist.add (" QA/Charged/h2_Pt_Eta" , " p_{T} vs #eta " , kTH2D , {{axisEta}, {axisPtCh}});
419427 hist.add (" QA/Charged/h3_Pt_Eta_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtCh}, {axisCent}});
420428 hist.add (" QA/Charged/h3_Pt_EtaMC_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtCh}, {axisCent}});
421- hist.add (" QA/Charged/h3_Pt_EtaMC_primary_centFT0M " , " Selected primary MC particles;#eta_{MC} ;p_{T,MC };FT0M (%)" , kTH3D , {{axisEta}, {axisPtCh}, {axisCent}});
429+ hist.add (" QA/Charged/h3_Pt_EtaTruth_primary_centFT0M " , " Selected truth primary tracks in reconstructed coordinates;#eta ;p_{T};FT0M (%)" , kTH3D , {{axisEta}, {axisPtCh}, {axisCent}});
422430 hist.add (" QA/Charged/h2_Pt_EtaMC" , " p_{T} vs #eta (MC)" , kTH2D , {{axisEta}, {axisPtCh}});
423431 };
424432 addTrackQAHistograms ();
@@ -429,7 +437,7 @@ struct MeanPtFlucId {
429437 hist.add (" QA/Pion/h2_Pt_Eta" , " p_{T} vs #eta " , kTH2D , {{axisEta}, {axisPtPi}});
430438 hist.add (" QA/Pion/h3_Pt_Eta_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtPi}, {axisCent}});
431439 hist.add (" QA/Pion/h3_Pt_EtaMC_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtPi}, {axisCent}});
432- hist.add (" QA/Pion/h3_Pt_EtaMC_primary_centFT0M " , " Correctly selected primary pions;#eta_{MC} ;p_{T,MC };FT0M (%)" , kTH3D , {{axisEta}, {axisPtPi}, {axisCent}});
440+ hist.add (" QA/Pion/h3_Pt_EtaTruth_primary_centFT0M " , " Selected truth primary tracks in reconstructed coordinates;#eta ;p_{T};FT0M (%)" , kTH3D , {{axisEta}, {axisPtPi}, {axisCent}});
433441 hist.add (" QA/Pion/h2_Pt_EtaMC" , " p_{T} vs #eta (MC)" , kTH2D , {{axisEta}, {axisPtPi}});
434442 hist.add (" QA/Pion/h_PtPos" , " p_{T} (positive) " , kTH1D , {axisPtPi});
435443 hist.add (" QA/Pion/h_PtNeg" , " p_{T} (negative) " , kTH1D , {axisPtPi});
@@ -446,7 +454,7 @@ struct MeanPtFlucId {
446454 hist.add (" QA/Kaon/h2_Pt_Eta" , " p_{T} vs #eta " , kTH2D , {{axisEta}, {axisPtKa}});
447455 hist.add (" QA/Kaon/h3_Pt_Eta_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtKa}, {axisCent}});
448456 hist.add (" QA/Kaon/h3_Pt_EtaMC_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtKa}, {axisCent}});
449- hist.add (" QA/Kaon/h3_Pt_EtaMC_primary_centFT0M " , " Correctly selected primary kaons;#eta_{MC} ;p_{T,MC };FT0M (%)" , kTH3D , {{axisEta}, {axisPtKa}, {axisCent}});
457+ hist.add (" QA/Kaon/h3_Pt_EtaTruth_primary_centFT0M " , " Selected truth primary tracks in reconstructed coordinates;#eta ;p_{T};FT0M (%)" , kTH3D , {{axisEta}, {axisPtKa}, {axisCent}});
450458 hist.add (" QA/Kaon/h2_Pt_EtaMC" , " p_{T} vs #eta (MC)" , kTH2D , {{axisEta}, {axisPtKa}});
451459 hist.add (" QA/Kaon/h_PtPos" , " p_{T} (positive) " , kTH1D , {axisPtKa});
452460 hist.add (" QA/Kaon/h_PtNeg" , " p_{T} (negative) " , kTH1D , {axisPtKa});
@@ -463,7 +471,7 @@ struct MeanPtFlucId {
463471 hist.add (" QA/Proton/h2_Pt_Eta" , " p_{T} vs #eta " , kTH2D , {{axisEta}, {axisPtPr}});
464472 hist.add (" QA/Proton/h3_Pt_Eta_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtPr}, {axisCent}});
465473 hist.add (" QA/Proton/h3_Pt_EtaMC_centFT0M" , " p_{T} vs #eta in centrality classes" , kTH3D , {{axisEta}, {axisPtPr}, {axisCent}});
466- hist.add (" QA/Proton/h3_Pt_EtaMC_primary_centFT0M " , " Correctly selected primary protons;#eta_{MC} ;p_{T,MC };FT0M (%)" , kTH3D , {{axisEta}, {axisPtPr}, {axisCent}});
474+ hist.add (" QA/Proton/h3_Pt_EtaTruth_primary_centFT0M " , " Selected truth primary tracks in reconstructed coordinates;#eta ;p_{T};FT0M (%)" , kTH3D , {{axisEta}, {axisPtPr}, {axisCent}});
467475 hist.add (" QA/Proton/h2_Pt_EtaMC" , " p_{T} vs #eta (MC)" , kTH2D , {{axisEta}, {axisPtPr}});
468476 hist.add (" QA/Proton/h_PtPos" , " p_{T} (positive) " , kTH1D , {axisPtPr});
469477 hist.add (" QA/Proton/h_PtNeg" , " p_{T} (negative) " , kTH1D , {axisPtPr});
@@ -689,12 +697,25 @@ struct MeanPtFlucId {
689697 std::fabs (track.tpcNSigmaPr ()) > cfgCutNSig3);
690698 }
691699
700+ // Share the corrected hypotheses between PID selection and selected-particle QA.
701+ // The before-PID histograms intentionally retain raw values for calibration.
702+ template <typename T>
703+ std::array<float , 4 > getTofNSigmaForPid (T const & track) const
704+ {
705+ std::array<float , 4 > values = {-999 .f , track.tofNSigmaPi (), track.tofNSigmaKa (), track.tofNSigmaPr ()};
706+ if (track.hasTOF ()) {
707+ values[static_cast <int >(PIDType::kPions )] -= cfgTofShiftPi.value ;
708+ values[static_cast <int >(PIDType::kKaons )] -= cfgTofShiftKa.value ;
709+ values[static_cast <int >(PIDType::kProtons )] -= cfgTofShiftPr.value ;
710+ }
711+ return values;
712+ }
713+
692714 // PID cuts for identified particles
693715 template <typename T>
694- bool identifyParticle (T const & track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold)
716+ bool identifyParticle (T const & track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold, const std::array< float , 4 >& tofNSigma )
695717 {
696718 const std::array<float , 4 > tpcNSigma = {-999 .f , track.tpcNSigmaPi (), track.tpcNSigmaKa (), track.tpcNSigmaPr ()};
697- const std::array<float , 4 > tofNSigma = {-999 .f , track.tofNSigmaPi (), track.tofNSigmaKa (), track.tofNSigmaPr ()};
698719
699720 const int selSpecies = static_cast <int >(species);
700721 const int rejSpecies1 = static_cast <int >(reject1);
@@ -1092,9 +1113,10 @@ struct MeanPtFlucId {
10921113 float nSigmaTPCPi = track.tpcNSigmaPi ();
10931114 float nSigmaTPCKa = track.tpcNSigmaKa ();
10941115 float nSigmaTPCPr = track.tpcNSigmaPr ();
1095- float nSigmaTOFPi = track.tofNSigmaPi ();
1096- float nSigmaTOFKa = track.tofNSigmaKa ();
1097- float nSigmaTOFPr = track.tofNSigmaPr ();
1116+ const auto tofNSigma = getTofNSigmaForPid (track);
1117+ const float nSigmaTOFPi = tofNSigma[static_cast <int >(PIDType::kPions )];
1118+ const float nSigmaTOFKa = tofNSigma[static_cast <int >(PIDType::kKaons )];
1119+ const float nSigmaTOFPr = tofNSigma[static_cast <int >(PIDType::kProtons )];
10981120 float rapPi = track.rapidity (MassPiPlus);
10991121 float rapKa = track.rapidity (MassKPlus);
11001122 float rapPr = track.rapidity (MassProton);
@@ -1129,16 +1151,13 @@ struct MeanPtFlucId {
11291151 hist.fill (HIST (" QA/after/h_DCAxy_primary" ), track.dcaXY ());
11301152 hist.fill (HIST (" QA/after/h_DCAz_primary" ), track.dcaZ ());
11311153 hist.fill (HIST (" QA/Charged/h_PtTruth_primary" ), track.pt ());
1132- const bool mcInChargedAcceptance = ptMC >= cfgCutPtMin && ptMC < cfgCutPtMax && std::abs (etaMC) < cfgCutEta;
1133- if (mcInChargedAcceptance) {
1134- hist.fill (HIST (" QA/Charged/h3_Pt_EtaMC_primary_centFT0M" ), etaMC, ptMC, centFT0M);
1135- if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1136- double weight = 0 .;
1137- if (!getEfficiencyWeight (PIDType::kNone , ptMC, etaMC, weight)) {
1138- LOGF (fatal, " Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g" , ptMC, etaMC, centFT0M);
1139- }
1140- chargedTracksTruthMatchedCorrected.push_back ({ptMC, weight});
1154+ hist.fill (HIST (" QA/Charged/h3_Pt_EtaTruth_primary_centFT0M" ), track.eta (), track.pt (), centFT0M);
1155+ if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1156+ double weight = 0 .;
1157+ if (!getEfficiencyWeight (PIDType::kNone , pt, eta, weight)) {
1158+ LOGF (fatal, " Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g" , pt, eta, centFT0M);
11411159 }
1160+ chargedTracksTruthMatchedCorrected.push_back ({pt, weight});
11421161 }
11431162 } else {
11441163 hist.fill (HIST (" QA/after/h_DCAxy_secondary" ), track.dcaXY ());
@@ -1169,9 +1188,9 @@ struct MeanPtFlucId {
11691188 if (cfgRejTrk && rejectTracks (track)) {
11701189 continue ;
11711190 }
1172- auto selIDPion = identifyParticle (track, PIDType::kPions , PIDType::kKaons , PIDType::kProtons , p, cfgCutPiThrsldP);
1173- auto selIDKaon = identifyParticle (track, PIDType::kKaons , PIDType::kPions , PIDType::kProtons , p, cfgCutKaThrsldP);
1174- auto selIDProton = identifyParticle (track, PIDType::kProtons , PIDType::kPions , PIDType::kKaons , p, cfgCutPrThrsldP);
1191+ auto selIDPion = identifyParticle (track, PIDType::kPions , PIDType::kKaons , PIDType::kProtons , p, cfgCutPiThrsldP, tofNSigma );
1192+ auto selIDKaon = identifyParticle (track, PIDType::kKaons , PIDType::kPions , PIDType::kProtons , p, cfgCutKaThrsldP, tofNSigma );
1193+ auto selIDProton = identifyParticle (track, PIDType::kProtons , PIDType::kPions , PIDType::kKaons , p, cfgCutPrThrsldP, tofNSigma );
11751194
11761195 if (selIDPion && track.pt () >= cfgCutPiPtMin) {
11771196 if (cfgApplyEfficiencyCorrection) {
@@ -1213,17 +1232,14 @@ struct MeanPtFlucId {
12131232 fillPtMCHist<QA_Pion>(false , pt, eta, rapPi, phi, pid, kPiPlus , kPiMinus );
12141233 if (mc.isPhysicalPrimary ()) {
12151234 hist.fill (HIST (" QA/Pion/h_PtTruth_primary" ), track.pt ());
1235+ hist.fill (HIST (" QA/Pion/h3_Pt_EtaTruth_primary_centFT0M" ), track.eta (), track.pt (), centFT0M);
12161236 hist.fill (HIST (" QA/Pion/h2_Pt_EtaTruth_primary" ), track.eta (), track.pt ());
1217- const bool mcInPionAcceptance = ptMC >= cfgCutPiPtMin && ptMC < cfgCutPtMax && std::abs (etaMC) < cfgCutEta;
1218- if (mcInPionAcceptance) {
1219- hist.fill (HIST (" QA/Pion/h3_Pt_EtaMC_primary_centFT0M" ), etaMC, ptMC, centFT0M);
1220- if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1221- double weight = 0 .;
1222- if (!getEfficiencyWeight (PIDType::kPions , ptMC, etaMC, weight)) {
1223- LOGF (fatal, " Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g" , ptMC, etaMC, centFT0M);
1224- }
1225- pionTracksTruthMatchedCorrected.push_back ({ptMC, weight});
1237+ if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1238+ double weight = 0 .;
1239+ if (!getEfficiencyWeight (PIDType::kPions , pt, eta, weight)) {
1240+ LOGF (fatal, " Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g" , pt, eta, centFT0M);
12261241 }
1242+ pionTracksTruthMatchedCorrected.push_back ({pt, weight});
12271243 }
12281244 } else {
12291245 hist.fill (HIST (" QA/Pion/h_PtTruth_secondary" ), track.pt ());
@@ -1236,17 +1252,14 @@ struct MeanPtFlucId {
12361252 fillPtMCHist<QA_Kaon>(false , pt, eta, rapKa, phi, pid, kKPlus , kKMinus );
12371253 if (mc.isPhysicalPrimary ()) {
12381254 hist.fill (HIST (" QA/Kaon/h_PtTruth_primary" ), track.pt ());
1255+ hist.fill (HIST (" QA/Kaon/h3_Pt_EtaTruth_primary_centFT0M" ), track.eta (), track.pt (), centFT0M);
12391256 hist.fill (HIST (" QA/Kaon/h2_Pt_EtaTruth_primary" ), track.eta (), track.pt ());
1240- const bool mcInKaonAcceptance = ptMC >= cfgCutKaPtMin && ptMC < cfgCutPtMax && std::abs (etaMC) < cfgCutEta;
1241- if (mcInKaonAcceptance) {
1242- hist.fill (HIST (" QA/Kaon/h3_Pt_EtaMC_primary_centFT0M" ), etaMC, ptMC, centFT0M);
1243- if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1244- double weight = 0 .;
1245- if (!getEfficiencyWeight (PIDType::kKaons , ptMC, etaMC, weight)) {
1246- LOGF (fatal, " Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g" , ptMC, etaMC, centFT0M);
1247- }
1248- kaonTracksTruthMatchedCorrected.push_back ({ptMC, weight});
1257+ if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1258+ double weight = 0 .;
1259+ if (!getEfficiencyWeight (PIDType::kKaons , pt, eta, weight)) {
1260+ LOGF (fatal, " Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g" , pt, eta, centFT0M);
12491261 }
1262+ kaonTracksTruthMatchedCorrected.push_back ({pt, weight});
12501263 }
12511264 } else {
12521265 hist.fill (HIST (" QA/Kaon/h_PtTruth_secondary" ), track.pt ());
@@ -1259,17 +1272,14 @@ struct MeanPtFlucId {
12591272 fillPtMCHist<QA_Proton>(false , pt, eta, rapPr, phi, pid, kProton , kProtonBar );
12601273 if (mc.isPhysicalPrimary ()) {
12611274 hist.fill (HIST (" QA/Proton/h_PtTruth_primary" ), track.pt ());
1275+ hist.fill (HIST (" QA/Proton/h3_Pt_EtaTruth_primary_centFT0M" ), track.eta (), track.pt (), centFT0M);
12621276 hist.fill (HIST (" QA/Proton/h2_Pt_EtaTruth_primary" ), track.eta (), track.pt ());
1263- const bool mcInProtonAcceptance = ptMC >= cfgCutPrPtMin && ptMC < cfgCutPtMax && std::abs (etaMC) < cfgCutEta;
1264- if (mcInProtonAcceptance) {
1265- hist.fill (HIST (" QA/Proton/h3_Pt_EtaMC_primary_centFT0M" ), etaMC, ptMC, centFT0M);
1266- if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1267- double weight = 0 .;
1268- if (!getEfficiencyWeight (PIDType::kProtons , ptMC, etaMC, weight)) {
1269- LOGF (fatal, " Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g" , ptMC, etaMC, centFT0M);
1270- }
1271- protonTracksTruthMatchedCorrected.push_back ({ptMC, weight});
1277+ if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
1278+ double weight = 0 .;
1279+ if (!getEfficiencyWeight (PIDType::kProtons , pt, eta, weight)) {
1280+ LOGF (fatal, " Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g" , pt, eta, centFT0M);
12721281 }
1282+ protonTracksTruthMatchedCorrected.push_back ({pt, weight});
12731283 }
12741284 } else {
12751285 hist.fill (HIST (" QA/Proton/h_PtTruth_secondary" ), track.pt ());
0 commit comments