File indexing completed on 2025-08-06 08:18:07
0001
0002
0003
0004
0005
0006
0007 #include "TpcSpaceChargeReconstructionHelper.h"
0008
0009 #include <TH2.h>
0010 #include <TH3.h>
0011 #include <TString.h>
0012
0013 #include <iostream>
0014
0015 namespace
0016 {
0017
0018 template <class T>
0019 inline constexpr T square(T x)
0020 {
0021 return x * x;
0022 }
0023
0024
0025 template <class T>
0026 inline constexpr T get_bound_angle(T phi)
0027 {
0028 while (phi < 0)
0029 {
0030 phi += 2 * M_PI;
0031 }
0032 while (phi >= 2 * M_PI)
0033 {
0034 phi -= 2 * M_PI;
0035 }
0036 return phi;
0037 }
0038
0039
0040 TpcSpaceChargeReconstructionHelper::range_t transform_range(const TpcSpaceChargeReconstructionHelper::range_t& a)
0041 {
0042 return {get_bound_angle(a.first), get_bound_angle(a.second)};
0043 }
0044
0045
0046 class range_ftor_t
0047 {
0048 public:
0049 explicit range_ftor_t(double value)
0050 : m_value(value){};
0051 bool operator()(const TpcSpaceChargeReconstructionHelper::range_t& range)
0052 {
0053 return m_value > range.first && m_value < range.second;
0054 }
0055
0056 private:
0057 double m_value = 0;
0058 };
0059
0060
0061 bool in_range(const double& value, const TpcSpaceChargeReconstructionHelper::range_t& range)
0062 { return range_ftor_t(value)(range); }
0063
0064
0065 bool in_range(const double& value, const TpcSpaceChargeReconstructionHelper::range_list_t& range_list)
0066 { return std::any_of(range_list.begin(), range_list.end(), range_ftor_t(value)); }
0067
0068 }
0069
0070
0071
0072 TpcSpaceChargeReconstructionHelper::range_t TpcSpaceChargeReconstructionHelper::phi_range_central = transform_range({-1.742, -1.43979});
0073
0074
0075 TpcSpaceChargeReconstructionHelper::range_t TpcSpaceChargeReconstructionHelper::phi_range_east = transform_range({-2.27002, -1.9673});
0076
0077
0078 TpcSpaceChargeReconstructionHelper::range_t TpcSpaceChargeReconstructionHelper::phi_range_west = transform_range({-1.21452, -0.911172});
0079
0080
0081 TpcSpaceChargeReconstructionHelper::range_list_t TpcSpaceChargeReconstructionHelper::theta_range_central = {{-0.918257, -0.613136}, {-0.567549, -0.031022}, {0.0332154, 0.570419}, {0.613631, 0.919122}};
0082
0083
0084 TpcSpaceChargeReconstructionHelper::range_list_t TpcSpaceChargeReconstructionHelper::theta_range_east = {{-0.636926, -0.133603}, {0.140678, 0.642714}};
0085
0086
0087 TpcSpaceChargeReconstructionHelper::range_list_t TpcSpaceChargeReconstructionHelper::theta_range_west = {{-0.643676, -0.141004}, {0.13485, 0.640695}};
0088
0089
0090 void TpcSpaceChargeReconstructionHelper::create_tpot_mask(TH3* hmask)
0091 {
0092 hmask->Reset();
0093
0094
0095 for (int ip = 0; ip < hmask->GetNbinsX(); ++ip)
0096 {
0097 for (int ir = 0; ir < hmask->GetNbinsY(); ++ir)
0098 {
0099 for (int iz = 0; iz < hmask->GetNbinsZ(); ++iz)
0100 {
0101 const double phi = hmask->GetXaxis()->GetBinCenter(ip + 1);
0102 const double r = hmask->GetYaxis()->GetBinCenter(ir + 1);
0103 const double z = hmask->GetZaxis()->GetBinCenter(iz + 1);
0104 const double theta = std::atan2(z, r);
0105 if (in_range(phi, phi_range_central) && in_range(theta, theta_range_central))
0106 {
0107 hmask->SetBinContent(ip + 1, ir + 1, iz + 1, 1);
0108 }
0109 }
0110 }
0111 }
0112 }
0113
0114
0115 void TpcSpaceChargeReconstructionHelper::extrapolate_z(TH3* source, const TH3* mask)
0116 {
0117 if (!source)
0118 {
0119 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_z - invalid source histogram" << std::endl;
0120 return;
0121 }
0122
0123 if (!mask)
0124 {
0125 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_z - invalid mask histogram" << std::endl;
0126 return;
0127 }
0128
0129
0130 for (int ir = 0; ir < source->GetNbinsY(); ++ir)
0131 {
0132 for (int ip = 0; ip < source->GetNbinsX(); ++ip)
0133 {
0134 int iz_min = -1;
0135 for (int iz = 0; iz < source->GetNbinsZ(); ++iz)
0136 {
0137 bool in_range = mask->GetBinContent(ip + 1, ir + 1, iz + 1) > 0;
0138 if (in_range)
0139 {
0140 iz_min = iz;
0141 continue;
0142 }
0143
0144
0145 if (iz_min < 0)
0146 {
0147 continue;
0148 }
0149
0150 int iz_max = iz + 1;
0151 for (; iz_max < source->GetNbinsZ(); ++iz_max)
0152 {
0153 in_range = mask->GetBinContent(ip + 1, ir + 1, iz_max + 1) > 0;
0154 if (in_range)
0155 {
0156 break;
0157 }
0158 }
0159
0160
0161 if (iz_max == source->GetNbinsZ())
0162 {
0163 continue;
0164 }
0165
0166
0167 const double z_min = source->GetZaxis()->GetBinCenter(iz_min + 1);
0168 const double z_max = source->GetZaxis()->GetBinCenter(iz_max + 1);
0169 const double z = source->GetZaxis()->GetBinCenter(iz + 1);
0170 const double alpha_min = (z_max - z) / (z_max - z_min);
0171 const double alpha_max = (z - z_min) / (z_max - z_min);
0172
0173 const double distortion_min = source->GetBinContent(ip + 1, ir + 1, iz_min + 1);
0174 const double distortion_max = source->GetBinContent(ip + 1, ir + 1, iz_max + 1);
0175 const double distortion = alpha_min * distortion_min + alpha_max * distortion_max;
0176
0177 const double error_min = source->GetBinError(ip + 1, ir + 1, iz_min + 1);
0178 const double error_max = source->GetBinError(ip + 1, ir + 1, iz_max + 1);
0179 const double error = std::sqrt(square(alpha_min * error_min) + square(alpha_max * error_max));
0180
0181 source->SetBinContent(ip + 1, ir + 1, iz + 1, distortion);
0182 source->SetBinError(ip + 1, ir + 1, iz + 1, error);
0183 }
0184 }
0185 }
0186 }
0187
0188
0189 void TpcSpaceChargeReconstructionHelper::extrapolate_z2(TH3* source, const TH3* mask, uint8_t side)
0190 {
0191 if (!source)
0192 {
0193 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_z - invalid source histogram" << std::endl;
0194 return;
0195 }
0196
0197 if (!mask)
0198 {
0199 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_z - invalid mask histogram" << std::endl;
0200 return;
0201 }
0202
0203
0204 for (int ir = 0; ir < source->GetNbinsY(); ++ir)
0205 {
0206 for (int ip = 0; ip < source->GetNbinsX(); ++ip)
0207 {
0208
0209 if (side & Side_positive)
0210 {
0211
0212 int iz_min = -1;
0213 for (int iz = source->GetNbinsZ() - 1; iz >= 0; --iz)
0214 {
0215 const bool in_range = mask->GetBinContent(ip + 1, ir + 1, iz + 1) > 0;
0216 if (in_range)
0217 {
0218 iz_min = iz;
0219 break;
0220 }
0221 }
0222
0223
0224 if (iz_min < 0)
0225 {
0226 continue;
0227 }
0228
0229
0230 for (int iz = iz_min + 1; iz < source->GetNbinsZ(); ++iz)
0231 {
0232 const double z_min = source->GetZaxis()->GetBinCenter(iz_min + 1);
0233 const double z_max = source->GetZaxis()->GetXmax();
0234 const double z = source->GetZaxis()->GetBinCenter(iz + 1);
0235 const double alpha_min = (z_max - z) / (z_max - z_min);
0236 const double alpha_max = (z - z_min) / (z_max - z_min);
0237
0238 const double distortion_min = source->GetBinContent(ip + 1, ir + 1, iz_min + 1);
0239 const double distortion_max = 0;
0240 const double distortion = alpha_min * distortion_min + alpha_max * distortion_max;
0241
0242 const double error_min = source->GetBinError(ip + 1, ir + 1, iz_min + 1);
0243 const double error_max = 0;
0244 const double error = std::sqrt(square(alpha_min * error_min) + square(alpha_max * error_max));
0245
0246 source->SetBinContent(ip + 1, ir + 1, iz + 1, distortion);
0247 source->SetBinError(ip + 1, ir + 1, iz + 1, error);
0248 }
0249 }
0250
0251
0252 if (side & Side_negative)
0253 {
0254
0255 int iz_max = -1;
0256 for (int iz = 0; iz < source->GetNbinsZ(); ++iz)
0257 {
0258 const bool in_range = mask->GetBinContent(ip + 1, ir + 1, iz + 1) > 0;
0259 if (in_range)
0260 {
0261 iz_max = iz;
0262 break;
0263 }
0264 }
0265
0266
0267 if (iz_max < 0)
0268 {
0269 continue;
0270 }
0271
0272
0273 for (int iz = 0; iz < iz_max; ++iz)
0274 {
0275 const double z_min = source->GetZaxis()->GetXmin();
0276 const double z_max = source->GetZaxis()->GetBinCenter(iz_max + 1);
0277 const double z = source->GetZaxis()->GetBinCenter(iz + 1);
0278 const double alpha_min = (z_max - z) / (z_max - z_min);
0279 const double alpha_max = (z - z_min) / (z_max - z_min);
0280
0281 const double distortion_min = 0;
0282 const double distortion_max = source->GetBinContent(ip + 1, ir + 1, iz_max + 1);
0283 const double distortion = alpha_min * distortion_min + alpha_max * distortion_max;
0284
0285 const double error_min = 0;
0286 const double error_max = source->GetBinError(ip + 1, ir + 1, iz_max + 1);
0287 const double error = std::sqrt(square(alpha_min * error_min) + square(alpha_max * error_max));
0288
0289 source->SetBinContent(ip + 1, ir + 1, iz + 1, distortion);
0290 source->SetBinError(ip + 1, ir + 1, iz + 1, error);
0291 }
0292 }
0293 }
0294 }
0295 }
0296
0297
0298 void TpcSpaceChargeReconstructionHelper::extrapolate_phi1(TH3* source, const TH2* source_cm, const TH3* mask)
0299 {
0300 if (!source)
0301 {
0302 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_phi1 - invalid source histogram" << std::endl;
0303 return;
0304 }
0305
0306 if (!mask)
0307 {
0308 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_phi1 - invalid mask histogram" << std::endl;
0309 return;
0310 }
0311
0312
0313 for (int ip = 0; ip < source->GetNbinsX(); ++ip)
0314 {
0315 for (int ir = 0; ir < source->GetNbinsY(); ++ir)
0316 {
0317 for (int iz = 0; iz < source->GetNbinsZ(); ++iz)
0318 {
0319
0320 bool in_range = mask->GetBinContent(ip + 1, ir + 1, iz + 1) > 0;
0321 if (in_range)
0322 {
0323 continue;
0324 }
0325
0326
0327 const double r = source->GetYaxis()->GetBinCenter(ir + 1);
0328 const double phi = source->GetXaxis()->GetBinCenter(ip + 1);
0329 static constexpr int n_sectors = 12;
0330 for (int sector = 1; sector < n_sectors; ++sector)
0331 {
0332
0333 double phi_ref = phi + 2. * M_PI * sector / n_sectors;
0334 while (phi_ref >= 2 * M_PI)
0335 {
0336 phi_ref -= 2 * M_PI;
0337 };
0338
0339 int ip_ref = source->GetXaxis()->FindBin(phi_ref) - 1;
0340 in_range = mask->GetBinContent(ip_ref + 1, ir + 1, iz + 1) > 0;
0341 if (!in_range)
0342 {
0343 continue;
0344 }
0345
0346
0347 double scale = 1;
0348 if (source_cm)
0349 {
0350 const double distortion_local = source_cm->Interpolate(phi, r);
0351 const double distortion_ref = source_cm->Interpolate(phi_ref, r);
0352 scale = distortion_local / distortion_ref;
0353 }
0354
0355
0356 const double distortion = scale * source->GetBinContent(ip_ref + 1, ir + 1, iz + 1);
0357 const double error = scale * source->GetBinError(ip_ref + 1, ir + 1, iz + 1);
0358 source->SetBinContent(ip + 1, ir + 1, iz + 1, distortion);
0359 source->SetBinError(ip + 1, ir + 1, iz + 1, error);
0360 }
0361 }
0362 }
0363 }
0364 }
0365
0366
0367 void TpcSpaceChargeReconstructionHelper::extrapolate_phi2(TH3* source, const TH3* mask)
0368 {
0369 if (!source)
0370 {
0371 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_phi2 - invalid source histogram" << std::endl;
0372 return;
0373 }
0374
0375 if (!mask)
0376 {
0377 std::cout << "TpcSpaceChargeReconstructionHelper::extrapolate_phi2 - invalid mask histogram" << std::endl;
0378 return;
0379 }
0380
0381
0382 for (int ir = 0; ir < source->GetNbinsY(); ++ir)
0383 {
0384 for (int iz = 0; iz < source->GetNbinsZ(); ++iz)
0385 {
0386 int ip_min = -1;
0387 for (int ip = 0; ip < source->GetNbinsX(); ++ip)
0388 {
0389 bool in_range = mask->GetBinContent(ip + 1, ir + 1, iz + 1) > 0;
0390 if (in_range)
0391 {
0392 ip_min = ip;
0393 continue;
0394 }
0395
0396
0397 if (ip_min < 0)
0398 {
0399 continue;
0400 }
0401
0402 int ip_max = ip + 1;
0403 for (; ip_max < source->GetNbinsX(); ++ip_max)
0404 {
0405 in_range = mask->GetBinContent(ip_max + 1, ir + 1, iz + 1) > 0;
0406 if (in_range)
0407 {
0408 break;
0409 }
0410 }
0411
0412
0413 if (ip_max == source->GetNbinsX())
0414 {
0415 continue;
0416 }
0417
0418
0419 const double phi_min = source->GetXaxis()->GetBinCenter(ip_min + 1);
0420 const double phi_max = source->GetXaxis()->GetBinCenter(ip_max + 1);
0421 const double phi = source->GetXaxis()->GetBinCenter(ip + 1);
0422
0423 const double alpha_min = (phi_max - phi) / (phi_max - phi_min);
0424 const double alpha_max = (phi - phi_min) / (phi_max - phi_min);
0425
0426 const double distortion_min = source->GetBinContent(ip_min + 1, ir + 1, iz + 1);
0427 const double distortion_max = source->GetBinContent(ip_max + 1, ir + 1, iz + 1);
0428 const double distortion = alpha_min * distortion_min + alpha_max * distortion_max;
0429
0430 const double error_min = source->GetBinError(ip_min + 1, ir + 1, iz + 1);
0431 const double error_max = source->GetBinError(ip_max + 1, ir + 1, iz + 1);
0432 const double error = std::sqrt(square(alpha_min * error_min) + square(alpha_max * error_max));
0433
0434 source->SetBinContent(ip + 1, ir + 1, iz + 1, distortion);
0435 source->SetBinError(ip + 1, ir + 1, iz + 1, error);
0436 }
0437 }
0438 }
0439 }
0440
0441
0442 std::tuple<TH3*, TH3*> TpcSpaceChargeReconstructionHelper::split(const TH3* source)
0443 {
0444 if (!source)
0445 {
0446 return std::make_tuple<TH3*, TH3*>(nullptr, nullptr);
0447 }
0448
0449 auto xaxis = source->GetXaxis();
0450 auto yaxis = source->GetYaxis();
0451 auto zaxis = source->GetZaxis();
0452 auto ibin = zaxis->FindBin((double) 0);
0453
0454
0455 const TString name(source->GetName());
0456 auto hneg = new TH3F(
0457 name + "_negz", name + "_negz",
0458 xaxis->GetNbins(), xaxis->GetXmin(), xaxis->GetXmax(),
0459 yaxis->GetNbins(), yaxis->GetXmin(), yaxis->GetXmax(),
0460 ibin - 1, zaxis->GetXmin(), zaxis->GetBinUpEdge(ibin - 1));
0461
0462 auto hpos = new TH3F(
0463 name + "_posz", name + "_posz",
0464 xaxis->GetNbins(), xaxis->GetXmin(), xaxis->GetXmax(),
0465 yaxis->GetNbins(), yaxis->GetXmin(), yaxis->GetXmax(),
0466 zaxis->GetNbins() - (ibin - 1), zaxis->GetBinLowEdge(ibin), zaxis->GetXmax());
0467
0468
0469 for (int ix = 0; ix < xaxis->GetNbins(); ++ix)
0470 {
0471 for (int iy = 0; iy < yaxis->GetNbins(); ++iy)
0472 {
0473 for (int iz = 0; iz < zaxis->GetNbins(); ++iz)
0474 {
0475 const auto content = source->GetBinContent(ix + 1, iy + 1, iz + 1);
0476 const auto error = source->GetBinError(ix + 1, iy + 1, iz + 1);
0477
0478 if (iz < ibin - 1)
0479 {
0480 hneg->SetBinContent(ix + 1, iy + 1, iz + 1, content);
0481 hneg->SetBinError(ix + 1, iy + 1, iz + 1, error);
0482 }
0483 else
0484 {
0485 hpos->SetBinContent(ix + 1, iy + 1, iz - (ibin - 1) + 1, content);
0486 hpos->SetBinError(ix + 1, iy + 1, iz - (ibin - 1) + 1, error);
0487 }
0488 }
0489 }
0490 }
0491
0492
0493 for (const auto h : {hneg, hpos})
0494 {
0495 h->GetXaxis()->SetTitle(source->GetXaxis()->GetTitle());
0496 h->GetYaxis()->SetTitle(source->GetYaxis()->GetTitle());
0497 h->GetZaxis()->SetTitle(source->GetZaxis()->GetTitle());
0498 }
0499
0500 return std::make_tuple(hneg, hpos);
0501 }
0502
0503
0504 TH3* TpcSpaceChargeReconstructionHelper::add_guarding_bins(const TH3* source, const TString& name)
0505 {
0506 std::array<int, 3> bins{};
0507 std::array<double, 3> x_min{};
0508 std::array<double, 3> x_max{};
0509
0510 int index = 0;
0511 for (const auto axis : {source->GetXaxis(), source->GetYaxis(), source->GetZaxis()})
0512 {
0513
0514 const auto bin_width = (axis->GetXmax() - axis->GetXmin()) / axis->GetNbins();
0515
0516
0517 bins[index] = axis->GetNbins() + 2;
0518
0519
0520 x_min[index] = axis->GetXmin() - bin_width;
0521 x_max[index] = axis->GetXmax() + bin_width;
0522 ++index;
0523 }
0524
0525
0526 auto hout = new TH3F(name, name,
0527 bins[0], x_min[0], x_max[0],
0528 bins[1], x_min[1], x_max[1],
0529 bins[2], x_min[2], x_max[2]);
0530
0531
0532 hout->GetXaxis()->SetTitle(source->GetXaxis()->GetTitle());
0533 hout->GetYaxis()->SetTitle(source->GetYaxis()->GetTitle());
0534 hout->GetZaxis()->SetTitle(source->GetZaxis()->GetTitle());
0535
0536
0537 const auto phibins = source->GetXaxis()->GetNbins();
0538 const auto rbins = source->GetYaxis()->GetNbins();
0539 const auto zbins = source->GetZaxis()->GetNbins();
0540
0541
0542 for (int iphi = 0; iphi < phibins; ++iphi)
0543 {
0544 for (int ir = 0; ir < rbins; ++ir)
0545 {
0546 for (int iz = 0; iz < zbins; ++iz)
0547 {
0548 hout->SetBinContent(iphi + 2, ir + 2, iz + 2, source->GetBinContent(iphi + 1, ir + 1, iz + 1));
0549 hout->SetBinError(iphi + 2, ir + 2, iz + 2, source->GetBinError(iphi + 1, ir + 1, iz + 1));
0550 }
0551 }
0552 }
0553
0554
0555
0556
0557
0558
0559
0560 for (int ir = 0; ir < rbins + 2; ++ir)
0561 {
0562 for (int iz = 0; iz < zbins + 2; ++iz)
0563 {
0564
0565 hout->SetBinContent(1, ir + 1, iz + 1, hout->GetBinContent(phibins + 1, ir + 1, iz + 1));
0566 hout->SetBinError(1, ir + 1, iz + 1, hout->GetBinError(phibins + 1, ir + 1, iz + 1));
0567
0568
0569 hout->SetBinContent(phibins + 2, ir + 1, iz + 1, hout->GetBinContent(2, ir + 1, iz + 1));
0570 hout->SetBinError(phibins + 2, ir + 1, iz + 1, hout->GetBinError(2, ir + 1, iz + 1));
0571 }
0572 }
0573
0574
0575 for (int iphi = 0; iphi < phibins + 2; ++iphi)
0576 {
0577 for (int iz = 0; iz < zbins + 2; ++iz)
0578 {
0579 hout->SetBinContent(iphi + 1, 1, iz + 1, hout->GetBinContent(iphi + 1, 2, iz + 1));
0580 hout->SetBinError(iphi + 1, 1, iz + 1, hout->GetBinError(iphi + 1, 2, iz + 1));
0581
0582 hout->SetBinContent(iphi + 1, rbins + 2, iz + 1, hout->GetBinContent(iphi + 1, rbins + 1, iz + 1));
0583 hout->SetBinError(iphi + 1, rbins + 2, iz + 1, hout->GetBinError(iphi + 1, rbins + 1, iz + 1));
0584 }
0585 }
0586
0587
0588 for (int iphi = 0; iphi < phibins + 2; ++iphi)
0589 {
0590 for (int ir = 0; ir < rbins + 2; ++ir)
0591 {
0592 hout->SetBinContent(iphi + 1, ir + 1, 1, hout->GetBinContent(iphi + 1, ir + 1, 2));
0593 hout->SetBinError(iphi + 1, ir + 1, 1, hout->GetBinError(iphi + 1, ir + 1, 2));
0594
0595 hout->SetBinContent(iphi + 1, ir + 1, zbins + 2, hout->GetBinContent(iphi + 1, ir + 1, zbins + 1));
0596 hout->SetBinError(iphi + 1, ir + 1, zbins + 2, hout->GetBinError(iphi + 1, ir + 1, zbins + 1));
0597 }
0598 }
0599
0600 return hout;
0601 }
0602
0603
0604 void TpcSpaceChargeReconstructionHelper::set_phi_range_central( const range_t& range)
0605 { phi_range_central = transform_range(range); }
0606
0607
0608 void TpcSpaceChargeReconstructionHelper::set_phi_range_east( const range_t& range)
0609 { phi_range_east = transform_range(range); }
0610
0611
0612 void TpcSpaceChargeReconstructionHelper::set_phi_range_west( const range_t& range)
0613 { phi_range_west = transform_range(range); }