Skip to content

Field Interpolation

A robust field interpolation is the prerequisite for pushing particles. This example demonstrates the construction of scalar/vector field interpolators for Cartesian/Spherical grids. If the field is analytic, you can directly pass the generated function to prepare.

julia
import TestParticle as TP
using StaticArrays

function setup_spherical_field()
   r = logrange(0.1, 10.0, length = 16)
   r_uniform = range(0.1, 10.0, length = 16)
   θ = range(0, π, length = 16)
   ϕ = range(0, , length = 16)

   B₀ = 1e-8 # [nT]
   B = zeros(3, length(r), length(θ), length(ϕ)) # vector
   A = zeros(length(r), length(θ), length(ϕ)) # scalar

   for (iθ, θ_val) in enumerate(θ)
      sinθ, cosθ = sincos(θ_val)
      B[1, :, iθ, :] .= B₀ * cosθ
      B[2, :, iθ, :] .= -B₀ * sinθ
      A[:, iθ, :] .= B₀ * sinθ
   end

   B_field_nu = TP.getinterp(TP.SphericalNonUniformR(), B, r, θ, ϕ)
   A_field_nu = TP.getinterp_scalar(TP.SphericalNonUniformR(), A, r, θ, ϕ)
   B_field = TP.getinterp(TP.Spherical(), B, r_uniform, θ, ϕ)
   A_field = TP.getinterp_scalar(TP.Spherical(), A, r_uniform, θ, ϕ)

   return B_field_nu, A_field_nu, B_field, A_field
end

function setup_cartesian_field()
   x = range(-10, 10, length = 16)
   y = range(-10, 10, length = 16)
   z = range(-10, 10, length = 16)
   B = zeros(3, length(x), length(y), length(z)) # vector
   B[3, :, :, :] .= 10e-9
   A = zeros(length(x), length(y), length(z)) # scalar
   A[:, :, :] .= 10e-9

   B_field = TP.getinterp(B, x, y, z)
   A_field = TP.getinterp_scalar(A, x, y, z)

   return B_field, A_field
end

B_sph_nu, A_sph_nu, B_sph, A_sph = setup_spherical_field()
B_car, A_car = setup_cartesian_field();

Gridded spherical interpolation:

julia
loc = SA[1.0, 1.0, 1.0];

@time B_sph_nu(loc); # precompilation
@time B_sph_nu(loc);
@time A_sph_nu(loc); # precompilation
@time A_sph_nu(loc);
  0.045479 seconds (44.77 k allocations: 1.840 MiB, 99.95% compilation time)
  0.000011 seconds (1 allocation: 32 bytes)
  0.108227 seconds (381.23 k allocations: 17.740 MiB, 99.98% compilation time)
  0.000008 seconds (1 allocation: 16 bytes)

Uniform spherical interpolation:

julia
@time B_sph(loc); # precompilation
@time B_sph(loc);
@time A_sph(loc); # precompilation
@time A_sph(loc);
  0.097449 seconds (395.09 k allocations: 18.077 MiB, 99.98% compilation time)
  0.000009 seconds (3 allocations: 80 bytes)
  0.055758 seconds (265.50 k allocations: 12.266 MiB, 99.96% compilation time)
  0.000007 seconds (1 allocation: 16 bytes)

Uniform Cartesian interpolation:

julia
@time B_car(loc); # precompilation
@time B_car(loc);
@time A_car(loc); # precompilation
@time A_car(loc);
  0.000014 seconds (5 allocations: 224 bytes)
  0.000004 seconds (1 allocation: 32 bytes)
  0.047614 seconds (186.60 k allocations: 8.481 MiB, 99.96% compilation time)
  0.000004 seconds (1 allocation: 16 bytes)

Based on the benchmarks, for the same grid size, gridded interpolation (SphericalNonuniformR()) is 2x slower than uniform mesh interpolation (Spherical(), Cartesian()).