Back to home page

sPhenix code displayed by LXR

 
 

    


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   };  // 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.
0027   enum LookupCase
0028   {
0029     Full3D,
0030     HybridRes,
0031     PhiSlice,
0032     Analytic,
0033     NoLookup
0034   };
0035   // Full3D = uses (nr x nphi x nz)^2 lookup table
0036   // 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
0037   // PhiSlice = uses (nr x 1 x nz) x (nr x nphi x nz) lookup table exploiting phi symmetry.
0038   // Analytic = doesn't use lookup tables -- no memory footprint, uses analytic E field at center of each bin.
0039   //     Note that this is not the same as analytic propagation, which checks the analytic field integrals in each step.
0040   // NoLookup = Don't build any structures -- effectively ignores any calculated spacecharge field
0041   enum ChargeCase
0042   {
0043     FromFile,
0044     AnalyticSpacecharge,
0045     NoSpacecharge
0046   };  // load from file, load from AnalyticFieldModel, or set to zero.
0047   // note that if we set to Zero, we skip the lookup step.
0048 
0049   // constructors with history for backwards compatibility
0050   AnnularFieldSim(float rmin, float rmax, float dz, int r, int phi, int z, float vdr);  // abbr. constructor with roi=full region
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   //! delete copy ctor and assignment opertor (cppcheck)
0067   explicit AnnularFieldSim(const AnnularFieldSim &) = delete;
0068   AnnularFieldSim &operator=(const AnnularFieldSim &) = delete;
0069 
0070   // debug functions:
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   // getters for internal states:
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   // file-writing functions for complex mapping questions:
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   };  // get an already-existing rossegger table instead of loading it ourselves.
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   };  // get an already-existing rossegger table instead of loading it ourselves.
0172   void set_twin(AnnularFieldSim *sim)
0173   {
0174     twin = sim;
0175     hasTwin = true;
0176     return;
0177   };  // 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.
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);         // puts phi in 0<phi<2pi
0186   int FilterPhiIndex(int phi, int range);  // puts phi in bin range 0<phi<range.  defaults to using nphi for 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   // now handled by setting 'analytic' lookup:  void populate_analytic_fieldmap();
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;   // stand-alone class to compute greens functions.
0205   float green_shift;  // how far to offset our position in z when querying our green's functions.
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   };  // various constants to match internal representation to the familiar formula.  Adding in these factors suggests I should switch to a unitful calculation throughout...
0233   // units:
0234   const float cm = 1;        // centimeters -- if you change this, check that all the loading functions are properly agnostic.
0235   const float m = 100 * cm;  // meters.
0236   const float mm = cm / 10;
0237   const float um = mm / 1e3;
0238 
0239   const float C = 1;  // Coulombs
0240   const float nC = C / 1e9;
0241   const float fC = C / 1e15;
0242 
0243   const float s = 1;  // seconds
0244   const float us = s / 1e6;
0245   const float ns = s / 1e9;
0246 
0247   const float V = 1;  // volts
0248 
0249   const float Tesla = V * s / m / m;  // Tesla=Vs/m^2
0250   const float kGauss = Tesla / 10;    // kGauss
0251 
0252   const float eps0 = 8.854e-12 * (C / V) / m;    // Farads(=Coulombs/Volts) per meter
0253   const float epsinv = 1 / eps0;                 // Vcm/C
0254   const float k_perm = 1 / (4 * 3.1416 * eps0);  // implied units of V*cm/C because we're doing unitful work here.
0255   // debug items
0256   // bool
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   // the other half of the detector:
0266 
0267   // constants of motion, dimensions, etc:
0268   //
0269   TVector3 zero_vector;  // a shorthand way to return a vectorial zero.
0270   // 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.
0271   // 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
0272 
0273   // gas constants:
0274   double vdrift = NAN;  // gas drift speed in cm/s
0275   double langevin_T1 = NAN;
0276   double langevin_T2 = NAN;       // gas tensor drift terms.
0277   double omegatau_nominal = NAN;  // nominal omegatau value, derived from vdrift and field strengths.
0278   // double vprime; //first derivative of drift velocity at specific E
0279   // double vprime2; //second derivative of drift velocity at specific E
0280 
0281   // field constants:
0282   std::string fieldstring;
0283   std::string Bfieldname;
0284   std::string Efieldname;
0285   //  char fieldstring[300],Bfieldname[100],Efieldname[100];
0286   std::string chargesourcename;
0287   std::string chargestring;
0288   float Enominal = NAN;  // magnitude of the nominal field on which drift speed is based, in V/cm.
0289   float Bnominal;        // magnitude of the nominal magnetic field on which drift speed is based, in Tesla.
0290 
0291   // physical dimensions
0292   float phispan;     // angular span of the area in the phi direction, since TVector3 is too smart.
0293   float rmin, rmax;  // inner and outer radii of the annulus
0294   float zmin, zmax;  // lower and upper edges of the coordinate system in z (not fully implemented yet)
0295   // float phimin, phimax;//not implemented at all yet.
0296   TVector3 dim;  // dimensions of simulated region, in cm
0297 
0298   // variables related to the whole-volume tiling:
0299   //
0300   int nr, nphi, nz;       // number of fundamental bins (f-bins) in each direction = dimensions of 3D array covering entire volume
0301   TVector3 step;          // size of an f-bin in each direction
0302   LookupCase lookupCase;  // which lookup system to instantiate and use.
0303   ChargeCase chargeCase;  // which charge model to use
0304   int truncation_length;  // distance in cells (full 3D metric in units of bins)
0305 
0306   // variables related to the region of interest:
0307   //
0308   int rmin_roi, phimin_roi, zmin_roi;  // lower edge of our region of interest, measured in f-bins
0309   int rmax_roi, phimax_roi, zmax_roi;  // excluded upper edge of our region of interest, measured in f-bins
0310   int nr_roi, nphi_roi, nz_roi;        // dimensions of our roi in f-bins
0311 
0312   // variables related to the high-res behavior:
0313   //
0314   int nr_high = -1;
0315   int nphi_high = -1;
0316   int nz_high = -1;  // dimensions, in f-bins of neighborhood of a f-bin in which we calculate the field in full resolution
0317 
0318   // variables related to the low-res behavior:
0319   //
0320   int r_spacing = -1;
0321   int phi_spacing = -1;
0322   int z_spacing = -1;  // number of f-bins, in each direction, to gang together to make a single low-resolution bin (l-bin)
0323   int nr_low = -1;
0324   int nphi_low = -1;
0325   int nz_low = -1;  // dimensions, in l-bins, of the entire volume
0326   int rmin_roi_low = -1;
0327   int phimin_roi_low = -1;
0328   int zmin_roi_low = -1;  // lowest l-bin that is at least partly in our region of interest
0329   int rmax_roi_low = -1;
0330   int phimax_roi_low = -1;
0331   int zmax_roi_low = -1;  // excluded upper edge l-bin of our region of interest
0332   int nr_roi_low = -1;
0333   int nphi_roi_low = -1;
0334   int nz_roi_low = -1;  // dimensions of our roi in l-bins
0335 
0336   // 3- and 6-dimensional arrays to handle bin and bin-to-bin data
0337   //
0338   MultiArray<TVector3> *Efield;             // total electric field in each f-bin in the roi for given configuration of charge AND external field.
0339   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.
0340   MultiArray<TVector3> *Epartial_lowres;    // electric field in each l-bin in the roi from charge in a given l-bin anywhere in the volume.
0341   MultiArray<TVector3> *Epartial;           // electric field for the old brute-force model.
0342   MultiArray<TVector3> *Epartial_phislice;  // electric field in a 2D phi-slice from the full 3D region.
0343   MultiArray<TVector3> *Eexternal;          // externally applied electric field in each f-bin in the roi
0344   MultiArray<TVector3> *Bfield;             // magnetic field in each f-bin in the roi
0345 
0346   ChargeMapReader *q;            // //class to read and report charge.
0347                                  //  MultiArray<double> *q;                    //space charge in each f-bin in the whole volume
0348   MultiArray<double> *q_local;   // temporary holder of space charge in each f-bin and summed bin of the high-res region.
0349   MultiArray<double> *q_lowres;  // space charge in each l-bin. = sums over sets of f-bins.
0350   TH2 *hRdeltaRComponent{nullptr};
0351 };