outward superbanana#2220
Open
unalmis wants to merge 16 commits into
Open
Conversation
e776baf to
bafdf25
Compare
This was referenced May 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #1748 .
batchutility to public apiSummary
This branch adds the Velasco prompt-loss metrics
Gamma_deltaandGamma_alpha, updates the VelascoGamma_cimplementation to the normalized\check{\Gamma}_cquantity, and introduces a reusableGammaLossobjective forthe new metrics.
It also factors several support utilities used by bounce-integral objectives:
Bounce1D.batchandBounce2D.batchnow own the common surface-batching,reshaping, FFT, and sparse-pullback plumbing.
Options._compute_objective(...)now owns the repeated objective path thatmaps field-line labels to
angleand calls compute functions.check_nufft(...)centralizes thejax-finufftavailability fallback._LossConeinquad_utils.pyimplements the periodic interval logic used byGamma_alpha.This branch does not include the later alpha-folding work #2223 for code simplicity. Here,
Gamma_deltaandGamma_alphareduce over theopts.alphasamples directly.1. Fast-Ion Compute Path
The branch adds a shared private compute driver:
The driver computes the common bounce-integral quantities
then delegates the final pitch/alpha/well reduction to one of:
This keeps the expensive bounce computation shared across the Velasco metrics
and makes each metric easier to review as a small mathematical reduction.
The branch also removes per-function
thetatoanglecompatibility logic fromthese compute functions. That argument migration is now handled once in
desc.compute.utils.compute(...).2.
Gamma_c VelascoNormalization ChangeThe branch changes the registered
"Gamma_c Velasco"compute quantity from theolder equation-16 normalization to the normalized
\check{\Gamma}_cquantity referenced as equation 20 in Velasco et al.The reduction itself is still
with
The scalar normalization in
_Gamma(...)is3.
Gamma_deltaGamma_deltaimplements Velasco model I: a pitch/well branch is counted as lostif there exists an outward superbanana somewhere in alpha.
The code uses monotonicity of arctan to bypass the nonlinearities of an
arctanas well assafedivby using the tangent-space threshold stored inopts.thresh:The branch condition is
This is equivalent to asking whether the signed drift ratio exceeds the
threshold, while preserving the direction of the radial drift. The reduction is
4.
Gamma_alphaGamma_alphaimplements Velasco model II: only the alpha interval betweeninward and outward superbanana branches is counted as lost.
The code constructs two signed branch scores:
where
Thus:
The interval orientation depends on the sign of the poloidal drift:
The edge-case rule is:
The final reduction is
5.
_LossConePeriodic Interval Logic_LossCone.indicator(...)turns signed branch scores into a periodic loss-coneindicator over the sampled alpha grid.
For
order=0, it returns the sampled boolean interval mask.For
order=1, it improves the interval boundary placement by linearlyinterpolating zero crossings of the signed scores. If the previous score is
p <= 0, the current score iss > 0, and the alpha spacing isdx, then theroot is located by
Each start crossing is paired to the first downstream stop crossing using the
forward periodic distance matrix
The
order=1output is a fractional generalized indicator in[0, 1], givingthe fraction of each uniform alpha cell covered by the loss interval.
Review point: this improves the discontinuous interval boundary without
interpolating
v_tau; the sampledv_tauvalues are still used as the cellvalues.
NOTE: Forming a distance matrix is not the most efficient strategy for this. However, I chose this implementation because the code is simpler.For a more detailed derivation of the loss-cone interval construction,
linear crossing formula, and fractional-width quadrature, see the end of this file.
6. Objective API
The branch adds:
where
Defaults:
GammaLoss._default_alpha(eq)returns 16 uniformly spaced field-line labels onwith
endpoint=False.The objective uses the shared
flow that is also adopted by
GammaC,EffectiveRipple, andAvailableEnergy.Review point:
GammaLossis one objective class with a requiredkindstring,not two separate objective classes.
7. Shared Infrastructure Changes
Bounce*D.batchBounce1D.batchandBounce2D.batchnow accept:Bounce2D.batchadditionally requiresangle=....This moves repeated reshape/FFT/surface-batching logic out of individual compute
functions. The old pattern passed a partially prepared
fun_datadictionary andmutated it. The new pattern builds the batched data dictionary internally from
data,names,custom_data, andrho_data.Options._compute_objectiveThe shared objective compute path now:
iota.anglethrough_map_poloidal_coordinates.angle,alpha, quadrature constants,and the objective hyperparameters.
This removes duplicated logic from fast-ion, neoclassical, and turbulence
objectives.
check_nufftThe NUFFT availability fallback now lives in
_interp_utils.pyand is reused bythe relevant objectives. It preserves the prior behavior: if
jax-finufftisunavailable and
nufft_epsrequests NUFFT use, warn and setnufft_eps = 0.0.Math Note: Loss-Cone Indicator For
Gamma_alphaGoal
This note explains the math behind the loss-cone indicator used in
Gamma_alpha, especially why the implementation uses linearly interpolatedcrossings and fractional cell widths, but does not interpolate
v_tau.For this branch, fix one flux surface, one pitch value, and one well branch.
All quantities below are functions of the field-line label
alpha.Branch Scores
Let
denote the bounce-integrated radial drift contribution, and let
denote the corresponding poloidal drift contribution. The threshold parameter
is stored in tangent space:
The outward and inward superbanana candidate scores are
and
Thus
means the branch is sufficiently outward drifting, while
means the branch is sufficiently inward drifting.
Equivalently, the outward condition is
and the inward condition is
The absolute value is on the poloidal drift only. We do not take
abs(radial), because inward-only branches should not count as outwardsuperbanana branches.
Loss Interval Orientation
Gamma_alphacounts alpha intervals between inward and outward branches. Theorientation depends on the sign of the poloidal drift.
If
the loss interval starts at the inward branch and stops at the next outward
branch:
If
the orientation reverses:
This is why the code calls the interval indicator twice with reversed
start/stop scores and then selects by the sign of
poloidal.Indicator As A Set
For a chosen start score
s_startand stop scores_stop, define the startcrossing set
and the stop crossing set
For each start crossing
we pair it with the first downstream stop crossing
The corresponding loss interval is
The continuous loss-cone indicator is then
The code constructs a sampled or fractional approximation to this indicator.
Linear Crossing Formula
Suppose a score crosses zero between two adjacent alpha samples:
Let
Assume
sis linear on the cell:The root satisfies
so
Thus the root is
The implementation stores the distance from the current sample backward to the
root:
That is the formula
in
_LossCone._root.order=0: Sampled IndicatorFor
order=0, no crossing interpolation is used. The code treats positivesample values as branch events and marks each sampled alpha as either inside or
outside the nearest start-to-stop interval.
This is simple, but the estimated interval length can be wrong by
because each crossing is snapped to the nearest sample.
order=1: Fractional Cell WidthFor
order=1, the code first finds the linearly interpolated start and stopcrossings. Then each alpha sample is assigned a cell
Instead of returning a boolean value, the loss-cone indicator returns the
fraction of that cell covered by the loss interval:
So
This is the "fractional width". A sample whose cell is fully inside the
loss interval has weight
1. A sample whose cell is fully outside has weight0. A sample whose cell is cut by a crossing gets a value between0and1.Why We Do Not Interpolate
v_tauThe
Gamma_alphaalpha integral has the formwhere
for the fixed pitch and well branch.
The discontinuous part is
not usually
V(alpha). The method uses the sampled valueas the value on cell
C_i, but integrates the discontinuous domain restrictionwith the fractional cell coverage:
Equivalently, because
the quadrature contribution is
So the fractional method improves the geometric measure of the loss interval
without pretending to know new values of
V(alpha).Why Interpolating Samples Is Not The Main Accuracy Gain
Simply upsampling a quadrature integrand by interpolation does not generally
create new information. If we only interpolated
then integrated the interpolant, we would still be limited by the sampled
location of the discontinuity in
The useful extra information here is different: the signed scores
contain sub-cell information about where the indicator changes state. Linear
root finding uses that signed information to locate the loss interval boundary
inside the cell.
This improves the convergence of the interval measure even though
v_tauisnot interpolated.
Code Map
The main implementation points are:
_reduction_gamma_alphaoutward_scoreandinward_score.poloidal.v_tau * loss_coneover alpha and sums over wells._LossCone._rootoffset = dx * score / (score - previous)._LossCone.indicator(..., order=0)_LossCone.indicator(..., order=1)