Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions docs/figure_tools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ Short git commit and ISO date stamped onto every figure. `commit` is the
`git rev-parse --short HEAD` hash (reusing the idiom from
`benchmarks/benchmark_git_branches.jl`), with a `-dirty` suffix when the
working tree has uncommitted changes so a figure never claims a cleaner
provenance than it has. Falls back to `"unknown"` outside a git checkout.
provenance than it has. Generated figures and the manifest do not count as changes, so
several figures can be regenerated in turn on one clean commit. Falls back to `"unknown"`
outside a git checkout.
"""
function figure_provenance()
date = string(Dates.today())
try
h = strip(read(`git -C $(_REPO_ROOT) rev-parse --short HEAD`, String))
dirty = !isempty(strip(read(`git -C $(_REPO_ROOT) status --porcelain`, String)))
h = String(strip(read(`git -C $(_REPO_ROOT) rev-parse --short HEAD`, String)))
outputs = [":(exclude,glob)docs/src/figures/**/*.png", ":(exclude)docs/src/figures/manifest.toml"]
dirty = !isempty(strip(read(`git -C $(_REPO_ROOT) status --porcelain -- . $outputs`, String)))
return (; commit=(dirty ? "$h-dirty" : h), date=date, dirty=dirty)
catch
return (; commit="unknown", date=date, dirty=false)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/citations.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Provides an efficient algorithm for computing the full Δ' matrix (coupling betw
> *Physics of Plasmas* **27**, 012506 (2020).
> DOI: [10.1063/1.5134999](https://doi.org/10.1063/1.5134999)

Constructs the Wasow large-``x`` asymptotic basis (the `inps` kernel) that supplies the far-field boundary condition for every GGJ InnerLayer backend — the Galerkin solver and the rotated-contour collocation (`:ray`) solver alike.
Constructs the Wasow large-``x`` asymptotic basis (the `inps` kernel) that supplies the far-field boundary condition for every GGJ InnerLayer backend — the traditional Galerkin solver and the rotated-contour (`:ray`) solver alike.

---

Expand Down
Binary file modified docs/src/figures/inner_layer/convergence_Sinvariance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/src/figures/inner_layer/make_backend_regime_map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ using Printf
const IL = GeneralizedPerturbedEquilibrium.InnerLayer
const GGJ = IL.GGJ

p = IL.q4_surface_benchmark()
p = IL.GGJ.q4_surface_benchmark()
γ(aq) = im * aq * GGJ.q0(p) # imaginary axis: Q = i|Q|

# Worst-case relative error over the two parity components vs the :ray reference.
Expand Down
20 changes: 10 additions & 10 deletions docs/src/figures/inner_layer/make_convergence_Sinvariance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
#
# Figure: honest numerical error bar on the matching data Δ at Q = 500i. The
# `delta_convergence` battery re-solves with each numerical knob perturbed on
# an independent axis (contour angle θ, spectral order p, series order/radius,
# refinement depth, march tolerance, handoff radius, purification e-folds). Δ
# an independent axis (contour angle θ, mesh resolution, series order/radius,
# march tolerance, handoff radius, purification e-folds). Δ
# is an analytic invariant of the contour, so the worst-case spread across
# these orthogonal perturbations bounds the true error. Eight solves; ~30 s.
# these orthogonal perturbations bounds the true error. Seven solves; ~30 s.
#
# Run manually: julia --project=. docs/src/figures/inner_layer/make_convergence_Sinvariance.jl

Expand All @@ -16,13 +16,13 @@ using Printf

const IL = GeneralizedPerturbedEquilibrium.InnerLayer

p = IL.q4_surface_benchmark()
p = IL.GGJ.q4_surface_benchmark()
Q = 500.0im

conv = IL.delta_convergence(p, Q; verbose=false)
names = [r.name for r in conv.table]
d1 = [max(r.d1, 1e-16) for r in conv.table] # relative change of Δ_odd
d2 = [max(r.d2, 1e-16) for r in conv.table] # relative change of Δ_even
d1 = [max(r.d1, 1e-16) for r in conv.table] # relative change of Δ₊ (interchange)
d2 = [max(r.d2, 1e-16) for r in conv.table] # relative change of Δ₋ (tearing)
n = length(names)

plt = plot(; size=(820, 540), legend=:topright, yscale=:log10,
Expand All @@ -31,14 +31,14 @@ plt = plot(; size=(820, 540), legend=:topright, yscale=:log10,
title=@sprintf("Convergence & contour-invariance of Δ, Q = %gi (q=4)", imag(Q)),
left_margin=10Plots.mm, bottom_margin=14Plots.mm)

scatter!(plt, 1:n, d1; marker=:circle, ms=7, color=1, label="δΔ_odd")
scatter!(plt, 1:n, d2; marker=:diamond, ms=7, color=2, label="δΔ_even")
scatter!(plt, 1:n, d1; marker=:circle, ms=7, color=1, label="δΔ₊ (interchange)")
scatter!(plt, 1:n, d2; marker=:diamond, ms=7, color=2, label="δΔ₋ (tearing)")

# Worst-case spread — the reported error bar on each parity.
hline!(plt, [conv.spread[1]]; color=1, ls=:dash, lw=1.5,
label=@sprintf("worst-case Δ_odd %.1e", conv.spread[1]))
label=@sprintf("worst-case Δ₊ %.1e", conv.spread[1]))
hline!(plt, [conv.spread[2]]; color=2, ls=:dash, lw=1.5,
label=@sprintf("worst-case Δ_even %.1e", conv.spread[2]))
label=@sprintf("worst-case Δ₋ %.1e", conv.spread[2]))

save_doc_figure(plt, "inner_layer", "convergence_Sinvariance";
script=basename(@__FILE__),
Expand Down
2 changes: 1 addition & 1 deletion docs/src/figures/inner_layer/make_rotated_ray_contour.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const GGJ = IL.GGJ
# q = 4 rational-surface benchmark on the imaginary-Q axis (the regime that
# defeats :galerkin). Q is the scaled growth rate; θ makes the parabolic
# exponent real.
p = IL.q4_surface_benchmark()
p = IL.GGJ.q4_surface_benchmark()
Q = 500.0im
θ = angle(Q) / 4 # = π/8 = 22.5°

Expand Down
21 changes: 10 additions & 11 deletions docs/src/figures/inner_layer/make_solution_profiles.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# make_solution_profiles.jl
#
# Figure: the inner-layer fields (Ψ, Ξ, Υ) reconstructed on the rotated ray for
# the q=4 benchmark surface. The collocation solution on [0, s_m] (solid) and
# the q=4 benchmark surface. The Hermite BVP solution on [0, s_m] (solid) and
# the analytic u_small + Δ·u_big asymptotic representation for s ≥ S (dashed)
# share the same power-law tail — the numeric↔asymptotic overlap the outer-
# region matching relies on. One BVP solve; a few minutes at large imaginary Q.
Expand All @@ -16,19 +16,19 @@ using Printf
const IL = GeneralizedPerturbedEquilibrium.InnerLayer
const GGJ = IL.GGJ

p = IL.q4_surface_benchmark()
p = IL.GGJ.q4_surface_benchmark()
Q = 2.0im # imaginary axis, beyond the |Q|≪1 shooting regime,
# small enough that the collocation domain reaches
# small enough that the BVP domain reaches
# the series radius directly (no march) — so the
# numeric and asymptotic segments join seamlessly.
isol = 1 # "odd" parity solution (Ψ'(0)=Ξ(0)=Υ(0)=0)
isol = 2 # odd-parity (tearing, Δ₋) solution: Ψ'(0)=Ξ(0)=Υ(0)=0

res = IL.solve_ray(p, Q)
s_m = res.breaks[end]
@printf("solve_ray: Q=%s θ=%.3f S=%.4g s_m=%.4g resid=%.1e\n",
string(Q), res.θ, res.S, s_m, res.resid)
@printf("solve_ray: Q=%s θ=%.3f S=%.4g s_m=%.4g cells=%d\n",
string(Q), res.θ, res.S, s_m, length(res.breaks) - 1)

# Collocation solution over the BVP domain [0, s_m].
# BVP solution over [0, s_m].
prof = IL.solution_profile(res; npc=8)

# Analytic tail on [S, few·S] where the inps series is trusted.
Expand All @@ -39,13 +39,13 @@ fields = ((:Ψ, prof.Ψ, asy.Ψ, 1), (:Ξ, prof.Ξ, asy.Ξ, 2), (:Υ, prof.Υ, a

plt = plot(; size=(760, 560), legend=:bottomleft, xscale=:log10, yscale=:log10,
ylims=(1e-3, 1e2),
xlabel="ray parameter s (x = e^{iθ}s)", ylabel="|field| (odd parity)",
xlabel="ray parameter s (x = e^{iθ}s)", ylabel="|field| (odd parity, tearing)",
title=@sprintf("Inner-layer fields on the rotated ray, Q = %gi (q=4)", imag(Q)),
left_margin=8Plots.mm, bottom_margin=5Plots.mm)

for (nm, col, acol, ci) in fields
plot!(plt, prof.s[2:end], abs.(col[2:end, isol]); lw=2.5, color=ci,
label="|$(nm)| collocation")
label="|$(nm)| BVP")
plot!(plt, asy.s, abs.(acol[:, isol]); lw=2, ls=:dash, color=ci, label="|$(nm)| asymptotic")
end

Expand All @@ -56,5 +56,4 @@ vline!(plt, [res.S]; color=:black, ls=:dot, lw=1,

save_doc_figure(plt, "inner_layer", "solution_profiles";
script=basename(@__FILE__),
depends=["src/InnerLayer/GGJ/Ray.jl", "src/InnerLayer/GGJ/RayAsymptotics.jl",
"src/InnerLayer/GGJ/InnerAsymptotics.jl"])
depends=["src/InnerLayer/GGJ/Ray.jl", "src/InnerLayer/GGJ/InnerAsymptotics.jl"])
Binary file modified docs/src/figures/inner_layer/solution_profiles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions docs/src/figures/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ depends = ["src/InnerLayer/GGJ/Ray.jl", "src/InnerLayer/GGJ/Galerkin.jl", "src/I
script = "make_backend_regime_map.jl"

[inner_layer.convergence_Sinvariance]
commit = "3a0837e3-dirty"
date = "2026-07-08"
commit = "5d11aad3e"
date = "2026-10-21"
depends = ["src/InnerLayer/GGJ/Ray.jl"]
script = "make_convergence_Sinvariance.jl"

Expand All @@ -37,7 +37,7 @@ depends = ["src/InnerLayer/GGJ/Ray.jl"]
script = "make_rotated_ray_contour.jl"

[inner_layer.solution_profiles]
commit = "3a0837e3-dirty"
date = "2026-07-08"
depends = ["src/InnerLayer/GGJ/Ray.jl", "src/InnerLayer/GGJ/RayAsymptotics.jl", "src/InnerLayer/GGJ/InnerAsymptotics.jl"]
commit = "5d11aad3e"
date = "2026-10-21"
depends = ["src/InnerLayer/GGJ/Ray.jl", "src/InnerLayer/GGJ/InnerAsymptotics.jl"]
script = "make_solution_profiles.jl"
Loading
Loading