biot_savart
Follow Welling et al. (2020) calculate the magnetic field at Earth’s surface.
Integrate Biot-Savart over:
All currents within the Vlasov domain
Birkeland currents (FACs) in the “gap region” between the MHD inner boundary and the ionosphere, mapped (assuming J propto B) along the field lines connecting ionosphere radius R_IONO to coupling radius r_C
Horizontal Ionospheric currents (altitude 100 km)
The integration is a discrete summation over the 3 domains.
Integrating the domain #2 will likely require this mesh to be ‘refined’ in order to resolve the FAC structures see the functions refine_mesh() and graded_mesh()
This script has been tested with the Vlasiator runs EGL, FHA, FIA note that the usefulness for EGL is limited because there is no ionosphere (domain #3) for that run
To run this script, require access to the data reducer/variable ‘vg_J’ in the .vlsv file This may be supplied by a .vlsv file’s vlsvReader object, see keyword f_J_sidecar
This script is written for the UH environment. Adapt file paths as needed.
###
EXAMPLE CALL (1 thread): python biot_savart.py -nproc 1 -task 1 -run FHA
- Example sidecar .vlsv files, containing ground magnetic field data, can be found at:
- /wrk-vakka/group/spacephysics/vlasiator/3D/{run name}/sidecars/ig_B/ 
- biot_savart.B_ionosphere(f, coord_list=None, ig_r=None, method='integrate')
- Ionospheric (domain #3) current contribution to magnetic field - B_ionosphere() evaluates the magnetic field produced by ionospheric currents - Inputs:
- f: VlsvReader object - keyword coord_list: locations where B-field is calculated - keyword ig_r: the ionospheric mesh - keyword method: - =’integrate’ (default): integrate over the whole ionosphere using Biot-Savart law - =’local’: ionosphere produces magnetic field locally, as by an infinite plane of current overhead 
- Outputs:
- Magnetic field evaluated at coord_list 
 
- biot_savart.B_magnetosphere(f, f_J_sidecar=None, r_C=31855000.0, ig_r=None)
- Inner and outer magnetospheric contributions to Biot-Savart integral (domains #1, #2) wrapper for biot_savart() 
- biot_savart.b_dip(x, y, z, mag_mom_vector=array([0.e+00, 0.e+00, -8.e+22]))
- Inputs: cartesian coordinates x,y,z [m]
- keyword mag_mom_vector: Earth’s vector magnetic dipole moment 
 - Outputs: dipole magnetic field 
- biot_savart.b_dip_direction(x, y, z, mag_mom_vector=array([0.e+00, 0.e+00, -8.e+22]))
- Inputs: cartesian coordinates x,y,z [m]
- keyword mag_mom_vector: Earth’s vector magnetic dipole moment 
 - Outputs: dipole magnetic field unit vector 
- biot_savart.b_dip_magnitude(theta, r, mag_mom=8e+22)
- Inputs: theta: colatitude [radians] r: radial distance [m] keyword mag_mom: magnetic dipole moment, default=8e22 [A / m^2], as in EGI, EGL, FIA, FHA runs - Outputs: Earth’s magnetic field magnitude [Tesla] 
- biot_savart.biot_savart(coord_list, f, f_J_sidecar=None, r_C=31855000.0, mesh='graded')
- param coord_list: a list of 3-element arrays of coordinates [ [x1,y1,z1], [x2,y2,z2], … ], SI units
- if considering just a single starting point, the code accepts a 3-element array-like object [x1,y1,z1] 
 - f: vlsvReader object f_J_sidecar: vlsvReader object that contains pre-computed current ‘vg_J’ - e.g., for EGL, files at: /wrk-vakka/group/spacephysics/vlasiator/3D/EGL/visualizations_2/ballooning/*.vlsv - runtime (FHA): overhead of about 200 sec (setup), plus 0.2 sec for each element of coord_list - returns a tuple (B_inner, B_outer) B_inner: the B-field [T] generated by FACs at 1 R_E < r< r_C B_outer: the B-field [T] generated by currents in simulation domain at r > r_C 
- biot_savart.cartesian_to_spherical(x, y, z)
- r > 0 0 < theta < pi -pi < phi < pi all are assumed to be numpy arrays of equal dimensions - returns: r, theta, phi [tuple] 
- biot_savart.fac_map(f, vg_x, vg_y, vg_z, dx, f_J_sidecar=None, r_C=31855000.0, mag_mom_vector=array([0.e+00, 0.e+00, -8.e+22]))
- Map the FACs along magnetic field lines (J propto B). - Inputs:
- f: VlsvReader object f_J_sidecar: vlsvReader object that contains pre-computed current ‘vg_J’ - if f_J_sidecar = None:
- here is assumed the data reducer ‘ig_fac’ exists (such as for runs FHA and FIA) In this case, the currents in the FAC region (domain #2) will be mapped UP from the ionosphere ‘ig_’ grid 
- otherwise (f_J_sidecar = a *.vlsv string, for a file containing the current density J in the vlasov ‘vg_’ grid)
- for run EGL, see files at /wrk-vakka/group/spacephysics/vlasiator/3D/EGL/visualizations_2/ballooning/*.vlsv In this case, the currents in the FAC region (domain #2) will be mapped DOWN from the vg_ grid 
 - vg_x,vg_y,vg_z position [m], 1D numpy arrays.
- note: these coordinates do not have to correspond with Vlasiator’s vg_ grid, This is relevant when fac_map() is called by biot_savart(), with keyword mesh=’refined’ or mesh=’graded’ 
 - dx is grid resolution [m], 1D numpy array, This is for the input cells which can be defined arbitrarily—not necessarily same as vg cells. 
 - * coordinates, not just coordinates on the vg_ grid * - Returns:
- the vector current density [A/m^2] at specified positions vg_x, vg_y, vg_z position output J=0 for cells that fall outside the FAC region (i.e if cell is not in region R_EARTH+dx/2 < r< r_C) 
 
- biot_savart.graded_mesh(x, y, z, dV, ns=array([8, 4, 2]), Rs=array([6371000., 12742000., 25484000.]))
- Iteratively refine the mesh in ‘inner’ FAC region R_IONO < r < r_C, used to calculate FAC contribution to Biot-Savart integral - Calls refine mesh with different refinement factors n, at specified refinement boundaries ns: numpy array of refinement factors (ints) Rs: numpy array of refinement boundary radii [R_E] edge case: arrays are aligned so that for r>Rs[-1], use ns[-1] refinement - Want the refinement level to roughly scale as r^{-3/2}. To resolve the mapped features at all radii This works because magnetic dipole field goes as 1/r^3, roughly, and area A goes as r^2. (Need to set areas of the cell faces so B*A~constant, to resolve features mapped along field lines) - Example: graded_mesh(x, y, z, dV, ns = np.array([8, 4, 2]), Rs = np.array([R_EARTH, R_EARTH*2, R_EARTH*4]))
- –> refines 1D mesh size by factor of 8 for 1 RE<r<=2 RE, by factor of 4 for 2 RE<r<=4 RE, by factor of 2 for r>4 RE 
 
- biot_savart.integrate_biot_savart(coord_list, x, y, z, J, delta)
- integration of the Biot-savart law magnetic field is evaluated at coordinates specified in coord_list (for example, the ionospheric coordinates) - Inputs:
- x,y,z (1D array, size n): Cartesian coordinates delta (1D array, size n): the volume or area of the element being integrated J (2D array, size [3, n]): current density - all units SI 
- Outputs:
- magnetic field evaluated at coord_list 
 - Note: the units of J and delta depend on the type of integral (volume or surface), but the equation form is unchanged - Biot-Savart (volume): B = (mu_0 / 4 * pi) int { J x r’ / |r’|^3 } dV ([J] = A/m^2, delta == dV)
- (surface): B = (mu_0 / 4 * pi) int { J x r’ / |r’|^3 } dA ([J] = A/m, delta = dS) 
 
- biot_savart.mkdir_path(path)
- Make a directory from the stem of an input file name (path) 
- biot_savart.nearest_node_index(f, x, y, z, node_coords_iono=None)
- helper function for finding nearest ionospheric node 
- biot_savart.refine_mesh(x, y, z, dV, n)
- refine the mesh in ‘inner’ FAC region R_IONO < r < r_C, used to calculate FAC contribution to Biot-Savart integral - x, y, z: initial coordinates (1D numpy float arrays), assumed to be at the center of cubic cell dV: cell volume 1D array or scalar value dx_0: side length of initial mesh (1D numpy array or single scalar value) n (int): the factor by which to refine the mesh 
- biot_savart.save_B_vlsv(input_tuple)
- calculate magnetic field at the Earth’s surface and save in a .vslv file - Inputs: input tuple
- input_tuple[0]: run (string) # ‘EGL’, ‘FHA’, or ‘FIA’ input_tuple[1]: fileIndex (int) 
- Outputs:
- ig_r: Cartesian ionospheric grid locations (radius R_EARTH + 100km)
- note that B_iono, B_inner, B_outer are in fact evaluated at radius R_EARTH ig_r is a copy of the Vlasiator ionosphere mesh, to enable combination with other data reducers 
 - B_iono: Ionospheric (Domain #3) contribution to ground magnetic field (radius R_EARTH) B_inner: Ionospheric (Domain #2) contribution to ground magnetic field (radius R_EARTH) B_outer: Ionospheric (Domain #1) contribution to ground magnetic field (radius R_EARTH) 
 - Note: the input and output .vlsv file paths may need to be modified in this script for different users 
- biot_savart.spherical_to_cartesian(r, theta, phi)
- r > 0 0 < theta < pi -pi < phi < pi all are assumed to be numpy arrays of equal dimensions - returns: x, y, z [tuple] 
- biot_savart.vec_len_2d(arr_2d)
- Vector length 
- biot_savart.vec_unit(arr_2d)
- assume arr_2d is a numpy array with shape [N, 3]. Return unit vectors with same shape