Quickstart

Install directly from PyPI:

pip install vmec-jax

Run the bundled CLI test

The fastest first check after a PyPI install is:

vmec --test

This does not require a source checkout. It copies the packaged input.nfp4_QH_warm_start into vmec_jax_test/, runs the fixed-boundary solver with FTOL_ARRAY = 1e-12 for a faster first check, writes wout_nfp4_QH_warm_start.nc, plots the WOUT file into vmec_jax_test/figures/, and prints the equivalent manual commands.

CLI (VMEC2000-style executable)

Once installed (or when working from the repo), you can run vmec like the VMEC2000 executable by pointing it to a single input.* file:

vmec examples/data/input.circular_tokamak

Sanity check (verifies the console script is wired to the right interpreter):

vmec --help

The vmec_jax, vmec-jax, and xvmec_jax command names remain aliases for compatibility. If no console command is found or a command raises ModuleNotFoundError, install and run via the module entrypoint:

python -m pip install -e .
python -m vmec_jax examples/data/input.circular_tokamak

This writes wout_circular_tokamak.nc next to the input file and prints the VMEC2000-style per-iteration screen output by default. Use --quiet to silence the iteration table, and --outdir or --output to control where the wout_*.nc file is written. If you only want a short debug run, pass --max-iter and --no-multigrid (single grid).

Boozer-coordinate CLI workflow

The plain vmec-jax install includes booz_xform_jax. Use vmec --booz to run a Boozer transform after a VMEC solve, or directly from an existing wout_*.nc file. The default transform resolution is mbooz = 32, nbooz = 32, with all VMEC surfaces included:

vmec --booz input.nfp4_QH_warm_start
vmec --booz --plot input.nfp4_QH_warm_start
vmec --booz wout_nfp4_QH_warm_start.nc
vmec --plot boozmn_nfp4_QH_warm_start.nc

--booz --plot writes the usual wout_*.nc, runs booz_xform_jax, writes boozmn_*.nc, and then creates:

  • mid-radius and LCFS |B| contour-line plots in Boozer coordinates,

  • radial Boozer |B| spectra grouped into QA/axisymmetric, QH, mirror, and non-symmetric mode families,

  • an LCFS Fourier spectrum for the largest Boozer modes.

Override the transform resolution or selected surfaces from the CLI:

vmec --booz wout_nfp4_QH_warm_start.nc --mbooz 48 --nbooz 48
vmec --booz wout_nfp4_QH_warm_start.nc --booz-surfaces "0.25,0.5,1.0"

Input decks can carry Boozer defaults in a separate namelist. LBOOZ = F is the safe default used by the example inputs; passing --booz overrides it:

&BOOZ_XFORM_JAX
  LBOOZ = F
  MBOOZ = 32
  NBOOZ = 32
  BOOZ_SURFACES = 'all'
/

vmec_jax writes diagnostic wout files from the last available state even when the requested residual tolerance is not reached. These files preserve the computed geometry, profiles, field diagnostics, and residual traces, and mark the solver status with ier_flag plus vmec_jax_converged__logical__ and vmec_jax_status. Treat vmec_jax_status = nonconverged as a diagnostic checkpoint rather than a validated equilibrium.

Load, save, and inspect a wout file

The wout_*.nc file is the standard VMEC output container. Use vmec_jax.wout.read_wout and vmec_jax.wout.write_wout when you want to inspect or round-trip these files directly:

import numpy as np

import vmec_jax as vj
from vmec_jax.wout import read_wout, write_wout

wout = read_wout("wout_nfp4_QH_warm_start.nc")
write_wout("wout_nfp4_QH_warm_start_copy.nc", wout, overwrite=True)

s = np.linspace(0.0, 1.0, int(wout.ns))
print("aspect =", float(wout.aspect))
print("mean edge iota =", float(wout.iotaf[-1]))

for js, (sj, iota_j) in enumerate(zip(s, wout.iotaf)):
    _theta, _zeta, bmag = vj.vmecplot2_bmag_grid(wout, s_index=js)
    print(f"s={sj:.3f}  iota={float(iota_j): .6e}  <|B|>={float(np.mean(bmag)): .6e}")

The complete runnable example is:

python examples/diagnostics/load_save_wout_profiles.py

It creates a wout from examples/data/input.nfp4_QH_warm_start if one does not already exist, saves a round-trip copy, then prints scalar diagnostics, the iota profile, and simple surface-averaged |B| values.

