Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:18:07

0001 /**
0002  * \file TpcSpaceChargeReconstructionHelper.cc
0003  * \brief performs simple histogram manipulations for generating space charge distortion map suitable for correcting TPC clusters
0004  * \author Hugo Pereira Da Costa <hugo.pereira-da-costa@cea.fr>
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   /// square
0018   template <class T>
0019   inline constexpr T square(T x)
0020   {
0021     return x * x;
0022   }
0023 
0024   // regularize angle between 0 and 2PI
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   /// make sure angles in a given window are betwwen [0, 2PI]
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   /// short class to check if a given value is in provided range
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   /// returns true if given value is in provided range
0061   bool in_range(const double& value, const TpcSpaceChargeReconstructionHelper::range_t& range)
0062   { return range_ftor_t(value)(range); }
0063 
0064   /// returns true if given value is in any of the provided range
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 }  // namespace
0069 
0070 /// default TPOT geometry, hardcoded
0071 /// phi range for central sector (TPC sectors 9 and 21)
0072 TpcSpaceChargeReconstructionHelper::range_t TpcSpaceChargeReconstructionHelper::phi_range_central = transform_range({-1.742, -1.43979});
0073 
0074 /// phi range for east sector (TPC sectors 8 and 20)
0075 TpcSpaceChargeReconstructionHelper::range_t TpcSpaceChargeReconstructionHelper::phi_range_east = transform_range({-2.27002, -1.9673});
0076 
0077 /// phi range for west sector (TPC sectors 10 and 22)
0078 TpcSpaceChargeReconstructionHelper::range_t TpcSpaceChargeReconstructionHelper::phi_range_west = transform_range({-1.21452, -0.911172});
0079 
0080 /// list of theta angles for each micromeas in central sector with theta defined as atan2(z,r)
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 /// list of theta angles for each micromeas in central sector with theta defined as atan2(z,r)
0084 TpcSpaceChargeReconstructionHelper::range_list_t TpcSpaceChargeReconstructionHelper::theta_range_east = {{-0.636926, -0.133603}, {0.140678, 0.642714}};
0085 
0086 /// list of theta angles for each micromeas in central sector with theta defined as atan2(z,r)
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   // loop over bins
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   // loop over phi bins
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         // iz is not in range. Check if iz_min was set. If not, skip this bin. If yes, find next bin in range
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         // check interpolation range validity
0161         if (iz_max == source->GetNbinsZ())
0162         {
0163           continue;
0164         }
0165 
0166         // do the interpolation
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   // loop over phi bins
0204   for (int ir = 0; ir < source->GetNbinsY(); ++ir)
0205   {
0206     for (int ip = 0; ip < source->GetNbinsX(); ++ip)
0207     {
0208       // handle pad plane on the positive side (zmax)
0209       if (side & Side_positive)
0210       {
0211         // find first non empty bin, starting from last zaxis bin
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         // check bin validity
0224         if (iz_min < 0)
0225         {
0226           continue;
0227         }
0228 
0229         // loop over empty bins and do the interpolation
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       // handle pad plane on the negative side (zmin
0252       if (side & Side_negative)
0253       {
0254         // find first non empty bin, starting from first zaxis bin
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         // check bin validity
0267         if (iz_max < 0)
0268         {
0269           continue;
0270         }
0271 
0272         // loop over empty bins and do the interpolation
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   // loop over phi bins
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         // do nothing if in TPOT acceptance
0320         bool in_range = mask->GetBinContent(ip + 1, ir + 1, iz + 1) > 0;
0321         if (in_range)
0322         {
0323           continue;
0324         }
0325 
0326         // phi not in TPOT range, rotate by steps of 2pi/12 (= one TPC sector) until found in range
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           // get ref phi
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           // get normalization factor from CM histograms
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           // update content and error
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   // loop over phi bins
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         // ip is not in range. Check if ip_min was set. If not, skip this bin. If yes, find next bin in range
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         // check that a valid bin was found
0413         if (ip_max == source->GetNbinsX())
0414         {
0415           continue;
0416         }
0417 
0418         // do the interpolation
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   // create histograms
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   // copy content and errors
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   // also copy axis titles
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     // calculate bin width
0514     const auto bin_width = (axis->GetXmax() - axis->GetXmin()) / axis->GetNbins();
0515 
0516     // increase the number of bins by two
0517     bins[index] = axis->GetNbins() + 2;
0518 
0519     // update axis limits accordingly
0520     x_min[index] = axis->GetXmin() - bin_width;
0521     x_max[index] = axis->GetXmax() + bin_width;
0522     ++index;
0523   }
0524 
0525   // create new histogram
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   // update axis legend
0532   hout->GetXaxis()->SetTitle(source->GetXaxis()->GetTitle());
0533   hout->GetYaxis()->SetTitle(source->GetYaxis()->GetTitle());
0534   hout->GetZaxis()->SetTitle(source->GetZaxis()->GetTitle());
0535 
0536   // copy content
0537   const auto phibins = source->GetXaxis()->GetNbins();
0538   const auto rbins = source->GetYaxis()->GetNbins();
0539   const auto zbins = source->GetZaxis()->GetNbins();
0540 
0541   // fill center
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   // fill guarding phi bins
0555   /*
0556    * we use 2pi periodicity to do that:
0557    * - last valid bin is copied to first guarding bin;
0558    * - first valid bin is copied to last guarding bin
0559    */
0560   for (int ir = 0; ir < rbins + 2; ++ir)
0561   {
0562     for (int iz = 0; iz < zbins + 2; ++iz)
0563     {
0564       // copy last bin to first guarding bin
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       // copy first bin to last guarding bin
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   // fill guarding r bins
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   // fill guarding z bins
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); }