1313// / \brief Provides a sparse with usefull two particle correlation info
1414// / \author Thor Jensen (thor.kjaersgaard.jensen@cern.ch) and Debojit Sarkar (debojit.sarkar@cern.ch)
1515
16+ #include < CCDB/BasicCCDBManager.h>
17+ #include " TRandom3.h"
1618#include < vector>
1719
1820#include " Framework/runDataProcessing.h"
1921#include " Framework/AnalysisTask.h"
2022#include " Framework/AnalysisDataModel.h"
2123#include " Framework/ASoAHelpers.h"
22- #include " Framework/ASoA .h"
24+ #include " Framework/StepTHn .h"
2325#include " Framework/HistogramRegistry.h"
2426#include " Framework/RunningWorkflowInfo.h"
2527#include " CommonConstants/MathConstants.h"
26- #include " CCDB/BasicCCDBManager.h"
2728#include " Common/Core/RecoDecay.h"
2829
2930#include " Common/DataModel/EventSelection.h"
3031#include " Common/DataModel/TrackSelectionTables.h"
3132#include " Common/DataModel/Centrality.h"
32- #include " Common/DataModel/Multiplicity.h"
3333#include " PWGCF/DataModel/CorrelationsDerived.h"
34+ #include " Common/DataModel/CollisionAssociationTables.h"
3435#include " PWGCF/Core/CorrelationContainer.h"
3536#include " PWGCF/Core/PairCuts.h"
37+ #include " DataFormatsParameters/GRPObject.h"
38+ #include " DataFormatsParameters/GRPMagField.h"
3639
40+ using namespace o2 ;
41+ using namespace o2 ::framework;
42+ using namespace o2 ::framework::expressions;
3743namespace o2 ::aod
3844{
3945namespace corrsparse
@@ -45,18 +51,14 @@ DECLARE_SOA_TABLE(Multiplicity, "AOD", "MULTIPLICITY",
4551
4652} // namespace o2::aod
4753
48- using namespace o2 ;
49- using namespace o2 ::framework;
50- using namespace o2 ::framework::expressions;
51-
5254// define the filtered collisions and tracks
5355#define O2_DEFINE_CONFIGURABLE (NAME, TYPE, DEFAULT, HELP ) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP};
5456
5557struct CalcNch {
5658 O2_DEFINE_CONFIGURABLE (cfgZVtxCut, float , 10 .0f , " Accepted z-vertex range" )
5759 O2_DEFINE_CONFIGURABLE (cfgPtCutMin, float , 0 .2f , " minimum accepted track pT" )
5860 O2_DEFINE_CONFIGURABLE (cfgPtCutMax, float , 10 .0f , " maximum accepted track pT" )
59- O2_DEFINE_CONFIGURABLE (cfgEtaCut, float , 0 . 8f , " Eta cut" )
61+ O2_DEFINE_CONFIGURABLE (cfgEtaCut, float , 10 . 0f , " Eta cut" )
6062 O2_DEFINE_CONFIGURABLE (cfgMinMixEventNum, int , 5 , " Minimum number of events to mix" )
6163
6264 Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t ) true ));
@@ -79,32 +81,45 @@ struct CalcNch {
7981
8082 void process (AodCollisions::iterator const & collision, AodTracks const & tracks)
8183 {
84+ // LOGF(info, "multiplicity from tracks %d, multiplicity from collision %d", tracks.size(), collision.numContrib());
8285 multiplicityNch (tracks.size ());
8386 registry.fill (HIST (" Ncharge" ), tracks.size ());
8487 registry.fill (HIST (" zVtx_all" ), collision.posZ ());
8588 }
8689};
8790
8891struct CorrSparse {
92+ Service<ccdb::BasicCCDBManager> ccdb;
93+
8994 O2_DEFINE_CONFIGURABLE (cfgZVtxCut, float , 10 .0f , " Accepted z-vertex range" )
9095 O2_DEFINE_CONFIGURABLE (cfgPtCutMin, float , 0 .2f , " minimum accepted track pT" )
9196 O2_DEFINE_CONFIGURABLE (cfgPtCutMax, float , 10 .0f , " maximum accepted track pT" )
9297 O2_DEFINE_CONFIGURABLE (cfgEtaCut, float , 0 .8f , " Eta cut" )
9398 O2_DEFINE_CONFIGURABLE (cfgMinMixEventNum, int , 5 , " Minimum number of events to mix" )
9499 O2_DEFINE_CONFIGURABLE (cfgMinMult, int , 0 , " Minimum multiplicity for collision" )
95100 O2_DEFINE_CONFIGURABLE (cfgMaxMult, int , 10 , " Maximum multiplicity for collision" )
101+ O2_DEFINE_CONFIGURABLE (cfgMergingCut, float , 0.0 , " Merging cut on track merge" )
102+ O2_DEFINE_CONFIGURABLE (cfgRadiusLow, float , 0.8 , " Low radius for merging cut" )
103+ O2_DEFINE_CONFIGURABLE (cfgRadiusHigh, float , 2.5 , " High radius for merging cut" )
104+ O2_DEFINE_CONFIGURABLE (etaMftTrackMin, float , -5.0 , " Minimum eta for MFT track" )
105+ O2_DEFINE_CONFIGURABLE (etaMftTrackMax, float , 0.0 , " Maximum eta for MFT track" )
106+ O2_DEFINE_CONFIGURABLE (nClustersMftTrack, int , 5 , " Minimum number of clusters for MFT track" )
107+ O2_DEFINE_CONFIGURABLE (cfgSampleSize, double , 10 , " Sample size for mixed event" )
108+
109+ Configurable<bool > processMFT{" processMFT" , true , " Associate particle from MFT" };
96110
97111 ConfigurableAxis axisVertex{" axisVertex" , {10 , -10 , 10 }, " vertex axis for histograms" };
98112 ConfigurableAxis axisEta{" axisEta" , {40 , -1 ., 1 .}, " eta axis for histograms" };
99113 ConfigurableAxis axisPhi{" axisPhi" , {72 , 0.0 , constants::math::TwoPI}, " phi axis for histograms" };
100114 ConfigurableAxis axisPt{" axisPt" , {VARIABLE_WIDTH, 0.5 , 1.0 , 1.5 , 2.0 , 3.0 , 4.0 , 6.0 , 10.0 }, " pt axis for histograms" };
101115 ConfigurableAxis axisDeltaPhi{" axisDeltaPhi" , {72 , -PIHalf, PIHalf * 3 }, " delta phi axis for histograms" };
102- ConfigurableAxis axisDeltaEta{" axisDeltaEta" , {40 , -2 , 2 }, " delta eta axis for histograms" };
116+ ConfigurableAxis axisDeltaEta{" axisDeltaEta" , {48 , -2.4 , 2.4 }, " delta eta axis for histograms" };
103117 ConfigurableAxis axisPtTrigger{" axisPtTrigger" , {VARIABLE_WIDTH, 0.5 , 1.0 , 1.5 , 2.0 , 3.0 , 4.0 , 6.0 , 10.0 }, " pt trigger axis for histograms" };
104118 ConfigurableAxis axisPtAssoc{" axisPtAssoc" , {VARIABLE_WIDTH, 0.5 , 1.0 , 1.5 , 2.0 , 3.0 , 4.0 , 6.0 , 10.0 }, " pt associated axis for histograms" };
105119 ConfigurableAxis axisMultiplicity{" axisMultiplicity" , {VARIABLE_WIDTH, 0 , 5 , 10 , 15 , 20 , 25 , 30 , 35 , 40 , 50 , 60 , 80 , 100 }, " multiplicity / centrality axis for histograms" };
106120 ConfigurableAxis vtxMix{" vtxMix" , {VARIABLE_WIDTH, -10 , -9 , -8 , -7 , -6 , -5 , -4 , -3 , -2 , -1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }, " vertex axis for mixed event histograms" };
107121 ConfigurableAxis multMix{" multMix" , {VARIABLE_WIDTH, 0 , 5 , 10 , 15 , 20 , 25 , 30 , 35 , 40 , 50 , 60 , 80 , 100 }, " multiplicity / centrality axis for mixed event histograms" };
122+ ConfigurableAxis axisSample{" axisSample" , {cfgSampleSize, 0 , cfgSampleSize}, " sample axis for histograms" };
108123
109124 ConfigurableAxis axisVertexEfficiency{" axisVertexEfficiency" , {10 , -10 , 10 }, " vertex axis for efficiency histograms" };
110125 ConfigurableAxis axisEtaEfficiency{" axisEtaEfficiency" , {20 , -1.0 , 1.0 }, " eta axis for efficiency histograms" };
@@ -114,18 +129,26 @@ struct CorrSparse {
114129 Filter collisionFilter = (nabs(aod::collision::posZ) < cfgZVtxCut) && (aod::corrsparse::multiplicity) > cfgMinMult && (aod::corrsparse::multiplicity) < cfgMaxMult && (aod::evsel::sel8) == true ;
115130 Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t ) true ));
116131
117- using AodCollisions = soa::Filtered<soa::Join<aod::Collisions, aod::EvSel, o2::aod::Multiplicity>>; // aod::CentFT0Cs
118- using AodTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection, aod::TracksExtra>>;
119-
120132 // Define the outputs
121133 OutputObj<CorrelationContainer> same{Form (" sameEvent_%i_%i" , static_cast <int >(cfgMinMult), static_cast <int >(cfgMaxMult))};
122134 OutputObj<CorrelationContainer> mixed{Form (" mixedEvent_%i_%i" , static_cast <int >(cfgMinMult), static_cast <int >(cfgMaxMult))};
123135
124136 HistogramRegistry registry{" registry" };
125137
138+ using AodCollisions = soa::Filtered<soa::Join<aod::Collisions, aod::EvSel, o2::aod::Multiplicity>>; // aod::CentFT0Cs
139+ using AodTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection, aod::TracksExtra>>;
140+
126141 void init (InitContext&)
127142 {
143+ ccdb->setURL (" http://alice-ccdb.cern.ch" );
144+ ccdb->setCaching (true );
145+ ccdb->setLocalObjectValidityChecking ();
146+
147+ auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ();
148+ ccdb->setCreatedNotAfter (now);
149+
128150 LOGF (info, " Starting init" );
151+
129152 // Make histograms to check the distributions after cuts
130153 registry.add (" deltaEta_deltaPhi_same" , " " , {HistType::kTH2D , {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution
131154 registry.add (" deltaEta_deltaPhi_mixed" , " " , {HistType::kTH2D , {axisDeltaPhi, axisDeltaEta}});
@@ -139,7 +162,7 @@ struct CorrSparse {
139162
140163 registry.add (" eventcount" , " bin" , {HistType::kTH1F , {{3 , 0 , 3 , " bin" }}}); // histogram to see how many events are in the same and mixed event
141164
142- std::vector<AxisSpec> corrAxis = {{axisMultiplicity , " Nch " },
165+ std::vector<AxisSpec> corrAxis = {{axisSample , " Sample " },
143166 {axisVertex, " z-vtx (cm)" },
144167 {axisPtTrigger, " p_{T} (GeV/c)" },
145168 {axisPtAssoc, " p_{T} (GeV/c)" },
@@ -160,6 +183,37 @@ struct CorrSparse {
160183 MixedEvent = 3
161184 };
162185
186+ template <typename TTrackAssoc>
187+ bool isAcceptedMftTrack (TTrackAssoc const & mftTrack)
188+ {
189+ // cut on the eta of MFT tracks
190+ if (mftTrack.eta () > etaMftTrackMax || mftTrack.eta () < etaMftTrackMin) {
191+ return false ;
192+ }
193+
194+ // cut on the number of clusters of the reconstructed MFT track
195+ if (mftTrack.nClusters () < nClustersMftTrack) {
196+ return false ;
197+ }
198+
199+ return true ;
200+ }
201+
202+ int getMagneticField (uint64_t timestamp)
203+ {
204+ // Get the magnetic field
205+ static o2::parameters::GRPMagField* grpo = nullptr ;
206+ if (grpo == nullptr ) {
207+ grpo = ccdb->getForTimeStamp <o2::parameters::GRPMagField>(" /GLO/Config/GRPMagField" , timestamp);
208+ if (grpo == nullptr ) {
209+ LOGF (fatal, " GRP object not found for timestamp %llu" , timestamp);
210+ return 0 ;
211+ }
212+ LOGF (info, " Retrieved GRP for timestamp %llu with magnetic field of %d kG" , timestamp, grpo->getNominalL3Field ());
213+ }
214+ return grpo->getNominalL3Field ();
215+ }
216+
163217 // fill multiple histograms
164218 template <typename TCollision, typename TTracks>
165219 void fillYield (TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms.
@@ -174,9 +228,38 @@ struct CorrSparse {
174228 }
175229 }
176230
177- template <CorrelationContainer::CFStep step, typename TTracks>
178- void fillCorrelations (TTracks tracks1, TTracks tracks2, float posZ, int system, float Nch) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms
231+ template <typename TTrack, typename TTrackAssoc>
232+ float getDPhiStar (TTrack const & track1, TTrackAssoc const & track2, float radius, int magField)
233+ {
234+ float charge1 = track1.sign ();
235+ float charge2 = track2.sign ();
236+
237+ float phi1 = track1.phi ();
238+ float phi2 = track2.phi ();
239+
240+ float pt1 = track1.pt ();
241+ float pt2 = track2.pt ();
242+
243+ int fbSign = (magField > 0 ) ? 1 : -1 ;
244+
245+ float dPhiStar = phi1 - phi2 - charge1 * fbSign * std::asin (0.075 * radius / pt1) + charge2 * fbSign * std::asin (0.075 * radius / pt2);
246+
247+ if (dPhiStar > constants::math::PI)
248+ dPhiStar = constants::math::TwoPI - dPhiStar;
249+ if (dPhiStar < -constants::math::PI)
250+ dPhiStar = -constants::math::TwoPI - dPhiStar;
251+
252+ return dPhiStar;
253+ }
254+
255+ //
256+ template <CorrelationContainer::CFStep step, typename TTracks, typename TTracksAssoc>
257+ void fillCorrelations (TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, float Nch, int magneticField) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms
179258 {
259+ TRandom3* gRandom = new TRandom3 ();
260+
261+ int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
262+
180263 // loop over all tracks
181264 for (auto const & track1 : tracks1) {
182265
@@ -187,47 +270,104 @@ struct CorrSparse {
187270 for (auto const & track2 : tracks2) {
188271
189272 if (track1.pt () <= track2.pt ())
190- continue ; // skip if the trigger pt is less than the associate p
273+ continue ; // skip if the trigger pt is less than the associate pt
274+
275+ if (processMFT) {
276+ if constexpr (std::is_same_v<aod::MFTTracks, TTracksAssoc>) {
277+ if (!isAcceptedMftTrack (track2)) {
278+ continue ;
279+ }
280+ }
281+ }
191282
192283 float deltaPhi = RecoDecay::constrainAngle (track1.phi () - track2.phi (), -PIHalf);
193284 float deltaEta = track1.eta () - track2.eta ();
194285
286+ if (std::abs (deltaEta) < cfgMergingCut) {
287+
288+ double dPhiStarHigh = getDPhiStar (track1, track2, cfgRadiusHigh, magneticField);
289+ double dPhiStarLow = getDPhiStar (track1, track2, cfgRadiusLow, magneticField);
290+
291+ const double kLimit = 3.0 * cfgMergingCut;
292+
293+ bool bIsBelow = kFALSE ;
294+
295+ if (std::abs (dPhiStarLow) < kLimit || std::abs (dPhiStarHigh) < kLimit || dPhiStarLow * dPhiStarHigh < 0 ) {
296+ for (double rad (cfgRadiusLow); rad < cfgRadiusHigh; rad += 0.01 ) {
297+ double dPhiStar = getDPhiStar (track1, track2, rad, magneticField);
298+ if (std::abs (dPhiStar) < kLimit ) {
299+ bIsBelow = kTRUE ;
300+ break ;
301+ }
302+ }
303+ if (bIsBelow)
304+ continue ;
305+ }
306+ }
307+
195308 // fill the right sparse and histograms
196309 if (system == SameEvent) {
197- same->getPairHist ()->Fill (step, Nch, posZ, track1.pt (), track2.pt (), deltaPhi, deltaEta);
310+
311+ same->getPairHist ()->Fill (step, fSampleIndex , posZ, track1.pt (), track2.pt (), deltaPhi, deltaEta);
198312 registry.fill (HIST (" deltaEta_deltaPhi_same" ), deltaPhi, deltaEta);
199313 } else if (system == MixedEvent) {
200- mixed->getPairHist ()->Fill (step, Nch, posZ, track1.pt (), track2.pt (), deltaPhi, deltaEta);
314+
315+ mixed->getPairHist ()->Fill (step, fSampleIndex , posZ, track1.pt (), track2.pt (), deltaPhi, deltaEta);
201316 registry.fill (HIST (" deltaEta_deltaPhi_mixed" ), deltaPhi, deltaEta);
202317 }
203318 }
204319 }
205320 }
206321
207- void processSame (AodCollisions::iterator const & collision, AodTracks const & tracks)
322+ void processSame (AodCollisions::iterator const & collision, AodTracks const & tracks, aod::MFTTracks const & mfts, aod::BCsWithTimestamps const & )
208323 {
209324
325+ auto bc = collision.bc_as <aod::BCsWithTimestamps>();
326+
210327 registry.fill (HIST (" eventcount" ), SameEvent); // because its same event i put it in the 1 bin
211328 fillYield (collision, tracks);
212- fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks, tracks, collision.posZ (), SameEvent, tracks.size ()); // fill the SE histogram and Sparse
329+
330+ if (processMFT) {
331+
332+ fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks, mfts, collision.posZ (), SameEvent, tracks.size (), getMagneticField (bc.timestamp ()));
333+
334+ } else {
335+
336+ fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks, tracks, collision.posZ (), SameEvent, tracks.size (), getMagneticField (bc.timestamp ()));
337+ }
213338 }
214339 PROCESS_SWITCH (CorrSparse, processSame, " Process same event" , true );
215340
216341 // event mixing
217-
218342 SliceCache cache;
219343 using MixedBinning = ColumnBinningPolicy<aod::collision::PosZ, aod::corrsparse::Multiplicity>;
220344
221345 // the process for filling the mixed events
222- void processMixed (AodCollisions const & collisions, AodTracks const & tracks)
346+ void processMixed (AodCollisions const & collisions, AodTracks const & tracks, aod::MFTTracks const & MFTtracks, aod::BCsWithTimestamps const & )
223347 {
224- MixedBinning binningOnVtxAndMult{{vtxMix, multMix}, true }; // true is for 'ignore overflows' (true by default)
225- auto tracksTuple = std::make_tuple (tracks);
226- SameKindPair<AodCollisions, AodTracks, MixedBinning> pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1 , collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip
227348
228- for (auto const & [collision1, tracks1, collision2, tracks2] : pairs) {
229- registry.fill (HIST (" eventcount" ), MixedEvent); // fill the mixed event in the 3 bin
230- fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks1, tracks2, collision1.posZ (), MixedEvent, tracks1.size ());
349+ if (processMFT) {
350+ MixedBinning binningOnVtxAndMult{{vtxMix, multMix}, true }; // true is for 'ignore overflows' (true by default)
351+ auto tracksTuple = std::make_tuple (tracks, MFTtracks);
352+ SameKindPair<AodCollisions, AodTracks, MixedBinning> pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1 , collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip
353+
354+ for (auto const & [collision1, tracks1, collision2, tracks2] : pairs) {
355+ registry.fill (HIST (" eventcount" ), MixedEvent); // fill the mixed event in the 3 bin
356+ auto bc = collision1.bc_as <aod::BCsWithTimestamps>();
357+
358+ fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks1, tracks2, collision1.posZ (), MixedEvent, tracks1.size (), getMagneticField (bc.timestamp ()));
359+ }
360+ } else {
361+ MixedBinning binningOnVtxAndMult{{vtxMix, multMix}, true }; // true is for 'ignore overflows' (true by default)
362+ auto tracksTuple = std::make_tuple (tracks, tracks);
363+ SameKindPair<AodCollisions, AodTracks, MixedBinning> pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1 , collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip
364+
365+ for (auto const & [collision1, tracks1, collision2, tracks2] : pairs) {
366+ registry.fill (HIST (" eventcount" ), MixedEvent); // fill the mixed event in the 3 bin
367+ auto bc = collision1.bc_as <aod::BCsWithTimestamps>();
368+
369+ fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks1, tracks2, collision1.posZ (), MixedEvent, tracks1.size (), getMagneticField (bc.timestamp ()));
370+ }
231371 }
232372 }
233373 PROCESS_SWITCH (CorrSparse, processMixed, " Process mixed events" , true );
0 commit comments