Process reference: magnetic_island
Generated from the docstrings of vaft.process.magnetic_island:
4 public functions. Each entry is what
vaft.process.describe("magnetic_island.<name>") prints.
All process categories
Overview
The equilibrium is the only source of plasma geometry. Nothing here takes a major radius, an elongation or a Shafranov shift: the resonant surface comes from the equilibrium’s safety factor, the poloidal angle from its straight-field-line map, and the island’s extent from the flux surfaces’ spacing on the outboard midplane. The island is a prescribed constant-psi perturbation on top of that, not a solution of anything.
Three objects are kept apart, because they are different physics and a phantom that conflates them cannot say which one a synthetic signal is sensitive to::
equilibrium psi(R, Z), q(psi_N) (input)
island topology helical flux Omega(R, Z; t, phi) magnetic_island_topology
emissivity epsilon(R, Z; t, phi) island_emissivity
The diagnostic response, a line integral of the emissivity, lives in
vaft.process.line_of_sight and vaft.process.soft_x_rays.
| Symbol | Meaning | Unit |
|---|---|---|
| psi_N | normalized poloidal flux, 0 on axis and 1 on the boundary | - |
| psi_N,s | psi_N of the resonant surface q = m/n | - |
| theta* | PEST straight-field-line poloidal angle | rad |
| phi | IMAS toroidal angle, counter-clockwise seen from above | rad |
| xi | helical phase m theta* - sigma n phi - alpha(t) | rad |
| x | outboard-midplane distance of a point's flux surface from the | |
| W | full island width at the outboard midplane | m |
| Omega | helical flux 8 (x/W)^2 - cos xi, -1 at the O-point, 1 on the |
W is the full width at the outboard midplane. x is a flux label
measured in metres: the outboard-midplane distance between the flux surface
through a point and the resonant surface. On the outboard midplane it is the
exact radial distance, so the separatrix branches through an outboard O-point
are exactly W apart; elsewhere the island is bounded by the same flux
surfaces, as a constant-psi island is, and its geometric width follows the
flux expansion, wider where the surfaces spread.
The helical phase is resonant by construction. sigma is the sign of
d phi / d theta* along a field line, read from the equilibrium’s field
direction, so xi is constant along every field line on the resonant
surface whichever way the current and the toroidal field point. phi is the
IMAS toroidal angle, the frame of soft_x_rays.channel.line_of_sight.phi.
O-point at xi = 0, X-point at xi = pi. alpha(t) = phase +
angular_frequency (t - t0) rotates the island rigidly; at fixed phi the
O-point moves to larger theta* when alpha grows. The sign of
angular_frequency is therefore a poloidal direction, not a toroidal one:
at fixed theta* the pattern moves in the IMAS toroidal angle at
d phi / dt = -angular_frequency / (sigma n), so the same spec propagates
the opposite way toroidally when the helicity flips (reversed plasma current
or toroidal field). A caller matching a measured toroidal phase velocity must
fold IslandTopology.helicity in.
Functions
equilibrium_safety_factor | The magnitude of the safety factor on normalized flux, as the equilibrium knows it. Convention |
island_emissivity | A soft-X-ray emissivity phantom from an island topology. Convention |
magnetic_island_topology | The helical flux of an m/n island placed on an equilibrium.
Convention |
resolve_rational_surface | Where the equilibrium’s own safety factor equals m/n.
Convention |
No function matches.
equilibrium_safety_factor
Machine-independentConvention-sensitive
source
equilibrium_safety_factor(equilibrium)
Show source vaft/process/magnetic_island.py, lines 209–269
def equilibrium_safety_factor(equilibrium) -> tuple[np.ndarray, np.ndarray]:
"""The magnitude of the safety factor on normalized flux, as the equilibrium knows it.
Parameters
----------
equilibrium : EquilibriumData or source
An equilibrium record, or anything
:func:`vaft.process.equilibrium.as_equilibrium` accepts [-].
Returns
-------
tuple of numpy.ndarray
``(psi_n, abs(q))``, sorted by increasing ``psi_n`` [-].
Raises
------
ValueError
The record carries neither a q profile nor the flux map and poloidal
current function to compute one, or its flux storage family is unknown.
Convention
----------
The record's own profile when it has one; otherwise q is computed from the
flux map and ``F`` by :func:`calculate_q_profile_from_psi` on 97 interior
levels, which is the case for an analytic Solov'ev export. Only the
magnitude is returned: resonance is ``|q| = m/n``, and the direction is the
helicity's job.
Applicability
-------------
Machine-independent.
Limitations
-----------
A computed profile starts at ``psi_n = 0.02`` and ends at ``0.98``, so a
resonance closer to the axis or the boundary than that is not found.
Provenance
----------
.. [1] :func:`vaft.process.equilibrium.calculate_q_profile_from_psi`, the
contour-integral safety factor it falls back to.
"""
eq = _coerce(equilibrium)
span = eq.psi_boundary - eq.psi_axis
if eq.q is not None and eq.psi_1d is not None and eq.q.size == eq.psi_1d.size:
psi_n = (eq.psi_1d - eq.psi_axis) / span
q = np.abs(eq.q)
else:
if eq.psi is None or eq.f is None or eq.psi_1d is None:
raise ValueError(
"the equilibrium has no q profile and lacks the flux map or F to compute one"
)
psi_n = np.linspace(0.02, 0.98, 97)
q = np.abs(np.asarray(calculate_q_profile_from_psi(
eq.psi, eq.r, eq.z, (eq.psi_1d, eq.f), eq.psi_axis, eq.psi_boundary, psi_n,
axis_rz=eq.magnetic_axis, cocos=_cocos_for_q(eq),
), dtype=float))
order = np.argsort(psi_n)
psi_n, q = psi_n[order], q[order]
keep = np.isfinite(q)
return psi_n[keep], q[keep]The magnitude of the safety factor on normalized flux, as the equilibrium knows it.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData or source | - | An equilibrium record, or anything |
| Returns | |||
| — | tuple of numpy.ndarray | - |
|
Convention
The record’s own profile when it has one; otherwise q is computed from the
flux map and F by calculate_q_profile_from_psi on 97 interior
levels, which is the case for an analytic Solov’ev export. Only the
magnitude is returned: resonance is |q| = m/n, and the direction is the
helicity’s job.
Raises
ValueErrorThe record carries neither a q profile nor the flux map and poloidal current function to compute one, or its flux storage family is unknown.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
A computed profile starts at psi_n = 0.02 and ends at 0.98, so a
resonance closer to the axis or the boundary than that is not found.
Provenance
vaft.process.equilibrium.calculate_q_profile_from_psi, the contour-integral safety factor it falls back to.
island_emissivity
Machine-independentConvention-sensitive
source
island_emissivity(topology, *, profile=None, model='flatten', amplitude=1.0, smoothing=0.1, hard_mask=False)
A soft-X-ray emissivity phantom from an island topology.
| Name | Type | Unit | Description |
|---|---|---|---|
topology | IslandTopology | - | The island on its equilibrium grid, from |
profile | callable or tuple of array_like, optional | emissivity unit | Axisymmetric background |
model | str, optional | - |
|
amplitude | float, optional | - or emissivity unit |
|
smoothing | float, optional | - | Width of the |
hard_mask | bool, optional | - | Use the binary mask |
| Returns | |||
| — | tuple of numpy.ndarray | emissivity unit |
|
Convention
The mask is M = (1 - tanh((Omega - 1)/smoothing)) / 2, one inside the
separatrix and zero outside it. "island": delta_epsilon = A M.
"flatten": delta_epsilon = A M (epsilon_0(psi_N,s) -
epsilon_0(psi_N)), so A = 0 returns the axisymmetric background and
A = 1 flattens it to the resonant-surface value inside the island.
Raises
ValueErrorAn unknown model, a flattening model without a profile, a non-positive smoothing, or a malformed profile table.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
A phenomenological response, not a transport calculation: the flattening is instantaneous and complete to the separatrix, with no dependence on the island’s size against a critical width, and no atomic or filter physics.
Provenance
- Le, T. X. K. et al., Plasma Phys. Control. Fusion 68, 065003 (2026), for modelling an island’s SXR signature as flattened emissivity.
- Dreval, M. B. et al., Plasma Phys. Control. Fusion 65, 035001 (2023), for a prescribed emissivity perturbation on magnetic surfaces.
magnetic_island_topology
Machine-independentConvention-sensitive
source
magnetic_island_topology(equilibrium, island, *, time=0.0, phi=0.0, sfl_map=None)
The helical flux of an m/n island placed on an equilibrium.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData or source | - | The axisymmetric equilibrium, the only source of geometry; anything |
island | MagneticIslandSpec | - | Mode numbers, outboard-midplane full width and phase. |
time | float, optional | s | Time at which to evaluate the island phase. |
phi | float, optional | rad | IMAS toroidal angle of the poloidal plane. |
sfl_map | StraightFieldLineMap, optional | - | A straight-field-line map already built for this equilibrium, to reuse |
| Returns | |||
| — | IslandTopology | - | The resonant surface, the helicity, the flux width, and on the equilibrium grid |
Convention
Omega = 8 (x/W)^2 - cos(xi) with xi = m theta* - sigma n phi -
alpha(t): Omega = -1 at the O-point (xi = 0, x = 0) and
Omega = 1 on the separatrix and at the X-point (xi = pi), and the
separatrix branches through an outboard O-point are exactly W apart.
x = R_out(psi) - R_out(psi_s), where R_out is the outboard-midplane
radius of a flux surface, so x is a flux label in metres, exact on the
outboard midplane and growing outward; theta* is PEST, zero on the outboard midplane; phi
is the IMAS toroidal angle. sigma is the sign of d phi / d theta*
along a field line from the equilibrium’s field, so xi is constant along
field lines on the resonant surface.
Raises
ValueErrorThe resonant surface does not exist, the boundary is not closed on the grid, or the helicity cannot be read from the record and was not given.
Processing steps · Applicability · Limitations · Provenance
Processing steps
- Build (or reuse) the straight-field-line map of the equilibrium.
- Find
psi_N,sfromq = m/n, unless the spec overrides it. - Solve the resonant surface; take the helicity from the field direction at its outboard-midplane point.
- Form the outboard-midplane displacement and the helical phase on the grid, and from them the helical flux and the separatrix mask.
- Locate the O- and X-points on the resonant surface.
Applicability
Machine-independent.
Limitations
A prescribed constant-psi island: no island-induced change of the equilibrium, no finite-width distortion beyond the quadratic flux model, and no island that crosses the boundary is treated specially. The displacement is first order in the flux offset, so an island wide against the local flux-surface curvature is only approximately symmetric.
Provenance
- Choi, G. J., Rev. Mod. Plasma Phys. 8, 11 (2024), the constant-psi helical flux.
- Le, T. X. K. et al., Plasma Phys. Control. Fusion 68, 065003 (2026), a rotating-island SXR forward model of the same scope on a spherical tokamak.
resolve_rational_surface
Machine-independentConvention-sensitive
source
resolve_rational_surface(equilibrium, m, n, *, index=0)
Show source vaft/process/magnetic_island.py, lines 272–347
def resolve_rational_surface(equilibrium, m: int, n: int, *, index: int = 0) -> tuple[float, float]:
"""Where the equilibrium's own safety factor equals ``m/n``.
Parameters
----------
equilibrium : EquilibriumData or source
An equilibrium record, or anything
:func:`vaft.process.equilibrium.as_equilibrium` accepts [-].
m : int
Poloidal mode number [-].
n : int
Toroidal mode number [-].
index : int, optional
Which crossing when ``q`` crosses ``m/n`` more than once, innermost
first [-].
Returns
-------
tuple of float
``(psi_n_s, q_s)``: the normalized flux of the resonant surface and the
profile's value there, which equals ``m/n`` to the root tolerance [-].
Raises
------
ValueError
``q = m/n`` does not occur in the profile, or ``index`` asks for a
crossing that does not exist.
Convention
----------
Resonance is ``|q| = m/n``. The crossings are bracketed by
:func:`find_rational_surfaces` and each is refined by a root solve on a
cubic spline through the profile, so the answer is not limited to the
linear interpolation between samples.
Applicability
-------------
Machine-independent.
Limitations
-----------
Only as good as the profile the equilibrium carries; a reconstruction with
a poorly constrained core q places a core resonance equally poorly.
Provenance
----------
.. [1] :func:`vaft.process.equilibrium.find_rational_surfaces` for the
bracketing.
"""
from scipy.interpolate import CubicSpline
from scipy.optimize import brentq
psi_n, q = equilibrium_safety_factor(equilibrium)
target = float(m) / float(n)
found = find_rational_surfaces(psi_n, q, n, m_range=(m, m))
coarse = np.asarray(found["psi_n_rational"], dtype=float)
coarse = coarse[np.asarray(found["m"]) == m]
if coarse.size == 0:
raise ValueError(
f"q = {m}/{n} = {target:.4g} does not occur in this equilibrium: |q| spans "
f"[{np.min(q):.4g}, {np.max(q):.4g}] over psi_N in [{psi_n[0]:.3g}, {psi_n[-1]:.3g}]"
)
coarse = np.sort(coarse)
if not 0 <= index < coarse.size:
raise ValueError(f"q = {m}/{n} crosses {coarse.size} time(s); index {index} does not exist")
guess = float(coarse[index])
unique, first = np.unique(psi_n, return_index=True)
# anti-alias: not time-domain -- q over normalized flux.
spline = CubicSpline(unique, q[first])
j = int(np.clip(np.searchsorted(unique, guess), 1, unique.size - 1))
lo, hi = unique[j - 1], unique[j]
f_lo, f_hi = spline(lo) - target, spline(hi) - target
if f_lo * f_hi > 0.0:
return guess, float(spline(guess))
root = float(brentq(lambda s: float(spline(s)) - target, lo, hi, xtol=1e-12))
return root, float(spline(root))Where the equilibrium’s own safety factor equals m/n.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData or source | - | An equilibrium record, or anything |
m | int | - | Poloidal mode number. |
n | int | - | Toroidal mode number. |
index | int, optional | - | Which crossing when |
| Returns | |||
| — | tuple of float | - |
|
Convention
Resonance is |q| = m/n. The crossings are bracketed by
find_rational_surfaces and each is refined by a root solve on a
cubic spline through the profile, so the answer is not limited to the
linear interpolation between samples.
Raises
ValueErrorq = m/ndoes not occur in the profile, orindexasks for a crossing that does not exist.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
Only as good as the profile the equilibrium carries; a reconstruction with a poorly constrained core q places a core resonance equally poorly.
Provenance
vaft.process.equilibrium.find_rational_surfacesfor the bracketing.