Skip to main content

VMEX

PyPI version Python License CI Coverage Docs

VMEX computes stellarator and tokamak ideal-MHD equilibria in JAX. It reads VMEC input files, solves fixed- and free-boundary problems, and writes standard wout_*.nc files. Implicit derivatives connect equilibria to boundary, profile, and coil optimization.

  • Use existing workflows: VMEC input/output, multigrid continuation and hot restart.
  • Design with gradients: SciPy or JAX optimizers, scalar adjoints and residual Jacobians.
  • Inspect the physics: Boozer transforms, magnetic fields and spatial derivatives, quasisymmetry, quasi-isodynamicity and stability diagnostics.
  • Choose the hardware: CPU or GPU equilibrium solves (optimization gradients default to CPU), reusable compilation and independent-case ensembles.
  • Connect coils: ESSOS fields, NESTOR free boundary and finite-beta exterior fields.

VMEX equilibria and diagnostics

The capability reference defines supported models and validation limits. VMEX's toroidal equilibrium model assumes nested flux surfaces; mirror and high-order polishing features have narrower validation scopes.

Install

pip install vmex
vmex --doctor
vmex --test

Python 3.11–3.12 is tested. CPU JAX is included; for GPUs follow the JAX installation guide and VMEX GPU guide. Optional extras include vmex[coils] (ESSOS), vmex[freeb] (virtual casing), vmex[neoclassical] (effective ripple), and vmex[optimizers] (JAXopt/Optax). See installation for dependencies.

Solve, plot and restart

With your own VMEC input file:

vmex input.my_case --plot
vmex --plot wout_my_case.nc
vmex --booz wout_my_case.nc
vmex input.nearby --restart wout_my_case.nc

--plot writes six PNGs beside the input or in --outdir: the summary below, flux-surface cross-sections, |B| in VMEC angles, radial profiles, Mercier stability and the 3-D LCFS. The summary adds Boozer |B|, a J map, D_R and the DESC-normalized force balance (effective ripple needs vmex[neoclassical]). The QA and QI panels are vmex examples/data/input.nfp2_QA_finite_beta --plot and vmex examples/data/input.nfp4_QI_finite_beta --plot.

vmex --plot summary of the bundled finite-beta NFP=2 QA equilibrium vmex --plot summary of the bundled finite-beta NFP=4 QI equilibrium

VMEX follows the deck's NS_ARRAY, FTOL_ARRAY and NITER_ARRAY. In Python:

import vmex as vj

inp = vj.VmecInput.from_file("input.my_case")
result = vj.solve_multigrid(inp, verbose=True)
print(result.converged, result.fsqr, result.fsqz, result.fsql)
wout = vj.wout_from_state(
    inp=inp, state=result.state, fsqr=result.fsqr, fsqz=result.fsqz,
    fsql=result.fsql, niter=result.iterations, converged=result.converged)
vj.write_wout("wout_my_case.nc", wout)

Pass initial_state=result.state for a nearby Python solve, or restart_from= for a saved WOUT. Restart and CLI guides cover resolution changes, devices, profiles and output controls.

vmex equilibrium.h5 reads DESC text inputs and HDF5/pickle outputs without installing DESC, using the final stage or equilibrium; it writes input.equilibrium and solves it to write wout_equilibrium.nc. --desc-tol 0 retains all boundary modes. The default 1% boundary tolerance does not guarantee magnetic-field accuracy. WOUT iota has the opposite sign to DESC.

Differentiate and optimize

Compute a boundary/profile derivative without differentiating through every forward iteration:

import jax
from vmex.core import implicit

params = implicit.params_from_input(inp)
gradient = jax.grad(lambda p: implicit.run(inp, p).aspect)(params)

For a simple boundary optimization, supply objectives and let SciPy choose the steps. Each tuple is (function, target, cost_weight):

from scipy.optimize import least_squares
from vmex import optimize as opt

problem = opt.VmecProblem.from_tuples(
    inp, [(opt.aspect_ratio, 4.0, 1.0)], max_mode=1, use_ess=True)
fit = least_squares(
    problem.residual, problem.x0, jac=problem.residual_jac,
    x_scale=problem.scales, max_nfev=20)
problem.input_from_x(fit.x).to_indata("input.optimized")
equilibrium = problem.equilibrium_from_x(fit.x)
vj.write_wout("wout_optimized.nc", equilibrium.wout)