Spline pressure, iota, and current profiles

VMEC input decks can prescribe profiles as polynomial coefficients or as tabulated spline knots. vmec_jax supports the common VMEC forms:

  • PMASS_TYPE = "power_series" with AM coefficients, or PMASS_TYPE = "cubic_spline", "akima_spline", or "line_segment" with AM_AUX_S and AM_AUX_F.

  • PIOTA_TYPE = "power_series" with AI coefficients, or PIOTA_TYPE = "cubic_spline", "akima_spline", or "line_segment" with AI_AUX_S and AI_AUX_F when NCURR = 0.

  • PCURR_TYPE = "power_series" with AC coefficients for \(I'(s)\), PCURR_TYPE = "power_series_i" with AC coefficients for \(I(s)\), or PCURR_TYPE = "cubic_spline_ip" / "cubic_spline_i" (and matching akima_spline or line_segment forms) with AC_AUX_S and AC_AUX_F when NCURR = 1.

The *_AUX_S arrays are knot locations in normalized toroidal flux \(s \in [0,1]\); the matching *_AUX_F arrays are profile values at those knots. A compact pressure/iota spline example is included:

vmec examples/data/input.profile_splines --plot

Generate editable polynomial and spline pressure/current decks side by side with:

python examples/profile_input_examples.py
vmec examples/outputs/profile_inputs/input.profile_polynomial_pressure_current
vmec examples/outputs/profile_inputs/input.profile_spline_pressure_current

For a finite-beta current-spline example, use:

vmec examples/data/input.nfp4_QH_finite_beta

Free-boundary CLI smoke test

For a small bundled free-boundary case, run:

vmec examples/data/input.cth_like_free_bdy_lasym_small

This input references the tracked examples/data/mgrid_cth_like_lasym_small.nc fixture, so it works in a fresh clone without downloading the large asset bundle. The resulting wout_cth_like_free_bdy_lasym_small.nc can be plotted with:

vmec --plot examples/data/wout_cth_like_free_bdy_lasym_small.nc

For ESSOS/direct-coil finite-beta scans and coil-only free-boundary examples, see Free-Boundary Coil Optimization.

If you want to compare the conservative parity track against the optimized fixed-boundary CLI-style controller from Python, run:

python examples/fixed_boundary_driver_tracks.py \
  examples/data/input.circular_tokamak \
  --quiet --json

That example writes two wout files (parity and optimized) unless you pass --no-write-wout, and it prints a short runtime / fsq_total comparison table at the end.

Kernel parity on reference states (solver-free)

To validate intermediate pipeline quantities on reference wout states (no nonlinear solve), run:

python tools/diagnostics/pipeline_parity_summary.py

By default this covers the 4-axisymmetric benchmark suite (circular_tokamak, purely_toroidal_field, shaped_tokamak_pressure, solovev).

Scalar residual parity (fsqr/fsqz/fsql) on reference states

To compare scalar residuals reconstructed from a reference state against wout.fsqr/fsqz/fsql:

python tools/diagnostics/getfsq_parity_cases.py --solve-metric

End-to-end solve snapshot

To run a short fixed-boundary solve and compare a few end-to-end outputs against released references, fetch the optional WOUT fixtures first:

python tools/fetch_assets.py --bundle wout-fixtures

python tools/diagnostics/end_to_end_solve_parity_summary.py --use-input-niter --fast

Drop --fast and increase --max-iter for a full parity snapshot (longer runtime).

External VMEC2000 run (optional)

If you have the VMEC2000 Python extension installed (vmec + mpi4py + netCDF4), you can run VMEC2000 on an input and compare outputs to released references:

python tools/diagnostics/external_vmec_driver_compare.py --case circular_tokamak

Simple optimization example

For a VMEC-JAX-only optimization workflow with explicit SIMSOPT-style objective construction, run:

PYTHONPATH=. JAX_PLATFORMS=cpu python examples/optimization/QH_optimization.py

The script builds a FixedBoundaryVMEC object, constructs objective tuples such as aspect ratio, iota floor, and quasisymmetry residuals, runs least_squares_solve, then shows how to save and plot the resulting equilibrium. The companion examples/optimization/README.md file lists the recommended standalone examples, sweep/rendering tools, and older comparison scripts.