Skip to content

Ballooning: guarantee pedestal resolution in auto-gridding, and make a default psi-window the standard for ballooning scans #308

Description

@logan-nc

Sub-issue of #302. #302 covers auto-mpsi under-resolving the edge (spurious dW / Δ′); this issue covers the ballooning-stability consequences and a paired performance default.

1. Auto-gridding must guarantee pedestal resolution for ballooning physics

High-n ballooning stability (Δ′, the s–α first/second boundaries in src/ForceFreeStates/Ballooning.jl) is physically most relevant in the pedestal, ψ_N ≈ 0.8–0.98. The edge under-resolution in #302 (N_edge ≈ 5 at the default psi_accuracy = 1e-3) under-resolves this whole band, not just the last rational surface — so the ballooning boundary profile there is unreliable. Whatever fix lands for the N_edge/N_mid imbalance in make_optimal_mpsi should explicitly ensure adequate, efficient resolution across the 0.8–0.98 pedestal band (not merely a handful of points at ψ→1), for log_asymptotic auto-mpsi as well as ldp / power gridding.

2. Make a default psi-window the standard for ballooning scans (performance)

The α-boundary drivers (ballooning_alpha_boundary / ballooning_alpha_boundaries) loop over every equilibrium ψ node and run up to n_scan (~24) ODE shooting solves per surface — the dominant local-stability cost (~24.5 s / 54 GB on the DIII-D case). The tightly packed axis (ψ<0.1) and far-edge (ψ>0.98) nodes produced by ldp / log_asymptotic / power gridding waste solves where ballooning boundaries are rarely used. Proposal: by default evaluate the ballooning α-boundary scan only on

ψ_N ∈ [0.1, min(0.99, psi_edge, psihigh)]

which trims the worst axis and edge packing across all grid types while retaining the pedestal.

Ordering / dependency

(2) depends on (1). Windowing a grid that is under-resolved in the pedestal just locks in the spurious values from #302, so the pedestal-resolution fix must land before or together with the default window.

Implementation notes (from prior analysis)

  • Clean approach for (2) is an index window/mask over the existing grid in the two α-boundary drivers, reusing the existing NaN sentinel (the drivers already fill(NaN, npsi) and continue on xs[i] > 1.0; outputs stay length-npsi, aligned to the ψ axis). A separate ballooning grid is too dirty: prepare_ballooning_coefficients, salpha_reference, and resistive_interchange_h read precomputed nodal bicubic partials (rzphi_*.nodal_derivs.partials[k, idx, itheta]) and spline node values (profiles.<spline>.y[idx]) that exist only at grid nodes — off-node evaluation re-architects all three and pays the geometry-bicubic cost.
  • Leave compute_ballooning_stability! (di / dr / Δ′, locstab cols 1/2/4) un-windowed or finite-filled: its locstab_fs is splined and evaluated at singular surfaces (intr.locstab(sing.psifac)), so a NaN at a skipped node would poison the whole profile.

Config question for reviewers (please weigh in)

I'd prefer not to add TOML window specifiers if everyone agrees the hard-coded default [0.1, min(0.99, psi_edge, psihigh)] is sufficient. Two things to confirm:

  1. Is a fixed default window acceptable, or do we need a [ForceFreeStates] config knob?
  2. Does min(0.99, psi_edge, psihigh) still span the full pedestal band of interest in your cases (i.e. it must not clip ψ_N ≈ 0.8–0.98)?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions