Off-Surface Evaluation
This section describes the off-surface evaluation paths for B and
GradB in virtual_casing_jax, including the adaptive refinement
logic and validation strategy. The implementation mirrors the reference
virtual-casing/BIEST flow and is designed to be both accurate and
efficient for small to moderate target sets.
Equations
Let \Gamma be the surface with outward normal n. Define the
surface densities:
For off-surface targets x, the jump term is absent. The external and
internal fields are
which matches the reference BIEST implementation [MCO2019] and
virtual-casing C++ API.
The off-surface gradient is
and \nabla \mathbf{B}_{\mathrm{int}} = - \nabla \mathbf{B}_{\mathrm{ext}}.
Algorithm
Off-surface evaluation is performed in two stages:
Base resampling: the surface and field are resampled to a quadrature grid that is at least the maximum of:
NFP * src_nt(toroidal modes from the source field)surface resolution from
setupa minimum patch size (
13x13) to match the BIEST off-surface singular-correction requirements.
Evaluation:
ComputeBOffSurfuses a combination ofLaplaceFxdUandBiotSavartFxU.ComputeGradBOffSurfusesLaplaceFxd2U(second derivatives) for both\mathbf{K}and\sigmaand assembles the curl term.
Adaptive Refinement
The off-surface field evaluator supports adaptive refinement, matching the strategy in BIEST:
Evaluate the Laplace double-layer
DxUon the target set using a constant density.Define an error metric:
\[\epsilon = \max_i \min(|1-U_i|, |U_i|),\]where
U_iis the double-layer potential at targeti.Refine the source grid by doubling
(Nt, Np)until\epsilon \le 10^{-digits}or the optionalmax_Nt/max_Npcaps are reached.
This logic is implemented in
virtual_casing_jax.integrals.computeB_offsurface_adaptive and
_offsurface_adapt_grid, mirroring
ExtVacuumField::EvalOffSurface in the C++ code.
JIT-Friendly Schedule
The Python adaptive loop changes grid sizes dynamically, which is not compatible with JIT compilation. For JIT-friendly workflows, a fixed refinement schedule can be provided:
computeB_offsurface_adaptive_schedule and
computeGradB_offsurface_adaptive_schedule accept a static tuple of
(Nt, Np) pairs (e.g. ((24, 24), (48, 48), (96, 96))). The
implementation evaluates each level and updates the result only when
the double-layer error is above the tolerance. This preserves the adaptive
decision while keeping the shapes static, so the function is JIT-safe.
High-level wrappers are exposed as:
VirtualCasingJAX.compute_external_B_offsurf_scheduleVirtualCasingJAX.compute_internal_B_offsurf_scheduleVirtualCasingJAX.compute_external_gradB_offsurf_scheduleVirtualCasingJAX.compute_internal_gradB_offsurf_schedule
These wrappers reuse the same density construction as the base off-surface
path, and support JIT when levels is passed as a static argument.
Off-Surface GradB (Base vs Adaptive)
The reference C++ code evaluates off-surface GradB on the base grid (no adaptive refinement). The default JAX path follows this behavior to maintain parity with the C++ dumps.
An optional adaptive GradB path is available via
adaptive=True in compute_external_gradB_offsurf. This uses the
same adaptive grid selection as the off-surface field evaluator, and is
validated against a finite-difference gradient of
compute_external_B_offsurf.
Validation
Off-surface validation includes:
Parity tests against the C++ dumps for: -
ComputeBOffSurf(external/internal) -ComputeGradBOffSurf(external)A finite-difference test comparing adaptive GradB against the gradient of
compute_external_B_offsurf.
See the tests:
tests/test_virtual_casing_offsurf_parity.pytests/test_virtual_casing_gradb_offsurf_fd.py
Performance Notes
The direct quadrature path is memory-intensive; use
chunk_sizeto control memory.Adaptive refinement can upsample aggressively for small surfaces; use
max_Ntandmax_Npto cap grid sizes if needed.Off-surface GradB is more expensive than off-surface B because it evaluates second-derivative kernels.
Implementation Mapping
JAX entry points and their reference equivalents:
VirtualCasingJAX.compute_external_B_offsurf→VirtualCasing::ComputeBextOffSurf(C++)VirtualCasingJAX.compute_internal_B_offsurf→VirtualCasing::ComputeBintOffSurf(C++)VirtualCasingJAX.compute_external_gradB_offsurf→VirtualCasing::ComputeGradBOffSurf(C++ local parity extension)
All kernel normalizations and sign conventions follow BIEST [BIEST] and the formulas in [MCO2019].