2929#include " Common/DataModel/PIDResponseTPC.h"
3030#include " Common/DataModel/TrackSelectionTables.h"
3131
32+ #include " CCDB/BasicCCDBManager.h"
33+ #include " DataFormatsParameters/GRPMagField.h"
3234#include " Framework/ASoAHelpers.h"
3335#include " Framework/AnalysisDataModel.h"
3436#include " Framework/AnalysisTask.h"
@@ -62,13 +64,11 @@ using namespace constants::physics;
6264using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels,
6365 aod::Run3MatchedToBCSparse>;
6466
65- // =============================================================================
66- // Main Analysis Struct
67- // =============================================================================
6867struct MultiplicityPt {
6968
7069 // Service
7170 Service<o2::framework::O2DatabasePDG> pdg;
71+ Service<ccdb::BasicCCDBManager> ccdb;
7272 static constexpr int CentBinMax = 100 ;
7373 static constexpr int MultBinMax = 200 ;
7474 static constexpr int RecMultBinMax = 100 ;
@@ -82,9 +82,6 @@ struct MultiplicityPt {
8282
8383 };
8484
85- // ===========================================================================
86- // Configurable Parameters
87- // ===========================================================================
8885 Configurable<bool > isRun3{" isRun3" , true , " is Run3 dataset" };
8986 Configurable<float > cfgCutVertex{" cfgCutVertex" , 10 .0f , " Accepted z-vertex range" };
9087 Configurable<int > cfgINELCut{" cfgINELCut" , 0 , " INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1" };
@@ -123,7 +120,12 @@ struct MultiplicityPt {
123120 Configurable<bool > nClTPCPIDCut{" nClTPCPIDCut" , true , " Apply TPC clusters for PID cut" };
124121
125122 // Phi cut parameters
126- Configurable<bool > applyPhiCut{" applyPhiCut" , false , " Apply phi sector cut" };
123+ Configurable<bool > applyPhiCut{" applyPhiCut" , false , " Apply phi sector cut to remove problematic TPC regions" };
124+ Configurable<float > pTthresholdPhiCut{" pTthresholdPhiCut" , 2 .0f , " pT threshold above which to apply phi cut" };
125+ Configurable<double > phiCutLowParam1{" phiCutLowParam1" , 0.119297 , " First parameter for low phi cut" };
126+ Configurable<double > phiCutLowParam2{" phiCutLowParam2" , 0.000379693 , " Second parameter for low phi cut" };
127+ Configurable<double > phiCutHighParam1{" phiCutHighParam1" , 0.16685 , " First parameter for high phi cut" };
128+ Configurable<double > phiCutHighParam2{" phiCutHighParam2" , 0.00981942 , " Second parameter for high phi cut" };
127129
128130 // Basic track cuts
129131 Configurable<float > cfgTrkEtaCut{" cfgTrkEtaCut" , 0 .8f , " Eta range for tracks" };
@@ -137,13 +139,13 @@ struct MultiplicityPt {
137139 // Custom track cuts matching spectraTOF
138140 TrackSelection customTrackCuts;
139141
142+ // TF1 pointers for phi cuts
143+ TF1* fphiCutLow = nullptr ;
144+ TF1* fphiCutHigh = nullptr ;
145+
140146 // Histogram Registry
141147 HistogramRegistry ue;
142148
143- // ===========================================================================
144- // Table Definitions - Using individual tables, not joined for MC
145- // ===========================================================================
146-
147149 // Data collisions (not used but kept for completeness)
148150 using CollisionTableData = soa::Join<aod::Collisions, aod::EvSels, aod::McCentFT0Ms>;
149151
@@ -165,9 +167,6 @@ struct MultiplicityPt {
165167 // Preslice for MC particles
166168 Preslice<aod::McParticles> perMCCol = aod::mcparticle::mcCollisionId;
167169
168- // ===========================================================================
169- // Constants
170- // ===========================================================================
171170 enum ParticleSpecies : int {
172171 kPion = 0 ,
173172 kKaon = 1 ,
@@ -179,9 +178,68 @@ struct MultiplicityPt {
179178 static constexpr int PDGKaon = kKPlus ;
180179 static constexpr int PDGProton = kProton ;
181180
182- // ===========================================================================
183- // Helper Functions
184- // ===========================================================================
181+ // Get magnetic field from CCDB
182+ int getMagneticField (uint64_t timestamp)
183+ {
184+ static o2::parameters::GRPMagField* grpo = nullptr ;
185+ if (grpo == nullptr ) {
186+ grpo = ccdb->getForTimeStamp <o2::parameters::GRPMagField>(" GLO/Config/GRPMagField" , timestamp);
187+ if (grpo == nullptr ) {
188+ LOGF (fatal, " GRP object not found for timestamp %llu" , timestamp);
189+ return 0 ;
190+ }
191+ LOGF (info, " Retrieved GRP for timestamp %llu with magnetic field of %d kG" , timestamp, grpo->getNominalL3Field ());
192+ }
193+ return grpo->getNominalL3Field ();
194+ }
195+
196+ // Get transformed phi for phi cut (with magnetic field)
197+ float getTransformedPhi (const float phi, const int charge, const float magField) const
198+ {
199+ float transformedPhi = phi;
200+ if (magField < 0 ) {
201+ transformedPhi = o2::constants::math::TwoPI - transformedPhi;
202+ }
203+ if (charge < 0 ) {
204+ transformedPhi = o2::constants::math::TwoPI - transformedPhi;
205+ }
206+ transformedPhi += o2::constants::math::PI / 18 .0f ;
207+ transformedPhi = std::fmod (transformedPhi, o2::constants::math::PI / 9 .0f );
208+ return transformedPhi;
209+ }
210+
211+ // Phi cut function (with magnetic field)
212+ template <typename TrackType>
213+ bool passedPhiCut (const TrackType& track, float magField) const
214+ {
215+ if (!applyPhiCut.value ) {
216+ return true ;
217+ }
218+
219+ if (track.pt () < pTthresholdPhiCut.value ) {
220+ return true ;
221+ }
222+
223+ float pt = track.pt ();
224+ float phi = track.phi ();
225+ int charge = track.sign ();
226+
227+ if (magField < 0 ) {
228+ phi = o2::constants::math::TwoPI - phi;
229+ }
230+ if (charge < 0 ) {
231+ phi = o2::constants::math::TwoPI - phi;
232+ }
233+
234+ phi += o2::constants::math::PI / 18 .0f ;
235+ phi = std::fmod (phi, o2::constants::math::PI / 9 .0f );
236+
237+ if (phi < fphiCutHigh->Eval (pt) && phi > fphiCutLow->Eval (pt)) {
238+ return false ;
239+ }
240+
241+ return true ;
242+ }
185243
186244 template <typename ParticleContainer>
187245 int countGeneratedChargedPrimaries (const ParticleContainer& particles, float etaMax, float ptMin) const
@@ -257,7 +315,7 @@ struct MultiplicityPt {
257315 }
258316
259317 template <typename TrackType>
260- bool passesTrackSelection (TrackType const & track) const
318+ bool passesTrackSelection (TrackType const & track, float magField = 0 ) const
261319 {
262320 if (track.eta () < cfgCutEtaMin.value || track.eta () > cfgCutEtaMax.value )
263321 return false ;
@@ -277,6 +335,10 @@ struct MultiplicityPt {
277335 if (!passedNClTPCPIDCut (track))
278336 return false ;
279337
338+ // Add phi cut with magnetic field
339+ if (!passedPhiCut (track, magField))
340+ return false ;
341+
280342 return true ;
281343 }
282344
@@ -348,9 +410,6 @@ struct MultiplicityPt {
348410 return true ;
349411 }
350412
351- // ===========================================================================
352- // Process Switches
353- // ===========================================================================
354413 void processData (CollisionTableData::iterator const & collision,
355414 TrackTableData const & tracks,
356415 BCsRun3 const & bcs);
@@ -365,9 +424,6 @@ struct MultiplicityPt {
365424 BCsRun3 const & bcs);
366425 PROCESS_SWITCH (MultiplicityPt, processMC, " process MC" , true );
367426
368- // ===========================================================================
369- // Standard Framework Functions
370- // ===========================================================================
371427 void init (InitContext const &);
372428
373429 void endOfStream (EndOfStreamContext& /* eos*/ )
@@ -382,24 +438,36 @@ struct MultiplicityPt {
382438 }
383439};
384440
385- // =============================================================================
386- // Workflow Definition
387- // =============================================================================
388441WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
389442{
390443 return WorkflowSpec{adaptAnalysisTask<MultiplicityPt>(cfgc)};
391444}
392445
393- // =============================================================================
394- // Implementation of Member Functions
395- // =============================================================================
396-
397446void MultiplicityPt::init (InitContext const &)
398447{
399448 LOG (info) << " ==================================================" ;
400449 LOG (info) << " Initializing MultiplicityPt task with full centrality diagnostics" ;
401450 LOG (info) << " ==================================================" ;
402451
452+ // Initialize phi cut functions
453+ if (applyPhiCut.value ) {
454+ fphiCutLow = new TF1 (" StandardPhiCutLow" ,
455+ Form (" %f/x/x+pi/18.0-%f" ,
456+ phiCutLowParam1.value , phiCutLowParam2.value ),
457+ 0 , 50 );
458+ fphiCutHigh = new TF1 (" StandardPhiCutHigh" ,
459+ Form (" %f/x+pi/18.0+%f" ,
460+ phiCutHighParam1.value , phiCutHighParam2.value ),
461+ 0 , 50 );
462+
463+ LOGF (info, " === Phi Cut Parameters ===" );
464+ LOGF (info, " Low cut: %.6f/x² + pi/18 - %.6f" ,
465+ phiCutLowParam1.value , phiCutLowParam2.value );
466+ LOGF (info, " High cut: %.6f/x + pi/18 + %.6f" ,
467+ phiCutHighParam1.value , phiCutHighParam2.value );
468+ LOGF (info, " Applied for pT > %.1f GeV/c" , pTthresholdPhiCut.value );
469+ }
470+
403471 if (useCustomTrackCuts.value ) {
404472 LOG (info) << " Using custom track cuts matching spectraTOF approach" ;
405473 customTrackCuts = getGlobalTrackSelectionRun3ITSMatch (itsPattern.value );
@@ -448,10 +516,6 @@ void MultiplicityPt::init(InitContext const&)
448516 }
449517 AxisSpec recoMultAxis = {recoMultBins, " N_{ch}^{reco}" };
450518
451- // ===========================================================================
452- // Comprehensive Histogram Registration
453- // ===========================================================================
454-
455519 // Centrality diagnostic histograms - USE FINE BINNING
456520 ue.add (" Centrality/hCentRaw" , " Raw FT0M Centrality (no cuts);Centrality (%);Counts" ,
457521 HistType::kTH1D , {centFineAxis});
@@ -578,6 +642,16 @@ void MultiplicityPt::init(InitContext const&)
578642 ue.add (" Inclusive/hPtMeasuredVsCent" , " All measured tracks (PID) vs centrality;#it{p}_{T} (GeV/#it{c});FT0M Centrality (%)" ,
579643 HistType::kTH2D , {ptAxis, centAxis});
580644
645+ // Phi cut monitoring histograms
646+ if (applyPhiCut.value ) {
647+ ue.add (" PhiCut/hPtVsPhiPrimeBefore" , " pT vs φ' before cut;p_{T} (GeV/c);φ'" ,
648+ HistType::kTH2F , {{100 , 0 , 10 }, {100 , 0 , 0.4 }});
649+ ue.add (" PhiCut/hPtVsPhiPrimeAfter" , " pT vs φ' after cut;p_{T} (GeV/c);φ'" ,
650+ HistType::kTH2F , {{100 , 0 , 10 }, {100 , 0 , 0.4 }});
651+ ue.add (" PhiCut/hRejectionRate" , " Track rejection rate by phi cut;p_{T} (GeV/c);Rejection Rate" ,
652+ HistType::kTProfile , {{100 , 0 , 10 }});
653+ }
654+
581655 // Particle-specific histograms
582656 const std::array<std::string, kNSpecies > particleNames = {" Pion" , " Kaon" , " Proton" };
583657 const std::array<std::string, kNSpecies > particleSymbols = {" #pi^{#pm}" , " K^{#pm}" , " p+#bar{p}" };
@@ -654,12 +728,11 @@ void MultiplicityPt::init(InitContext const&)
654728 LOG (info) << " === Initialized MultiplicityPt task with full centrality diagnostics ===" ;
655729 LOG (info) << " Standard centrality binning: " << centBinningStd.size () - 1 << " bins (0-100%)" ;
656730 LOG (info) << " Fine centrality binning: " << centBinningFine.size () - 1 << " bins (0-100%)" ;
731+ if (applyPhiCut.value ) {
732+ LOG (info) << " Phi cut ENABLED for pT > " << pTthresholdPhiCut.value << " GeV/c" ;
733+ }
657734}
658735
659- // =============================================================================
660- // Process Functions
661- // =============================================================================
662-
663736void MultiplicityPt::processData (CollisionTableData::iterator const & /* collision*/ ,
664737 TrackTableData const & /* tracks*/ ,
665738 BCsRun3 const & /* bcs*/ )
@@ -681,9 +754,6 @@ void MultiplicityPt::processMC(TrackTableMC const& tracks,
681754 LOG (info) << " Total collision labels: " << labels.size ();
682755 LOG (info) << " Total centrality entries: " << centTable.size ();
683756
684- // ===========================================================================
685- // DEBUG: Print raw centrality information first
686- // ===========================================================================
687757 LOG (info) << " \n === CENTRALITY DEBUG - RAW DATA ===" ;
688758 LOG (info) << " First 20 centrality values from centTable:" ;
689759 int debugCount = 0 ;
@@ -714,9 +784,6 @@ void MultiplicityPt::processMC(TrackTableMC const& tracks,
714784 LOG (info) << " Checking if centrality might be inverted..." ;
715785 LOG (info) << " Will check correlation with multiplicity in the next step." ;
716786
717- // ===========================================================================
718- // FIRST PASS: Build maps of MC collision ID to generated particle counts
719- // ===========================================================================
720787 std::map<int64_t , int > mcCollisionToNch;
721788 std::map<int64_t , float > mcCollisionVz;
722789 std::set<int64_t > physicsSelectedMCCollisions;
@@ -797,9 +864,6 @@ void MultiplicityPt::processMC(TrackTableMC const& tracks,
797864 LOG (info) << " INEL>1: " << mcINELgt1;
798865 LOG (info) << " Physics-selected MC collisions: " << physicsSelectedMCCollisions.size ();
799866
800- // ===========================================================================
801- // Build maps for labels and centrality
802- // ===========================================================================
803867 std::map<int64_t , int64_t > recoToMcMap;
804868 std::map<int64_t , float > recoToCentMap;
805869
@@ -837,9 +901,6 @@ void MultiplicityPt::processMC(TrackTableMC const& tracks,
837901 LOG (info) << " recoToMcMap size: " << recoToMcMap.size ();
838902 LOG (info) << " recoToCentMap size: " << recoToCentMap.size ();
839903
840- // ===========================================================================
841- // DEBUG: Check correlation between centrality and multiplicity
842- // ===========================================================================
843904 LOG (info) << " \n === CENTRALITY VS MULTIPLICITY DEBUG ===" ;
844905
845906 // Create temporary vectors to check correlation
@@ -1003,6 +1064,13 @@ void MultiplicityPt::processMC(TrackTableMC const& tracks,
10031064 nSelectedEvents++;
10041065 nPassAll++;
10051066
1067+ // Get magnetic field for phi cut
1068+ float magField = 0 ;
1069+ if (applyPhiCut.value ) {
1070+ const auto & bc = collision.bc_as <BCsRun3>();
1071+ magField = getMagneticField (bc.timestamp ());
1072+ }
1073+
10061074 // Process tracks in selected events
10071075 int nTracksInEvent = 0 ;
10081076 for (const auto & track : tracks) {
@@ -1011,9 +1079,22 @@ void MultiplicityPt::processMC(TrackTableMC const& tracks,
10111079 if (track.collisionId () != collId)
10121080 continue ;
10131081
1014- if (!passesTrackSelection (track)) {
1082+ // Fill phi cut monitoring before cut
1083+ if (applyPhiCut.value && track.pt () >= pTthresholdPhiCut.value ) {
1084+ float phiPrime = getTransformedPhi (track.phi (), track.sign (), magField);
1085+ ue.fill (HIST (" PhiCut/hPtVsPhiPrimeBefore" ), track.pt (), phiPrime);
1086+ }
1087+
1088+ if (!passesTrackSelection (track, magField)) {
10151089 continue ;
10161090 }
1091+
1092+ // Fill phi cut monitoring after cut
1093+ if (applyPhiCut.value && track.pt () >= pTthresholdPhiCut.value ) {
1094+ float phiPrime = getTransformedPhi (track.phi (), track.sign (), magField);
1095+ ue.fill (HIST (" PhiCut/hPtVsPhiPrimeAfter" ), track.pt (), phiPrime);
1096+ }
1097+
10171098 nTracksInEvent++;
10181099
10191100 // Fill TPC cluster histograms
0 commit comments