@@ -97,7 +97,7 @@ struct zdc2stagecalibration {
9797 uint64_t eorTimestamp = 0 ;
9898 TH2D * gainprofile = nullptr ;
9999 TH3D * spatialprofile = nullptr ;
100- TH2D * qRecenteringProfile = nullptr ;
100+ TH3D * qRecenteringProfile = nullptr ;
101101
102102 static constexpr int kQRecenteringNFeatures = 21 ;
103103 static constexpr int kQRecenteringNMatrixMoments = kQRecenteringNFeatures * (kQRecenteringNFeatures + 1 ) / 2 ;
@@ -123,6 +123,8 @@ struct zdc2stagecalibration {
123123 AxisSpec vertexXYAxis = {100 , -0.5 , 0.5 , " vertex x/y (cm)" };
124124 AxisSpec vertexZAxis = {100 , -10.0 , 10.0 , " vertex z (cm)" };
125125 AxisSpec qComponentAxis = {4 , 0.0 , 4.0 , " Q component" };
126+ AxisSpec qCorrelationComponentAxis = {4 , 0.0 , 4.0 , " A-C correlation component" };
127+ AxisSpec qValueAxis = {200 , -4.0 , 4.0 , " Q" };
126128
127129 histos.add (" hEvtSelInfo" , " hEvtSelInfo" , kTH1F , {{10 , 0.0 , 10.0 }});
128130 auto hEvtSelInfo = histos.get <TH1 >(HIST (" hEvtSelInfo" ));
@@ -161,6 +163,12 @@ struct zdc2stagecalibration {
161163 histos.add (" PhiQA/hPhiAfterGainZNC" , " ZNC #phi after gain calibration;#phi;events" , kTH1F , {phiAxis});
162164 histos.add (" PhiQA/hPhiAfterSpatialZNA" , " ZNA #phi after spatial calibration;#phi;events" , kTH1F , {phiAxis});
163165 histos.add (" PhiQA/hPhiAfterSpatialZNC" , " ZNC #phi after spatial calibration;#phi;events" , kTH1F , {phiAxis});
166+ histos.add (" PhiQA/hPhiRawVsCentralityZNA" , " ZNA #phi raw vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
167+ histos.add (" PhiQA/hPhiRawVsCentralityZNC" , " ZNC #phi raw vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
168+ histos.add (" PhiQA/hPhiAfterGainVsCentralityZNA" , " ZNA #phi after gain vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
169+ histos.add (" PhiQA/hPhiAfterGainVsCentralityZNC" , " ZNC #phi after gain vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
170+ histos.add (" PhiQA/hPhiAfterSpatialVsCentralityZNA" , " ZNA #phi after spatial calibration vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
171+ histos.add (" PhiQA/hPhiAfterSpatialVsCentralityZNC" , " ZNC #phi after spatial calibration vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
164172
165173 // Stage-1 correction input. For each time bin the first 10 y bins contain sum(T_i*T_j), the next 4 contain sum(C*T_i), and the last contains the event count.
166174 histos.add (" GainCalibration/hGainMomentsZNA" , " ZNA linear-regression moments;time from SOR (h);moment index" , kTH2D , {timeAxis, momentAxis});
@@ -170,13 +178,15 @@ struct zdc2stagecalibration {
170178 histos.add (" SpatialCalibration/hSpatialMomentsZNA" , " ZNA normalized pair spatial regression moments;X cross;Y cross;moment index" , kTH3D , {spatialCalibAxis, spatialCalibAxis, spatialMomentAxis});
171179 histos.add (" SpatialCalibration/hSpatialMomentsZNC" , " ZNC normalized pair spatial regression moments;X cross;Y cross;moment index" , kTH3D , {spatialCalibAxis, spatialCalibAxis, spatialMomentAxis});
172180
173- // Q-recentering regression moments. Feature order:
181+ // Q-recentering regression moments derived independently in 1% centrality bins.
182+ // The centrality feature C is local to each 1% bin: C=2*(cent-(floor(cent)+0.5)), so C is in [-1,1).
183+ // Feature order:
174184 // 0:1, 1:C, 2:T, 3:Vx, 4:Vy, 5:Vz, 6:C2, 7:T2, 8:Vx2, 9:Vy2, 10:Vz2,
175185 // 11:C*T, 12:C*Vx, 13:C*Vy, 14:C*Vz, 15:T*Vx, 16:T*Vy, 17:T*Vz,
176186 // 18:Vx*Vy, 19:Vx*Vz, 20:Vy*Vz.
177- // Moments 0..230 are the upper triangle of sum(X_i X_j).
178- // Then 4 blocks of 21 sum(X_i Q): QxA, QyA, QxC, QyC.
179- histos.add (" QRecenteringCalibration/hRegressionMoments" , " Q recentering regression moments;moment index;sum " , kTH1D , {qRecenteringMomentAxis});
187+ // For each 1% centrality bin, moments 0..230 are the upper triangle of sum(X_i X_j),
188+ // followed by 4 blocks of 21 sum(X_i Q): QxA, QyA, QxC, QyC.
189+ histos.add (" QRecenteringCalibration/hRegressionMoments" , " Q recentering regression moments;centrality (%); moment index" , kTH2D , {centralityAxis, qRecenteringMomentAxis});
180190
181191 histos.add (" QRecenteringQA/pQBeforeVsCentrality" , " Q before recentering vs centrality;centrality (%);Q component;<Q>" , kTProfile2D , {centralityAxis, qComponentAxis});
182192 histos.add (" QRecenteringQA/pQBeforeVsTime" , " Q before recentering vs time;time from SOR (h);Q component;<Q>" , kTProfile2D , {timeAxis, qComponentAxis});
@@ -188,8 +198,26 @@ struct zdc2stagecalibration {
188198 histos.add (" QRecenteringQA/pQAfterVsVx" , " Q after recentering vs v_{x};v_{x} (cm);Q component;<Q>" , kTProfile2D , {vertexXYAxis, qComponentAxis});
189199 histos.add (" QRecenteringQA/pQAfterVsVy" , " Q after recentering vs v_{y};v_{y} (cm);Q component;<Q>" , kTProfile2D , {vertexXYAxis, qComponentAxis});
190200 histos.add (" QRecenteringQA/pQAfterVsVz" , " Q after recentering vs v_{z};v_{z} (cm);Q component;<Q>" , kTProfile2D , {vertexZAxis, qComponentAxis});
201+
202+ // A-C Q-vector correlation QA. These histograms are diagnostic only; no Qx/Qy mixing is applied.
203+ histos.add (" QCorrelationQA/hQxAQxCBefore" , " QxA vs QxC before recentering;Q_{x}^{A};Q_{x}^{C}" , kTH2F , {qValueAxis, qValueAxis});
204+ histos.add (" QCorrelationQA/hQyAQyCBefore" , " QyA vs QyC before recentering;Q_{y}^{A};Q_{y}^{C}" , kTH2F , {qValueAxis, qValueAxis});
205+ histos.add (" QCorrelationQA/hQxAQyCBefore" , " QxA vs QyC before recentering;Q_{x}^{A};Q_{y}^{C}" , kTH2F , {qValueAxis, qValueAxis});
206+ histos.add (" QCorrelationQA/hQyAQxCBefore" , " QyA vs QxC before recentering;Q_{y}^{A};Q_{x}^{C}" , kTH2F , {qValueAxis, qValueAxis});
207+ histos.add (" QCorrelationQA/hQxAQxCAfter" , " QxA vs QxC after recentering;Q_{x}^{A};Q_{x}^{C}" , kTH2F , {qValueAxis, qValueAxis});
208+ histos.add (" QCorrelationQA/hQyAQyCAfter" , " QyA vs QyC after recentering;Q_{y}^{A};Q_{y}^{C}" , kTH2F , {qValueAxis, qValueAxis});
209+ histos.add (" QCorrelationQA/hQxAQyCAfter" , " QxA vs QyC after recentering;Q_{x}^{A};Q_{y}^{C}" , kTH2F , {qValueAxis, qValueAxis});
210+ histos.add (" QCorrelationQA/hQyAQxCAfter" , " QyA vs QxC after recentering;Q_{y}^{A};Q_{x}^{C}" , kTH2F , {qValueAxis, qValueAxis});
191211 histos.add (" PhiQA/hPhiAfterRecenteringZNA" , " ZNA #phi after Q recentering;#phi;events" , kTH1F , {phiAxis});
192212 histos.add (" PhiQA/hPhiAfterRecenteringZNC" , " ZNC #phi after Q recentering;#phi;events" , kTH1F , {phiAxis});
213+ histos.add (" PhiQA/hPhiAfterRecenteringVsCentralityZNA" , " ZNA #phi after Q recentering vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
214+ histos.add (" PhiQA/hPhiAfterRecenteringVsCentralityZNC" , " ZNC #phi after Q recentering vs centrality;centrality (%);#phi" , kTH2F , {centralityAxis, phiAxis});
215+
216+ // A-C Q correlations versus centrality. Component convention:
217+ // 0: QxA*QxC, 1: QyA*QyC, 2: QxA*QyC, 3: QyA*QxC.
218+ // These are QA only; they are never used in the recentering correction.
219+ histos.add (" QCorrelationQA/pQACorrelationBeforeVsCentrality" , " A-C Q correlations before recentering;centrality (%);correlation component;<Q_{A}Q_{C}>" , kTProfile2D , {centralityAxis, qCorrelationComponentAxis});
220+ histos.add (" QCorrelationQA/pQACorrelationAfterVsCentrality" , " A-C Q correlations after recentering;centrality (%);correlation component;<Q_{A}Q_{C}>" , kTProfile2D , {centralityAxis, qCorrelationComponentAxis});
193221
194222 ccdb->setURL (cfgCcdbParam.cfgURL );
195223 ccdb->setCaching (true );
@@ -225,7 +253,7 @@ struct zdc2stagecalibration {
225253 }
226254 }
227255 if (calibrationStage.value == 2 && useQRecentering.value && !confQRecenteringPath.value .empty ()) {
228- qRecenteringProfile = ccdb->getForTimeStamp <TH2D >(confQRecenteringPath.value , timestamp);
256+ qRecenteringProfile = ccdb->getForTimeStamp <TH3D >(confQRecenteringPath.value , timestamp);
229257 if (!qRecenteringProfile) {
230258 LOGF (warn, " No ZDC Q-recentering calibration found for run %d at timestamp %llu" , runNumber, static_cast <unsigned long long >(timestamp));
231259 }
@@ -260,9 +288,12 @@ struct zdc2stagecalibration {
260288
261289 std::array<double , kQRecenteringNFeatures > makeQRecenteringFeatures (float centrality, float timeFromSOR, float vx, float vy, float vz) const
262290 {
263- // Fixed scaling keeps the polynomial basis numerically well behaved and must be
264- // used identically when solving/applying the CCDB coefficients.
265- const double c = (static_cast <double >(centrality) - 40.0 ) / 40.0 ;
291+ // Recentering is solved independently in each 1% centrality bin.
292+ // Keep a local centrality coordinate inside the bin so correlations with time/vertex
293+ // are retained without using the global 0-80% centrality scale.
294+ const double cent = static_cast <double >(centrality);
295+ const double centBinLow = std::floor (cent);
296+ const double c = 2.0 * (cent - (centBinLow + 0.5 ));
266297 const double runHours = (eorTimestamp > sorTimestamp) ? static_cast <double >(eorTimestamp - sorTimestamp) * 1 .e -3 / 3600.0 : static_cast <double >(cfgMaxRunHours.value );
267298 const double t = (runHours > 0.0 ) ? (2.0 * static_cast <double >(timeFromSOR) / runHours - 1.0 ) : 0.0 ;
268299 const double x = static_cast <double >(vx) / 0.1 ;
@@ -370,6 +401,8 @@ struct zdc2stagecalibration {
370401 const double phiRawC = std::atan2 (rawYC, rawXC);
371402 histos.fill (HIST (" PhiQA/hPhiRawZNA" ), phiRawA);
372403 histos.fill (HIST (" PhiQA/hPhiRawZNC" ), phiRawC);
404+ histos.fill (HIST (" PhiQA/hPhiRawVsCentralityZNA" ), centrality, phiRawA);
405+ histos.fill (HIST (" PhiQA/hPhiRawVsCentralityZNC" ), centrality, phiRawC);
373406
374407 if (calibrationStage.value == 1 ) {
375408 std::array<double , 15 > momentsA{};
@@ -429,6 +462,8 @@ struct zdc2stagecalibration {
429462 const double phiGainC = std::atan2 (gainYC, gainXC);
430463 histos.fill (HIST (" PhiQA/hPhiAfterGainZNA" ), phiGainA);
431464 histos.fill (HIST (" PhiQA/hPhiAfterGainZNC" ), phiGainC);
465+ histos.fill (HIST (" PhiQA/hPhiAfterGainVsCentralityZNA" ), centrality, phiGainA);
466+ histos.fill (HIST (" PhiQA/hPhiAfterGainVsCentralityZNC" ), centrality, phiGainC);
432467
433468 const double crossLookupXA = (znaCorr[3 ] - znaCorr[0 ]) / (znaCorr[3 ] + znaCorr[0 ]);
434469 const double crossLookupYA = (znaCorr[2 ] - znaCorr[1 ]) / (znaCorr[2 ] + znaCorr[1 ]);
@@ -518,6 +553,8 @@ struct zdc2stagecalibration {
518553 const double phiSpatialC = std::atan2 (centroidYC, centroidXC);
519554 histos.fill (HIST (" PhiQA/hPhiAfterSpatialZNA" ), phiSpatialA);
520555 histos.fill (HIST (" PhiQA/hPhiAfterSpatialZNC" ), phiSpatialC);
556+ histos.fill (HIST (" PhiQA/hPhiAfterSpatialVsCentralityZNA" ), centrality, phiSpatialA);
557+ histos.fill (HIST (" PhiQA/hPhiAfterSpatialVsCentralityZNC" ), centrality, phiSpatialC);
521558
522559 histos.fill (HIST (" GainQA/hSumOverCommonVsTimeZNA" ), timeFromSOR, ratioA);
523560 histos.fill (HIST (" GainQA/hSumOverCommonVsTimeZNC" ), timeFromSOR, ratioC);
@@ -607,18 +644,27 @@ struct zdc2stagecalibration {
607644 histos.fill (HIST (" QRecenteringQA/pQBeforeVsVz" ), vz, component, qValues[i]);
608645 }
609646
647+ histos.fill (HIST (" QCorrelationQA/hQxAQxCBefore" ), qValues[0 ], qValues[2 ]);
648+ histos.fill (HIST (" QCorrelationQA/hQyAQyCBefore" ), qValues[1 ], qValues[3 ]);
649+ histos.fill (HIST (" QCorrelationQA/hQxAQyCBefore" ), qValues[0 ], qValues[3 ]);
650+ histos.fill (HIST (" QCorrelationQA/hQyAQxCBefore" ), qValues[1 ], qValues[2 ]);
651+ histos.fill (HIST (" QCorrelationQA/pQACorrelationBeforeVsCentrality" ), centrality, 0.5 , qValues[0 ] * qValues[2 ]);
652+ histos.fill (HIST (" QCorrelationQA/pQACorrelationBeforeVsCentrality" ), centrality, 1.5 , qValues[1 ] * qValues[3 ]);
653+ histos.fill (HIST (" QCorrelationQA/pQACorrelationBeforeVsCentrality" ), centrality, 2.5 , qValues[0 ] * qValues[3 ]);
654+ histos.fill (HIST (" QCorrelationQA/pQACorrelationBeforeVsCentrality" ), centrality, 3.5 , qValues[1 ] * qValues[2 ]);
655+
610656 if (calibrationStage.value == 2 && useGainCallib.value && useSpatialCalib.value && deriveQRecentering.value && !useQRecentering.value ) {
611657 int moment = 0 ;
612658 for (int i = 0 ; i < kQRecenteringNFeatures ; ++i) {
613659 for (int j = i; j < kQRecenteringNFeatures ; ++j) {
614- histos.fill (HIST (" QRecenteringCalibration/hRegressionMoments" ), moment + 0.5 , qFeatures[i] * qFeatures[j]);
660+ histos.fill (HIST (" QRecenteringCalibration/hRegressionMoments" ), centrality, moment + 0.5 , qFeatures[i] * qFeatures[j]);
615661 ++moment;
616662 }
617663 }
618664 for (int component = 0 ; component < kQRecenteringNComponents ; ++component) {
619665 for (int i = 0 ; i < kQRecenteringNFeatures ; ++i) {
620666 const int index = kQRecenteringNMatrixMoments + component * kQRecenteringNFeatures + i;
621- histos.fill (HIST (" QRecenteringCalibration/hRegressionMoments" ), index + 0.5 , qFeatures[i] * qValues[component]);
667+ histos.fill (HIST (" QRecenteringCalibration/hRegressionMoments" ), centrality, index + 0.5 , qFeatures[i] * qValues[component]);
622668 }
623669 }
624670 }
@@ -631,7 +677,7 @@ struct zdc2stagecalibration {
631677 for (int component = 0 ; component < kQRecenteringNComponents ; ++component) {
632678 double predictedBias = 0.0 ;
633679 for (int i = 0 ; i < kQRecenteringNFeatures ; ++i) {
634- const double coefficient = qRecenteringProfile->GetBinContent (qRecenteringProfile->FindBin (i + 0.5 , component + 0.5 ));
680+ const double coefficient = qRecenteringProfile->GetBinContent (qRecenteringProfile->FindBin (centrality, i + 0.5 , component + 0.5 ));
635681 if (!std::isfinite (coefficient)) {
636682 qRecenteringOK = false ;
637683 break ;
@@ -660,10 +706,21 @@ struct zdc2stagecalibration {
660706 histos.fill (HIST (" QRecenteringQA/pQAfterVsVz" ), vz, component, qValues[i]);
661707 }
662708
709+ histos.fill (HIST (" QCorrelationQA/hQxAQxCAfter" ), qValues[0 ], qValues[2 ]);
710+ histos.fill (HIST (" QCorrelationQA/hQyAQyCAfter" ), qValues[1 ], qValues[3 ]);
711+ histos.fill (HIST (" QCorrelationQA/hQxAQyCAfter" ), qValues[0 ], qValues[3 ]);
712+ histos.fill (HIST (" QCorrelationQA/hQyAQxCAfter" ), qValues[1 ], qValues[2 ]);
713+ histos.fill (HIST (" QCorrelationQA/pQACorrelationAfterVsCentrality" ), centrality, 0.5 , qValues[0 ] * qValues[2 ]);
714+ histos.fill (HIST (" QCorrelationQA/pQACorrelationAfterVsCentrality" ), centrality, 1.5 , qValues[1 ] * qValues[3 ]);
715+ histos.fill (HIST (" QCorrelationQA/pQACorrelationAfterVsCentrality" ), centrality, 2.5 , qValues[0 ] * qValues[3 ]);
716+ histos.fill (HIST (" QCorrelationQA/pQACorrelationAfterVsCentrality" ), centrality, 3.5 , qValues[1 ] * qValues[2 ]);
717+
663718 const double phiRecenteringA = std::atan2 (qValues[1 ], qValues[0 ]);
664719 const double phiRecenteringC = std::atan2 (qValues[3 ], qValues[2 ]);
665720 histos.fill (HIST (" PhiQA/hPhiAfterRecenteringZNA" ), phiRecenteringA);
666721 histos.fill (HIST (" PhiQA/hPhiAfterRecenteringZNC" ), phiRecenteringC);
722+ histos.fill (HIST (" PhiQA/hPhiAfterRecenteringVsCentralityZNA" ), centrality, phiRecenteringA);
723+ histos.fill (HIST (" PhiQA/hPhiAfterRecenteringVsCentralityZNC" ), centrality, phiRecenteringC);
667724
668725 histos.fill (HIST (" hEvtSelInfo" ), 7.5 );
669726 fillTable (true , static_cast <float >(qValues[0 ]), static_cast <float >(qValues[2 ]), static_cast <float >(qValues[1 ]), static_cast <float >(qValues[3 ]));
0 commit comments