Numerics¶
Grid and Fourier reconstruction¶
Each selected surface is reconstructed on a tensor-product grid
for theta_n = N_\theta and phi_n = N_\phi. One toroidal field period
is covered in \(\phi\).
The primary Fourier reconstruction is
NEO_JAX evaluates these sums in two ways:
vectorizedmode: allocates \(\theta \times \phi \times \text{mode}\) temporaries and is generally fasteststreamedmode: loops over modes withjax.lax.fori_loopand uses less memory
The code also evaluates the derivatives required for the metric:
Derived metric quantities¶
Once the basic Fourier fields are reconstructed, NEO_JAX forms the covariant metric coefficients used by the solver:
The code stores these as gtbtb, gpbpb, and gtbpb. It then forms
In the implementation, these appear as sqrg11, kg, and pard.
Spline representation¶
After Fourier reconstruction, the fields are converted into periodic 2D cubic splines. This is the main interpolation layer used during field-line integration:
b_splfor \(B\)g_splfor \(\sqrt{g^{11}}\)k_splfor \(K_G\)p_splfor \(\partial_\parallel B\)q_splfor the current-related path when needed
This split is important numerically:
the expensive Fourier evaluation is done once per surface
the ODE right-hand side then uses local spline evaluation
the resulting integration cost scales primarily with the line-following work, not with repeated mode summation
Finding \(B_{\min}\) and \(B_{\max}\)¶
The solver starts from the grid extrema of \(B\) and refines them with a Newton solve on the spline representation. Denoting \(f = \partial B/\partial\theta\) and \(g = \partial B/\partial\phi\), the root finder solves
using the local Jacobian of first and second spline derivatives. The resulting
theta_bmin, phi_bmin, theta_bmax, and phi_bmax are then used to
evaluate the refined extrema.
Field-line integration¶
The ODE system is advanced with classical fourth-order Runge-Kutta. For a step size \(h\), the code computes
The actual step size is
so nstep_per is the direct resolution knob per field period.
The integration horizon is controlled by:
nstep_min: minimum number of field periods before convergence is allowednstep_max: hard cap on the number of field periodsacc_req: tolerance used in rational-surface logic and stopping decisions
Rational surfaces and workload control¶
Near rational surfaces, the solver may need to traverse many field periods and many starting angles. The characteristic scaling is
This is the source of the expensive low-|iota| regime. NEO_JAX therefore
adds a preflight estimate before entering the costly correction:
max_rational_field_periodslimits the estimated field-period countrational_surface_policy="error"fails fast with a detailed diagnosticrational_surface_policy="approximate"keeps the base integration result and skips the expensive correction when the estimate is too largemax_rational_field_periods=0requests the full exact long run
The approximate mode is intentionally explicit in the diagnostics and progress output so that downstream studies can decide whether the controlled fallback is acceptable.
JAX implementation strategy¶
The JAX backend leverages three main ideas:
precompute once per surface: Fourier reconstruction and spline coefficients are built before the dominant integration loop
device-resident stepping: the scan backend keeps RK4 staging and trapped-particle bookkeeping inside a compiled JAX loop
batched surface execution:
jax_surface_scan=Trueallows a compiled surface batch when the workflow is compatible with it
The JAX backend is most effective when:
surface counts and grid sizes are reused across calls
diagnostic file output is disabled
the same compiled kernel is reused inside outer loops
Radial coordinates¶
NEO_JAX reports multiple radial coordinates derived from the Boozer flux grid:
s: normalized toroidal flux, defined on the Boozer surfaces ass = (j - 1.5) / (ns_b - 1)for surface indexj(NEO convention).sqrt_s: square root ofs, often used as a proxy for minor radius.r_eff: effective radius computed by integrating the NEO quantitydr/dψacross the flux grid:
This mirrors the reference NEO accumulation in the Fortran code.
Scaling and reported output¶
The internal integrals are converted to the reported output through the chosen reference scaling:
ref_swi = 1: use the inner-grid reference fieldref_swi = 2: use the flux-surface maximum field
This affects the final reported b_ref and the scaling of
\(\epsilon_{\mathrm{eff}}^{3/2}\).