File indexing completed on 2025-12-18 09:17:52
0001 #include "Rossegger.h"
0002
0003 #include <TVector3.h>
0004
0005 #include <cmath>
0006 #include <limits>
0007 #include <string>
0008
0009 class AnalyticFieldModel;
0010 class ChargeMapReader;
0011 class TH2;
0012 class TH3;
0013 class TTree;
0014
0015 template <class T>
0016 class MultiArray;
0017
0018 class AnnularFieldSim
0019 {
0020 public:
0021 enum BoundsCase
0022 {
0023 InBounds,
0024 OnHighEdge,
0025 OnLowEdge,
0026 OutOfBounds
0027 };
0028 enum LookupCase
0029 {
0030 Full3D,
0031 HybridRes,
0032 PhiSlice,
0033 Analytic,
0034 NoLookup
0035 };
0036
0037
0038
0039
0040
0041
0042 enum ChargeCase
0043 {
0044 FromFile,
0045 AnalyticSpacecharge,
0046 NoSpacecharge
0047 };
0048
0049
0050
0051 AnnularFieldSim(float rin, float rout, float dz, int r, int phi, int z, float vdr);
0052 AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
0053 int r, int roi_r0, int roi_r1,
0054 int phi, int roi_phi0, int roi_phi1,
0055 int z, int roi_z0, int roi_z1,
0056 float vdr, LookupCase in_lookupCase = PhiSlice);
0057 AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
0058 int r, int roi_r0, int roi_r1, int in_rLowSpacing, int in_rHighSize,
0059 int phi, int roi_phi0, int roi_phi1, int in_phiLowSpacing, int in_phiHighSize,
0060 int z, int roi_z0, int roi_z1, int in_zLowSpacing, int in_zHighSize,
0061 float vdr, LookupCase in_lookupCase);
0062 AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
0063 int r, int roi_r0, int roi_r1, int in_rLowSpacing, int in_rHighSize,
0064 int phi, int roi_phi0, int roi_phi1, int in_phiLowSpacing, int in_phiHighSize,
0065 int z, int roi_z0, int roi_z1, int in_zLowSpacing, int in_zHighSize,
0066 float vdr, LookupCase in_lookupCase, ChargeCase in_chargeCase);
0067
0068 explicit AnnularFieldSim(const AnnularFieldSim &) = delete;
0069 AnnularFieldSim &operator=(const AnnularFieldSim &) = delete;
0070
0071
0072 void UpdateEveryN(int n)
0073 {
0074 debug_npercent = n;
0075 debug_printActionEveryN = 0;
0076 return;
0077 };
0078 bool debugFlag()
0079 {
0080 if (debug_printActionEveryN > 0 && debug_printCounter++ >= debug_printActionEveryN)
0081 {
0082 debug_printCounter = 0;
0083 return true;
0084 }
0085 return false;
0086 };
0087 void SetDistortionScaleRPZ(float a, float b, float c)
0088 {
0089 debug_distortionScale.SetXYZ(a, b, c);
0090 return;
0091 };
0092 void SetTruncationDistance(int x)
0093 {
0094 truncation_length = x;
0095 return;
0096 }
0097
0098
0099 std::string GetLookupString();
0100 std::string GetGasString();
0101 std::string GetFieldString();
0102 const std::string &GetChargeString() { return chargestring; };
0103 float GetNominalB() { return Bnominal; };
0104 float GetNominalE() { return Enominal; };
0105 float GetChargeAt(const TVector3 &pos);
0106 TVector3 GetLocalFieldComponents(const TVector3 &field, const TVector3 &pos, const TVector3 &origin);
0107 TVector3 GetFieldAt(const TVector3 &pos);
0108 TVector3 GetBFieldAt(const TVector3 &pos);
0109 TVector3 GetFieldStep() { return step; };
0110 int GetFieldStepsR() { return nr_roi; };
0111 int GetFieldStepsPhi() { return nphi_roi; };
0112 int GetFieldStepsZ() { return nz_roi; };
0113 TVector3 GetInnerEdge() { return TVector3(rmin, 0, zmin); };
0114 TVector3 GetOuterEdge() { return TVector3(rmax, 0, zmax); };
0115
0116
0117 void GenerateDistortionMaps(const std::string &filebase, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false);
0118
0119 void GenerateSeparateDistortionMaps(const std::string &filebase, int nSteps = 500, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false);
0120
0121 void PlotFieldSlices(const std::string &filebase, const TVector3 &pos, char which = 'E');
0122
0123 void load_spacecharge(const std::string &filename, const std::string &histname, float zoffset = 0, float chargescale = 1, float cmscale = 1, bool isChargeDensity = true);
0124 void load_spacecharge(TH3 *hist, float zoffset, float chargescale, float cmscale, bool isChargeDensity, const std::string &inputchargestring = "");
0125
0126 void load_digital_current(TH3 *hist, TH2 *gainHist, float chargescale, float cmscale, const std::string &inputchargestring);
0127
0128 void load_and_resample_spacecharge(int new_nphi, int new_nr, int new_nz, const std::string &filename, const std::string &histname, float zoffset, float chargescale, float cmscale, bool isChargeDensity);
0129
0130 void load_and_resample_spacecharge(int new_nphi, int new_nr, int new_nz, TH3 *hist, float zoffset, float chargescale, float cmscale, bool isChargeDensity);
0131 void save_spacecharge(const std::string &filename);
0132 void load_analytic_spacecharge(float scalefactor);
0133 void add_testcharge(float r, float phi, float z, float coulombs);
0134
0135 void setNominalB(float x)
0136 {
0137 Bnominal = x;
0138 UpdateOmegaTau();
0139 return;
0140 };
0141 void setNominalE(float x)
0142 {
0143 Enominal = x;
0144 UpdateOmegaTau();
0145 return;
0146 };
0147 void setFlatFields(float B, float E);
0148 void loadEfield(const std::string &filename, const std::string &treename, int zsign = 1);
0149 void loadBfield(const std::string &filename, const std::string &treename);
0150 void load3dBfield(const std::string &filename, const std::string &treename, int zsign = 1, float scale = 1.0, float xshift = 0, float yshift = 0, float zshift = 0);
0151
0152 void loadField(MultiArray<TVector3> **field, TTree *source, const float *rptr, const float *phiptr, const float *zptr, const float *frptr, const float *fphiptr, const float *fzptr, float fieldunit, int zsign, float xshift = 0, float yshift = 0, float zshift = 0);
0153
0154 void load_rossegger(double epsilon = 1E-4)
0155 {
0156 green = new Rossegger(rmin, rmax, zmax, epsilon);
0157 return;
0158 };
0159 void borrow_rossegger(Rossegger *ross, float zshift)
0160 {
0161 green = ross;
0162 green_shift = zshift;
0163 printf("AnnularFieldSim::borrow_rossegger: borrowed Rossegger table with zshift %f\n", zshift);
0164 return;
0165 };
0166 void borrow_epartial_from(AnnularFieldSim *sim, float zshift)
0167 {
0168 Epartial_phislice = sim->Epartial_phislice;
0169 green_shift = zshift;
0170 printf("AnnularFieldSim::borrow_epartial_from: borrowed Epartial_phislice table with zshift %f\n", zshift);
0171 return;
0172 };
0173 void set_twin(AnnularFieldSim *sim)
0174 {
0175 twin = sim;
0176 hasTwin = true;
0177 return;
0178 };
0179
0180 TVector3 calc_unit_field(TVector3 at, TVector3 from);
0181 TVector3 analyticFieldIntegral(float zdest, TVector3 start) { return analyticFieldIntegral(zdest, start, Efield); };
0182
0183 TVector3 analyticFieldIntegral(float zdest, TVector3 start, MultiArray<TVector3> *field);
0184 TVector3 interpolatedFieldIntegral(float zdest, TVector3 start) { return interpolatedFieldIntegral(zdest, start, Efield); };
0185 TVector3 interpolatedFieldIntegral(float zdest, const TVector3 &start, MultiArray<TVector3> *field);
0186 double FilterPhiPos(double phi);
0187 int FilterPhiIndex(int phi, int range) const;
0188
0189 TVector3 GetCellCenter(int r, int phi, int z);
0190 TVector3 GetRoiCellCenter(int r, int phi, int z);
0191 TVector3 GetGroupCellCenter(int r0, int r1, int phi0, int phi1, int z0, int z1);
0192 TVector3 GetWeightedCellCenter(int r, int phi, int z);
0193 TVector3 fieldIntegral(float zdest, const TVector3 &start, MultiArray<TVector3> *field);
0194 void populate_fieldmap();
0195
0196 void populate_lookup();
0197 void populate_full3d_lookup();
0198 void populate_highres_lookup();
0199 void populate_lowres_lookup();
0200 void populate_phislice_lookup();
0201
0202 void load_phislice_lookup(const std::string &sourcefile);
0203 void save_phislice_lookup(const std::string &destfile);
0204
0205 Rossegger *green;
0206 float green_shift;
0207 AnnularFieldSim *twin = nullptr;
0208 bool hasTwin = false;
0209
0210 TVector3 sum_field_at(int r, int phi, int z);
0211 TVector3 sum_full3d_field_at(int r, int phi, int z);
0212 TVector3 sum_local_field_at(int r, int phi, int z);
0213 TVector3 sum_nonlocal_field_at(int r, int phi, int z);
0214 TVector3 sum_phislice_field_at(int r, int phi, int z);
0215 TVector3 swimToInAnalyticSteps(float zdest, TVector3 start, int steps, int *goodToStep);
0216 TVector3 swimToInSteps(float zdest, const TVector3 &start, int steps, bool interpolate, int *goodToStep);
0217 TVector3 swimTo(float zdest, const TVector3 &start, bool interpolate = true, bool useAnalytic = false);
0218 TVector3 GetStepDistortion(float zdest, const TVector3 &start, bool interpolate = true, bool useAnalytic = false);
0219 TVector3 GetTotalDistortion(float zdest, const TVector3 &start, int nsteps, bool interpolate = true, int *goodToStep = 0, int *success = 0);
0220
0221 private:
0222 BoundsCase GetRindexAndCheckBounds(float pos, int *r);
0223 BoundsCase GetPhiIndexAndCheckBounds(float pos, int *phi);
0224 BoundsCase GetZindexAndCheckBounds(float pos, int *z);
0225 int GetRindex(float pos);
0226 int GetPhiIndex(float pos);
0227 int GetZindex(float pos);
0228
0229 void UpdateOmegaTau()
0230 {
0231 omegatau_nominal = -Bnominal * vdrift / std::abs(Enominal);
0232 return;
0233 };
0234
0235 const float cm = 1;
0236 const float m = 100 * cm;
0237 const float mm = cm / 10;
0238 const float um = mm / 1e3;
0239
0240 const float C = 1;
0241 const float nC = C / 1e9;
0242 const float fC = C / 1e15;
0243
0244 const float s = 1;
0245 const float us = s / 1e6;
0246 const float ns = s / 1e9;
0247
0248 const float V = 1;
0249
0250 const float Tesla = V * s / m / m;
0251 const float kGauss = Tesla / 10;
0252
0253 const float eps0 = 8.854e-12 * (C / V) / m;
0254 const float epsinv = 1 / eps0;
0255 const float k_perm = 1 / (4 * 3.1416 * eps0);
0256
0257
0258 bool RdeltaRswitch = false;
0259 int debug_printActionEveryN;
0260 int debug_npercent;
0261 int debug_printCounter;
0262 TVector3 debug_distortionScale;
0263
0264 AnalyticFieldModel *aliceModel = nullptr;
0265
0266
0267
0268
0269
0270 TVector3 zero_vector;
0271
0272
0273
0274
0275 double vdrift = std::numeric_limits<double>::quiet_NaN();
0276 double langevin_T1 = std::numeric_limits<double>::quiet_NaN();
0277 double langevin_T2 = std::numeric_limits<double>::quiet_NaN();
0278 double omegatau_nominal = std::numeric_limits<double>::quiet_NaN();
0279
0280
0281
0282
0283 std::string fieldstring;
0284 std::string Bfieldname;
0285 std::string Efieldname;
0286
0287 std::string chargesourcename;
0288 std::string chargestring;
0289 float Enominal = std::numeric_limits<double>::quiet_NaN();
0290 float Bnominal;
0291
0292
0293 float phispan;
0294 float rmin, rmax;
0295 float zmin, zmax;
0296
0297 TVector3 dim;
0298
0299
0300
0301 int nr, nphi, nz;
0302 TVector3 step;
0303 LookupCase lookupCase;
0304 ChargeCase chargeCase;
0305 int truncation_length;
0306
0307
0308
0309 int rmin_roi, phimin_roi, zmin_roi;
0310 int rmax_roi, phimax_roi, zmax_roi;
0311 int nr_roi, nphi_roi, nz_roi;
0312
0313
0314
0315 int nr_high{-1};
0316 int nphi_high{-1};
0317 int nz_high{-1};
0318
0319
0320
0321 int r_spacing{-1};
0322 int phi_spacing{-1};
0323 int z_spacing{-1};
0324 int nr_low{-1};
0325 int nphi_low{-1};
0326 int nz_low{-1};
0327 int rmin_roi_low{-1};
0328 int phimin_roi_low{-1};
0329 int zmin_roi_low{-1};
0330 int rmax_roi_low{-1};
0331 int phimax_roi_low{-1};
0332 int zmax_roi_low{-1};
0333 int nr_roi_low{-1};
0334 int nphi_roi_low{-1};
0335 int nz_roi_low{-1};
0336
0337
0338
0339 MultiArray<TVector3> *Efield;
0340 MultiArray<TVector3> *Epartial_highres;
0341 MultiArray<TVector3> *Epartial_lowres;
0342 MultiArray<TVector3> *Epartial;
0343 MultiArray<TVector3> *Epartial_phislice;
0344 MultiArray<TVector3> *Eexternal;
0345 MultiArray<TVector3> *Bfield;
0346
0347 ChargeMapReader *q;
0348
0349 MultiArray<double> *q_local;
0350 MultiArray<double> *q_lowres;
0351 TH2 *hRdeltaRComponent{nullptr};
0352 };