4444
4545#include < TF1.h>
4646#include < TH1.h>
47+ #include < TH2.h>
4748#include < TH3.h>
4849#include < TNamed.h>
4950#include < TObjArray.h>
@@ -78,14 +79,15 @@ struct FlowGfwNonflow {
7879 Configurable<int > cfgMpar{" cfgMpar" , 4 , " Highest order of pt-pt correlations" };
7980 Configurable<int > cfgCentEstimator{" cfgCentEstimator" , 0 , " 0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A, 4:NTPV, 5:NGlobal, 6:MFT" };
8081 Configurable<bool > cfgUseNch{" cfgUseNch" , false , " Do correlations as function of Nch" };
81- Configurable<int > cfgUseNchCorrection{" cfgUseNchCorrection" , 1 , " Use correction for Nch ; 0: Use size of tracks table, 1: Use efficiency-corrected Nch values , 2: Use uncorrected Nch values " };
82+ Configurable<int > cfgUseNchCorrection{" cfgUseNchCorrection" , 1 , " Nch used on the x-axis ; 0: tracks table size , 1: efficiency-corrected, 2: accepted reconstructed, 3: Reco.-gen. response-matrix corrected " };
8283 Configurable<bool > cfgRunByRun{" cfgRunByRun" , false , " Use run-by-run NUA" };
8384 Configurable<bool > cfgFillQA{" cfgFillQA" , false , " Fill QA histograms" };
8485 Configurable<bool > cfgUseCentralMoments{" cfgUseCentralMoments" , true , " Use central moments in vn-pt calculations" };
8586 Configurable<bool > cfgUseMultiplicityFlowWeights{" cfgUseMultiplicityFlowWeights" , true , " Enable or disable the use of multiplicity-based event weighting" };
8687 struct : ConfigurableGroup {
8788 Configurable<std::string> cfgEfficiencyPath{" cfgEfficiencyPath" , " " , " CCDB path to efficiency object" };
8889 Configurable<bool > cfgUse2DEfficiency{" cfgUse2DEfficiency" , false , " Toggle the use of 2D (pt, centrality) efficiency versus centrality integrated efficiency" };
90+ Configurable<std::string> cfgNchResponsePath{" cfgNchResponsePath" , " " , " CCDB path to TH2 response matrix (reconstructed Nch on x, generated Nch on y)" };
8991 Configurable<std::string> cfgAcceptancePath{" cfgAcceptancePath" , " " , " CCDB path to acceptance object" };
9092 } cfgCorrections;
9193 struct : ConfigurableGroup {
@@ -181,6 +183,7 @@ struct FlowGfwNonflow {
181183
182184 struct Config {
183185 TH1 * mEfficiency = nullptr ;
186+ TH2 * mNchResponse = nullptr ;
184187 std::vector<GFWWeights*> mAcceptance ;
185188 bool correctionsLoaded = false ;
186189 } correctionsConfig;
@@ -240,6 +243,12 @@ struct FlowGfwNonflow {
240243 ProtonID,
241244 SpeciesCount
242245 };
246+ enum NchSelector {
247+ TableSize,
248+ Corrected,
249+ Uncorrected,
250+ ResponseMatrixCorrected
251+ };
243252
244253 // Generic Framework
245254 GFW * fGFW = new GFW ();
@@ -379,6 +388,9 @@ struct FlowGfwNonflow {
379388 registry.add (" eventQA/before/occ_mult_cent" , " ; occupancy; N_{ch}; centrality (%)" , {HistType::kTH3D , {occAxis, nchAxis, centAxis}});
380389 }
381390 }
391+ if (doprocessMCReco) {
392+ registry.add (" MCReco/Nch_reco_gen" , " ; N_{ch}^{reco}; N_{ch}^{gen}" , {HistType::kTH2D , {nchAxis, nchAxis}});
393+ }
382394 registry.add (" eventQA/before/centrality" , " ; centrality (%); Counts" , {HistType::kTH1D , {centAxis}});
383395 registry.add (" eventQA/before/multiplicity" , " ; N_{ch}; Counts" , {HistType::kTH1D , {nchAxis}});
384396 registry.addClone (" eventQA/before/" , " eventQA/after/" );
@@ -639,9 +651,43 @@ struct FlowGfwNonflow {
639651 }
640652 LOGF (info, " Loaded efficiency histogram from %s" , cfgCorrections.cfgEfficiencyPath .value .c_str ());
641653 }
654+ if (!cfgCorrections.cfgNchResponsePath .value .empty ()) {
655+ correctionsConfig.mNchResponse = ccdb->getForTimeStamp <TH2D >(cfgCorrections.cfgNchResponsePath , timestamp);
656+ if (correctionsConfig.mNchResponse == nullptr ) {
657+ LOGF (fatal, " Could not load Nch response matrix from %s" , cfgCorrections.cfgNchResponsePath .value .c_str ());
658+ }
659+ LOGF (info, " Loaded Nch response matrix from %s" , cfgCorrections.cfgNchResponsePath .value .c_str ());
660+ } else if (cfgUseNchCorrection == NchSelector::ResponseMatrixCorrected) {
661+ LOGF (fatal, " cfgUseNchCorrection=3 requires cfgNchResponsePath" );
662+ }
642663 correctionsConfig.correctionsLoaded = true ;
643664 }
644665
666+ float getResponseCorrectedNch (const unsigned int multReconstructed) const
667+ {
668+ if (!correctionsConfig.mNchResponse ) {
669+ return multReconstructed;
670+ }
671+ const auto * response = correctionsConfig.mNchResponse ;
672+ const int recoBin = response->GetXaxis ()->FindFixBin (multReconstructed);
673+ if (recoBin < 1 || recoBin > response->GetNbinsX ()) {
674+ LOGF (warn, " Reconstructed Nch %u is outside the response matrix; using the uncorrected value" , multReconstructed);
675+ return multReconstructed;
676+ }
677+ double sumWeights = 0 .;
678+ double sumGeneratedNch = 0 .;
679+ for (int genBin = 1 ; genBin <= response->GetNbinsY (); ++genBin) {
680+ const double weight = response->GetBinContent (recoBin, genBin);
681+ sumWeights += weight;
682+ sumGeneratedNch += weight * response->GetYaxis ()->GetBinCenter (genBin);
683+ }
684+ if (sumWeights <= 0 .) {
685+ LOGF (warn, " Response matrix has no entries for reconstructed Nch %u; using the uncorrected value" , multReconstructed);
686+ return multReconstructed;
687+ }
688+ return sumGeneratedNch / sumWeights;
689+ }
690+
645691 template <typename TTrack>
646692 double getAcceptance (const TTrack& track, const double & vtxz)
647693 { // 0 ref, 1 ch, 2 pi, 3 ka, 4 pr
@@ -677,22 +723,22 @@ struct FlowGfwNonflow {
677723 return -1 .;
678724 }
679725 return 1 . / eff;
680- } else {
681- auto * effHist = dynamic_cast <TH1D *>(correctionsConfig.mEfficiency );
682- if (!effHist) {
683- LOGF (error, " Efficiency object at %s is not a TH1D" , cfgCorrections.cfgEfficiencyPath .value .c_str ());
684- return -1 .;
685- }
686- bin = effHist->FindBin (track.pt ());
687- if (!bin) {
688- return -1 .;
689- }
690- const double eff = effHist->GetBinContent (bin);
691- if (!std::isfinite (eff) || eff <= 0 .) {
692- return -1 .;
693- }
694- return 1 . / eff;
695726 }
727+
728+ auto * effHist = dynamic_cast <TH1D *>(correctionsConfig.mEfficiency );
729+ if (!effHist) {
730+ LOGF (error, " Efficiency object at %s is not a TH1D" , cfgCorrections.cfgEfficiencyPath .value .c_str ());
731+ return -1 .;
732+ }
733+ bin = effHist->FindBin (track.pt ());
734+ if (!bin) {
735+ return -1 .;
736+ }
737+ const double eff = effHist->GetBinContent (bin);
738+ if (!std::isfinite (eff) || eff <= 0 .) {
739+ return -1 .;
740+ }
741+ return 1 . / eff;
696742 }
697743
698744 template <typename TCollision>
@@ -1014,7 +1060,7 @@ struct FlowGfwNonflow {
10141060 };
10151061
10161062 template <DataType dt, typename TCollision, typename TTracks>
1017- void processCollision (const TCollision& collision, const TTracks& tracks, const float & centrality, const float & field)
1063+ void processCollision (const TCollision& collision, const TTracks& tracks, const float & centrality, const float & field, const int generatedNch = - 1 )
10181064 {
10191065 if (tracks.size () < 1 ) {
10201066 return ;
@@ -1037,22 +1083,30 @@ struct FlowGfwNonflow {
10371083 for (const auto & track : tracks) {
10381084 processTrack (track, vtxz, field, centrality, acceptedTracks);
10391085 }
1086+ if constexpr (dt == Reco) {
1087+ if (generatedNch >= 0 ) {
1088+ registry.fill (HIST (" MCReco/Nch_reco_gen" ), acceptedTracks.totaluncorr , generatedNch);
1089+ }
1090+ }
10401091 if (dt != Gen && cfgFillQA) {
10411092 registry.fill (HIST (" trackQA/after/Nch_corrected" ), acceptedTracks.total );
10421093 registry.fill (HIST (" trackQA/after/Nch_uncorrected" ), acceptedTracks.totaluncorr );
10431094 }
10441095
10451096 float multiplicity = 0 .f ;
10461097 switch (cfgUseNchCorrection) {
1047- case 0 :
1098+ case NchSelector::TableSize :
10481099 multiplicity = tracks.size ();
10491100 break ;
1050- case 1 :
1101+ case NchSelector::Corrected :
10511102 multiplicity = acceptedTracks.total ;
10521103 break ;
1053- case 2 :
1104+ case NchSelector::Uncorrected :
10541105 multiplicity = acceptedTracks.totaluncorr ;
10551106 break ;
1107+ case NchSelector::ResponseMatrixCorrected:
1108+ multiplicity = (dt == Gen) ? acceptedTracks.totaluncorr : getResponseCorrectedNch (acceptedTracks.totaluncorr );
1109+ break ;
10561110 default :
10571111 multiplicity = tracks.size ();
10581112 break ;
@@ -1155,8 +1209,10 @@ struct FlowGfwNonflow {
11551209
11561210 using GFWCollisions = soa::Filtered<soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::CentFT0Cs, aod::CentFT0CVariant1s, aod::CentFT0Ms, aod::CentFV0As, aod::CentNTPVs, aod::CentNGlobals, aod::CentMFTs>>;
11571211 using GFWMCCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::CentFT0Cs, aod::CentFT0CVariant1s, aod::CentFT0Ms, aod::CentFV0As, aod::CentNTPVs, aod::CentNGlobals, aod::CentMFTs, aod::McCollisionLabels>;
1212+ using FilteredGFWMCCollisions = soa::Filtered<GFWMCCollisions>;
11581213 using GFWTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection, aod::TracksDCA>>;
11591214 using GFWMCTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection, aod::TracksDCA, aod::McTrackLabels>>;
1215+ Preslice<aod::McParticles> particlesPerMcCollision = aod::mcparticle::mcCollisionId;
11601216
11611217 SliceCache cache;
11621218 Partition<GFWTracks> posTracks = aod::track::signed1Pt > 0 .0f ;
@@ -1221,7 +1277,7 @@ struct FlowGfwNonflow {
12211277 }
12221278 PROCESS_SWITCH (FlowGfwNonflow, processData, " Process analysis for non-derived data" , true );
12231279
1224- void processMCReco (GFWCollisions ::iterator const & collision, aod::BCsWithTimestamps const &, GFWMCTracks const & tracks, aod::McParticles const &)
1280+ void processMCReco (FilteredGFWMCCollisions ::iterator const & collision, aod::BCsWithTimestamps const &, GFWMCTracks const & tracks, aod::McParticles const & particles )
12251281 {
12261282 auto bc = collision.bc_as <aod::BCsWithTimestamps>();
12271283 int run = bc.runNumber ();
@@ -1265,9 +1321,16 @@ struct FlowGfwNonflow {
12651321 if (cfgFillQA) {
12661322 fillEventQA<After>(collision, tracks);
12671323 }
1324+ unsigned int generatedNch = 0 ;
1325+ const auto particlesThisCollision = particles.sliceBy (particlesPerMcCollision, collision.mcCollisionId ());
1326+ for (const auto & particle : particlesThisCollision) {
1327+ if (particle.isPhysicalPrimary () && particle.eta () > cfgKinematics.cfgEtaNch ->first && particle.eta () < cfgKinematics.cfgEtaNch ->second && particle.pt () > gfwMemberCache.ptlow && particle.pt () < gfwMemberCache.ptup ) {
1328+ ++generatedNch;
1329+ }
1330+ }
12681331 loadCorrections (bc);
12691332 auto field = (cfgEventSelection.cfgMagField == DefaultMagneticFieldCut) ? getMagneticField (bc.timestamp ()) : static_cast <int >(cfgEventSelection.cfgMagField );
1270- processCollision<Reco>(collision, tracks, centrality, field);
1333+ processCollision<Reco>(collision, tracks, centrality, field, generatedNch );
12711334 }
12721335 PROCESS_SWITCH (FlowGfwNonflow, processMCReco, " Process analysis for MC reconstructed events" , false );
12731336
0 commit comments