Theory and conventions

This page summarizes conventions used in vmec-jax. The goal is compatibility with VMEC2000 (wout_*.nc) and with standard VMEC literature.

Coordinates and angles

VMEC uses curvilinear coordinates on nested flux surfaces. In this repo we use:

  • \(s \in [0,1]\): normalized toroidal flux label (VMEC’s “radial” coordinate).

  • \(\theta \in [0, 2\pi)\): poloidal angle.

  • \(\zeta \in [0, 2\pi)\): field-period toroidal angle (VMEC internal coordinate).

  • physical toroidal angle \(\phi_{\mathrm{phys}} = \zeta / \mathrm{NFP}\), where \(\mathrm{NFP}\) is the number of field periods.

Fourier phases are written as:

\[\mathrm{phase}(m,n;\theta,\zeta) = m\theta - n\zeta.\]

Here \(n\) is the field-period toroidal mode number (VMEC stores xn = n*NFP in wout).

Derivatives w.r.t. the physical toroidal angle satisfy:

\[\frac{\partial}{\partial \phi_{\mathrm{phys}}} = \mathrm{NFP}\,\frac{\partial}{\partial \zeta}.\]

Surface representation

VMEC represents a surface in cylindrical coordinates using Fourier series:

\[R(s,\theta,\zeta) = \sum_{m,n} \Bigl( R_{mn}^c(s)\cos(m\theta-n\zeta) + R_{mn}^s(s)\sin(m\theta-n\zeta) \Bigr),\]
\[Z(s,\theta,\zeta) = \sum_{m,n} \Bigl( Z_{mn}^c(s)\cos(m\theta-n\zeta) + Z_{mn}^s(s)\sin(m\theta-n\zeta) \Bigr).\]

vmec-jax stores these coefficients in a VMECState as arrays shaped (ns, K) where K is the number of (m,n) modes in the main VMEC ordering.

Regularity and internal storage

VMEC stores odd-m harmonics in an internal form that factors out the radial \(\sqrt{s}\) behavior so that coefficients remain finite on-axis. This is implemented through the scalxc array (1 for even-m, \(1/\sqrt{s}\) for odd-m) and is applied whenever VMEC interpolates between radial grids or builds preconditioned residuals.

When LCONM1 is enabled, VMEC also applies a constrained internal basis for the \(m=1\) boundary modes:

\[R^{s}_{1n,\mathrm{int}} = \frac{1}{2}\left(R^{s}_{1n,\mathrm{phys}} + Z^{c}_{1n,\mathrm{phys}}\right), \qquad Z^{c}_{1n,\mathrm{int}} = \frac{1}{2}\left(R^{s}_{1n,\mathrm{phys}} - Z^{c}_{1n,\mathrm{phys}}\right).\]

vmec-jax uses the same internal storage so that its boundary mapping, multigrid interpolation, and parity diagnostics match VMEC2000.

The lambda field

VMEC introduces a scalar field \(\lambda(s,\theta,\zeta)\) to define the “straight-field-line” poloidal angle:

\[u = \theta + \lambda(s,\theta,\zeta),\]

so that magnetic field lines are straight in the (u,\zeta) angle pair.

Important scaling convention

In VMEC2000 wout files, the stored Fourier coefficients of \(\lambda\) are scaled by a run-dependent scalar lamscale. VMEC multiplies \(\partial\lambda/\partial\theta\) and \(\partial\lambda/\partial\zeta\) by lamscale before using them in the contravariant field formulas.

vmec-jax follows this convention so we can validate against wout values.

Geometry, metric, and Jacobian

We form covariant basis vectors by embedding the surface into 3D Cartesian coordinates using the physical toroidal angle \(\phi_{\mathrm{phys}}\):

\[x = R\cos\phi_{\mathrm{phys}}, \qquad y = R\sin\phi_{\mathrm{phys}}, \qquad z = Z.\]

The covariant basis vectors are:

\[\mathbf{e}_s = \partial_s \mathbf{r}, \qquad \mathbf{e}_\theta = \partial_\theta \mathbf{r}, \qquad \mathbf{e}_\phi = \partial_{\phi_{\mathrm{phys}}}\mathbf{r}.\]

The covariant metric is:

\[g_{ij} = \mathbf{e}_i \cdot \mathbf{e}_j, \qquad i,j \in \{s,\theta,\phi\}.\]

The signed Jacobian is:

\[\sqrt{g} = \mathbf{e}_s \cdot (\mathbf{e}_\theta \times \mathbf{e}_\phi).\]

VMEC stores a sign convention signgs = ±1 such that signgs*sqrtg is positive away from the axis.

Contravariant magnetic field (VMEC form)

For fixed-boundary VMEC, the magnetic field is represented in terms of contravariant components \(B^u\) and \(B^v\) (VMEC’s bsupu and bsupv) and 1D flux functions:

  • phipf(s) = dΦ/ds (toroidal flux derivative),

  • chipf(s) = dΧ/ds (poloidal flux derivative),

plus lambda derivatives.

In this repo (matching VMEC’s bcovar + add_fluxes logic), the formulas are:

\[\mathrm{bsupv} = \frac{\mathrm{phipf} + \mathrm{lamscale}\,\partial_\theta\lambda} {\mathrm{signgs}\,\sqrt{g}\,2\pi},\]
\[\mathrm{bsupu} = \frac{\mathrm{chipf} - \mathrm{lamscale}\,\partial_\zeta\lambda} {\mathrm{signgs}\,\sqrt{g}\,2\pi}.\]

Note that \(\partial_\zeta \lambda\) is w.r.t. the field-period coordinate \(\zeta\), while the geometry kernel returns \(\partial_{\phi_{\mathrm{phys}}}\lambda\), so we convert using \(\partial_\zeta = (1/\mathrm{NFP})\,\partial_{\phi_{\mathrm{phys}}}\).

Energy scalars (wb and wp)

VMEC reports the magnetic energy scalar wb and thermal energy scalar wp in wout files. In VMEC normalization:

\[\mathrm{wb} = \frac{1}{(2\pi)^2}\int \frac{B\cdot B}{2}\,dV, \qquad \mathrm{wp} = \frac{1}{(2\pi)^2}\int p\,dV.\]

Important: VMEC treats internal pressure in units of \(\mu_0\,\mathrm{Pa}\) (i.e. \(B^2\) units). vmec-jax follows this convention for parity.