Equilibrium Module

The Equilibrium module provides tools to read, construct, and analyze magnetohydrodynamic (MHD) plasma equilibria. It wraps a variety of equilibrium file formats (EFIT, CHEASE, SOL, LAR, and others), runs the appropriate direct or inverse solver, and returns a processed PlasmaEquilibrium object ready for downstream calculations.

Overview

Key responsibilities of the module:

  • Read equilibrium input files and TOML configuration (see EquilibriumConfig).
  • Provide convenient constructors for analytic / model equilibria (Large
Aspect Ratio, Solev'ev).
  • Build spline representations used throughout the code (1D cubic and
2D bicubic splines).
  • Run the direct or inverse equilibrium solver and post-process results
(global parameters, q-profile finding, separatrix finding, GSE checks).

The module exposes a small public API that covers setup, configuration, and common analyses used by other GPEC components (e.g. ForceFreeStates, vacuum interfaces).

EFIT solver strategies

When eq_type is one of the EFIT-based options, three solver strategies are available:

eq_typeMethodBest for
"efit"Geometric-angle field-line ODEDefault; fast and robust for standard cases
"efit_arclength"Arc-length field-line ODENear-separatrix surfaces where the geometric-angle ODE becomes singular
"efit_by_inversion"Contour.jl marching-squares → inverse solverHighest geometric accuracy; avoids ODE singularities entirely

efit integrates field lines using the geometric angle η (polar angle from the magnetic axis, 0→2π) as the independent variable. Position at each step is computed as R = R₀ + rfac·cos(η), so the RHS denominator is Bz·cos(η) − Br·sin(η) — the projection of B_pol onto the radial direction. Near an X-point where Bp → 0 this denominator passes through zero, causing a coordinate singularity: the ODE steps become extremely small or the solver fails to converge.

efit_arclength uses arc length along the flux surface as the independent variable instead. The tangent direction (dR/ds, dZ/ds) = ∇ψ⊥/|∇ψ| has unit magnitude by construction, so the position equations have no denominator and remain well-behaved all the way to the separatrix. The 1/Bp factors in the accumulated integrals still diverge near X-points, but their solver tolerances are set large so they do not restrict the step size — only the position tracking drives adaptivity. The two methods produce identical results when both succeed; efit_arclength extends the reliable range of psihigh closer to 1.

efit_by_inversion traces flux surface level sets directly from ψ(R,Z) using marching squares, resamples each closed curve to a uniform geometric-angle grid, and feeds the result into the inverse equilibrium solver (the same path used by CHEASE input). The Cartesian evaluation grid is clipped to the separatrix bounding box and its resolution is set adaptively from a bilinear interpolation error bound, so no manual tuning is needed.

Radial grid packing

The default grid_type = "log_asymptotic" uses a three-region grid that respects the asymptotic behavior of q near both the magnetic axis and the separatrix:

  • Core (ψ < 0.15): geometric spacing in log(ψ) — handles the axis where profiles behave as ψⁿ
  • Middle (0.15 ≤ ψ ≤ 0.95): uniform spacing — preserves resolution through the pedestal region
  • Edge (ψ > 0.95): geometric spacing in log(1−ψ) — tracks the logarithmic divergence q ~ −A·ln(1−ψ) near a diverted separatrix

With mpsi = 0 (the default), the number of radial knots is chosen automatically from the psi_accuracy parameter (target absolute error in q). Two probe field-line integrations near psihigh estimate the local log-slope A, and the knot count is set so the cubic spline error stays below psi_accuracy throughout the domain. The legacy grid_type = "ldp" (sin²-spaced) and explicit mpsi are still supported.

API Reference

GeneralizedPerturbedEquilibrium.Equilibrium.DirectRunInputType
DirectRunInput(...)

A container struct that bundles all necessary inputs for the direct_run function. It is created by one of the equilibrium file read-in functions after processing the raw equilibrium data and preparing the initial splines.

Fields

  • config::EquilibriumConfig The equilibrium configuration object.

  • sq_in 1D spline data versus normalized poloidal flux psin. Quantities:

    1. F = R * B_t — toroidal flux function [m·T]
    2. μ₀ * Pressure — plasma pressure (non-negative) [T²]
    3. q — safety factor profile
    4. √ψ_norm — square root of normalized flux
  • psi_in 2D cubic interpolant on the (R, Z) grid [m]. The values correspond to the poloidal flux adjusted to be zero at the boundary [Wb/rad]. Definitions:

    1. ψ(R, Z) = ψ_boundary - ψ(R, Z)

    2. ψ = ψ * sign(ψ(centerR, centerZ))

      • 1D profiles are represented by CubicInterpolant or CubicSeriesInterpolant
      • 2D flux surfaces by CubicInterpolantND
  • psi_in_xs::Vector{Float64} — R coordinate grid for psi_in [m]

  • psi_in_ys::Vector{Float64} — Z coordinate grid for psi_in [m]

  • rmin::Float64 — Minimum R-coordinate of the computational grid [m]

  • rmax::Float64 — Maximum R-coordinate of the computational grid [m]

  • zmin::Float64 — Minimum Z-coordinate of the computational grid [m]

  • zmax::Float64 — Maximum Z-coordinate of the computational grid [m]

  • psio::Float64 — Total flux difference |ψ_axis - ψ_boundary| [Wb/rad]

source
GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumConfigType
EquilibriumConfig(...)

A mutable struct containing configuration parameters for equilibrium reconstruction. Bundles all necessary settings originally specified in the equil fortran namelists.

Fields

  • eq_type::String - Type of equilibrium file ("efit", "solovev", "lar", etc.)
  • eq_filename::String - Path to equilibrium input file
  • jac_type::String - Jacobian coordinate type ("hamada", "pest", "equal_arc", "boozer", "park", "other")
  • power_bp::Int - Poloidal field power exponent for Jacobian
  • power_b::Int - Total field power exponent for Jacobian
  • power_r::Int - Major radius power exponent for Jacobian
  • power_rc::Int - Minor radius (rfac = √((R-R₀)²+(Z-Z₀)²)) power exponent for Jacobian
  • r0exp::Float64 - Major radius normalization for CHEASE/EQDSK [m]
  • b0exp::Float64 - On-axis toroidal field normalization for CHEASE/EQDSK [T]
  • grid_type::String - Grid type for flux surface discretization ("log_asymptotic", "ldp")
  • psilow::Float64 - Lower limit of normalized flux coordinate
  • psihigh::Float64 - Upper limit of normalized flux coordinate
  • mpsi::Int - Number of radial grid points (0 = auto-compute from psi_accuracy)
  • psi_accuracy::Float64 - Target absolute error in q for auto-mpsi (used when mpsi=0 and gridtype="logasymptotic")
  • mtheta::Int - Number of poloidal grid points
  • newq0::Int - Override for on-axis safety factor (0 = use input value)
  • etol::Float64 - Error tolerance for equilibrium solver
  • force_termination::Bool - Terminate after equilibrium setup (skip stability calculations)
  • use_galgrid::Bool - Use the same grid as galerkin method
source
GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumParametersType
EquilibriumParameters

A mutable struct containing computed equilibrium parameters and diagnostic flags.

Fields

  • ro::Union{Nothing,Float64} - R-coordinate of the magnetic axis [m]
  • zo::Union{Nothing,Float64} - Z-coordinate of the magnetic axis [m]
  • psio::Union{Nothing,Float64} - Total flux difference |ψaxis - ψboundary| [Wb/rad]
  • rsep::Union{Nothing,Vector{Float64}} - R-coordinates of the plasma boundary [m]
  • zsep::Union{Nothing,Vector{Float64}} - Z-coordinates of the plasma boundary [m]
  • rext::Union{Nothing,Vector{Float64}} - R-coordinates of the plasma edge [m]
  • zext::Union{Nothing,Vector{Float64}} - Z-coordinates of the plasma edge [m]
  • psi0::Union{Nothing,Float64} - Normalized poloidal flux at reference location
  • b0::Union{Nothing,Float64} - Total magnetic field strength at the axis [T]
  • q0::Union{Nothing,Float64} - Safety factor at the axis
  • qmin::Union{Nothing,Float64} - Minimum safety factor in the plasma
  • qmax::Union{Nothing,Float64} - Maximum safety factor in the plasma
  • qa::Union{Nothing,Float64} - Safety factor at the plasma edge
  • q95::Union{Nothing,Float64} - Safety factor at 95% flux surface
  • qextrema_psi::Union{Nothing,Vector{Float64}} - Normalized flux values at q extrema
  • qextrema_q::Union{Nothing,Vector{Float64}} - Safety factor values at extrema
  • mextrema::Union{Nothing,Int} - Number of extrema in q-profile
  • psi_norm::Union{Nothing,Float64} - Normalized poloidal flux
  • b_norm::Union{Nothing,Float64} - Normalized magnetic field strength
  • psi_axis::Union{Nothing,Float64} - Poloidal flux at the axis
  • psi_boundary::Union{Nothing,Float64} - Poloidal flux at the boundary
  • psi_boundary_norm::Union{Nothing,Float64} - Normalized boundary flux
  • psi_axis_norm::Union{Nothing,Float64} - Normalized axis flux
  • psi_boundary_offset::Union{Nothing,Float64} - Boundary flux offset
  • psi_axis_offset::Union{Nothing,Float64} - Axis flux offset
  • psi_boundary_sign::Union{Nothing,Int} - Sign of boundary flux
  • psi_axis_sign::Union{Nothing,Int} - Sign of axis flux
  • psi_boundary_zero::Union{Nothing,Bool} - Whether boundary flux is zero
  • rmean::Union{Nothing,Float64} - Mean major radius [m]
  • amean::Union{Nothing,Float64} - Mean minor radius [m]
  • aratio::Union{Nothing,Float64} - Aspect ratio (R0/a)
  • kappa::Union{Nothing,Float64} - Plasma elongation
  • delta1::Union{Nothing,Float64} - Upper triangularity
  • delta2::Union{Nothing,Float64} - Lower triangularity
  • bt0::Union{Nothing,Float64} - Toroidal field at axis [T]
  • crnt::Union{Nothing,Float64} - Plasma current [A]
  • bwall::Union{Nothing,Float64} - Toroidal field at wall [T]
  • verbose::Bool - Enable verbose output
  • diagnose_src::Bool - Enable source data diagnostics
  • diagnose_maxima::Bool - Enable extrema diagnostics
  • volume::Union{Nothing,Float64} - Plasma volume [m³]
  • betat::Union{Nothing,Float64} - Toroidal beta
  • betan::Union{Nothing,Float64} - Normalized beta
  • betaj::Union{Nothing,Float64} - Total beta
  • betap1::Union{Nothing,Float64} - Poloidal beta (definition 1)
  • betap2::Union{Nothing,Float64} - Poloidal beta (definition 2)
  • betap3::Union{Nothing,Float64} - Poloidal beta (definition 3)
  • li1::Union{Nothing,Float64} - Internal inductance (definition 1)
  • li2::Union{Nothing,Float64} - Internal inductance (definition 2)
  • li3::Union{Nothing,Float64} - Internal inductance (definition 3)
source
GeneralizedPerturbedEquilibrium.Equilibrium.InverseRunInputType
InverseRunInput(...)

A container struct for inputs to the inverse_run function.

Fields

  • config::EquilibriumConfig - The equilibrium configuration object
  • sq_in::CubicSeriesInterpolant - 1D profile spline for F, P, q
  • rz_in_xs::Vector{Float64} - ψ coordinate grid for rz_in
  • rz_in_ys::Vector{Float64} - θ coordinate grid for rz_in
  • rz_in_R::CubicInterpolantND - R coordinate interpolant [m]
  • rz_in_Z::CubicInterpolantND - Z coordinate interpolant [m]
  • ro::Float64 - R-coordinate of magnetic axis [m]
  • zo::Float64 - Z-coordinate of magnetic axis [m]
  • psio::Float64 - Total flux difference |ψaxis - ψboundary| [Wb/rad]
source
GeneralizedPerturbedEquilibrium.Equilibrium.LargeAspectRatioConfigType
LargeAspectRatioConfig(...)

A mutable struct holding parameters for the Large Aspect Ratio (LAR) plasma equilibrium model.

Fields:

  • lar_r0: The major radius of the plasma [m].
  • lar_a: The minor radius of the plasma [m].
  • beta0: The beta value on axis (normalized pressure).
  • q0: The safety factor on axis.
  • p_pres: The exponent for the pressure profile, defined as p00 * (1 - (r / a)^2)^p_pres.
  • p_sig: The exponent that determines the shape of the current-related function profile.
  • sigma_type: The type of sigma profile, can be "default" or "wesson". If "wesson", the sigma profile is defined as sigma0 * (1 - (r / a)^2)^p_sig.
  • mtau: The number of grid points in the poloidal direction.
  • ma: The number of grid points in the radial direction.
  • zeroth: If set to true, it neglects the Shafranov shift
source
GeneralizedPerturbedEquilibrium.Equilibrium.PlasmaEquilibriumType
PlasmaEquilibrium(...)

The final, self-contained result of the equilibrium reconstruction. This object provides a complete representation of the processed plasma equilibrium in flux coordinates.

Fields

  • config::EquilibriumConfig: The equilibrium configuration object used for the reconstruction.

  • params::EquilibriumParameters: Computed equilibrium parameters and diagnostics.

  • profiles::ProfileSplines: Named 1D profile splines (F, P, dV/dψ, q) on normalized psi grid. Access values at grid points via profiles.F_spline.y[i], etc. Access derivatives via profiles.F_deriv.y[i] or profiles.F_deriv(psi).

  • Grid coordinates (shared by all rzphi/eqfun interpolants):

    • rzphi_xs::Vector{Float64}: ψ coordinates (length mpsi+1)
    • rzphi_ys::Vector{Float64}: θ coordinates (length mtheta+1)
  • Geometric quantities (rzphi, 4 interpolants): 2D cubic interpolants for flux-coordinate mapping with periodic BC in theta.

    • x value: normalized ψ
    • y value: SFL poloidal angle ∈ [0, 1]
    • rzphi_rsquared::CubicInterpolantND: r_coord² = (R - ro)² + (Z - zo)²
    • rzphi_offset::CubicInterpolantND: η/(2π) - θₙₑw (angle offset)
    • rzphi_nu::CubicInterpolantND: ν in ϕ = 2πζ + ν(ψ, θ)
    • rzphi_jac::CubicInterpolantND: Jacobian
  • Physics quantities (eqfun, 3 interpolants): 2D cubic interpolants storing local physics and geometric quantities.

    • x value: normalized ψ
    • y value: SFL poloidal angle θₙₑw
    • eqfun_B::CubicInterpolantND: Total magnetic field strength [T]
    • eqfun_metric1::CubicInterpolantND: (e₁⋅e₂ + q⋅e₃⋅e₁)/(J⋅B²)
    • eqfun_metric2::CubicInterpolantND: (e₂⋅e₃ + q⋅e₃⋅e₃)/(J⋅B²)
  • ro::Float64: R-coordinate of the magnetic axis [m]

  • zo::Float64: Z-coordinate of the magnetic axis [m]

  • psio::Float64: Total flux difference |Ψaxis - Ψboundary| [Weber/radian]

source
GeneralizedPerturbedEquilibrium.Equilibrium.ProfileSplinesType
ProfileSplines

Named 1D cubic spline interpolants for equilibrium profiles. Each profile is stored as a separate spline for code clarity.

Fields

  • xs::Vector{Float64}: Shared x-axis (normalized psi)
  • F_spline: 2π*F (toroidal flux function, where F = R * B_toroidal)
  • P_spline: μ₀*P (plasma pressure × μ₀)
  • dVdpsi_spline: dV/dψ (volume derivative)
  • q_spline: q (safety factor)

Derivative Interpolants (for continuous derivative evaluation)

  • F_deriv, P_deriv, dVdpsi_deriv, q_deriv: First derivative interpolants

Notes

  • Node values at grid points: Access via spline.y[i]
  • Derivative at any point: Call deriv(x) (derivative views are callable)
  • Grid: Access via xs field or spline.cache.x
source
GeneralizedPerturbedEquilibrium.Equilibrium.SolovevConfigType
SolovevConfig(...)

A mutable struct holding parameters for the Solev'ev (SOL) plasma equilibrium model.

Fields:

  • mr: number of radial grid zones
  • mz: number of axial grid zones
  • ma: number of flux grid zones
  • e: elongation
  • a: minor radius
  • r0: major radius
  • q0: safety factor at the o-point
  • p0fac: scale on-axis pressure (P-> P+P0*p0fac. beta changes. Phi,q constant)
  • b0fac: scale toroidal field at constant beta (sPhi,sf,s^2*P. bt changes. Shape,beta constant)
  • f0fac: scale toroidal field at constant pressure (s*f. beta,q changes. Phi,p,bp constant)
source
GeneralizedPerturbedEquilibrium.Equilibrium._build_psi_gridMethod
_build_psi_grid(equil_params, psilow, psihigh, fieldline_int, raw_profile, ro, zo, rs2)

Resolve mpsi and build psi_nodes for any supported grid_type.

For "log_asymptotic" with mpsi=0, estimates the separatrix log slope from two probe integrations and computes the minimum knot count for psi_accuracy. For "ldp", uses the sin²-spaced grid. Shared by direct_fieldline_int and efit_by_inversion solvers.

source
GeneralizedPerturbedEquilibrium.Equilibrium._estimate_log_slopeMethod
_estimate_log_slope(fieldline_int, raw_profile, ro, zo, rs2, psihigh)

Estimate the logarithmic slope A from two field-line probe integrations near the separatrix, using the asymptotic form q(ψ) ≃ −A·ln(1−ψ) (Fitzpatrick 2024, eq. 19).

Returns A = |Δq| / ln(2). Falls back to A=2.0 on integration failure.

source
GeneralizedPerturbedEquilibrium.Equilibrium._estimate_mid_spacingMethod
_estimate_mid_spacing(sq_in, psi_split_core, psi_split_edge, tau)

Estimate the uniform knot spacing needed in the middle ψ region to resolve the sharpest profile feature (usually the pressure pedestal) to relative accuracy tau.

Uses central-difference second derivatives of all 4 sqin profiles on a 300-point sample. The required spacing for profile k is hk = sqrt(8τ / d2normk) where d2normk is max|f''| / max|f| over [psisplitcore, psisplitedge].

source
GeneralizedPerturbedEquilibrium.Equilibrium._read_1d_gfile_formatMethod

read1dgfileformat(linesblock, numvalues)

Internal helper function to parse Fortran-style fixed-width numerical blocks from a vector of strings.

Arguments:

  • lines_block: A Vector{String} containing the lines to parse.
  • num_values: The total number of Float64 values to read from the block.

Returns:

  • A Vector{Float64} containing the parsed values.
source
GeneralizedPerturbedEquilibrium.Equilibrium._winding_number_vertsMethod
_winding_number_verts(verts, r_test, z_test)

Winding number point-in-polygon test (Sunday algorithm) on a Ctr.vertices vector. Returns the signed winding count; nonzero means the test point is inside the polygon. More robust than ray-casting for near-collinear edges (e.g., surfaces near an x-point).

source
GeneralizedPerturbedEquilibrium.Equilibrium.adaptive_grid_paramsMethod
adaptive_grid_params(raw_profile, ro, zo, r_lo, r_hi, z_lo, z_hi,
                     psilow, Δψ, bbox_curve) → (nr, nz, β_r, β_z)

Physics-based Cartesian grid sizing for contour-tracing equilibrium reconstruction.

Computes required cell widths from the bilinear interpolation error bound δψ ≈ (dR²·|ψRR| + dZ²·|ψZZ|)/8 ≤ Δψ → dRreq = √(8Δψ/|ψRR|) sampled at each LCFS vertex (reusing bbox_curve), plus an axis constraint ensuring the innermost surface (psilow) has ≥ 5 cells per semi-axis on the global grid.

β = acosh(hmax/hmin) from the ratio of coarsest to finest required cell widths. n = 1 + ⌈span·sinch(β)/h_min⌉ where sinch(β) = β/sinh(β).

source
GeneralizedPerturbedEquilibrium.Equilibrium.arclength_fieldline_der!Method
arclength_fieldline_der!(dy, y, params, s)

RHS for the arc-length-parameterized level-set ODE.

State y = [R, Z, ∫dl/Bp, ∫dl/(R²Bp), ∫jac·dl/Bp]. The independent variable s is arc length [m].

The tangent direction (dR/ds, dZ/ds) = (∂ψ/∂Z, −∂ψ/∂R) / |∇ψ| follows the ψ = const level set counterclockwise, staying on the flux surface without correction.

Near x-points where Bp → 0, the position integration (dy[1:2]) remains well-behaved because grad_norm never appears in the denominator alone. dy[3:5] use abstol=1e20 so the solver never restricts step size for them.

source
GeneralizedPerturbedEquilibrium.Equilibrium.arclength_fieldline_intMethod
arclength_fieldline_int(psifac, raw_profile, ro, zo, rs2)

Arc-length-parameterized flux surface integration. Drop-in replacement for direct_fieldline_int with identical return format:

  • y_out[:, 1]: geometric angle η ∈ 0 to 2π (CCW from outboard midplane)
  • y_out[:, 2]: accumulated ∫dl/Bp
  • y_out[:, 3]: rfac = √((R−ro)² + (Z−zo)²)
  • y_out[:, 4]: accumulated ∫dl/(R²Bp)
  • y_out[:, 5]: accumulated ∫jac·dl/Bp

The ODE is terminated by a ContinuousCallback that detects the return to the outboard midplane (Z = zo, R > ro) after a minimum arc-length guard.

source
GeneralizedPerturbedEquilibrium.Equilibrium.classify_topologyMethod
classify_topology(raw_profile, psio; xpt_threshold=0.05) → Symbol

Classify the plasma topology as :limited, :sn_lower, :sn_upper, or :double_null by evaluating ψ on the (R, Z) grid and finding the minimum in each Z half-domain.

An x-point is detected when the minimum ψ in a half-domain falls below xpt_threshold * psio.

source
GeneralizedPerturbedEquilibrium.Equilibrium.direct_fieldline_der!Method
direct_fieldline_der!(dy, y, params, eta)

The derivative function for the field-line integration ODE. This is passed to the DifferentialEquations.jl solver. This is a Julia adaptation of the Fortran direct_fl_der subroutine, with an added safeguard against division by zero.

Arguments:

  • dy: The derivative vector (output, modified in-place).
  • y: The state vector [∫(dl/Bp), rfac, ∫(dl/(R²Bp)), ∫(jac*dl/Bp)].
  • params: A FieldLineDerivParams struct with all necessary parameters.
  • eta: The independent variable (geometric angle η).
source
GeneralizedPerturbedEquilibrium.Equilibrium.direct_fieldline_intMethod
direct_fieldline_int(psifac, raw_profile, ro, zo, rs2)

Performs the field-line integration for a single flux surface. This is a Julia adaptation of the Fortran direct_fl_int subroutine. Note that the array y_out is now indexed from 1:5 rather than 0:4 as in Fortran.

Arguments:

  • psifac: normalized psi value for the surface (ψ_norm).
  • raw_profile: DirectRunInput object containing splines and parameters.
  • ro, zo: Coordinates of the magnetic axis [m].
  • rs2: R-coordinate of the outboard separatrix [m].

Returns:

- `y_out`: A matrix containing the integrated quantities vs. the geometric angle `η`.
    - `y_out[:, 1]`: η (geometric poloidal angle)
    - `y_out[:, 2]`: ∫(dl/Bp)
    - `y_out[:, 3]`: rfac (radial distance from magnetic axis)
    - `y_out[:, 4]`: ∫(dl/(R²Bp))
    - `y_out[:, 5]`: ∫(jac*dl/Bp)
  • bfield: A DirectBField object with values at the integration start point.
source
GeneralizedPerturbedEquilibrium.Equilibrium.direct_get_bfield!Method
direct_get_bfield!(bf_out, r, z, psi_in, sq_in, sq_in_deriv, psio; derivs=0)

Calculates the magnetic field and its derivatives at a given (R,Z) point. The results are stored in-place in the bf_out object. This is equivalent to the direct_get_bfield subroutine in the Fortran code, adapted for the Julia spline implementation.

Arguments:

  • bf_out: A mutable DirectBField struct to store the results
  • r: R-coordinate to evaluate at
  • z: Z-coordinate to evaluate at
  • psi_in: 2D cubic interpolant for poloidal flux ψ(R,Z)
  • sq_in: 1D cubic spline for profiles F(ψ_norm) and P(ψ_norm)
  • sq_in_deriv: Pre-computed derivative view of sq_in
  • psio: total toroidal flux
  • derivs: An integer specifying number of derivatives to compute (0, 1, or 2)
source
GeneralizedPerturbedEquilibrium.Equilibrium.direct_position!Method
direct_position!(raw_profile)

Finds the key geometric locations of the equilibrium: the magnetic axis (O-point) and the inboard/outboard separatrix crossings on the midplane. It also updates the spline representing the poloidal flux ψ(R,Z) based on the new magnetic axis location. This function performs the same overall function as the Fortran direct_position subroutine with better iteration control and error handling. We have also added a helper function for separatrix finding.

Arguments:

  • raw_profile: A DirectRunInput object containing splines and parameters.

Returns:

  • ro: R-coordinate of the magnetic axis [m].
  • zo: Z-coordinate of the magnetic axis [m].
  • rs1: R-coordinate of the inboard separatrix crossing [m].
  • rs2: R-coordinate of the outboard separatrix crossing [m].
  • psi_in_new : returns psi_in renormalized by * psio/psi(ro,zo)
source
GeneralizedPerturbedEquilibrium.Equilibrium.direct_refineMethod
direct_refine(rfac, eta, psi0, params)

Refines the radial distance rfac at a given angle eta to ensure the point lies exactly on the target flux surface psi0.

Arguments:

  • rfac: The current guess for the radial distance from the magnetic axis.
  • eta: The geometric poloidal angle.
  • psi0: The target ψ value for the flux surface.
  • params: A FieldLineDerivParams struct.

Returns:

  • The refined rfac value.
source
GeneralizedPerturbedEquilibrium.Equilibrium.equilibrium_gse!Method
equilibrium_gse!(equil::PlasmaEquilibrium)

Diagnoses the Grad-Shafranov solution by computing the residual of the Grad-Shafranov equation across the grid and writing diagnostic data to HDF5 files. Performs the same function as equiloutgse in the Fortran code.

source
GeneralizedPerturbedEquilibrium.Equilibrium.equilibrium_solverFunction
equilibrium_solver(raw_profile)

The main driver for the direct equilibrium reconstruction. It orchestrates the entire process from finding the magnetic axis to integrating along field lines and constructing the final coordinate and physics quantity splines. This performs the same overall function as the Fortran direct_run subroutine, with better checks for numerical robustness.

Arguments:

  • raw_profile: A DirectRunInput object containing the initial splines (psi_in, sq_in) and run parameters (equil_input).

Returns:

  • A PlasmaEquilibrium object containing the final, processed equilibrium data, including the profile spline (sq), the coordinate mapping spline (rzphi), and the physics quantity spline (eqfun).
source
GeneralizedPerturbedEquilibrium.Equilibrium.equilibrium_solver_by_inversionMethod
equilibrium_solver_by_inversion(raw_profile; resolution_factor=1.0,
                                refine=nothing, β_r=nothing, β_z=nothing)

Driver for contour-tracing equilibrium reconstruction.

Grid parameters (n and β in each direction) are computed adaptively from the bilinear interpolation error bound along the LCFS and an axis constraint. resolution_factor scales both n values uniformly (higher → more points, same β).

Legacy keyword arguments refine, β_r, β_z override the adaptive values when provided (for benchmark sweeps and backward compatibility).

Select via eq_type = "efit_by_inversion" in gpec.toml.

source
GeneralizedPerturbedEquilibrium.Equilibrium.inverse_extrapMethod
inverse_extrap(xx::Matrix{Float64}, ff::Matrix{Float64}, x::Float64) -> Vector{Float64}

Performs component-wise Lagrange extrapolation for a vector-valued function.

Arguments:

  • xx: A (m × n) matrix where each row contains the x-values for each component.
  • ff: A (m × n) matrix where each row contains function values at the corresponding xx.
  • x: A scalar Float64 value at which to extrapolate.

Returns:

  • A vector of length n representing the extrapolated function values at x.
source
GeneralizedPerturbedEquilibrium.Equilibrium.lar_init_conditionsMethod
lar_init_conditions(rmin, sigma_type, params)

Initializes the starting radius and state vector for solving the LAR ODE system. Also evaluates the initial derivative using the analytic model.

Arguments:

  • rmin: Normalized starting radius (as a fraction of lar_a).
  • lar_input: A LargeAspectRatioConfig object containing equilibrium parameters.

Returns:

  • r: Physical radius corresponding to rmin * lar_a.
  • y: Initial state vector of length 5.
source
GeneralizedPerturbedEquilibrium.Equilibrium.make_multi_stretched_gridMethod
make_multi_stretched_grid(lo, hi, centers, n, β) → Vector{Float64}

Build a 1D grid of length n on [lo, hi] with sinh-stretching toward each point in centers. The domain is split at each interior concentration point; each resulting sub-interval uses:

  • symmetric (double-ended) sinh when both endpoints are concentration points
  • one-sided sinh fine at the concentration-point end otherwise

Domain boundaries (lo, hi) are treated as concentration points only if they appear in centers. This produces a grid that is simultaneously fine near the magnetic axis (an interior concentration point) and near x-points (which lie at domain boundaries for the clipped plasma bounding box). Returns a uniform grid if β ≤ 0.

source
GeneralizedPerturbedEquilibrium.Equilibrium.make_optimal_mpsiMethod
make_optimal_mpsi(psilow, psihigh, A, sq_in; tau, psi_split_core, psi_split_edge)

Compute the minimum number of radial knots needed to achieve target accuracy τ in q, given the separatrix log slope A. Three-region geometric grid: core, pedestal, far edge. The middle-region spacing is driven by profile curvature (P, F, dV/dψ, q) via sq_in.

source
GeneralizedPerturbedEquilibrium.Equilibrium.make_optimal_psi_gridMethod
make_optimal_psi_grid(psilow, psihigh, N_core, N_mid, N_edge; psi_split_core, psi_split_edge)

Build a three-region ψ grid with (Ncore + Nmid + N_edge)+1 knots, using the counts directly as provided — core and edge are geometric in log(ψ) and log(1−ψ) respectively; middle is uniform in ψ.

source
GeneralizedPerturbedEquilibrium.Equilibrium.make_stretched_z_gridMethod
make_stretched_z_grid(z_lo, z_hi, zo, nz, topology, β_z) → Vector{Float64}

Grid of nz points on [z_lo, z_hi] concentrated near zo (magnetic axis) and near each x-point boundary (at z_lo for :sn_lower/:double_null, at z_hi for :sn_upper/:double_null). Thin wrapper around make_multi_stretched_grid.

source
GeneralizedPerturbedEquilibrium.Equilibrium.read_chease_asciiMethod
read_chease_ascii(config)

Parses a ascii CHEASE file, creates initial 1D and 2D splines, finds magnetic axis, and bundles them into a InverseRunInput object.

Arguments:

  • config: The EquilibriumConfig object containing the filename and parameters.

Returns:

  • A InverseRunInput object ready for the inverse solver.
source
GeneralizedPerturbedEquilibrium.Equilibrium.read_efitMethod
_read_efit(equil_in)

Parses an EFIT g-file, creates initial 1D and 2D splines, and bundles them into a DirectRunInput object.

Arguments:

  • equil_in: The EquilInput object containing the filename and parameters.

Returns:

  • A DirectRunInput object ready for the direct solver.
source
GeneralizedPerturbedEquilibrium.Equilibrium.resample_contour_to_theta_grid!Method
resample_contour_to_theta_grid!(R_out, Z_out, curve, ro, zo, theta_grid)

Resample a Contour.jl curve onto a uniform geometric-angle grid, writing results directly into the pre-allocated R_out and Z_out vectors (views into Rtable/Ztable).

Uses a polar representation: fits a cubic spline on log ρ(η) where ρi = sqrt((Ri − ro)² + (Zi − zo)²) and ηi = atan2(Zi − zo, Ri − ro). This guarantees exp(logρ_spl) > 0 everywhere — a self-intersecting contour is impossible by construction — making it robust near x-points where R(η) and Z(η) splines tend to overshoot between widely-spaced knots.

source
GeneralizedPerturbedEquilibrium.Equilibrium.sol_runMethod

This function handles the Solovev analytical equilibrium model, transforming the input parameters into the necessary splines and scalar values for equilibrium construction. This is a Julia version of the Fortran code in sol.f, with no major differences except for arrays going from 0:n to 1:n+1.

Arguments:

  • mr: Number of radial grid zones
  • mz: Number of axial grid zones
  • ma: Number of flux grid zones
  • e: Elongation
  • a: Minor radius
  • r0: Major radius
  • q0: Safety factor at the o-point
  • p0fac: Scales on axis pressure (s*P. beta changes. Phi,q constant)
  • b0fac: Scales on toroidal field (sPhi,sf,s^2*P. bt changes. Shape,beta constant)
  • f0fac: Scales on toroidal field (s*f. bt,q changes. Phi,p,bp constant)

Returns:

  • DirectRunInput object
source

Important types

  • EquilibriumConfig — top-level configuration container parsed from a
TOML file (outer constructor `EquilibriumConfig(path::String)` is
provided).
  • EquilibriumControl — low-level control parameters (grid, jacobian
type, tolerances, etc.).
  • PlasmaEquilibrium — the runtime structure containing spline fields,
geometry, profiles, and computed diagnostics (q-profile, separatrix,
etc.).
  • LargeAspectRatioConfig, SolevevConfig — convenience structs to
construct analytic/model equilibria when using `eq_type = "lar"` or
`eq_type = "sol"`.

Key functions

  • setup_equilibrium(path::String = "equil.toml")
— main entry point that reads configuration, builds the equilibrium,
runs the solver, and returns a `PlasmaEquilibrium` instance.
  • equilibrium_separatrix_find!(pe::PlasmaEquilibrium) — locate
separatrix and related boundary geometry in-place.
  • equilibrium_global_parameters!(pe::PlasmaEquilibrium) — populate
common global parameters (major radius, magnetic axis, volumes, etc.).
  • equilibrium_qfind!(pe::PlasmaEquilibrium) — compute safety factor
(q) information across the grid.
  • equilibrium_gse!(pe::PlasmaEquilibrium) — diagnostics on the
Grad–Shafranov solution.

Example usage

Basic example: read a TOML config and build an equilibrium

using GeneralizedPerturbedEquilibrium

# Build from a TOML file (searches relative paths if needed)
pe = GeneralizedPerturbedEquilibrium.Equilibrium.setup_equilibrium("docs/examples/ForceFreeStates.toml")

println("Magnetic axis: ", pe.params.r0, ", ", pe.params.z0)
println("q(0) = ", pe.params.q0)

# Find separatrix (in-place) and inspect results
GeneralizedPerturbedEquilibrium.Equilibrium.equilibrium_separatrix_find!(pe)
println("rsep = ", pe.params.rsep)

Analytic / testing example: construct a large-aspect-ratio model

using GeneralizedPerturbedEquilibrium

# Create a LAR config from a small TOML fragment or file
larcfg = GeneralizedPerturbedEquilibrium.Equilibrium.LargeAspectRatioConfig(lar_r0=10.0, lar_a=1.0, beta0=1e-3)
pe = GeneralizedPerturbedEquilibrium.Equilibrium.setup_equilibrium(GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumConfig(control=Dict("eq_filename"=>"unused","eq_type"=>"lar")), larcfg)

println("Built LAR equilibrium with a = ", lorcfg.lar_a)

Notes and Caveats

  • EquilibriumConfig is constructed from the [Equilibrium] section of gpec.toml. Paths that are not absolute are resolved relative to the TOML file location.
  • The Equilibrium module contains readers for EFIT and CHEASE formats. Ensure the required data files are present and paths are set correctly in gpec.toml.

See also

  • docs/src/vacuum.md — coupling between equilibrium and vacuum solvers