1616// / \since October 28, 2025
1717
1818#include " PWGCF/Core/CorrelationContainer.h"
19- #include " PWGCF/Core/PairCuts.h"
2019#include " PWGCF/TwoParticleCorrelations/DataModel/LongRangeDerived.h"
2120#include " PWGLF/DataModel/LFStrangenessTables.h"
2221#include " PWGMM/Mult/DataModel/bestCollisionTable.h"
22+ #include " PWGUD/Core/SGCutParHolder.h"
2323#include " PWGUD/Core/SGSelector.h"
24+ #include " PWGUD/Core/UDHelpers.h"
2425#include " PWGUD/Core/UPCHelpers.h"
2526
27+ #include " Common/CCDB/EventSelectionParams.h"
2628#include " Common/Core/RecoDecay.h"
2729#include " Common/Core/TrackSelection.h"
2830#include " Common/Core/TrackSelectionDefaults.h"
29- #include " Common/Core/trackUtilities.h"
3031#include " Common/DataModel/Centrality.h"
31- #include " Common/DataModel/CollisionAssociationTables.h"
3232#include " Common/DataModel/EventSelection.h"
33- #include " Common/DataModel/FT0Corrected.h"
3433#include " Common/DataModel/Multiplicity.h"
3534#include " Common/DataModel/PIDResponseITS.h"
3635#include " Common/DataModel/PIDResponseTOF.h"
3736#include " Common/DataModel/PIDResponseTPC.h"
3837#include " Common/DataModel/TrackSelectionTables.h"
3938
40- #include " CCDB/BasicCCDBManager.h"
41- #include " CCDB/CcdbApi.h"
42- #include " CommonConstants/MathConstants.h"
43- #include " CommonConstants/PhysicsConstants.h"
44- #include " DetectorsCommonDataFormats/AlignParam.h"
45- #include " FT0Base/Geometry.h"
46- #include " Framework/ASoAHelpers.h"
47- #include " Framework/AnalysisDataModel.h"
48- #include " Framework/AnalysisTask.h"
49- #include " Framework/HistogramRegistry.h"
50- #include " Framework/O2DatabasePDGPlugin.h"
51- #include " Framework/runDataProcessing.h"
52- #include " ReconstructionDataFormats/PID.h"
53- #include " ReconstructionDataFormats/Track.h"
54-
55- #include < TComplex.h>
56- #include < TH1F.h>
57- #include < TMath.h>
58- #include < TPDGCode.h>
59-
39+ #include < CCDB/BasicCCDBManager.h>
40+ #include < CCDB/CcdbApi.h>
41+ #include < CommonConstants/PhysicsConstants.h>
42+ #include < DetectorsCommonDataFormats/AlignParam.h>
43+ #include < FT0Base/Geometry.h>
44+ #include < Framework/AnalysisDataModel.h>
45+ #include < Framework/AnalysisHelpers.h>
46+ #include < Framework/AnalysisTask.h>
47+ #include < Framework/Configurable.h>
48+ #include < Framework/HistogramRegistry.h>
49+ #include < Framework/HistogramSpec.h>
50+ #include < Framework/InitContext.h>
51+ #include < Framework/O2DatabasePDGPlugin.h>
52+ #include < Framework/OutputObjHeader.h>
53+ #include < Framework/runDataProcessing.h>
54+ #include < MathUtils/Utils.h>
55+ #include < ReconstructionDataFormats/PID.h>
56+
57+ #include < sys/types.h>
58+
59+ #include < array>
6060#include < chrono>
61+ #include < cmath>
62+ #include < cstdint>
6163#include < cstdio>
64+ #include < cstdlib>
6265#include < string>
6366#include < vector>
6467
@@ -72,8 +75,13 @@ using namespace o2::constants::math;
7275
7376auto static constexpr CintZero = 0 ;
7477auto static constexpr KminFt0cCell = 96 ;
78+ auto static constexpr PionTrackN = 1 ;
79+ auto static constexpr KaonTrackN = 2 ;
80+ auto static constexpr ProtonTrackN = 3 ;
7581AxisSpec axisEvent{15 , 0.5 , 15.5 , " #Event" , " EventAxis" };
7682auto static constexpr KminCharge = 3 .0f ;
83+ static constexpr std::string_view species[] = {" Pi" , " Ka" , " Pr" , " K0s" , " L0s" };
84+ static constexpr std::array<int , 5 > speciesIds{kPiPlus , kKPlus , kProton , kK0Short , kLambda0 };
7785
7886enum KindOfV0 {
7987 kLambda = 0 ,
@@ -105,6 +113,7 @@ struct LongrangeMaker {
105113 Configurable<bool > isApplyCentFT0M{" isApplyCentFT0M" , false , " Centrality based on FT0A + FT0C" };
106114 Configurable<bool > isApplyOccuSelection{" isApplyOccuSelection" , false , " Enable occupancy selection" };
107115 Configurable<int > cfgOccuCut{" cfgOccuCut" , 1000 , " Occupancy selection" };
116+ Configurable<float > cfgVtxCut{" cfgVtxCut" , 10 .0f , " vertex Z selection" };
108117 Configurable<bool > isApplyBestCollIndex{" isApplyBestCollIndex" , true , " bestCollIndex" };
109118 } cfgevtsel;
110119
@@ -130,6 +139,13 @@ struct LongrangeMaker {
130139 Configurable<float > cfgMftPtCutMax{" cfgMftPtCutMax" , 10 .f , " maximum accepted MFT track pT" };
131140 } cfgmfttrksel;
132141
142+ struct : ConfigurableGroup {
143+ Configurable<float > cfigFt0aEtaMax{" cfigFt0aEtaMax" , 4 .9f , " Maximum FT0A eta cut" };
144+ Configurable<float > cfigFt0aEtaMin{" cfigFt0aEtaMin" , 3 .5f , " Minimum FT0A eta cut" };
145+ Configurable<float > cfigFt0cEtaMax{" cfigFt0cEtaMax" , -2 .1f , " Maximum FT0C eta cut" };
146+ Configurable<float > cfigFt0cEtaMin{" cfigFt0cEtaMin" , -3 .3f , " Minimum FT0C eta cut" };
147+ } cfgfittrksel;
148+
133149 struct : ConfigurableGroup {
134150 Configurable<float > minTPCcrossedrows{" minTPCcrossedrows" , 70 .f , " cut on minimum number of crossed rows in TPC" };
135151 Configurable<float > minTPCcrossedrowsoverfindcls{" minTPCcrossedrowsoverfindcls" , 0 .8f , " cut on minimum value of the ratio between crossed rows and findable clusters in the TPC" };
@@ -162,6 +178,13 @@ struct LongrangeMaker {
162178 Configurable<std::vector<double >> tofNsigmaPidCut{" tofNsigmaPidCut" , std::vector<double >{1.5 , 1.5 , 1.5 , -1.5 , -1.5 , -1.5 }, " TOF n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma" };
163179 Configurable<float > cfgTofPidPtCut{" cfgTofPidPtCut" , 0 .3f , " Minimum pt to use TOF N-sigma" };
164180 Configurable<bool > isUseItsPid{" isUseItsPid" , false , " Use ITS PID for particle identification" };
181+ Configurable<int > isUseDataLikeMult{" isUseDataLikeMult" , 0 , " Data like mult/cent classification" };
182+
183+ ConfigurableAxis vtxHistBin{" vtxHistBin" , {20 , -10 , 10 }, " " };
184+ ConfigurableAxis multHistBin{" multHistBin" , {100 , 0 , 100 }, " " };
185+ ConfigurableAxis etaHistBin{" etaHistBin" , {20 , -1 , 1 }, " " };
186+ ConfigurableAxis ptHistBin{" ptHistBin" , {10 , 0 , 10 }, " " };
187+ ConfigurableAxis speciesHistBin{" speciesHistBin" , {6 , 0.5 , 6.5 }, " " };
165188
166189 Service<o2::ccdb::BasicCCDBManager> ccdb;
167190 Service<o2::framework::O2DatabasePDG> pdg;
@@ -212,6 +235,27 @@ struct LongrangeMaker {
212235 x->SetBinLabel (12 , " ApplyOccupancySelection" );
213236 histos.add (" hSelectionResult" , " hSelectionResult" , kTH1I , {{5 , -0.5 , 4.5 }});
214237
238+ AxisSpec axisVtx = {vtxHistBin, " Vertex" , " VtxAxis" };
239+ AxisSpec axisMult = {multHistBin, " Mult" , " MultAxis" };
240+ AxisSpec axisEta = {etaHistBin, " Eta" , " EtaAxis" };
241+ AxisSpec axisPt = {ptHistBin, " Pt" , " PtAxis" };
242+ AxisSpec axisSpecies = {speciesHistBin, " Species" , " SpeciesAxis" };
243+
244+ if (doprocessTPCtrackEff || doprocessMFTtrackEff) {
245+ histos.add (" hGenMCdndpt" , " hGenMCdndpt" , kTHnSparseD , {axisVtx, axisMult, axisEta, axisPt, axisSpecies}, false );
246+ histos.add (" hRecMCdndpt" , " hRecMCdndpt" , kTHnSparseD , {axisVtx, axisMult, axisEta, axisPt, axisSpecies}, false );
247+ auto hGenSpecies = histos.get <THnSparse>(HIST (" hGenMCdndpt" ));
248+ auto hRecSpecies = histos.get <THnSparse>(HIST (" hRecMCdndpt" ));
249+ auto * axisGen = hGenSpecies->GetAxis (4 );
250+ auto * axisRec = hRecSpecies->GetAxis (4 );
251+ for (auto i = 0U ; i < speciesIds.size (); ++i) {
252+ axisGen->SetBinLabel (i + 1 , species[i].data ());
253+ axisRec->SetBinLabel (i + 1 , species[i].data ());
254+ }
255+ axisGen->SetBinLabel (6 , " Other" );
256+ axisRec->SetBinLabel (6 , " Other" );
257+ }
258+
215259 myTrackFilter = getGlobalTrackSelectionRun3ITSMatch (TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default);
216260 myTrackFilter.SetPtRange (cfgtrksel.cfgPtCutMin , cfgtrksel.cfgPtCutMax );
217261 myTrackFilter.SetEtaRange (-cfgtrksel.cfgEtaCut , cfgtrksel.cfgEtaCut );
@@ -604,12 +648,12 @@ struct LongrangeMaker {
604648 if (std::abs (particle.eta ()) < cfgtrksel.cfgEtaCut && particle.pt () > cfgtrksel.cfgPtCutMin && particle.pt () < cfgtrksel.cfgPtCutMult )
605649 lrmidmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi (), particle.pdgCode (), particle.flags ());
606650 // Fill FT0 tracks
607- if (3.5 < particle.eta () && particle.eta () < 4.9 )
651+ if (cfgfittrksel. cfigFt0aEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0aEtaMax )
608652 lrft0amctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
609- if (- 3.3 < particle.eta () && particle.eta () < - 2.1 )
653+ if (cfgfittrksel. cfigFt0cEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0cEtaMax )
610654 lrft0cmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
611655 // Fill MFT tracks
612- if (- 3.6 < particle.eta () && particle.eta () < - 2.4 )
656+ if (cfgmfttrksel. cfigMftEtaMin < particle.eta () && particle.eta () < cfgmfttrksel. cfigMftEtaMax )
613657 lrmftmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
614658 }
615659 }
@@ -633,16 +677,137 @@ struct LongrangeMaker {
633677 if (std::abs (particle.eta ()) < cfgtrksel.cfgEtaCut && particle.pt () > cfgtrksel.cfgPtCutMin && particle.pt () < cfgtrksel.cfgPtCutMult )
634678 lrmidmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi (), particle.pdgCode (), particle.flags ());
635679 // Fill FT0 tracks
636- if (3.5 < particle.eta () && particle.eta () < 4.9 )
680+ if (cfgfittrksel. cfigFt0aEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0aEtaMax )
637681 lrft0amctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
638- if (- 3.3 < particle.eta () && particle.eta () < - 2.1 )
682+ if (cfgfittrksel. cfigFt0cEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0cEtaMax )
639683 lrft0cmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
640684 // Fill MFT tracks
641- if (- 3.6 < particle.eta () && particle.eta () < - 2.4 )
685+ if (cfgmfttrksel. cfigMftEtaMin < particle.eta () && particle.eta () < cfgmfttrksel. cfigMftEtaMax )
642686 lrmftmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
643687 }
644688 }
645689
690+ void processTPCtrackEff (ColMCTrueTable::iterator const & mcCollision, ColMCRecTable const & RecCols,
691+ TrksMCRecTable const & RecTracks, aod::McParticles const & mcparticles)
692+ {
693+ if (std::abs (mcCollision.posZ ()) >= cfgevtsel.cfgVtxCut ) {
694+ return ;
695+ }
696+ auto multiplicity = 0 ;
697+ for (const auto & particle : mcparticles) {
698+ if (!isGenPartSelected (particle) || std::abs (particle.eta ()) > cfgtrksel.cfgEtaCut || particle.pt () < cfgtrksel.cfgPtCutMin || particle.pt () > cfgtrksel.cfgPtCutMult )
699+ continue ;
700+ multiplicity++;
701+ }
702+ if (isUseDataLikeMult > 0 ) {
703+ for (const auto & RecCol : RecCols) {
704+ if (!isEventSelected (RecCol)) {
705+ continue ;
706+ }
707+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
708+ continue ;
709+ }
710+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
711+ continue ;
712+ }
713+ multiplicity = selColCent (RecCol);
714+ }
715+ }
716+
717+ for (const auto & particle : mcparticles) {
718+ if (!isGenPartSelected (particle) || std::abs (particle.eta ()) > cfgtrksel.cfgEtaCut || particle.pt () < cfgtrksel.cfgPtCutMin || particle.pt () > cfgtrksel.cfgPtCutMult )
719+ continue ;
720+ auto pos = std::distance (speciesIds.begin (), std::find (speciesIds.begin (), speciesIds.end (), particle.pdgCode ())) + 1 ;
721+ histos.fill (HIST (" hGenMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), pos);
722+ }
723+
724+ for (const auto & RecCol : RecCols) {
725+ if (!isEventSelected (RecCol)) {
726+ continue ;
727+ }
728+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
729+ continue ;
730+ }
731+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
732+ continue ;
733+ }
734+ auto recTracksPart = RecTracks.sliceBy (perColMidtrack, RecCol.globalIndex ());
735+ for (const auto & track : recTracksPart) {
736+ if (!track.isGlobalTrack ())
737+ continue ;
738+ if (!myTrackFilter.IsSelected (track))
739+ continue ;
740+ if (!track.has_mcParticle ())
741+ continue ;
742+ auto particle = track.mcParticle ();
743+ if (RecCol.mcCollisionId () != particle.mcCollisionId ())
744+ continue ;
745+ if (particle.isPhysicalPrimary ()) {
746+ auto pos = std::distance (speciesIds.begin (), std::find (speciesIds.begin (), speciesIds.end (), particle.pdgCode ())) + 1 ;
747+ histos.fill (HIST (" hRecMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), pos);
748+ }
749+ }
750+ }
751+ }
752+
753+ void processMFTtrackEff (ColMCTrueTable::iterator const & mcCollision, ColMCRecTable const & RecCols,
754+ MftTrkMCRecTable const & mfttracks, aod::McParticles const & mcparticles)
755+ {
756+ if (std::abs (mcCollision.posZ ()) >= cfgevtsel.cfgVtxCut ) {
757+ return ;
758+ }
759+ auto multiplicity = 0 ;
760+ for (const auto & particle : mcparticles) {
761+ if (!isGenPartSelected (particle) || std::abs (particle.eta ()) > cfgtrksel.cfgEtaCut || particle.pt () < cfgtrksel.cfgPtCutMin || particle.pt () > cfgtrksel.cfgPtCutMult )
762+ continue ;
763+ multiplicity++;
764+ }
765+ if (isUseDataLikeMult > 0 ) {
766+ for (const auto & RecCol : RecCols) {
767+ if (!isEventSelected (RecCol)) {
768+ continue ;
769+ }
770+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
771+ continue ;
772+ }
773+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
774+ continue ;
775+ }
776+ multiplicity = selColCent (RecCol);
777+ }
778+ }
779+
780+ for (const auto & particle : mcparticles) {
781+ if (!isGenPartSelected (particle) || particle.eta () > cfgmfttrksel.cfigMftEtaMax || particle.eta () < cfgmfttrksel.cfigMftEtaMin || particle.pt () < cfgmfttrksel.cfgMftPtCutMin || particle.pt () > cfgmfttrksel.cfgMftPtCutMax )
782+ continue ;
783+ histos.fill (HIST (" hGenMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), 1.0 );
784+ }
785+
786+ for (const auto & RecCol : RecCols) {
787+ if (!isEventSelected (RecCol)) {
788+ continue ;
789+ }
790+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
791+ continue ;
792+ }
793+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
794+ continue ;
795+ }
796+ auto recTracksPart = mfttracks.sliceBy (perColMfttrack, RecCol.globalIndex ());
797+ for (const auto & track : recTracksPart) {
798+ if (!isMftTrackSelected (track))
799+ continue ;
800+ if (!track.has_mcParticle ())
801+ continue ;
802+ auto particle = track.mcParticle ();
803+ if (RecCol.mcCollisionId () != particle.mcCollisionId ())
804+ continue ;
805+ if (particle.isPhysicalPrimary ())
806+ histos.fill (HIST (" hRecMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), 1.0 );
807+ }
808+ }
809+ }
810+
646811 template <typename CheckGenPart>
647812 bool isGenPartSelected (CheckGenPart const & particle)
648813 {
@@ -755,6 +920,7 @@ struct LongrangeMaker {
755920 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)};
756921 std::array<float , 3 > nSigmaToUse = isUseItsPid ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS
757922 std::vector<double > detectorNsigmaCut = isUseItsPid ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS
923+ int pid = -1 ;
758924 bool isPion, isKaon, isProton;
759925 bool isDetectedPion = nSigmaToUse[0 ] < detectorNsigmaCut[0 ] && nSigmaToUse[0 ] > detectorNsigmaCut[0 + 3 ];
760926 bool isDetectedKaon = nSigmaToUse[1 ] < detectorNsigmaCut[1 ] && nSigmaToUse[1 ] > detectorNsigmaCut[1 + 3 ];
@@ -945,6 +1111,8 @@ struct LongrangeMaker {
9451111 PROCESS_SWITCH (LongrangeMaker, processUpc, " process UPC collisions" , false );
9461112 PROCESS_SWITCH (LongrangeMaker, processMCGen, " process MC generated collisions" , false );
9471113 PROCESS_SWITCH (LongrangeMaker, processMCRec, " process MC both gen and rec collisions" , false );
1114+ PROCESS_SWITCH (LongrangeMaker, processTPCtrackEff, " process TPC track efficiency" , false );
1115+ PROCESS_SWITCH (LongrangeMaker, processMFTtrackEff, " process MFT track efficiency" , false );
9481116};
9491117
9501118WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments