You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Julia port of Fortran gpvacuum_flxsurf — compute_surface_inductance_from_greens in src/PerturbedEquilibrium/SingularCoupling.jl — does not reproduce the Fortran theta-reversal / Fourier-transform sequence exactly. The current Julia form was chosen because it reproduces the previously-validated numerical result, but a more faithful port produces significantly different singular-coupling metrics. Which form actually matches Fortran best is unresolved and needs a deeper trace plus broader benchmarking.
Surfaced during the PR #196 review while unifying the FourierTransform sign convention.
What Fortran does
gpvacuum_flxsurf (in gpec/gpvacuum.f) builds the surface-inductance "current" matrix from the vacuum Green's functions. Per column mode, for each theta point it:
Reads the Green's function grri/grre at the reversed theta index (rtheta = mthsurf - itheta).
Forms the complex field grri_real - i*grri_imag (and the exterior analogue).
Multiplies by the toroidal phase EXP(-i*n*dphi) evaluated at the forward index (itheta+1).
Applies iscdftf — the exp(-imθ) forward DFT.
Key point: Fortran reverses only the un-phased Green's function; the toroidal phase is applied un-reversed. The theta reversal exists because the Green's-function rows come from VACUUM/mscvac, whose theta grid runs opposite to GPEC/DCON theta.
What Julia currently does
After PR #196 unified the FourierTransform forward to exp(-imθ) (Fortran iscdftf), compute_surface_inductance_from_greens computes:
i.e. Julia reverses the phased product (Green's function × phase together), not just the un-phased Green's function. This is algebraically equivalent to the historical pre-unification behavior (the old real-input ft used exp(+imθ), which silently absorbed a full reversal), and it reproduces the validated DIII-D benchmark.
There is also a smaller open detail: _reverse_theta uses circshift(reverse(v), 1) vs plain reverse(v) — these differ by a single-grid-step exp(im·2π/N) per-mode phase, and the correct choice depends on the exact index convention of iscdftf / the Julia ft.
Finding: a more faithful port changes the answer significantly
A stricter port matching Fortran — reverse only the un-phased Green's function, apply the phase forward — was benchmarked against Fortran GPEC (DIII-D, n=1):
q
ψ
Φ_res err, current Julia
Φ_res err, faithful port
2
0.594
14.6%
97.2%
3
0.819
9.8%
9.0%
4
0.928
21.2%
38.1%
5
0.988
50.6%
4.3%
The faithful port sharply improves the edge surface (q=5: 50.6% → 4.3%) but badly regresses the core (q=2: 14.6% → 97%). Neither pure form is cleanly correct, so the stricter port was not merged. The mixed result strongly suggests a real theta-convention mismatch somewhere in the chain — most likely the Julia Vacuum module orders the Green's-function rows and/or the SFL toroidal offset ν differently than Fortran orders grri vs dphi, so a single-call-site fix cannot resolve it.
What needs to be done
Trace the Julia Vacuum theta conventions end-to-end. Determine the theta ordering of the grri/grre rows produced by the Julia Vacuum module, and the ordering of ν from Vacuum.PlasmaGeometry, and compare against how Fortran orders grri (VACUUM theta) vs dphi (DCON theta). Confirm whether the Julia reimplementation preserves or removes the VACUUM/DCON theta-order mismatch.
Pin the iscdftf index convention so the _reverse_theta grid-step ambiguity (reverse vs circshift(reverse,1)) is settled analytically, not by trial.
Benchmark with equilibrium scans, not the single DIII-D n=1 case — multiple equilibria and multiple toroidal mode numbers — to determine which form genuinely matches Fortran across the board. The q=2-vs-q=5 split above shows a single case is not enough to decide.
Pointers
Julia consumer: src/PerturbedEquilibrium/SingularCoupling.jl — compute_surface_inductance_from_greens and the _reverse_theta helper.
Fortran reference: gpec/gpvacuum.f — gpvacuum_flxsurf; DFT definitions in gpec/ismath.f (iscdftf/iscdftb).
Summary
The Julia port of Fortran
gpvacuum_flxsurf—compute_surface_inductance_from_greensinsrc/PerturbedEquilibrium/SingularCoupling.jl— does not reproduce the Fortran theta-reversal / Fourier-transform sequence exactly. The current Julia form was chosen because it reproduces the previously-validated numerical result, but a more faithful port produces significantly different singular-coupling metrics. Which form actually matches Fortran best is unresolved and needs a deeper trace plus broader benchmarking.Surfaced during the PR #196 review while unifying the
FourierTransformsign convention.What Fortran does
gpvacuum_flxsurf(ingpec/gpvacuum.f) builds the surface-inductance "current" matrix from the vacuum Green's functions. Per column mode, for each theta point it:grri/grreat the reversed theta index (rtheta = mthsurf - itheta).grri_real - i*grri_imag(and the exterior analogue).EXP(-i*n*dphi)evaluated at the forward index (itheta+1).iscdftf— theexp(-imθ)forward DFT.Key point: Fortran reverses only the un-phased Green's function; the toroidal phase is applied un-reversed. The theta reversal exists because the Green's-function rows come from VACUUM/
mscvac, whose theta grid runs opposite to GPEC/DCON theta.What Julia currently does
After PR #196 unified the
FourierTransformforward toexp(-imθ)(Fortraniscdftf),compute_surface_inductance_from_greenscomputes:i.e. Julia reverses the phased product (Green's function × phase together), not just the un-phased Green's function. This is algebraically equivalent to the historical pre-unification behavior (the old real-input
ftusedexp(+imθ), which silently absorbed a full reversal), and it reproduces the validated DIII-D benchmark.There is also a smaller open detail:
_reverse_thetausescircshift(reverse(v), 1)vs plainreverse(v)— these differ by a single-grid-stepexp(im·2π/N)per-mode phase, and the correct choice depends on the exact index convention ofiscdftf/ the Juliaft.Finding: a more faithful port changes the answer significantly
A stricter port matching Fortran — reverse only the un-phased Green's function, apply the phase forward — was benchmarked against Fortran GPEC (DIII-D, n=1):
The faithful port sharply improves the edge surface (q=5: 50.6% → 4.3%) but badly regresses the core (q=2: 14.6% → 97%). Neither pure form is cleanly correct, so the stricter port was not merged. The mixed result strongly suggests a real theta-convention mismatch somewhere in the chain — most likely the Julia Vacuum module orders the Green's-function rows and/or the SFL toroidal offset
νdifferently than Fortran ordersgrrivsdphi, so a single-call-site fix cannot resolve it.What needs to be done
grri/grrerows produced by the Julia Vacuum module, and the ordering ofνfromVacuum.PlasmaGeometry, and compare against how Fortran ordersgrri(VACUUM theta) vsdphi(DCON theta). Confirm whether the Julia reimplementation preserves or removes the VACUUM/DCON theta-order mismatch.iscdftfindex convention so the_reverse_thetagrid-step ambiguity (reversevscircshift(reverse,1)) is settled analytically, not by trial.Pointers
src/PerturbedEquilibrium/SingularCoupling.jl—compute_surface_inductance_from_greensand the_reverse_thetahelper.gpec/gpvacuum.f—gpvacuum_flxsurf; DFT definitions ingpec/ismath.f(iscdftf/iscdftb).bc321504unified theFourierTransformconvention and made the reversal explicit).