problem.value_and_grad supplies scalar objectives to BFGS/L-BFGS-B; problem.jax_value_and_grad supports JAX optimizers. problem.evaluate(x) reports solve effort and derivative status. Implicit derivatives describe the chosen discrete equilibrium equations: small linear residuals alone do not establish continuum accuracy. See the gradient tutorial and optimization guide for convergence checks, constraints, scaling and finite-difference verification.

What you can build

Every figure below is regenerated by the script named beside it, from decks in this repository.

Quasisymmetric and quasi-isodynamic boundaries

QA at nfp 2, QH at nfp 4 and QP at nfp 2

Boundary optimization for quasi-axisymmetry, quasi-helical symmetry and quasi-poloidal symmetry, each at its own field-period count, from examples/optimization/QA_optimization.py and its QH and QP siblings. python examples/plot_optimized_families.py draws the panel.

QI at nfp 1, 2, 3 and 4

Quasi-isodynamic designs across four field-period counts, showing how the |B| contours close poloidally as nfp rises. The QI scripts in examples/optimization/ cover vacuum, finite beta, bootstrap-consistent and maximum-J continuation variants, and the same families have scalar-adjoint, SciPy, JAXopt and Optax drivers.

Free boundary with coils

Free-boundary beta ramp and Shafranov shift

NESTOR free boundary driven by ESSOS coils, ramping beta and tracking the Shafranov shift: python examples/free_boundary_essos_coils.py. Free-boundary runs also accept an MGRID table, and VmecExtender evaluates the exterior field with the plasma's own virtual-casing contribution, within the distance limits below.

Single-stage plasma and coil design

examples/optimization/single_stage_optimization.py adjusts the plasma boundary and the coils against one weighted objective, solving the equilibrium implicitly at every step; single_stage_free_boundary_optimization.py couples them through a true free-boundary solve. Both print final plasma and coil metrics; single_stage_optimization.py also states whether it met its rotational-transform and normal-field targets. A lower weighted penalty with unmet targets is not a design.

Open mirrors and stellarator-mirror hybrids

Fixed-boundary non-axisymmetric mirror

Fixed-boundary open mirrors, from examples/mirror/mirror_fixed_boundary_nonaxisymmetric.py.

Free-boundary mirror beta scan

The free-boundary mirror beta scan, examples/mirror/mirror_free_boundary_beta_scan.py, over the validated 0 to 10 percent beta range.

Stellarator-mirror hybrid

Periodic stellarator-mirror hybrids, examples/mirror/stellarator_mirror_hybrid.py, with a quasi-isodynamic variant in qi_mirror_hybrid_fourier_vs_bspline.py. Hybrids and anisotropy are research scopes: see the mirror guide for what is validated.

Agreement with VMEC2000 and VMEC++

Force-residual traces for VMEX, VMEC2000 and VMEC++

The same deck through all three codes, python benchmarks/make_readme_figures.py --only convergence. Cross-code agreement, its norms and its limits are in the validation record.

Running the examples

git clone https://github.com/uwplasma/vmex
cd vmex
pip install -e .
vmex examples/data/input.circular_tokamak --plot
python examples/take_gradients.py
Application Runnable starting point
Tokamak or stellarator equilibrium vmex examples/data/input.circular_tokamak --plot; other decks in examples/data
QA, QH, QP or QI boundary design examples/optimization, including bootstrap, ballooning, Mercier and maximum-J variants
Asymmetric boundary design stellarator_asymmetry vacuum and finite-beta scripts
Single-stage plasma and coils single_stage_optimization.py, single_stage_free_boundary_optimization.py
Fields and spatial derivatives python examples/vmex_get_B_gradB.py
ESSOS coils and a free-boundary beta scan python examples/free_boundary_essos_coils.py
Finite-beta exterior field lines python examples/vmex_fieldline_tracing_finite_beta.py
Effective ripple python examples/epsilon_effective.py
Open mirrors mirror/mirror_fixed_boundary_nonaxisymmetric.py, mirror/mirror_free_boundary_beta_scan.py
Research force-balance polishing python examples/force_balance_polishing.py

The optimization scripts expose resolutions, objective weights and iteration budgets near the top. Inspect those settings before a research run; advanced coil examples need the optional dependencies and versions in the ESSOS guide.

Fields, coils and free boundary

The live equilibrium exposes Cartesian B(), gradB(), gradgradB() and gradgradgradB(), with corresponding VJPs in the originating problem's degrees of freedom. Use set_points_xyz(...) or set_points_flux(...) to select interior evaluation points.

