Scientific diagrams

vaft.diagram draws concepts: topology, coordinate systems, workflows. It does not draw data. The three layers split the work:

Layer Owns Example
vaft.formula the physics: every equation a diagram depends on helical_phase, island_pendulum_hamiltonian
vaft.diagram explanatory geometry: sampling, projection, camera, labels magnetic_island(projection="3d")
vaft.plot data and numerical results from an ODS equilibrium_2d_profiles

A diagram never restates an equation. It calls the formula function, so the picture and the formula reference cannot drift apart.

This page explains the diagrams family by family. The complete list – every builder, every committed SVG and the exact call that draws it – is the generated diagram gallery.

Magnetic island

import vaft

d = vaft.diagram.magnetic_island(
    m=3, n=2, width=0.16, phase=0.0, projection="poloidal",
    r_s=0.55, elongation=1.7, triangularity=0.4,   # D-shaped plasma; defaults give a circle
)
d.tikz       # the LaTeX/TikZ source; needs no TeX installation
# With latex and dvisvgm installed:
# d            -> displays inline in Jupyter (SVG)
# d.save("island.svg")
Projection Poloidal section at $\phi=0$ Top view $(R,\phi)$ 3-D view of the O and X helices
  poloidal top 3d

All three views are drawn from one model, and the convention is the same in each:

Quantity Definition
helical phase $\xi = m\theta^* - n\phi - \phi_0$, where $\theta^*$ is the straight-field-line (PEST) angle of each surface, running from the outboard midplane towards the top, and $\phi$ runs counter-clockwise seen from above
straight-field-line angle $\theta^* = 2\pi\int \mathcal{J}/R^2\,d\theta / \oint \mathcal{J}/R^2\,d\theta$ (vaft.formula.straight_field_line_angle), taken from the surface geometry alone. O- and X-points are evenly spaced in $\theta^*$, so they spread out on the low-field side even on circular surfaces
flux function $\mathcal{H}(x,\xi) = \tfrac12 x^2 - (w/4)^2\cos\xi$, with $x = r - r_s$
O-points / X-points $\xi = 0$ (minimum of $\mathcal{H}$) / $\xi = \pi$ (saddle): $m$ of each per poloidal section, alternating
separatrix $\mathcal{H} = (w/4)^2$, so $x_\mathrm{sep} = \tfrac{w}{2}\lvert\cos(\xi/2)\rvert$
width the full radial width at the O-point, in units of the minor radius
geometry Miller shaping from vaft.formula.miller_surface: $R = R_0 + r\cos(\theta + \arcsin\delta(r)\,\sin\theta)$ and $Z = \kappa r\sin\theta$, with $\delta(r) = \delta\,r$ so the surfaces stay nested and become circular towards the axis. Lengths are in units of the minor radius $a$
caveats The surfaces are prescribed, with no Shafranov shift, so $\theta^*$ is exact for these surfaces rather than for a Grad-Shafranov equilibrium. width is a width in the flux label $r$ and is a physical distance only on the outboard midplane

The top view suppresses $Z$, so crossings of the projected O and X loci there are not reconnection points. The separatrix and $w$ are only visible in the poloidal section.

Animating the island: a phase scan or a rigid rotation

The same call draws the island over a trajectory of its phase when it is asked to with animation=True (issues #1049, #1053). It returns the animation result that plot_*(..., animation=True) returns. An array argument never animates by itself.

import numpy as np
import vaft

# A helical-phase scan: one frame per phi_0, the same model as the static call.
scan = vaft.diagram.magnetic_island(m=2, n=1, phase=np.linspace(0, 2 * np.pi, 120), animation=True, fps=30)
scan.save("island.mp4")          # or .webm (both need vaft[video]) or .gif (needs nothing)

# A rigid rotation at f = 5 kHz: phi_0(t) = phi_0 + 2*pi*f*(t - t_0), from phase= at the first time.
rotation = vaft.diagram.magnetic_island(
    m=2, n=1, time=np.linspace(0, 2e-3, 120), rotation_frequency=5e3, animation=True,
)
rotation.metadata["driver"]      # name "time", unit "s", and every frame's time
  • Exactly one trajectory. A trajectory is either phase as an array (driver phase [rad]) or time with rotation_frequency (driver time [s]).
    • A phase array combined with time is refused, because it is ambiguous.
    • So is a single phase with animation=True, which is a static diagram.
  • Units and direction. rotation_frequency is a frequency $f$ in Hz. The synthetic island of #886 (vaft.process.magnetic_island.MagneticIslandSpec) takes the angular frequency $\omega = 2\pi f$ in rad/s. A positive $f$ moves the O-points towards $+\theta^$ on a section. At fixed $\theta^$, it moves them towards $-\phi$, which is clockwise seen from above.
  • Physics, not pictures. Every state is the static diagram at that phase, with the same O/X topology, width and shaping. The rotation is the phase relation evaluated at each time; the drawing is never rotated as an image.
  • Presentation only. fps or duration set only how fast the frames are shown, never the rotation rate. Each frame’s phase or time is kept in metadata and in the .json sidecar of save().
  • A preview of the canonical figure. The frames are a Matplotlib drawing of each state’s scene (the template’s colours and line styles, with labels through mathtext). The canonical static figure remains the SVG above.

Stability and operational-space diagrams

Textbook 2-D charts: two axes, the boundaries that divide the plane, and one label per region. A boundary that physics defines is computed by vaft.formula. Only the peeling–ballooning boundary, which has no closed form, is a schematic, and the figure says so.

vaft.diagram.peeling_ballooning()
vaft.diagram.s_alpha_ballooning(s_max=1.5, alpha_max=3.5)
vaft.diagram.hugill(elongation=1.0)                       # no size parameter: R, a, B cancel
vaft.diagram.hugill_st(elongation=1.8)                   # spherical-tokamak q_cyl (Sykes et al. 2000, MAST)
vaft.diagram.troyon(aspect_ratio=3.0, elongation=1.7)      # Troyon stability reference ~2.76, experimental levels dashed
vaft.diagram.li_qa(reference="wesson_1989")                # JET empirical l_i-q_psi space
vaft.diagram.li_qa(reference="cheng_1987")                 # theoretical MHD-stable l_i-q(a) domain
   
peeling-ballooning s-alpha
Hugill Troyon
l_i-q Wesson l_i-q Cheng
Diagram Question it answers Axes Boundaries
Peeling–ballooning Which edge instability limits the pedestal? $\alpha_\mathrm{max}$, $J_{B,\mathrm{max}}$ (arbitrary units) Schematic. Two linear margins joined by a smooth maximum. The ★, where the peeling and ballooning limits meet (typical ELM onset), is computed where the two margins are equal
$s$–$\alpha$ How does shear set the ballooning limit, and where is second stability? $\alpha$, $s$ The first and second stability boundaries come from s_alpha_marginal_alpha, which applies Newcomb’s criterion to the Connor–Hastie–Taylor equation. The dashed line is the $0.6\,s$ approximation of ballooning_stability_criterion. Not resolved below $s \approx 0.05$
Hugill Where is the density limit? $\bar n_e R/B_T$, $1/q_\mathrm{cyl}$ The registered greenwald_hugill line (slope $\pi/50\kappa_a$ in $1/q_\mathrm{cyl}$ against $\bar n_e R/B_T$) and murakami_hugill ($\bar n_e R/B_T = 1$). The registered low_q is on the equilibrium $q_\psi$, not $q_\mathrm{cyl}$, so it is not drawn; q_limit= adds a dashed reference $q_\mathrm{cyl}$ line
Hugill (ST) Where is the density limit in a spherical tokamak? $\bar n_e R/B_T$, $1/q^{ST}\mathrm{cyl}$ with $q^{ST}\mathrm{cyl} = 2.5a^2(1+\kappa^2)B_T/(RI_p)$ vaft.diagram.hugill_st(elongation=1.8): the Hugill limit as Sykes et al. (2000, MAST) define it (sykes_2000_st_hugill) and the Greenwald limit on these axes (greenwald_hugill_st, derived); Murakami dashed as a historical conventional-tokamak reference. Not substitutable with the conventional hugill axes (#1602)
$l_i$–$q$ Where do current-profile peaking and edge q allow stable operation? Wesson: $q_\psi$, $l_i(3)$. Cheng: cylinder $q(a)$, $l_i$ Two separate references, never mixed. Wesson 1989 Fig. 6: the JET empirical boundaries (kink and double tearing below, density-limit disruptions above), with the registered low_q closing $q_\psi = 2$. Cheng 1987 Fig. 4: the theoretical MHD-stable domain of a cylinder with $q(0) = 1.01$ (ideal kink below, resistive kinks above), plotted as $l_i$ rather than $l_i/2$
Troyon How much pressure has the current held, against which references? $I_p/(aB_T)$, $\beta_T$ The registered troyon stability reference, $\beta_N = 2.2\,\mu_0 10^6 \approx 2.76$, through $\beta_T = \beta_N I_p/(aB_T)$, with the experimental $\beta_N$ levels of the troyon projection dashed (DIII-D envelope and record, ST reference, NSTX record; #1691). None is a limit, so no side is shaded or called stable. beta_N_max= draws a what-if value and the note says so; q_limit= adds a dashed reference $q_\mathrm{cyl}$ cutoff

These charts show the boundaries of an operating space. Each one reads its lines from vaft.formula.boundaries through a canonical projection (#1425), and a population of measured or modelled states goes on the same projection with vaft.plot.operational_space.operational_space_population(table, "hugill"). Table columns are named by quantity identity (murakami_parameter, inverse_cylindrical_q, normalized_beta, …) with units in table.attrs["units"]. A boundary is drawn only when both plotted columns are exactly the projection’s quantities in its units: a q95 column never carries a $q_\psi$ or $q_\mathrm{cyl}$ boundary. Projections: hugill, troyon, beta_n_li, q95_li, greenwald_fraction_power, li_qa_wesson, li_qa_cheng, beta_n_li1 (Strait’s $\beta_N = 4\,l_i(1)$ envelope), and the #1691 beta-normalisation views volume_beta_in, beta_n_normalizations (with a $y = x$ guide), aspect_ratio_beta_n, aspect_ratio_volume_beta_n; list_projections() gives the full set. See #944 and #636.

Dimensionless similarity spaces

The limit diagrams above ask whether a state crosses a boundary. A similarity space asks where a state sits relative to other machines and to reactor designs, and which extrapolation separates them. In $\nu_$–$\rho_$, $\rho_$ is the size / finite-gyroradius direction ($1/\rho_$ is roughly the number of ion gyroradii across the minor radius) and $\nu_$ the collisionality direction ($1/\nu_$ is roughly the number of trapped-ion bounce orbits before a collision). $\beta_N$–$\rho_$ splits MHD-normalised pressure from machine scale. $\Omega_{ci}\tau_{E,\mathrm{th}}$–$\rho_$ splits confinement time, counted in gyro-orbits, from size. All three come from the ARC physics-basis comparison (Hillesheim et al., J. Plasma Phys. 92 (2026) E69, Fig. 6). They are zero-dimensional and draw no boundary by default (Luce, Petty and Cordey, PPCF 50 (2008) 043001, explain why these coordinates separate transport mechanisms).

Projection Question it answers Axes (exact quantity)
rho_star_nu_star Is the extrapolation in size, in collisionality, or both? rho_star_verdoolaege_2021, nu_star_verdoolaege_2021
rho_star_beta_n How much is pressure, how much is scale? rho_star_verdoolaege_2021, normalized_beta
rho_star_omega_ci_tau_e Size against confinement time in gyro-orbits rho_star_verdoolaege_2021, omega_ci_tau_e_th

The $\rho_$ and $\nu_$ axes follow the ITPA confinement-database convention, Verdoolaege et al., Nucl. Fusion 61 (2021) 076006, Eqs. (1a) and (1c), which Hillesheim et al. use. $n$ and $T$ are volume averages with $T_e = T_i$. The functions that evaluate them are rho_star_from_M_T_B_R_epsilon, nu_star_from_n_T_B_R_epsilon_kappa_I and omega_i_tau_E_from_B_tau_E_M in vaft.formula.equilibrium. VAFT has other $\nu_$ and $\rho_$ definitions (issue 353): Sauter’s local $\nu_$, pedestal $\nu^_e$, edge and separatrix collisionalities. Each is a different quantity, so it cannot be drawn on these axes. A missing input leaves the state unassessed: it is counted per group, in a warning and in the legend, and is never estimated. Each projection carries its meaning as metadata:

from vaft.diagram import _op_space
from vaft.plot.dimensionless_space import dimensionless_similarity

print(_op_space.get_projection("rho_star_nu_star").interpretation.describe())
fig, ax = dimensionless_similarity(table, "rho_star_nu_star", group="machine")   # ARC V3A overlaid
ax.vaft_exclusions.summary()

The only built-in reference point is ARC V3A ($\beta_N = 1.8$, $\rho_* = 0.0017$, $\nu_* = 0.031$, $\Omega_{ci}\tau_{E,\mathrm{th}} = 4.1\times10^8$), the values Hillesheim et al. state in Sec. 4. Their SPARC, ITER and EU-DEMO points appear only as plotted markers, so they are not digitised. Pass such points as reference_table= with a source column. See #1624.

Reduced stability diagnostics

What each analytic or reduced criterion is, and what it proves, is on Reduced stability diagnostics (#1635).

vaft.diagram.stability_diagnostic_taxonomy()
vaft.diagram.interchange_criteria()
   
taxonomy interchange
Diagram Concept
stability_diagnostic_taxonomy VAFT’s criteria by physical problem (rows) and logical status (columns): exact definition, reduced model, empirical or semi-empirical boundary, heuristic, and solver-derived. It also lists what is still absent. The reduced columns are compared with the solvers, not used as a gate
interchange_criteria suydam_criterion and mercier_criterion_circular on one schematic profile. The toroidal $p’(1 - q^2)$ stabilises outside $q = 1$, where Suydam’s criterion still fails

Single-particle motion

Gyration and guiding-centre drifts, drawn in the island family’s style and 3-D camera. Every orbit is integrated from the Lorentz force by vaft.formula.boris_orbit, and every drift arrow is the drift formula of vaft.formula.particle. The tests require the integrated guiding centre to move at the formula’s velocity, so the figure cannot show a drift that the orbit does not make.

vaft.diagram.exb_drift(mass_ratio=4.0)
vaft.diagram.curvature_drift()
vaft.diagram.magnetization_current()
vaft.diagram.toroidal_drift(aspect_ratio=2.2)
   
E x B drift curvature drift
magnetization current toroidal drift
Diagram Shows Arrows from
E×B drift An ion and an electron at equal energy in crossed uniform fields. The orbits differ in size, but the drift is the same, so no current flows exb_drift_velocity
Curvature and ∇B drift An ion spirals along a field line of $B_0R_0/R\,\hat\phi$ and drifts along $+z$ grad_b_drift_velocity + curvature_drift_velocity
Magnetization current Gyro-currents cancel inside a region. At its edge the diamagnetic $\mathbf{J}_M = \nabla\times\mathbf{M}$ survives the binned current of the integrated orbits
Toroidal drift ∇B and curvature drifts separate charge. The resulting vertical $\mathbf{E}$ drives an outward $\mathbf{E}\times\mathbf{B}$, so a purely toroidal field cannot confine the drift formulas at the drawn cross-section

Every view shows the relevant equations in a box. They are read from the $$…$$ definition in each formula’s docstring, so the figure shows exactly what the formula documents and implements. There is no second copy of any equation.

Each has further projections of the same computed orbits, chosen with projection=:

Diagram Projections (default first) What the extra views add
exb_drift perpendicular, 3d Helices along $\mathbf{B}$ drifting sideways. The parallel velocity does not change the perpendicular motion, so both views show the same orbits
curvature_drift 3d, poloidal, top poloidal looks along the field line, where the gyration circle climbs at the drift velocity. top shows the curved line and the inward $\nabla B$
magnetization_current perpendicular, 3d Helical columns along $\mathbf{B}$ with the edge current looping around them
toroidal_drift 3d, poloidal, top poloidal is the textbook $(R, z)$ cross-section. top shows the circular field lines, with the vertical drifts pointing out of the page

The units are normalised ($|q| = 1$, $m_e = 1$, fields of order one). The ion-to-electron mass ratio is reduced (4 by default) so that both orbits are visible; the figures state this.

Tearing physics

The ideas upstream of an island, one concept per diagram, so each can be used on its own in a page, notebook or slide. None takes an equilibrium, shot or solver output: the curves are schematic.

vaft.diagram.rational_surface(m=2, n=1)
vaft.diagram.delta_prime(sign="positive")   # "positive", "zero" or "negative"
vaft.diagram.tearing_layer_matching()
     
rational surface Delta prime layer matching
Diagram Question What is schematic
rational_surface Where does a perturbation resonate with the field-line pitch, $q(r_s) = m/n$? The monotonic $q(r)$; it is not an equilibrium profile
delta_prime What does the tearing stability index measure? The outer solutions: quadratics that vanish on the axis and at the edge. Their slopes at $r_s$ go through vaft.formula.delta_prime_from_outer_derivatives, and only the sign of $\Delta’$ is meaningful
tearing_layer_matching Why are the ideal outer regions and the non-ideal inner layer solved separately? The layer width and the layer solution, which only joins the outer solutions in value and slope

The index drawn here is the definition, not a stability result: no outer equation is solved. Solver values of $\Delta’$ (RDCON, STRIDE) belong to vaft.plot, and they are not the RDCON $D_R$ or the Modified Rutherford terms. The object these lead to is magnetic_island.

3-D perturbation harmonics

How a linear 3-D perturbation is written as complex Fourier harmonics, and what the complex numbers mean. Each diagram is one concept and needs no equilibrium, shot or GPEC output.

vaft.diagram.normal_field_component()
vaft.diagram.complex_harmonic(amplitude=1.0, phase=1.05)
vaft.diagram.toroidal_harmonic_phase(n=1)
vaft.diagram.harmonic_real_space_projection(m=2, n=1, phase=1.05)
vaft.diagram.complex_field_superposition(case="screening")   # "amplification", "phase_shift"
   
normal component complex harmonic
toroidal phase superposition

real-space projection

Diagram Concept
normal_field_component $\delta B_n = \delta\mathbf B\cdot\hat{\mathbf n}$ is the part of a perturbation that crosses a magnetic surface. It is geometric only, with no code-specific normalisation
complex_harmonic One harmonic is $\hat b = b_R + i\,b_I = A e^{i\alpha}$. $b_R$ and $b_I$ are the cosine and sine quadratures of one pattern, not two fields
toroidal_harmonic_phase Moving the toroidal origin by $\Delta\phi$ turns $\hat b$ by $-n\Delta\phi$. $\lvert\hat b\rvert$ is invariant; $b_R$ and $b_I$ are not
harmonic_real_space_projection The physical field is real, $\delta b = \mathrm{Re}[\hat b\,e^{i(m\theta - n\phi)}]$ (vaft.formula.helical_harmonic): stripes of slope $n/m$ on the unwrapped $(\phi, \theta)$ plane
complex_field_superposition External and plasma-response fields add as complex numbers, so screening, amplification and phase shift all come from one vector sum

The phase convention is helical_phase’s $\xi = m\theta - n\phi$, with both mode numbers positive and the helicity in the minus sign. vaft.code.gpec stores each complex quantity as a real/imaginary pair (i = 0 real, i = 1 imaginary) and rebuilds it as real + 1j * imag, deciding no convention. For GPEC’s spectral outputs that pair is the $(b_R, b_I)$ of complex_harmonic, and it becomes a field only through the real-space reconstruction. Two sources differ:

  • the *_fun quantities (b_n_fun, xi_n_fun) are already real-space in $\theta$, and GPEC writes them as $(\mathrm{Re}, -h\,\mathrm{Im})$ with its helicity $h$;
  • vaft.process.toroidal_mode_decomposition returns the conjugate, $\hat b = 2\,\overline{C_n}$.

helical_harmonic’s Convention section states both. Amplitudes, phases and responses in these figures are schematic.

Collision processes

A classification of the interactions in a fusion plasma, built from the concept-diagram primitives. Coulomb collisions between charged particles relax the distribution. Atomic processes change charge states and bound electrons. Nuclear reactions change nuclei.

vaft.diagram.collision_processes()

collision processes

The diagram contains no numbers except the D–T alpha energy, which is vaft.formula.constants.E_ALPHA. Collision frequencies, the Coulomb logarithm and collisionality regimes are left to formula-backed diagrams (#1111).

Geometric approximations

How slab, cylindrical and toroidal models relate, keeping geometry and ordering on separate axes. The physics is in vaft.formula.geometry. Geometric approximations explains each representation.

vaft.diagram.geometry_ordering_map()
vaft.diagram.field_line_geometry(geometry="toroidal")   # "cylindrical", "slab"
vaft.diagram.mode_number_mapping(m=2, n=1)
vaft.diagram.mhd_mode_geometry_map()
Diagram Concept
geometry_ordering_map Geometries are columns and orderings are bands. Each reduction arrow names what it keeps or drops
field_line_geometry The same $q$ field line on a torus and on the cylinder straightened at $R_0$, and the tilt of the sheared-slab field lines growing with $x$
mode_number_mapping The cylinder’s $k_\parallel(r)$ crosses zero at $q(r_s) = m/n$. The local slab of local_slab_from_cylinder is its tangent there
mhd_mode_geometry_map Pressure-driven, current-driven, resonant and $n = 0$ mode families in slab, cylinder and torus. Exact relabelling, limits, analogues and branches are drawn as four different arrows. The text is MHD mode representations across geometries

Asymptotic orderings

The scale separations a reduced model assumes, evaluated rather than assumed. The kernels are in vaft.formula.ordering, and Asymptotic orderings (#1627) explains them. Which diagrams the scale-to-model chain needs, and which are still planned, is Characteristic scales and orderings, “Diagram contracts”.

vaft.diagram.timescale_hierarchy()
vaft.diagram.spatial_scale_orderings()
vaft.diagram.ordering_contract_map()
vaft.diagram.adapter_contract_map()
Diagram Concept
timescale_hierarchy Inverse gyrofrequencies, collision, Alfvén, sound-crossing, inverse ion transit and bounce frequencies, evolution, wall, pulse and resistive times of one illustrative state on one logarithmic axis, each from a formula kernel. Below it are the ordering ratios: $S$, $\tau_{evol}/\tau_A$, $\tau_{pulse}/\tau_R$, $d_i/a$. Drift precession (no kernel) and $\tau_E$ (no inventory) are left out
spatial_scale_orderings Electron and ion Larmor radii, $\rho_s$, $d_i$, the banana width, an illustrative gradient length, $a$, $R_0$ and $qR_0$ of the same state on one logarithmic axis. Below it are $\rho_i/L$, $\Delta_b/L$, $d_i/a$, with brackets for the ratios that need a mode ($k_\perp\rho$, $k_\parallel/k_\perp$, $\omega/\Omega_c$)
ordering_contract_map Which model needs which ordering, read from vaft.validation.orderings.CONTRACTS. Quantities are grouped by scale (foundational, global, profile, perturbation, inner layer, time history) and models by family (fluid, reduced MHD, kinetic, neoclassical, evolution). Each cell is a separate assumption with its own margin, and an empty cell is not ordered.
adapter_contract_map Which ordering contracts each VAFT code-adapter mode consumes, and how each enters the calculation: governing (filled), RDCON’s outer solution and layer solution, DCON-kinetic’s fluid part and kinetic part, PENTRC’s closure, inherited by a reduced model that does not solve its parent theory (dashed). An empty cell is no registered contract, not physical independence (vaft.validation.model_contracts, #1823)

Plasma-model guide

Figures for the plasma-model guide (#1739). Every node is read from the formalism records: a node lists the adapter:mode ids of vaft.validation.model_contracts.ADAPTER_MODES whose record matches it, and codes not in VAFT (vaft.diagram.EXTERNAL_CODES) are hollow and labelled so. Four edge kinds are used: asymptotic reduction (solid), model coupling (double-headed), software dependency (dotted) and surrogate ancestry (dashed). No direction is a fidelity axis.

vaft.diagram.plasma_model_reduction_map()
vaft.diagram.formalism_axes_map()
vaft.diagram.solver_placement_map()
vaft.diagram.kinetic_mhd_coupling()
vaft.diagram.reduced_model_ancestry()
Diagram Concept
plasma_model_reduction_map One starting point (Vlasov / Fokker–Planck + Maxwell, no VAFT solver) and the reductions to the fluid, drift-kinetic, gyrokinetic, particle, hybrid, reduced and equilibrium descriptions, each edge labelled with its ordering, each node with its VAFT modes
formalism_axes_map The independent axes of vaft.code.formalism.AXES, one column each with an N/A cell, and three runs (CGYRO nonlinear, DCON kinetic, NUBEAM) drawn across them. The numerical representation is a separate box, not an axis
solver_placement_map Every adapter mode against bulk, model, spatial domain and regime, filled from its record, unclassified modes greyed; then the codes not in VAFT, hollow
kinetic_mhd_coupling Kinetic-MHD as a coupling loop between an ideal-MHD bulk and a drift-kinetic population: energy closes it (DCON, GPEC kinetic), closure is one-way (PENTRC), and RDCON’s T_e, n_e input is a coefficient, not a coupling
reduced_model_ancestry Parent theory, model reduction and VAFT realization of every reduced mode; TGLF-NN descends from TGLF. Every row inherits its parent’s contract and adds a closure no contract covers

Reduced representations

How formulas compress plasma information, from fields to profiles to scalars and from dimensional to dimensionless quantities, is classified on Reduced representations (#1626). The figures are built from the formulas’ Reduction docstring sections and the relation metadata in vaft.formula._taxonomy.

vaft.diagram.reduced_representation_hierarchy()
vaft.diagram.reduced_representation_hierarchy_compact()
vaft.diagram.reduction_graph(family="current_q")   # "pressure_energy", "kinetic_profiles", "dimensionless_similarity"
Diagram Concept
reduced_representation_hierarchy Spatial reduction (field, profile, scalar) down, dimensionless normalisation across, so a dimensionless quantity can still be a profile. Each cell counts the catalogued formulas that land there
reduced_representation_hierarchy_compact The same axes and arrows with only the example symbols in each box, without the counts, at reduced box height and spacing, for slides and overview pages
reduction_graph One family as a layered graph of quantities. A solid edge is a formula, and its catalogued reduction kind is shown as via. A dashed edge is a step VAFT performs elsewhere

Tokamak geometry and flux coordinates

The parent geometry that the cylindrical and slab reductions start from. Surfaces are miller_surface, the shift is shafranov_shift_from_r_a_R0_beta_p_li, the field is vacuum_toroidal_field, and $\theta^*$ is straight_field_line_angle.

vaft.diagram.tokamak_torus(projection="3d")        # "poloidal"
vaft.diagram.flux_surfaces(shape="circular")       # "shifted"
vaft.diagram.shaping_family()
vaft.diagram.hfs_lfs_field()
vaft.diagram.safety_factor_winding(q=3)
vaft.diagram.flux_coordinates()
vaft.diagram.poloidal_angle_comparison()
vaft.diagram.unwrapped_flux_surface(q=2.5)
vaft.diagram.field_line_pitch(q=1.0)
   
torus cross-section
concentric Shafranov shift
HFS/LFS safety factor
flux coordinates theta vs theta*

field-line pitch

shaping

unwrapped surface

Diagram Concept
tokamak_torus $R_0$, $a$, $\phi$ (counter-clockwise from above) and $\theta$ (from the outboard midplane), with $R = R_0 + r\cos\theta$
flux_surfaces Concentric surfaces, then the Shafranov shift: $\Delta(r)$ is zero at the edge and largest on axis, so the magnetic axis sits outside the geometric axis
shaping_family Circular, $\kappa$, $\delta$, and both. Positive triangularity pulls the top in to $R_0 - \delta r$
hfs_lfs_field $B_\phi = B_0R_0/R$ is stronger on the inboard (high-field) side
field_line_pitch $\mathbf B = B_\phi\hat{\boldsymbol\phi} + B_\theta\hat{\boldsymbol\theta}$ at a point of a field line, with $B_\theta/B_\phi = r/(qR)$ so that $\mathbf B$ lies along the line
safety_factor_winding $q$ toroidal turns per poloidal turn, counted at one cross-section
flux_coordinates $(\psi, \theta, \phi)$, with $+\phi$ into the page when $R$ is to the right and $Z$ is up
poloidal_angle_comparison On a D shape, equal steps of $\theta^*$ are not rays of the geometric angle
unwrapped_flux_surface A field line is straight, $d\phi/d\theta^* = q$, in straight-field-line coordinates, and not in the parametrisation angle $\theta$

The field line on a torus, its cylindrical and slab reductions, and the geometry/ordering map are in the geometric-approximations section above. The toroidal → cylindrical → slab bridge is geometry_ordering_map together with field_line_geometry.

Toroidicity and TF ripple

From the $1/R$ mirror to ripple-induced fast-particle transport. The formulas are in vaft.formula.ripple, and each one names its diagram under See Also. $B_\phi \propto 1/R$ itself is hfs_lfs_field, in the tokamak-geometry section.

vaft.diagram.trapped_and_passing_orbits()
vaft.diagram.toroidal_field_ripple(n_tf=16)
vaft.diagram.ripple_well_formation()
vaft.diagram.stochastic_ripple_orbit()
   
trapped and passing TF ripple
ripple wells stochastic tips
Diagram Concept Formula
trapped_and_passing_orbits $\mu$ and energy conservation in $B \propto 1/R$: small pitches bounce as bananas, large ones pass parallel_speed_from_mu, vacuum_toroidal_field
toroidal_field_ripple $N_\mathrm{TF}$ coils corrugate $B(\phi)$: maximal under a coil, minimal between toroidal_ripple_field, ripple_amplitude
ripple_well_formation Along a field line the ripple makes local wells where $\alpha^* \lesssim 1$, near the midplanes (to first order in $\epsilon$) ripple_well_parameter
stochastic_ripple_orbit Ripple kicks at banana tips decorrelate above $\delta_\mathrm{GWB}$. Drawn as the standard map with $K \sim \delta/\delta_\mathrm{GWB}$ gwb_stochastic_threshold, gwb_stochasticity_parameter

These are regime indicators, not a loss calculation. Orbit following (ASCOT, NUBEAM) is the quantitative check. Low-$n$ error fields, NTV and locking are separate topics.

Guiding-centre invariants and toroidal symmetry

This is the global view of the orbit physics that curvature_drift and toroidal_drift show locally. The grad-B and curvature drifts say why a guiding centre moves at each instant. Conservation of $P_\phi$ constrains the whole orbit in an axisymmetric field. These are the same physics seen two ways, not competing explanations.

vaft.diagram.guiding_center_invariants()
vaft.diagram.canonical_toroidal_momentum(phase=0.45)
vaft.diagram.toroidal_symmetry_breaking()
   
invariants P_phi

symmetry breaking

Diagram Concept Formula
guiding_center_invariants Gyration, bounce and toroidal drift, with invariants $\mu$, $J_\parallel = \oint p_\parallel\,dl$ and $P_\phi$, valid for $\Omega_c \gg \omega_b \gg \omega_d$ magnetic_moment
canonical_toroidal_momentum A banana built from $\mu$ and $P_\phi$ conservation. From the bounce tip, $\Delta(q\psi)$ and $\Delta(mv_\parallel Rb_\phi)$ cancel, so $\psi$ moves with $v_\parallel$: this is the orbit width. phase is the state a future animation steps guiding_center_toroidal_momentum, parallel_speed_from_mu
toroidal_symmetry_breaking A 3-D field changes $P_\phi$. Away from resonance the change oscillates; where $\Delta\omega_\mathrm{BH} = 0$ it is secular bounce_harmonic_detuning

Conventions.

  • $P_\phi = mRv_\phi + qRA_\phi$ (canonical_toroidal_momentum) uses physical components and the IMAS $\phi$.
  • The guiding-centre form uses $\psi = RA_\phi$ in Wb per radian, largest on the axis for a current along $+\phi$. psi_per_radian_from_cocos converts a stored flux: $-\psi/2\pi$ for COCOS 11 (IMAS DD3) and $+\psi/2\pi$ for COCOS 17 (DD4). Used as stored, the flux has the wrong sign or a $2\pi$ error.
  • $J_\parallel$ is documented but deliberately not a numerical helper: its bounce interval and orientation depend on the orbit.
  • The drift of one orbit’s $P_\phi$ is not NTV. Torque and transport are #1111’s, and need the kinetic response of the whole distribution.

Straight-field-line coordinates

Straight field lines are a condition, not a coordinate system. The freedom the condition leaves is what PEST, Boozer, Hamada and equal-arc fix in different ways. All four are members of one generalised family, $\mathcal{J} \propto R^{p_R}/(B_p^{p_{Bp}}B^{p_B})$ (vaft.formula.generalized_straight_field_line_angle, as in DCON/GPEC). The unwrapped picture of a straight field line is unwrapped_flux_surface. Clebsch, field-aligned and ballooning coordinates are #1075’s.

vaft.diagram.sfl_coordinate_grids()
vaft.diagram.sfl_coordinate_taxonomy()
vaft.diagram.sfl_fourier_convergence()

grids

   
taxonomy spectra
Coordinate $(p_{Bp}, p_B, p_R)$ Geometric $\phi$ kept Also simplified Typical use
PEST $(0, 0, 2)$ yes the toroidal angle classical MHD stability
Boozer $(0, 2, 0)$ no ($\zeta = \phi + \nu$) $\mathcal{J} \propto B^{-2}$, the $B$ spectrum orbits, neoclassical, 3-D
Hamada $(0, 0, 0)$ no flux-function Jacobian; current lines straight too MHD stability
equal-arc $(1, 0, 0)$ no ($\zeta = \phi + \nu$) uniform poloidal sampling numerical representation
  • Same equilibrium, different grids. All four panels of sfl_coordinate_grids share one equilibrium: $R_0/a = 1.7$, $\kappa = 2$, $\delta = 0.45$. The surfaces are identical and only the angle changes. A test checks this.
  • Different Fourier costs. In sfl_fourier_convergence, one outboard-localised, axisymmetric perturbation needs anywhere from 9 to 26 poloidal harmonics, depending on the angle it is expanded in. Moved inboard, the ranking reverses: which angle is compact depends on where the structure sits. For $n \ne 0$, the toroidal shift $\nu$ of every angle except PEST couples harmonics further. The figure leaves that out.
  • Only PEST keeps $\phi$. Keeping the geometric $\phi$ forces $\mathcal{J} \propto R^2$, so every other member has $\zeta = \phi + \nu$.
  • Boozer ≈ PEST here. The two nearly coincide at this $B_p \ll B_\phi$, where $B^2 \propto R^{-2}$.
  • COCOS is not a coordinate choice. It fixes signs and orientations across every node of the taxonomy, independently of which angle is chosen.

Toroidal shift, action angles, validity, and COCOS

Every straight-field-line angle except PEST needs its own toroidal angle $\zeta = \phi + \nu$. vaft.formula.equilibrium.sfl_toroidal_angle_shift gives the shift as $\nu = q(\theta_\mathrm{sfl} - \theta_\mathrm{PEST})$, which follows from $d\phi = q\,d\theta_\mathrm{PEST}$ and $d\zeta = q\,d\theta_\mathrm{sfl}$ along a field line. For a toroidal mode number $n \neq 0$, a mode aligned with the nearest rational surface $q = m_0/n$, read at fixed $\zeta$, has in every angle the $n = 0$ spectrum moved to $m \approx m_0$ with its width unchanged. sfl_fourier_convergence(n=2) shows this: the shift $\nu$ is what keeps such a mode compact. A structure fixed in the geometric $\phi$ is instead moved by the angle-dependent $\nu$, and stays unshifted only in PEST (spectra_with_toroidal_mode).

  • field_line_action_angle follows one field line over a poloidal turn. Against the geometric angles $(\phi, \vartheta)$ it bends; against $(\zeta, \theta_\mathrm{PEST})$ it is the straight line of slope $1/q$. Nested surfaces make the field-line flow integrable, so SFL coordinates are its action-angle variables; the action is the toroidal flux, and the poloidal flux is the Hamiltonian. Canonical SFL coordinates, which also give the guiding-centre Hamiltonian its canonical form, stay a branch of sfl_coordinate_taxonomy; no transformation is implemented here.
  • sfl_coordinate_validity computes $|q|$ toward the last closed surface. On a limited Solov’ev equilibrium it settles; on a single-null one it grows as $-\ln(1 - \psi_N)$, because $B_p \to 0$ at the X-point and $\theta^*$ degenerates there. Islands and stochastic fields have no global surfaces at all (see magnetic_island and stochastic_layer).
  • coordinates_vs_cocos draws the coordinate choice and the COCOS convention as orthogonal axes: every combination is valid, and a coordinate system is not a COCOS convention.

DCON and GPEC use the generalized family (PEST, Boozer, Hamada, equal-arc, and $J \propto R^{p_R}/(B_p^{p_{B_p}} B^{p_B})$). An input or output handled in VAFT should therefore keep four things together: the coordinate type, its powers, the Fourier convention $e^{i(m\theta - n\zeta)}$, and where the mapping came from. Two analyses in different SFL coordinates describe the same equilibrium with different harmonic content. DCON output already keeps jac_type and the powers (vaft.code.gpec).

vaft.diagram.sfl_fourier_convergence(n=2)
vaft.diagram.field_line_action_angle()
vaft.diagram.sfl_coordinate_validity()
vaft.diagram.coordinates_vs_cocos()
   
n = 2 action angle
validity cocos

Clebsch labels and the ballooning representation

These figures go from straight-field-line coordinates to the local, field-aligned and ballooning descriptions that high-$n$ stability and turbulence models use. The formulas are field_line_label, s_alpha_curvature_drive and s_alpha_ballooning_solution in vaft.formula.stability, on the circular $s$–$\alpha$ model.

vaft.diagram.clebsch_field_line_label(q=2.5)
vaft.diagram.ballooning_curvature_drive()
vaft.diagram.ballooning_newcomb_test()
vaft.diagram.ballooning_harmonic_envelope(n=20)
vaft.diagram.ballooning_workflow()
   
Clebsch curvature
Newcomb test harmonics

workflow

Diagram Concept
clebsch_field_line_label A field line is where $\psi$ = const meets $\alpha = \phi - q\theta$ = const. In helical_phase’s left-handed $(\psi, \theta, \phi)$, with $\psi$ rising outward and $\mathbf B$ along $+\phi$, $\mathbf B \propto \nabla\psi\times\nabla\alpha$. Right-handed coordinates give the Connor–Hastie–Taylor form $\nabla\alpha\times\nabla\psi$
ballooning_curvature_drive Normal curvature $\cos\theta > 0$ (bad, outboard, shaded) once per $2\pi$ period of the covering space, and the total drive $K = \cos\theta + \Lambda\sin\theta$. Its outer lobes come from the geodesic term, which grows with the local shear. Also shown with $\theta_0$
ballooning_newcomb_test Newcomb’s test on the marginal solution $F(\theta)$: it stays positive (stable), crosses zero (unstable), or is positive again beyond $\alpha_2$ (second stability). These are not localised eigenfunctions
ballooning_harmonic_envelope $a_m = \hat F(m - nq)$ for a stated model envelope: many coupled harmonics around $nq$. Their sum oscillates at $m \approx nq$ under the envelope, localised outboard
ballooning_workflow Straight-field-line coordinates → field-line label → field-aligned → ballooning / flux tube, and the infinite-$n$ path. A finite-$n$ global calculation keeps what that path drops

The straight-field-line coordinates they start from are in the section above (sfl_coordinate_taxonomy). The resulting $(s, \alpha)$ stability diagram is s_alpha_ballooning.

Field-aligned basis, flux tube, shear, and the ballooning eigenfunction

  • field_aligned_basis unrolls one flux surface. Its field lines are the lines of constant $\alpha = \phi - q\theta$. With $x = \psi$, $y = \alpha$ and $z = \theta$, two coordinates are constant along $\mathbf B$, so $\mathbf B\cdot\nabla = (\mathbf B\cdot\nabla z)\,\partial_z$.
  • flux_tube_patch goes from a flux surface to one field line, then to its thin neighbourhood, then to the local $(x, y, z)$ box used by flux-tube gyrokinetic codes and by the sheared slab.
  • magnetic_shear_field_aligned follows a mode along the line. With $k_x = k_y\hat s\theta$ (ballooning_radial_wavenumber at $\alpha = 0$, the $\Lambda$ of the $s$-$\alpha$ model), its phase fronts rotate: the sheared slab’s $k_x(z) = k_{x0} + k_y\hat s z$, seen in the tokamak. The binormal period stays fixed, so the spacing across the fronts shrinks as $1/\sqrt{1+\hat s^2\theta^2}$; that growth of $k_\perp$ is the $(1+\Lambda^2)$ of line bending and inertia.
  • ballooning_eigenfunction solves the $s$-$\alpha$ equation with inertia on the extended angle (s_alpha_ballooning_eigenmode). An unstable surface has a mode peaked at the outboard midplane (bad curvature) that decays within a few transits; a stable surface has only the continuum.

  • ballooning_transit_map ties the extended angle to the cross-section: one poloidal circle per transit $k$, under $\theta = 2\pi k$, its outboard point (bad curvature) labelled with $F(2\pi k)$. The same point, revisited on every transit, carries less of the mode each time.
  • ballooning_boundary_conditions puts the two ways of closing the field line side by side. The ballooning representation requires decay on the covering space, $F \to 0$ as $|\theta| \to \infty$. A flux tube joins its ends after one poloidal turn, and because $k_x = k_y\hat s\theta$ the rejoined end has a shifted $k_x$: twist and shift, named and not derived.
  • field_aligned_xpoint_limitation draws lines of constant straight-field-line angle $\theta^$ ($d\theta^/dl \propto 1/(R^2B_p)$) on the diverted toy equilibrium of the Grad–Shafranov diagrams. They are evenly spread in the core and crowd into the X-point near the separatrix, where $B_p \to 0$ and $q \propto \oint dl/(R^2B_p)$ diverges; outside it the lines are open and X-point-adapted coordinates take over. See also sfl_coordinate_validity (#1074).
vaft.diagram.field_aligned_basis(q=2.5)
vaft.diagram.flux_tube_patch()
vaft.diagram.magnetic_shear_field_aligned(shear=1.0)
vaft.diagram.ballooning_eigenfunction()
vaft.diagram.ballooning_transit_map(transits=2)
vaft.diagram.ballooning_boundary_conditions(shear=1.0)
vaft.diagram.field_aligned_xpoint_limitation(n_theta=24)
   
basis eigenfunction

flux tube transits boundary conditions X-point limitation

shear

Ballooning formulations

How the reduced $s$–$\alpha$ equation follows from the general ballooning equation, and how DCON’s $C_A$ and GPEC.jl’s ballooning $\Delta’$ relate to it, is on Ballooning formulations (#1637).

vaft.diagram.ballooning_formulation_hierarchy()

ballooning formulations

Diagram Concept
ballooning_formulation_hierarchy The general equation either loses its geometry step by step (large aspect ratio, shifted circles, the $1 + \Lambda^2$ metric, the $\cos\theta + \Lambda\sin\theta$ curvature) to become the CHT equation VAFT solves, or keeps it, as DCON ($C_A$, stable when positive) and GPEC.jl ($\Delta’$, stable when negative, with poles) do. All three must share the normalisation of shear_from_volume and ballooning_alpha_from_volume before their boundaries can be compared

Slab resonant layers: tearing and twisting parity

How a global harmonic becomes a local layer response. The mapping $(m, n) \to (k_y, k_z)$ and $q = m/n \Leftrightarrow k_\parallel = 0$ is mode_number_mapping. The flux is vaft.formula.slab_perturbed_flux; its tearing form is the island pendulum of magnetic_island.

vaft.diagram.slab_parity(parity="tearing")   # "twisting"
vaft.diagram.slab_parity_comparison()
vaft.diagram.poloidal_harmonic_coupling(m=3)
vaft.diagram.resonant_layer_matching()

parity

   
coupling matching
Diagram Concept
slab_parity Contours of $\Psi_T = B_s’x^2/2 + \psi_0\cos k_yy$: an island of width $4\sqrt{\psi_0/B_s’}$, O- and X-points, and $\delta B_x(0) \ne 0$. Contours of $\Psi_W = B_s’x^2/2 + \psi_1x\cos k_yy$, drawn with its $O(\psi_1^2)$ completion: no normal field at the layer ($k_\parallel = 0$) and no reconnection, and every surface, the rational one included, displaced together by $\xi = -\psi_1\cos k_yy/B_s’$
slab_parity_comparison Both side by side, with the parity of $\tilde\psi$ and $\tilde\phi$, $\delta B_x(0)$ and the topology
poloidal_harmonic_coupling $\cos\theta$ (toroidicity) couples $m \to m \pm 1$ and $\cos 2\theta$ (elongation) couples $m \to m \pm 2$, at fixed $n$. The harmonic index $m$ is not the parity
resonant_layer_matching Every rational surface of one $n$ has a T and a W channel. The outer region couples them all into one $2N\times2N$ matrix (RDCON/STRIDE), and each layer is solved on its own (SLAYER)

Cylindrical geometry: profiles, mode shapes and matching

The screw-pinch picture between the torus and the slab. The profile is Wesson’s peaked current $j \propto (1 - x^2)^\nu$, given by peaked_current_safety_factor together with cylindrical_poloidal_field (Ampère). The screw-pinch field line is field_line_geometry("cylindrical"), and the cylinder-versus-torus harmonic contrast is poloidal_harmonic_coupling.

vaft.diagram.current_to_q_profile(nu=1.0, q_a=3.5)
vaft.diagram.cylindrical_rational_surfaces(n=1)
vaft.diagram.cylindrical_mode_morphology()
vaft.diagram.internal_external_kink()
vaft.diagram.plasma_vacuum_wall(m=2)
vaft.diagram.cylindrical_tearing_outer(m=2, n=1)

profiles

   
rational surfaces mode shapes
kinks wall

tearing outer

Diagram Concept
current_to_q_profile $j \to B_\theta \to q$. More peaked current means lower $q_0 = q_a/(\nu+1)$ and stronger shear
cylindrical_rational_surfaces For one $n$, one surface $q(r_s) = m/n$ for each $m$ between $q_0$ and $q_a$
cylindrical_mode_morphology $m = 0$ sausage, $m = 1$ kink (a rigid shift), $m = 2, 3$ helical distortions
internal_external_kink The $m = 1$ internal kink lives inside $q = 1$. An external kink reaches the boundary. Kruskal–Shafranov is a heuristic
plasma_vacuum_wall One harmonic matched across plasma, vacuum ($Ar^m + Br^{-m}$) and an ideal wall
cylindrical_tearing_outer The outer solutions at $r_s$ and their $\Delta’$, for the outer, ideal problem. The inner layer at $r_s$ is slab_parity

From the cylinder to the slab: mode_number_mapping expands $k_\parallel(r)$ about $r_s$ into the local slab of local_slab_from_cylinder, and resonant_layer_matching couples several such layers. The screw-pinch field line itself is field_line_geometry("cylindrical"), and the cylinder-vs-torus harmonic picture (independent $m$ vs toroidally coupled $m, m\pm1$) is poloidal_harmonic_coupling.

Current-profile and q topology

What the shape of the current does to the poloidal field, the internal inductance and the safety factor, and how the shape of $q$ decides how many rational surfaces one $m/n$ has (#1604). All four diagrams use one reduced model: a straight cylinder whose current is peaked ($j \propto (1 - x^2)^2$), broad ($1 - x^4$) or hollow / off-axis ($(0.1 + x^2)(1 - x^2)^{3/2}$), each normalized to the same $I_p$. The chain is cylindrical_enclosed_current, cylindrical_poloidal_field (Ampère), cylindrical_safety_factor_from_r_B, cylindrical_poloidal_flux (for $\psi_N$), cylindrical_internal_inductance and shear_from_r_q. The crossings come from vaft.process.equilibrium.find_rational_surfaces, the routine that finds them on a reconstructed $q$. These are concept figures, not equilibria and not stability results.

vaft.diagram.current_profile_shapes()
vaft.diagram.q_profile_topologies()
vaft.diagram.q_profile_landmarks(profile="monotonic")         # or "reversed_shear"
vaft.diagram.rational_surface_topology(profile="reversed_shear", m=2, n=1)

current-profile shapes

q topologies

   
q landmarks, monotonic q landmarks, reversed shear
one rational surface double rational surfaces
Diagram Concept
current_profile_shapes $j(r) \to I(r) \to B_\theta(r) \to l_i$ at fixed $I_p$. Peaked, broad and hollow are shapes of the current density. $l_i$ is one number for the whole profile: a more centrally enclosed current tends to a larger $l_i$, but different profiles can share one $l_i$
q_profile_topologies Peaked current gives a monotonic $q$, broad current a wide weak-shear core ($s \approx 0$), hollow current a reversed-shear $q$ with $s < 0$ inside $q_{\min}$. Every $q$ has $s \to 0$ on axis, so each column carries a narrow $s \approx 0$ band there; the width of the flat core is the discriminator. Not every hollow current reverses the shear
q_profile_landmarks $q_0$ on axis; $q_{\min}$, equal to $q_0$ only when $q$ is monotonic; $q_{95} = q(\psi_N = 0.95)$, which is not at $r/a = 0.95$; $q_a$, the boundary value of a cylinder or limited plasma. In a diverted equilibrium $q \to \infty$ at the separatrix, so $q_{95}$ is quoted. In the cylinder $q_a = q_\mathrm{cyl}$; in a shaped torus $q_{95}$ and the edge $q$ differ from $q_\mathrm{cyl}$ and $q^*$
rational_surface_topology A monotonic $q$ crosses one $m/n$ once. A reversed-shear $q$ can cross it twice, $q(r_1) = q(r_2) = m/n$ with $r_1 < r_{\min} < r_2$: a double-resonant configuration. A double tearing mode is the instability in which tearing layers on the two surfaces couple, and only a stability calculation can say whether it grows

These diagrams sit upstream of the others. current_to_q_profile keeps the analytic peaked family $j \propto (1 - x^2)^\nu$ and cylindrical_rational_surfaces the monotonic surfaces of one $n$ (#1072). rational_surface keeps the single-crossing definition, and delta_prime and tearing_layer_matching follow it (#1039). The $l_i$–$q$ diagrams of li_qa (#1603) are operating spaces: one scalar $l_i$ against one scalar edge $q$, from the literature. They are not plots of a current profile. The data-side counterparts are vaft.plot.equilibrium_profile_j_tor and equilibrium_profile_q (#1505).

Current diffusion and current drive

How the current-density and safety-factor profiles above form in time (#1605). Both diagrams evolve one reduced model: the enclosed current $I(\rho, t)$ of a straight cylinder under cylindrical_current_diffusion_rate (Faraday, Ampère and Ohm’s law with a non-inductive source $j_\mathrm{ni}$), integrated implicitly. The resistivity is a fixed Spitzer $\eta(\rho)$ (spitzer_resistivity_from_T_e_Z_eff_ln_Lambda) on a hot-core, cold-edge $T_e(\rho)$, and time is in units of the core resistive_diffusion_time $\tau_R = \mu_0 a^2/\eta(0)$. The profiles are representative, not universal: there is no transport, bootstrap current or toroidal geometry.

vaft.diagram.current_diffusion()
vaft.diagram.current_drive_profiles(deposition="off_axis")   # or "on_axis"

current diffusion

   
current drive, off axis current drive, on axis
Diagram Concept
current_diffusion A fast ohmic ramp, $t_\mathrm{ramp} = 0.01\,\tau_R \ll \tau_R$ (the ordering of a fast ramp such as VEST’s; the ratio is illustrative), leaves the current in an off-axis shell, depleted at the cold edge: hollow $j_\phi$, $q_{\min}$ off axis and $s < 0$ inside it. The current then penetrates and relaxes towards $j_\phi \propto 1/\eta$ with one $E_\phi$ across the radius. The relaxed profile is peaked only because the core is hotter; with a uniform $\eta$ (dashed) the same diffusion relaxes to a flat current
current_drive_profiles Ohmic, ECCD and NBCD rows: actuator, the source $j_\mathrm{drive}(\rho)$ it drives, the total $j_\phi(\rho, t)$ before, shortly after and long after switch-on, and $q(\rho, t)$. The driven source persists where it is deposited while the ohmic current around it readjusts resistively; the source itself does not diffuse. ECCD is narrow and modifies the local shear; NBCD is broad. NBI’s pressure, rotation, fast-ion and bootstrap effects and counter-drive are not drawn

Field configurations, reconnection and MHD waves

The canonical slab configurations, the topology of reconnection, and the linear ideal-MHD waves. All are drawn in the slab frame of vaft.formula.geometry: $x$ is the sheet normal (radial), $y$ the reconnecting (binormal) direction, and $z$ the current and guide-field direction. The geometry itself (slab, sheared slab, cylinder, torus) belongs to Geometric approximations. The formulas are harris_sheet_field, harris_sheet_current_density and x_point_flux in geometry, and shear_alfven_frequency and magnetosonic_phase_speeds in stability.

vaft.diagram.slab_field_configuration(kind="sheared")   # "uniform", "reversed", "guide"
vaft.diagram.current_sheet(guide_field=False)
vaft.diagram.harris_sheet()
vaft.diagram.x_point()
vaft.diagram.magnetic_reconnection()
vaft.diagram.island_formation()
vaft.diagram.shear_alfven_wave()
vaft.diagram.fast_magnetosonic_wave()
vaft.diagram.mhd_wave_family()
   
sheared reversed
sheet harris
x-point reconnection
shear Alfven fast

island formation

wave family

Diagram Concept
slab_field_configuration The field on stacked $x$ = const sheets. Uniform; sheared, where the direction rotates and $\lvert\mathbf B\rvert = B_0$ to first order in $x/L_s$; reversed, where $B_y(-x) = -B_y(x)$ with a null at $x = 0$; and reversed with a guide field $B_g$, which rotates with no null. Shear and reversal are different things
current_sheet The reversing Harris field seen along the current, with lines at equal flux spacing (spacing $\propto 1/\lvert B_y\rvert$), the sheet of thickness $2a$, its normal, and $\otimes J_z$. With guide_field=True, $B_g\hat{\mathbf z}$ removes the null and leaves $J_z$ unchanged
harris_sheet $B_y = B_0\tanh(x/a)$ and $J_z = (B_0/\mu_0a)\,\mathrm{sech}^2(x/a)$ on one chart: the reversal and the localized current are the same layer
x_point The current-free null $\psi = B’(x^2 - y^2)/2$: four branches and two separatrices at right angles. Geometry only
magnetic_reconnection Model-neutral reconnection: inflow, outflow jets, diffusion region, upstream and reconnected field lines about a stretched X-point. No Sweet–Parker, Petschek, Hall or kinetic assumption
island_formation slab_perturbed_flux with growing $\psi_0$: straight sheared lines, then X- and O-points, then an island of width $w = 4\sqrt{\psi_0/B’}$. The growth is delta_prime, slab_parity and tearing_layer_matching
shear_alfven_wave Field-line bending with equally spaced lines, so $\lvert\mathbf B\rvert$ is unchanged to first order. $\delta\mathbf v_\perp$ and $\delta\mathbf B_\perp = -(B_0/v_A)\delta\mathbf v_\perp$ lie normal to the $\mathbf k$-$\mathbf B_0$ plane, and $\omega = \lvert k_\parallel\rvert v_A$
fast_magnetosonic_wave At $\mathbf k \perp \mathbf B_0$ the lines bunch and spread, $\delta B_z = -B_0\partial_x\xi_x$, and $v_f = (v_A^2 + c_s^2)^{1/2}$. It is the compressional Alfvén wave only in the limit $c_s \ll v_A$
mhd_wave_family The Friedrichs diagram of fast, shear-Alfvén and slow phase speeds against the angle to $\mathbf B_0$ ($v_s \le v_A\lvert\cos\theta\rvert \le v_f$), with each branch’s restoring force, compressibility and polarization

From these to the tokamak: the current sheet and the island lead to the tearing layer (slab_parity), then to the cylindrical and toroidal tearing mode (delta_prime, resonant_layer_matching). Here $q(r_s) = m/n$ globally is $k_\parallel = 0$ locally (mode_number_mapping). The uniform-slab shear Alfvén wave leads to the Alfvén continuum, where $v_A(r)$ and $k_\parallel(r)$ vary. Toroidal coupling (poloidal_harmonic_coupling) then opens the gaps of the TAE and EAE. Those are not computed here.

The Grad–Shafranov problem: regions, boundaries and problem classes

The axisymmetric field is $\mathbf B = R^{-1}\nabla\psi\times\hat{\boldsymbol\phi} + F(\psi)R^{-1}\hat{\boldsymbol\phi}$, with $\psi$ the poloidal flux per radian and $F = RB_\phi$ the poloidal-current function. Its components are radial_magnetic_field_from_psi and vertical_magnetic_field_from_psi (COCOS-aware); in vacuum $F$ is constant, and $B_\phi = F/R$ is vacuum_toroidal_field. One flux function $\psi(R, Z)$ is solved across the plasma, vacuum and coil regions, each with its own source. vaft.formula.grad_shafranov_source gives the Ampère form $\Delta^*\psi = -\mu_0RJ_\phi$, which holds in every region. toroidal_current_density_from_p_prime_ff_prime gives the plasma current that force balance allows, $J_\phi = Rp’ + FF’/(\mu_0R)$. On a grid, the operator is vaft.process.equilibrium.grad_shafranov_operator. The flux maps are a toy: prescribed ring currents and three coils superposed through green_psi_exact. The topology (axis, X-point, limiter contact, LCFS) is then found from the total flux, as a free-boundary code finds it. A production solver would also make the plasma current consistent with $p’$ and $FF’$.

vaft.diagram.grad_shafranov_domain_decomposition()
vaft.diagram.fixed_vs_free_boundary_equilibrium()
vaft.diagram.limiter_and_diverted_topologies()
vaft.diagram.equilibrium_problem_taxonomy()
vaft.diagram.poloidal_flux_source_decomposition()

domains

fixed vs free

topologies

taxonomy

sources

Diagram Concept
grad_shafranov_domain_decomposition Same $\psi$, different $J_\phi$. The plasma source comes from force balance. The vacuum is homogeneous, $\Delta^*\psi = 0$: Laplace-type, but not $\nabla^2$. A coil carries its prescribed current. All of this sits inside the computational boundary
fixed_vs_free_boundary_equilibrium The boundary is an input (LCFS and $\psi_b$ given, only the inside solved) or it is part of the solution (coils and sources given, $\psi$ everywhere, LCFS read from the topology)
limiter_and_diverted_topologies Limited: the LCFS is the surface through the limiter tip. Diverted: the separatrix through the X-point ($\nabla\psi = 0$), with SOL and private flux. The boundary is the larger of $\psi_\mathrm{lim}$ and $\psi_X$
equilibrium_problem_taxonomy Forward/inverse and fixed/free are separate axes. CHEASE is forward and fixed, TokaMaker forward and free, EFIT inverse and free. Free boundary and inverse are not synonyms
poloidal_flux_source_decomposition $\psi_\mathrm{plasma} + \psi_\mathrm{coil} = \psi_\mathrm{total}$. Only the sum has the X-point and the LCFS. $\psi_\mathrm{passive}$ (eddy currents) is a further term, not drawn

Equilibrium-aware phenomena: kink displacement and sawtooth

This layer sits between the reference diagrams and result plotting. The geometry comes from an equilibrium (any vaft.data.equilibrium.EquilibriumData); the physical state is a prescribed, documented model. The default equilibrium is the exact Solov’ev (Cerfon–Freidberg) equilibrium of vaft.process.equilibrium.solovev_example with $A = 0$, where $q$ rises from about 0.8 to 3. Surfaces, normals and the PEST angle $\theta^$ come from straight_field_line_map, and $q(\rho)$ from calculate_q_profile_from_psi, with $\rho = \sqrt{\psi_N}$. The mode phase uses $\theta^$. The drawing uses the real $(R, Z)$ surfaces.

vaft.diagram.kink_mode(equilibrium=None, m=1, n=1, amplitude=0.06, radial_profile="internal")
vaft.diagram.kink_mode(m=2, n=1, radial_profile="global", harmonics={2: 1.0, 3: 0.3})
vaft.diagram.sawtooth(stage="precursor")   # "reconnection", "post_crash"
   
1/1 internal 2/1 global

precursor

   
reconnection post crash
Diagram Model class Concept
kink_mode synthetic parameterization Each surface moves along its normal by $\xi_n = A\,a\,F(\rho)\,\mathrm{Re}\sum c_m e^{i(m\theta^* - n\phi)}$, with a named envelope. internal is a top hat inside $q = m/n$, global is $\rho^{m-1}$, and edge is $\rho^{4m}$. Under flux freezing this is flux_perturbation_from_normal_displacement, $\delta\psi = -\xi_n\lvert\nabla\psi\rvert$. It is not an eigenfunction. The cylindrical reference view is internal_external_kink
sawtooth reduced model precursor: the 1/1 internal kink inside $q = 1$, with nested topology kept. reconnection: a hot core of radius $\rho_1(1-f)$ pushed against an outer separatrix, with the X-point where they touch and the 1/1 island in the crescent between. post_crash: nested surfaces again, with the region inside the Kadomtsev mixing radius flattened at conserved $\int T\rho\,d\rho$

Two reduced Hamiltonian models extend the vocabulary of magnetic_island to several resonances, and to the X-point.

vaft.diagram.stochastic_layer(regime="touching")   # "isolated", "overlapping"; or overlap=, perturbations=
vaft.diagram.separatrix_lobes(perturbation=0.02, m=8, n=4)       # or separatrix_lobes(equilibrium, ...)
   
isolated overlapping

touching

lobes

Diagram Model class Concept
stochastic_layer reduced Hamiltonian A Poincaré section of $H = \int\iota\,d\psi_N - \sum_k\epsilon_k\cos(m_k\theta^* - n_k\phi)$ on the equilibrium’s $q$ (default 3/2 and 2/1). Each resonance alone is the pendulum of island_pendulum_hamiltonian, width $4\sqrt{\epsilon/\lvert\iota’\rvert}$. The pair overlap $\sigma$ (vaft.process.perturbation.chirikov) is 0.5, 1 or 1.6. The inset shows where the section sits
separatrix_lobes reduced Hamiltonian A lower-single-null equilibrium (by default the single-null Solov’ev) plus a prescribed $\delta\psi \propto (r/r_X)^m\cos(m\vartheta - n\phi)$. The field-line map over $2\pi/n$ has a hyperbolic fixed point (Newton, multipliers $\lambda$ and $1/\lambda$). Its unstable and stable manifolds split from the unperturbed separatrix and cross each other, which makes lobes, and one strike point on the target becomes several

In stochastic_layer, $x = \psi_N$ stands in for the toroidal-flux action, so $\epsilon$ is a model amplitude and area in the section is not flux. separatrix_lobes takes any lower-single-null EquilibriumData: the X-point must be a saddle of the flux on the boundary value, below the axis, and the window scales with the minor radius; a limited equilibrium is refused. Neither diagram is a GPEC, MARS or vacuum-field trace: those belong to result plotting.

The mixing radius comes from vaft.formula.kadomtsev_mixing_radius: the 1/1 helical flux $\psi_* \propto \int r(1/q - 1)\,dr$ returns to its axis value there. It equals $\sqrt2\,r_1$ when $1/q - 1$ is parabolic. Complete (Kadomtsev) reconnection is the $f \to 1$ limit, not a claim about every crash.

MARFE

marfe puts a prescribed radiation condensation on the edge of an equilibrium and shows the condition that makes it.

  • On the high-field side (localization="hfs", the usual location) the band straddles the last closed surface. It is about 30° wide poloidally and 0.1$a$ deep, as Lipschultz (1987) reports.
  • Next to the X-point ("xpoint", Greenwald 2002 p. R35) the band is drawn on the closed side with the same sizes, which are borrowed, not measured there.
  • Its $T_e$ is below about 10 eV (Greenwald p. R34), and it is toroidally symmetric: a ring.

The right panel is Drake’s (1987) constant-pressure criterion in dimensionless form, computed from vaft.formula.sol.radiative_condensation_growth_rate. For $k_\parallel > 0$ the boundary is $k_\parallel^2\kappa_\parallel T/L = 2 - \partial\ln L/\partial\ln T$, so condensation does not need a falling radiation curve. On the $k_\parallel = 0$ axis only the constant-density flute limit (radiative_thermal_instability_growth_rate) applies, and it is unstable where $L$ falls with $T$.

The band is prescribed, not solved, and no cooling curve or density-limit formula is built in; MARFE onset and density-limit semantics belong to #1068. The API names its sizes poloidal_width_deg and radial_fraction; the issue’s "prescribed" localization is not implemented.

vaft.diagram.marfe(localization="hfs")      # or "xpoint"; poloidal_width_deg=30, radial_fraction=0.1
   
marfe marfe x-point

Divertor heat-flux footprint

divertor_heat_footprint maps an Eich target profile onto a diverted equilibrium. The geometry comes from the equilibrium itself: the X-point is the zero of $\nabla\psi$ next to the lowest boundary point, the strike point is where the separatrix leg crosses a horizontal target, and the total flux expansion $f_x = (\partial\psi/\partial R)\mathrm{OMP} / (\partial\psi/\partial s)\mathrm{target}$ is evaluated on the flux, not assumed. The profile is vaft.formula.sol.eich_target_heat_flux_profile with that $f_x$. $\lambda_q$ (at the outer midplane) and $S$ (at the target) are illustrative inputs: this is a schematic, and measured IR profiles belong in vaft.plot. The SOL surfaces one, two and three $\lambda_q$ outside the separatrix at the midplane fan out to about $k\lambda_q f_x$ on the target. The equilibrium must be lower single null, with an X-point on its boundary flux and legs that reach the target inside the limiter; anything else is refused rather than drawn.

vaft.diagram.divertor_heat_footprint(lambda_q=0.004, spreading=0.0015, target="outer")

footprint

Disruption physics: quench sequence, runaways and energy paths

The chain from loss of confinement to a runaway plateau, each link a relation in the new vaft.formula.disruption category or an existing one:

  • thermal_quench_temperature, current_quench_current and inductive_parallel_electric_field;
  • connor_hastie_critical_field, dreicer_field, runaway_critical_momentum and relativistic_collision_time;
  • dreicer_generation_rate, avalanche_growth_rate, avalanche_efolds_from_current_drop and runaway_current_from_density;
  • the Spitzer resistivity, and the startup plasma resistance, inductance and L/R time.

Detecting a disruption in data stays in vaft.process.transients. Simulating one belongs to kinetic or integrated codes.

vaft.diagram.disruption_timeline()
vaft.diagram.disruption_causal_chain()
vaft.diagram.runaway_generation()
vaft.diagram.disruption_energy_pathways()

timeline

causal chain

   
runaway generation energy
Diagram Concept
disruption_timeline A 0-D reference model built from the formulas. A prescribed thermal quench raises the Spitzer $\eta$. The L/R current quench then induces $E_\parallel \approx 10^3E_c$ ($\approx 2\,\%$ of $E_D$). A Dreicer seed of a few kA is multiplied about 25-fold by the avalanche (at 1 MA, only a few e-folds) into a runaway plateau. Magnitudes are illustrative: no universal waveform
disruption_causal_chain The same sequence as cause and effect, each arrow labelled by its formula
runaway_generation The avalanche rate (per runaway) and the Dreicer rate (per electron) against $E/E_c$. The normalisations differ, so the two magnitudes are not compared. Nothing runs away below $E_c$, and Dreicer is drawn only within its asymptotic range, $E \le 0.1E_D$. Hot-tail seeding is not drawn
disruption_energy_pathways Thermal energy leaves by conduction and radiation. Magnetic energy $\tfrac12L_pI_p^2$ goes to ohmic heating, the vessel and coils, runaway kinetic energy and halo currents (#1042). The existing thermal_energy_from_p_V, virial_thermal_energy and magnetic_energy_from_li_B_pa_V_p compute the two pools

Vertical displacement events: hot and cold VDE, halo currents

A hot VDE moves a still-hot plasma into the wall, and the scraping can trigger the thermal quench. A cold VDE follows the quench, as the decaying current loses its centred vertical equilibrium. Wall contact then drives halo currents through the scrape-off layer and the wall. The model-neutral reference quantities are in the new vaft.formula.vde category:

  • vertical_velocity and vde_growth_rate (a local $d\ln\lvert\Delta Z\rvert/dt$);
  • thin_wall_time and wall_mode_decay_time;
  • halo_current_fraction and toroidal_peaking_factor.

A wall element’s $L/R$ is lr_time_from_L_R. The named reduced VDE models (edge-current loss, filament-plus-wall, analytic halo) are not chosen yet. The disruption chain these diagrams couple to is vaft.formula.disruption.

vaft.diagram.hot_vde_sequence()
vaft.diagram.cold_vde_bifurcation()
vaft.diagram.plasma_wall_halo_current()
vaft.diagram.vde_timescales()

hot VDE

   
cold VDE halo

timescales

Diagram Concept
hot_vde_sequence The Solov’ev plasma moved 0, 8 and 16 cm into its limiter. The limiting surface shrinks, so the edge moves inward to lower $q$ (the equilibrium’s own profile; the cylindrical estimate at fixed $I_p$ falls as $a^2$). Below, the causal chain towards the thermal quench
cold_vde_bifurcation A schematic normal form: below a critical current the centred equilibrium is lost, and the plasma follows an off-centre branch into the wall as $I_p$ decays. The real branches come from a model not chosen here
plasma_wall_halo_current Poloidal halo current through the scrape-off layer and the wall, toroidal eddy currents in the wall, and $\mathbf J_\mathrm{halo}\times\mathbf B_\phi$ on the floor, for one sign of $I_p$ and $B_\phi$
vde_timescales $a/v_A$, the $m = 1$ wall time, and the L/R current-quench time at 5 and 20 eV for one medium-tokamak parameter set. The ordering is not universal

Plasma-wall interaction

The plasma-wall vocabulary: one impact and its outcomes, reflection (particle versus energy), physical sputtering, recycling versus retention, and particle versus energy balance. This is level 0 of the issue’s enrichment, semantics only. No reflection or sputtering coefficient, yield or threshold is drawn unless it is computed by a vaft.formula.pwi relation from inputs the caller supplies:

  • binary_collision_energy_transfer_factor, the exact elastic kinematics;
  • mean_reflected_energy_fraction, which is $R_E/R_N$;
  • recycling_coefficient;
  • sputtering_threshold_bohdansky, a named empirical fit that needs the surface binding energy.

Projectile and target species go through vaft.data.atomic and are drawn apart: projectile blue, target dark. Each diagram’s model names the IMAS paths of the quantities it shows, under wall.global_quantities.neutral[:]: the recycling particle and energy coefficients, the fluxes from the plasma and from the wall, the wall inventory, and the per-incident-species sputtering coefficients. IMAS’s recycling energy coefficient covers all recycling channels, so it is not the prompt-reflection $R_E$. The canonical sputtering figure uses $E_s = 8.68$ eV, the sublimation energy of W, as a stated input.

vaft.diagram.plasma_wall_interaction_processes(projectile="D", target="W")
vaft.diagram.plasma_wall_interaction_reflection()
vaft.diagram.plasma_wall_interaction_sputtering(surface_binding_energy=8.68)   # threshold only if E_s given
vaft.diagram.plasma_wall_interaction_recycling()
vaft.diagram.plasma_wall_interaction_energy_partition()
vaft.diagram.plasma_wall_interaction_reflection_energy()
vaft.diagram.plasma_wall_interaction_angle_dependence()
vaft.diagram.plasma_wall_interaction_sputtering_threshold(surface_binding_energy=8.68)   # E_th only if E_s given
vaft.diagram.plasma_wall_interaction_particle_balance()
vaft.diagram.plasma_wall_interaction_surface_response()

processes

   
reflection sputtering
recycling energy
reflected energy angle
threshold particle balance

surface response

Diagram Concept
plasma_wall_interaction_processes Reflection (fast atom), implantation and retention, re-emission (thermal molecule), sputtering (target atom), and heat
plasma_wall_interaction_reflection $E_\mathrm{in}$, $E_\mathrm{refl}$, $\theta_\mathrm{in}$ and $\theta_\mathrm{refl}$ as separate quantities; $R_N$ is not $R_E$
plasma_wall_interaction_sputtering A collision cascade ejects a target atom. One collision passes at most $\gamma E$ (D on W: $\gamma = 0.043$), hence the high threshold
plasma_wall_interaction_recycling Prompt reflection plus delayed re-emission make recycling; retention is the rest
plasma_wall_interaction_energy_partition Particle balance and energy balance side by side. They are not the same bookkeeping
plasma_wall_interaction_reflection_energy Incident $f_i(E_i)$ to reflected $f_r(E_r)$ through the surface. Only the binary-collision limit $(1-\gamma)E_i$ is stated; $R_N(E_i)$, $R_E(E_i)$, $\langle E_r\rangle(E_i)$ are empty enrichment slots
plasma_wall_interaction_angle_dependence Normal and grazing incidence, angles from the surface normal; $R_N$, $R_E$, $Y$ as functions of $(E_i, \theta_i)$ are named, not drawn
plasma_wall_interaction_sputtering_threshold A schematic $Y(E_i)$ with no scale: a threshold exists. $E_\mathrm{th}$ is printed only for a supplied $E_s$ (Bohdansky)
plasma_wall_interaction_particle_balance The projectile balance (reflected + re-emitted + retained) with the sputtered target atoms drawn apart, as another species’ source
plasma_wall_interaction_surface_response Inputs, surface response ($R_N$, $R_E$, $Y_\mathrm{sput}$), outputs: the extension point for tabulated data or an external PWI code (levels 2–4)

Spectroscopy and ionization

Concept diagrams in the vocabulary of vaft.data.atomic and vaft.data.spectroscopy. parse_emission_term and parse_line_label are the same parsers emission= uses in vaft.plot, so a term that selects a trace selects the same diagram. Metadata is progressive, and nothing is fabricated:

  • level 0 is the semantic identity (stage, charge, element);
  • level 1 is what the data declare (the wavelength in an IMAS processed_line label such as OI_7770);
  • hydrogenic lines add Bohr-model levels and Rydberg vacuum wavelengths with the isotope’s reduced mass (hydrogenic_energy_level and hydrogenic_transition_wavelength in vaft.formula.atomic). For one-electron systems this model is the authoritative source; each model records it under source;
  • many-electron levels and photon emissivities would need OPEN-ADAS ADF04 and ADF15. Those are extension points and are not loaded; ADF11 stays in vaft.formula.atomic.
vaft.diagram.spectroscopy_ionization_stages("C III")   # "C2+", "carbon", "CIII_1909" too
vaft.diagram.spectroscopy_transitions("H-alpha")        # "OI_7770": declared wavelength only
vaft.diagram.spectroscopy_energy_levels("D-alpha")
vaft.diagram.spectroscopy_spectrum()                    # the labels VEST's spectrometer declares

stages

   
H-alpha O I

levels

spectrum

Diagram Concept
spectroscopy_ionization_stages Every stage of an element, with the named one outlined. Stage $s$ is charge $s - 1$, and D and T are hydrogen with a mass number. Semantic only
spectroscopy_transitions A hydrogen series member gets Bohr-model levels and its vacuum wavelength (an unspecified isotope is taken as protium, and the title says so). Fully stripped ions are refused, since they have no lines. Any other line gets unnamed levels, and a wavelength only if its label declares one
spectroscopy_energy_levels The hydrogenic ladder with the Lyman, Balmer and Paschen series. Hydrogenic only: other species need ADF04
spectroscopy_spectrum Declared lines, each at its label’s wavelength (air above 200 nm by convention). Computed hydrogenic lines are dashed and in vacuum. Lines with no wavelength are listed, not placed

Neutral beam injection: lifecycle and reduced attenuation

A small, machine-independent NBI layer. It is not NUBEAM, ASCOT5 or BEAMS3D, and it never replaces vaft.code.nubeam.

  • Formulas (vaft.formula.nbi): beam_particle_rate_from_power_energy (per energy component, in eV), neutral_beam_optical_depth, neutral_survival_fraction_from_optical_depth, beam_birth_probability_density (a density along the path, not a volumetric deposition), shine_through_fraction, and injected_toroidal_angular_momentum_rate. The last is the ideal rate carried in, not the torque on the plasma.
  • Process (vaft.process.nbi.neutral_beam_attenuation_along_path): composes these along a prescribed 1-D path and adds the particle and power bookkeeping. Births are counted per path cell as $S_i - S_{i+1}$, so $\sum_i + f_\mathrm{shine} = 1$ and $P_\mathrm{birth} + P_\mathrm{shine} = P_\mathrm{injected}$ hold exactly on any grid. The “power birth profile” is where neutrals become fast ions, not where the plasma is heated. The process module’s docstring tabulates what this layer answers and what needs a full solver; related work is #265 (VEST NBI description), #592 (NUBEAM → IMAS), #1064 and #1092 (scales, orbits).

The attenuation coefficient $\alpha = \sum_j n_j\sigma_j$ is always an input; no beam-stopping data are built in. Orbits, trapped and passing fast ions, and $P_\phi$ are the particle-motion diagrams’, and are not redrawn here.

vaft.diagram.nbi_particle_lifecycle()      # shine-through / prompt loss / delayed loss kept apart
vaft.diagram.nbi_neutral_attenuation()     # S(s), b(s), births and f_shine from vaft.formula.nbi

Iteration behaviour, branch bifurcation and branch selection

Non-convergence can arise from true branch structure or from numerical cycling. A solver that does not converge has not necessarily found an unphysical solution, and these diagrams separate the cases. They are generic concept diagrams for EFIT convergence, grid, weighting and continuation studies. No shot, residual or grid comparison is shown or implied, and none of them claims that a physical bifurcation exists in VEST equilibria.

Every curve is computed:

  • the iteration panels come from the logistic map $x_{k+1} = rx_k(1 - x_k)$ at $r = 2.8$, $3.2$ and $3.5$, and from an expanding linear map;
  • the branch diagram is the saddle-node normal form $\dot x = \lambda + x - x^3$;
  • the basins are its exact relaxation at $\lambda = 0$.

The bifurcation is drawn once. The basin diagram is the same model at one control parameter, not a second bifurcation figure.

vaft.diagram.iteration_behavior()       # fixed point, divergence, 2-cycle, period-4 limit cycle
vaft.diagram.branch_bifurcation()       # stable (solid) / unstable (dashed), folds, jumps, hysteresis
vaft.diagram.basin_of_attraction()      # initial condition selects branch A or B
vaft.diagram.grid_induced_two_cycle()   # each re-solve lands nearer the other node: a one-cell hop
vaft.diagram.branch_selection()         # the last two side by side under one caption

iteration

   
bifurcation basin

branch selection

Diagram Concept
iteration_behavior $x_k$ against $k$ in one format. The fixed point $x^*$ (thin line) exists in every panel but is stable only in the first; guides mark the four levels of the period-4 cycle
branch_bifurcation Stable and unstable branches, the two folds, the jump at each fold, and the hysteresis loop; three equilibria coexist between the folds
basin_of_attraction Two stable solutions at one control parameter. The unstable equilibrium is the basin boundary, and the start decides the branch
grid_induced_two_cycle A numerical artifact. Solved from A the optimum lands nearer B, and from B nearer A, so the index hops by one grid cell and the pattern changes with the grid. The fit stays nearly flat (a secondary cue). It is not a second physical branch
branch_selection basin_of_attraction beside grid_induced_two_cycle: physical branch structure against numerical cycling

Cold-plasma waves: dispersion, cutoffs, resonances and the CMA diagram

Each diagram is drawn from the cold-plasma equations in vaft.formula.waves:

  • plasma_frequency;
  • stix_parameters, giving $R, L, S, D, P$ with the signed cyclotron frequency, so $\Omega_e < 0$, and dielectric_tensor;
  • cold_plasma_refractive_index_squared, the two roots of $An^4 - Bn^2 + C = 0$, in a cancellation-free form that keeps the finite root at a resonance cone;
  • perpendicular_refractive_index_squared, giving $n_O^2 = P$ and $n_X^2 = RL/S$;
  • cma_coordinates, giving $X = \omega_{pe}^2/\omega^2$ and $Y = \Omega_e /\omega$;
  • propagation_regime, which classifies propagating, evanescent, cutoff and resonance.

Boundaries are zeros or poles of the Stix parameters, located by bracketing the formulas; no closed form is typed into a drawing. The $\pm$ roots are algebraic branches, not mode names, so O/X and R/L are named only where the mode is tracked: at $\theta = \pi/2$ and $\theta = 0$. Electrons only, ions immobile: the electron-cyclotron range. Warm-plasma effects, damping, ray tracing and full-wave solutions are out of scope.

import math

vaft.diagram.o_mode_cutoff()                                  # n_O^2 = P, cutoff at omega_pe
vaft.diagram.x_mode_dispersion(omega_pe_over_omega_ce=1.2)    # L, R cutoffs; upper-hybrid resonance
vaft.diagram.cma_diagram()                                    # P, R, L, S = 0 and Y = 1 in (X, Y)
vaft.diagram.profile_propagation()                            # layers along an example midplane
vaft.diagram.profile_propagation(theta=math.radians(60))      # oblique: both roots, A = 0 resonances
vaft.diagram.wave_dispersion_omega_k(omega_pe_over_omega_ce=1.2)  # branches in the omega-k plane
vaft.diagram.refractive_index_vs_X(Y=0.5)                     # rising density at fixed field
vaft.diagram.refractive_index_vs_Y(X=0.5)                     # rising field at fixed density

Every view takes theta, from $5^\circ$ to $\pi/2$ (below that, parallel propagation is the picture). At $\theta = \pi/2$ the branches are named O (blue) and X (red). At any other angle both roots of cold_plasma_refractive_index_squared are drawn in one colour, because the algebraic $\pm$ branches swap at the cyclotron layer, and the resonance moves from $S = 0$ to the cone $A = S\sin^2\theta + P\cos^2\theta = 0$, which is marked.

Neoclassical and NTV collisionality regimes

Two different regime families that share the word “collisionality”. Axisymmetric neoclassical transport orders the collision frequency against the transit and bounce frequencies. Neoclassical toroidal viscosity (NTV) in broken symmetry orders it against the bounce-averaged precession $\omega_d = \omega_E + \omega_B$:

Coulomb collisions -> transit / bounce motion -> nu_hat = qR nu/v -> banana / plateau / Pfirsch-Schlueter
3-D delta B + precession omega_d -> 1/nu / nu-sqrt(nu) / superbanana-plateau / nu -> NTV torque

The axis of the first diagram is $\hat\nu = qR_0\nu/v$ (collisions_per_transit), not a $\nu_$. VAFT’s several $\nu_$ conventions (issue 353) share the symbol but not the value. The boundaries $\hat\nu = \epsilon^{3/2}$ and $1$ come from neoclassical_regime_boundaries. The orbit scales behind them are transit_frequency, deeply_trapped_bounce_frequency, trapped_particle_effective_collision_frequency and banana_width in vaft.formula.neoclassical.

vaft.formula.ntv holds the exact, convention-bearing relations:

  • ntv_precession_frequency, whose zero is the superbanana-plateau resonance. $\omega_E$ is the $E\times B$ frequency omega_exb, never the toroidal rotation, and both $\omega_E$ and $\omega_B$ are measured along the plasma current;
  • nonambipolar_torque_density, the torque on the plasma: the $\mathbf J\times\mathbf B$ of the return current that cancels the non-ambipolar flux. Ion loss in a co-current plasma drives counter-current rotation.

The size of the flux needs a drift-kinetic code (vaft.code), and Shaing’s connected formula is not implemented, so the NTV regime diagram shows slopes only.

vaft.diagram.neoclassical_collisionality(epsilon=0.1)
vaft.diagram.ntv_collisionality()
vaft.diagram.ntv_precession_regimes(omega_magnetic=1.0)
   
lifecycle attenuation
Diagram Concept
nbi_particle_lifecycle Injection, ionisation, fast-ion birth, confinement, slowing down, heating and drive, then thermalisation. Each loss branches at its own stage: shine-through while neutral, prompt orbit loss after ionisation, delayed loss after confinement
nbi_neutral_attenuation Survival $e^{-\tau}$ and birth density $\alpha S$ along a path through a parabolic plasma (an illustrative $\alpha$). Births are drawn at equal probability steps, and the shine-through is marked at the exit
O mode X mode
CMA profile
omega-k omega-k oblique
n2-X n2-Y
n2-X oblique n2-Y oblique
profile oblique  
Diagram Concept
o_mode_cutoff Evanescent below $\omega_{pe}$, propagating above; the cutoff $P = 0$ does not depend on $B$
x_mode_dispersion Evanescent below $\omega_L$, propagating to the upper-hybrid pole, evanescent to $\omega_R$, then propagating. Poles are masked
cma_diagram Cutoffs (solid) and resonances (dashed) of a cold electron plasma in the CMA plane
profile_propagation $n_O^2$ and $n_X^2$ along $R$, with strips where each mode propagates (propagation_regime), for an example tokamak (not a device) at the on-axis electron cyclotron frequency: O cutoffs, L and R cutoffs, the upper-hybrid layer behind the R cutoff, and the ECR. With theta, both oblique roots and the $A = 0$ layers
wave_dispersion_omega_k Each branch in the $\omega$-$k$ plane ($k = n\omega/c$ where $n^2 > 0$): it starts at $k = 0$ on its cutoff ($P$, $R$ or $L = 0$) – the oblique whistler leaves the origin instead – runs to $k \to \infty$ at a resonance, and approaches the light line at high frequency
refractive_index_vs_X $n^2$ against $X$ at fixed $Y$: cutoffs at $X = 1 - Y$ ($R$), $1$ ($P$), $1 + Y$ ($L$), the upper hybrid at $X = 1 - Y^2$, all located by bracketing
refractive_index_vs_Y $n^2$ against $Y$ at fixed $X$: at $\theta = \pi/2$ the O branch does not depend on $Y$; the other has the $R$ cutoff at $Y = 1 - X$, the upper hybrid at $\sqrt{1 - X}$, and $Y = 1$ is the cyclotron layer
neoclassical ntv
precession  
Diagram Concept    
neoclassical_collisionality $D/D_\mathrm{plateau}$ against $\hat\nu$: asymptotes $\hat\nu/\epsilon^{3/2}$, 1 and $\hat\nu$ meeting at the formula’s boundaries. Orderings, not phase boundaries    
ntv_collisionality Non-resonant ($1/\nu$, then $\nu$–$\sqrt\nu$) and resonant ($1/\nu$, superbanana plateau, superbanana $\nu$) branches, with Shaing’s exponents. Schematic breakpoints    
ntv_precession_regimes $\nu_\mathrm{eff}$ against $\omega_E/\omega_B$: the resonance $\omega_d = 0$ and the ordering $\nu_\mathrm{eff} = \omega_d $ from ntv_precession_frequency. A schematic resonant band holds the superbanana plateau and $\nu$ regimes

Wall conditioning

Baking, glow-discharge cleaning and boronization, each drawn as a transition of the wall state $S^{(0)}\mathrm{wall} \to S^{(1)}\mathrm{wall}$ (WALL_STATE_CHANGE in the module), not only as “cleaning”. The diagrams are reduced and semantic, and share one vessel with an inlet port, a pump port and a wall-surface primitive:

  • baking is thermal desorption only: no glow, anode, ion bombardment or coating;
  • the glow discharges share one apparatus template: gas feed, glow, anode, the wall as cathode, and ions accelerated across the cathode sheath onto the whole wall. H$_2$/D$_2$ is reactive cleaning, with volatile O/C products that match the feed isotope. He is ion-induced release of retained H/D, drawn with its own arrow style;
  • boronization names a “B-containing precursor” unless one is passed, and leaves a B-rich layer.

Species are examples. No temperature, precursor, pressure or thickness is built in. A temperature (in K or °C) or a thickness is drawn only when the caller passes it together with its source. The sequence ends in plasma operation; how the conditioned wall responds then is the plasma-wall interaction section.

vaft.diagram.wall_conditioning_baking()        # temperature=, temperature_unit="K"|"degC", temperature_source=
vaft.diagram.wall_conditioning_gdc("D2")       # "H2", "D2" or "He"
vaft.diagram.wall_conditioning_boronization(precursor="B$_2$H$_6$")
vaft.diagram.wall_conditioning_sequence(("baking", "D2_gdc", "He_gdc", "boronization"))

sequence

   
baking boronization
D2 GDC He GDC
Diagram Concept
wall_conditioning_baking External heat drives adsorbed water and gases off the wall into the pump
wall_conditioning_gdc One glow-discharge template. H$_2$/D$_2$: O and C leave as volatile products. He: He$^+$ bombardment releases retained H/D
wall_conditioning_boronization A B-containing precursor in a deposition plasma leaves a B-rich surface layer, a change of surface state rather than cleaning
wall_conditioning_sequence The single stages in the caller’s order, each arrow a wall-state transition, ending in plasma operation. The order is not a recommended procedure

SOL blobs and filaments

A blob is a localized positive density (pressure) perturbation in the scrape-off layer, and a hole is a negative one. The filament is the field-aligned structure whose perpendicular cross-section is the blob.

How a blob moves:

  • curvature and $\nabla B$ drift ions and electrons apart;
  • the density monopole becomes a charge dipole, $+$ above and $-$ below;
  • the dipole’s $E$ field drives an $E\times B$ drift outward on the low-field side, down $\nabla B$ (a hole moves inward).

How fast it moves depends on where the polarization current closes:

  • along the field to the sheaths (sheath-connected, $v \propto \delta^{-2}$);
  • across the field by ion inertia (inertial or resistive-ballooning, $v \propto \delta^{1/2}$);
  • with resistivity and X-point fanning, in between.

vaft.formula.sol holds the prescribed filament state blob_density_perturbation (a blob, or a hole below the background), the reference size $\delta_* = \rho_s^{4/5}L_\parallel^{2/5}/R^{1/5}$, the reference velocity $v_$, the collisionality $\Lambda$, both limits, the interpolation, and the four regime scalings. All follow D’Ippolito, Myra and Zweben (2011), with a Gaussian of radius $\delta$. The $O(1)$ prefactors in Krasheninnikov (2001) and Theiler et al. (2011) belong to their own size definitions. The NSTX parameters of Myra et al. (2006) give $\hat a \approx 1.3$, as in their Fig. 1, and $v_ \approx 3$ km/s from their symbolic Eq. (3); their text quotes $v_* \sim 2$ km/s. Cold ions throughout: $c_s = (T_e/m_i)^{1/2}$.

vaft.diagram.blob_polarization()        # the mechanism: dipole, E, E x B; perturbation="hole" reverses it
vaft.diagram.blob_current_closure(regime="sheath")   # or "inertial": where the current closes
vaft.diagram.blob_velocity_scaling()    # v/v* against delta/delta*: both limits and Eq. (9)
vaft.diagram.blob_regimes(epsilon_x=0.1)  # Lambda against Theta = delta_hat^{5/2}: RB, RX, C_i, C_s
   
polarization hole
sheath closure inertial closure
   
velocity regimes

The VAFT framework: pillars, research cycle, managed pipeline, provenance

These diagrams describe what VAFT is and how scientific data moves through it (#1090). They work at the level of scientific capabilities, not deployment: no storage backend, endpoint, path or module name appears in them, and a test enforces this. The README uses the four pillars, the research cycle and the managed pipeline.

vaft.diagram.vaft_four_pillars()
vaft.diagram.fusion_science_knowledge_lifecycle()
vaft.diagram.scientific_workflow()
vaft.diagram.interoperability_layers()
vaft.diagram.scientific_provenance_chain()
vaft.diagram.plasma_state_provenance()
vaft.diagram.scientific_infrastructure_principles()
vaft.diagram.machine_agnostic_architecture()
vaft.diagram.experiment_modeling_theory_data_network()   # "point_to_point", "common_model", "equilibrium"
vaft.diagram.integrated_scientific_framework()           # domain=None or "equilibrium"
vaft.diagram.human_ai_interface()
vaft.diagram.machine_research_archive()
Diagram Concept
vaft_four_pillars Four capabilities at one level: the Standardized Data Interface, the Traceable & Reproducible Pipeline, the FAIR Scientific Data Repository and the Machine Knowledge Archive. They sit under the purpose (integrate fusion experiment, modelling, data and knowledge, so that plasma states are findable, comparable, reproducible and testable) and stand on the shared design principles. VEST is labelled as the reference implementation, not the foundation
fusion_science_knowledge_lifecycle A research-learning cycle: Experiment → Machine Description & Raw Data → Data Processing & Qualification → Modelling & Analysis → Physical Interpretation → Comparison & Synthesis → Discovery & New Questions → Experiment. New questions return only to the experiment
scientific_workflow A managed pipeline. Heterogeneous machine and experimental sources feed ingestion and orchestration, then diagnostic processing → equilibrium reconstruction and profile fitting → interpretive simulation, all reading and writing the standardized scientific state held in the Common Data Model (IMAS). Configuration and description, provenance and versioning, and V&V with quality assessment cut across it, and V&V feeds back to the configurations. The product is qualified, analysis-ready data
interoperability_layers From machine to scientific workflows in both directions, through the native representation, validation/standardization, the Common Data Model (IMAS) and the IMAS database. Native artifacts are stored alongside the standard (the dashed path)
scientific_provenance_chain An example tokamak analysis chain: raw signal → processed data → equilibrium reconstruction and profile fitting → derived physics quantities → analysis and visualization. Versioned inputs and configurations are kept apart from the cross-cutting quality metadata
plasma_state_provenance The information layers of one plasma state (Tutorial 03, #1714): measured quantities ($I_p$, magnetics, diamagnetic flux, Thomson and charge-exchange profiles) and assumed priors (profile model, weights and uncertainties, $Z_\mathrm{eff}$, boundary conditions) both enter the reconstruction or fit, whose fields and profiles feed the derived descriptors ($\kappa$, $\delta$, $q_{95}$, $\beta$, $\ell_i$, pressures, $\nu^$, $\rho^$, $a/L_T$). A derived number is never itself a measurement
scientific_infrastructure_principles Two foundations, both converging on VAFT. On one side are the common principles for modern scientific infrastructure (FAIR, W3C PROV, TRUST). On the other are three fusion-community requirements: verification and validation, integrated modelling and data analysis, and multi-machine comparison and extrapolation. Each side’s references, FAIR4RS among them, sit beneath it
machine_agnostic_architecture Theory, experiment, modelling and simulation, and data-driven methods share one scientific framework and one Common Data Model (IMAS), which holds design, experimental and simulation data and is stored in the IMAS database. Machine-specific data access and mapping absorbs device differences, so the same architecture serves existing fusion experiments and future devices and reactor concepts. No device is named
experiment_modeling_theory_data_network A three-step argument for a common data model. Point to point needs $N(N-1)/2$ pairwise adapters, and a new mode needs $N-1$ more. The Common Data Model (IMAS) needs $N$ adapters, and a new mode needs one. The IMAS equilibrium IDS, a standardized equilibrium representation, then serves as a tokamak example with representative routes and references
integrated_scientific_framework The common-model network one level up (#1698). The same four research modes and Common Data Model (IMAS), placed exactly as in the network, sit inside an Integrated Framework boundary, and the shared state feeds one Analysis node. The Common Data Model is the shared representation; the framework connects, runs, compares and reproduces research through it; analysis is the scientific use. With domain="equilibrium" the routes and the IMAS equilibrium IDS return, and the analysis reads MHD parameters, plasma shape and operational space. These are equilibrium-derived descriptors; stability codes such as DCON and RDCON are downstream models and stay out
human_ai_interface Three layers: actors, shared access interfaces and one backend. Human researchers and AI agents collaborate through the Python API, CLI, GUI, repository and docs, and MCP (planned). The interface layer reaches the framework and the IMAS database through one common connection
machine_research_archive VEST’s institutional and scientific memory since 2012: machine history, research on VEST and research knowledge feed one living archive, which new analyses and research build on. No dates are drawn beyond the start of operation

The four pillars of VAFT Research-learning cycle Managed scientific processing pipeline Interoperability layers Scientific provenance chain Plasma state provenance Principles for scientific infrastructure Machine-agnostic architecture Without a common model With a common model The IMAS equilibrium as a common model Integrated scientific framework Integrated scientific framework: equilibrium Human-AI collaborative access Machine and research archive

The interoperability figures read as one progression, from data interoperability through scientific integration to infrastructure and implementation. The four nodes of the network and framework figures are research modes, not physics domains; Research domains sets out how the two classifications cross:

  1. pairwise interfaces, experiment_modeling_theory_data_network("point_to_point");
  2. a shared scientific representation, experiment_modeling_theory_data_network("common_model");
  3. an integrated scientific framework, integrated_scientific_framework(), and its equilibrium example, integrated_scientific_framework(domain="equilibrium");
  4. the broader research infrastructure, experimental_research_infrastructure() (#1636);
  5. the managed workflow, scientific_workflow();
  6. the VEST implementation, vest_data_platform().

The pillar names are the four README sections. The diagrams are built from the concept primitives in vaft.diagram._concept: box, connector, band, and database, a drum drawn as polylines. They use the concept … and connector … styles of the template.

Research infrastructure: four levels of integration, the community and ownership

Why VAFT is built the way it is, in four levels (#1641, #1636, #1638, #1640). Each level is a pair of figures from one builder: organization="fragmented" draws the problem and organization="integrated" the architecture that answers it. The pair grammar is shared:

  • the fragmented figure draws research paths as dashed silos, joined only by red, dashed ad-hoc links (level 3 is one chain of steps instead, with the evidence each step loses beneath it);
  • the integrated figure draws the same entities around the shared layer that replaces those links;
  • both carry the level tag at the top left and numbered notes at the bottom, set as columns of text. The fragmented figure lists what goes wrong, each in plain words with its technical term and, where there is one, a reference: ^n plain words (technical term) [reference]. The integrated figure lists what answers each one, under the same number;
  • the numbers are cited like footnotes, as a grey superscript after the text they belong to. In the figure they mark where a symptom arises and which part of the architecture answers it, and they run in the order the problem figure cites them.
vaft.diagram.scientific_representation("fragmented")             # level 1, #1641
vaft.diagram.scientific_representation()                         # "integrated" is the default
vaft.diagram.experimental_research_infrastructure("fragmented")  # level 2, #1636
vaft.diagram.scientific_credibility("fragmented")                # level 3, #1638
vaft.diagram.research_modality_architecture("fragmented")        # level 4, #1640
vaft.diagram.fusion_research_ecosystem()                         # #1643, "full" or "presentation"
vaft.diagram.scientific_ownership_architecture()                 # #1645

Read in order, the figures make one argument. A Common Data Model answers the representation problem (experiment_modeling_theory_data_network). It is not enough on its own: a research infrastructure also needs a FAIR repository and a research framework. Reproducibility is not enough either: a result also needs traceable justification. The same science must then serve every researcher, interface and environment. The managed pipeline is scientific_workflow, and the VEST implementation is vest_data_platform.

Level Question Without With
1 Representation What does this information mean? One quantity held five ways, and each of four layers fragments on its own: the spoken term (“Ip”, “plasma current”), the stored name (a DAQ channel, a NetCDF variable, a struct field), the structure and the encoding. Stored names are mapped pairwise by hand Format and structure mappings feed the Common Data Model (IMAS), which owns meaning. Taxonomy, strict aliases and discovery connect researchers and agents to it. Storage and access (local or remote; eager, lazy, partial, cached) sit beside it
2 Infrastructure How is a state produced, stored and reused? Five silos, each running source → ad-hoc step → activity with private calibration copies; the reconstruction is copied by hand into other paths Sources and activities meet only in three complementary capabilities: the Common Data Model, the FAIR Scientific Data Repository and the Research Framework
3 Credibility Why should this result be trusted for this use? Locally reasonable steps lose evidence, ending in an apparently precise result. Twelve losses, each with a plain label and the literature term (parametric entanglement, fortuitous agreement, primacy hierarchy, domain of applicability, …) Provenance, uncertainty and assumptions feed one credibility and traceability structure, which verification, validation and sensitivity examine. The assessment is a profile, not a score, and yields a qualified scientific state
4 Modality & portability Can every researcher, language and environment use the same science? The science is copied into a GUI, a notebook, a MATLAB workflow and HPC scripts, and AI gets no capability interface Sibling interfaces (Python, Jupyter, CLI, GUI, documentation, MCP for agents) sit over shared public APIs and one modular core. Below it are language and runtime interoperability (MATLAB and Julia bindings marked as future) and portable execution. The versioned lifecycle runs beside them

The figures keep several distinctions visible, and the tests check them:

  • HDF5 is a serialization format, not the scientific model. The level-1 figure shows it only as one encoding beside NetCDF, MATLAB files and native outputs, and names no storage service;
  • provenance is not validity, numerical verification is not physical applicability, and a surrogate’s training domain is checked apart from its physics model;
  • GUI, CLI and MCP are interfaces, never part of the core;
  • external solvers keep their own platform limits.

fusion_research_ecosystem asks a different question: who does fusion research, what they do, and which shared scientific states connect it (#1643). The "full" figure shows research roles a person may combine, with graduate researchers and learners across every activity. Planning leads to a planned shot and a planned simulation run. Experiment and simulation are parallel, epistemically distinct producers. Comparison, validation and synthesis yield qualified states and feed new questions back to planning. Knowledge is preserved and transferred, and the states serve generic research contexts; only the reference implementation, VEST, is named. The "presentation" figure is a one-slide projection of the same model, with shared scientific states feeding experimental planning and operation, physics interpretation and discovery, and modelling, prediction and validation. Curved arrows show exchange between neighbouring uses; they do not prescribe a fixed sequence. A test checks that its roles, verbs, states and uses map back to the detailed figure’s roles, activities and states.

scientific_ownership_architecture shows where scientific logic lives as research software matures (#1645). Research groups Studies by membership, not by execution order, and neither executes anything. A workflow or notebook composes computation and matures reusable logic out of itself. Data and the database, and Formula, Process, Code and learned models, produce results and evidence. Validation interprets that evidence, and an optional use policy decides what a workflow does about it. The Actor contract is an optional overlay, off every edge. The graduation rule promotes matured logic by meaning. Computational layers is the zoomed view of the computation band, and Scientific architecture uses this figure as VAFT’s normative architecture.

Related issues: #1090 (the concept family), #1550 (the VEST workflow), #497 (placement of canonical visuals), #248, #252, #1505, #1626-#1629 (provenance, contracts and applicability), #1077, #1165, #1170, #1639, #1642, #669 (ownership, Study, Research, learned models), #1174, #1086, #188, #1423, #1002, #1012, #1013, #1016 (interfaces and runtimes).

References for the terminology in the level-3 and community figures:

  • R. Fischer and A. Dinklage, Integrated data analysis of fusion diagnostics by means of the Bayesian probability theory, Rev. Sci. Instrum. 75, 4237 (2004): data inconsistency, parametric entanglement, diagnostic interdependencies, complex error propagation.
  • P. W. Terry et al., Validation in fusion research: towards guidelines and best practices, Phys. Plasmas 15, 062503 (2008): qualification, fortuitous agreement, primacy hierarchy.
  • M. Greenwald, Verification and validation for magnetic fusion, Phys. Plasmas 17, 058101 (2010).
  • W3C, PROV-DM: the PROV data model, W3C Recommendation (2013).
  • M. D. Wilkinson et al., The FAIR guiding principles for scientific data management and stewardship, Sci. Data 3, 160018 (2016).
  • D. Lin et al., The TRUST principles for digital repositories, Sci. Data 7, 144 (2020).
  • F. Imbeaux et al., Design and first applications of the ITER integrated modelling & analysis suite, Nucl. Fusion 55, 123006 (2015).
  • ITER Organization, ITER Research Plan within the Staged Approach, ITR-18-03 (2018).
  • ITER Physics Basis, Nucl. Fusion 39, 2137 (1999); Progress in the ITER Physics Basis, Nucl. Fusion 47, S1 (2007).

Fragmented scientific representation One scientific meaning, many representations and names Fragmented experimental research Integrated research infrastructure Unqualified scientific inference Qualified scientific state Locked-in research software One modular scientific core, many ways to research The fusion-research ecosystem Connecting the activities of fusion research Scientific ownership and maturation

The content is the data at the top of each section of vaft.diagram._research_concepts (INFRA_*, CREDIBILITY_*, MODALITY_*, REPRESENTATION_*, ECOSYSTEM_*, PRESENTATION_*, OWNERSHIP_*), so a figure is changed by editing data.

The VEST data platform

The VEST data platform as a database-centred scientific workflow (#1550), laid out as a cross about the database. The VEST machine, a CAD render packaged with vaft.diagram and embedded in the SVG, sits outside the platform server and feeds experimental data processing (the render). A per-shot directory is the hub: reconstruction and physics inference (above) and simulation (right) read from it and write back to it. Users reach it from below, and the whole runs on Windows, macOS and Linux, locally or on an HPC cluster. The content is declared in vaft.diagram._platform (EXPERIMENTAL_PROCESSING, DATABASE_LAYOUT, RECONSTRUCTION, DERIVED_PHYSICS, SIMULATION, ACCESS, EXECUTION_*), so the figure is updated by editing data. The database technology appears once, as a muted caption under its title (DATABASE_TECHNOLOGY: IMAS · HDF5 · HSDS); no other backend or workflow-engine names are drawn.

vaft.diagram.vest_data_platform()           # the reference architecture view
vaft.diagram.vest_data_platform_overview()  # five stages, for papers and slides
Area Content
Experimental data processing Machine Model & History, Signal Processing, Quality & Validation, Fault & Anomaly Detection, Shot Classification, Event Detection
Database {shot}/: master.h5; experimental files; reconstructed state; physics products; each group open-ended
Reconstruction & physics inference Reconstruction (Eddy Current Model, Magnetic EFIT, Profile Fitting, Plasma Parameter Inference, Kinetic EFIT); Derived Physics (Vacuum Field Proxies, MHD Parameters, Synthetic Diagnostics, Coordinate Conversion, Power Balance)
Simulation Each entry is the concept, with its code or model authors beneath. Equilibrium: Fixed Boundary (CHEASE), Free Boundary (TokaMaker), Analytic GS (Solov’ev · Guazzotto & Freidberg). Stability: Ideal (DCON), Resistive (RDCON). 3D Response & Topology: Plasma Response (GPEC), Field-Line Following (FLARE). Transport: Classical (Braginskii), Neoclassical (NEO / Sauter & Redl), Turbulent (TGLF / CGYRO)
Access & analysis Python API, CLI, GUI, MCP, Documentation; Data Access · Search · Visualization · Comparison · Statistics · Export · Tutorials · Research Archive

The VEST data platform The VEST data platform in five stages

Integrated modeling: knowledge basis, realization, abstraction

A single “analytic / numerical / empirical / data-driven” list mixes three independent questions. These diagrams keep them apart (#1085):

  • Knowledge basis: where does the model’s knowledge come from, from first-principles to data-driven?
  • Computational realization: how is the model evaluated, from analytical to fully numerical?
  • Physical abstraction: at what description level is the system represented, from particle orbits to static equilibrium?

The diagrams then combine the three axes into one space and connect models by typed couplings. They show location and character, not ranking: neither end of an axis is better.

vaft.diagram.knowledge_basis()
vaft.diagram.computational_realization()
vaft.diagram.physical_abstraction()
vaft.diagram.integrated_modeling_space()                 # "fusion", "tearing"
vaft.diagram.integrated_modeling_process()
Diagram Concept
knowledge_basis Mechanistic/first-principles, semi-empirical/closure, empirical, data-driven. Physics-informed models (physical constraints with fitted or learned parts) are a bridge over the axis, not one point on it
computational_realization Analytical, semi-analytical, reduced numerical, fully numerical. Learned surrogates are not a rung: they are placed by knowledge basis and role
physical_abstraction Particle/orbit, kinetic, moment/fluid, MHD, equilibrium/static. Each arrow names its reduction: ensemble average, velocity moments + closure, single fluid at low frequency, stationary force balance
integrated_modeling_space Knowledge basis across, realization up. The physical abstraction is shown by the fill colour of each model and repeated in its border pattern, so it survives grayscale. Conceptual and heuristic models (physical picture, cartoon, scaling argument, toy model) are an explanatory layer beside the space, not a fourth axis
integrated_modeling_process Experiment, measurement, processing, inverse model (parameter inference), physical state, forward and data-driven models, prediction, and validation/control, with the eight coupling types of the legend

Semi-empirical is a knowledge basis: a physical form with fitted coefficients. Semi-analytical is a computational realization: an asymptotic expansion, a Green-function reduction or a quadrature of a closed form. The words look alike but belong to different axes.

knowledge basis computational realization physical abstraction integrated modeling space

Positions are semantic, not layout. Models with the same knowledge basis share an x and are separated in y. A learned model is not a realization rung. A surrogate takes the y of the model it emulates and is linked to it; a model that emulates nothing, such as a classifier, sits at the rung of its evaluation.

The "fusion" overlay places familiar codes, from Solov’ev, EFIT and CHEASE to TGLF, TRANSP and ASCOT5, with an empirical confinement scaling, a neural-operator surrogate of TGLF and an event classifier. These placements are illustrative, not a classification:

  • EFIT is an inverse model: it solves the Grad–Shafranov equation numerically inside a fit to measurements.
  • TRANSP is mainly used interpretively, so it is also an inverse model.
  • DCON integrates the Newcomb ODE, which is a reduced numerical method.
  • TGLF is gyro-Landau-fluid approximating gyrokinetics, with a saturation rule fitted to nonlinear gyrokinetic runs, so it sits at semi-empirical/closure. The "tearing" variant follows one phenomenon from an island picture in the explanatory layer, through the Rutherford equation, to a nonlinear resistive-MHD simulation.

integrated modeling space, fusion integrated modeling space, tearing

The coupling types are data flow, closure, parameter inference/calibration, surrogate replacement, residual correction, validation/benchmarking, feedback/control and iterative coupling. A coupling is a label on an edge. The data-driven model’s three uses are alternatives: a closure inside the forward model, or a surrogate replacement of it, or a residual correction of its prediction (the hybrid mode). Validation compares the prediction with the processed measurement, and control acts on the experiment.

integrated modeling process

The vocabulary and the example placements are data in vaft.diagram._modeling_schema: the axis stations, ModelDescriptor, ModelCoupling and the coupling types. They are kept apart from the drawing so that documentation and provenance tooling can reuse them. They are not a stable public API yet.

Spatial vocabulary: coordinates, geometry, meshes, mappings and topology

Concept-oriented schematics of the spatial ideas VAFT works with, organised by the concept rather than by a code: a structured grid or a logical mapping is drawn as the numerical idea several equilibrium, transport and MHD codes share. They need no shot data; vaft.plot draws a particular equilibrium, mesh or field. vaft.diagram._spatial.SPATIAL_FAMILIES files every builder below by family.

vaft.diagram.tokamak_top_view(cocos=11)
vaft.diagram.cocos_orientation(11)                 # one panel
vaft.diagram.cocos_orientation(range(1, 9))        # one panel per index, one scale
vaft.diagram.machine_and_equilibrium_geometry()
vaft.diagram.structured_rz_grid(n_r=13, n_z=21)
vaft.diagram.geometry_to_mesh()
vaft.diagram.logical_to_physical_mapping()
vaft.diagram.physical_to_flux_mapping()
Family Concept Builder
coordinate cylindrical $(R, \phi, Z)$ and toroidal $(r, \theta, \phi)$ tokamak_torus, tokamak_top_view
coordinate COCOS orientation, generic: $\phi$, $B_\phi$ and $I_p$ (on the magnetic axis) in or out of the page, the sense of $\theta$, the direction $\psi$ increases and its unit; titled by the index and $(\sigma_{B_p}, \sigma_{R\phi Z}, \sigma_{\rho\theta\phi}, \psi)$ cocos_orientation (signs from vaft.data.cocos.cocos_spec); coordinate choice against COCOS: coordinates_vs_cocos
coordinate flux coordinates $(\psi, \theta, \phi)$ and poloidal angles flux_coordinates, poloidal_angle_comparison
geometry machine geometry (wall, limiter, coils, passive structure) against equilibrium geometry (axis, surfaces, separatrix, X-point) machine_and_equilibrium_geometry
geometry limited and diverted equilibria; shaping limiter_and_diverted_topologies, shaping_family
mesh structured $(R, Z)$ grid with the plasma boundary between nodes structured_rz_grid
mesh unstructured mesh with region-dependent resolution geometry_to_mesh
mesh flux-aligned grid; logical $(\xi, \eta) \mapsto (R, Z)$ logical_to_physical_mapping, sfl_coordinate_grids
mapping measurement at $(R, Z)$ → $\psi$ → $\psi_N$ → $\rho_{\mathrm{tor},N}$ → profile coordinate physical_to_flux_mapping
mapping geometry → regions → mesh geometry_to_mesh
topology nested flux surfaces flux_surfaces
topology X-point and separatrix x_point, separatrix_lobes
topology magnetic island, stochastic layer magnetic_island, stochastic_layer

Conventions shared by every figure: $R$ to the right and $Z$ up in the poloidal plane; $\odot$ out of and $\otimes$ into the page; the magnetic axis is a filled blue dot, an X-point a cross; the LCFS a black line, the separatrix blue; the computational boundary dashed; the machine (vessel, limiter, coils) in black outline, faint where it is shown only for reference; regions shaded plasma blue, vacuum green, conductor grey; measurements red (outboard) and orange (inboard). The machine and the flux are the toy free-boundary model of the Grad–Shafranov diagrams, not any device. The sense of $\theta$ differs on purpose: the cocos_orientation panels draw it as the index fixes it (COCOS 11, $\sigma_{R\phi Z} = +1$ and $\sigma_{\rho\theta\phi} = +1$ with $\phi$ into the page, puts $\theta$ clockwise in the $(R, Z)$ plane as drawn), while the torus, mesh and mapping figures (tokamak_torus, logical_to_physical_mapping, sfl_coordinate_grids) are convention-free sketches that use the mathematical angle, counter-clockwise from the outboard midplane.

Top view COCOS orientation COCOS 1 to 8 Machine and equilibrium geometry Structured R-Z grid Geometry to mesh Logical to physical mapping Physical to flux mapping

Physics workflows: derivation, inference and solver coupling

The level-2 view below the platform overview (#1585). Each figure is drawn from one declarative WorkflowSpec (vaft.diagram._workflow); the same record produces the figure and the table under it, and the tests require every API and equation it names to exist on this tree. The figures follow the current implementation: where VAFT does not yet implement the physically complete step, or has no IMAS mapping, the node carries a red IMAS mapping TODO and the workflow lists its follow-up TODOs instead of drawing an unsupported capability. Node style says how a quantity was obtained:

Kind Meaning
measured experimentally observed
reconstructed the solution of an inverse problem
derived computed deterministically from existing state
inferred estimated with a model, prior or closure
synthetic (assumption-completed) completed from an equilibrium and explicit assumptions with no kinetic data; never a measurement
model assumption / prior an assumed value or prior the result depends on; drawn entering from the side
model choice / convention a model choice or convention (basis, sign, conductivity model, mode numbers); drawn from the side
machine geometry / static data static machine data: geometry, Green tables, circuits; drawn from the side
code input a code-specific projection of the canonical state
solver / model an external or internal physical model
native result the solver’s own output, before any mapping
standardized IMAS the IMAS / OMAS representation VAFT stores

Inputs and outputs carry their representative variables under the label, and standardized nodes their IMAS path. A step’s equation is drawn inside it: the vaft.formula catalog definition (formula_equation) where one exists, otherwise a relation restating the expression the named API implements.

vaft.diagram.plasma_parameter_inference()
vaft.diagram.romero_transformer_balance()
vaft.diagram.resistive_zeff_inference()
vaft.diagram.magnetic_efit()
vaft.diagram.kinetic_efit()
vaft.diagram.analytic_mhd_equilibrium()
vaft.diagram.chease_coupling()
vaft.diagram.tokamaker_coupling()
vaft.diagram.dcon_rdcon_stability()
vaft.diagram.gpec_plasma_response()
vaft.diagram.flare_field_line_topology()
vaft.diagram.neo_neoclassical()
vaft.diagram.tglf_cgyro_local_transport()
vaft.diagram.parameter_inference_overview()
vaft.diagram.parameter_inference_dependency_graph()

Plasma parameter inference: ion temperature and species

Measured electron profiles and the equilibrium resolved into an ion temperature, a species mix and the local quantities transport codes read. Each ion-temperature branch is kept apart, and the resolved state is held in memory (ResolvedTransportState), not written back to IMAS.

Plasma parameter inference: ion temperature and species

Node Kind Variables API IDS
Electron profiles measured $T_e(\rho),\ n_e(\rho)$   core_profiles.profiles_1d[:].electrons.{temperature, density_thermal}
Equilibrium reconstructed $p_{\mathrm{eq}}(\psi),\ r(\psi)$   equilibrium.time_slice[:].profiles_1d.{pressure, r_inboard, r_outboard}
Measured ion temperature (CX) measured $T_i^{\mathrm{CX}}(\rho)$   core_profiles.profiles_1d[:].ion[:].temperature
Pressure-partition ion temperature inferred   vaft.process.kinetic_closure.infer_ti_pressure_partition  
Temperature ratio model assumption / prior   vaft.machine_mapping.core_profiles.vest_core_profiles_policy  
Ion-temperature branch selection derived $\mathrm{measured} \succ \mathrm{pressure\ partition} \succ \mathrm{ratio}$ vaft.process.transport_state.resolve_transport_state  
Zeff and one impurity species model assumption / prior (enters Species resolution) $Z_{\mathrm{eff}},\ Z_I\ (\mathrm{default\ C})$   core_profiles.profiles_1d[:].zeff
Species resolution derived   vaft.code.gacode.inputs.impurity_fractions  
Normalized gradients derived   vaft.code.gacode.tglf.prepare_tglf_input  
Electron collision rate derived   vaft.code.gacode.tglf.prepare_tglf_input  
Resolved local state derived $T_e,\ T_i,\ n_e,\ n_H,\ n_I,\ a/L_{T,n},\ \hat\nu_{ee}$ vaft.process.transport_state.resolve_transport_state IMAS mapping TODO: in memory only; not written to core_profiles

Follow-up TODOs (implementation or IMAS mapping):

  • The resolved state (T_i choice, n_H, n_I) is not written back to core_profiles.
  • Normalized gradients and the GACODE collision rate are computed inside the TGLF input projection, not as vaft.formula definitions.

Plasma resistance from Romero’s transformer balance

The reconstructed boundary flux, plasma current and internal inductance close Romero’s voltage balance; what the inductive part does not explain is the resistive voltage, from which the plasma resistance follows.

Plasma resistance from Romero's transformer balance

Node Kind Variables API IDS
Reconstructed equilibrium reconstructed $I_p(t),\ \psi_B(t),\ l_{i,3}(t)$   equilibrium.time_slice[:].global_quantities.{ip, psi_boundary, psi_axis, li_3}
Romero convention: full flux model choice / convention (enters Loop voltages) $V = -\dot\psi,\ \psi\ \mathrm{in\ Wb}, \mathrm{sign\ from}\ (\psi_a - \psi_B)I_p$    
Internal inductance and equilibrium flux derived   vaft.omas.process_wrapper.compute_romero_flux_balance_ods  
Loop voltages derived   vaft.process.equilibrium.romero_flux_balance  
Non-inductive current model assumption / prior (enters Plasma resistance) $I_{\mathrm{ni}}\ (0\ \mathrm{stated\ for\ Ohmic})$    
Resistive voltage derived $V_R = V_B - V_I$    
Plasma resistance inferred $R_p = V_R/(I_p - I_{\mathrm{ni}})$ vaft.omas.process_wrapper.compute_romero_flux_balance_ods IMAS mapping TODO: returned dict only; no IDS path

Follow-up TODOs (implementation or IMAS mapping):

  • psi_C is formed as psi_B + L_i I_p from li_3; the current-weighted integral (transformer.current_weighted_flux_from_psi_j_dS) exists but is not used here.
  • No IMAS storage for V_B, V_I, V_R or R_p (e.g. summary.global_quantities.v_loop).

Resistively equivalent effective charge

One scalar Zeff over a time window: the effective charge a chosen parallel-conductivity model needs to reproduce the plasma resistance observed through Romero’s balance. It is a model-inferred, resistively equivalent value, not a measured or radially resolved Zeff(rho).

Resistively equivalent effective charge

Node Kind Variables API IDS
Electron profiles measured $T_e(\rho),\ n_e(\rho)$   core_profiles.profiles_1d[:].electrons.{temperature, density}
Flux-surface geometry reconstructed $\langle J!\cdot!B\rangle,\ \langle B^2\rangle,\ V(\psi),\ f_t$   equilibrium.time_slice[:].profiles_1d.{gm5, volume, f, trapped_fraction}
Observed resistive voltage inferred $V_R^{\mathrm{obs}}(t),\ R_p^{\mathrm{obs}}(t)\ \ (\mathrm{Romero\ balance})$ vaft.process.resistive_zeff.observed_resistance  
Conductivity model model choice / convention (enters Parallel conductivity) $\mathrm{spitzer_nrl \mid sauter_spitzer \mid sauter \mid redl}$    
Coulomb logarithm prescription model choice / convention (enters Parallel conductivity) $\ln\Lambda\ \mathrm{fixed\ or\ Sauter}$    
Parallel conductivity derived $\sigma_\parallel(\rho; Z)$ vaft.process.resistive_zeff.parallel_conductivity  
Model resistance derived   vaft.process.resistive_zeff.model_resistance  
Fit bounds and weights model assumption / prior (enters Bounded scalar fit) $Z_{\min} \le Z \le Z_{\max}\ (\mathrm{caller\ set}),\ \ w_t\ \mathrm{uniform}$    
Bounded scalar fit derived   vaft.process.resistive_zeff.infer_resistive_zeff  
Resistive Zeff (scalar) inferred $Z_{\mathrm{eff}}^{\mathrm{res}} \pm \sigma_Z, \mathrm{residual\ rms},\ \mathrm{bound\ hit}$   IMAS mapping TODO: CSV/JSON product; core_profiles.zeff untouched

Follow-up TODOs (implementation or IMAS mapping):

  • The observed resistance carries no propagated uncertainty (smoothing ‘none’ by default); the Zeff uncertainty is the fit’s sqrt(J/(n-1)/sum w (dV/dZ)^2).
  • No IMAS mapping for the scalar resistive Zeff.

Magnetic equilibrium reconstruction (EFIT)

A free-boundary Grad-Shafranov inverse problem: magnetic measurements with their uncertainties, modelled vessel currents and the machine’s Green-function tables constrain a low-order p’ and FF’ basis. EFIT fits; it does not forward-solve.

Magnetic equilibrium reconstruction (EFIT)

Node Kind Variables API IDS
PF coil currents measured $I_{\mathrm{PF},j}(t)$   pf_active.coil[:].current.data
Magnetic diagnostics measured $I_p,\ B_{p,k},\ \psi_{\mathrm{FL},k},\ \Phi_{\mathrm{dia}}$   magnetics.{ip, b_field_pol_probe, flux_loop, diamagnetic_flux}
Vessel circuit model machine geometry / static data (enters Vessel eddy currents (modelled)) $R,\ L,\ M\ \mathrm{of\ the\ passive\ loops}$    
Vessel eddy currents (modelled) derived   vaft.process.electromagnetics.solve_eddy_currents pf_passive.loop[:].current
Weights, uncertainty floor, exclusions model assumption / prior (enters Measurement constraints) $\sigma_k = \max(\sigma_k^{\mathrm{meas}}/s_g,\ 0.02\,\mathrm{median}|y|), \mathrm{diagonal\ weights}$    
Measurement constraints code input $y_k \pm \sigma_k,\ \ w_k \in {0, 1}$ vaft.code.efit.generate_constraints_ods  
Profile basis model choice / convention (enters k-file) $p’(\psi): 2,\ FF’(\psi): 1\ \mathrm{polynomial\ terms}, \mathrm{zero\ at\ the\ edge}$    
Green tables, limiter machine geometry / static data (enters EFIT inverse solve) $G(R,Z;R’,Z’),\ \mathrm{limiter\ (free\ boundary)}$    
k-file code input   vaft.code.efit.prepare_efit_inputs  
EFIT inverse solve solver / model   vaft.code.efit.run_efit  
g-, a-, m-files native result $\psi(R,Z),\ p’(\psi),\ FF’(\psi),\ \chi^2$ vaft.code.efit.collect_efit_outputs  
Equilibrium standardized IMAS $\psi,\ q,\ p,\ \beta_p,\ l_i$ vaft.code.efit.gfile_to_omas equilibrium.time_slice[:].{profiles_1d, profiles_2d, boundary, global_quantities}

Follow-up TODOs (implementation or IMAS mapping):

  • Vessel currents are modelled from a circuit driven by measured PF currents and I_p filaments, not fitted (IFITVS=0 by default); no flux loop constrains them.
  • Measurement weighting is diagonal; no covariance enters EFIT.
  • Native k/g/a/m files are recorded only by path and hash under equilibrium.code.parameters.

Kinetically constrained equilibrium reconstruction

The magnetic constraints plus a kinetic pressure profile: Thomson T_e, n_e and a measured or ratio-assumed T_i give pressure points with propagated uncertainty, placed in real space so EFIT maps them to psi on its own solution.

Kinetically constrained equilibrium reconstruction

Node Kind Variables API IDS
Thomson scattering measured $T_e \pm \sigma_{T_e},\ n_e \pm \sigma_{n_e}\ \mathrm{at}\ R_k$   thomson_scattering.channel[:].{t_e, n_e, position.r}
Ion temperature measured $T_i \pm \sigma_{T_i}, \mathrm{or}\ T_i = rT_e,\ r \pm \sigma_r\ \mathrm{from\ machine\ policy}$   charge_exchange.channel[:].ion[0].t_i
Major radius to normalized flux derived $\psi_N(R, Z{=}0)\ \mathrm{for\ the}\ T_i\ \mathrm{fit}$   equilibrium.time_slice[:].profiles_2d[0].psi
Kinetic pressure points derived   vaft.code.efit.kinetic_pressure_points  
Minimum pressure uncertainty model assumption / prior (enters Kinetic pressure points) $\sigma_p \ge 0.05\,p$    
Magnetic constraints code input $y_k \pm \sigma_k$ vaft.code.efit.generate_constraints_ods  
k-file with pressure block code input $\mathrm{KPRFIT}=1:\ (R_k, 0, p_k, \sigma_{p,k}), \mathrm{separatrix}\ p = 0 \pm 0.05\,p_{\max}$ vaft.code.efit.inject_pressure_constraint  
EFIT inverse solve solver / model   vaft.code.efit.run_kinetic_efit  
Kinetic equilibrium standardized IMAS $\psi,\ p(\psi),\ q$ vaft.code.efit.run_kinetic_chain equilibrium.time_slice[:].{profiles_1d.pressure, profiles_2d}

Follow-up TODOs (implementation or IMAS mapping):

  • Pressure assumes one ion species with n_i = n_e: no impurity dilution or Zeff enters p_kin.
  • The pressure points and the Ip scale run_kinetic_efit settles on are not stored in IMAS (manifest only); the work directory with the k-file is deleted.
  • Single pass against the magnetic equilibrium: no kinetic <-> equilibrium iteration.

Analytic MHD equilibrium models

Two uses of closed-form Grad-Shafranov solutions. Forward generation builds an equilibrium from shape parameters and a profile class; fitting projects a reconstructed equilibrium onto a Solov’ev basis and reports how well it is represented.

Analytic MHD equilibrium models

Node Kind Variables API IDS
Shape and topology model assumption / prior $R_0,\ a,\ \kappa,\ \delta,\ \mathrm{limited\ /\ single\ /\ double\ null}$    
Reconstructed equilibrium reconstructed $\psi(R,Z)\ \mathrm{inside\ the\ LCFS}$   equilibrium.time_slice[:].profiles_2d[0].psi
Solov’ev / Cerfon-Freidberg solver / model   vaft.process.solve_solovev_constraints  
Guazzotto-Freidberg solver / model   vaft.process.solve_guazzotto_freidberg  
Solov’ev basis model choice / convention (enters Least-squares projection) $\mathrm{classic}\ 5 \mid \mathrm{CF\ even}\ 7, \mathrm{CF}\ 12\ \mathrm{terms}$    
Least-squares projection derived   vaft.process.fit_solovev  
Analytic flux native result $\psi(R,Z),\ c_k$    
Fit fidelity native result $\psi_{\mathrm{rms}},\ \mathrm{boundary\ rms},\ \mathrm{topology\ match}$    
Equilibrium standardized IMAS $\psi,\ q,\ p$ vaft.data.eqdsk.to_omas equilibrium.time_slice[:].{profiles_1d, profiles_2d}

Follow-up TODOs (implementation or IMAS mapping):

  • No direct ODS writer: forward results reach IMAS through EquilibriumData -> GEQDSK -> to_omas.
  • Fit results (SolovevFit) are not written to IMAS.

Fixed-boundary equilibrium refinement (CHEASE)

A reconstructed boundary and profiles re-solved at fixed boundary; the COCOS transform into and out of CHEASE is explicit.

Fixed-boundary equilibrium refinement (CHEASE)

Node Kind Variables API IDS
Reconstructed equilibrium reconstructed $R_b,\ Z_b,\ p’(\psi),\ FF’(\psi)$   equilibrium.time_slice[:].{boundary.outline, profiles_1d}
COCOS transform model choice / convention (enters EXPEQ, namelist) $\mathrm{COCOS}\ 11 \to 2 \to 11$    
EXPEQ, namelist code input   vaft.code.chease.prepare_chease_inputs  
CHEASE fixed-boundary solve solver / model   vaft.code.chease.run_chease  
EQDSK, output files native result $\psi(R,Z),\ q(\psi)$ vaft.code.chease.collect_chease_outputs  
Refined equilibrium standardized IMAS $\psi,\ q,\ \langle\cdot\rangle_\psi$ vaft.code.chease.refine_equilibrium equilibrium.time_slice[:].{profiles_1d, profiles_2d}

Free-boundary equilibrium (TokaMaker)

Machine geometry, measured coil currents and power-law profile shapes solved at free boundary on a finite-element mesh; the plasma boundary is part of the solution.

Free-boundary equilibrium (TokaMaker)

Node Kind Variables API IDS
Coil currents measured $I_{\mathrm{PF},j}$   pf_active.coil[:].current.data
Plasma current and vacuum field measured $I_p,\ F_0 = R_0 B_0$   {equilibrium | magnetics}.ip; tf
Wall, coils, vessel machine geometry / static data (enters TokaMaker inputs)     {wall, pf_active.coil, pf_passive.loop}
TokaMaker inputs code input   vaft.code.tokamaker.prepare_tokamaker_inputs  
Finite-element mesh code input   vaft.code.tokamaker.build_tokamaker_mesh  
Profile shape model assumption / prior (enters TokaMaker free-boundary solve) $p’,\ FF’ \propto (1-\hat\psi^{\alpha_a})^{\alpha_b},\ \ p_{\mathrm{ax}},\ I_{FF’}/I_{p’}$    
TokaMaker free-boundary solve solver / model   vaft.code.tokamaker.run_tokamaker  
Flux, boundary, statistics native result $\psi(R,Z),\ R_b,\ Z_b$ vaft.code.tokamaker.collect_tokamaker_outputs  
Equilibrium standardized IMAS $\psi,\ q,\ \beta_p$   equilibrium.time_slice[:].{profiles_1d, profiles_2d, boundary}

Ideal and resistive MHD stability (DCON / RDCON)

An equilibrium tested for ideal stability (DCON energy principle) and for tearing (RDCON matching at the rational surfaces); the solver-native energies and Delta-prime come before any verdict.

Ideal and resistive MHD stability (DCON / RDCON)

Node Kind Variables API IDS
Equilibrium reconstructed $\psi,\ q(\psi),\ p(\psi)$   equilibrium.time_slice[:]
Toroidal modes and flux range model choice / convention (enters DCON / RDCON inputs) $n = 1, 2,\ \ \psi_N \in [0.01, 0.994], \Delta m = 8\ (\mathrm{RDCON}\ 16)$    
DCON / RDCON inputs code input   vaft.code.gpec.prepare_gpec_suite_case  
Vacuum boundary model choice / convention (enters DCON ideal energy principle) $\mathrm{free\ boundary,\ no\ wall\ (far\ wall)}$    
Resistive inner layers derived $\eta(T_e, Z_{\mathrm{eff}}, \ln\Lambda),\ \rho_m\ \mathrm{at}\ q = m/n$ vaft.code.gpec._solvers.write_rmatch_resistive_layers  
DCON ideal energy principle solver / model   vaft.code.gpec.run_gpec_suite_case  
RDCON resistive matching solver / model   vaft.code.gpec.run_gpec_suite_case  
Energy and eigenfunctions native result $\delta W_n = \delta W_p + \delta W_v,\ \ \xi_{m,n}(\psi)$ vaft.code.gpec.read_dcon_output  
Delta-prime at rational surfaces native result $\Delta’_{m/n}\ \mathrm{at}\ q = m/n$ vaft.code.gpec.read_pest3_matching_output  
Ideal mode standardized IMAS $n,\ \delta W_n,\ \xi_\perp$   mhd_linear.time_slice[:].toroidal_mode[:].{energy_perturbed, plasma}
Tearing stability index standardized IMAS $\Delta’_{m/n}$   ntms.time_slice[:].mode[:].deltaw[0]

Follow-up TODOs (implementation or IMAS mapping):

  • energy_perturbed carries the DCON-normalised total delta W, not joules; the plasma/vacuum split and the full Delta-prime matrices stay native.
  • Wall position, qlow and delta_mlow/high come from the packaged templates, not from VAFT options.

Ideal plasma response to 3-D fields (GPEC)

An applied non-axisymmetric coil field and the plasma’s ideal response to it: coil geometry is machine data, the excitation is prescribed, and the total, plasma and resonant fields are kept apart.

Ideal plasma response to 3-D fields (GPEC)

Node Kind Variables API IDS
Equilibrium reconstructed $\psi,\ q,\ p,\ F$   equilibrium.time_slice[:]
3-D coil geometry machine geometry / static data (enters GPEC inputs) $\mathrm{VEST\ UP/MID/LOW\ coils,\ coil.in}$    
Coil current and phasing model assumption / prior (enters GPEC inputs)   vaft.machine_mapping.coils_non_axisymmetric_geometry.CoilExcitation.from_mode  
GPEC inputs code input   vaft.code.gpec.prepare_gpec_suite_case  
Response model model choice / convention (enters GPEC ideal response) $\mathrm{ideal,\ static}\ (\omega = 0), \mathrm{no\ rotation,\ no\ kinetic\ terms}$    
GPEC ideal response solver / model   vaft.code.gpec.run_gpec_suite_case  
Perturbed fields native result $\delta\mathbf B_{\mathrm{total}} = \delta\mathbf B_{\mathrm{vac}} + \delta\mathbf B_{\mathrm{plasma}}$ vaft.code.gpec.read_gpec_netcdf  
Resonant response native result $\Phi_{\mathrm{res}},\ w_{\mathrm{isl}}, K_{\mathrm{Chirikov}},\ \delta W$ vaft.code.gpec.read_gpec_netcdf  
Perturbed normal field standardized IMAS $\delta\mathbf B\cdot\nabla\psi$   mhd_linear.time_slice[:].toroidal_mode[:].plasma.b_field_perturbed; IMAS mapping TODO: dB(R,Z,phi), its vacuum part and resonant quantities

Follow-up TODOs (implementation or IMAS mapping):

  • GPEC returns total and plasma fields; the vacuum part (total minus plasma) is not computed by any mapping.
  • No frequency, rotation or kinetic response inputs: the response is ideal and static.
  • Energies go to code.parameters; resonant quantities and cylindrical fields are not mapped.

Magnetic field-line topology (FLARE)

Field lines traced through the axisymmetric background plus the 3-D perturbation: Poincare maps, connection lengths and strike-point footprints are the native products; a heat load needs an explicit model, here a relative proxy.

Magnetic field-line topology (FLARE)

Node Kind Variables API IDS
Axisymmetric background field reconstructed $\mathbf B_0(R,Z)$   equilibrium.time_slice[:]
3-D perturbation from GPEC native result $\delta\mathbf B(R,Z,\phi)$ vaft.code.flare.write_helicity_flipped_field  
Field-direction convention model choice / convention (enters FLARE field-line tracing) $\mathrm{scale}{I_p},\ \mathrm{scale}{B_t}\ \mathrm{from\ COCOS}$ vaft.code.flare.flare_equilibrium_scales  
Wall and target geometry machine geometry / static data (enters FLARE field-line tracing) $\mathrm{in\ the\ FLARE\ control\ file}$    
Tracing configuration model choice / convention (enters FLARE field-line tracing) $\mathrm{in\ the\ FLARE\ control\ file}$    
FLARE field-line tracing solver / model   vaft.code.flare.run_flare  
Poincare map native result $(R, Z)\ \mathrm{crossings\ at\ fixed}\ \phi$ vaft.data.flare_products.read_flare_product IMAS mapping TODO: no IMAS path
Connection length native result $L_c(R,Z)$   plasma_initiation.b_field_lines
Strike-point footprint native result $\psi_{\min},\ \alpha\ \mathrm{at\ the\ target}$    
Relative heat-load proxy derived   vaft.process.field_line_topology.footprint_heat_load_proxy  
Incident power fractions standardized IMAS $f_{\mathrm{inc}}$   divertors[:].target[:].power_incident_fraction

Follow-up TODOs (implementation or IMAS mapping):

  • Wall/target geometry and tracing settings live in the user’s FLARE control file, not in VAFT.
  • No island width or stochasticity metric is computed from FLARE output (GPEC’s Chirikov K is the only one in VAFT).
  • The heat load is a relative proxy; no parallel-transport or q_perp model is implemented.

Neoclassical transport: closed-form fits and drift-kinetic solution

The same resolved local state through the Sauter and Redl fits and the drift-kinetic solver NEO, so the two can be compared at one state.

Neoclassical transport: closed-form fits and drift-kinetic solution

Node Kind Variables API IDS
Resolved local state derived $T_s,\ n_s,\ q,\ \epsilon,\ f_t$ vaft.process.transport_state.resolve_transport_state  
Sauter / Redl fits derived   vaft.formula.neoclassical.redl_bootstrap_current  
NEO input code input   vaft.code.gacode.neo.prepare_neo_case  
NEO drift-kinetic solve solver / model   vaft.code.gacode.neo.run_neo  
Fluxes, bootstrap current native result $\Gamma_s,\ Q_s,\ \langle j_{\mathrm{bs}}B\rangle$ vaft.code.gacode.neo.collect_neo_outputs  
Neoclassical transport standardized IMAS $\Gamma_s,\ Q_s,\ j_{\mathrm{bs}}$   core_transport.model[:].profiles_1d[:]

Local turbulent transport: quasilinear and gyrokinetic

One local gyrokinetic state projected into TGLF (quasilinear) and CGYRO (local delta-f, linear or nonlinear); their outputs are different physical objects and are kept apart.

Local turbulent transport: quasilinear and gyrokinetic

Node Kind Variables API IDS
Equilibrium reconstructed $q,\ r,\ R,\ \kappa,\ \delta$   equilibrium.time_slice[:].profiles_1d
Kinetic profiles measured $T_s,\ n_s,\ Z_{\mathrm{eff}}$   core_profiles.profiles_1d[:]
Resolved local gyrokinetic state derived $n_s, T_s, Z_s, m_s,\ a/L_{n_s}, a/L_{T_s},\ T_i/T_e, Z_{\mathrm{eff}},\ \hat\nu_{ee},\ \beta_e,\ q,\ \hat s,\ \kappa, s_\kappa,\ \delta, s_\delta$ vaft.process.transport_state.resolve_transport_state  
Rotation and ExB shear model assumption / prior (enters Resolved local gyrokinetic state) $\gamma_E = 0,\ M = 0\ (\mathrm{not\ derived})$    
input.tglf code input   vaft.code.gacode.tglf.prepare_tglf_input  
input.cgyro code input   vaft.code.gacode.cgyro.prepare_cgyro_input  
TGLF model choices model choice / convention (enters TGLF quasilinear model) $\mathrm{SAT_RULE},\ \delta B_\perp, \delta B_\parallel, \mathrm{XNU_MODEL},\ k_y\ \mathrm{grid}$    
TGLF quasilinear model solver / model   vaft.code.gacode.tglf.run_tglf  
CGYRO local delta-f solver / model   vaft.code.gacode.cgyro.run_cgyro  
CGYRO model choices model choice / convention (enters CGYRO local delta-f) $\mathrm{linear \mid nonlinear},\ N_{\mathrm{field}}, \mathrm{Sugama\ collisions},\ \mathrm{Miller\ geometry}$    
Quasilinear fluxes and spectrum native result $Q_s,\ \Gamma_s;\ \gamma(k_y),\ \omega(k_y)$ vaft.code.gacode.tglf.collect_tglf_outputs  
Linear eigenmodes native result $\gamma,\ \omega,\ \phi(\theta)$ vaft.code.gacode.cgyro.collect_cgyro_outputs  
Saturated fluxes (nonlinear) native result $\langle Q_s\rangle_t,\ \langle\Gamma_s\rangle_t$ vaft.code.gacode.cgyro.collect_cgyro_outputs  
Turbulent transport (TGLF) standardized IMAS $Q_s,\ \Gamma_s\ \mathrm{(quasilinear)}$ vaft.machine_mapping.turbulence.core_transport_from_tglf core_transport.model[:]; IMAS mapping TODO: no TGLF to gyrokinetics_local writer
Gyrokinetic run (CGYRO) standardized IMAS $\gamma,\ \omega;\ \langle Q_s\rangle_t,\ \langle\Gamma_s\rangle_t$ vaft.machine_mapping.gyrokinetics.gyrokinetics_local_from_cgyro gyrokinetics_local.{linear.wavevector[:].eigenmode[:], non_linear.fluxes_1d}

Follow-up TODOs (implementation or IMAS mapping):

  • Rotation and ExB shear are zero in both projections (TGLF VEXB_SHEAR, CGYRO GAMMA_E, MACH): their derivation from data is not implemented (#553).
  • Squareness zeta enters as 0 (VEST equilibria carry no squareness); Z_EFF is not written to input.cgyro by design: CGYRO recomputes it from the species list (Z_EFF_METHOD=2).
  • No implemented local-gyrokinetic validity criterion (rho*): compare_with_oracle checks only the input translation against CGYRO’s own projection.
  • No TGLF to gyrokinetics_local mapping.

Plasma parameter inference: completing the kinetic profiles

Where inference sits: diagnostics and the equilibrium give reconstructed but incomplete kinetic profiles; explicit assumptions and the closures VAFT implements complete them, and every completed quantity keeps its origin on the way to simulation.

Plasma parameter inference: completing the kinetic profiles

Node Kind Variables API IDS
Thomson scattering measured $T_e,\ n_e\ \mathrm{at}\ (R, Z)$   thomson_scattering.channel[:]
Charge exchange (optional) measured $T_i^{\mathrm{CX}}\ \mathrm{at}\ (R, Z)$   charge_exchange.channel[:].ion[0].t_i
Magnetic equilibrium reconstructed $p_{\mathrm{eq}}(\psi),\ q,\ \langle j\cdot B\rangle,\ \mathrm{geometry}$   equilibrium.time_slice[:].profiles_1d
Reconstructed kinetic profiles reconstructed $T_e(\rho),\ n_e(\rho)\ (\mathrm{fitted}),\ [T_i(\rho)], p_{\mathrm{eq}}(\rho),\ q(\rho)$   core_profiles.profiles_1d[:].electrons
Fitting assumptions model choice / convention (enters Reconstructed kinetic profiles) $\mathrm{polynomial\ |\ core\text{-}poly/edge\text{-}exp\ |\ GP}, \mathrm{order}\ N,\ x = \rho_{\mathrm{tor},N}\ \mathrm{or}\ \psi_N, T, n > 0,\ \sigma\text{-}\mathrm{weighted}$ vaft.process.profile.profile_fitting_thomson_scattering  
Closure assumptions model assumption / prior (enters Reconstructed kinetic profiles) $\mathrm{common}\ T_i,\ \mathrm{impurity\ species},\ Z_{\mathrm{eff}}, \sigma_\parallel:\ \mathrm{Spitzer\ or\ neoclassical},\ \ln\Lambda$    
Thermodynamic closure inferred   vaft.process.kinetic_closure.infer_ti_pressure_partition  
Impurity closure inferred   vaft.process.impurity.resolve_impurity_composition  
Resistive closure inferred $V_R^{\mathrm{obs}} \to Z_{\mathrm{eff}}^{\mathrm{res}}\ (\mathrm{scalar}), \sigma_\parallel:\ \mathrm{Spitzer\ |\ neoclassical\ (Sauter,\ Redl)}$ vaft.process.resistive_zeff.infer_resistive_zeff  
Completed kinetic profiles derived $n_e, T_e, T_i, n_s, Z_{\mathrm{eff}}, \mathrm{each\ with\ origin=\ldots;\ method=\ldots}$   core_profiles.profiles_1d[:].{electrons, ion[:], zeff}
Simulation-ready code input $\mathrm{every\ input\ quantity\ with\ its\ origin}$    

References:

  1. L. L. Lao et al., Nucl. Fusion 25 (1985) 1611
  2. J. Wesson, Tokamaks, 4th ed., Oxford University Press (2011), Sec. 4.25
  3. J. A. Romero and JET-EFDA contributors, Nucl. Fusion 50 (2010) 115002
  4. L. Spitzer and R. Harm, Phys. Rev. 89 (1953) 977
  5. O. Sauter, C. Angioni and Y. R. Lin-Liu, Phys. Plasmas 6 (1999) 2834
  6. A. Redl et al., Phys. Plasmas 28 (2021) 022502

Follow-up TODOs (implementation or IMAS mapping):

  • Atomic-model-constrained Z_eff(rho) (transient charge states projected through the resistive closure) is on develop as resolve_radial_composition(normalization=’resistive_closure’) (#1565, #1566, PR #1659); this diagram still draws the scalar resistive closure only.
  • Rotation, E_r and the ExB shear are not inferred: downstream codes receive gamma_E = 0 as an explicit assumption (#553).
  • Provenance is recorded per quantity where it exists (core_profiles origin=…; method=… records for composition, the T_i result’s origin/method fields); there is no single runtime provenance object, by design (#1601 is documentation-first).

Inferred quantities depend on inferred quantities

Provenance propagates: a composition assumption fixes the ion densities, which set the pressure-partition T_i, whose gradients reach the gyrokinetic input beside an assumed zero ExB shear. Every link below the measurements carries the assumptions above it.

Inferred quantities depend on inferred quantities

Node Kind Variables API IDS
Electron profiles measured $T_e(\rho),\ n_e(\rho)$   core_profiles.profiles_1d[:].electrons.{temperature, density_thermal}
Equilibrium pressure reconstructed $p_{\mathrm{eq}}(\psi)\ \ (\mathrm{independent\ lineage})$   equilibrium.time_slice[:].profiles_1d.pressure
Impurity source model assumption / prior (enters Ion densities) $\mathrm{measured} \succ \mathrm{explicit} \succ \mathrm{derived} \succ \mathrm{assumed}$    
Ion densities derived   vaft.process.impurity.resolve_impurity_composition  
Pressure-partition ion temperature inferred   vaft.process.kinetic_closure.infer_ti_pressure_partition  
Ion pressure derived $p_i(\rho),\ dp_i/dr$    
Normalized gradients derived $a/L_{T_i},\ a/L_{n_i},\ T_i/T_e$ vaft.code.gacode.tglf.prepare_tglf_input  
ExB shear model assumption / prior (enters Gyrokinetic input) $\gamma_E = 0\ \ (\mathrm{assumed})$    
Gyrokinetic input code input $\mathrm{local\ state\ with\ origins}$ vaft.code.gacode.cgyro.prepare_cgyro_input  

References:

  1. L. L. Lao et al., Nucl. Fusion 25 (1985) 1611
  2. J. Wesson, Tokamaks, 4th ed., Oxford University Press (2011), Sec. 4.25

Follow-up TODOs (implementation or IMAS mapping):

  • E_r, rotation and gamma_E are not inferred from data (#553): gamma_E = 0 enters the gyrokinetic input as an assumption, and force balance is future scope.

Using the committed assets

The reference SVGs live in docs/assets/diagrams/ and are the artifacts to embed anywhere:

  • Documentation pages: ![island]({{ '/assets/diagrams/magnetic_island_poloidal.svg' | relative_url }}).
  • The README, notebooks and slides: link or copy the SVG. It is self-contained, with glyphs stored as paths and no external fonts or images.

They do not ship in the wheel. An installed package builds any diagram from its packaged TikZ template.

Regenerating and checking

python -m vaft.diagram.build            # re-render diagrams whose TikZ source changed
python -m vaft.diagram.build --check    # verify the committed assets; needs no TeX

Each SVG carries its own build record: one comment line after the XML declaration holding the call, the SHA-256 of the generated TikZ document it was rendered from, and the SHA-256 of the SVG without that line. Because the record lives in the diagram’s own file, two pull requests that change different diagrams share no generated file and do not conflict (#1750). --check rebuilds the TikZ in pure Python and fails in five cases: an asset is stale, an asset was edited by hand, an asset is missing, an asset has no record, or an asset is orphaned. CI runs it on every pull request. Freshness is judged on the source and not on SVG bytes, because two dvisvgm releases write different but equally correct SVG for the same picture. Rendering needs latex and dvisvgm, which TeX Live and MacTeX provide. The generated .tex, PDF, PNG and LaTeX by-products are never committed.

results matching ""

    No results matching ""