File indexing completed on 2026-04-06 08:12:10
0001 #include "QVecCalib.h"
0002 #include "EventPlaneData.h"
0003
0004
0005
0006
0007 #include <calobase/TowerInfoDefs.h>
0008
0009
0010 #include <fun4all/Fun4AllReturnCodes.h>
0011 #include <fun4all/Fun4AllServer.h>
0012
0013
0014 #include <phool/PHCompositeNode.h>
0015 #include <phool/getClass.h>
0016
0017
0018 #include <epd/EpdGeom.h>
0019
0020
0021 #include <ffaobjects/RunHeader.h>
0022
0023
0024 #include <cdbobjects/CDBTTree.h>
0025
0026 #include <TFile.h>
0027 #include <TH1.h>
0028 #include <TH2.h>
0029 #include <TProfile.h>
0030
0031
0032
0033
0034
0035 #include <format>
0036 #include <numbers>
0037 #include <filesystem>
0038
0039
0040 QVecCalib::QVecCalib(const std::string &name):
0041 SubsysReco(name)
0042 {
0043
0044 }
0045
0046
0047 int QVecCalib::Init([[maybe_unused]] PHCompositeNode *topNode)
0048 {
0049 if (Verbosity() > 1)
0050 {
0051 std::cout << "QVecCalib::Init(PHCompositeNode *topNode) Initializing" << std::endl;
0052
0053 Fun4AllServer *se = Fun4AllServer::instance();
0054 se->Print("NODETREE");
0055 }
0056
0057 int ret = process_QA_hist();
0058 if (ret)
0059 {
0060 return ret;
0061 }
0062
0063 init_hists();
0064
0065 if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening)
0066 {
0067 ret = load_correction_data();
0068 if (ret)
0069 {
0070 return ret;
0071 }
0072 }
0073
0074 prepare_hists();
0075
0076 return Fun4AllReturnCodes::EVENT_OK;
0077 }
0078
0079 void QVecCalib::prepare_hists()
0080 {
0081 if (m_pass == Pass::ComputeRecentering)
0082 {
0083 prepare_average_hists();
0084 }
0085 else if (m_pass == Pass::ApplyRecentering)
0086 {
0087 prepare_recenter_hists();
0088 }
0089 else if (m_pass == Pass::ApplyFlattening)
0090 {
0091 prepare_flattening_hists();
0092 }
0093 }
0094
0095 int QVecCalib::process_QA_hist()
0096 {
0097 TH1::AddDirectory(kFALSE);
0098 auto* file = TFile::Open(m_input_hist.c_str());
0099
0100
0101 if (!file || file->IsZombie())
0102 {
0103 std::cout << PHWHERE << "Error! Cannot not open file: " << m_input_hist << std::endl;
0104 return Fun4AllReturnCodes::ABORTRUN;
0105 }
0106
0107
0108 int ret = process_sEPD_event_thresholds(file);
0109 if (ret)
0110 {
0111 return ret;
0112 }
0113
0114
0115 ret = process_bad_channels(file);
0116 if (ret)
0117 {
0118 return ret;
0119 }
0120
0121
0122 file->Close();
0123 delete file;
0124
0125 return Fun4AllReturnCodes::EVENT_OK;
0126 }
0127
0128 int QVecCalib::process_sEPD_event_thresholds(TFile* file)
0129 {
0130 Fun4AllServer *se = Fun4AllServer::instance();
0131
0132 std::string sepd_totalcharge_centrality = "h2SEPD_totalcharge_centrality";
0133
0134 TH2 *hist {nullptr};
0135 file->GetObject(sepd_totalcharge_centrality.c_str(),hist);
0136
0137
0138 if (hist == nullptr)
0139 {
0140 std::cout << PHWHERE << "Error! Cannot find hist: " << sepd_totalcharge_centrality << std::endl;
0141 return Fun4AllReturnCodes::ABORTRUN;
0142 }
0143
0144 h2SEPD_Charge = static_cast<TH2*>(hist->Clone("h2SEPD_Charge"));
0145 h2SEPD_Chargev2 = static_cast<TH2*>(hist->Clone("h2SEPD_Chargev2"));
0146
0147 se->registerHisto(h2SEPD_Charge);
0148 se->registerHisto(h2SEPD_Chargev2);
0149
0150 auto* h2SEPD_Charge_py = h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s");
0151
0152 int binsx = h2SEPD_Charge->GetNbinsX();
0153 int binsy = h2SEPD_Charge->GetNbinsY();
0154 double ymin = h2SEPD_Charge->GetYaxis()->GetXmin();
0155 double ymax = h2SEPD_Charge->GetYaxis()->GetXmax();
0156
0157 hSEPD_Charge_Min = new TProfile("hSEPD_Charge_Min", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax);
0158 hSEPD_Charge_Max = new TProfile("hSEPD_Charge_Max", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax);
0159
0160 se->registerHisto(hSEPD_Charge_Min);
0161 se->registerHisto(hSEPD_Charge_Max);
0162
0163 for (int y = 1; y <= binsy; ++y)
0164 {
0165 double cent = h2SEPD_Charge_py->GetBinCenter(y);
0166 double mean = h2SEPD_Charge_py->GetBinContent(y);
0167 double sigma = h2SEPD_Charge_py->GetBinError(y);
0168
0169 if (sigma == 0)
0170 {
0171 continue;
0172 }
0173
0174 double charge_low = mean - m_sEPD_sigma_threshold * sigma;
0175 double charge_high = mean + m_sEPD_sigma_threshold * sigma;
0176
0177 hSEPD_Charge_Min->Fill(cent, charge_low);
0178 hSEPD_Charge_Max->Fill(cent, charge_high);
0179
0180 for (int x = 1; x <= binsx; ++x)
0181 {
0182 double charge = h2SEPD_Charge->GetXaxis()->GetBinCenter(x);
0183 double zscore = (charge - mean) / sigma;
0184
0185 if (std::abs(zscore) > m_sEPD_sigma_threshold)
0186 {
0187 h2SEPD_Chargev2->SetBinContent(x, y, 0);
0188 h2SEPD_Chargev2->SetBinError(x, y, 0);
0189 }
0190 }
0191 }
0192
0193 return Fun4AllReturnCodes::EVENT_OK;
0194 }
0195
0196 int QVecCalib::process_bad_channels(TFile* file)
0197 {
0198 Fun4AllServer *se = Fun4AllServer::instance();
0199
0200 std::string sepd_charge_hist = "hSEPD_Charge";
0201
0202 TProfile *hSEPD_Charge{nullptr};
0203 file->GetObject(sepd_charge_hist.c_str(), hSEPD_Charge);
0204
0205
0206 if (hSEPD_Charge == nullptr)
0207 {
0208 std::cout << PHWHERE << "Error! Cannot find hist: " << sepd_charge_hist << ", in file: " << file->GetName() << std::endl;
0209 return Fun4AllReturnCodes::ABORTRUN;
0210 }
0211
0212 int rbins = 16;
0213 int bins_charge = 40;
0214
0215 h2SEPD_South_Charge_rbin = new TH2F("h2SEPD_South_Charge_rbin",
0216 "sEPD South; r_{bin}; Avg Charge",
0217 rbins, -0.5, rbins - 0.5,
0218 bins_charge, 0, bins_charge);
0219
0220 h2SEPD_North_Charge_rbin = new TH2F("h2SEPD_North_Charge_rbin",
0221 "sEPD North; r_{bin}; Avg Charge",
0222 rbins, -0.5, rbins - 0.5,
0223 bins_charge, 0, bins_charge);
0224
0225 h2SEPD_South_Charge_rbinv2 = new TH2F("h2SEPD_South_Charge_rbinv2",
0226 "sEPD South; r_{bin}; Avg Charge",
0227 rbins, -0.5, rbins - 0.5,
0228 bins_charge, 0, bins_charge);
0229
0230 h2SEPD_North_Charge_rbinv2 = new TH2F("h2SEPD_North_Charge_rbinv2",
0231 "sEPD North; r_{bin}; Avg Charge",
0232 rbins, -0.5, rbins - 0.5,
0233 bins_charge, 0, bins_charge);
0234
0235 hSEPD_Bad_Channels = new TProfile("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", QVecShared::SEPD_CHANNELS, -0.5, QVecShared::SEPD_CHANNELS-0.5);
0236
0237 se->registerHisto(h2SEPD_South_Charge_rbin);
0238 se->registerHisto(h2SEPD_North_Charge_rbin);
0239 se->registerHisto(h2SEPD_South_Charge_rbinv2);
0240 se->registerHisto(h2SEPD_North_Charge_rbinv2);
0241 se->registerHisto(hSEPD_Bad_Channels);
0242
0243 for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel)
0244 {
0245 unsigned int key = TowerInfoDefs::encode_epd(channel);
0246 int rbin = TowerInfoDefs::get_epd_rbin(key);
0247 unsigned int arm = TowerInfoDefs::get_epd_arm(key);
0248
0249 double avg_charge = hSEPD_Charge->GetBinContent(channel + 1);
0250
0251 auto* h2 = (arm == 0) ? h2SEPD_South_Charge_rbin : h2SEPD_North_Charge_rbin;
0252
0253 h2->Fill(rbin, avg_charge);
0254 }
0255
0256 auto* hSpx = h2SEPD_South_Charge_rbin->ProfileX("hSpx", 2, -1, "s");
0257 auto* hNpx = h2SEPD_North_Charge_rbin->ProfileX("hNpx", 2, -1, "s");
0258
0259 int ctr_dead = 0;
0260 int ctr_hot = 0;
0261 int ctr_cold = 0;
0262
0263 for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel)
0264 {
0265 unsigned int key = TowerInfoDefs::encode_epd(channel);
0266 int rbin = TowerInfoDefs::get_epd_rbin(key);
0267 unsigned int arm = TowerInfoDefs::get_epd_arm(key);
0268
0269 auto* h2 = (arm == 0) ? h2SEPD_South_Charge_rbinv2 : h2SEPD_North_Charge_rbinv2;
0270 auto* hprof = (arm == 0) ? hSpx : hNpx;
0271
0272 double charge = hSEPD_Charge->GetBinContent(channel + 1);
0273 double mean_charge = hprof->GetBinContent(rbin + 1);
0274 double sigma = hprof->GetBinError(rbin + 1);
0275 double zscore = 0.0;
0276
0277 if (sigma > 0)
0278 {
0279 zscore = (charge - mean_charge) / sigma;
0280 }
0281
0282 if (charge < m_sEPD_min_avg_charge_threshold || std::abs(zscore) > m_sEPD_sigma_threshold)
0283 {
0284 m_bad_channels.insert(channel);
0285
0286 std::string type;
0287 QVecShared::ChannelStatus status_fill;
0288
0289
0290 if (charge == 0)
0291 {
0292 type = "Dead";
0293 status_fill = QVecShared::ChannelStatus::Dead;
0294 ++ctr_dead;
0295 }
0296
0297 else if (zscore > m_sEPD_sigma_threshold)
0298 {
0299 type = "Hot";
0300 status_fill = QVecShared::ChannelStatus::Hot;
0301 ++ctr_hot;
0302 }
0303
0304 else
0305 {
0306 type = "Cold";
0307 status_fill = QVecShared::ChannelStatus::Cold;
0308 ++ctr_cold;
0309 }
0310
0311 hSEPD_Bad_Channels->Fill(channel, static_cast<int>(status_fill));
0312 std::cout << std::format("{:4} Channel: {:3d}, arm: {}, rbin: {:2d}, Mean: {:5.2f}, Charge: {:5.2f}, Z-Score: {:5.2f}",
0313 type, channel, arm, rbin, mean_charge, charge, zscore) << std::endl;
0314 }
0315 else
0316 {
0317 h2->Fill(rbin, charge);
0318 }
0319 }
0320
0321 std::cout << "Total Bad Channels: " << m_bad_channels.size() << ", Dead: "
0322 << ctr_dead << ", Hot: " << ctr_hot << ", Cold: " << ctr_cold << std::endl;
0323
0324 std::cout << "Finished processing Hot sEPD channels" << std::endl;
0325 return Fun4AllReturnCodes::EVENT_OK;
0326 }
0327
0328 void QVecCalib::init_hists()
0329 {
0330 unsigned int bins_psi = 126;
0331 double psi_low = -std::numbers::pi;
0332 double psi_high = std::numbers::pi;
0333
0334 Fun4AllServer *se = Fun4AllServer::instance();
0335
0336 hCentrality = new TH1F("hCentrality", "|z| < 10 cm and MB; Centrality [%]; Events", m_cent_bins, m_cent_low, m_cent_high);
0337 se->registerHisto(hCentrality);
0338
0339 std::string pass_suffix;
0340 if (m_pass == Pass::ApplyRecentering)
0341 {
0342 pass_suffix = "_corr";
0343 }
0344 else if (m_pass == Pass::ApplyFlattening)
0345 {
0346 pass_suffix = "_corr2";
0347 }
0348
0349
0350 for (int n : m_harmonics)
0351 {
0352 std::string name_S = std::format("h2_sEPD_Psi_S_{}{}", n, pass_suffix);
0353 std::string name_N = std::format("h2_sEPD_Psi_N_{}{}", n, pass_suffix);
0354 std::string name_NS = std::format("h2_sEPD_Psi_NS_{}{}", n, pass_suffix);
0355
0356 std::string title_S = std::format("sEPD South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{S}}_{{{0}}}", n);
0357 std::string title_N = std::format("sEPD North #Psi (Order {0}); Centrality [%]; {0}#Psi^{{N}}_{{{0}}}", n);
0358 std::string title_NS = std::format("sEPD North South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{NS}}_{{{0}}}", n);
0359
0360 m_hists2D[name_S] = new TH2F(name_S.c_str(), title_S.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high);
0361 m_hists2D[name_N] = new TH2F(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high);
0362 m_hists2D[name_NS] = new TH2F(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high);
0363
0364
0365 for (auto det : m_subdetectors)
0366 {
0367 std::string det_str = (det == QVecShared::Subdetector::S) ? "S" : "N";
0368 std::string det_name = (det == QVecShared::Subdetector::S) ? "South" : "North";
0369
0370 std::string q_avg_sq_cross_name;
0371 std::string q_avg_sq_cross_title = std::format("sEPD {0}; Centrality [%]; <Q_{{{1},x}} Q_{{{1},y}}>", det_name, n);
0372
0373 if (m_pass == Pass::ApplyRecentering)
0374 {
0375 q_avg_sq_cross_name = QVecShared::get_hist_name(det_str, "xy", n);
0376 }
0377
0378 if (m_pass == Pass::ApplyFlattening)
0379 {
0380 q_avg_sq_cross_name = QVecShared::get_hist_name(det_str, "xy", n, "_corr");
0381 }
0382
0383 if (!q_avg_sq_cross_name.empty())
0384 {
0385 m_profiles[q_avg_sq_cross_name] = new TProfile(q_avg_sq_cross_name.c_str(), q_avg_sq_cross_title.c_str(),
0386 m_cent_bins, m_cent_low, m_cent_high);
0387 }
0388
0389 for (auto comp : m_components)
0390 {
0391 std::string comp_str = (comp == QVecShared::QComponent::X) ? "x" : "y";
0392 std::string name = QVecShared::get_hist_name(det_str, comp_str, n, pass_suffix);
0393
0394 auto add_profile = [&](const std::string& prof_name, std::string_view label_suffix = "")
0395 {
0396 std::string title = std::format("sEPD {}; Centrality [%]; <Q_{{{},{}}}{}>", det_name, n, comp_str, label_suffix);
0397 m_profiles[prof_name] = new TProfile(prof_name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high);
0398 };
0399
0400 add_profile(name);
0401
0402
0403 switch (m_pass)
0404 {
0405 case Pass::ComputeRecentering:
0406 {
0407 break;
0408 }
0409
0410 case Pass::ApplyRecentering:
0411 {
0412 std::string name_sq = QVecShared::get_hist_name(det_str, comp_str+comp_str, n);
0413 add_profile(name_sq, "^{2}");
0414 break;
0415 }
0416
0417 case Pass::ApplyFlattening:
0418 {
0419 std::string name_sq_corr = QVecShared::get_hist_name(det_str, comp_str+comp_str, n, "_corr");
0420 add_profile(name_sq_corr, "^{2}");
0421 break;
0422 }
0423 }
0424 }
0425 }
0426
0427
0428 if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening)
0429 {
0430 std::string det_str = "NS";
0431
0432
0433 for (const auto* comp : {"xx", "yy", "xy"})
0434 {
0435 std::string name = QVecShared::get_hist_name(det_str, comp, n);
0436 std::string title = std::format("sEPD NS; Centrality [%]; <Q_{{{},{}}}>", n, comp);
0437 m_profiles[name] = new TProfile(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high);
0438 }
0439
0440
0441 if (m_pass == Pass::ApplyFlattening)
0442 {
0443 for (const auto* comp : {"xx", "yy", "xy"})
0444 {
0445 std::string name = QVecShared::get_hist_name(det_str, comp, n, "_corr");
0446 std::string title = std::format("sEPD NS Corrected; Centrality [%]; <Q_{{{},{}}}^{{2}}>", n, comp);
0447 m_profiles[name] = new TProfile(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high);
0448 }
0449 }
0450 }
0451 }
0452 }
0453
0454 std::array<std::array<double, 2>, 2> QVecCalib::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label)
0455 {
0456 double D_arg = (xx * yy) - (xy * xy);
0457 if (D_arg < 1e-12)
0458 {
0459 std::cout << "Warning: Near-zero determinant in bin " << cent_bin << ". Skipping matrix calc." << std::endl;
0460 return std::array<std::array<double, 2>, 2>{{{1, 0}, {0, 1}}};
0461 }
0462 double D = std::sqrt(D_arg);
0463
0464 double N_term = D * (xx + yy + (2 * D));
0465 if (N_term <= 0)
0466 {
0467 std::cout << "Invalid N-term (" << N_term << ") for n=" << n << ", cent=" << cent_bin
0468 << ", det=" << det_label << std::endl;
0469 exit(1);
0470 }
0471 double inv_sqrt_N = 1.0 / std::sqrt(N_term);
0472
0473 std::array<std::array<double, 2>, 2> mat{};
0474 mat[0][0] = inv_sqrt_N * (yy + D);
0475 mat[0][1] = -inv_sqrt_N * xy;
0476 mat[1][0] = mat[0][1];
0477 mat[1][1] = inv_sqrt_N * (xx + D);
0478 return mat;
0479 }
0480
0481 template <typename T>
0482 T* QVecCalib::load_and_clone(TFile* file, const std::string& name) {
0483 T *obj {nullptr};
0484 file->GetObject(name.c_str(),obj);
0485 if (!obj)
0486 {
0487 std::cout << "Could not find histogram " << name << " in file " << file->GetName() << std::endl;
0488 exit(1);
0489 }
0490 return static_cast<T*>(obj->Clone());
0491 }
0492
0493 int QVecCalib::load_correction_data()
0494 {
0495 Fun4AllServer *se = Fun4AllServer::instance();
0496 auto* file = TFile::Open(m_input_Q_calib.c_str());
0497
0498 if (!file || file->IsZombie())
0499 {
0500 std::cout << PHWHERE << "Error! Cannot open: " << m_input_Q_calib << std::endl;
0501 return Fun4AllReturnCodes::ABORTRUN;
0502 }
0503
0504 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
0505 {
0506 int n = m_harmonics[h_idx];
0507
0508
0509 auto load_reg = [&](const std::string& det, const std::string& var, const std::string& suffix = "")
0510 {
0511 std::string name = QVecShared::get_hist_name(det, var, n, suffix);
0512 m_profiles[name] = load_and_clone<TProfile>(file, name);
0513 se->registerHisto(m_profiles[name]);
0514 return name;
0515 };
0516
0517
0518 std::string s_names[2][2];
0519 for (int d = 0; d < 2; ++d)
0520 {
0521 std::string det_str = (d == 0) ? "S" : "N";
0522 s_names[d][0] = load_reg(det_str, "x");
0523 s_names[d][1] = load_reg(det_str, "y");
0524 }
0525
0526
0527 if (m_pass == Pass::ApplyFlattening)
0528 {
0529 for (const auto& det_str : {"S", "N", "NS"})
0530 {
0531 for (const auto& var : {"xx", "yy", "xy"})
0532 {
0533 load_reg(det_str, var);
0534 }
0535 }
0536 }
0537
0538
0539 for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin)
0540 {
0541 int bin = static_cast<int>(cent_bin) + 1;
0542
0543
0544 for (int d = 0; d < 2; ++d)
0545 {
0546 m_correction_data[cent_bin][h_idx][d].avg_Q = {m_profiles[s_names[d][0]]->GetBinContent(bin), m_profiles[s_names[d][1]]->GetBinContent(bin)};
0547 }
0548
0549 if (m_pass == Pass::ApplyFlattening)
0550 {
0551
0552 for (int d = 0; d < (int) QVecShared::Subdetector::Count; ++d)
0553 {
0554 std::string det_str;
0555 switch (d)
0556 {
0557 case 0:
0558 det_str = "S";
0559 break;
0560 case 1:
0561 det_str = "N";
0562 break;
0563 default:
0564 det_str = "NS";
0565 break;
0566 }
0567
0568 double xx = m_profiles[QVecShared::get_hist_name(det_str, "xx", n)]->GetBinContent(bin);
0569 double yy = m_profiles[QVecShared::get_hist_name(det_str, "yy", n)]->GetBinContent(bin);
0570 double xy = m_profiles[QVecShared::get_hist_name(det_str, "xy", n)]->GetBinContent(bin);
0571
0572 auto& data = m_correction_data[cent_bin][h_idx][d];
0573 data.X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, det_str);
0574 data.avg_Q_xx = xx;
0575 data.avg_Q_yy = yy;
0576 data.avg_Q_xy = xy;
0577 }
0578 }
0579 }
0580 }
0581
0582 file->Close();
0583 delete file;
0584 return Fun4AllReturnCodes::EVENT_OK;
0585 }
0586
0587 void QVecCalib::prepare_average_hists()
0588 {
0589 Fun4AllServer *se = Fun4AllServer::instance();
0590
0591 for (int n : m_harmonics)
0592 {
0593 std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n);
0594 std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n);
0595 std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n);
0596 std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n);
0597
0598 std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}", n);
0599 std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}", n);
0600 std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}", n);
0601
0602 AverageHists h;
0603
0604 h.S_x_avg = m_profiles.at(S_x_avg_name);
0605 h.S_y_avg = m_profiles.at(S_y_avg_name);
0606 h.N_x_avg = m_profiles.at(N_x_avg_name);
0607 h.N_y_avg = m_profiles.at(N_y_avg_name);
0608
0609 h.Psi_S = m_hists2D.at(psi_S_name);
0610 h.Psi_N = m_hists2D.at(psi_N_name);
0611 h.Psi_NS = m_hists2D.at(psi_NS_name);
0612
0613 se->registerHisto(h.S_x_avg);
0614 se->registerHisto(h.S_y_avg);
0615 se->registerHisto(h.N_x_avg);
0616 se->registerHisto(h.N_y_avg);
0617
0618 se->registerHisto(h.Psi_S);
0619 se->registerHisto(h.Psi_N);
0620 se->registerHisto(h.Psi_NS);
0621
0622 m_average_hists.push_back(h);
0623 }
0624 }
0625
0626 void QVecCalib::prepare_recenter_hists()
0627 {
0628 Fun4AllServer *se = Fun4AllServer::instance();
0629
0630 for (int n : m_harmonics)
0631 {
0632 std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr");
0633 std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr");
0634 std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr");
0635 std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr");
0636
0637 std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n);
0638 std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n);
0639 std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n);
0640 std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n);
0641 std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n);
0642 std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n);
0643
0644 std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n);
0645 std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n);
0646 std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n);
0647
0648 std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr", n);
0649 std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr", n);
0650 std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr", n);
0651
0652 RecenterHists h;
0653
0654 h.S_x_corr_avg = m_profiles.at(S_x_corr_avg_name);
0655 h.S_y_corr_avg = m_profiles.at(S_y_corr_avg_name);
0656 h.N_x_corr_avg = m_profiles.at(N_x_corr_avg_name);
0657 h.N_y_corr_avg = m_profiles.at(N_y_corr_avg_name);
0658
0659 h.S_xx_avg = m_profiles.at(S_xx_avg_name);
0660 h.S_yy_avg = m_profiles.at(S_yy_avg_name);
0661 h.S_xy_avg = m_profiles.at(S_xy_avg_name);
0662
0663 h.N_xx_avg = m_profiles.at(N_xx_avg_name);
0664 h.N_yy_avg = m_profiles.at(N_yy_avg_name);
0665 h.N_xy_avg = m_profiles.at(N_xy_avg_name);
0666
0667 h.NS_xx_avg = m_profiles.at(NS_xx_avg_name);
0668 h.NS_yy_avg = m_profiles.at(NS_yy_avg_name);
0669 h.NS_xy_avg = m_profiles.at(NS_xy_avg_name);
0670
0671 h.Psi_S_corr = m_hists2D.at(psi_S_name);
0672 h.Psi_N_corr = m_hists2D.at(psi_N_name);
0673 h.Psi_NS_corr = m_hists2D.at(psi_NS_name);
0674
0675 se->registerHisto(h.S_x_corr_avg);
0676 se->registerHisto(h.S_y_corr_avg);
0677 se->registerHisto(h.N_x_corr_avg);
0678 se->registerHisto(h.N_y_corr_avg);
0679
0680 se->registerHisto(h.S_xx_avg);
0681 se->registerHisto(h.S_yy_avg);
0682 se->registerHisto(h.S_xy_avg);
0683
0684 se->registerHisto(h.N_xx_avg);
0685 se->registerHisto(h.N_yy_avg);
0686 se->registerHisto(h.N_xy_avg);
0687
0688 se->registerHisto(h.NS_xx_avg);
0689 se->registerHisto(h.NS_yy_avg);
0690 se->registerHisto(h.NS_xy_avg);
0691
0692 se->registerHisto(h.Psi_S_corr);
0693 se->registerHisto(h.Psi_N_corr);
0694 se->registerHisto(h.Psi_NS_corr);
0695
0696 m_recenter_hists.push_back(h);
0697 }
0698 }
0699
0700 void QVecCalib::prepare_flattening_hists()
0701 {
0702 Fun4AllServer *se = Fun4AllServer::instance();
0703
0704 for (int n : m_harmonics)
0705 {
0706 std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2");
0707 std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2");
0708 std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2");
0709 std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2");
0710
0711 std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr");
0712 std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr");
0713 std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr");
0714 std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr");
0715 std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr");
0716 std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr");
0717
0718 std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr");
0719 std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr");
0720 std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr");
0721
0722 std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr2", n);
0723 std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr2", n);
0724 std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr2", n);
0725
0726 FlatteningHists h;
0727
0728 h.S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name);
0729 h.S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name);
0730 h.N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name);
0731 h.N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name);
0732
0733 h.S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name);
0734 h.S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name);
0735 h.S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name);
0736
0737 h.N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name);
0738 h.N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name);
0739 h.N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name);
0740
0741 h.NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name);
0742 h.NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name);
0743 h.NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name);
0744
0745 h.Psi_S_corr2 = m_hists2D.at(psi_S_name);
0746 h.Psi_N_corr2 = m_hists2D.at(psi_N_name);
0747 h.Psi_NS_corr2 = m_hists2D.at(psi_NS_name);
0748
0749 se->registerHisto(h.S_x_corr2_avg);
0750 se->registerHisto(h.S_y_corr2_avg);
0751 se->registerHisto(h.N_x_corr2_avg);
0752 se->registerHisto(h.N_y_corr2_avg);
0753
0754 se->registerHisto(h.S_xx_corr_avg);
0755 se->registerHisto(h.S_yy_corr_avg);
0756 se->registerHisto(h.S_xy_corr_avg);
0757
0758 se->registerHisto(h.N_xx_corr_avg);
0759 se->registerHisto(h.N_yy_corr_avg);
0760 se->registerHisto(h.N_xy_corr_avg);
0761
0762 se->registerHisto(h.NS_xx_corr_avg);
0763 se->registerHisto(h.NS_yy_corr_avg);
0764 se->registerHisto(h.NS_xy_corr_avg);
0765
0766 se->registerHisto(h.Psi_S_corr2);
0767 se->registerHisto(h.Psi_N_corr2);
0768 se->registerHisto(h.Psi_NS_corr2);
0769
0770 m_flattening_hists.push_back(h);
0771 }
0772 }
0773
0774 int QVecCalib::InitRun(PHCompositeNode *topNode)
0775 {
0776 RunHeader* run_header = findNode::getClass<RunHeader>(topNode, "RunHeader");
0777 if (!run_header)
0778 {
0779 std::cout << PHWHERE << "RunHeader Node missing." << std::endl;
0780 return Fun4AllReturnCodes::ABORTRUN;
0781 }
0782
0783 m_runnumber = run_header->get_RunNumber();
0784
0785 EpdGeom* epdgeom = findNode::getClass<EpdGeom>(topNode, "TOWERGEOM_EPD");
0786 if (!epdgeom)
0787 {
0788 std::cout << PHWHERE << "TOWERGEOM_EPD Node missing." << std::endl;
0789 return Fun4AllReturnCodes::ABORTRUN;
0790 }
0791
0792 m_trig_cache.assign(m_harmonics.size(), std::vector<std::pair<double, double>>(QVecShared::SEPD_CHANNELS));
0793
0794 for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel)
0795 {
0796 unsigned int key = TowerInfoDefs::encode_epd(channel);
0797 double phi = epdgeom->get_phi(key);
0798
0799 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
0800 {
0801 int n = m_harmonics[h_idx];
0802 m_trig_cache[h_idx][channel] = {std::cos(n * phi), std::sin(n * phi)};
0803 }
0804 }
0805
0806 std::cout << "QVecCalib::InitRun - Trigonometry cache initialized for "
0807 << QVecShared::SEPD_CHANNELS << " channels." << std::endl;
0808
0809 return Fun4AllReturnCodes::EVENT_OK;
0810 }
0811
0812 void QVecCalib::process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h)
0813 {
0814 double psi_S = std::atan2(q_S.y, q_S.x);
0815 double psi_N = std::atan2(q_N.y, q_N.x);
0816 double psi_NS = std::atan2(q_S.y + q_N.y, q_S.x + q_N.x);
0817
0818 h.S_x_avg->Fill(cent, q_S.x);
0819 h.S_y_avg->Fill(cent, q_S.y);
0820 h.N_x_avg->Fill(cent, q_N.x);
0821 h.N_y_avg->Fill(cent, q_N.y);
0822
0823 h.Psi_S->Fill(cent, psi_S);
0824 h.Psi_N->Fill(cent, psi_N);
0825 h.Psi_NS->Fill(cent, psi_NS);
0826 }
0827
0828 void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h)
0829 {
0830 int cent_bin = hCentrality->FindBin(cent) - 1;
0831
0832 const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S];
0833 const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N];
0834
0835 double Q_S_x_avg = S.avg_Q.x;
0836 double Q_S_y_avg = S.avg_Q.y;
0837 double Q_N_x_avg = N.avg_Q.x;
0838 double Q_N_y_avg = N.avg_Q.y;
0839
0840 QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg};
0841 QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg};
0842
0843
0844
0845 QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y};
0846
0847 double psi_S_corr = std::atan2(q_S_corr.y, q_S_corr.x);
0848 double psi_N_corr = std::atan2(q_N_corr.y, q_N_corr.x);
0849 double psi_NS_corr = std::atan2(q_NS_corr.y, q_NS_corr.x);
0850
0851 h.S_x_corr_avg->Fill(cent, q_S_corr.x);
0852 h.S_y_corr_avg->Fill(cent, q_S_corr.y);
0853 h.N_x_corr_avg->Fill(cent, q_N_corr.x);
0854 h.N_y_corr_avg->Fill(cent, q_N_corr.y);
0855
0856 h.S_xx_avg->Fill(cent, q_S_corr.x * q_S_corr.x);
0857 h.S_yy_avg->Fill(cent, q_S_corr.y * q_S_corr.y);
0858 h.S_xy_avg->Fill(cent, q_S_corr.x * q_S_corr.y);
0859 h.N_xx_avg->Fill(cent, q_N_corr.x * q_N_corr.x);
0860 h.N_yy_avg->Fill(cent, q_N_corr.y * q_N_corr.y);
0861 h.N_xy_avg->Fill(cent, q_N_corr.x * q_N_corr.y);
0862
0863 h.NS_xx_avg->Fill(cent, q_NS_corr.x * q_NS_corr.x);
0864 h.NS_yy_avg->Fill(cent, q_NS_corr.y * q_NS_corr.y);
0865 h.NS_xy_avg->Fill(cent, q_NS_corr.x * q_NS_corr.y);
0866
0867 h.Psi_S_corr->Fill(cent, psi_S_corr);
0868 h.Psi_N_corr->Fill(cent, psi_N_corr);
0869 h.Psi_NS_corr->Fill(cent, psi_NS_corr);
0870 }
0871
0872 void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h)
0873 {
0874 int cent_bin = hCentrality->FindBin(cent) - 1;
0875
0876 const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S];
0877 const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N];
0878 const auto& NS = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::NS];
0879
0880 double Q_S_x_avg = S.avg_Q.x;
0881 double Q_S_y_avg = S.avg_Q.y;
0882 double Q_N_x_avg = N.avg_Q.x;
0883 double Q_N_y_avg = N.avg_Q.y;
0884
0885 QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg};
0886 QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg};
0887
0888
0889 QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y};
0890
0891 const auto& X_S = S.X_matrix;
0892 const auto& X_N = N.X_matrix;
0893 const auto& X_NS = NS.X_matrix;
0894
0895 double Q_S_x_corr2 = X_S[0][0] * q_S_corr.x + X_S[0][1] * q_S_corr.y;
0896 double Q_S_y_corr2 = X_S[1][0] * q_S_corr.x + X_S[1][1] * q_S_corr.y;
0897 double Q_N_x_corr2 = X_N[0][0] * q_N_corr.x + X_N[0][1] * q_N_corr.y;
0898 double Q_N_y_corr2 = X_N[1][0] * q_N_corr.x + X_N[1][1] * q_N_corr.y;
0899
0900 double Q_NS_x_corr2 = X_NS[0][0] * q_NS_corr.x + X_NS[0][1] * q_NS_corr.y;
0901 double Q_NS_y_corr2 = X_NS[1][0] * q_NS_corr.x + X_NS[1][1] * q_NS_corr.y;
0902
0903 QVecShared::QVec q_S_corr2 = {Q_S_x_corr2, Q_S_y_corr2};
0904 QVecShared::QVec q_N_corr2 = {Q_N_x_corr2, Q_N_y_corr2};
0905 QVecShared::QVec q_NS_corr2 = {Q_NS_x_corr2, Q_NS_y_corr2};
0906
0907 double psi_S = std::atan2(q_S_corr2.y, q_S_corr2.x);
0908 double psi_N = std::atan2(q_N_corr2.y, q_N_corr2.x);
0909 double psi_NS = std::atan2(q_NS_corr2.y, q_NS_corr2.x);
0910
0911 h.S_x_corr2_avg->Fill(cent, q_S_corr2.x);
0912 h.S_y_corr2_avg->Fill(cent, q_S_corr2.y);
0913 h.N_x_corr2_avg->Fill(cent, q_N_corr2.x);
0914 h.N_y_corr2_avg->Fill(cent, q_N_corr2.y);
0915
0916 h.S_xx_corr_avg->Fill(cent, q_S_corr2.x * q_S_corr2.x);
0917 h.S_yy_corr_avg->Fill(cent, q_S_corr2.y * q_S_corr2.y);
0918 h.S_xy_corr_avg->Fill(cent, q_S_corr2.x * q_S_corr2.y);
0919 h.N_xx_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.x);
0920 h.N_yy_corr_avg->Fill(cent, q_N_corr2.y * q_N_corr2.y);
0921 h.N_xy_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.y);
0922
0923 h.NS_xx_corr_avg->Fill(cent, q_NS_corr2.x * q_NS_corr2.x);
0924 h.NS_yy_corr_avg->Fill(cent, q_NS_corr2.y * q_NS_corr2.y);
0925 h.NS_xy_corr_avg->Fill(cent, q_NS_corr2.x * q_NS_corr2.y);
0926
0927 h.Psi_S_corr2->Fill(cent, psi_S);
0928 h.Psi_N_corr2->Fill(cent, psi_N);
0929 h.Psi_NS_corr2->Fill(cent, psi_NS);
0930 }
0931
0932 bool QVecCalib::process_sEPD()
0933 {
0934 double sepd_total_charge_south = 0;
0935 double sepd_total_charge_north = 0;
0936
0937
0938 for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel)
0939 {
0940 double charge = m_evtdata->get_sepd_charge(channel);
0941
0942
0943 if (m_bad_channels.contains(channel) || charge <= 0)
0944 {
0945 continue;
0946 }
0947
0948 unsigned int key = TowerInfoDefs::encode_epd(channel);
0949 unsigned int arm = TowerInfoDefs::get_epd_arm(key);
0950
0951
0952
0953 if (arm == 0)
0954 {
0955 sepd_total_charge_south += charge;
0956 }
0957 else
0958 {
0959 sepd_total_charge_north += charge;
0960 }
0961
0962
0963 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
0964 {
0965
0966 const auto& [cached_cos, cached_sin] = m_trig_cache[h_idx][channel];
0967
0968 m_q_vectors[h_idx][arm].x += charge * cached_cos;
0969 m_q_vectors[h_idx][arm].y += charge * cached_sin;
0970 }
0971 }
0972
0973
0974 if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0)
0975 {
0976 return false;
0977 }
0978
0979
0980 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
0981 {
0982 for (auto det : m_subdetectors)
0983 {
0984 size_t det_idx = (det == QVecShared::Subdetector::S) ? 0 : 1;
0985 double sepd_total_charge = (det_idx == 0) ? sepd_total_charge_south : sepd_total_charge_north;
0986 m_q_vectors[h_idx][det_idx].x /= sepd_total_charge;
0987 m_q_vectors[h_idx][det_idx].y /= sepd_total_charge;
0988 }
0989 }
0990
0991 return true;
0992 }
0993
0994 bool QVecCalib::process_event_check()
0995 {
0996 double cent = m_evtdata->get_event_centrality();
0997 int cent_bin = hSEPD_Charge_Min->FindBin(cent);
0998
0999 double sepd_totalcharge = m_evtdata->get_sepd_totalcharge();
1000
1001 double sepd_totalcharge_min = hSEPD_Charge_Min->GetBinContent(cent_bin);
1002 double sepd_totalcharge_max = hSEPD_Charge_Max->GetBinContent(cent_bin);
1003
1004 return sepd_totalcharge > sepd_totalcharge_min && sepd_totalcharge < sepd_totalcharge_max;
1005 }
1006
1007
1008 int QVecCalib::process_event(PHCompositeNode *topNode)
1009 {
1010 m_evtdata = findNode::getClass<EventPlaneData>(topNode, "EventPlaneData");
1011 if (!m_evtdata)
1012 {
1013 std::cout << PHWHERE << "EventPlaneData Node missing." << std::endl;
1014 return Fun4AllReturnCodes::ABORTRUN;
1015 }
1016
1017 int event_id = m_evtdata->get_event_id();
1018
1019 if (Verbosity() && m_event % PROGRESS_REPORT_INTERVAL == 0)
1020 {
1021 std::cout << "Progress: " << m_event << ", Global: " << event_id << std::endl;
1022 }
1023 ++m_event;
1024
1025 double cent = m_evtdata->get_event_centrality();
1026
1027 bool isGood = process_event_check();
1028
1029
1030 if (!isGood)
1031 {
1032 ++m_event_counters.bad_centrality_sepd_correlation;
1033 return Fun4AllReturnCodes::ABORTEVENT;
1034 }
1035
1036 isGood = process_sEPD();
1037
1038
1039 if (!isGood)
1040 {
1041 ++m_event_counters.zero_sepd_total_charge;
1042 return Fun4AllReturnCodes::ABORTEVENT;
1043 }
1044
1045 hCentrality->Fill(cent);
1046
1047 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
1048 {
1049 const auto& q_S = m_q_vectors[h_idx][0];
1050 const auto& q_N = m_q_vectors[h_idx][1];
1051
1052
1053 if (m_pass == Pass::ComputeRecentering)
1054 {
1055 process_averages(cent, q_S, q_N, m_average_hists[h_idx]);
1056 }
1057
1058
1059 else if (m_pass == Pass::ApplyRecentering)
1060 {
1061 process_recentering(cent, h_idx, q_S, q_N, m_recenter_hists[h_idx]);
1062 }
1063
1064
1065 else if (m_pass == Pass::ApplyFlattening)
1066 {
1067 process_flattening(cent, h_idx, q_S, q_N, m_flattening_hists[h_idx]);
1068 }
1069 }
1070
1071 return Fun4AllReturnCodes::EVENT_OK;
1072 }
1073
1074
1075 int QVecCalib::ResetEvent(PHCompositeNode * )
1076 {
1077 m_q_vectors = {};
1078
1079 return Fun4AllReturnCodes::EVENT_OK;
1080 }
1081
1082 void QVecCalib::compute_averages(size_t cent_bin, int h_idx)
1083 {
1084 int n = m_harmonics[h_idx];
1085
1086 std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n);
1087 std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n);
1088 std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n);
1089 std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n);
1090
1091 int bin = cent_bin + 1;
1092
1093 double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin);
1094 double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin);
1095 double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin);
1096 double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin);
1097
1098 m_correction_data[cent_bin][h_idx][static_cast<size_t>(QVecShared::Subdetector::S)].avg_Q = {Q_S_x_avg, Q_S_y_avg};
1099 m_correction_data[cent_bin][h_idx][static_cast<size_t>(QVecShared::Subdetector::N)].avg_Q = {Q_N_x_avg, Q_N_y_avg};
1100
1101 std::cout << std::format(
1102 "Centrality Bin: {}, "
1103 "Harmonic: {}, "
1104 "Q_S_x_avg: {:13.10f}, "
1105 "Q_S_y_avg: {:13.10f}, "
1106 "Q_N_x_avg: {:13.10f}, "
1107 "Q_N_y_avg: {:13.10f}",
1108 cent_bin,
1109 n,
1110 Q_S_x_avg,
1111 Q_S_y_avg,
1112 Q_N_x_avg,
1113 Q_N_y_avg) << std::endl;
1114 }
1115
1116 void QVecCalib::compute_recentering(size_t cent_bin, int h_idx)
1117 {
1118 int n = m_harmonics[h_idx];
1119
1120 std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr");
1121 std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr");
1122 std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr");
1123 std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr");
1124
1125 int bin = cent_bin + 1;
1126
1127 double Q_S_x_corr_avg = m_profiles[S_x_corr_avg_name]->GetBinContent(bin);
1128 double Q_S_y_corr_avg = m_profiles[S_y_corr_avg_name]->GetBinContent(bin);
1129 double Q_N_x_corr_avg = m_profiles[N_x_corr_avg_name]->GetBinContent(bin);
1130 double Q_N_y_corr_avg = m_profiles[N_y_corr_avg_name]->GetBinContent(bin);
1131
1132
1133 std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n);
1134 std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n);
1135 std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n);
1136 std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n);
1137 std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n);
1138 std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n);
1139
1140 double Q_S_xx_avg = m_profiles[S_xx_avg_name]->GetBinContent(bin);
1141 double Q_S_yy_avg = m_profiles[S_yy_avg_name]->GetBinContent(bin);
1142 double Q_S_xy_avg = m_profiles[S_xy_avg_name]->GetBinContent(bin);
1143 double Q_N_xx_avg = m_profiles[N_xx_avg_name]->GetBinContent(bin);
1144 double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin);
1145 double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin);
1146
1147
1148 std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n);
1149 std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n);
1150 std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n);
1151
1152 double Q_NS_xx_avg = m_profiles[NS_xx_avg_name]->GetBinContent(bin);
1153 double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin);
1154 double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin);
1155
1156 m_correction_data[cent_bin][h_idx][static_cast<size_t>(QVecShared::Subdetector::NS)].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS");
1157
1158 for (size_t det_idx = 0; det_idx < 2; ++det_idx)
1159 {
1160 double xx = (det_idx == 0) ? Q_S_xx_avg : Q_N_xx_avg;
1161 double yy = (det_idx == 0) ? Q_S_yy_avg : Q_N_yy_avg;
1162 double xy = (det_idx == 0) ? Q_S_xy_avg : Q_N_xy_avg;
1163
1164 std::string label = (det_idx == 0) ? "S" : "N";
1165
1166 m_correction_data[cent_bin][h_idx][det_idx].X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, label);
1167 }
1168
1169 std::cout << std::format(
1170 "Centrality Bin: {}, "
1171 "Harmonic: {}, "
1172 "Q_S_x_corr_avg: {:13.10f}, "
1173 "Q_S_y_corr_avg: {:13.10f}, "
1174 "Q_N_x_corr_avg: {:13.10f}, "
1175 "Q_N_y_corr_avg: {:13.10f}, "
1176 "Q_S_xx_avg / Q_S_yy_avg: {:13.10f}, "
1177 "Q_N_xx_avg / Q_N_yy_avg: {:13.10f}, "
1178 "Q_NS_xx_avg / Q_NS_yy_avg: {:13.10f}, "
1179 "Q_S_xy_avg: {:13.10f}, "
1180 "Q_N_xy_avg: {:13.10f}, "
1181 "Q_NS_xy_avg: {:13.10f}",
1182 cent_bin,
1183 n,
1184 Q_S_x_corr_avg,
1185 Q_S_y_corr_avg,
1186 Q_N_x_corr_avg,
1187 Q_N_y_corr_avg,
1188 Q_S_xx_avg / Q_S_yy_avg,
1189 Q_N_xx_avg / Q_N_yy_avg,
1190 Q_NS_xx_avg / Q_NS_yy_avg,
1191 Q_S_xy_avg,
1192 Q_N_xy_avg,
1193 Q_NS_xy_avg) << std::endl;
1194 }
1195
1196 void QVecCalib::print_flattening(size_t cent_bin, int n) const
1197 {
1198 std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2");
1199 std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2");
1200 std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2");
1201 std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2");
1202
1203 std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr");
1204 std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr");
1205 std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr");
1206 std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr");
1207 std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr");
1208 std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr");
1209
1210 std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr");
1211 std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr");
1212 std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr");
1213
1214 int bin = cent_bin + 1;
1215
1216 double Q_S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name)->GetBinContent(bin);
1217 double Q_S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name)->GetBinContent(bin);
1218 double Q_N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name)->GetBinContent(bin);
1219 double Q_N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name)->GetBinContent(bin);
1220
1221 double Q_S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name)->GetBinContent(bin);
1222 double Q_S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name)->GetBinContent(bin);
1223 double Q_S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name)->GetBinContent(bin);
1224 double Q_N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name)->GetBinContent(bin);
1225 double Q_N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name)->GetBinContent(bin);
1226 double Q_N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name)->GetBinContent(bin);
1227
1228 double Q_NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name)->GetBinContent(bin);
1229 double Q_NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name)->GetBinContent(bin);
1230 double Q_NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name)->GetBinContent(bin);
1231
1232 std::cout << std::format(
1233 "Centrality Bin: {}, "
1234 "Harmonic: {}, "
1235 "Q_S_x_corr2_avg: {:13.10f}, "
1236 "Q_S_y_corr2_avg: {:13.10f}, "
1237 "Q_N_x_corr2_avg: {:13.10f}, "
1238 "Q_N_y_corr2_avg: {:13.10f}, "
1239 "Q_S_xx_corr_avg / Q_S_yy_corr_avg: {:13.10f}, "
1240 "Q_N_xx_corr_avg / Q_N_yy_corr_avg: {:13.10f}, "
1241 "Q_NS_xx_corr_avg / Q_NS_yy_corr_avg: {:13.10f}, "
1242 "Q_S_xy_corr_avg: {:13.10f}, "
1243 "Q_N_xy_corr_avg: {:13.10f}, "
1244 "Q_NS_xy_corr_avg: {:13.10f}",
1245 cent_bin,
1246 n,
1247 Q_S_x_corr2_avg,
1248 Q_S_y_corr2_avg,
1249 Q_N_x_corr2_avg,
1250 Q_N_y_corr2_avg,
1251 Q_S_xx_corr_avg / Q_S_yy_corr_avg,
1252 Q_N_xx_corr_avg / Q_N_yy_corr_avg,
1253 Q_NS_xx_corr_avg / Q_NS_yy_corr_avg,
1254 Q_S_xy_corr_avg,
1255 Q_N_xy_corr_avg,
1256 Q_NS_xy_corr_avg) << std::endl;
1257 }
1258
1259 void QVecCalib::write_cdb()
1260 {
1261 std::error_code ec;
1262 if (std::filesystem::create_directories(m_cdb_output_dir, ec))
1263 {
1264 std::cout << "Success: Directory " << m_cdb_output_dir << " created" << std::endl;
1265 }
1266 else if (ec)
1267 {
1268 std::cout << "Failed to create directory " << m_cdb_output_dir << ": " << ec.message() << std::endl;
1269 exit(1);
1270 }
1271 else
1272 {
1273 std::cout << "Info: Directory " << m_cdb_output_dir << " already exists." << std::endl;
1274 }
1275
1276 write_cdb_BadTowers();
1277 write_cdb_EventPlane();
1278 }
1279
1280 void QVecCalib::write_cdb_BadTowers()
1281 {
1282 std::cout << "Writing Bad Towers CDB" << std::endl;
1283
1284 std::string payload = "SEPD_HotMap";
1285 std::string fieldname_status = "status";
1286 std::string fieldname_sigma = "SEPD_sigma";
1287 std::string output_file = std::format("{}/{}-{}-{}.root", m_cdb_output_dir, payload, m_dst_tag, m_runnumber);
1288
1289 CDBTTree cdbttree(output_file);
1290
1291 for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel)
1292 {
1293 unsigned int key = TowerInfoDefs::encode_epd(channel);
1294 int status = hSEPD_Bad_Channels->GetBinContent(channel+1);
1295
1296 float sigma = 0;
1297
1298
1299 if (status == static_cast<int>(QVecShared::ChannelStatus::Hot))
1300 {
1301 sigma = SIGMA_HOT;
1302 }
1303
1304
1305 else if (status == static_cast<int>(QVecShared::ChannelStatus::Cold))
1306 {
1307 sigma = SIGMA_COLD;
1308 }
1309
1310 cdbttree.SetIntValue(key, fieldname_status, status);
1311 cdbttree.SetFloatValue(key, fieldname_sigma, sigma);
1312 }
1313
1314 std::cout << "Saving CDB: " << payload << " to " << output_file << std::endl;
1315
1316 cdbttree.Commit();
1317 cdbttree.WriteCDBTTree();
1318 }
1319
1320 void QVecCalib::write_cdb_EventPlane()
1321 {
1322 std::cout << "Writing Event Plane CDB" << std::endl;
1323
1324 std::string payload = "SEPD_EventPlaneCalib";
1325 std::string output_file = std::format("{}/{}-{}-{}.root", m_cdb_output_dir, payload, m_dst_tag, m_runnumber);
1326
1327 CDBTTree cdbttree(output_file);
1328
1329 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
1330 {
1331 int n = m_harmonics[h_idx];
1332
1333
1334 auto field = [&](const std::string& det, const std::string& var)
1335 {
1336 return std::format("Q_{}_{}_{}_avg", det, var, n);
1337 };
1338
1339 for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin)
1340 {
1341 int key = cent_bin;
1342
1343
1344 for (size_t d = 0; d < static_cast<size_t>(QVecShared::Subdetector::Count); ++d)
1345 {
1346 auto det_enum = static_cast<QVecShared::Subdetector>(d);
1347
1348
1349 std::string det_label;
1350 switch (det_enum)
1351 {
1352 case QVecShared::Subdetector::S:
1353 det_label = "S";
1354 break;
1355 case QVecShared::Subdetector::N:
1356 det_label = "N";
1357 break;
1358 case QVecShared::Subdetector::NS:
1359 det_label = "NS";
1360 break;
1361 default:
1362 continue;
1363 }
1364
1365 const auto& data = m_correction_data[cent_bin][h_idx][d];
1366
1367 if (det_enum != QVecShared::Subdetector::NS)
1368 {
1369 cdbttree.SetDoubleValue(key, field(det_label, "x"), data.avg_Q.x);
1370 cdbttree.SetDoubleValue(key, field(det_label, "y"), data.avg_Q.y);
1371 }
1372
1373
1374 cdbttree.SetDoubleValue(key, field(det_label, "xx"), data.avg_Q_xx);
1375 cdbttree.SetDoubleValue(key, field(det_label, "yy"), data.avg_Q_yy);
1376 cdbttree.SetDoubleValue(key, field(det_label, "xy"), data.avg_Q_xy);
1377 }
1378 }
1379 }
1380
1381 std::cout << "Saving CDB: " << payload << " to " << output_file << std::endl;
1382
1383 cdbttree.Commit();
1384 cdbttree.WriteCDBTTree();
1385 }
1386
1387
1388 int QVecCalib::End(PHCompositeNode * )
1389 {
1390 std::cout << "QVecCalib::End(PHCompositeNode *topNode) This is the End..." << std::endl;
1391
1392 std::cout << "\n--- Event Counter Summary ---" << std::endl;
1393 std::cout << "Bad Centrality/sEPD corr: " << m_event_counters.bad_centrality_sepd_correlation << std::endl;
1394 std::cout << "Zero sEPD Charge: " << m_event_counters.zero_sepd_total_charge << std::endl;
1395 std::cout << "Total Events Seen: " << m_event << std::endl;
1396 std::cout << "-----------------------------\n" << std::endl;
1397
1398 for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin)
1399 {
1400 for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx)
1401 {
1402 int n = m_harmonics[h_idx];
1403
1404 if (m_pass == Pass::ComputeRecentering)
1405 {
1406 compute_averages(cent_bin, h_idx);
1407 }
1408
1409 else if (m_pass == Pass::ApplyRecentering)
1410 {
1411 compute_recentering(cent_bin, h_idx);
1412 }
1413
1414 else if (m_pass == Pass::ApplyFlattening)
1415 {
1416 print_flattening(cent_bin, n);
1417 }
1418 }
1419 }
1420
1421 if (m_pass == Pass::ApplyFlattening)
1422 {
1423 write_cdb();
1424 }
1425
1426 return Fun4AllReturnCodes::EVENT_OK;
1427 }