For an exterior field, vj.VmecExtender.from_file("wout_my_case.nc", external_field=coils.B) combines the plasma's virtual-casing contribution with the supplied coil field. The plasma part is a quadrature over a source grid on the plasma surface (32 points per field period in each angle by default) whose error grows rapidly near that surface: evaluate at distances of at least about twice the toroidal source-grid spacing from the plasma surface. Closer in, with_near_surface_continuation uses a first-order continuation of the on-surface field. Targets must also stay away from coil filaments, and an MGRID field has a finite tabulated domain. See the exterior-field explanation and field and coil usage.

Exterior field lines of a finite-beta QA with coils only and with coils plus plasma

Field lines seeded within 5 mm outside a finite-beta QA boundary, in the coil field alone and with the plasma's field added, stopped 55 mm out where the continuation ends: python examples/vmex_fieldline_tracing_finite_beta.py (needs ESSOS).

Joint boundary/coil optimization and the boundary-Schur adjoint remain advanced workflows with substantial solve costs. Open mirrors support defined isotropic fixed/free-boundary cases; the shipped free-boundary 0–10% beta range is the supported range, while higher beta, anisotropy and periodic hybrids need further validation. See the mirror guide.

Accuracy and optional polishing

A small VMEC FSQR/FSQZ/FSQL means the discrete solve converged. It does not by itself bound the continuous force error J × B − ∇p. Optional spline-based polishing is disabled by default and remains a research feature: recorded certified cases are axisymmetric; a generally accurate, affordable 3-D polished solve is still an open goal.

vmex examples/data/input.shaped_tokamak_pressure_polished --polish auto --plot

AUTO estimates the Gauss–Newton work against --polish-budget; this is an admission estimate, not an enforced end-to-end timeout. Inspect result.polish_report when using Python. The legacy pointwise eps_F metric is bounded above by 2 by construction and can saturate in vacuum; read the dimensional and volume-normalized metrics with it.

The validation record explains the measured near-axis improvement, failed 3-D attempts, native DESC comparison and export errors. The polishing reference defines the method and certificate. Exported-and-refitted WOUT comparisons measure reconstruction error as well as solver error.

Performance and parallel execution

JAX compilation is reused for matching array structures. Measure first-call, cache-reload and warm costs separately, including refinement and gradients for optimization. CPU/GPU performance depends on resolution and workload; see benchmark evidence and profiling tools.

vj.parallel.solve_ensemble(inputs, workers=None) distributes independent cases; workers=1 provides a serial baseline. Set worker and device budgets using the ensemble guide. Multi-device kernel/AD tests do not yet establish a scalable distributed nonlinear equilibrium solve.

Documentation, development and citation

Start with your first equilibrium, then your first optimization. The API, VMEC compatibility and troubleshooting pages cover research use.

For development, install pip install -e ".[dev]" and run python tools/preflight.py --static; the test manifest defines numerical suites. Report issues with the input deck and vmex --doctor output. See contributing, citation metadata, license and the plan/logbook. A new release will follow integration and validation of the agreed priorities.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vmex-0.9.0.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vmex-0.9.0-py3-none-any.whl (803.7 kB view details)

Uploaded Python 3

File details

Details for the file vmex-0.9.0.tar.gz.

File metadata

  • Download URL: vmex-0.9.0.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vmex-0.9.0.tar.gz
Algorithm Hash digest
SHA256 5af990d616e7b9ba5c80488e3c2ca16b321464149381d75d8bf68b9fb913470d
MD5 66bf8f7943f079b2b936a84f4d4dff4f
BLAKE2b-256 e97771586c62c74bafc556caab8da6b10b0f956e2c23de375152697fa71192de

See more details on using hashes here.

Provenance

The following attestation bundles were made for vmex-0.9.0.tar.gz:

Publisher: publish-pypi.yml on uwplasma/vmex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vmex-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: vmex-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 803.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vmex-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b4aca1f8a21e0f69a9dac710e042a4dda1996d009c4b39b57575bffd59d8c726
MD5 7a9459e6017aaf1cb5630f0cbda8f090
BLAKE2b-256 63f8b9c8c2ed401d7798b8eb3281de6e975a741d7adbf521ea762654a04895e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for vmex-0.9.0-py3-none-any.whl:

Publisher: publish-pypi.yml on uwplasma/vmex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 files

0.8.1

2 files

0.8.0

2 files

0.7.1

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page