Skip to content

Commit 5b38f03

Browse files
authored
[PWGLF] Add close pair QA for spin correlation and fine centrality calibration of ZDC SP (#17972)
1 parent b87f2e6 commit 5b38f03

2 files changed

Lines changed: 494 additions & 40 deletions

File tree

PWGLF/TableProducer/Common/zdc2stagecalibration.cxx

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)