@@ -78,14 +78,15 @@ struct FlowGfwNonflow {
7878 Configurable<int > cfgMpar{" cfgMpar" , 4 , " Highest order of pt-pt correlations" };
7979 Configurable<int > cfgCentEstimator{" cfgCentEstimator" , 0 , " 0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A, 4:NTPV, 5:NGlobal, 6:MFT" };
8080 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 " };
81+ Configurable<int > cfgUseNchCorrection{" cfgUseNchCorrection" , 1 , " Nch used on the x-axis ; 0: tracks table size , 1: efficiency-corrected, 2: accepted reconstructed, 3: response-matrix corrected " };
8282 Configurable<bool > cfgRunByRun{" cfgRunByRun" , false , " Use run-by-run NUA" };
8383 Configurable<bool > cfgFillQA{" cfgFillQA" , false , " Fill QA histograms" };
8484 Configurable<bool > cfgUseCentralMoments{" cfgUseCentralMoments" , true , " Use central moments in vn-pt calculations" };
8585 Configurable<bool > cfgUseMultiplicityFlowWeights{" cfgUseMultiplicityFlowWeights" , true , " Enable or disable the use of multiplicity-based event weighting" };
8686 struct : ConfigurableGroup {
8787 Configurable<std::string> cfgEfficiencyPath{" cfgEfficiencyPath" , " " , " CCDB path to efficiency object" };
8888 Configurable<bool > cfgUse2DEfficiency{" cfgUse2DEfficiency" , false , " Toggle the use of 2D (pt, centrality) efficiency versus centrality integrated efficiency" };
89+ Configurable<std::string> cfgNchResponsePath{" cfgNchResponsePath" , " " , " CCDB path to TH2 response matrix (reconstructed Nch on x, generated Nch on y)" };
8990 Configurable<std::string> cfgAcceptancePath{" cfgAcceptancePath" , " " , " CCDB path to acceptance object" };
9091 } cfgCorrections;
9192 struct : ConfigurableGroup {
@@ -181,6 +182,7 @@ struct FlowGfwNonflow {
181182
182183 struct Config {
183184 TH1 * mEfficiency = nullptr ;
185+ TH2 * mNchResponse = nullptr ;
184186 std::vector<GFWWeights*> mAcceptance ;
185187 bool correctionsLoaded = false ;
186188 } correctionsConfig;
@@ -379,6 +381,9 @@ struct FlowGfwNonflow {
379381 registry.add (" eventQA/before/occ_mult_cent" , " ; occupancy; N_{ch}; centrality (%)" , {HistType::kTH3D , {occAxis, nchAxis, centAxis}});
380382 }
381383 }
384+ if (doprocessMCReco) {
385+ registry.add (" MCReco/Nch_reco_gen" , " ; N_{ch}^{reco}; N_{ch}^{gen}" , {HistType::kTH2D , {nchAxis, nchAxis}});
386+ }
382387 registry.add (" eventQA/before/centrality" , " ; centrality (%); Counts" , {HistType::kTH1D , {centAxis}});
383388 registry.add (" eventQA/before/multiplicity" , " ; N_{ch}; Counts" , {HistType::kTH1D , {nchAxis}});
384389 registry.addClone (" eventQA/before/" , " eventQA/after/" );
@@ -639,9 +644,43 @@ struct FlowGfwNonflow {
639644 }
640645 LOGF (info, " Loaded efficiency histogram from %s" , cfgCorrections.cfgEfficiencyPath .value .c_str ());
641646 }
647+ if (!cfgCorrections.cfgNchResponsePath .value .empty ()) {
648+ correctionsConfig.mNchResponse = ccdb->getForTimeStamp <TH2D >(cfgCorrections.cfgNchResponsePath , timestamp);
649+ if (correctionsConfig.mNchResponse == nullptr ) {
650+ LOGF (fatal, " Could not load Nch response matrix from %s" , cfgCorrections.cfgNchResponsePath .value .c_str ());
651+ }
652+ LOGF (info, " Loaded Nch response matrix from %s" , cfgCorrections.cfgNchResponsePath .value .c_str ());
653+ } else if (cfgUseNchCorrection == 3 ) {
654+ LOGF (fatal, " cfgUseNchCorrection=3 requires cfgNchResponsePath" );
655+ }
642656 correctionsConfig.correctionsLoaded = true ;
643657 }
644658
659+ float getResponseCorrectedNch (const unsigned int multReconstructed) const
660+ {
661+ if (!correctionsConfig.mNchResponse ) {
662+ return multReconstructed;
663+ }
664+ const auto * response = correctionsConfig.mNchResponse ;
665+ const int recoBin = response->GetXaxis ()->FindFixBin (multReconstructed);
666+ if (recoBin < 1 || recoBin > response->GetNbinsX ()) {
667+ LOGF (warn, " Reconstructed Nch %u is outside the response matrix; using the uncorrected value" , multReconstructed);
668+ return reconstructedNch;
669+ }
670+ double sumWeights = 0 .;
671+ double sumGeneratedNch = 0 .;
672+ for (int genBin = 1 ; genBin <= response->GetNbinsY (); ++genBin) {
673+ const double weight = response->GetBinContent (recoBin, genBin);
674+ sumWeights += weight;
675+ sumGeneratedNch += weight * response->GetYaxis ()->GetBinCenter (genBin);
676+ }
677+ if (sumWeights <= 0 .) {
678+ LOGF (warn, " Response matrix has no entries for reconstructed Nch %u; using the uncorrected value" , multReconstructed);
679+ return multReconstructed;
680+ }
681+ return sumGeneratedNch / sumWeights;
682+ }
683+
645684 template <typename TTrack>
646685 double getAcceptance (const TTrack& track, const double & vtxz)
647686 { // 0 ref, 1 ch, 2 pi, 3 ka, 4 pr
@@ -1014,7 +1053,7 @@ struct FlowGfwNonflow {
10141053 };
10151054
10161055 template <DataType dt, typename TCollision, typename TTracks>
1017- void processCollision (const TCollision& collision, const TTracks& tracks, const float & centrality, const float & field)
1056+ void processCollision (const TCollision& collision, const TTracks& tracks, const float & centrality, const float & field, const int generatedNch = - 1 )
10181057 {
10191058 if (tracks.size () < 1 ) {
10201059 return ;
@@ -1037,6 +1076,11 @@ struct FlowGfwNonflow {
10371076 for (const auto & track : tracks) {
10381077 processTrack (track, vtxz, field, centrality, acceptedTracks);
10391078 }
1079+ if constexpr (dt == Reco) {
1080+ if (generatedNch >= 0 ) {
1081+ registry.fill (HIST (" MCReco/Nch_reco_gen" ), acceptedTracks.totaluncorr , generatedNch);
1082+ }
1083+ }
10401084 if (dt != Gen && cfgFillQA) {
10411085 registry.fill (HIST (" trackQA/after/Nch_corrected" ), acceptedTracks.total );
10421086 registry.fill (HIST (" trackQA/after/Nch_uncorrected" ), acceptedTracks.totaluncorr );
@@ -1053,6 +1097,9 @@ struct FlowGfwNonflow {
10531097 case 2 :
10541098 multiplicity = acceptedTracks.totaluncorr ;
10551099 break ;
1100+ case 3 :
1101+ multiplicity = (dt == Gen) ? acceptedTracks.totaluncorr : getResponseCorrectedNch (acceptedTracks.totaluncorr );
1102+ break ;
10561103 default :
10571104 multiplicity = tracks.size ();
10581105 break ;
@@ -1155,8 +1202,10 @@ struct FlowGfwNonflow {
11551202
11561203 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>>;
11571204 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>;
1205+ using FilteredGFWMCCollisions = soa::Filtered<GFWMCCollisions>;
11581206 using GFWTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection, aod::TracksDCA>>;
11591207 using GFWMCTracks = soa::Filtered<soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection, aod::TracksDCA, aod::McTrackLabels>>;
1208+ Preslice<aod::McParticles> particlesPerMcCollision = aod::mcparticle::mcCollisionId;
11601209
11611210 SliceCache cache;
11621211 Partition<GFWTracks> posTracks = aod::track::signed1Pt > 0 .0f ;
@@ -1221,7 +1270,7 @@ struct FlowGfwNonflow {
12211270 }
12221271 PROCESS_SWITCH (FlowGfwNonflow, processData, " Process analysis for non-derived data" , true );
12231272
1224- void processMCReco (GFWCollisions ::iterator const & collision, aod::BCsWithTimestamps const &, GFWMCTracks const & tracks, aod::McParticles const &)
1273+ void processMCReco (FilteredGFWMCCollisions ::iterator const & collision, aod::BCsWithTimestamps const &, GFWMCTracks const & tracks, aod::McParticles const & particles )
12251274 {
12261275 auto bc = collision.bc_as <aod::BCsWithTimestamps>();
12271276 int run = bc.runNumber ();
@@ -1265,9 +1314,16 @@ struct FlowGfwNonflow {
12651314 if (cfgFillQA) {
12661315 fillEventQA<After>(collision, tracks);
12671316 }
1317+ unsigned int generatedNch = 0 ;
1318+ const auto particlesThisCollision = particles.sliceBy (particlesPerMcCollision, collision.mcCollisionId ());
1319+ for (const auto & particle : particlesThisCollision) {
1320+ if (particle.isPhysicalPrimary () && particle.eta () > cfgKinematics.cfgEtaNch ->first && particle.eta () < cfgKinematics.cfgEtaNch ->second && particle.pt () > gfwMemberCache.ptlow && particle.pt () < gfwMemberCache.ptup ) {
1321+ ++generatedNch;
1322+ }
1323+ }
12681324 loadCorrections (bc);
12691325 auto field = (cfgEventSelection.cfgMagField == DefaultMagneticFieldCut) ? getMagneticField (bc.timestamp ()) : static_cast <int >(cfgEventSelection.cfgMagField );
1270- processCollision<Reco>(collision, tracks, centrality, field);
1326+ processCollision<Reco>(collision, tracks, centrality, field, generatedNch );
12711327 }
12721328 PROCESS_SWITCH (FlowGfwNonflow, processMCReco, " Process analysis for MC reconstructed events" , false );
12731329
0 commit comments