1313// / \file uecharged.cxx
1414// / \brief Underlying event analysis task
1515// / \since November 2021
16- // / \last update: September 2025
16+ // / \last update: October 2025
1717
1818#include " Common/Core/TrackSelection.h"
1919#include " Common/Core/TrackSelectionDefaults.h"
3030#include " Framework/runDataProcessing.h"
3131#include " ReconstructionDataFormats/Track.h"
3232
33+ #include " PWGLF/Utils/inelGt.h"
3334#include " TDatabasePDG.h"
3435#include < TF1.h>
3536#include < TH1F.h>
4546using namespace o2 ;
4647using namespace o2 ::framework;
4748using namespace o2 ::framework::expressions;
48- using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels,
49- aod::Run3MatchedToBCSparse>;
49+ using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels, aod::Run3MatchedToBCSparse>;
5050
5151struct ueCharged {
5252
@@ -80,8 +80,7 @@ struct ueCharged {
8080 selectedTracks.SetMaxChi2PerClusterTPC (4 .f );
8181 selectedTracks.SetRequireHitsInITSLayers (1 , {0 , 1 }); // one hit in any SPD layer
8282 selectedTracks.SetMaxChi2PerClusterITS (36 .f );
83- // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f /
84- // pow(pt, 1.1f); });
83+ // selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); });
8584 selectedTracks.SetMaxDcaZ (2 .f );
8685 return selectedTracks;
8786 }
@@ -91,14 +90,15 @@ struct ueCharged {
9190
9291 Service<o2::framework::O2DatabasePDG> pdg;
9392 float deltaPhi (float phia, float phib, float rangeMin, float rangeMax);
93+
9494 // Configurable for event selection
9595 Configurable<bool > isRun3{" isRun3" , true , " is Run3 dataset" };
9696 Configurable<bool > piluprejection{" piluprejection" , true , " Pileup rejection" };
9797 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" };
9898 Configurable<bool > sel8{" sel8" , true , " Apply the sel8 event selection" };
9999 Configurable<bool > removeITSROFBorder{" removeITSROFBorder" , false , " Remove ITS Read-Out Frame border and only apply kIsTriggerTVX & kNoTimeFrameBorder (recommended for MC)" };
100100 Configurable<bool > analyzeEvandTracksel{" analyzeEvandTracksel" , true , " Analyze the event and track selection" };
101-
101+ Configurable< int > cfgINELCut{ " cfgINELCut " , 0 , " INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1 " };
102102 // acceptance cuts
103103 Configurable<float > cfgTrkEtaCut{" cfgTrkEtaCut" , 0 .8f , " Eta range for tracks" };
104104 Configurable<float > cfgTrkLowPtCut{" cfgTrkLowPtCut" , 0 .15f , " Minimum constituent pT" };
@@ -130,6 +130,9 @@ struct ueCharged {
130130 static constexpr std::string_view hPtVsPtLeadingTrue[3 ] = {
131131 " hPtVsPtLeadingTrue_NS" , " hPtVsPtLeadingTrue_AS" ,
132132 " hPtVsPtLeadingTrue_TS" };
133+ static constexpr std::string_view hPtVsPtLeadingTruePS[3 ] = {
134+ " hPtVsPtLeadingTruePS_NS" , " hPtVsPtLeadingTruePS_AS" ,
135+ " hPtVsPtLeadingTruePS_TS" };
133136 // all wo detector effects
134137 static constexpr std::string_view pNumDenTrueAll[3 ] = {
135138 " pNumDenTrueAll_NS" , " pNumDenTrueAll_AS" , " pNumDenTrueAll_TS" };
@@ -140,7 +143,6 @@ struct ueCharged {
140143 " pNumDenTrue_NS" , " pNumDenTrue_AS" , " pNumDenTrue_TS" };
141144 static constexpr std::string_view pSumPtTrue[3 ] = {
142145 " pSumPtTrue_NS" , " pSumPtTrue_AS" , " pSumPtTrue_TS" };
143-
144146 // this must have all event selection effects, but it has not been implemented
145147 // 50%
146148 static constexpr std::string_view pNumDenTruePS[3 ] = {
@@ -165,16 +167,11 @@ struct ueCharged {
165167 template <typename C, typename T>
166168 void analyzeEventAndTrackSelection (const C& collision, const T& tracks);
167169
168- Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) &&
169- (aod::track::pt > cfgTrkLowPtCut);
170+ Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) && (aod::track::pt > cfgTrkLowPtCut);
170171
171172 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>>;
173+ using CollisionTableMC = soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions, aod::EvSels, aod::PVMults>>;
174+ using TrackTableMC = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::McTrackLabels, aod::TrackSelection>>;
178175 using ParticleTableMC = aod::McParticles;
179176 Preslice<TrackTableMC> perCollision = aod::track::collisionId;
180177 void processMC (CollisionTableMCTrue::iterator const & mcCollision,
@@ -183,36 +180,31 @@ struct ueCharged {
183180 BCsRun3 const &);
184181 PROCESS_SWITCH (ueCharged, processMC, " process MC" , false );
185182
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>>;
183+ using CollisionTableMCData = soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSels, aod::PVMults>;
184+ using TrackTableMCData = soa::Filtered<soa::Join<aod::Tracks, aod::McTrackLabels, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
192185 void processDataMC (CollisionTableMCData::iterator const & collision,
193186 TrackTableMCData const & tracks,
194187 ParticleTableMC const & particles,
195188 aod::McCollisions const & mcCollisions);
196189 PROCESS_SWITCH (ueCharged, processDataMC, " process data MC" , false );
197190
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>>;
191+ using CollisionTableData = soa::Join<aod::Collisions, aod::EvSels, aod::PVMults>;
192+ using TrackTableData = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
203193 void processData (CollisionTableData::iterator const & collision,
204194 TrackTableData const & tracks, aod::FT0s const &,
205195 BCsRun3 const &);
206196 PROCESS_SWITCH (ueCharged, processData, " process data" , false );
207197
208198 // add new method
209199};
200+
210201WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
211202{
212203 WorkflowSpec workflow{};
213204 workflow.push_back (adaptAnalysisTask<ueCharged>(cfgc));
214205 return workflow;
215206}
207+
216208// implementation
217209float ueCharged::deltaPhi (float phia, float phib,
218210 float rangeMin = -o2::constants::math::PI / 2.0 ,
@@ -289,7 +281,6 @@ void ueCharged::init(InitContext const&)
289281 {{ptAxis}, {121 , -3.025 , 3.025 , " #it{DCA}_{xy} (cm)" }});
290282 ue.add (" hPtDCAMat" , " Material; DCA_xy; Nch" , HistType::kTH2D ,
291283 {{ptAxis}, {121 , -3.025 , 3.025 , " #it{DCA}_{xy} (cm)" }});
292-
293284 ue.add (" hmultTrue" , " mult true" , HistType::kTH1F ,
294285 {{200 , -0.5 , 199.5 , " " }});
295286 ue.add (" hmultTrueGen" , " mult true all Gen" , HistType::kTH1F ,
@@ -299,8 +290,8 @@ void ueCharged::init(InitContext const&)
299290 HistType::kTH1D , {ptAxist});
300291
301292 for (int i = 0 ; i < 3 ; ++i) {
302- ue.add (hPtVsPtLeadingTrue[i].data (), " " , HistType::kTH2D ,
303- {{ptAxist}, {ptAxis}});
293+ ue.add (hPtVsPtLeadingTrue[i].data (), " " , HistType::kTH2D , {{ptAxist}, {ptAxis}});
294+ ue. add (hPtVsPtLeadingTruePS[i]. data (), " " , HistType:: kTH2D , {{ptAxist}, {ptAxis}});
304295 ue.add (pNumDenTrueAll[i].data (), " " , HistType::kTProfile , {ptAxist});
305296 ue.add (pSumPtTrueAll[i].data (), " " , HistType::kTProfile , {ptAxist});
306297 ue.add (pNumDenTrue[i].data (), " " , HistType::kTProfile , {ptAxist});
@@ -324,14 +315,21 @@ void ueCharged::init(InitContext const&)
324315 ue.add (" phiEta" , " ;#eta;#varphi" , HistType::kTH2F ,
325316 {{50 , -2.5 , 2.5 }, {200 , 0 ., 2 * o2::constants::math::PI , " " }});
326317 ue.add (" hvtxZ" , " vtxZ" , HistType::kTH1F , {{40 , -20.0 , 20.0 , " " }});
327-
328318 ue.add (" hCounter" , " Counter; sel; Nev" , HistType::kTH1D , {{7 , 0 , 7 , " " }});
329319 ue.add (" hPtLeadingRecPS" , " rec pTleading after physics selection" ,
330320 HistType::kTH1D , {ptAxist});
331321 ue.add (" hPtLeadingMeasured" , " measured pTleading after physics selection" ,
332322 HistType::kTH1D , {ptAxist});
333323 ue.add (" hPtLeadingVsTracks" , " " , HistType::kTProfile , {{ptAxist}});
334324
325+ auto h = ue.get <TH1 >(HIST (" hCounter" ));
326+ h->GetXaxis ()->SetBinLabel (1 , " Events read" );
327+ h->GetXaxis ()->SetBinLabel (2 , " INEL" );
328+ h->GetXaxis ()->SetBinLabel (3 , " Sel8" );
329+ h->GetXaxis ()->SetBinLabel (4 , " NoSameBunchPileup" );
330+ h->GetXaxis ()->SetBinLabel (5 , " IsGoodZvtxFT0vsPV" );
331+ h->GetXaxis ()->SetBinLabel (6 , " posZ passed" );
332+
335333 for (int i = 0 ; i < 3 ; ++i) {
336334 ue.add (pNumDenMeasuredPS[i].data (),
337335 " Number Density; ; #LT #it{N}_{trk} #GT" , HistType::kTProfile ,
@@ -534,7 +532,16 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles)
534532 ue.fill (HIST (" hPtInPrimGen" ), particle.pt ());
535533 }
536534 ue.fill (HIST (" hmultTrueGen" ), multTrue);
537- if (std::abs (mcCollision.posZ ()) > 10 .f && multTrueINEL <= 0 ) {
535+
536+ if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc (particles, pdg)) {
537+ return ;
538+ }
539+
540+ if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc (particles, pdg)) {
541+ return ;
542+ }
543+
544+ if (std::abs (mcCollision.posZ ()) > 10 .f ) {
538545 return ;
539546 }
540547
@@ -648,6 +655,14 @@ void ueCharged::processMeas(const C& collision, const T& tracks)
648655
649656 ue.fill (HIST (" hCounter" ), 0 );
650657
658+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
659+ return ;
660+ }
661+
662+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
663+ return ;
664+ }
665+
651666 ue.fill (HIST (" hCounter" ), 1 );
652667
653668 if (sel8 && !collision.sel8 ()) {
@@ -668,6 +683,7 @@ void ueCharged::processMeas(const C& collision, const T& tracks)
668683 }
669684
670685 ue.fill (HIST (" hCounter" ), 3 );
686+
671687 if (goodzvertex &&
672688 !collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV )) {
673689 return ;
@@ -860,6 +876,14 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
860876 const P& particles)
861877{
862878
879+ if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc (particles, pdg)) {
880+ return ;
881+ }
882+
883+ if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc (particles, pdg)) {
884+ return ;
885+ }
886+
863887 ue.fill (HIST (" hStat" ), collision.size ());
864888 auto vtxZ = collision.posZ ();
865889
@@ -960,6 +984,14 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
960984
961985 ue.fill (HIST (" hCounter" ), 0 );
962986
987+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
988+ return ;
989+ }
990+
991+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
992+ return ;
993+ }
994+
963995 ue.fill (HIST (" hCounter" ), 1 );
964996
965997 if (sel8 && !collision.sel8 ()) {
@@ -978,18 +1010,20 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
9781010 !collision.selection_bit (o2::aod::evsel::kNoSameBunchPileup )) {
9791011 return ;
9801012 }
1013+
9811014 ue.fill (HIST (" hCounter" ), 3 );
9821015
9831016 if (goodzvertex &&
9841017 !collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV )) {
9851018 return ;
9861019 }
1020+
9871021 ue.fill (HIST (" hCounter" ), 4 );
9881022
989- // only PS
9901023 if ((std::abs (collision.posZ ()) >= 10 .f )) {
9911024 return ;
9921025 }
1026+
9931027 ue.fill (HIST (" hCounter" ), 5 );
9941028
9951029 ue.fill (HIST (pNumDenTruePS[0 ]), flPtTrue, ueTrue[0 ]);
@@ -1020,7 +1054,24 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks,
10201054 continue ;
10211055 }
10221056 ue.fill (HIST (" hPtInPrim" ), particle.pt ());
1057+
1058+ // remove the autocorrelation
1059+ if (flIndexTrue == particle.globalIndex ()) {
1060+ continue ;
1061+ }
1062+ double dPhi = deltaPhi (particle.phi (), flPhiTrue);
1063+
1064+ // definition of the topological regions
1065+ if (std::abs (dPhi) < o2::constants::math::PI / 3.0 ) { // near side
1066+ ue.fill (HIST (hPtVsPtLeadingTruePS[0 ]), flPtTrue, particle.pt ());
1067+ } else if (std::abs (dPhi - o2::constants::math::PI ) <
1068+ o2::constants::math::PI / 3.0 ) { // away side
1069+ ue.fill (HIST (hPtVsPtLeadingTruePS[1 ]), flPtTrue, particle.pt ());
1070+ } else { // transverse side
1071+ ue.fill (HIST (hPtVsPtLeadingTruePS[2 ]), flPtTrue, particle.pt ());
1072+ }
10231073 }
1074+
10241075 ue.fill (HIST (" hmultTrue" ), multTrue);
10251076
10261077 // loop over selected tracks
@@ -1229,6 +1280,14 @@ void ueCharged::analyzeEventAndTrackSelection(const C& collision,
12291280 const T& tracks)
12301281{
12311282
1283+ if (cfgINELCut == 1 && !collision.isInelGt0 ()) {
1284+ return ;
1285+ }
1286+
1287+ if (cfgINELCut == 2 && !collision.isInelGt1 ()) {
1288+ return ;
1289+ }
1290+
12321291 // z-vertex from FT0 vs PV analysis
12331292
12341293 const auto & foundBC = collision.template foundBC_as <BCsRun3>();
0 commit comments