2222#include " Common/DataModel/Multiplicity.h"
2323#include " Common/DataModel/TrackSelectionTables.h"
2424
25+ #include < CCDB/BasicCCDBManager.h>
2526#include < CommonConstants/MathConstants.h>
27+ #include < DataFormatsParameters/GRPMagField.h>
2628#include < Framework/AnalysisDataModel.h>
2729#include < Framework/AnalysisHelpers.h>
2830#include < Framework/AnalysisTask.h>
3638#include < Framework/runDataProcessing.h>
3739
3840#include < TH1.h>
41+ #include < TH2.h>
42+ #include < TH3.h>
43+ #include < TMCProcess.h>
3944#include < TPDGCode.h>
45+ #include < TProfile.h>
46+ #include < TString.h>
47+ #include < TVector3.h>
4048
4149#include < algorithm>
50+ #include < array>
51+ #include < chrono>
4252#include < cmath>
53+ #include < cstddef>
4354#include < cstdint>
55+ #include < cstdio>
4456#include < cstdlib>
57+ #include < memory>
58+ #include < string>
4559#include < vector>
4660
4761using namespace o2 ;
@@ -110,10 +124,6 @@ static constexpr TrackSelectionFlags::flagtype TrackSelectionTpc =
110124 TrackSelectionFlags::kTPCNCls |
111125 TrackSelectionFlags::kTPCCrossedRowsOverNCls |
112126 TrackSelectionFlags::kTPCChi2NDF ;
113- static constexpr TrackSelectionFlags::flagtype TrackSelectionDca =
114- TrackSelectionFlags::kDCAz | TrackSelectionFlags::kDCAxy ;
115- static constexpr TrackSelectionFlags::flagtype TrackSelectionDcaxyOnly =
116- TrackSelectionFlags::kDCAxy ;
117127
118128AxisSpec axisEvent{15 , 0.5 , 15.5 , " #Event" , " EventAxis" };
119129AxisSpec axisVtxZ{40 , -20 , 20 , " Vertex Z" , " VzAxis" };
@@ -133,20 +143,46 @@ struct PtmultCorr {
133143
134144 HistogramRegistry histos{" histos" , {}, OutputObjHandlingPolicy::AnalysisObject};
135145 Service<o2::framework::O2DatabasePDG> pdg;
146+ Service<ccdb::BasicCCDBManager> ccdb;
136147 Preslice<TrackMCRecTable> perCollision = aod::track::collisionId;
137- Configurable<float > etaRange{" etaRange" , 1 . 0f , " Eta range to consider" };
148+ Configurable<float > etaRange{" etaRange" , 0 . 8f , " Eta range to consider" };
138149 Configurable<float > vtxRange{" vtxRange" , 10 .0f , " Vertex Z range to consider" };
139150 Configurable<float > occuRange{" occuRange" , 500 .0f , " Occupancy range to consider" };
140- Configurable<float > dcaZ{ " dcaZ " , 0 .2f , " Custom DCA Z cut (ignored if negative) " };
141- Configurable<float > cfgPtCutMin{ " cfgPtCutMin " , 0 . 15f , " minimum accepted track pT" };
151+ Configurable<float > cfgPtCutMin{ " cfgPtCutMin " , 0 .1f , " minimum accepted track pT " };
152+ Configurable<float > cfgPtCutMax{ " cfgPtCutMax " , 1e9f , " maximum accepted track pT" };
142153 Configurable<float > extraphicut1{" extraphicut1" , 3 .07666f , " Extra Phi cut 1" };
143154 Configurable<float > extraphicut2{" extraphicut2" , 3 .12661f , " Extra Phi cut 2" };
144155 Configurable<float > extraphicut3{" extraphicut3" , 0 .03f , " Extra Phi cut 3" };
145156 Configurable<float > extraphicut4{" extraphicut4" , 6 .253f , " Extra Phi cut 4" };
157+
158+ // Track quality cuts (matching piKpRAA analysis)
159+ Configurable<uint8_t > cfgMinNClusITS{" cfgMinNClusITS" , 7 , " Minimum ITS clusters" };
160+ Configurable<int16_t > cfgMinNCrossedRows{" cfgMinNCrossedRows" , 70 , " Minimum TPC crossed rows" };
161+ Configurable<int16_t > cfgMinNcls{" cfgMinNcls" , 130 , " Minimum TPC clusters (applied only if cfgApplyNclSel is true)" };
162+ Configurable<bool > cfgApplyNclSel{" cfgApplyNclSel" , true , " Enable minimum TPC cluster selection" };
163+ Configurable<bool > cfgUseNclsPID{" cfgUseNclsPID" , false , " Use NclsPID instead of NclsFound for the Ncls cut" };
164+ Configurable<float > cfgMinChi2ClsTPC{" cfgMinChi2ClsTPC" , 0 .5f , " Minimum TPC chi2/cls" };
165+ Configurable<float > cfgMaxChi2ClsTPC{" cfgMaxChi2ClsTPC" , 4 .0f , " Maximum TPC chi2/cls" };
166+ Configurable<float > cfgMaxChi2ClsITS{" cfgMaxChi2ClsITS" , 36 .0f , " Maximum ITS chi2/cls" };
167+ Configurable<float > cfgNSigmaDCAxy{" cfgNSigmaDCAxy" , 1 .0f , " nSigma scaling for DCAxy cut" };
168+ Configurable<float > cfgNSigmaDCAz{" cfgNSigmaDCAz" , 1 .0f , " nSigma scaling for DCAz cut" };
169+
170+ // CCDB paths for pT-dependent DCA cuts
171+ Configurable<std::string> pathDCAxy{" pathDCAxy" , " " , " CCDB path for DCAxy parametrisation (leave empty to skip)" };
172+ Configurable<std::string> pathDCAz{" pathDCAz" , " " , " CCDB path for DCAz parametrisation (leave empty to skip)" };
173+ Configurable<int64_t > ccdbNoLaterThan{" ccdbNoLaterThan" , std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count (), " latest acceptable CCDB timestamp" };
174+
146175 ConfigurableAxis ptHistBin{" ptHistBin" , {200 , 0 ., 20 .}, " " };
147176 ConfigurableAxis centralityBinning{" centralityBinning" , {VARIABLE_WIDTH, 0 , 5 , 10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 , 100 }, " " };
148177 ConfigurableAxis binsImpactPar{" binsImpactPar" , {VARIABLE_WIDTH, 0.0 , 3.00065 , 4.28798 , 6.14552 , 7.6196 , 8.90942 , 10.0897 , 11.2002 , 12.2709 , 13.3167 , 14.4173 , 23.2518 }, " Binning of the impact parameter axis" };
149178
179+ // DCA cache (loaded from CCDB)
180+ struct ConfigDCA {
181+ TH1F* hDCAxy = nullptr ;
182+ TH1F* hDCAz = nullptr ;
183+ bool loaded = false ;
184+ } cfgDCA;
185+
150186 Configurable<bool > isApplySameBunchPileup{" isApplySameBunchPileup" , false , " Enable SameBunchPileup cut" };
151187 Configurable<bool > isApplyGoodZvtxFT0vsPV{" isApplyGoodZvtxFT0vsPV" , false , " Enable GoodZvtxFT0vsPV cut" };
152188 Configurable<bool > isApplyExtraPhiCut{" isApplyExtraPhiCut" , false , " Enable extra phi cut" };
@@ -159,6 +195,19 @@ struct PtmultCorr {
159195
160196 void init (InitContext const &)
161197 {
198+ // Load DCA parametrisations from CCDB (matching piKpRAA)
199+ if (!pathDCAxy.value .empty ()) {
200+ cfgDCA.hDCAxy = ccdb->getForTimeStamp <TH1F>(pathDCAxy, ccdbNoLaterThan);
201+ if (cfgDCA.hDCAxy == nullptr )
202+ LOGF (fatal, " Could not load DCAxy histogram from %s" , pathDCAxy.value .c_str ());
203+ }
204+ if (!pathDCAz.value .empty ()) {
205+ cfgDCA.hDCAz = ccdb->getForTimeStamp <TH1F>(pathDCAz, ccdbNoLaterThan);
206+ if (cfgDCA.hDCAz == nullptr )
207+ LOGF (fatal, " Could not load DCAz histogram from %s" , pathDCAz.value .c_str ());
208+ }
209+ if (cfgDCA.hDCAxy && cfgDCA.hDCAz )
210+ cfgDCA.loaded = true ;
162211 AxisSpec centAxis = {centralityBinning, " Centrality" , " CentralityAxis" };
163212 AxisSpec axisPt = {ptHistBin, " pT" , " pTAxis" };
164213 AxisSpec impactParAxis = {binsImpactPar, " Impact Parameter" };
@@ -290,9 +339,59 @@ struct PtmultCorr {
290339 template <typename CheckTrack>
291340 bool isTrackSelected (CheckTrack const & track)
292341 {
342+ // --- eta (applied to all track types) ---
293343 if (std::abs (track.eta ()) >= etaRange) {
294344 return false ;
295345 }
346+
347+ // --- pT (applied to all track types) ---
348+ if (track.pt () < cfgPtCutMin || track.pt () > cfgPtCutMax) {
349+ return false ;
350+ }
351+
352+ if (track.hasTPC ()) {
353+ // ---- Global (ITS+TPC) tracks:
354+
355+ // ITS inner-barrel hit: must fire layer 0 or layer 1
356+ if (!(track.itsClusterMap () & 0x01 ) && !(track.itsClusterMap () & 0x02 )) {
357+ return false ;
358+ }
359+ if (track.itsNCls () < cfgMinNClusITS) {
360+ return false ;
361+ }
362+ if (track.tpcNClsCrossedRows () < cfgMinNCrossedRows) {
363+ return false ;
364+ }
365+ // optional minimum TPC clusters (found or PID, matching piKpRAA applyNclSel)
366+ if (cfgApplyNclSel) {
367+ const int16_t ncl = cfgUseNclsPID ? track.tpcNClsPID () : track.tpcNClsFound ();
368+ if (ncl < cfgMinNcls) {
369+ return false ;
370+ }
371+ }
372+ if (track.tpcChi2NCl () < cfgMinChi2ClsTPC || track.tpcChi2NCl () > cfgMaxChi2ClsTPC) {
373+ return false ;
374+ }
375+ if (track.itsChi2NCl () > cfgMaxChi2ClsITS) {
376+ return false ;
377+ }
378+ // pT-dependent DCA cuts from CCDB
379+ if (cfgDCA.loaded ) {
380+ const float pt = track.pt ();
381+ const double dcaXYcut = cfgNSigmaDCAxy * (cfgDCA.hDCAxy ->GetBinContent (1 ) +
382+ cfgDCA.hDCAxy ->GetBinContent (2 ) /
383+ std::pow (std::abs (pt), cfgDCA.hDCAxy ->GetBinContent (3 )));
384+ const double dcaZcut = cfgNSigmaDCAz * (cfgDCA.hDCAz ->GetBinContent (1 ) +
385+ cfgDCA.hDCAz ->GetBinContent (2 ) /
386+ std::pow (std::abs (pt), cfgDCA.hDCAz ->GetBinContent (3 )));
387+ if (std::abs (track.dcaZ ()) > dcaZcut || std::abs (track.dcaXY ()) > dcaXYcut) {
388+ return false ;
389+ }
390+ }
391+ }
392+ // ITS-only tracks: quality already ensured by the framework-level fTrackSelectionITS filter
393+
394+ // --- optional phi cut (applied to all track types) ---
296395 histos.fill (HIST (" PhiVsEtaHistNoCut" ), track.phi (), track.eta ());
297396 if (isApplyExtraPhiCut && ((track.phi () > extraphicut1 && track.phi () < extraphicut2) || track.phi () <= extraphicut3 || track.phi () >= extraphicut4)) {
298397 return false ;
@@ -330,8 +429,7 @@ struct PtmultCorr {
330429 ncheckbit (aod::track::trackCutFlag, TrackSelectionIts);
331430 Filter fTrackSelectionTPC = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t )o2::aod::track::TPC),
332431 ncheckbit (aod::track::trackCutFlag, TrackSelectionTpc), true );
333- Filter fTrackSelectionDCA = ifnode(dcaZ.node() > 0 .f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly),
334- ncheckbit (aod::track::trackCutFlag, TrackSelectionDca));
432+ // DCA is now applied manually inside isTrackSelected() using pT-dependent CCDB parametrisation
335433 Filter fTracksPt = aod::track::pt > cfgPtCutMin;
336434
337435 void processDataPbPb (ColDataTablePbPb::iterator const & cols, FilTrackDataTable const & tracks)
0 commit comments