solver="adi" is an implicit time-stepping scheme that can take steps larger
than the usual Courant limit. It is experimental. This page shows when it
helps, what the larger step costs in accuracy, and what it cannot model.
Why it exists
The default solver="yee" is explicit. Its time step is set by the smallest
cell anywhere in the mesh, so one thin layer or narrow gap forces tiny steps on
the whole model. ADI (the Zheng–Chen–Zhang two-sub-step scheme) removes that
stability limit, and adi_cfl_factor sets how many times larger than the Yee
step it goes.
Stability is free; accuracy is not. ADI adds a dispersion error that grows
roughly as the square of the step. adi_cfl_factor is a speed setting, not an
accuracy setting.
Example: a PEC cavity three ways
This resonates an empty 24 × 12 × 36 mm PEC cavity with explicit Yee and with ADI at factors 2 and 5, and compares the TE101 frequency with the closed form:
import numpy as npfrom rfx import GaussianPulse, Simulation
C0 = 299_792_458.0a, b, d = 24e-3, 12e-3, 36e-3f_te101 = C0 / 2 * np.sqrt((1 / a) ** 2 + (1 / d) ** 2)
def cavity(solver, factor=2.0): sim = Simulation(freq_max=12e9, domain=(a, b, d), dx=1.5e-3, boundary="pec", solver=solver, adi_cfl_factor=factor) sim.add_source((0.37 * a, 0.41 * b, 0.20 * d), "ey", waveform=GaussianPulse(f0=f_te101, bandwidth=0.9), amplitude_kind="field") # ADI implements field sources only sim.add_probe((0.63 * a, 0.58 * b, 0.80 * d), "ey") return sim
for label, solver, factor in [("yee", "yee", 1.0), ("adi x2", "adi", 2.0), ("adi x5", "adi", 5.0)]: sim = cavity(solver, factor) dt = sim.run(n_steps=2, skip_preflight=True).dt n_steps = int(6.9e-9 / dt) # the same 6.9 ns record each time result = sim.run(n_steps=n_steps) modes = result.find_resonances(freq_range=(0.7 * f_te101, 1.5 * f_te101)) te101 = min(modes, key=lambda m: abs(m.freq - f_te101)) err = 100 * (te101.freq - f_te101) / f_te101 print(f"{label}: {n_steps} steps, TE101 error {err:+.2f}%")The ADI runs take a half and a fifth of the Yee steps for the same record, and
their TE101 error grows with the factor. The factor-5 run triggers the
adi_3d_accuracy preflight advisory.
Choosing adi_cfl_factor
The committed check holds the 3-D lane at the default factor 2 within 2 % of
the analytic eigenfrequency of an empty PEC cavity
(tests/unit/misc/test_review_tier1_validation_battery.py::test_optc1_adi_3d_cavity_eigenfrequency).
Larger factors are not judged; the error grows with the factor and shrinks with
finer cells.
Use adi_cfl_factor <= 2 when a frequency must be accurate. The default
is 2; a larger factor trades accuracy for larger steps on stiff meshes.
What ADI can model
ADI runs a small subset of rfx:
mode="3d"ormode="2d_tmz", on a uniform mesh;boundary="pec"only. Every absorbing boundary is refused when theSimulationis built, and the default boundary is"cpml", so passboundary="pec"explicitly;- a uniform, non-dispersive dielectric filling the whole domain. A dielectric or conductivity interface is refused;
- soft sources with
amplitude_kind="field"(add_source) and point probes.
It refuses everything else before the first step: interior conductors of any
kind (volumes, sheets, wires), ports, TFSF, waveguide, coaxial and Floquet
ports, lumped RLC elements, dispersive materials, DFT planes, NTFF boxes,
graded meshes and subgridding. run() also refuses until_decay, snapshots,
checkpointing, subpixel smoothing and conformal_pec.
Interior PEC is refused at every factor. A conductor inside the domain
made the ADI fields grow without bound, even at factor 1. Preflight reports
adi_interior_pec_unsupported, and run() and forward() raise even if you
skip preflight. A PEC domain boundary is fine. For a model with metal inside,
use solver="yee".
solver="adi" is differentiable: jax.grad flows through the implicit
solves.
Limits
- Experimental. The 3-D lane is checked against an analytic PEC cavity (within 2 % at factor 2), and the 2-D TMz lane against a cavity resonance at factor 5. Neither contains a conductor or material interface, and ADI refuses both.
- No demonstrated speed-up. The larger step is allowed, but no measured end-to-end speed and accuracy gain on a real stiff mesh has been published. Do not assume ADI is faster for your model.
- Accuracy falls with the factor. Keep
adi_cfl_factor <= 2for frequency-accurate results, or use Yee. - No interior metal, ports or S-parameters. Use
solver="yee"for antennas, circuits and anything you will publish. - Status and scope: see the support matrix.
For a longer walk-through, run examples/tutorials/adi_solver_demo.py from a
source checkout.
