Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e3cac1a
Test - TEST - Add deck/API parity tests with the known drifts marked …
matt-pharr Oct 20, 2026
39ce663
Test - TEST - Check the two-pass re-form by grid identity, not knot c…
matt-pharr Oct 20, 2026
b8ff18a
Repo - API! - Time stages in main and drop the runtimes keyword
matt-pharr Oct 21, 2026
e808dd2
ForceFreeStates - REFACTOR! - Run deck matching through a MatchProble…
matt-pharr Oct 21, 2026
b7fd82f
Merge remote-tracking branch 'origin/develop' into test/deck-api-parity
matt-pharr Oct 22, 2026
0ad81a2
Test - TEST - Compare deck and API matching on the galerkin inner model
matt-pharr Oct 22, 2026
4cc6e5a
Merge branch 'test/deck-api-parity' into refactor/stage-timing-in-main
matt-pharr Oct 23, 2026
85a38ec
Merge branch 'refactor/stage-timing-in-main' into refactor/deck-match…
matt-pharr Oct 23, 2026
1e71d80
LocalStability - API - Add LocalStabilityProblem, Ballooning and Loca…
matt-pharr Oct 23, 2026
b870ee8
LocalStability - FEATURE - Expose the α-scan window, search bound, bi…
matt-pharr Oct 23, 2026
fb8bd46
Merge remote-tracking branch 'origin/develop' into feature/local-stab…
matt-pharr Oct 23, 2026
70b7847
LocalStability - API! - Run LocalStability from its own [LocalStabili…
matt-pharr Oct 23, 2026
7d2cbbe
Examples - MINOR - Move every deck's local_stability_flag to a [Local…
matt-pharr Oct 23, 2026
59b4b4d
LocalStability - MINOR - Drop the local_stability_flag checks and let…
matt-pharr Oct 23, 2026
ece661d
Test - TEST - Drop the assertion that a removed Runtimes entry is absent
matt-pharr Oct 23, 2026
c6b6512
ForceFreeStates - REFACTOR! - Take the cut solution off the deck surface
matt-pharr Oct 23, 2026
769685c
Merge remote-tracking branch 'origin/refactor/stage-timing-in-main' i…
matt-pharr Oct 23, 2026
bc9e134
Analysis - BUGFIX - Read Jb_theta, Jb_zeta and the kinetic rational_p…
matt-pharr Oct 23, 2026
13c45e1
Merge remote-tracking branch 'origin/refactor/plasma-response' into r…
matt-pharr Oct 24, 2026
08f504a
Merge remote-tracking branch 'origin/refactor/deck-match-in-main' int…
matt-pharr Oct 24, 2026
d2ea925
Merge remote-tracking branch 'origin/refactor/equilibrium-file-split'…
matt-pharr Oct 24, 2026
7cec1df
Merge remote-tracking branch 'origin/bugfix/tearing-enabled-checks' i…
matt-pharr Oct 24, 2026
ea7550d
Merge remote-tracking branch 'origin/bugfix/report-el-abort' into ref…
matt-pharr Oct 24, 2026
146d0d9
Merge remote-tracking branch 'origin/bugfix/analysis-h5-readers' into…
matt-pharr Oct 25, 2026
4ef6100
Merge remote-tracking branch 'origin/bugfix/singfac-min-converged' in…
matt-pharr Oct 25, 2026
53c6d05
Merge remote-tracking branch 'origin/refactor/plasma-response' into r…
matt-pharr Oct 26, 2026
c4d66fe
Merge remote-tracking branch 'origin/develop' into refactor/v2-consol…
matt-pharr Oct 26, 2026
4d178be
Merge remote-tracking branch 'origin/develop' into refactor/v2-consol…
matt-pharr Oct 26, 2026
fb7aebe
Merge remote-tracking branch 'origin/develop' into refactor/v2-consol…
matt-pharr Oct 27, 2026
0d9a48a
Merge remote-tracking branch 'origin/feature/kinetic-profiles-on-equi…
matt-pharr Oct 27, 2026
d23a92c
Examples - BUGFIX - Remove the duplicated LocalStability section from…
matt-pharr Oct 27, 2026
6358e35
Merge remote-tracking branch 'origin/feature/galerkin-cholesky' into …
matt-pharr Oct 27, 2026
fd75d3b
Merge remote-tracking branch 'origin/develop' into refactor/v2-consol…
matt-pharr Oct 28, 2026
14a3745
Vacuum - API! - Make walls optional with shape-specific settings
matt-pharr Oct 28, 2026
c6536ef
Repo - API! - Unify stage result saving under save_to_hdf5
matt-pharr Oct 28, 2026
4f9e4d6
ForceFreeStates - API! - Rename EulerLagrangeProblem to ForceBalanceP…
matt-pharr Oct 28, 2026
de7d87d
ForceFreeStates - API! - Move integration numerics onto algorithm obj…
matt-pharr Oct 28, 2026
b0b44f0
Merge remote-tracking branch 'origin/develop' into refactor/v2-consol…
matt-pharr Oct 28, 2026
0671b86
LocalStability - API! - Separate problem settings from ballooning num…
matt-pharr Oct 29, 2026
a4e32cb
Merge remote-tracking branch 'origin/bugfix/slayer-polish-antianalyti…
matt-pharr Oct 29, 2026
c63561d
Merge remote-tracking branch 'origin/develop' into refactor/v2-consol…
matt-pharr Oct 29, 2026
9733111
Merge remote-tracking branch 'origin/test/streamline-suite' into refa…
matt-pharr Oct 29, 2026
345d1d1
Tearing - API! - Fold Runner into Tearing and solve GGJ growth rates …
matt-pharr Oct 29, 2026
fae9142
Equilibrium - API! - Hold the plasma's species, transport defaults an…
matt-pharr Oct 29, 2026
58cadc4
Tearing - API! - Put the SLAYER layer closures on SLAYERModel and cap…
matt-pharr Oct 29, 2026
1a694bc
Merge branch 'develop' into refactor/v2-consolidation
matt-pharr Oct 29, 2026
cb523a1
Repo - API! - Move the output file and verbosity into one [Run] secti…
matt-pharr Oct 29, 2026
fb53c73
Repo - API! - Resolve deck paths against the deck directory and drop …
matt-pharr Oct 29, 2026
924109e
ForceFreeStates - API! - Select the kinetic source by type with a kin…
matt-pharr Oct 29, 2026
a0232cc
Repo - API! - Read every deck section through one parser into the new…
matt-pharr Oct 29, 2026
2fbf7b3
Merge branch 'develop' into refactor/v2-consolidation
matt-pharr Oct 29, 2026
1b53d96
Merge branch 'develop' into refactor/v2-consolidation
matt-pharr Oct 29, 2026
daaea02
Equilibrium - API! - Select an analytic equilibrium by its own deck s…
matt-pharr Oct 29, 2026
6375f88
KineticForces - API! - Evaluate the kinetic torque with kinetic_torqu…
matt-pharr Oct 29, 2026
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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,5 @@ repos:
- id: toml-no-deprecated-keys
name: 'TOML conventions: no deprecated config keys'
language: pygrep
entry: '^(mer_flag|force_wv_symmetry|ode_flag|cyl_flag|mat_flag|reform_eq_with_psilim|use_riccati|use_parallel|parallel_threads|populate_dense_xi|gal_flag|nstep|diagnose_ca|diagnose|ksing|power_bp|power_b|power_r|power_rc|use_galgrid|moment|eq_out|theta_out|xlmda_out|eqpsi_out|save_records|gpec_file|fnml_flag|ellip_flag|diag_flag|force_xialpha|fixed_boundary|output_eigenmodes|filter_modes|singular_point_method|compute_response|local_stability_flag|profile_file|profile_group)\s*='
entry: '^(mer_flag|force_wv_symmetry|ode_flag|cyl_flag|mat_flag|reform_eq_with_psilim|use_riccati|use_parallel|parallel_threads|populate_dense_xi|gal_flag|nstep|diagnose_ca|diagnose|ksing|power_bp|power_b|power_r|power_rc|use_galgrid|moment|eq_out|theta_out|xlmda_out|eqpsi_out|save_records|gpec_file|fnml_flag|ellip_flag|diag_flag|force_xialpha|fixed_boundary|output_eigenmodes|filter_modes|singular_point_method|compute_response|local_stability_flag|gal_solver|gal_sing_order|gap_kHz_threshold|force_termination|HDF5_filename|write_outputs_to_HDF5|output_filename|kinetic_source|nn_low|nn_high|gal_[A-Za-z0-9_]+|output_benchmark_data|ion_charge|ion_mass|chi_perp_e|chi_perp_i|chi_tor|profile_file|profile_group)\s*=|^\[(DEBUG|SOL_INPUT|LAR_INPUT|TJ_ANALYTIC_INPUT|SLAYER\.scan_grid|SLAYER\.CriticalResonantField)\]|^eq_type\s*=\s*"(sol|lar|tj_analytic|tj_analytic_direct)"'
files: ^(examples/.*\.toml|test/test_data/.*\.toml)$
26 changes: 9 additions & 17 deletions benchmarks/benchmark_against_fortran_run.jl
Original file line number Diff line number Diff line change
Expand Up @@ -406,9 +406,6 @@ function write_gpec_toml_coil(
println(io, "mtheta = $(p.mtheta_equil)")
println(io, "flux_surface_rtol = 1e-7")
println(io)
println(io, "[Wall]")
println(io, "shape = \"nowall\"")
println(io)
println(io, "[LocalStability]")
println(io)
println(io, "[ForceFreeStates]")
Expand All @@ -418,13 +415,14 @@ function write_gpec_toml_coil(
# (= outermost rational q + dmlim). psiedge from dcon.in (=1.0 → no edge dW scan).
@printf(io, "qhigh = %.4f\n", qhigh)
@printf(io, "dW_edge_scan_start = %.4f\n", p.psiedge)
println(io, "nn_low = $(p.nn)")
println(io, "nn_high = $(p.nn)")
println(io, "nn = $(p.nn)")
println(io, "delta_mlow = $(p.delta_mlow)")
println(io, "delta_mhigh = $(p.delta_mhigh)")
println(io, "mtheta_vacuum = 512")
println(io, "eulerlagrange_tolerance = 1e-7")
println(io, "singfac_min = 1e-4")
println(io)
println(io, "[Riccati]")
println(io, "eulerlagrange_tolerance = 1e-7")
println(io, "save_interval = $(p.euler_stride)")
println(io)
println(io, "[ForcingTerms]")
Expand All @@ -441,8 +439,6 @@ function write_gpec_toml_coil(
println(io)
println(io, "[PerturbedEquilibrium]")
println(io, "compute_singular_coupling = true")
println(io, "verbose = true")
println(io, "write_outputs_to_HDF5 = true")
end
end

Expand All @@ -468,22 +464,20 @@ function write_gpec_toml_file(
println(io, "mtheta = $(p.mtheta_equil)")
println(io, "flux_surface_rtol = 1e-7")
println(io)
println(io, "[Wall]")
println(io, "shape = \"nowall\"")
println(io)
println(io, "[LocalStability]")
println(io)
println(io, "[ForceFreeStates]")
println(io, "vac_flag = true")
@printf(io, "qlow = %.4f\n", p.qlow)
@printf(io, "dW_edge_scan_start = %.4f\n", p.psiedge)
println(io, "nn_low = $(p.nn)")
println(io, "nn_high = $(p.nn)")
println(io, "nn = $(p.nn)")
println(io, "delta_mlow = $(p.delta_mlow)")
println(io, "delta_mhigh = $(p.delta_mhigh)")
println(io, "mtheta_vacuum = 512")
println(io, "eulerlagrange_tolerance = 1e-7")
println(io, "singfac_min = 1e-4")
println(io)
println(io, "[Riccati]")
println(io, "eulerlagrange_tolerance = 1e-7")
println(io, "save_interval = $(p.euler_stride)")
println(io)
println(io, "[ForcingTerms]")
Expand All @@ -492,8 +486,6 @@ function write_gpec_toml_file(
println(io)
println(io, "[PerturbedEquilibrium]")
println(io, "compute_singular_coupling = true")
println(io, "verbose = true")
println(io, "write_outputs_to_HDF5 = true")
end
end

Expand All @@ -511,7 +503,7 @@ function setup_equil(p::FortranRunParams, fortran_dir::String)
"grid_type" => p.grid_type,
"flux_surface_rtol" => 1e-7
)
eq_config = Equilibrium.EquilibriumConfig(eq_dict, fortran_dir)
eq_config = GeneralizedPerturbedEquilibrium.equilibrium_config(Dict{String,Any}("Equilibrium" => eq_dict), fortran_dir)
return Equilibrium.PlasmaEquilibrium(eq_config)
end

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/benchmark_coil_ForcingTerms_against_fortran.jl
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ t_equil = @elapsed begin
"psi_accuracy" => 0.001,
"flux_surface_rtol" => 1e-7,
)
eq_config = Equilibrium.EquilibriumConfig(eq_dict, run_dir)
eq_config = GeneralizedPerturbedEquilibrium.equilibrium_config(Dict{String,Any}("Equilibrium" => eq_dict), run_dir)
equil = Equilibrium.PlasmaEquilibrium(eq_config)
end
@printf " Done in %.1f s (bt_sign=%d)\n" t_equil equil.params.bt_sign
Expand Down
14 changes: 6 additions & 8 deletions benchmarks/benchmark_delta_prime_methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ const FFS = GeneralizedPerturbedEquilibrium.ForceFreeStates
function setup_and_run_solovev()
ex = joinpath(@__DIR__, "..", "test", "test_data", "regression_solovev_ideal_example")
inputs = TOML.parsefile(joinpath(ex, "gpec.toml"))
inputs["ForceFreeStates"]["verbose"] = false
inputs["ForceFreeStates"]["integrator"] = "riccati"
intr = FFS.ForceFreeStatesInternal(; dir_path=ex)
ctrl = FFS.ForceFreeStatesControl(;
(Symbol(k) => v for (k, v) in inputs["ForceFreeStates"])...)
eq_config = GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumConfig(inputs["Equilibrium"], ex)
inputs["ForceFreeStates"]["integrator"] = "Riccati"
inputs["Riccati"] = pop!(inputs, "Forward")
intr = FFS.ForceFreeStatesInternal()
ctrl = GeneralizedPerturbedEquilibrium.force_balance_control(inputs, ex)
eq_config = GeneralizedPerturbedEquilibrium.equilibrium_config(inputs, ex)
equil = GeneralizedPerturbedEquilibrium.Equilibrium.PlasmaEquilibrium(eq_config)
intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.WallShapeSettings(;
(Symbol(k) => v for (k, v) in inputs["Wall"])...)
intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.parse_wall(get(inputs, "Wall", nothing))
FFS.sing_lim!(intr, ctrl, equil)
intr.nlow = ctrl.nn_low;
intr.nhigh = ctrl.nn_high;
Expand Down
12 changes: 3 additions & 9 deletions benchmarks/benchmark_diiid_ideal_ntv_torque.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,31 +125,25 @@ mtheta = 256
newq0 = 0
flux_surface_rtol = 1e-7

[Wall]
shape = "nowall"

[LocalStability]

[ForceFreeStates]
vac_flag = true
force_termination = false

dW_edge_scan_start = 1.0 # No edge-scan truncation (rational_offset_fraction truncation off)
qlow = 1.02
qhigh = 1e3
sing_start = 0

nn_low = 1
nn_high = 1
nn = 1
delta_mlow = 8
delta_mhigh = 8
mtheta_vacuum = 512
singfac_min = 1e-4

kinetic_source = "fixed"
kinetic_factor = 0.0
[Riccati]
eulerlagrange_tolerance = 1e-7
save_interval = 3
singfac_min = 1e-4
renorm_threshold = 1e4
"""
)
Expand Down
28 changes: 9 additions & 19 deletions benchmarks/benchmark_diiid_kinetic_stability.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Benchmark the self-consistent kinetic-DCON path (KF → FFS → PE) against
Fortran GPEC's kinetic DCON reference.

Runs `GPE.main()` with `kinetic_source="calculated"` and `kinetic_factor=1.0`
Runs `GPE.main()` with `kinetic = "KineticForces"`
against the EFIT g-file and `.kin` profile taken from a Fortran GPEC
kinetic example directory, then compares the least-stable total-energy
eigenvalue `ForceFreeStates/FreeBoundaryStability/eigenmode_energies[1]` against `W_t_eigenvalue[:, 0]` in the Fortran
Expand Down Expand Up @@ -123,8 +123,6 @@ function build_benchmark_tomldir(eq_file::String, kin_file::String)
[Equilibrium]
eq_filename = "$eq_name"
kinetic_file = "$kin_file"
eq_type = "efit"
jac_type = "hamada"
grid_type = "pow1" # Matches Fortran DIIID_kinetic_example (equil/grid.f90 powspace)
psilow = 0.01
psihigh = 0.993
Expand All @@ -133,39 +131,31 @@ mtheta = 256
newq0 = 0
flux_surface_rtol = 1e-7

[Wall]
shape = "nowall"

[LocalStability]

[ForceFreeStates]
vac_flag = true
force_termination = true # Skip PE+KF post-processing — we only need FFS eigenvalues

dW_edge_scan_start = 1.0 # No edge-scan truncation (rational_offset_fraction truncation off)
qlow = 1.02
qhigh = 1e3
sing_start = 0

nn_low = 1
nn_high = 1
nn = 1
delta_mlow = 8
delta_mhigh = 8
mtheta_vacuum = 512
thmax0 = 1

kinetic_source = "calculated"
kinetic_factor = 1.0
eulerlagrange_tolerance = 1e-7
integrator = "Forward"
kinetic = "KineticForces"
singfac_min = 1e-4

[Forward]
eulerlagrange_tolerance = 1e-7
renorm_threshold = 1e4
write_outputs_to_HDF5 = true

[KineticForces]
nn = 1
nl = 4
zi = 1
mi = 2
bounce_harmonic_max = 4
nutype = "harmonic"
f0type = "maxwellian"
"""
Expand All @@ -192,7 +182,7 @@ function run_benchmark(fortran_dir::String=default_fortran_dir())

tomldir = build_benchmark_tomldir(inputs.eq_file, inputs.kin_file)

_p("\n--- Running GPE.main with kinetic_source=\"calculated\" ---")
_p("\n--- Running GPE.main with kinetic = \"KineticForces\" ---")
t0 = time()
GPE.main([tomldir])
wall = time() - t0
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/benchmark_q_vs_iota_edge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const EXAMPLE_DIR = joinpath(@__DIR__, "..", "examples", "DIIID-like_ideal_examp
function reference_q()
inputs, _, additional_input = GPE.build_inputs_from_toml(EXAMPLE_DIR)
equil_dict = merge(inputs["Equilibrium"], Dict{String,Any}("grid_type" => "core_edge_packed", "mpsi" => 1024))
eq_config = GPE.Equilibrium.EquilibriumConfig(equil_dict, EXAMPLE_DIR)
eq_config = GPE.equilibrium_config(Dict{String,Any}("Equilibrium" => equil_dict), EXAMPLE_DIR)
equil = GPE.Equilibrium.PlasmaEquilibrium(eq_config, additional_input)
# The dict rides along so the mpsi scan can rebuild configs; EquilibriumConfig is immutable.
return equil, equil_dict
Expand Down Expand Up @@ -65,7 +65,7 @@ function main()

for N in (16, 32, 64, 128, 256)
# Same log_asymptotic knot layout the auto grid uses for fixed mpsi
cfg = GPE.Equilibrium.EquilibriumConfig(merge(equil_dict, Dict{String,Any}("mpsi" => N)), EXAMPLE_DIR)
cfg = GPE.equilibrium_config(Dict{String,Any}("Equilibrium" => merge(equil_dict, Dict{String,Any}("mpsi" => N))), EXAMPLE_DIR)
knots = GPE.Equilibrium._build_psi_grid(cfg, psilow, psihigh)
q_nodes = [q_ref_itp(p) for p in knots]

Expand Down
13 changes: 5 additions & 8 deletions benchmarks/benchmark_riccati_der.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,11 @@ const FFS = GeneralizedPerturbedEquilibrium.ForceFreeStates
function setup_solovev()
ex = joinpath(@__DIR__, "..", "test", "test_data", "regression_solovev_ideal_example")
inputs = TOML.parsefile(joinpath(ex, "gpec.toml"))
inputs["ForceFreeStates"]["verbose"] = false
intr = FFS.ForceFreeStatesInternal(; dir_path=ex)
ctrl = FFS.ForceFreeStatesControl(;
(Symbol(k) => v for (k, v) in inputs["ForceFreeStates"])...)
eq_config = GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumConfig(inputs["Equilibrium"], ex)
intr = FFS.ForceFreeStatesInternal()
ctrl = GeneralizedPerturbedEquilibrium.force_balance_control(inputs, ex)
eq_config = GeneralizedPerturbedEquilibrium.equilibrium_config(inputs, ex)
equil = GeneralizedPerturbedEquilibrium.Equilibrium.PlasmaEquilibrium(eq_config)
intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.WallShapeSettings(;
(Symbol(k) => v for (k, v) in inputs["Wall"])...)
intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.parse_wall(get(inputs, "Wall", nothing))
FFS.sing_lim!(intr, ctrl, equil)
intr.nlow = ctrl.nn_low;
intr.nhigh = ctrl.nn_high;
Expand Down Expand Up @@ -80,7 +77,7 @@ println("Test state: Hermitian S (physical constraint). Expected error: ~machine
ctrl, equil, mats, intr = setup_solovev()
N = intr.numpert_total

odet = FFS.OdeState(N, ctrl.numsteps_init, ctrl.numunorms_init, intr.msing)
odet = FFS.OdeState(N, ctrl.algorithm.numsteps_init, ctrl.algorithm.numunorms_init, intr.msing)
FFS.initialize_el_at_axis!(odet, ctrl, equil.profiles, intr)
chunks = FFS.chunk_el_integration_bounds(odet, ctrl, intr)

Expand Down
6 changes: 3 additions & 3 deletions benchmarks/benchmark_solovev_kinetic_stability.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""
benchmark_solovev_kinetic_stability.jl

Benchmark the self-consistent kinetic-DCON path (`kinetic_source="calculated"`)
Benchmark the self-consistent kinetic-DCON path (`kinetic = "KineticForces"`)
for the analytic **Solovev** equilibrium against Fortran GPEC's kinetic DCON.

Unlike the DIIID benchmark (which reads a pre-existing `dcon_output_n1.nc`),
Expand Down Expand Up @@ -103,7 +103,7 @@ function build_matched_fortran_deck(workdir::String)

# dcon.in — kinetic flags already match; align mode band, edge truncation, n.
dconin = joinpath(workdir, "dcon.in")
replace_namelist_value!(dconin, "nn", string(ffs["nn_low"]))
replace_namelist_value!(dconin, "nn", string(first(ffs["nn"])))
replace_namelist_value!(dconin, "delta_mlow", string(get(ffs, "delta_mlow", 0)))
replace_namelist_value!(dconin, "delta_mhigh", string(get(ffs, "delta_mhigh", 0)))
replace_namelist_value!(dconin, "qlow", string(ffs["qlow"]))
Expand Down Expand Up @@ -171,7 +171,7 @@ function run_benchmark()
fort_re, fort_im = run_fortran_reference(workdir)
_p(@sprintf(" Fortran W_t[1]: Re = %.6f Im = %.6f", fort_re, fort_im))

_p("\n--- Running GPE.main with kinetic_source=\"calculated\" ---")
_p("\n--- Running GPE.main with kinetic = \"KineticForces\" ---")
jul_re, jul_im, wall = run_julia_reference()
_p(@sprintf(" GPE.main completed in %.1f s", wall))

Expand Down
37 changes: 9 additions & 28 deletions benchmarks/benchmark_threads.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Thread-scaling benchmark for the Riccati chunked propagator integration.
# Runs the Solovev (N=8) and DIIID-like (N=26) examples with integrator="riccati"
# Runs the Solovev (N=8) and DIIID-like (N=26) examples with the Riccati integrator
# across 1, 2, 4, 8 threads and compares against the forward path. The chunk list is
# thread-independent, so et[1] must not move with the thread count — only wall-clock.
#
Expand All @@ -8,32 +8,13 @@

using GeneralizedPerturbedEquilibrium, TOML, Printf, Statistics

# One solve of the example deck with `integrator` (Forward or Riccati), sharing the deck's ODE numerics.
function run_ffs(ex; integrator)
inputs = TOML.parsefile(joinpath(ex, "gpec.toml"))
inputs["ForceFreeStates"]["verbose"] = false
inputs["ForceFreeStates"]["integrator"] = integrator
inputs["ForceFreeStates"]["write_outputs_to_HDF5"] = false
intr = GeneralizedPerturbedEquilibrium.ForceFreeStates.ForceFreeStatesInternal(; dir_path=ex)
ctrl = GeneralizedPerturbedEquilibrium.ForceFreeStates.ForceFreeStatesControl(;
(Symbol(k) => v for (k, v) in inputs["ForceFreeStates"])...)
eq_config = GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumConfig(inputs["Equilibrium"], ex)
equil = GeneralizedPerturbedEquilibrium.Equilibrium.PlasmaEquilibrium(eq_config)
intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.WallShapeSettings(;
(Symbol(k) => v for (k, v) in inputs["Wall"])...)
GeneralizedPerturbedEquilibrium.ForceFreeStates.sing_lim!(intr, ctrl, equil)
intr.nlow = ctrl.nn_low;
intr.nhigh = ctrl.nn_high;
intr.npert = 1
GeneralizedPerturbedEquilibrium.ForceFreeStates.sing_find!(intr, equil)
intr.mlow = min(intr.nlow * equil.params.qmin, 0) - 4 - ctrl.delta_mlow
intr.mhigh = trunc(Int, intr.nhigh * equil.params.qmax) + ctrl.delta_mhigh
intr.mpert = intr.mhigh - intr.mlow + 1
intr.numpert_total = intr.mpert * intr.npert
metric = GeneralizedPerturbedEquilibrium.ForceFreeStates.make_metric(equil, intr.mpert)
mats = GeneralizedPerturbedEquilibrium.ForceFreeStates.build_matrix_splines(equil, intr, metric)
odet, _, _, _ = GeneralizedPerturbedEquilibrium.ForceFreeStates.eulerlagrange_integration(ctrl, equil, mats, intr)
vac = GeneralizedPerturbedEquilibrium.ForceFreeStates.free_run(odet, ctrl, equil, mats, intr)
return real(vac.et[1]), intr.numpert_total
GPE = GeneralizedPerturbedEquilibrium
inputs, config, analytic = GPE.build_inputs_from_toml(ex)
alg = integrator(; GPE.section_keywords(inputs["Forward"], "Forward", GPE._struct_fields(Forward))...)
ffs = solve(PlasmaEquilibrium(config, analytic), alg; GPE.force_balance_keywords(inputs, ex)...)
return real(ffs.free_boundary.et[1]), ffs.numpert_total
end

function timed_run(ex; integrator, nwarm=1, nrep=2)
Expand All @@ -60,8 +41,8 @@ diiid_ex = joinpath(root, "examples", "DIIID-like_ideal_example")
println("\n=== Thread-scaling benchmark ($(nthreads) thread(s)) ===\n")

for (label, ex) in [("Solovev", sol_ex), ("DIIID-like", diiid_ex)]
t_fwd, et_fwd, N = timed_run(ex; integrator="forward")
t_ric, et_ric, _ = timed_run(ex; integrator="riccati")
t_fwd, et_fwd, N = timed_run(ex; integrator=Forward)
t_ric, et_ric, _ = timed_run(ex; integrator=Riccati)

err_ric = abs(et_ric - et_fwd) / abs(et_fwd) * 100

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/equil_method_comparison.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function make_config(path::String, eq_type::String; psihigh=nothing)
raw["Equilibrium"]["eq_type"] = eq_type
psihigh !== nothing && (raw["Equilibrium"]["psihigh"] = psihigh)
base = dirname(path)
return Equilibrium.EquilibriumConfig(raw["Equilibrium"], base)
return GeneralizedPerturbedEquilibrium.equilibrium_config(raw, base)
end

# ─── Run each method (3 warm runs, report average of last 2) ─────────────────
Expand Down
Loading
Loading