Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:15:39

0001 #include "ChargeMapReader.h"
0002 
0003 #include "MultiArray.h"
0004 
0005 #include <TAxis.h>
0006 #include <TFile.h>
0007 #include <TH2.h>
0008 #include <TH3.h>
0009 
0010 #include <boost/format.hpp>
0011 
0012 #include <cassert>
0013 #include <cmath>
0014 #include <iostream>
0015 
0016 #define DEBUG false
0017 
0018 ChargeMapReader::ChargeMapReader()
0019   : ChargeMapReader(20, 20.0, 78.0, 20, 0, 2 * M_PI, 40, -105.5, 105.5)
0020 {
0021   std::cout << "made a new ChargeMapReader with default values -- cascading to next constructor" << std::endl;
0022   return;
0023 }
0024 
0025 ChargeMapReader::ChargeMapReader(int _nr, float _rmin, float _rmax, int _nphi, float _phimin, float _phimax, int _nz, float _zmin, float _zmax)
0026 {
0027   std::cout << boost::str(boost::format("made a new ChargeMapReader with defined values:\n %d %.2f %.2f\n %d %.2f %.2f\n %d %.2f %.2f") % _nr % _rmin % _rmax % _nphi % _phimin % _phimax % _nz % _zmin % _zmax) << std::endl;
0028   SetOutputParameters(_nr, _rmin, _rmax, _nphi, _phimin, _phimax, _nz, _zmin, _zmax);
0029   return;
0030 }
0031 
0032 bool ChargeMapReader::CanInterpolateAt(float r, float phi, float z)
0033 {
0034   return CanInterpolateAt(phi, r, z, hChargeDensity);
0035 }
0036 
0037 // a convenient method to check whether it's safe to interpolate for a particular histogram.
0038 bool ChargeMapReader::CanInterpolateAt(float x, float y, float z, TH3* h)
0039 {
0040   if (h == nullptr)
0041   {
0042     return false;
0043   }
0044   float pos[3] = {x, y, z};
0045   // todo: is it worth keeping these values somewhere for ease of access?
0046   TAxis* ax[3] = {nullptr, nullptr, nullptr};
0047   ax[0] = h->GetXaxis();
0048   ax[1] = h->GetYaxis();
0049   ax[2] = h->GetZaxis();
0050 
0051   int nbins[3];
0052   for (int i = 0; i < 3; i++)
0053   {
0054     nbins[i] = ax[i]->GetNbins();  // number of bins, not counting under and overflow.
0055     if (nbins[i] == 1)
0056     {
0057       return false;  // if there's only one non over/under bin, then no place is safe to interpolate.
0058     }
0059   }
0060 
0061   //   0     1     2   ...   n-1    n    n+1
0062   // under|first|   ..|  ..  |  .. |last| over
0063   for (int i = 0; i < 3; i++)
0064   {  // check each axis:
0065     int axbin = ax[i]->FindBin(pos[i]);
0066 
0067     if (axbin < 1 || axbin > nbins[i])
0068     {
0069       return false;  // before the first bin, or after the last bin
0070     }
0071     if (axbin > 1 && axbin < nbins[i])
0072     {
0073       continue;  // if we're in a middle bin, we're fine on this axis.
0074     }
0075 
0076     // now we need to check if we're in the safe parts of the first and last bins:
0077     float low = ax[i]->GetBinLowEdge(axbin);
0078     float high = ax[i]->GetBinUpEdge(axbin);
0079     float binmid = 0.5 * (high + low);
0080 
0081     if (axbin == 1 && pos[i] <= binmid)
0082     {
0083       return false;  // we're in the first bin, but below the midpoint, so we would interpolate out of bounds
0084     }
0085     if (axbin == nbins[i] && pos[i] >= binmid)
0086     {
0087       return false;  // we're in the last bin, but above the midpoint, so we would interpolate out of bounds
0088     }
0089   }
0090 
0091   // if we get here, we are in the okay-range of all three axes.
0092   return true;
0093 }
0094 
0095 void ChargeMapReader::FillChargeHistogram(TH3* h)
0096 {
0097   // fills the provided histogram with the data from the internal representation.
0098 
0099   //   0     1     2     ...   n-1
0100   // first|   ..|  ..  |  .. |last
0101   float dphi, dr, dz;  // bin widths in each dimension.  Got too confusing to make these an array.
0102   if (DEBUG)
0103   {
0104     std::cout << "filling chargehistogram" << std::endl;
0105   }
0106 
0107   dr = binWidth[0];
0108   dphi = binWidth[1];
0109   dz = binWidth[2];
0110 
0111   float phimid, zmid;  // midpoints at each step.
0112   int i[3];
0113   for (i[0] = 0; i[0] < nBins[0]; i[0]++)
0114   {  // r
0115     float rmid = lowerBound[0] + (i[0] + 0.5) * dr;
0116     for (i[1] = 0; i[1] < nBins[1]; i[1]++)
0117     {  // phi
0118       phimid = lowerBound[1] + (i[1] + 0.5) * dphi;
0119       for (i[2] = 0; i[2] < nBins[2]; i[2]++)
0120       {  // z
0121         zmid = lowerBound[2] + (i[2] + 0.5) * dz;
0122         h->Fill(phimid, rmid, zmid, charge->Get(i[0], i[1], i[2]));
0123       }  // z
0124     }    // phi
0125   }      // r
0126   return;
0127 }
0128 
0129 void ChargeMapReader::RegenerateCharge()
0130 {
0131   // Builds the charge 3D array (internal representation) from the internal charge density map.
0132   // either the density map has changed, or the binning of the output has changed (hopefully not the latter, because that's a very unusual thing to change mid-run.
0133   // we want to rebuild the charge per bin of our output representation in any case.  Generally, we will interpolate from the charge density that we know we have, but we need to be careful not to ask to interpolate in regions where that is not allowed.
0134   if (DEBUG)
0135   {
0136     std::cout << boost::str(boost::format("regenerating charge array contents with axis scale=%1.2E and charge scale=%1.2E") % inputAxisScale % inputChargeScale) << std::endl;
0137   }
0138   if (hChargeDensity == nullptr)
0139   {
0140     // we don't have charge information, so set everything to zeroes
0141     std::cout << "no charge data found.  Setting all charges to 0.0" << std::endl;
0142     charge->SetAll(0);  // otherwise set the array to all zeroes.
0143     return;
0144   }
0145 
0146   //   0     1     2     ...   n-1
0147   // first|   ..|  ..  |  .. |last
0148   float dphi, dr, dz;  // internal rep bin widths in each dimension.  Got too confusing to make these an array.
0149   dr = binWidth[0];
0150   dphi = binWidth[1];
0151   dz = binWidth[2];
0152   float dzhist, drhist;
0153   dzhist = dz / inputAxisScale;
0154   drhist = dr / inputAxisScale;
0155 
0156   float phimid, zmid;  // position of the center of each fixed-width array bin, in the input histogram units
0157   // note that since we computed density using the hist units, we must use those units for the volume term again here.
0158   int i[3];
0159   for (i[0] = 0; i[0] < nBins[0]; i[0]++)
0160   {  // r
0161     float rmid = (lowerBound[0] + (i[0] + 0.5) * dr) / inputAxisScale;
0162     // float rlow = (lowerBound[0] + dr * i[0]) / inputAxisScale;
0163     float histBinVolume = dzhist * dphi * rmid * drhist;  // volume of our output bin in histogram units.
0164     // note that since we have equal bin widths, the volume term depends only on r.
0165     //  Q_bin=Density_ion_interp*bin_volume*(coulomb/ion)
0166     float scaleFactor = histBinVolume * inputChargeScale;  // hence the total scale factor is the volume term times the charge scale factor
0167     for (i[1] = 0; i[1] < nBins[1]; i[1]++)
0168     {  // phi
0169       phimid = lowerBound[1] + (i[1] + 0.5) * dphi;
0170       for (i[2] = 0; i[2] < nBins[2]; i[2]++)
0171       {  // z
0172         zmid = (lowerBound[2] + (i[2] + 0.5) * dz) / inputAxisScale;
0173         float q = 0;
0174         if (CanInterpolateAt(phimid, rmid, zmid, hChargeDensity))
0175         {  // interpolate if we can
0176           if (false)
0177           {  // deep debug statements.
0178             std::cout << boost::str(boost::format("function said we could interpolate at (r,phi,z)=(%.2f, %.2f,%.2f), bounds are:") % rmid % phimid % zmid);
0179             std::cout << boost::str(boost::format("  r: %.2f < %.2f < %.2f") % hChargeDensity->GetYaxis()->GetXmin() % rmid % (hChargeDensity->GetYaxis()->GetXmax()));
0180             std::cout << boost::str(boost::format("  p: %.2f < %.2f < %.2f") % hChargeDensity->GetXaxis()->GetXmin() % phimid % hChargeDensity->GetXaxis()->GetXmax());
0181             std::cout << boost::str(boost::format("  z: %.2f < %.2f < %.2f") % hChargeDensity->GetZaxis()->GetXmin() % zmid % hChargeDensity->GetZaxis()->GetXmax()) << std::endl;
0182           }
0183           q = scaleFactor * hChargeDensity->Interpolate(phimid, rmid, zmid);
0184         }
0185         else
0186         {  // otherwise, just take the central value and assume it's flat.  Better than a zero.
0187           q = scaleFactor * hChargeDensity->GetBinContent(hChargeDensity->FindBin(phimid, rmid, zmid));
0188         }
0189         if (false)
0190         {  // deep debug statements.
0191           int global = hSourceCharge->FindBin(phimid, rmid, zmid);
0192           if (CanInterpolateAt(phimid, rmid, zmid, hChargeDensity))
0193           {
0194             std::cout << boost::str(boost::format("density debug report (interp) (r,phi,z)=(%.2f, %.2f,%.2f), glob=%d, q_dens=%E") % rmid % phimid % zmid % global % q);
0195             std::cout << boost::str(boost::format(", density=%E, vol=%E") % (hChargeDensity->Interpolate(phimid, rmid, zmid)) % histBinVolume);
0196             std::cout << boost::str(boost::format(", q_bin=%E, q_bin_coul=%E") % (hSourceCharge->GetBinContent(hSourceCharge->FindBin(phimid, rmid, zmid))) % (hSourceCharge->GetBinContent(hSourceCharge->FindBin(phimid, rmid, zmid)) * inputChargeScale));
0197             std::cout << boost::str(boost::format(", q_interp=%E, q_bin_coul/vol=%E") % (hSourceCharge->Interpolate(phimid, rmid, zmid)) % (hSourceCharge->GetBinContent(hSourceCharge->FindBin(phimid, rmid, zmid)) / histBinVolume)) << std::endl;
0198           }
0199           else
0200           {
0201             std::cout << boost::str(boost::format("density debug report (getbin) (r,phi,z)=(%.2f, %.2f,%.2f), glob=%d, q_dens=%E") % rmid % phimid % zmid % global % q);
0202             std::cout << boost::str(boost::format(", density=%E, vol=%E") % hChargeDensity->GetBinContent(hChargeDensity->FindBin(phimid, rmid, zmid)) % histBinVolume);
0203             std::cout << boost::str(boost::format(", q_bin=%E, q_bin_ions=%E") % hSourceCharge->GetBinContent(hSourceCharge->FindBin(phimid, rmid, zmid)) % (hSourceCharge->GetBinContent(hSourceCharge->FindBin(phimid, rmid, zmid)) / inputChargeScale));
0204             std::cout << boost::str(boost::format(", q_bin_ions/vol=%E") % (hSourceCharge->GetBinContent(hSourceCharge->FindBin(phimid, rmid, zmid)) / scaleFactor)) << std::endl;
0205           }
0206         }
0207         charge->Set(i[0], i[1], i[2], q);
0208 
0209       }  // z
0210     }    // phi
0211   }      // r
0212 
0213   if (DEBUG)
0214   {
0215     std::cout << "done regenerating charge array contents" << std::endl;
0216   }
0217 
0218   return;
0219 }
0220 
0221 void ChargeMapReader::RegenerateDensity()
0222 {
0223   // assume the input map has changed, so we need to rebuild our internal representation of the density.
0224   // this is done by cloning the SourceCharge histogram and dividing each bin in it by its volume
0225   if (DEBUG)
0226   {
0227     std::cout << "regenerating density histogram" << std::endl;
0228   }
0229 
0230   // if we have one already, delete it.
0231   if (hChargeDensity != nullptr)
0232   {
0233     if (DEBUG)
0234     {
0235       std::cout << "deleting old density histogram" << std::endl;
0236     }
0237     delete hChargeDensity;
0238   }
0239   if (hSourceCharge == nullptr)
0240   {
0241     // the source data doesn't exist, so we will fail if we try to clone
0242     std::cout << "no source charge data file is open, or the histogram was not found." << std::endl;
0243     return;
0244   }
0245 
0246   // clone this from the source histogram, which we assume is open.
0247   hChargeDensity = static_cast<TH3*>(hSourceCharge->Clone("hChargeDensity"));
0248   hChargeDensity->Reset();
0249 
0250   // then go through it, bin by bin, and replace each bin content with the corresponding density, so we can interpolate correctly.
0251   // TODO:  Does this mean we once again need 'guard' bins?  Gross.
0252 
0253   TAxis* ax[3] = {nullptr, nullptr, nullptr};
0254   ax[0] = hChargeDensity->GetXaxis();
0255   ax[1] = hChargeDensity->GetYaxis();
0256   ax[2] = hChargeDensity->GetZaxis();
0257 
0258   int nbins[3];
0259   for (int i = 0; i < 3; i++)
0260   {
0261     nbins[i] = ax[i]->GetNbins();  // number of bins, not counting under and overflow.
0262   }
0263 
0264   //   0     1     2   ...   n-1    n    n+1
0265   // under|first|   ..|  ..  |  .. |last| over
0266   int i[3];
0267   float low[3], high[3];
0268   float dr, dz;  // bin widths in each dimension.  Got too confusing to make these an array.
0269   // note that all of this is done in the native units of the source data, specifically, the volume element is in hist units, not our internal units.
0270 
0271   for (i[0] = 1; i[0] <= nbins[0]; i[0]++)
0272   {  // phi
0273     int a = 0;
0274     low[a] = ax[a]->GetBinLowEdge(i[a]);
0275     high[a] = ax[a]->GetBinUpEdge(i[a]);
0276     float dphi = high[a] - low[a];
0277     for (i[1] = 1; i[1] <= nbins[1]; i[1]++)
0278     {  // r
0279       a = 1;
0280       low[a] = ax[a]->GetBinLowEdge(i[a]);
0281       high[a] = ax[a]->GetBinUpEdge(i[a]);
0282       dr = high[a] - low[a];
0283       float rphiterm = dphi * (low[1] + 0.5 * dr) * dr;
0284       for (i[2] = 1; i[2] <= nbins[2]; i[2]++)
0285       {  // z
0286         a = 2;
0287         low[a] = ax[a]->GetBinLowEdge(i[a]);
0288         high[a] = ax[a]->GetBinUpEdge(i[a]);
0289         dz = high[a] - low[a];
0290         // float volume=dz*dphi*(low[1]+0.5*dr)*dr;
0291         float volume = dz * rphiterm;
0292         int globalBin = hSourceCharge->GetBin(i[0], i[1], i[2]);
0293         float q = hSourceCharge->GetBinContent(globalBin);
0294         hChargeDensity->SetBinContent(globalBin, q / volume);
0295         if (false)
0296         {  // deep debug statements.
0297           std::cout << boost::str(boost::format("iprz=(%d,%d,%d),glob=%d") % i[0] % i[1] % i[2] % globalBin);
0298           std::cout << boost::str(boost::format("edges=[%.2f,%.2f],[%.1f,%.1f],[%.1f,%f.1],") % low[0] % high[0] % low[1] % high[1] % low[2] % high[2]);
0299           std::cout << boost::str(boost::format("\tq=%E,vol=%E,dens=%E") % q % volume % hChargeDensity->GetBinContent(globalBin)) << std::endl;
0300         }
0301       }
0302     }
0303   }
0304   if (DEBUG)
0305   {
0306     std::cout << "done regenerating density histogram" << std::endl;
0307   }
0308 
0309   return;
0310 }
0311 
0312 bool ChargeMapReader::ReadSourceCharge(const std::string& filename, const std::string& histname, float axisScale, float contentScale)
0313 {
0314   // load the charge-per-bin data from the specified file.
0315   inputAxisScale = axisScale;
0316   inputChargeScale = contentScale;
0317   TFile* inputFile = TFile::Open(filename.c_str(), "READ");
0318   inputFile->GetObject(histname.c_str(), hSourceCharge);
0319   if (hSourceCharge == nullptr)
0320   {
0321     return false;
0322   }
0323   RegenerateDensity();
0324   RegenerateCharge();
0325   inputFile->Close();
0326   // after this, the source histogram doesn't exist anymore.
0327   return true;
0328 }
0329 
0330 bool ChargeMapReader::ReadSourceCharge(TH3* sourceHist, float axisScale, float contentScale)
0331 {
0332   if (DEBUG)
0333   {
0334     std::cout << "reading charge from " << sourceHist->GetName() << std::endl;
0335   }
0336   inputAxisScale = axisScale;
0337   inputChargeScale = contentScale;
0338   hSourceCharge = sourceHist;  // note that this means we don't own this histogram!
0339   if (hSourceCharge == nullptr)
0340   {
0341     return false;
0342   }
0343   RegenerateDensity();
0344   RegenerateCharge();
0345 
0346   if (DEBUG)
0347   {
0348     std::cout << "done reading charge from " << sourceHist->GetName() << std::endl;
0349   }
0350 
0351   return true;
0352 }
0353 
0354 bool ChargeMapReader::ReadSourceAdc(const std::string& adcfilename, const std::string& adchistname, const std::string& ibfgainfilename, const std::string& ibfgainhistname, float axisScale, float contentScale)
0355 {
0356   // load the adc-per-bin data from the specified file.
0357   TFile* adcInputFile = TFile::Open(adcfilename.c_str(), "READ");
0358   TH3* hAdc = nullptr;
0359   adcInputFile->GetObject(adchistname.c_str(), hAdc);
0360   if (hSourceCharge == nullptr)
0361   {
0362     std::cout << "Source Charge hist or file " << adcfilename << " not found!" << std::endl;
0363     return false;
0364   }
0365   // load the conversion factor from adc sum to ibf
0366   TFile* ibfGainInputFile = TFile::Open(ibfgainfilename.c_str(), "READ");
0367   TH2* hIbfGain = nullptr;
0368   ibfGainInputFile->GetObject(ibfgainhistname.c_str(), hIbfGain);
0369   if (hIbfGain == nullptr)
0370   {
0371     std::cout << "IBF Gain hist or file " << ibfgainfilename << " not found!" << std::endl;
0372     return false;
0373   }
0374 
0375   // and then hand the task off to the next function
0376   bool ret = ReadSourceAdc(hAdc, hIbfGain, axisScale, contentScale);
0377   adcInputFile->Close();
0378   // after this, the source histograms don't exist anymore.
0379   return ret;
0380 }
0381 
0382 bool ChargeMapReader::ReadSourceAdc(TH3* adcHist, TH2* gainHist, float axisScale, float contentScale)
0383 {
0384   if (DEBUG)
0385   {
0386     std::cout << "reading ADCs from " << adcHist->GetName() << ", ibfGain from "
0387               << gainHist->GetName() << std::endl;
0388   }
0389   inputAxisScale = axisScale;
0390   inputChargeScale = contentScale;
0391   hSourceCharge = adcHist;  // note that this means we don't own this histogram!  It may disappear.
0392   if (hSourceCharge == nullptr)
0393   {
0394     return false;
0395   }
0396 
0397   // scale the voxels of the sourcecharge by the gainhist data.
0398 
0399   TAxis* ax[3] = {nullptr, nullptr, nullptr};
0400   ax[0] = hSourceCharge->GetXaxis();
0401   ax[1] = hSourceCharge->GetYaxis();
0402   ax[2] = hSourceCharge->GetZaxis();
0403 
0404   int nbins[3];
0405   for (int i = 0; i < 3; i++)
0406   {
0407     nbins[i] = ax[i]->GetNbins();  // number of bins, not counting under and overflow.
0408   }
0409 
0410   //   0     1     2   ...   n-1    n    n+1
0411   // under|first|   ..|  ..  |  .. |last| over
0412   int i[3];
0413 
0414   for (i[0] = 1; i[0] <= nbins[0]; i[0]++)
0415   {  // phi
0416     for (i[1] = 1; i[1] <= nbins[1]; i[1]++)
0417     {  // r
0418       int globalBin2D = gainHist->GetBin(i[0], i[1]);
0419       float scalefactor = gainHist->GetBinContent(globalBin2D);
0420       for (i[2] = 1; i[2] <= nbins[2]; i[2]++)
0421       {  // z
0422         int globalBin = hSourceCharge->GetBin(i[0], i[1], i[2]);
0423         float q = hSourceCharge->GetBinContent(globalBin);
0424         hSourceCharge->SetBinContent(globalBin, q * scalefactor);
0425         if (false)
0426         {  // deep debug statements.
0427           std::cout << boost::str(boost::format("applying gain to adc input:  iprz=(%d,%d,%d), glob3d=%d, glob2d=%d, adc=%f, scale=%f") % i[0] % i[1] % i[2] % globalBin % globalBin2D % q % scalefactor) << std::endl;
0428         }
0429       }  // z
0430     }    // r
0431   }      // phi
0432   if (DEBUG)
0433   {
0434     std::cout << "done converting adc hist to ions" << std::endl;
0435   }
0436 
0437   RegenerateDensity();
0438   RegenerateCharge();
0439 
0440   if (DEBUG)
0441   {
0442     std::cout << "done converting ADCs from " << adcHist->GetName() << std::endl;
0443   }
0444 
0445   return true;
0446 }
0447 
0448 bool ChargeMapReader::SetOutputParameters(int _nr, float _rmin, float _rmax, int _nphi, float _phimin, float _phimax, int _nz, float _zmin, float _zmax)
0449 {
0450   // change all the parameters of our output array and rebuild the array from scratch.
0451   if (!(_rmax > _rmin) || !(_phimax > _phimin) || !(_zmax > _zmin))
0452   {
0453     return false;  // the bounds are not well-ordered.
0454   }
0455   if (_nr < 1 || _nphi < 1 || _nz < 1)
0456   {
0457     return false;  // must be at least one bin wide.
0458   }
0459 
0460   nBins[0] = _nr;
0461   nBins[1] = _nphi;
0462   nBins[2] = _nz;
0463   lowerBound[0] = _rmin;
0464   lowerBound[1] = _phimin;
0465   lowerBound[2] = _zmin;
0466   upperBound[0] = _rmax;
0467   upperBound[1] = _phimax;
0468   upperBound[2] = _zmax;
0469 
0470   for (int i = 0; i < 3; i++)
0471   {
0472     binWidth[i] = (upperBound[i] - lowerBound[i]) / (1.0 * nBins[i]);
0473   }
0474 
0475   // if the array exists, delete it.
0476   if (charge != nullptr)
0477   {
0478     if (DEBUG)
0479     {
0480       std::cout << "charge array existed.  deleting" << std::endl;
0481     }
0482     delete charge;
0483     charge = nullptr;
0484   }
0485   if (DEBUG)
0486   {
0487     std::cout << "building new charge array" << std::endl;
0488   }
0489   if (DEBUG)
0490   {
0491     std::cout << "should have " << (nBins[0] * nBins[1] * nBins[2])
0492               << " elements" << std::endl;
0493   }
0494 
0495   charge = new MultiArray<float>(nBins[0], nBins[1], nBins[2]);
0496 
0497   if (hChargeDensity != nullptr)
0498   {
0499     if (DEBUG)
0500     {
0501       std::cout << "charge density data exists, regenerating charge" << std::endl;
0502     }
0503     RegenerateCharge();  // fill the array with the charge data if available
0504   }
0505   else
0506   {
0507     charge->SetAll(0);  // otherwise set the array to all zeroes.
0508   }
0509   if (DEBUG)
0510   {
0511     std::cout << "finished building array" << std::endl;
0512   }
0513 
0514   return true;
0515 }
0516 
0517 bool ChargeMapReader::SetOutputBounds(float _rmin, float _rmax, float _phimin, float _phimax, float _zmin, float _zmax)
0518 {
0519   // change all the bounds of our output array and rebuild the array from scratch, leaving the original binning
0520 
0521   if (!(_rmax > _rmin) || !(_phimax > _phimin) || !(_zmax > _zmin))
0522   {
0523     return false;  // the bounds are not well-ordered.
0524   }
0525 
0526   lowerBound[0] = _rmin;
0527   lowerBound[1] = _phimin;
0528   lowerBound[2] = _zmin;
0529   upperBound[0] = _rmax;
0530   upperBound[1] = _phimax;
0531   upperBound[2] = _zmax;
0532 
0533   for (int i = 0; i < 3; i++)
0534   {
0535     binWidth[i] = (upperBound[i] - lowerBound[i]) / (1.0 * nBins[i]);
0536   }
0537 
0538   // if the array exists, delete it.
0539   if (charge != nullptr)
0540   {
0541     delete charge;
0542     charge = nullptr;
0543   }
0544   charge = new MultiArray<float>(nBins[0], nBins[1], nBins[2]);
0545 
0546   if (hChargeDensity != nullptr)
0547   {
0548     RegenerateCharge();  // fill the array with the charge data if available
0549   }
0550   else
0551   {
0552     charge->SetAll(0);  // otherwise set the array to all zeroes.
0553   }
0554   return true;
0555 
0556   return true;
0557 }
0558 
0559 bool ChargeMapReader::SetOutputBins(int _nr, int _nphi, int _nz)
0560 {
0561   // change the number of bins of our output array and rebuild the array from scratch, leaving the bounds alone.
0562   if (_nr < 1 || _nphi < 1 || _nz < 1)
0563   {
0564     return false;  // must be at least one bin wide.
0565   }
0566   nBins[0] = _nr;
0567   nBins[1] = _nphi;
0568   nBins[2] = _nz;
0569 
0570   for (int i = 0; i < 3; i++)
0571   {
0572     binWidth[i] = (upperBound[i] - lowerBound[i]) / (1.0 * nBins[i]);
0573   }
0574 
0575   // if the array exists, delete it.
0576   if (charge != nullptr)
0577   {
0578     delete charge;
0579     charge = nullptr;
0580   }
0581   charge = new MultiArray<float>(nBins[0], nBins[1], nBins[2]);
0582 
0583   if (hChargeDensity != nullptr)
0584   {
0585     RegenerateCharge();  // fill the array with the charge data if available
0586   }
0587   else
0588   {
0589     charge->SetAll(0);  // otherwise set the array to all zeroes.
0590   }
0591   return true;
0592 }
0593 
0594 void ChargeMapReader::AddChargeInBin(int r, int phi, int z, float q)
0595 {
0596   assert(r > 0 && r < nBins[0]);
0597   assert(phi > 0 && phi < nBins[1]);
0598   assert(z > 0 && z < nBins[2]);
0599   if (DEBUG)
0600   {
0601     std::cout << boost::str(boost::format("adding charge in array element %d %d %d to %.2E") % r % phi % z % q) << std::endl;
0602   }
0603 
0604   charge->Add(r, phi, z, q);
0605   return;
0606 }
0607 
0608 void ChargeMapReader::AddChargeAtPosition(float r, float phi, float z, float q)
0609 {
0610   // bounds checking are handled by the binwise function, so no need to do so here:
0611   AddChargeInBin((r - lowerBound[0]) / binWidth[0], (phi - lowerBound[1]) / binWidth[1], (z - lowerBound[2]) / binWidth[2], q);
0612   return;
0613 }
0614 
0615 float ChargeMapReader::GetChargeInBin(int r, int phi, int z)
0616 {
0617   if (!(r >= 0 && r < nBins[0]))
0618   {
0619     std::cout << "requested rbin " << r << ", but bounds are 0 to "
0620               << nBins[0] << ". Failing." << std::endl;
0621     assert(r >= 0 && r < nBins[0]);
0622   }
0623   if (!(phi >= 0 && phi < nBins[1]))
0624   {
0625     std::cout << "requested phibin " << phi << ", but bounds are 0 to "
0626               << nBins[1] << ". Failing." << std::endl;
0627     assert(phi >= 0 && phi < nBins[1]);
0628   }
0629   if (!(z >= 0 && z < nBins[2]))
0630   {
0631     std::cout << "requested rbin " << z << ", but bounds are 0 to "
0632               << nBins[2] << ". Failing." << std::endl;
0633     assert(z >= 0 && z < nBins[2]);
0634   }
0635 
0636   if (DEBUG)
0637   {
0638     std::cout << "getting charge in array element " << r << " "
0639               << phi << " " << z << std::endl;
0640   }
0641 
0642   return charge->Get(r, phi, z);
0643 }
0644 
0645 float ChargeMapReader::GetChargeAtPosition(float r, float phi, float z)
0646 {
0647   // bounds checking are handled by the binwise function, so no need to do so here:
0648   return GetChargeInBin((r - lowerBound[0]) / binWidth[0], (phi - lowerBound[1]) / binWidth[1], (z - lowerBound[2]) / binWidth[2]);
0649 }
0650 
0651 void ChargeMapReader::SetChargeInBin(int r, int phi, int z, float q)
0652 {
0653   if (!(r >= 0 && r < nBins[0]))
0654   {
0655     std::cout << "requested rbin " << r << ", but bounds are to " << nBins[0]
0656               << ". Failing." << std::endl;
0657     assert(r >= 0 && r < nBins[0]);
0658   }
0659   if (!(phi >= 0 && phi < nBins[1]))
0660   {
0661     std::cout << "requested phibin " << phi << ", but bounds are 0 to "
0662               << nBins[1] << ". Failing." << std::endl;
0663     assert(phi >= 0 && phi < nBins[1]);
0664   }
0665   if (!(z >= 0 && z < nBins[2]))
0666   {
0667     std::cout << "requested rbin " << z << ", but bounds are 0 to "
0668               << nBins[2] << ". Failing." << std::endl;
0669     assert(z >= 0 && z < nBins[2]);
0670   }
0671   if (DEBUG)
0672   {
0673     std::cout << boost::str(boost::format("setting charge in array element %d %d %d to %.2E") % r % phi % z % q) << std::endl;
0674   }
0675 
0676   charge->Set(r, phi, z, q);
0677   return;
0678 }
0679 
0680 void ChargeMapReader::SetChargeAtPosition(float r, float phi, float z, float q)
0681 {
0682   // bounds checking are handled by the binwise function, so no need to do so here:
0683   SetChargeInBin((r - lowerBound[0]) / binWidth[0], (phi - lowerBound[1]) / binWidth[1], (z - lowerBound[2]) / binWidth[2], q);
0684   return;
0685 }