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