Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AnnularFieldSim.h
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AnnularFieldSim.h
1 #include "Rossegger.h"
2 
3 #include <TH2.h>
4 #include <TVector3.h>
5 
6 #include <cmath> // for NAN, abs
7 #include <string> // for string
8 
10 class ChargeMapReader;
11 class TH3;
12 class TTree;
13 
14 template <class T>
15 class MultiArray;
16 
18 {
19  public:
21  {
26  }; // note that 'OnLowEdge' is qualitatively different from 'OnHighEdge'. Low means there is a non-zero distance between the point and the edge of the bin. High applies even if that distance is exactly zero.
28  {
34  };
35  // Full3D = uses (nr x nphi x nz)^2 lookup table
36  // Hybrid = uses (nr x nphi x nz) x (nr_local x nphi_local x nz_local) + (nr_low x nphi_low x nz_low)^2 set of tables
37  // PhiSlice = uses (nr x 1 x nz) x (nr x nphi x nz) lookup table exploiting phi symmetry.
38  // Analytic = doesn't use lookup tables -- no memory footprint, uses analytic E field at center of each bin.
39  // Note that this is not the same as analytic propagation, which checks the analytic field integrals in each step.
40  // NoLookup = Don't build any structures -- effectively ignores any calculated spacecharge field
42  {
46  }; // load from file, load from AnalyticFieldModel, or set to zero.
47  // note that if we set to Zero, we skip the lookup step.
48 
49  // constructors with history for backwards compatibility
50  AnnularFieldSim(float rmin, float rmax, float dz, int r, int phi, int z, float vdr); // abbr. constructor with roi=full region
51  AnnularFieldSim(float rin, float rout, float dz,
52  int r, int roi_r0, int roi_r1,
53  int phi, int roi_phi0, int roi_phi1,
54  int z, int roi_z0, int roi_z1,
55  float vdr, LookupCase in_lookupCase = PhiSlice);
56  AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
57  int r, int roi_r0, int roi_r1, int in_rLowSpacing, int in_rHighSize,
58  int phi, int roi_phi0, int roi_phi1, int in_phiLowSpacing, int in_phiHighSize,
59  int z, int roi_z0, int roi_z1, int in_zLowSpacing, int in_zHighSize,
60  float vdr, LookupCase in_lookupCase);
61  AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
62  int r, int roi_r0, int roi_r1, int in_rLowSpacing, int in_rHighSize,
63  int phi, int roi_phi0, int roi_phi1, int in_phiLowSpacing, int in_phiHighSize,
64  int z, int roi_z0, int roi_z1, int in_zLowSpacing, int in_zHighSize,
65  float vdr, LookupCase in_lookupCase, ChargeCase in_chargeCase);
67  explicit AnnularFieldSim(const AnnularFieldSim &) = delete;
68  AnnularFieldSim &operator=(const AnnularFieldSim &) = delete;
69 
70  // debug functions:
71  void UpdateEveryN(int n)
72  {
73  debug_npercent = n;
75  return;
76  };
77  bool debugFlag()
78  {
80  {
82  return true;
83  }
84  return false;
85  };
86  void SetDistortionScaleRPZ(float a, float b, float c)
87  {
88  debug_distortionScale.SetXYZ(a, b, c);
89  return;
90  };
92  {
94  return;
95  }
96 
97  // getters for internal states:
98  const char *GetLookupString();
99  const char *GetGasString();
100  const char *GetFieldString();
101  const char *GetChargeString() { return chargestring; };
102  float GetNominalB() { return Bnominal; };
103  float GetNominalE() { return Enominal; };
104  float GetChargeAt(const TVector3 &pos);
105  TVector3 GetFieldAt(const TVector3 &pos);
106  TVector3 GetBFieldAt(const TVector3 &pos);
107  TVector3 GetFieldStep() { return step; };
108  int GetFieldStepsR() { return nr_roi; };
109  int GetFieldStepsPhi() { return nphi_roi; };
110  int GetFieldStepsZ() { return nz_roi; };
111  TVector3 GetInnerEdge() { return TVector3(rmin, 0, zmin); };
112  TVector3 GetOuterEdge() { return TVector3(rmax, 0, zmax); };
113 
114  // file-writing functions for complex mapping questions:
115  void GenerateDistortionMaps(const char *filebase, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false);
116 
117  void GenerateSeparateDistortionMaps(const char *filebase, int nSteps = 500, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false);
118 
119  void PlotFieldSlices(const char *filebase, const TVector3 &pos, char which = 'E');
120 
121  void load_spacecharge(const std::string &filename, const std::string &histname, float zoffset = 0, float chargescale = 1, float cmscale = 1, bool isChargeDensity = true);
122  void load_spacecharge(TH3 *hist, float zoffset, float chargescale, float cmscale, bool isChargeDensity, const char *inputchargestring = "");
123 
124  void load_digital_current(TH3 *hist, TH2 *gainHist, float chargescale, float cmscale, const char *inputchargestring);
125 
126  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);
127 
128  void load_and_resample_spacecharge(int new_nphi, int new_nr, int new_nz, TH3 *hist, float zoffset, float chargescale, float cmscale, bool isChargeDensity);
130  void load_analytic_spacecharge(float scalefactor);
131  void add_testcharge(float r, float phi, float z, float coulombs);
132 
133  void setNominalB(float x)
134  {
135  Bnominal = x;
136  UpdateOmegaTau();
137  return;
138  };
139  void setNominalE(float x)
140  {
141  Enominal = x;
142  UpdateOmegaTau();
143  return;
144  };
145  void setFlatFields(float B, float E);
146  void loadEfield(const std::string &filename, const std::string &treename, int zsign = 1);
147  void loadBfield(const std::string &filename, const std::string &treename);
148  void load3dBfield(const std::string &filename, const std::string &treename, int zsign = 1, float scale = 1.0);
149 
150  void loadField(MultiArray<TVector3> **field, TTree *source, float *rptr, float *phiptr, float *zptr, float *frptr, float *fphiptr, float *fzptr, float fieldunit, int zsign);
151 
152  void load_rossegger(double epsilon = 1E-4)
153  {
154  green = new Rossegger(rmin, rmax, zmax, epsilon);
155  return;
156  };
157  void borrow_rossegger(Rossegger *ross, float zshift)
158  {
159  green = ross;
160  green_shift = zshift;
161  return;
162  }; // get an already-existing rossegger table instead of loading it ourselves.
163  void borrow_epartial_from(AnnularFieldSim *sim, float zshift)
164  {
166  green_shift = zshift;
167  return;
168  }; // get an already-existing rossegger table instead of loading it ourselves.
170  {
171  twin = sim;
172  hasTwin = true;
173  return;
174  }; // define a twin to handle the negative-z drifting. If asked to drift something out of range in z, if the twin flag is set we will ask the twin to do the drifting. Note that the twin does not get linked back in to this side. It is only the follower.
175 
176  TVector3 calc_unit_field(TVector3 at, TVector3 from);
177  TVector3 analyticFieldIntegral(float zdest, TVector3 start) { return analyticFieldIntegral(zdest, start, Efield); };
178 
179  TVector3 analyticFieldIntegral(float zdest, TVector3 start, MultiArray<TVector3> *field);
180  TVector3 interpolatedFieldIntegral(float zdest, TVector3 start) { return interpolatedFieldIntegral(zdest, start, Efield); };
181  TVector3 interpolatedFieldIntegral(float zdest, const TVector3 &start, MultiArray<TVector3> *field);
182  double FilterPhiPos(double phi); // puts phi in 0<phi<2pi
183  int FilterPhiIndex(int phi, int range); // puts phi in bin range 0<phi<range. defaults to using nphi for range.
184 
185  TVector3 GetCellCenter(int r, int phi, int z);
186  TVector3 GetRoiCellCenter(int r, int phi, int z);
187  TVector3 GetGroupCellCenter(int r0, int r1, int phi0, int phi1, int z0, int z1);
188  TVector3 GetWeightedCellCenter(int r, int phi, int z);
189  TVector3 fieldIntegral(float zdest, const TVector3 &start, MultiArray<TVector3> *field);
190  void populate_fieldmap();
191  // now handled by setting 'analytic' lookup: void populate_analytic_fieldmap();
192  void populate_lookup();
193  void populate_full3d_lookup();
195  void populate_lowres_lookup();
197 
198  void load_phislice_lookup(const char *sourcefile);
199  void save_phislice_lookup(const char *destfile);
200 
201  Rossegger *green; // stand-alone class to compute greens functions.
202  float green_shift; // how far to offset our position in z when querying our green's functions.
203  AnnularFieldSim *twin = nullptr;
204  bool hasTwin = false;
205 
206  TVector3 sum_field_at(int r, int phi, int z);
207  TVector3 sum_full3d_field_at(int r, int phi, int z);
208  TVector3 sum_local_field_at(int r, int phi, int z);
209  TVector3 sum_nonlocal_field_at(int r, int phi, int z);
210  TVector3 sum_phislice_field_at(int r, int phi, int z);
211  TVector3 swimToInAnalyticSteps(float zdest, TVector3 start, int steps, int *goodToStep);
212  TVector3 swimToInSteps(float zdest, const TVector3 &start, int steps, bool interpolate, int *goodToStep);
213  TVector3 swimTo(float zdest, const TVector3 &start, bool interpolate = true, bool useAnalytic = false);
214  TVector3 GetStepDistortion(float zdest, const TVector3 &start, bool interpolate = true, bool useAnalytic = false);
215  TVector3 GetTotalDistortion(float zdest, const TVector3 &start, int nsteps, bool interpolate = true, int *goodToStep = 0, int *success = 0);
216 
217  private:
221  int GetRindex(float pos);
222  int GetPhiIndex(float pos);
223  int GetZindex(float pos);
224 
226  {
228  return;
229  }; // various constants to match internal representation to the familiar formula. Adding in these factors suggests I should switch to a unitful calculation throughout...
230  // units:
231  const float cm = 1; // centimeters -- if you change this, check that all the loading functions are properly agnostic.
232  const float m = 100 * cm; // meters.
233  const float mm = cm / 10;
234  const float um = mm / 1e3;
235 
236  const float C = 1; // Coulombs
237  const float nC = C / 1e9;
238  const float fC = C / 1e15;
239 
240  const float s = 1; // seconds
241  const float us = s / 1e6;
242  const float ns = s / 1e9;
243 
244  const float V = 1; // volts
245 
246  const float Tesla = V * s / m / m; // Tesla=Vs/m^2
247  const float kGauss = Tesla / 10; // kGauss
248 
249  const float eps0 = 8.854e-12 * (C / V) / m; // Farads(=Coulombs/Volts) per meter
250  const float epsinv = 1 / eps0; // Vcm/C
251  const float k_perm = 1 / (4 * 3.1416 * eps0); // implied units of V*cm/C because we're doing unitful work here.
252  // debug items
253  // bool
254  bool RdeltaRswitch = false;
259 
261 
262  // the other half of the detector:
263 
264  // constants of motion, dimensions, etc:
265  //
266  TVector3 zero_vector; // a shorthand way to return a vectorial zero.
267  // static constexpr float k=8.987e13;//=1/(4*pi*eps0) in N*cm^2/C^2 in a vacuum. N*cm^2/C units, so that we supply space charge in coulomb units.
268  // static constexpr float k_perm=8.987e11;//=1/(4*pi*eps0) in (V*cm)/C in a vacuum. so that we supply space charge in Coulombs, distance in cm, and fields in V/cm
269 
270  // gas constants:
271  double vdrift = NAN; // gas drift speed in cm/s
272  double langevin_T1 = NAN;
273  double langevin_T2 = NAN; // gas tensor drift terms.
274  double omegatau_nominal = NAN; // nominal omegatau value, derived from vdrift and field strengths.
275  // double vprime; //first derivative of drift velocity at specific E
276  // double vprime2; //second derivative of drift velocity at specific E
277 
278  // field constants:
282  // char fieldstring[300],Bfieldname[100],Efieldname[100];
284  char chargestring[300] = {0}; //, chargefilename[100];
285  float Enominal = NAN; // magnitude of the nominal field on which drift speed is based, in V/cm.
286  float Bnominal; // magnitude of the nominal magnetic field on which drift speed is based, in Tesla.
287 
288  // physical dimensions
289  float phispan; // angular span of the area in the phi direction, since TVector3 is too smart.
290  float rmin, rmax; // inner and outer radii of the annulus
291  float zmin, zmax; // lower and upper edges of the coordinate system in z (not fully implemented yet)
292  // float phimin, phimax;//not implemented at all yet.
293  TVector3 dim; // dimensions of simulated region, in cm
294 
295  // variables related to the whole-volume tiling:
296  //
297  int nr, nphi, nz; // number of fundamental bins (f-bins) in each direction = dimensions of 3D array covering entire volume
298  TVector3 step; // size of an f-bin in each direction
299  LookupCase lookupCase; // which lookup system to instantiate and use.
300  ChargeCase chargeCase; // which charge model to use
301  int truncation_length; // distance in cells (full 3D metric in units of bins)
302 
303  // variables related to the region of interest:
304  //
305  int rmin_roi, phimin_roi, zmin_roi; // lower edge of our region of interest, measured in f-bins
306  int rmax_roi, phimax_roi, zmax_roi; // excluded upper edge of our region of interest, measured in f-bins
307  int nr_roi, nphi_roi, nz_roi; // dimensions of our roi in f-bins
308 
309  // variables related to the high-res behavior:
310  //
311  int nr_high = -1;
312  int nphi_high = -1;
313  int nz_high = -1; // dimensions, in f-bins of neighborhood of a f-bin in which we calculate the field in full resolution
314 
315  // variables related to the low-res behavior:
316  //
317  int r_spacing = -1;
318  int phi_spacing = -1;
319  int z_spacing = -1; // number of f-bins, in each direction, to gang together to make a single low-resolution bin (l-bin)
320  int nr_low = -1;
321  int nphi_low = -1;
322  int nz_low = -1; // dimensions, in l-bins, of the entire volume
323  int rmin_roi_low = -1;
324  int phimin_roi_low = -1;
325  int zmin_roi_low = -1; // lowest l-bin that is at least partly in our region of interest
326  int rmax_roi_low = -1;
327  int phimax_roi_low = -1;
328  int zmax_roi_low = -1; // excluded upper edge l-bin of our region of interest
329  int nr_roi_low = -1;
330  int nphi_roi_low = -1;
331  int nz_roi_low = -1; // dimensions of our roi in l-bins
332 
333  // 3- and 6-dimensional arrays to handle bin and bin-to-bin data
334  //
335  MultiArray<TVector3> *Efield; // total electric field in each f-bin in the roi for given configuration of charge AND external field.
336  MultiArray<TVector3> *Epartial_highres; // electric field in each f-bin in the roi from charge in a given f-bin or summed bin in the high res region.
337  MultiArray<TVector3> *Epartial_lowres; // electric field in each l-bin in the roi from charge in a given l-bin anywhere in the volume.
338  MultiArray<TVector3> *Epartial; // electric field for the old brute-force model.
339  MultiArray<TVector3> *Epartial_phislice; // electric field in a 2D phi-slice from the full 3D region.
340  MultiArray<TVector3> *Eexternal; // externally applied electric field in each f-bin in the roi
341  MultiArray<TVector3> *Bfield; // magnetic field in each f-bin in the roi
342 
343  ChargeMapReader *q; // //class to read and report charge.
344  // MultiArray<double> *q; //space charge in each f-bin in the whole volume
345  MultiArray<double> *q_local; // temporary holder of space charge in each f-bin and summed bin of the high-res region.
346  MultiArray<double> *q_lowres; // space charge in each l-bin. = sums over sets of f-bins.
347  TH2F *hRdeltaRComponent{nullptr};
348 };