Theory and conventions¶
This page summarizes conventions used in vmex. 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:
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:
Surface representation¶
VMEC represents a surface in cylindrical coordinates using Fourier series:
vmex stores these coefficients in the
SpectralState pytree as arrays shaped
(ns, K) where K is the number of (m,n) modes in the main VMEC
ordering (see vmex.core.fourier for the mode bookkeeping).
Parities and stellarator symmetry (lasym)¶
A stellarator-symmetric equilibrium is invariant under \((\theta,\zeta) \to (-\theta,-\zeta)\) with \(R \to R\), \(Z \to -Z\). Each field therefore keeps only one Fourier parity:
Field |
symmetric ( |
antisymmetric partner ( |
|---|---|---|
\(R\) |
\(\cos(m\theta-n\zeta)\) ( |
\(\sin\) ( |
\(Z\) |
\(\sin(m\theta-n\zeta)\) ( |
\(\cos\) ( |
\(\lambda\) |
\(\sin(m\theta-n\zeta)\) ( |
\(\cos\) ( |
SpectralState always carries all six blocks
(R_cos, R_sin, Z_cos, Z_sin, L_cos, L_sin); in symmetric runs the
antisymmetric partners are structurally zero and do not evolve. The synthesis
fourier_to_real() (VMEC totzsps +
totzspa) handles both parities in one signed-\((m,n)\) cos/sin
packing.
Stellarator symmetry also halves the angular grid: the stored poloidal extent
is \(\theta \in [0,\pi]\) (ntheta2) for symmetric runs and the full
\([0, 2\pi)\) (ntheta1) when lasym — the ntheta3 property of
Resolution. For lasym runs, the force
kernels are first split into symmetric/antisymmetric parts on the reduced
interval (VMEC symforce.f, symforce_split(),
applied by symmetrize_forces()) and each part is
projected with the matching analysis transform
(tomnsps() /
tomnspa()).
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:
vmex 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:
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.
vmex 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}}\):
The covariant basis vectors are:
The covariant metric is:
The signed Jacobian is:
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:
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}}}\).
Covariant components and \(|B|\)¶
Because \(B^s = 0\), lowering the index needs only the angular metric block:
and the field magnitude follows without ever forming Cartesian components:
The computation chain per iteration is:
real_space_geometry()— synthesize \(R, Z, \lambda\) and their angular derivatives (even/odd-m planes);half_mesh_jacobian()— half-mesh \(\sqrt{g}\) and the \(\tau\) sign proxy;metric_elements()— half-meshguu, guv, gvv;magnetic_fields()—bsupu/bsupvfrom the flux profiles and \(\lambda\) derivatives, thenbsubu/bsubvand the total pressure \(|B|^2/2 + p\) (VMECbsq).
Energy scalars (wb and wp)¶
VMEC reports the magnetic energy scalar wb and thermal energy scalar wp
in wout files. In VMEC normalization:
Important: VMEC treats internal pressure in units of \(\mu_0\,\mathrm{Pa}\)
(i.e. \(B^2\) units). vmex follows this convention for parity.