2929#include " Common/DataModel/FT0Corrected.h"
3030#include " Common/DataModel/Multiplicity.h"
3131#include " Common/DataModel/PIDResponse.h"
32+ #include " Common/DataModel/PIDResponseITS.h"
3233#include " Common/DataModel/TrackSelectionTables.h"
3334
3435#include " CommonConstants/MathConstants.h"
4445#include " Framework/RunningWorkflowInfo.h"
4546#include " Framework/StepTHn.h"
4647#include " Framework/runDataProcessing.h"
48+ #include " ReconstructionDataFormats/PID.h"
49+ #include " ReconstructionDataFormats/Track.h"
4750#include < CCDB/BasicCCDBManager.h>
4851
4952#include " TF1.h"
@@ -59,9 +62,12 @@ using namespace o2::framework::expressions;
5962
6063// define the filtered collisions and tracks
6164#define O2_DEFINE_CONFIGURABLE (NAME, TYPE, DEFAULT, HELP ) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP};
65+ // template for labelled array
66+ static constexpr float LongArrayFloat[3 ][20 ] = {{1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 }, {2.1 , 2.2 , 2.3 , -2.1 , -2.2 , -2.3 , 1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 }, {3.1 , 3.2 , 3.3 , -3.1 , -3.2 , -3.3 , 1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 , 1.3 , -1.1 , -1.2 , -1.3 , 1.1 , 1.2 }};
6267
6368struct LongRangeDihadronCor {
6469 Service<ccdb::BasicCCDBManager> ccdb;
70+ o2::aod::ITSResponse itsResponse;
6571
6672 O2_DEFINE_CONFIGURABLE (cfgCutVtxZ, float , 10 .0f , " Accepted z-vertex range" )
6773 O2_DEFINE_CONFIGURABLE (cfgCutPtMin, float , 0 .2f , " minimum accepted track pT" )
@@ -130,6 +136,12 @@ struct LongRangeDihadronCor {
130136 TF1* fT0AV0AMean = nullptr ;
131137 TF1* fT0AV0ASigma = nullptr ;
132138 } cfgFuncParas;
139+ struct : ConfigurableGroup {
140+ O2_DEFINE_CONFIGURABLE (cfgUseItsPID, bool , true , " Use ITS PID for particle identification" )
141+ O2_DEFINE_CONFIGURABLE (cfgPIDParticle, int , 0 , " 1 = pion, 2 = kaon, 3 = proton, 4 = kshort, 5 = lambda, 6 = phi, 0 for no PID" )
142+ O2_DEFINE_CONFIGURABLE (cfgTofPtCut, float , 0 .5f , " Minimum pt to use TOF N-sigma" )
143+ Configurable<LabeledArray<float >> nSigmas{" nSigmas" , {LongArrayFloat[0 ], 3 , 6 , {" TPC" , " TOF" , " ITS" }, {" pos_pi" , " pos_ka" , " pos_pr" , " neg_pi" , " neg_ka" , " neg_pr" }}, " Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)" };
144+ } cfgPIDConfig;
133145
134146 SliceCache cache;
135147
@@ -161,7 +173,7 @@ struct LongRangeDihadronCor {
161173 Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVtxZ);
162174 Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == static_cast <uint8_t >(true ))) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls) && (nabs(aod::track::dcaZ) < cfgCutDCAz);
163175 using FilteredCollisions = soa::Filtered<soa::Join<aod::Collisions, aod::EvSel, aod::CentFT0Cs, aod::CentFT0CVariant1s, aod::CentFT0Ms, aod::CentFV0As, aod::Mults>>;
164- using FilteredTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection, aod::TracksExtra, aod::TracksDCA>>;
176+ using FilteredTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection, aod::TracksExtra, aod::TracksDCA, aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, aod::pidTOFbeta, aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr >>;
165177
166178 // FT0 geometry
167179 o2::ft0::Geometry ft0Det;
@@ -201,6 +213,31 @@ struct LongRangeDihadronCor {
201213 kFT0A = 0 ,
202214 kFT0C = 1
203215 };
216+ enum ParticleNsigma {
217+ kPionUp = 0 ,
218+ kKaonUp ,
219+ kProtonUp ,
220+ kPionLow ,
221+ kKaonLow ,
222+ kProtonLow
223+ };
224+ enum PIDIndex {
225+ kCharged = 0 ,
226+ kPions ,
227+ kKaons ,
228+ kProtons ,
229+ kK0 ,
230+ kLambda ,
231+ kPhi
232+ };
233+ enum DetectorType {
234+ kTPC = 0 ,
235+ kTOF ,
236+ kITS
237+ };
238+ std::array<float , 6 > tofNsigmaCut;
239+ std::array<float , 6 > itsNsigmaCut;
240+ std::array<float , 6 > tpcNsigmaCut;
204241
205242 void init (InitContext&)
206243 {
@@ -218,6 +255,28 @@ struct LongRangeDihadronCor {
218255
219256 LOGF (info, " Starting init" );
220257
258+ // filling tpc nSigmas array
259+ tpcNsigmaCut[kPionUp ] = cfgPIDConfig.nSigmas ->getData ()[kTPC ][kPionUp ];
260+ tpcNsigmaCut[kKaonUp ] = cfgPIDConfig.nSigmas ->getData ()[kTPC ][kKaonUp ];
261+ tpcNsigmaCut[kProtonUp ] = cfgPIDConfig.nSigmas ->getData ()[kTPC ][kProtonUp ];
262+ tpcNsigmaCut[kPionLow ] = cfgPIDConfig.nSigmas ->getData ()[kTPC ][kPionLow ];
263+ tpcNsigmaCut[kKaonLow ] = cfgPIDConfig.nSigmas ->getData ()[kTPC ][kKaonLow ];
264+ tpcNsigmaCut[kProtonLow ] = cfgPIDConfig.nSigmas ->getData ()[kTPC ][kProtonLow ];
265+ // filling tof nSigmas array
266+ tofNsigmaCut[kPionUp ] = cfgPIDConfig.nSigmas ->getData ()[kTOF ][kPionUp ];
267+ tofNsigmaCut[kKaonUp ] = cfgPIDConfig.nSigmas ->getData ()[kTOF ][kKaonUp ];
268+ tofNsigmaCut[kProtonUp ] = cfgPIDConfig.nSigmas ->getData ()[kTOF ][kProtonUp ];
269+ tofNsigmaCut[kPionLow ] = cfgPIDConfig.nSigmas ->getData ()[kTOF ][kPionLow ];
270+ tofNsigmaCut[kKaonLow ] = cfgPIDConfig.nSigmas ->getData ()[kTOF ][kKaonLow ];
271+ tofNsigmaCut[kProtonLow ] = cfgPIDConfig.nSigmas ->getData ()[kTOF ][kProtonLow ];
272+ // filling its nSigmas array
273+ itsNsigmaCut[kPionUp ] = cfgPIDConfig.nSigmas ->getData ()[kITS ][kPionUp ];
274+ itsNsigmaCut[kKaonUp ] = cfgPIDConfig.nSigmas ->getData ()[kITS ][kKaonUp ];
275+ itsNsigmaCut[kProtonUp ] = cfgPIDConfig.nSigmas ->getData ()[kITS ][kProtonUp ];
276+ itsNsigmaCut[kPionLow ] = cfgPIDConfig.nSigmas ->getData ()[kITS ][kPionLow ];
277+ itsNsigmaCut[kKaonLow ] = cfgPIDConfig.nSigmas ->getData ()[kITS ][kKaonLow ];
278+ itsNsigmaCut[kProtonLow ] = cfgPIDConfig.nSigmas ->getData ()[kITS ][kProtonLow ];
279+
221280 // Event Counter
222281 if ((doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameFt0aFt0c) && cfgUseAdditionalEventCut) {
223282 registry.add (" hEventCountSpecific" , " Number of Event;; Count" , {HistType::kTH1D , {{12 , 0 , 12 }}});
@@ -410,6 +469,58 @@ struct LongRangeDihadronCor {
410469 return ((track.tpcNClsFound () >= cfgCutTPCclu) && (track.tpcNClsCrossedRows () >= cfgCutTPCCrossedRows) && (track.itsNCls () >= cfgCutITSclu));
411470 }
412471
472+ template <typename TTrack>
473+ int getNsigmaPID (TTrack track)
474+ {
475+ // Computing Nsigma arrays for pion, kaon, and protons
476+ std::array<float , 3 > nSigmaTPC = {track.tpcNSigmaPi (), track.tpcNSigmaKa (), track.tpcNSigmaPr ()};
477+ std::array<float , 3 > nSigmaTOF = {track.tofNSigmaPi (), track.tofNSigmaKa (), track.tofNSigmaPr ()};
478+ std::array<float , 3 > nSigmaITS = {itsResponse.nSigmaITS <o2::track::PID::Pion>(track), itsResponse.nSigmaITS <o2::track::PID::Kaon>(track), itsResponse.nSigmaITS <o2::track::PID::Proton>(track)};
479+ int pid = -1 ; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton
480+
481+ std::array<float , 3 > nSigmaToUse = cfgPIDConfig.cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS
482+ std::array<float , 6 > detectorNsigmaCut = cfgPIDConfig.cfgUseItsPID ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS
483+
484+ bool isPion = false ;
485+ bool isKaon = false ;
486+ bool isProton = false ;
487+ bool isDetectedPion = nSigmaToUse[kPionUp ] < detectorNsigmaCut[kPionUp ] && nSigmaToUse[kPionUp ] > detectorNsigmaCut[kPionLow ];
488+ bool isDetectedKaon = nSigmaToUse[kKaonUp ] < detectorNsigmaCut[kKaonUp ] && nSigmaToUse[kKaonUp ] > detectorNsigmaCut[kKaonLow ];
489+ bool isDetectedProton = nSigmaToUse[kProtonUp ] < detectorNsigmaCut[kProtonUp ] && nSigmaToUse[kProtonUp ] > detectorNsigmaCut[kProtonLow ];
490+
491+ bool isTofPion = nSigmaTOF[kPionUp ] < tofNsigmaCut[kPionUp ] && nSigmaTOF[kPionUp ] > tofNsigmaCut[kPionLow ];
492+ bool isTofKaon = nSigmaTOF[kKaonUp ] < tofNsigmaCut[kKaonUp ] && nSigmaTOF[kKaonUp ] > tofNsigmaCut[kKaonLow ];
493+ bool isTofProton = nSigmaTOF[kProtonUp ] < tofNsigmaCut[kProtonUp ] && nSigmaTOF[kProtonUp ] > tofNsigmaCut[kProtonLow ];
494+
495+ if (track.pt () > cfgPIDConfig.cfgTofPtCut && !track.hasTOF ()) {
496+ return -1 ;
497+ } else if (track.pt () > cfgPIDConfig.cfgTofPtCut && track.hasTOF ()) {
498+ isPion = isTofPion && isDetectedPion;
499+ isKaon = isTofKaon && isDetectedKaon;
500+ isProton = isTofProton && isDetectedProton;
501+ } else {
502+ isPion = isDetectedPion;
503+ isKaon = isDetectedKaon;
504+ isProton = isDetectedProton;
505+ }
506+
507+ if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) {
508+ return -1 ; // more than one particle satisfy the criteria
509+ }
510+
511+ if (isPion) {
512+ pid = kPions ;
513+ } else if (isKaon) {
514+ pid = kKaons ;
515+ } else if (isProton) {
516+ pid = kProtons ;
517+ } else {
518+ return -1 ; // no particle satisfies the criteria
519+ }
520+
521+ return pid; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton
522+ }
523+
413524 void loadAlignParam (uint64_t timestamp)
414525 {
415526 offsetFT0 = ccdb->getForTimeStamp <std::vector<o2::detectors::AlignParam>>(" FT0/Calib/Align" , timestamp);
@@ -558,6 +669,8 @@ struct LongRangeDihadronCor {
558669
559670 if (!trackSelected (track1))
560671 continue ;
672+ if (cfgPIDConfig.cfgPIDParticle && getNsigmaPID (track1) != cfgPIDConfig.cfgPIDParticle )
673+ continue ; // if PID is selected, check if the track has the right PID
561674 if (!getEfficiencyCorrection (triggerWeight, track1.eta (), track1.pt (), posZ))
562675 continue ;
563676 if (system == SameEvent) {
0 commit comments