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
@@ -74,6 +77,8 @@ auto static constexpr CintZero = 0;
7477auto static constexpr KminFt0cCell = 96 ;
7578AxisSpec axisEvent{15 , 0.5 , 15.5 , " #Event" , " EventAxis" };
7679auto static constexpr KminCharge = 3 .0f ;
80+ static constexpr std::string_view species[] = {" Pi" , " Ka" , " Pr" , " K0s" , " L0s" };
81+ static constexpr std::array<int , 5 > speciesIds{kPiPlus , kKPlus , kProton , kK0Short , kLambda0 };
7782
7883enum KindOfV0 {
7984 kLambda = 0 ,
@@ -105,6 +110,7 @@ struct LongrangeMaker {
105110 Configurable<bool > isApplyCentFT0M{" isApplyCentFT0M" , false , " Centrality based on FT0A + FT0C" };
106111 Configurable<bool > isApplyOccuSelection{" isApplyOccuSelection" , false , " Enable occupancy selection" };
107112 Configurable<int > cfgOccuCut{" cfgOccuCut" , 1000 , " Occupancy selection" };
113+ Configurable<float > cfgVtxCut{" cfgVtxCut" , 10 .0f , " vertex Z selection" };
108114 Configurable<bool > isApplyBestCollIndex{" isApplyBestCollIndex" , true , " bestCollIndex" };
109115 } cfgevtsel;
110116
@@ -130,6 +136,13 @@ struct LongrangeMaker {
130136 Configurable<float > cfgMftPtCutMax{" cfgMftPtCutMax" , 10 .f , " maximum accepted MFT track pT" };
131137 } cfgmfttrksel;
132138
139+ struct : ConfigurableGroup {
140+ Configurable<float > cfigFt0aEtaMax{" cfigFt0aEtaMax" , 4 .9f , " Maximum FT0A eta cut" };
141+ Configurable<float > cfigFt0aEtaMin{" cfigFt0aEtaMin" , 3 .5f , " Minimum FT0A eta cut" };
142+ Configurable<float > cfigFt0cEtaMax{" cfigFt0cEtaMax" , -2 .1f , " Maximum FT0C eta cut" };
143+ Configurable<float > cfigFt0cEtaMin{" cfigFt0cEtaMin" , -3 .3f , " Minimum FT0C eta cut" };
144+ } cfgfittrksel;
145+
133146 struct : ConfigurableGroup {
134147 Configurable<float > minTPCcrossedrows{" minTPCcrossedrows" , 70 .f , " cut on minimum number of crossed rows in TPC" };
135148 Configurable<float > minTPCcrossedrowsoverfindcls{" minTPCcrossedrowsoverfindcls" , 0 .8f , " cut on minimum value of the ratio between crossed rows and findable clusters in the TPC" };
@@ -162,6 +175,13 @@ struct LongrangeMaker {
162175 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" };
163176 Configurable<float > cfgTofPidPtCut{" cfgTofPidPtCut" , 0 .3f , " Minimum pt to use TOF N-sigma" };
164177 Configurable<bool > isUseItsPid{" isUseItsPid" , false , " Use ITS PID for particle identification" };
178+ Configurable<int > isUseDataLikeMult{" isUseDataLikeMult" , 0 , " Data like mult/cent classification" };
179+
180+ ConfigurableAxis vtxHistBin{" vtxHistBin" , {20 , -10 , 10 }, " " };
181+ ConfigurableAxis multHistBin{" multHistBin" , {100 , 0 , 100 }, " " };
182+ ConfigurableAxis etaHistBin{" etaHistBin" , {20 , -1 , 1 }, " " };
183+ ConfigurableAxis ptHistBin{" ptHistBin" , {10 , 0 , 10 }, " " };
184+ ConfigurableAxis speciesHistBin{" speciesHistBin" , {6 , 0.5 , 6.5 }, " " };
165185
166186 Service<o2::ccdb::BasicCCDBManager> ccdb;
167187 Service<o2::framework::O2DatabasePDG> pdg;
@@ -212,6 +232,27 @@ struct LongrangeMaker {
212232 x->SetBinLabel (12 , " ApplyOccupancySelection" );
213233 histos.add (" hSelectionResult" , " hSelectionResult" , kTH1I , {{5 , -0.5 , 4.5 }});
214234
235+ AxisSpec axisVtx = {vtxHistBin, " Vertex" , " VtxAxis" };
236+ AxisSpec axisMult = {multHistBin, " Mult" , " MultAxis" };
237+ AxisSpec axisEta = {etaHistBin, " Eta" , " EtaAxis" };
238+ AxisSpec axisPt = {ptHistBin, " Pt" , " PtAxis" };
239+ AxisSpec axisSpecies = {speciesHistBin, " Species" , " SpeciesAxis" };
240+
241+ if (doprocessTPCtrackEff || doprocessMFTtrackEff) {
242+ histos.add (" hGenMCdndpt" , " hGenMCdndpt" , kTHnSparseD , {axisVtx, axisMult, axisEta, axisPt, axisSpecies}, false );
243+ histos.add (" hRecMCdndpt" , " hRecMCdndpt" , kTHnSparseD , {axisVtx, axisMult, axisEta, axisPt, axisSpecies}, false );
244+ auto hGenSpecies = histos.get <THnSparse>(HIST (" hGenMCdndpt" ));
245+ auto hRecSpecies = histos.get <THnSparse>(HIST (" hRecMCdndpt" ));
246+ auto * axisGen = hGenSpecies->GetAxis (4 );
247+ auto * axisRec = hRecSpecies->GetAxis (4 );
248+ for (auto i = 0U ; i < speciesIds.size (); ++i) {
249+ axisGen->SetBinLabel (i + 1 , species[i].data ());
250+ axisRec->SetBinLabel (i + 1 , species[i].data ());
251+ }
252+ axisGen->SetBinLabel (6 , " Other" );
253+ axisRec->SetBinLabel (6 , " Other" );
254+ }
255+
215256 myTrackFilter = getGlobalTrackSelectionRun3ITSMatch (TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default);
216257 myTrackFilter.SetPtRange (cfgtrksel.cfgPtCutMin , cfgtrksel.cfgPtCutMax );
217258 myTrackFilter.SetEtaRange (-cfgtrksel.cfgEtaCut , cfgtrksel.cfgEtaCut );
@@ -604,12 +645,12 @@ struct LongrangeMaker {
604645 if (std::abs (particle.eta ()) < cfgtrksel.cfgEtaCut && particle.pt () > cfgtrksel.cfgPtCutMin && particle.pt () < cfgtrksel.cfgPtCutMult )
605646 lrmidmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi (), particle.pdgCode (), particle.flags ());
606647 // Fill FT0 tracks
607- if (3.5 < particle.eta () && particle.eta () < 4.9 )
648+ if (cfgfittrksel. cfigFt0aEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0aEtaMax )
608649 lrft0amctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
609- if (- 3.3 < particle.eta () && particle.eta () < - 2.1 )
650+ if (cfgfittrksel. cfigFt0cEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0cEtaMax )
610651 lrft0cmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
611652 // Fill MFT tracks
612- if (- 3.6 < particle.eta () && particle.eta () < - 2.4 )
653+ if (cfgmfttrksel. cfigMftEtaMin < particle.eta () && particle.eta () < cfgmfttrksel. cfigMftEtaMax )
613654 lrmftmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
614655 }
615656 }
@@ -633,16 +674,137 @@ struct LongrangeMaker {
633674 if (std::abs (particle.eta ()) < cfgtrksel.cfgEtaCut && particle.pt () > cfgtrksel.cfgPtCutMin && particle.pt () < cfgtrksel.cfgPtCutMult )
634675 lrmidmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi (), particle.pdgCode (), particle.flags ());
635676 // Fill FT0 tracks
636- if (3.5 < particle.eta () && particle.eta () < 4.9 )
677+ if (cfgfittrksel. cfigFt0aEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0aEtaMax )
637678 lrft0amctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
638- if (- 3.3 < particle.eta () && particle.eta () < - 2.1 )
679+ if (cfgfittrksel. cfigFt0cEtaMin < particle.eta () && particle.eta () < cfgfittrksel. cfigFt0cEtaMax )
639680 lrft0cmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
640681 // Fill MFT tracks
641- if (- 3.6 < particle.eta () && particle.eta () < - 2.4 )
682+ if (cfgmfttrksel. cfigMftEtaMin < particle.eta () && particle.eta () < cfgmfttrksel. cfigMftEtaMax )
642683 lrmftmctracks (lrmccollision.lastIndex (), particle.pt (), particle.eta (), particle.phi ());
643684 }
644685 }
645686
687+ void processTPCtrackEff (ColMCTrueTable::iterator const & mcCollision, ColMCRecTable const & RecCols,
688+ TrksMCRecTable const & RecTracks, aod::McParticles const & mcparticles)
689+ {
690+ if (std::abs (mcCollision.posZ ()) >= cfgevtsel.cfgVtxCut ) {
691+ return ;
692+ }
693+ auto multiplicity = 0 ;
694+ for (const auto & particle : mcparticles) {
695+ if (!isGenPartSelected (particle) || std::abs (particle.eta ()) > cfgtrksel.cfgEtaCut || particle.pt () < cfgtrksel.cfgPtCutMin || particle.pt () > cfgtrksel.cfgPtCutMult )
696+ continue ;
697+ multiplicity++;
698+ }
699+ if (isUseDataLikeMult > 0 ) {
700+ for (const auto & RecCol : RecCols) {
701+ if (!isEventSelected (RecCol)) {
702+ continue ;
703+ }
704+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
705+ continue ;
706+ }
707+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
708+ continue ;
709+ }
710+ multiplicity = selColCent (RecCol);
711+ }
712+ }
713+
714+ for (const auto & particle : mcparticles) {
715+ if (!isGenPartSelected (particle) || std::abs (particle.eta ()) > cfgtrksel.cfgEtaCut || particle.pt () < cfgtrksel.cfgPtCutMin || particle.pt () > cfgtrksel.cfgPtCutMult )
716+ continue ;
717+ auto pos = std::distance (speciesIds.begin (), std::find (speciesIds.begin (), speciesIds.end (), particle.pdgCode ())) + 1 ;
718+ histos.fill (HIST (" hGenMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), pos);
719+ }
720+
721+ for (const auto & RecCol : RecCols) {
722+ if (!isEventSelected (RecCol)) {
723+ continue ;
724+ }
725+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
726+ continue ;
727+ }
728+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
729+ continue ;
730+ }
731+ auto recTracksPart = RecTracks.sliceBy (perColMidtrack, RecCol.globalIndex ());
732+ for (const auto & track : recTracksPart) {
733+ if (!track.isGlobalTrack ())
734+ continue ;
735+ if (!myTrackFilter.IsSelected (track))
736+ continue ;
737+ if (!track.has_mcParticle ())
738+ continue ;
739+ auto particle = track.mcParticle ();
740+ if (RecCol.mcCollisionId () != particle.mcCollisionId ())
741+ continue ;
742+ if (particle.isPhysicalPrimary ()) {
743+ auto pos = std::distance (speciesIds.begin (), std::find (speciesIds.begin (), speciesIds.end (), particle.pdgCode ())) + 1 ;
744+ histos.fill (HIST (" hRecMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), pos);
745+ }
746+ }
747+ }
748+ }
749+
750+ void processMFTtrackEff (ColMCTrueTable::iterator const & mcCollision, ColMCRecTable const & RecCols,
751+ MftTrkMCRecTable const & mfttracks, aod::McParticles const & mcparticles)
752+ {
753+ if (std::abs (mcCollision.posZ ()) >= cfgevtsel.cfgVtxCut ) {
754+ return ;
755+ }
756+ auto multiplicity = 0 ;
757+ for (const auto & particle : mcparticles) {
758+ if (!isGenPartSelected (particle) || std::abs (particle.eta ()) > cfgtrksel.cfgEtaCut || particle.pt () < cfgtrksel.cfgPtCutMin || particle.pt () > cfgtrksel.cfgPtCutMult )
759+ continue ;
760+ multiplicity++;
761+ }
762+ if (isUseDataLikeMult > 0 ) {
763+ for (const auto & RecCol : RecCols) {
764+ if (!isEventSelected (RecCol)) {
765+ continue ;
766+ }
767+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
768+ continue ;
769+ }
770+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
771+ continue ;
772+ }
773+ multiplicity = selColCent (RecCol);
774+ }
775+ }
776+
777+ for (const auto & particle : mcparticles) {
778+ if (!isGenPartSelected (particle) || particle.eta () > cfgmfttrksel.cfigMftEtaMax || particle.eta () < cfgmfttrksel.cfigMftEtaMin || particle.pt () < cfgmfttrksel.cfgMftPtCutMin || particle.pt () > cfgmfttrksel.cfgMftPtCutMax )
779+ continue ;
780+ histos.fill (HIST (" hGenMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), 1.0 );
781+ }
782+
783+ for (const auto & RecCol : RecCols) {
784+ if (!isEventSelected (RecCol)) {
785+ continue ;
786+ }
787+ if (std::abs (RecCol.posZ ()) >= cfgevtsel.cfgVtxCut ) {
788+ continue ;
789+ }
790+ if (cfgevtsel.isApplyBestCollIndex && RecCol.globalIndex () != mcCollision.bestCollisionIndex ()) {
791+ continue ;
792+ }
793+ auto recTracksPart = mfttracks.sliceBy (perColMfttrack, RecCol.globalIndex ());
794+ for (const auto & track : recTracksPart) {
795+ if (!isMftTrackSelected (track))
796+ continue ;
797+ if (!track.has_mcParticle ())
798+ continue ;
799+ auto particle = track.mcParticle ();
800+ if (RecCol.mcCollisionId () != particle.mcCollisionId ())
801+ continue ;
802+ if (particle.isPhysicalPrimary ())
803+ histos.fill (HIST (" hRecMCdndpt" ), mcCollision.posZ (), multiplicity, particle.eta (), particle.pt (), 1.0 );
804+ }
805+ }
806+ }
807+
646808 template <typename CheckGenPart>
647809 bool isGenPartSelected (CheckGenPart const & particle)
648810 {
@@ -945,6 +1107,8 @@ struct LongrangeMaker {
9451107 PROCESS_SWITCH (LongrangeMaker, processUpc, " process UPC collisions" , false );
9461108 PROCESS_SWITCH (LongrangeMaker, processMCGen, " process MC generated collisions" , false );
9471109 PROCESS_SWITCH (LongrangeMaker, processMCRec, " process MC both gen and rec collisions" , false );
1110+ PROCESS_SWITCH (LongrangeMaker, processTPCtrackEff, " process TPC track efficiency" , false );
1111+ PROCESS_SWITCH (LongrangeMaker, processMFTtrackEff, " process MFT track efficiency" , false );
9481112};
9491113
9501114WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments