Skip to content

Add a VMEX interoperability example - #62

Open
rogeriojorge wants to merge 1 commit into
mainfrom
docs/vmex-interop
Open

Add a VMEX interoperability example#62
rogeriojorge wants to merge 1 commit into
mainfrom
docs/vmex-interop

Conversation

@rogeriojorge

Copy link
Copy Markdown
Member

Needs the project's external reviewer. ESSOS PRs are not self-merged.

Why

ESSOS optimizes coils. The equilibrium those coils hold is what VMEX
(pip install vmex, a JAX implementation of VMEC) solves. The two packages fit
together without either importing the other -- coils leave ESSOS as a
Biot-Savart field tabulated onto a cylindrical grid, which is what VMEX's
free-boundary solver consumes, and the equilibrium comes back as a wout file,
which is what essos.fields.Vmec already reads. Nothing in the repository
showed that.

What this adds

examples/simple_examples/equilibrium_from_coils_vmex.py, in the directory that
already holds the cross-package scripts (coils_from_BOOZ_XFORM.py):

  1. loads the bundled Landreman-Paul QA Coils and vmaps BiotSavart.B into the
    batch callable VMEX's tabulator wants;
  2. vj.MgridField.from_cartesian_field(...) -> the external field;
  3. vj.scale_input maps the reactor-scale QA deck this repository ships onto the
    unit size those coils were optimized for, to seed the guess;
  4. vj.solve_free_boundary(...) -> a converged vacuum equilibrium whose last
    closed surface was found by the coils, not prescribed;
  5. vj.write_wout -> essos.fields.Vmec -> Tracing(model='FieldLine'), and
    the rotational transform measured from the trace is compared with the one
    VMEX computed from force balance.

Plus a short section in README.md and docs/getting_started.rst pointing at
it.

Measured output:

Tabulating 16 filaments took 0.63 seconds
vmex free-boundary solve took 48.84 seconds, converged: True
Aspect ratio 6.012, |B| on axis 0.2637 T
ESSOS field-line tracing took 7.04 seconds
iota at s=0.5: 0.417488 traced, 0.417531 from vmex

The figure shows the coils with the solved surface in 3-D and the Poincare
section of the traced lines.

Scope

Deliberately limited to released VMEX 0.6.0 (the PyPI wheel):
MgridField.from_cartesian_field, scale_input, solve_free_boundary,
wout_from_state, write_wout. No unreleased API, and nothing here depends on
#61 or on any other open ESSOS branch -- the ESSOS surface used is Coils,
BiotSavart, Vmec and Tracing.

VMEX has a companion PR (uwplasma/vmex#146) documenting the same two seams from
its side and adding one-call helpers for both directions. Once that is released
the tabulation block here shortens to vj.MgridField.from_coils(coils, ...);
until then the explicit vmap-and-chunk wrapper is what the released wheel needs,
so it is what this example shows.

README.md's Project Structure tree is already stale (flat examples/ listing,
inputs/ rather than input_files/) and is left alone rather than half-fixed.

Local verification

macOS 14.4, MacPorts Python 3.11, jax/jaxlib 0.9.2, VMEX 0.6.0 from PyPI-tagged
main, ESSOS at this branch.

Check Result
pytest tests/ 79 passed, 1 xfailed, 30.9 s
flake8 --select=E9,F63,F7,F82 on the new example 0
flake8 --max-line-length=127 on the new example only the 10 E402s every ESSOS example has from the XLA_FLAGS prologue
example, full run exit 0, 62.6 s, figure and wout written to examples/output/
example, VMEX_EXAMPLES_CI=1 exit 0, 48.8 s, plot skipped

The VMEX_EXAMPLES_CI switch is the one VMEX's own examples read; it is the
single concession to the other repository's conventions, and it exists so the
script can be smoke-run headless.

Not verified: GPU, and any Python other than 3.11.

ESSOS optimizes coils; the equilibrium those coils hold is what VMEX
(pip install vmex) solves. The two meet without either importing the other,
but nothing in the repository showed how.

examples/simple_examples/equilibrium_from_coils_vmex.py takes the bundled
Landreman-Paul QA Coils, tabulates their Biot-Savart field onto the
cylindrical grid VMEX's free-boundary solver consumes, solves the vacuum
free boundary, reads the result back as an essos.fields.Vmec and traces
field lines through it. The rotational transform it measures agrees with
VMEC's own iotaf to 1e-4 relative.

Uses only released VMEX 0.6.0 (MgridField.from_cartesian_field,
scale_input, solve_free_boundary, wout_from_state, write_wout), so it runs
against the published wheel.

README and getting_started gain a short section pointing at it.
@codecov

codecov Bot commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant