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+
1718
1819#include " Common/Core/TrackSelection.h"
1920#include " Common/Core/TrackSelectionDefaults.h"
2930#include " Framework/StaticFor.h"
3031#include " Framework/runDataProcessing.h"
3132#include " ReconstructionDataFormats/Track.h"
33+ #include " PWGLF/Utils/inelGt.h"
3234
3335#include " TDatabasePDG.h"
3436#include < TF1.h>
4547using namespace o2 ;
4648using namespace o2 ::framework;
4749using namespace o2 ::framework::expressions;
48- using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels,
49- aod::Run3MatchedToBCSparse>;
50+ using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels, aod::Run3MatchedToBCSparse>;
5051
5152struct ueCharged {
5253
@@ -80,8 +81,7 @@ struct ueCharged {
8081 selectedTracks.SetMaxChi2PerClusterTPC (4 .f );
8182 selectedTracks.SetRequireHitsInITSLayers (1 , {0 , 1 }); // one hit in any SPD layer
8283 selectedTracks.SetMaxChi2PerClusterITS (36 .f );
83- // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f /
84- // pow(pt, 1.1f); });
84+ // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); });
8585 selectedTracks.SetMaxDcaZ (2 .f );
8686 return selectedTracks;
8787 }
@@ -91,14 +91,15 @@ struct ueCharged {
9191
9292 Service<o2::framework::O2DatabasePDG> pdg;
9393 float deltaPhi (float phia, float phib, float rangeMin, float rangeMax);
94+
9495 // Configurable for event selection
9596 Configurable<bool > isRun3{" isRun3" , true , " is Run3 dataset" };
9697 Configurable<bool > piluprejection{" piluprejection" , true , " Pileup rejection" };
9798 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" };
9899 Configurable<bool > sel8{" sel8" , true , " Apply the sel8 event selection" };
99100 Configurable<bool > removeITSROFBorder{" removeITSROFBorder" , false , " Remove ITS Read-Out Frame border and only apply kIsTriggerTVX & kNoTimeFrameBorder (recommended for MC)" };
100101 Configurable<bool > analyzeEvandTracksel{" analyzeEvandTracksel" , true , " Analyze the event and track selection" };
101-
102+ Configurable< int > cfgINELCut{ " cfgINELCut " , 0 , " INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1 " };
102103 // acceptance cuts
103104 Configurable<float > cfgTrkEtaCut{" cfgTrkEtaCut" , 0 .8f , " Eta range for tracks" };
104105 Configurable<float > cfgTrkLowPtCut{" cfgTrkLowPtCut" , 0 .15f , " Minimum constituent pT" };
@@ -130,6 +131,9 @@ struct ueCharged {
130131 static constexpr std::string_view hPtVsPtLeadingTrue[3 ] = {
131132 " hPtVsPtLeadingTrue_NS" , " hPtVsPtLeadingTrue_AS" ,
132133 " hPtVsPtLeadingTrue_TS" };
134+ static constexpr std::string_view hPtVsPtLeadingTruePS[3 ] = {
135+ " hPtVsPtLeadingTruePS_NS" , " hPtVsPtLeadingTruePS_AS" ,
136+ " hPtVsPtLeadingTruePS_TS" };
133137 // all wo detector effects
134138 static constexpr std::string_view pNumDenTrueAll[3 ] = {
135139 " pNumDenTrueAll_NS" , " pNumDenTrueAll_AS" , " pNumDenTrueAll_TS" };
@@ -140,7 +144,6 @@ struct ueCharged {
140144 " pNumDenTrue_NS" , " pNumDenTrue_AS" , " pNumDenTrue_TS" };
141145 static constexpr std::string_view pSumPtTrue[3 ] = {
142146 " pSumPtTrue_NS" , " pSumPtTrue_AS" , " pSumPtTrue_TS" };
143-
144147 // this must have all event selection effects, but it has not been implemented
145148 // 50%
146149 static constexpr std::string_view pNumDenTruePS[3 ] = {
@@ -165,16 +168,11 @@ struct ueCharged {
165168 template <typename C, typename T>
166169 void analyzeEventAndTrackSelection (const C& collision, const T& tracks);
167170
168- Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) &&
169- (aod::track::pt > cfgTrkLowPtCut);
171+ Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) && (aod::track::pt > cfgTrkLowPtCut);
170172
171173 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>>;
174+ using CollisionTableMC = soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions, aod::EvSels, aod::PVMults>>;
175+ using TrackTableMC = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::McTrackLabels, aod::TrackSelection>>;
178176 using ParticleTableMC = aod::McParticles;
179177 Preslice<TrackTableMC> perCollision = aod::track::collisionId;
180178 void processMC (CollisionTableMCTrue::iterator const & mcCollision,
@@ -183,36 +181,31 @@ struct ueCharged {
183181 BCsRun3 const &);
184182 PROCESS_SWITCH (ueCharged, processMC, " process MC" , false );
185183
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>>;
184+ using CollisionTableMCData = soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSels, aod::PVMults>;
185+ using TrackTableMCData = soa::Filtered<soa::Join<aod::Tracks, aod::McTrackLabels, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
192186 void processDataMC (CollisionTableMCData::iterator const & collision,
193187 TrackTableMCData const & tracks,
194188 ParticleTableMC const & particles,
195189 aod::McCollisions const & mcCollisions);
196190 PROCESS_SWITCH (ueCharged, processDataMC, " process data MC" , false );
197191
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>>;
192+ using CollisionTableData = soa::Join<aod::Collisions, aod::EvSels, aod::PVMults>;
193+ using TrackTableData = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
203194 void processData (CollisionTableData::iterator const & collision,
204195 TrackTableData const & tracks, aod::FT0s const &,
205196 BCsRun3 const &);
206197 PROCESS_SWITCH (ueCharged, processData, " process data" , false );
207198
208199 // add new method
209200};
201+
210202WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
211203{
212204 WorkflowSpec workflow{};
213205 workflow.push_back (adaptAnalysisTask<ueCharged>(cfgc));
214206 return workflow;
215207}
208+
216209// implementation
217210float ueCharged::deltaPhi (float phia, float phib,
218211 float rangeMin = -o2::constants::math::PI / 2.0 ,
@@ -289,7 +282,6 @@ void ueCharged::init(InitContext const&)
289282 {{ptAxis}, {121 , -3.025 , 3.025 , " #it{DCA}_{xy} (cm)" }});
290283 ue.add (" hPtDCAMat" , " Material; DCA_xy; Nch" , HistType::kTH2D ,
291284 {{ptAxis}, {121 , -3.025 , 3.025 , " #it{DCA}_{xy} (cm)" }});
292-
293285 ue.add (" hmultTrue" , " mult true" , HistType::kTH1F ,
294286 {{200 , -0.5 , 199.5 , " " }});
295287 ue.add (" hmultTrueGen" , " mult true all Gen" , HistType::kTH1F ,
@@ -299,8 +291,8 @@ void ueCharged::init(InitContext const&)
299291 HistType::kTH1D , {ptAxist});
300292
301293 for (int i = 0 ; i < 3 ; ++i) {
302- ue.add (hPtVsPtLeadingTrue[i].data (), " " , HistType::kTH2D ,
303- {{ptAxist}, {ptAxis}});
294+ ue.add (hPtVsPtLeadingTrue[i].data (), " " , HistType::kTH2D , {{ptAxist}, {ptAxis}});
295+ ue. add (hPtVsPtLeadingTruePS[i]. data (), " " , HistType:: kTH2D , {{ptAxist}, {ptAxis}});
304296 ue.add (pNumDenTrueAll[i].data (), " " , HistType::kTProfile , {ptAxist});
305297 ue.add (pSumPtTrueAll[i].data (), " " , HistType::kTProfile , {ptAxist});
306298 ue.add (pNumDenTrue[i].data (), " " , HistType::kTProfile , {ptAxist});
@@ -324,14 +316,21 @@ void ueCharged::init(InitContext const&)
324316 ue.add (" phiEta" , " ;#eta;#varphi" , HistType::kTH2F ,
325317 {{50 , -2.5 , 2.5 }, {200 , 0 ., 2 * o2::constants::math::PI, " " }});
326318 ue.add (" hvtxZ" , " vtxZ" , HistType::kTH1F , {{40 , -20.0 , 20.0 , " " }});
327-
328319 ue.add (" hCounter" , " Counter; sel; Nev" , HistType::kTH1D , {{7 , 0 , 7 , " " }});
329320 ue.add (" hPtLeadingRecPS" , " rec pTleading after physics selection" ,
330321 HistType::kTH1D , {ptAxist});
331322 ue.add (" hPtLeadingMeasured" , " measured pTleading after physics selection" ,
332323 HistType::kTH1D , {ptAxist});
333324 ue.add (" hPtLeadingVsTracks" , " " , HistType::kTProfile , {{ptAxist}});
334325
326+ auto h = ue.get <TH1>(HIST (" hCounter" ));
327+ h->GetXaxis ()->SetBinLabel (1 , " Events read" );
328+ h->GetXaxis ()->SetBinLabel (2 , " INEL" );
329+ h->GetXaxis ()->SetBinLabel (3 , " Sel8" );
330+ h->GetXaxis ()->SetBinLabel (4 , " NoSameBunchPileup" );
331+ h->GetXaxis ()->SetBinLabel (5 , " IsGoodZvtxFT0vsPV" );
332+ h->GetXaxis ()->SetBinLabel (6 , " posZ passed" );
333+
335334 for (int i = 0 ; i < 3 ; ++i) {
336335 ue.add (pNumDenMeasuredPS[i].data (),
337336 " Number Density; ; #LT #it{N}_{trk} #GT" , HistType::kTProfile ,
@@ -534,7 +533,16 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles)
534533 ue.fill (HIST (" hPtInPrimGen" ), particle.pt ());
535534 }
536535 ue.fill (HIST (" hmultTrueGen" ), multTrue);
537- if (std::abs (mcCollision.posZ ()) > 10 .f && multTrueINEL <= 0 ) {
536+
537+ if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc (particles, pdg)) {
538+ return ;
539+ }
540+
541+ if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc (particles, pdg)) {
542+ return ;
543+ }
544+
545+ if (std::abs (mcCollision.posZ ()) > 10 .f ) {
538546 return ;
539547 }
540548
@@ -648,6 +656,14 @@ void ueCharged::processMeas(const C& collision, const T& tracks)
648656
649657 ue.fill (HIST (" hCounter" ), 0 );
650658
659+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
660+ return ;
661+ }
662+
663+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
664+ return ;
665+ }
666+
651667 ue.fill (HIST (" hCounter" ), 1 );
652668
653669 if (sel8 && !collision.sel8 ()) {
@@ -668,6 +684,7 @@ void ueCharged::processMeas(const C& collision, const T& tracks)
668684 }
669685
670686 ue.fill (HIST (" hCounter" ), 3 );
687+
671688 if (goodzvertex &&
672689 !collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV )) {
673690 return ;
@@ -860,6 +877,14 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
860877 const P& particles)
861878{
862879
880+ if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc (particles, pdg)) {
881+ return ;
882+ }
883+
884+ if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc (particles, pdg)) {
885+ return ;
886+ }
887+
863888 ue.fill (HIST (" hStat" ), collision.size ());
864889 auto vtxZ = collision.posZ ();
865890
@@ -960,6 +985,14 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
960985
961986 ue.fill (HIST (" hCounter" ), 0 );
962987
988+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
989+ return ;
990+ }
991+
992+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
993+ return ;
994+ }
995+
963996 ue.fill (HIST (" hCounter" ), 1 );
964997
965998 if (sel8 && !collision.sel8 ()) {
@@ -978,18 +1011,20 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
9781011 !collision.selection_bit (o2::aod::evsel::kNoSameBunchPileup )) {
9791012 return ;
9801013 }
1014+
9811015 ue.fill (HIST (" hCounter" ), 3 );
9821016
9831017 if (goodzvertex &&
9841018 !collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV )) {
9851019 return ;
9861020 }
1021+
9871022 ue.fill (HIST (" hCounter" ), 4 );
9881023
989- // only PS
9901024 if ((std::abs (collision.posZ ()) >= 10 .f )) {
9911025 return ;
9921026 }
1027+
9931028 ue.fill (HIST (" hCounter" ), 5 );
9941029
9951030 ue.fill (HIST (pNumDenTruePS[0 ]), flPtTrue, ueTrue[0 ]);
@@ -1020,7 +1055,24 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
10201055 continue ;
10211056 }
10221057 ue.fill (HIST (" hPtInPrim" ), particle.pt ());
1058+
1059+ // remove the autocorrelation
1060+ if (flIndexTrue == particle.globalIndex ()) {
1061+ continue ;
1062+ }
1063+ double dPhi = deltaPhi (particle.phi (), flPhiTrue);
1064+
1065+ // definition of the topological regions
1066+ if (std::abs (dPhi) < o2::constants::math::PI / 3.0 ) { // near side
1067+ ue.fill (HIST (hPtVsPtLeadingTruePS[0 ]), flPtTrue, particle.pt ());
1068+ } else if (std::abs (dPhi - o2::constants::math::PI) <
1069+ o2::constants::math::PI / 3.0 ) { // away side
1070+ ue.fill (HIST (hPtVsPtLeadingTruePS[1 ]), flPtTrue, particle.pt ());
1071+ } else { // transverse side
1072+ ue.fill (HIST (hPtVsPtLeadingTruePS[2 ]), flPtTrue, particle.pt ());
1073+ }
10231074 }
1075+
10241076 ue.fill (HIST (" hmultTrue" ), multTrue);
10251077
10261078 // loop over selected tracks
@@ -1229,6 +1281,14 @@ void ueCharged::analyzeEventAndTrackSelection(const C& collision,
12291281 const T& tracks)
12301282{
12311283
1284+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
1285+ return ;
1286+ }
1287+
1288+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
1289+ return ;
1290+ }
1291+
12321292 // z-vertex from FT0 vs PV analysis
12331293
12341294 const auto & foundBC = collision.template foundBC_as <BCsRun3>();
0 commit comments