1717// / \author Tanu Gahlaut <tanu.gahlaut@cern.ch>
1818
1919#include " Common/CCDB/EventSelectionParams.h"
20+ #include " Common/Core/TrackSelection.h"
2021#include " Common/DataModel/Centrality.h"
2122#include " Common/DataModel/EventSelection.h"
2223#include " Common/DataModel/Multiplicity.h"
@@ -65,24 +66,31 @@ struct MeanPtFlucId {
6566 Configurable<float > cfgCutPtMax{" cfgCutPtMax" , 2.0 , " maximum pT" };
6667 Configurable<float > cfgCutPtMin{" cfgCutPtMin" , 0.2 , " minimum pT" };
6768 Configurable<float > cfgCutEta{" cfgCutEta" , 0.8 , " Eta cut" };
68- Configurable<float > cfgCutITSChi2NCl{" cfgCutITSChi2NCl" , 36.0 , " ITS Chi2/NCl cut" };
69- Configurable<float > cfgCutTPCChi2NCl{" cfgCutTPCChi2NCl" , 4.0 , " TPC Chi2/NCl cut" };
70- Configurable<float > cfgCutTPCNCls{" cfgCutTPCNCls" , 70.0 , " TPC NCls cut" };
7169 Configurable<float > cfgCutDCAxy{" cfgCutDCAxy" , 0.1 , " DCAxy cut" };
7270 Configurable<float > cfgCutDCAz{" cfgCutDCAz" , 0.2 , " DCAz cut" };
7371 Configurable<float > cfgDcaPtDepOffset{" cfgDcaPtDepOffset" , 0.004 , " Offset of the pT-dependent DCA cut (cm)" };
7472 Configurable<float > cfgDcaPtDepScale{" cfgDcaPtDepScale" , 0.013 , " 1/pT coefficient of the pT-dependent DCA cut (cm GeV/c)" };
75- Configurable<int > cfgCutNCrossedRowsTPC{" cfgCutNCrossedRowsTPC" , 70 , " Minimum number of crossed TPC rows" };
7673 Configurable<bool > cfgGlobalTrack{" cfgGlobalTrack" , true , " Require the standard global-track selection (includes its DCA cuts)" };
7774 Configurable<bool > cfgGlobalTrackWoDCA{" cfgGlobalTrackWoDCA" , false , " Require global-track quality without built-in DCA cuts; disable cfgGlobalTrack to use only this selection" };
78- Configurable<bool > cfgDcaXYPtDep{" cfgDcaXYPtDep" , true , " Apply the pT-dependent absolute DCAxy cut; takes precedence over cfgDcaXY" };
79- Configurable<bool > cfgNTPCCrossedRows{" cfgNTPCCrossedRows" , false , " Apply the minimum number of crossed TPC rows" };
80- Configurable<bool > cfgTPCChi2NCl{" cfgTPCChi2NCl" , false , " Chi2 per N_{TPC} Clusters Cut " };
81- Configurable<bool > cfgITSChi2NCl{" cfgITSChi2NCl" , false , " Chi2 per N_{ITS} Clusters Cut " };
8275 Configurable<bool > cfgDcaXY{" cfgDcaXY" , false , " DCA XY Cut " };
8376 Configurable<bool > cfgDcaZ{" cfgDcaZ" , false , " DCA Z Cut " };
77+ Configurable<bool > cfgDcaXYPtDep{" cfgDcaXYPtDep" , true , " Apply the pT-dependent absolute DCAxy cut; takes precedence over cfgDcaXY" };
8478 Configurable<bool > cfgDcaZPtDep{" cfgDcaZPtDep" , false , " DCA Z pT dependent Cut " };
8579 } trackCuts;
80+ struct : ConfigurableGroup {
81+ Configurable<bool > cfgUseCustomTrackSelection{" cfgUseCustomTrackSelection" , false , " Use custom Run 3 quality instead of global flags; shared acceptance and DCA cuts still apply" };
82+ Configurable<int > cfgCustomMinTPCClusters{" cfgCustomMinTPCClusters" , 0 , " Custom minimum TPC found clusters (global default: no additional minimum)" };
83+ Configurable<int > cfgCustomMinTPCCrossedRows{" cfgCustomMinTPCCrossedRows" , 70 , " Custom minimum TPC crossed rows" };
84+ Configurable<float > cfgCustomMinTPCCrossedRowsOverFindable{" cfgCustomMinTPCCrossedRowsOverFindable" , 0 .8f , " Custom minimum crossed rows / findable TPC clusters" };
85+ Configurable<float > cfgCustomMaxTPCChi2{" cfgCustomMaxTPCChi2" , 4 .f , " Custom maximum TPC chi2 per cluster" };
86+ Configurable<int > cfgCustomMinITSClusters{" cfgCustomMinITSClusters" , 0 , " Custom minimum ITS clusters, in addition to the selected hit pattern" };
87+ Configurable<float > cfgCustomMaxITSChi2{" cfgCustomMaxITSChi2" , 36 .f , " Custom maximum ITS chi2 per cluster" };
88+ Configurable<int > cfgCustomITSMatching{" cfgCustomITSMatching" , 1 , " Custom ITS hits: 1=any inner 3, 2=any of 7, 3=all 7, 4=first layer, 5=at least 2 inner" };
89+ Configurable<bool > cfgCustomRequireITS{" cfgCustomRequireITS" , true , " Require ITS information (Run 3 ITS-refit criterion)" };
90+ Configurable<bool > cfgCustomRequireTPC{" cfgCustomRequireTPC" , true , " Require TPC information (Run 3 TPC-refit criterion)" };
91+ } customTrackCuts;
92+
93+ TrackSelection mySelection;
8694 struct : ConfigurableGroup {
8795 Configurable<float > cfgCutPosZ{" cfgCutPosZ" , 7.0 , " cut for vertex Z" };
8896 Configurable<float > cfgP0U{" cfgP0U" , 6.36269 , " p_{0} for upper cut for N_{TPC} vs N{sim}" };
@@ -281,8 +289,64 @@ struct MeanPtFlucId {
281289 std::vector<double > matrixWInBin;
282290 std::vector<double > matrixW2InBin;
283291
292+ // Run 3 global quality baseline, with each systematic threshold set explicitly.
293+ TrackSelection myTrackSelection ()
294+ {
295+ constexpr int MinITSMatchingMode = 1 ;
296+ constexpr int MaxITSMatchingMode = 5 ;
297+ constexpr int NumberOfITSLayers = 7 ;
298+ const auto & cuts = customTrackCuts;
299+ auto finiteNonnegative = [](float value) { return std::isfinite (value) && value >= 0 .f ; };
300+ if (cuts.cfgCustomITSMatching .value < MinITSMatchingMode || cuts.cfgCustomITSMatching .value > MaxITSMatchingMode ||
301+ cuts.cfgCustomMinTPCClusters .value < 0 || cuts.cfgCustomMinTPCCrossedRows .value < 0 ||
302+ cuts.cfgCustomMinITSClusters .value < 0 || cuts.cfgCustomMinITSClusters .value > NumberOfITSLayers ||
303+ !finiteNonnegative (cuts.cfgCustomMinTPCCrossedRowsOverFindable .value ) ||
304+ !finiteNonnegative (cuts.cfgCustomMaxTPCChi2 .value ) || !finiteNonnegative (cuts.cfgCustomMaxITSChi2 .value )) {
305+ LOGF (fatal, " Invalid custom track-selection settings: check hit counts, ITS matching and nonnegative finite thresholds" );
306+ }
307+ if (!std::isfinite (trackCuts.cfgCutPtMin .value ) || !std::isfinite (trackCuts.cfgCutPtMax .value ) ||
308+ !std::isfinite (trackCuts.cfgCutEta .value ) || trackCuts.cfgCutPtMin .value <= 0 .f ||
309+ trackCuts.cfgCutPtMin .value >= trackCuts.cfgCutPtMax .value || trackCuts.cfgCutEta .value <= 0 .f ) {
310+ LOGF (fatal, " Custom selection requires finite 0 < pTmin < pTmax and etaMax > 0" );
311+ }
312+ TrackSelection selectedTracks;
313+ selectedTracks.SetTrackType (aod::track::TrackTypeEnum::Track); // Run 3 propagated tracks
314+ // Run 3 ITS layers: no Run 2 SPD requirement.
315+ switch (cuts.cfgCustomITSMatching .value ) {
316+ case 1 :
317+ selectedTracks.SetRequireHitsInITSLayers (1 , {0 , 1 , 2 });
318+ break ;
319+ case 2 :
320+ selectedTracks.SetRequireHitsInITSLayers (1 , {0 , 1 , 2 , 3 , 4 , 5 , 6 });
321+ break ;
322+ case 3 :
323+ selectedTracks.SetRequireHitsInITSLayers (7 , {0 , 1 , 2 , 3 , 4 , 5 , 6 });
324+ break ;
325+ case 4 :
326+ selectedTracks.SetRequireHitsInITSLayers (1 , {0 });
327+ break ;
328+ case 5 :
329+ selectedTracks.SetRequireHitsInITSLayers (2 , {0 , 1 , 2 });
330+ break ;
331+ }
332+ selectedTracks.SetRequireITSRefit (cuts.cfgCustomRequireITS .value );
333+ selectedTracks.SetRequireTPCRefit (cuts.cfgCustomRequireTPC .value );
334+ selectedTracks.SetMinNClustersTPC (cuts.cfgCustomMinTPCClusters .value );
335+ selectedTracks.SetMinNCrossedRowsTPC (cuts.cfgCustomMinTPCCrossedRows .value );
336+ selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC (cuts.cfgCustomMinTPCCrossedRowsOverFindable .value );
337+ selectedTracks.SetMaxChi2PerClusterTPC (cuts.cfgCustomMaxTPCChi2 .value );
338+ selectedTracks.SetMinNClustersITS (cuts.cfgCustomMinITSClusters .value );
339+ selectedTracks.SetMaxChi2PerClusterITS (cuts.cfgCustomMaxITSChi2 .value );
340+ return selectedTracks;
341+ }
342+
284343 void init (InitContext const &)
285344 {
345+ if (customTrackCuts.cfgUseCustomTrackSelection ) {
346+ mySelection = myTrackSelection ();
347+ LOGF (info, " Custom Run 3 quality replaces global flags; pT, eta and DCA cuts are applied in selTrack" );
348+ mySelection.print ();
349+ }
286350 if (!std::isfinite (pidConfig.cfgTofShiftPi .value ) || !std::isfinite (pidConfig.cfgTofShiftKa .value ) || !std::isfinite (pidConfig.cfgTofShiftPr .value )) {
287351 LOGF (fatal, " TOF nSigma shifts must be finite: pion=%g, kaon=%g, proton=%g" ,
288352 pidConfig.cfgTofShiftPi .value , pidConfig.cfgTofShiftKa .value , pidConfig.cfgTofShiftPr .value );
@@ -753,27 +817,41 @@ struct MeanPtFlucId {
753817 template <typename T>
754818 bool selTrack (T const & track)
755819 {
756- if (trackCuts.cfgGlobalTrack && !track.isGlobalTrack ()) {
757- return false ;
758- }
759-
760- if (trackCuts.cfgGlobalTrackWoDCA && !track.isGlobalTrackWoDCA ()) {
820+ // Shared analysis acceptance, evaluated once for either selection mode.
821+ if (!std::isfinite (track.pt ()) || !std::isfinite (track.eta ()) || track.pt () <= 0 .f ||
822+ track.pt () < trackCuts.cfgCutPtMin || track.pt () >= trackCuts.cfgCutPtMax ||
823+ std::abs (track.eta ()) >= trackCuts.cfgCutEta || track.sign () == 0 ) {
761824 return false ;
762825 }
763826
764- if (track.pt () < trackCuts.cfgCutPtMin ) {
765- return false ;
766- }
767-
768- if (track.pt () >= trackCuts.cfgCutPtMax ) {
769- return false ;
770- }
771-
772- if (track.sign () == 0 ) {
773- return false ;
827+ if (customTrackCuts.cfgUseCustomTrackSelection ) {
828+ // Acceptance is checked above with the analysis's exclusive upper bounds.
829+ // Only quality cuts belong to the custom selector; DCA is applied below.
830+ const bool isRun2 = TrackSelection::IsRun2Track (track);
831+ for (int i = 0 ; i < static_cast <int >(TrackSelection::TrackCuts::kNCuts ); ++i) {
832+ const auto cut = static_cast <TrackSelection::TrackCuts>(i);
833+ if (cut == TrackSelection::TrackCuts::kPtRange || cut == TrackSelection::TrackCuts::kEtaRange ||
834+ cut == TrackSelection::TrackCuts::kDCAxy || cut == TrackSelection::TrackCuts::kDCAz ) {
835+ continue ;
836+ }
837+ if (!mySelection.IsSelected (track, cut, isRun2)) {
838+ return false ;
839+ }
840+ }
841+ } else if (trackCuts.cfgGlobalTrack ) {
842+ if (!track.isGlobalTrack ()) {
843+ return false ;
844+ }
845+ } else if (trackCuts.cfgGlobalTrackWoDCA ) {
846+ if (!track.isGlobalTrackWoDCA ()) {
847+ return false ;
848+ }
774849 }
775850
776- const float maxDca = trackCuts.cfgDcaPtDepOffset + trackCuts.cfgDcaPtDepScale / track.pt ();
851+ // Shared DCA cuts, applied after either custom or standard quality selection.
852+ const float maxDca = (trackCuts.cfgDcaXYPtDep || trackCuts.cfgDcaZPtDep )
853+ ? trackCuts.cfgDcaPtDepOffset + trackCuts.cfgDcaPtDepScale / track.pt ()
854+ : 0 .f ;
777855
778856 if (trackCuts.cfgDcaXYPtDep ) {
779857 if (std::abs (track.dcaXY ()) >= maxDca) {
@@ -795,22 +873,6 @@ struct MeanPtFlucId {
795873 }
796874 }
797875
798- if (std::abs (track.eta ()) >= trackCuts.cfgCutEta ) {
799- return false ;
800- }
801-
802- if (trackCuts.cfgTPCChi2NCl && track.tpcChi2NCl () > trackCuts.cfgCutTPCChi2NCl ) {
803- return false ;
804- }
805-
806- if (trackCuts.cfgITSChi2NCl && track.itsChi2NCl () > trackCuts.cfgCutITSChi2NCl ) {
807- return false ;
808- }
809-
810- if (trackCuts.cfgNTPCCrossedRows && track.tpcNClsCrossedRows () < trackCuts.cfgCutNCrossedRowsTPC ) {
811- return false ;
812- }
813-
814876 return true ;
815877 }
816878
@@ -1498,11 +1560,12 @@ struct MeanPtFlucId {
14981560 eta = mcPart.eta ();
14991561 phi = mcPart.phi ();
15001562
1501- if (std::abs (eta) < trackCuts.cfgCutEta ) {
1502- nSim++ ;
1563+ if (!( std::abs (eta) < trackCuts.cfgCutEta ) ) {
1564+ continue ;
15031565 }
1566+ nSim++;
15041567
1505- if (pt >= trackCuts.cfgCutPtMin && pt < trackCuts.cfgCutPtMax && std::abs (eta) < trackCuts. cfgCutEta ) {
1568+ if (pt >= trackCuts.cfgCutPtMin && pt < trackCuts.cfgCutPtMax ) {
15061569 chargedTracksGen.push_back ({pt});
15071570 hist.fill (HIST (" Gen/Charged/h_PtTruth" ), pt);
15081571 hist.fill (HIST (" Gen/Charged/h_PtTruth_e" ), pt);
0 commit comments