@@ -93,6 +93,17 @@ static constexpr std::string_view kEvntType[] = {"SE/", "ME/"};
9393auto static constexpr kMinFt0cCell = 96 ;
9494AxisSpec axisEvent{10 , 0.5 , 9.5 , " #Event" , " EventAxis" };
9595
96+ namespace o2 ::aod
97+ {
98+ namespace longrangemultclass
99+ {
100+ DECLARE_SOA_COLUMN (Multiplicity, multiplicity, float ); // ! Centrality/multiplicity value
101+ } // namespace longrangemultclass
102+ DECLARE_SOA_TABLE (LRMultTables, " AOD" , " LRMULTTABLE" , longrangemultclass::Multiplicity); // ! Transient multiplicity table
103+
104+ using LRMultTable = LRMultTables::iterator;
105+ } // namespace o2::aod
106+
96107struct LongrangeCorrelation {
97108
98109 struct : ConfigurableGroup {
@@ -139,7 +150,7 @@ struct LongrangeCorrelation {
139150 ConfigurableAxis amplitudeFt0a{" amplitudeFt0a" , {5000 , 0 , 10000 }, " FT0A amplitude" };
140151 ConfigurableAxis channelFt0aAxis{" channelFt0aAxis" , {96 , 0.0 , 96.0 }, " FT0A channel" };
141152
142- using CollTable = soa::Join<aod::Collisions, aod::EvSels>;
153+ using CollTable = soa::Join<aod::Collisions, aod::EvSels, aod::LRMultTables >;
143154 using TrksTable = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>>;
144155 using MftTrkTable = soa::Filtered<aod::MFTTracks>;
145156 Preslice<TrksTable> perColGlobal = aod::track::collisionId;
@@ -325,11 +336,11 @@ struct LongrangeCorrelation {
325336 }
326337
327338 template <CorrelationContainer::CFStep step, typename TTarget, typename TTriggers, typename TFT0s>
328- void fillCorrFt0aGlobal (TTarget target, TTriggers const & triggers, TFT0s const & ft0, bool mixing, float vz)
339+ void fillCorrFt0aGlobal (TTarget target, TTriggers const & triggers, TFT0s const & ft0, bool mixing, float vz, float multiplicity )
329340 {
330341 int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
331342 if (!mixing)
332- histos.fill (HIST (" Ft0aGlobal/SE/hMult_used" ), triggers. size () );
343+ histos.fill (HIST (" Ft0aGlobal/SE/hMult_used" ), multiplicity );
333344 for (auto const & triggerTrack : triggers) {
334345 if (!mixing)
335346 histos.fill (HIST (" Ft0aGlobal/SE/Trig_hist" ), fSampleIndex , vz, triggerTrack.pt ());
@@ -367,11 +378,11 @@ struct LongrangeCorrelation {
367378 } // fillCorrFt0aGlobal
368379
369380 template <CorrelationContainer::CFStep step, typename TTarget, typename TTriggers, typename TFT0s>
370- void fillCorrFt0cGlobal (TTarget target, TTriggers const & triggers, TFT0s const & ft0, bool mixing, float vz)
381+ void fillCorrFt0cGlobal (TTarget target, TTriggers const & triggers, TFT0s const & ft0, bool mixing, float vz, float multiplicity )
371382 {
372383 int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
373384 if (!mixing)
374- histos.fill (HIST (" Ft0cGlobal/SE/hMult_used" ), triggers. size () );
385+ histos.fill (HIST (" Ft0cGlobal/SE/hMult_used" ), multiplicity );
375386 for (auto const & triggerTrack : triggers) {
376387 if (!mixing)
377388 histos.fill (HIST (" Ft0cGlobal/SE/Trig_hist" ), fSampleIndex , vz, triggerTrack.pt ());
@@ -409,11 +420,11 @@ struct LongrangeCorrelation {
409420 } // fillCorrFt0cGlobal
410421
411422 template <CorrelationContainer::CFStep step, typename TTarget, typename TTriggers, typename TMFTs>
412- void fillCorrMftGlobal (TTarget target, TTriggers const & triggers, TMFTs const & mft, bool mixing, float vz)
423+ void fillCorrMftGlobal (TTarget target, TTriggers const & triggers, TMFTs const & mft, bool mixing, float vz, float multiplicity )
413424 {
414425 int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
415426 if (!mixing)
416- histos.fill (HIST (" MftGlobal/SE/hMult_used" ), triggers. size () );
427+ histos.fill (HIST (" MftGlobal/SE/hMult_used" ), multiplicity );
417428 for (auto const & triggerTrack : triggers) {
418429 if (!mixing)
419430 histos.fill (HIST (" MftGlobal/SE/Trig_hist" ), fSampleIndex , vz, triggerTrack.pt ());
@@ -444,12 +455,12 @@ struct LongrangeCorrelation {
444455 } // trigger tracks
445456 } // fillCorrMftGlobal
446457
447- template <CorrelationContainer::CFStep step, typename TTarget, typename TTracks, typename TTriggers, typename TFT0s>
448- void fillCorrFt0aMft (TTarget target, TTracks const & tracks, TTriggers const & triggers, TFT0s const & ft0, bool mixing, float vz)
458+ template <CorrelationContainer::CFStep step, typename TTarget, typename TTriggers, typename TFT0s>
459+ void fillCorrFt0aMft (TTarget target, TTriggers const & triggers, TFT0s const & ft0, bool mixing, float vz, float multiplicity )
449460 {
450461 int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
451462 if (!mixing)
452- histos.fill (HIST (" Ft0aMft/SE/hMult_used" ), tracks. size () );
463+ histos.fill (HIST (" Ft0aMft/SE/hMult_used" ), multiplicity );
453464 for (auto const & triggerTrack : triggers) {
454465 if (!isMftTrackSelected (triggerTrack)) {
455466 continue ;
@@ -493,12 +504,12 @@ struct LongrangeCorrelation {
493504 } // trigger tracks
494505 } // fillCorrFt0aMft
495506
496- template <CorrelationContainer::CFStep step, typename TTarget, typename TTriggers, typename TFT0As, typename TFT0Cs>
497- void fillCorrFt0aFt0c (TTarget target, TTriggers const & triggers, TFT0As const & ft0a, TFT0Cs const & ft0c, bool mixing, float vz)
507+ template <CorrelationContainer::CFStep step, typename TTarget, typename TFT0As, typename TFT0Cs>
508+ void fillCorrFt0aFt0c (TTarget target, TFT0As const & ft0a, TFT0Cs const & ft0c, bool mixing, float vz, float multiplicity )
498509 {
499510 int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
500511 if (!mixing)
501- histos.fill (HIST (" Ft0aFt0c/SE/hMult_used" ), triggers. size () );
512+ histos.fill (HIST (" Ft0aFt0c/SE/hMult_used" ), multiplicity );
502513
503514 for (std::size_t iChA = 0 ; iChA < ft0a.channelA ().size (); iChA++) {
504515 if (!mixing)
@@ -581,10 +592,11 @@ struct LongrangeCorrelation {
581592 if (col.has_foundFT0 ()) {
582593 fillYield<kFT0AGLOBAL , kSE >(tracks);
583594 const auto & ft0 = col.foundFT0 ();
584- if (tracks.size () < cfgMinMult || tracks.size () >= cfgMaxMult) {
595+ auto multiplicity = col.multiplicity ();
596+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
585597 return ;
586598 }
587- fillCorrFt0aGlobal<CorrelationContainer::kCFStepReconstructed >(sameFt0aGlobal, tracks, ft0, false , col.posZ ());
599+ fillCorrFt0aGlobal<CorrelationContainer::kCFStepReconstructed >(sameFt0aGlobal, tracks, ft0, false , col.posZ (), multiplicity );
588600 }
589601 } // same event
590602
@@ -596,10 +608,11 @@ struct LongrangeCorrelation {
596608 if (col.has_foundFT0 ()) {
597609 fillYield<kFT0CGLOBAL , kSE >(tracks);
598610 const auto & ft0 = col.foundFT0 ();
599- if (tracks.size () < cfgMinMult || tracks.size () >= cfgMaxMult) {
611+ auto multiplicity = col.multiplicity ();
612+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
600613 return ;
601614 }
602- fillCorrFt0cGlobal<CorrelationContainer::kCFStepReconstructed >(sameFt0cGlobal, tracks, ft0, false , col.posZ ());
615+ fillCorrFt0cGlobal<CorrelationContainer::kCFStepReconstructed >(sameFt0cGlobal, tracks, ft0, false , col.posZ (), multiplicity );
603616 }
604617 } // same event
605618
@@ -609,39 +622,42 @@ struct LongrangeCorrelation {
609622 return ;
610623 }
611624 fillYield<kMFTGLOBAL , kSE >(tracks);
612- if (tracks.size () < cfgMinMult || tracks.size () >= cfgMaxMult) {
625+ auto multiplicity = col.multiplicity ();
626+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
613627 return ;
614628 }
615- fillCorrMftGlobal<CorrelationContainer::kCFStepReconstructed >(sameMftGlobal, tracks, mfttracks, false , col.posZ ());
629+ fillCorrMftGlobal<CorrelationContainer::kCFStepReconstructed >(sameMftGlobal, tracks, mfttracks, false , col.posZ (), multiplicity );
616630 } // same event
617631
618- void processFt0aMftSE (CollTable::iterator const & col, aod::FT0s const &, TrksTable const & tracks, MftTrkTable const & mfttracks)
632+ void processFt0aMftSE (CollTable::iterator const & col, aod::FT0s const &, MftTrkTable const & mfttracks)
619633 {
620634 if (!isEventSelected (col)) {
621635 return ;
622636 }
623637 if (col.has_foundFT0 ()) {
624638 fillYield<kFT0AMFT , kSE >(mfttracks);
625639 const auto & ft0 = col.foundFT0 ();
626- if (tracks.size () < cfgMinMult || tracks.size () >= cfgMaxMult) {
640+ auto multiplicity = col.multiplicity ();
641+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
627642 return ;
628643 }
629- fillCorrFt0aMft<CorrelationContainer::kCFStepReconstructed >(sameFt0aMft, tracks, mfttracks, ft0, false , col.posZ ());
644+ fillCorrFt0aMft<CorrelationContainer::kCFStepReconstructed >(sameFt0aMft, mfttracks, ft0, false , col.posZ (), multiplicity );
630645 }
631646 } // same event
632647
633- void processFt0aFt0cSE (CollTable::iterator const & col, aod::FT0s const &, TrksTable const & tracks )
648+ void processFt0aFt0cSE (CollTable::iterator const & col, aod::FT0s const &)
634649 {
635650 if (!isEventSelected (col)) {
636651 return ;
637652 }
638653 if (col.has_foundFT0 ()) {
639- histos.fill (HIST (" Ft0aFt0c/SE/hMult" ), tracks.size ());
654+ auto multiplicity = col.multiplicity ();
655+ histos.fill (HIST (" Ft0aFt0c/SE/hMult" ), multiplicity);
640656 const auto & ft0 = col.foundFT0 ();
641- if (tracks. size () < cfgMinMult || tracks. size () >= cfgMaxMult) {
657+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
642658 return ;
643659 }
644- fillCorrFt0aFt0c<CorrelationContainer::kCFStepReconstructed >(sameFt0aFt0c, tracks, ft0, ft0, false , col.posZ ());
660+ fillCorrFt0aFt0c<CorrelationContainer::kCFStepReconstructed >(sameFt0aFt0c, ft0, ft0, false , col.posZ (), multiplicity );
645661 }
646662 } // same event
647663
@@ -665,10 +681,11 @@ struct LongrangeCorrelation {
665681 auto slicedTriggerTracks = tracks.sliceBy (perColGlobal, col1.globalIndex ());
666682 fillYield<kFT0AGLOBAL , kME >(slicedTriggerTracks);
667683 const auto & ft0 = col2.foundFT0 ();
668- if (slicedTriggerTracks.size () < cfgMinMult || slicedTriggerTracks.size () >= cfgMaxMult) {
684+ auto multiplicity = col1.multiplicity ();
685+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
669686 continue ;
670687 }
671- fillCorrFt0aGlobal<CorrelationContainer::kCFStepReconstructed >(mixedFt0aGlobal, slicedTriggerTracks, ft0, true , col1.posZ ());
688+ fillCorrFt0aGlobal<CorrelationContainer::kCFStepReconstructed >(mixedFt0aGlobal, slicedTriggerTracks, ft0, true , col1.posZ (), multiplicity );
672689 }
673690 }
674691 } // mixed event
@@ -693,10 +710,11 @@ struct LongrangeCorrelation {
693710 auto slicedTriggerTracks = tracks.sliceBy (perColGlobal, col1.globalIndex ());
694711 fillYield<kFT0CGLOBAL , kME >(slicedTriggerTracks);
695712 const auto & ft0 = col2.foundFT0 ();
696- if (slicedTriggerTracks.size () < cfgMinMult || slicedTriggerTracks.size () >= cfgMaxMult) {
713+ auto multiplicity = col1.multiplicity ();
714+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
697715 continue ;
698716 }
699- fillCorrFt0cGlobal<CorrelationContainer::kCFStepReconstructed >(mixedFt0cGlobal, slicedTriggerTracks, ft0, true , col1.posZ ());
717+ fillCorrFt0cGlobal<CorrelationContainer::kCFStepReconstructed >(mixedFt0cGlobal, slicedTriggerTracks, ft0, true , col1.posZ (), multiplicity );
700718 }
701719 }
702720 } // mixed event
@@ -716,10 +734,11 @@ struct LongrangeCorrelation {
716734 if (!isEventSelected (col1) || !isEventSelected (col2)) {
717735 continue ;
718736 }
719- if ((tracks1.size () < cfgMinMult || tracks1.size () >= cfgMaxMult)) {
737+ auto multiplicity = col1.multiplicity ();
738+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
720739 continue ;
721740 }
722- fillCorrMftGlobal<CorrelationContainer::kCFStepReconstructed >(mixedMftGlobal, tracks1, tracks2, true , col1.posZ ());
741+ fillCorrMftGlobal<CorrelationContainer::kCFStepReconstructed >(mixedMftGlobal, tracks1, tracks2, true , col1.posZ (), multiplicity );
723742 }
724743 } // mixed event
725744
@@ -740,14 +759,14 @@ struct LongrangeCorrelation {
740759 continue ;
741760 }
742761 if (col1.has_foundFT0 () && col2.has_foundFT0 ()) {
743- auto slicedGlobalTracks = tracks.sliceBy (perColGlobal, col1.globalIndex ());
744762 auto slicedTriggerMftTracks = mfttracks.sliceBy (perColMft, col1.globalIndex ());
745763 fillYield<kFT0AMFT , kME >(slicedTriggerMftTracks);
746764 const auto & ft0 = col2.foundFT0 ();
747- if (slicedGlobalTracks.size () < cfgMinMult || slicedGlobalTracks.size () >= cfgMaxMult) {
765+ auto multiplicity = col1.multiplicity ();
766+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
748767 continue ;
749768 }
750- fillCorrFt0aMft<CorrelationContainer::kCFStepReconstructed >(mixedFt0aMft, slicedGlobalTracks, slicedTriggerMftTracks, ft0, true , col1.posZ ());
769+ fillCorrFt0aMft<CorrelationContainer::kCFStepReconstructed >(mixedFt0aMft, slicedTriggerMftTracks, ft0, true , col1.posZ (), multiplicity );
751770 }
752771 }
753772 } // mixed event
@@ -769,14 +788,14 @@ struct LongrangeCorrelation {
769788 continue ;
770789 }
771790 if (col1.has_foundFT0 () && col2.has_foundFT0 ()) {
772- auto slicedTriggerTracks = tracks. sliceBy (perColGlobal, col1.globalIndex () );
773- histos.fill (HIST (" Ft0aFt0c/ME/hMult" ), slicedTriggerTracks. size () );
791+ auto multiplicity = col1.multiplicity ( );
792+ histos.fill (HIST (" Ft0aFt0c/ME/hMult" ), multiplicity );
774793 const auto & ft0a = col1.foundFT0 ();
775794 const auto & ft0c = col2.foundFT0 ();
776- if (slicedTriggerTracks. size () < cfgMinMult || slicedTriggerTracks. size () >= cfgMaxMult) {
795+ if (multiplicity < cfgMinMult || multiplicity >= cfgMaxMult) {
777796 continue ;
778797 }
779- fillCorrFt0aFt0c<CorrelationContainer::kCFStepReconstructed >(mixedFt0aFt0c, slicedTriggerTracks, ft0a, ft0c, true , col1.posZ ());
798+ fillCorrFt0aFt0c<CorrelationContainer::kCFStepReconstructed >(mixedFt0aFt0c, ft0a, ft0c, true , col1.posZ (), multiplicity );
780799 }
781800 }
782801 } // mixed event
@@ -794,7 +813,89 @@ struct LongrangeCorrelation {
794813 PROCESS_SWITCH (LongrangeCorrelation, processFt0aFt0cME, " mixed event FT0a vs FT0c" , false );
795814};
796815
816+ struct MultiplicityClassifier {
817+ Produces<aod::LRMultTables> multvalue;
818+ Configurable<float > cfgEtaCut{" cfgEtaCut" , 0 .8f , " Eta range to consider" };
819+ Configurable<float > dcaZ{" dcaZ" , 0 .2f , " Custom DCA Z cut (ignored if negative)" };
820+ Configurable<float > cfgPtCutMin{" cfgPtCutMin" , 0 .2f , " minimum accepted track pT" };
821+ Configurable<float > cfgPtCutMax{" cfgPtCutMax" , 3 .0f , " maximum accepted track pT" };
822+ HistogramRegistry histos{" histos" , {}, OutputObjHandlingPolicy::AnalysisObject};
823+
824+ Filter fTrackSelectionITS = ncheckbit(aod::track::v001::detectorMap, (uint8_t )o2::aod::track::ITS) &&
825+ ncheckbit (aod::track::trackCutFlag, TrackSelectionIts);
826+ Filter fTrackSelectionTPC = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t )o2::aod::track::TPC),
827+ ncheckbit (aod::track::trackCutFlag, TrackSelectionTpc), true );
828+ Filter fTrackSelectionDCA = ifnode(dcaZ.node() > 0 .f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly),
829+ ncheckbit (aod::track::trackCutFlag, TrackSelectionDca));
830+ Filter fTracksEta = nabs(aod::track::eta) < cfgEtaCut;
831+ Filter fTracksPt = (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax);
832+
833+ void init (InitContext const &)
834+ {
835+ int enabledFunctions = 0 ;
836+ if (doprocessTracks) {
837+ histos.add (" htrackPt" , " htrackPt" , {HistType::kTH1F , {{10 , 0 ., 10 .}}});
838+ histos.add (" htrackMult" , " htrackMult" , {HistType::kTH1F , {{500 , 0 ., 500 .}}});
839+ enabledFunctions++;
840+ }
841+ if (doprocessFT0C) {
842+ histos.add (" hCentFt0c" , " hCentFt0c" , {HistType::kTH1F , {{100 , 0 ., 100 .}}});
843+ enabledFunctions++;
844+ }
845+ if (doprocessFV0A) {
846+ histos.add (" hCentFv0a" , " hCentFv0a" , {HistType::kTH1F , {{100 , 0 ., 100 .}}});
847+ enabledFunctions++;
848+ }
849+ if (doprocessFT0M) {
850+ histos.add (" hCentFt0m" , " hCentFt0m" , {HistType::kTH1F , {{100 , 0 ., 100 .}}});
851+ enabledFunctions++;
852+ }
853+ if (enabledFunctions != 1 ) {
854+ LOGP (fatal, " {} multiplicity classifier enabled but we need exactly 1." , enabledFunctions);
855+ }
856+ }
857+
858+ void processTracks (aod::Collision const &, soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>> const & tracks)
859+ {
860+ multvalue (tracks.size ());
861+ histos.fill (HIST (" htrackMult" ), tracks.size ());
862+ for (auto const & iTrk : tracks)
863+ histos.fill (HIST (" htrackPt" ), iTrk.pt ());
864+ }
865+
866+ void processFT0C (aod::CentFT0Cs const & centralities)
867+ {
868+ for (auto const & c : centralities) {
869+ multvalue (c.centFT0C ());
870+ histos.fill (HIST (" hCentFt0c" ), c.centFT0C ());
871+ }
872+ }
873+
874+ void processFV0A (aod::CentFV0As const & centralities)
875+ {
876+ for (auto const & c : centralities) {
877+ multvalue (c.centFV0A ());
878+ histos.fill (HIST (" hCentFv0a" ), c.centFV0A ());
879+ }
880+ }
881+
882+ void processFT0M (aod::CentFT0Ms const & centralities)
883+ {
884+ for (auto const & c : centralities) {
885+ multvalue (c.centFT0M ());
886+ histos.fill (HIST (" hCentFt0m" ), c.centFT0M ());
887+ }
888+ }
889+
890+ PROCESS_SWITCH (MultiplicityClassifier, processTracks, " Select track count as multiplicity" , false );
891+ PROCESS_SWITCH (MultiplicityClassifier, processFT0C, " Select FT0C centrality as multiplicity" , false );
892+ PROCESS_SWITCH (MultiplicityClassifier, processFV0A, " Select FV0A centrality as multiplicity" , false );
893+ PROCESS_SWITCH (MultiplicityClassifier, processFT0M, " Select FT0M centrality as multiplicity" , false );
894+ };
895+
797896WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
798897{
799- return WorkflowSpec{adaptAnalysisTask<LongrangeCorrelation>(cfgc)};
898+ return WorkflowSpec{
899+ adaptAnalysisTask<LongrangeCorrelation>(cfgc),
900+ adaptAnalysisTask<MultiplicityClassifier>(cfgc)};
800901}
0 commit comments