1313// / \file uecharged.cxx
1414// / \brief Underlying event analysis task
1515// / \since November 2021
16- // / \last update: September 2025
16+ // / \last update: October 2025
17+
18+ #include " PWGLF/DataModel/mcCentrality.h"
19+ #include " PWGLF/Utils/inelGt.h"
20+ #include " PWGLF/Utils/mcParticle.h"
1721
1822#include " Common/Core/TrackSelection.h"
1923#include " Common/Core/TrackSelectionDefaults.h"
3034#include " Framework/runDataProcessing.h"
3135#include " ReconstructionDataFormats/Track.h"
3236
33- #include " TDatabasePDG .h"
37+ #include " TPDGCode .h"
3438#include < TF1.h>
3539#include < TH1F.h>
3640#include < TH2F.h>
4549using namespace o2 ;
4650using namespace o2 ::framework;
4751using namespace o2 ::framework::expressions;
48- using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels,
49- aod::Run3MatchedToBCSparse>;
52+ using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels, aod::Run3MatchedToBCSparse>;
5053
5154struct ueCharged {
5255
@@ -80,8 +83,7 @@ struct ueCharged {
8083 selectedTracks.SetMaxChi2PerClusterTPC (4 .f );
8184 selectedTracks.SetRequireHitsInITSLayers (1 , {0 , 1 }); // one hit in any SPD layer
8285 selectedTracks.SetMaxChi2PerClusterITS (36 .f );
83- // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f /
84- // pow(pt, 1.1f); });
86+ // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); });
8587 selectedTracks.SetMaxDcaZ (2 .f );
8688 return selectedTracks;
8789 }
@@ -91,14 +93,15 @@ struct ueCharged {
9193
9294 Service<o2::framework::O2DatabasePDG> pdg;
9395 float deltaPhi (float phia, float phib, float rangeMin, float rangeMax);
96+
9497 // Configurable for event selection
9598 Configurable<bool > isRun3{" isRun3" , true , " is Run3 dataset" };
9699 Configurable<bool > piluprejection{" piluprejection" , true , " Pileup rejection" };
97100 Configurable<bool > goodzvertex{" goodzvertex" , true , " removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference" };
98101 Configurable<bool > sel8{" sel8" , true , " Apply the sel8 event selection" };
99102 Configurable<bool > removeITSROFBorder{" removeITSROFBorder" , false , " Remove ITS Read-Out Frame border and only apply kIsTriggerTVX & kNoTimeFrameBorder (recommended for MC)" };
100103 Configurable<bool > analyzeEvandTracksel{" analyzeEvandTracksel" , true , " Analyze the event and track selection" };
101-
104+ Configurable< int > cfgINELCut{ " cfgINELCut " , 0 , " INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1 " };
102105 // acceptance cuts
103106 Configurable<float > cfgTrkEtaCut{" cfgTrkEtaCut" , 0 .8f , " Eta range for tracks" };
104107 Configurable<float > cfgTrkLowPtCut{" cfgTrkLowPtCut" , 0 .15f , " Minimum constituent pT" };
@@ -130,6 +133,9 @@ struct ueCharged {
130133 static constexpr std::string_view hPtVsPtLeadingTrue[3 ] = {
131134 " hPtVsPtLeadingTrue_NS" , " hPtVsPtLeadingTrue_AS" ,
132135 " hPtVsPtLeadingTrue_TS" };
136+ static constexpr std::string_view hPtVsPtLeadingTruePS[3 ] = {
137+ " hPtVsPtLeadingTruePS_NS" , " hPtVsPtLeadingTruePS_AS" ,
138+ " hPtVsPtLeadingTruePS_TS" };
133139 // all wo detector effects
134140 static constexpr std::string_view pNumDenTrueAll[3 ] = {
135141 " pNumDenTrueAll_NS" , " pNumDenTrueAll_AS" , " pNumDenTrueAll_TS" };
@@ -140,7 +146,6 @@ struct ueCharged {
140146 " pNumDenTrue_NS" , " pNumDenTrue_AS" , " pNumDenTrue_TS" };
141147 static constexpr std::string_view pSumPtTrue[3 ] = {
142148 " pSumPtTrue_NS" , " pSumPtTrue_AS" , " pSumPtTrue_TS" };
143-
144149 // this must have all event selection effects, but it has not been implemented
145150 // 50%
146151 static constexpr std::string_view pNumDenTruePS[3 ] = {
@@ -165,16 +170,11 @@ struct ueCharged {
165170 template <typename C, typename T>
166171 void analyzeEventAndTrackSelection (const C& collision, const T& tracks);
167172
168- Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) &&
169- (aod::track::pt > cfgTrkLowPtCut);
173+ Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) && (aod::track::pt > cfgTrkLowPtCut);
170174
171175 using CollisionTableMCTrue = aod::McCollisions;
172- using CollisionTableMC =
173- soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions,
174- aod::EvSels, aod::PVMults>>;
175- using TrackTableMC =
176- soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA,
177- aod::McTrackLabels, aod::TrackSelection>>;
176+ using CollisionTableMC = soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions, aod::EvSels, aod::PVMults>>;
177+ using TrackTableMC = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::McTrackLabels, aod::TrackSelection>>;
178178 using ParticleTableMC = aod::McParticles;
179179 Preslice<TrackTableMC> perCollision = aod::track::collisionId;
180180 void processMC (CollisionTableMCTrue::iterator const & mcCollision,
@@ -183,36 +183,31 @@ struct ueCharged {
183183 BCsRun3 const &);
184184 PROCESS_SWITCH (ueCharged, processMC, " process MC" , false );
185185
186- using CollisionTableMCData =
187- soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSels,
188- aod::PVMults>;
189- using TrackTableMCData =
190- soa::Filtered<soa::Join<aod::Tracks, aod::McTrackLabels, aod::TracksExtra,
191- aod::TracksDCA, aod::TrackSelection>>;
186+ using CollisionTableMCData = soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSels, aod::PVMults>;
187+ using TrackTableMCData = soa::Filtered<soa::Join<aod::Tracks, aod::McTrackLabels, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
192188 void processDataMC (CollisionTableMCData::iterator const & collision,
193189 TrackTableMCData const & tracks,
194190 ParticleTableMC const & particles,
195191 aod::McCollisions const & mcCollisions);
196192 PROCESS_SWITCH (ueCharged, processDataMC, " process data MC" , false );
197193
198- using CollisionTableData =
199- soa::Join<aod::Collisions, aod::EvSels, aod::PVMults>;
200- using TrackTableData =
201- soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA,
202- aod::TrackSelection>>;
194+ using CollisionTableData = soa::Join<aod::Collisions, aod::EvSels, aod::PVMults>;
195+ using TrackTableData = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
203196 void processData (CollisionTableData::iterator const & collision,
204197 TrackTableData const & tracks, aod::FT0s const &,
205198 BCsRun3 const &);
206199 PROCESS_SWITCH (ueCharged, processData, " process data" , false );
207200
208201 // add new method
209202};
203+
210204WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
211205{
212206 WorkflowSpec workflow{};
213207 workflow.push_back (adaptAnalysisTask<ueCharged>(cfgc));
214208 return workflow;
215209}
210+
216211// implementation
217212float ueCharged::deltaPhi (float phia, float phib,
218213 float rangeMin = -o2::constants::math::PI / 2.0 ,
@@ -289,7 +284,6 @@ void ueCharged::init(InitContext const&)
289284 {{ptAxis}, {121 , -3.025 , 3.025 , " #it{DCA}_{xy} (cm)" }});
290285 ue.add (" hPtDCAMat" , " Material; DCA_xy; Nch" , HistType::kTH2D ,
291286 {{ptAxis}, {121 , -3.025 , 3.025 , " #it{DCA}_{xy} (cm)" }});
292-
293287 ue.add (" hmultTrue" , " mult true" , HistType::kTH1F ,
294288 {{200 , -0.5 , 199.5 , " " }});
295289 ue.add (" hmultTrueGen" , " mult true all Gen" , HistType::kTH1F ,
@@ -299,8 +293,8 @@ void ueCharged::init(InitContext const&)
299293 HistType::kTH1D , {ptAxist});
300294
301295 for (int i = 0 ; i < 3 ; ++i) {
302- ue.add (hPtVsPtLeadingTrue[i].data (), " " , HistType::kTH2D ,
303- {{ptAxist}, {ptAxis}});
296+ ue.add (hPtVsPtLeadingTrue[i].data (), " " , HistType::kTH2D , {{ptAxist}, {ptAxis}});
297+ ue. add (hPtVsPtLeadingTruePS[i]. data (), " " , HistType:: kTH2D , {{ptAxist}, {ptAxis}});
304298 ue.add (pNumDenTrueAll[i].data (), " " , HistType::kTProfile , {ptAxist});
305299 ue.add (pSumPtTrueAll[i].data (), " " , HistType::kTProfile , {ptAxist});
306300 ue.add (pNumDenTrue[i].data (), " " , HistType::kTProfile , {ptAxist});
@@ -324,14 +318,21 @@ void ueCharged::init(InitContext const&)
324318 ue.add (" phiEta" , " ;#eta;#varphi" , HistType::kTH2F ,
325319 {{50 , -2.5 , 2.5 }, {200 , 0 ., 2 * o2::constants::math::PI, " " }});
326320 ue.add (" hvtxZ" , " vtxZ" , HistType::kTH1F , {{40 , -20.0 , 20.0 , " " }});
327-
328321 ue.add (" hCounter" , " Counter; sel; Nev" , HistType::kTH1D , {{7 , 0 , 7 , " " }});
329322 ue.add (" hPtLeadingRecPS" , " rec pTleading after physics selection" ,
330323 HistType::kTH1D , {ptAxist});
331324 ue.add (" hPtLeadingMeasured" , " measured pTleading after physics selection" ,
332325 HistType::kTH1D , {ptAxist});
333326 ue.add (" hPtLeadingVsTracks" , " " , HistType::kTProfile , {{ptAxist}});
334327
328+ auto h = ue.get <TH1>(HIST (" hCounter" ));
329+ h->GetXaxis ()->SetBinLabel (1 , " Events read" );
330+ h->GetXaxis ()->SetBinLabel (2 , " INEL" );
331+ h->GetXaxis ()->SetBinLabel (3 , " Sel8" );
332+ h->GetXaxis ()->SetBinLabel (4 , " NoSameBunchPileup" );
333+ h->GetXaxis ()->SetBinLabel (5 , " IsGoodZvtxFT0vsPV" );
334+ h->GetXaxis ()->SetBinLabel (6 , " posZ passed" );
335+
335336 for (int i = 0 ; i < 3 ; ++i) {
336337 ue.add (pNumDenMeasuredPS[i].data (),
337338 " Number Density; ; #LT #it{N}_{trk} #GT" , HistType::kTProfile ,
@@ -512,7 +513,7 @@ template <typename C, typename P>
512513void ueCharged::processTrue (const C& mcCollision, const P& particles)
513514{
514515 int multTrue = 0 ;
515- int multTrueINEL = 0 ;
516+ // int multTrueINEL = 0;
516517 for (const auto & particle : particles) {
517518 auto pdgParticle = pdg->GetParticle (particle.pdgCode ());
518519 if (!pdgParticle || pdgParticle->Charge () == 0 .) {
@@ -522,7 +523,7 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles)
522523 continue ;
523524 }
524525 if (std::abs (particle.eta ()) <= 1.0 ) {
525- multTrueINEL++;
526+ // multTrueINEL++;
526527 }
527528 if (std::abs (particle.eta ()) >= cfgTrkEtaCut) {
528529 continue ;
@@ -534,7 +535,16 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles)
534535 ue.fill (HIST (" hPtInPrimGen" ), particle.pt ());
535536 }
536537 ue.fill (HIST (" hmultTrueGen" ), multTrue);
537- if (std::abs (mcCollision.posZ ()) > 10 .f && multTrueINEL <= 0 ) {
538+
539+ if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc (particles, pdg)) {
540+ return ;
541+ }
542+
543+ if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc (particles, pdg)) {
544+ return ;
545+ }
546+
547+ if (std::abs (mcCollision.posZ ()) > 10 .f ) {
538548 return ;
539549 }
540550
@@ -648,6 +658,14 @@ void ueCharged::processMeas(const C& collision, const T& tracks)
648658
649659 ue.fill (HIST (" hCounter" ), 0 );
650660
661+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
662+ return ;
663+ }
664+
665+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
666+ return ;
667+ }
668+
651669 ue.fill (HIST (" hCounter" ), 1 );
652670
653671 if (sel8 && !collision.sel8 ()) {
@@ -668,6 +686,7 @@ void ueCharged::processMeas(const C& collision, const T& tracks)
668686 }
669687
670688 ue.fill (HIST (" hCounter" ), 3 );
689+
671690 if (goodzvertex &&
672691 !collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV )) {
673692 return ;
@@ -860,6 +879,14 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
860879 const P& particles)
861880{
862881
882+ if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc (particles, pdg)) {
883+ return ;
884+ }
885+
886+ if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc (particles, pdg)) {
887+ return ;
888+ }
889+
863890 ue.fill (HIST (" hStat" ), collision.size ());
864891 auto vtxZ = collision.posZ ();
865892
@@ -960,6 +987,14 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
960987
961988 ue.fill (HIST (" hCounter" ), 0 );
962989
990+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
991+ return ;
992+ }
993+
994+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
995+ return ;
996+ }
997+
963998 ue.fill (HIST (" hCounter" ), 1 );
964999
9651000 if (sel8 && !collision.sel8 ()) {
@@ -978,18 +1013,20 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
9781013 !collision.selection_bit (o2::aod::evsel::kNoSameBunchPileup )) {
9791014 return ;
9801015 }
1016+
9811017 ue.fill (HIST (" hCounter" ), 3 );
9821018
9831019 if (goodzvertex &&
9841020 !collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV )) {
9851021 return ;
9861022 }
1023+
9871024 ue.fill (HIST (" hCounter" ), 4 );
9881025
989- // only PS
9901026 if ((std::abs (collision.posZ ()) >= 10 .f )) {
9911027 return ;
9921028 }
1029+
9931030 ue.fill (HIST (" hCounter" ), 5 );
9941031
9951032 ue.fill (HIST (pNumDenTruePS[0 ]), flPtTrue, ueTrue[0 ]);
@@ -1020,7 +1057,24 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
10201057 continue ;
10211058 }
10221059 ue.fill (HIST (" hPtInPrim" ), particle.pt ());
1060+
1061+ // remove the autocorrelation
1062+ if (flIndexTrue == particle.globalIndex ()) {
1063+ continue ;
1064+ }
1065+ double dPhi = deltaPhi (particle.phi (), flPhiTrue);
1066+
1067+ // definition of the topological regions
1068+ if (std::abs (dPhi) < o2::constants::math::PI / 3.0 ) { // near side
1069+ ue.fill (HIST (hPtVsPtLeadingTruePS[0 ]), flPtTrue, particle.pt ());
1070+ } else if (std::abs (dPhi - o2::constants::math::PI) <
1071+ o2::constants::math::PI / 3.0 ) { // away side
1072+ ue.fill (HIST (hPtVsPtLeadingTruePS[1 ]), flPtTrue, particle.pt ());
1073+ } else { // transverse side
1074+ ue.fill (HIST (hPtVsPtLeadingTruePS[2 ]), flPtTrue, particle.pt ());
1075+ }
10231076 }
1077+
10241078 ue.fill (HIST (" hmultTrue" ), multTrue);
10251079
10261080 // loop over selected tracks
@@ -1229,6 +1283,14 @@ void ueCharged::analyzeEventAndTrackSelection(const C& collision,
12291283 const T& tracks)
12301284{
12311285
1286+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
1287+ return ;
1288+ }
1289+
1290+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
1291+ return ;
1292+ }
1293+
12321294 // z-vertex from FT0 vs PV analysis
12331295
12341296 const auto & foundBC = collision.template foundBC_as <BCsRun3>();
0 commit comments