-
Notifications
You must be signed in to change notification settings - Fork 7
ForceFreeStates: Dual Riccati + Parallel FM integration + Δ' output #178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
logan-nc
wants to merge
53
commits into
develop
Choose a base branch
from
perf/riccati
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
ce6d0a6
ForceFreeStates - NEW FEATURE - Dual Riccati reformulation of EL ODE …
logan-nc 0385e7f
ForceFreeStates - NEW FEATURE - Parallel FM integration + Δ' output
logan-nc 1d2a863
ForceFreeStates - IMPROVEMENT - Fix Δ' computation and add Riccati/pa…
logan-nc 11f394b
ForceFreeStates - CLEANUP - Correct explanation for why standard path…
logan-nc 0ca20e2
ForceFreeStates - IMPROVEMENT - Off-diagonal Δ' column + parallel FM …
logan-nc 5a7b756
ForceFreeStates - NEW FEATURE - STRIDE global BVP inter-surface Δ' ma…
logan-nc af7f359
ForceFreeStates - NEW FEATURE - Bidirectional parallel FM integration…
logan-nc 9961fbd
ForceFreeStates - NEW FEATURE - Thread-scaling benchmark script
logan-nc 7bb3942
ForceFreeStates - BUG FIX - Address Claude code review of perf/riccati
logan-nc 88448fc
ForceFreeStates - NEW FEATURE - Sanity-check benchmarks for riccati_d…
logan-nc 86b60a2
ForceFreeStates - CLEANUP - Clarify Riccati integration strategy docs…
logan-nc cb4c2bf
ForceFreeStates - IMPROVEMENT - Refactor runtests_riccati.jl: shared …
logan-nc c7dfa41
ForceFreeStates - IMPROVEMENT - Remove dead parallel_threads field; a…
logan-nc 2eb3c26
ForceFreeStates - MERGE - Merge origin/develop (GPEC rename) into per…
logan-nc 2f494c9
ForceFreeStates - CLEANUP - Update JPEC→GeneralizedPerturbedEquilibri…
logan-nc 142a79c
ForceFreeStates - NEW FEATURE - Add stability analysis documentation …
logan-nc 1515591
ForceFreeStates - BUG FIX - Fix CI failures (Random stdlib + docs mar…
logan-nc 725a527
ForceFreeStates - IMPROVEMENT - Thread safety, psilim guard, consiste…
logan-nc a63dc69
Merge develop into perf/riccati
matt-pharr 6431392
TESTING - FIX - fixed failing tests post merge
matt-pharr 0d72584
TESTING - FIX - Re-add comments to gpec.toml accidentally removed in …
matt-pharr dc2b44b
BENCH - NEW - integration paths benchmark script
matt-pharr 8dc4dc4
Merge remote-tracking branch 'origin/develop' into perf/riccati
matt-pharr 290cfc5
EQUIL - NEW FEATURE - TJ analytic model (tj_run inverse + tj_run_direct)
d-burg 5be4c98
ForceFreeStates - NEW FEATURE - Parallel FM Δ' BVP with inter-surface…
d-burg 97a6826
BENCH - NEW - TJ pole-approach scans, regression case, and unit tests
d-burg d67cabd
CLEANUP - Drop unused deps, fix stale comments and docs
d-burg b9c177e
CLEANUP - Drop brittle Fortran/TJ source line-number citations from c…
d-burg 57db4e7
Merge origin/develop into perf/riccati
d-burg 5d5b8ee
ForceFreeStates - NEW FEATURE - Decouple edge-dW scan from integratio…
d-burg 685a92a
EXAMPLES - BUG FIX - Remove stale kin_flag/con_flag from LAR/TJ scan …
d-burg defcec8
CI - BUG FIX - Restore Random stdlib dep and refresh test regression …
d-burg 1dfc3ae
CI - BUG FIX - Loosen Solovev Δ'(surface 2) regression test
d-burg c6c845f
CI - BUG FIX - Handle maxthreadid() and decouple DIIID cross-path test
d-burg 54d12fe
ForceFreeStates - NEW FEATURE - Port set_psilim_via_dmlim + default t…
d-burg 4845ec8
ForceFreeStates - IMPROVEMENT - Default use_parallel=true, singfac_mi…
d-burg db7c490
ForceFreeStates - BUG FIX - Wire ctrl.parallel_threads into BVP path;…
d-burg 7ac87c8
ForceFreeStates - PERFORMANCE - parallel_threads default 1 → 2 (≈20% …
d-burg 3c8130d
ForceFreeStates - BUG FIX + EXAMPLES - truncate_at_dW_peak self-consi…
d-burg 5acf147
ForceFreeStates - NEW FEATURE - Dense ξ in parallel BVP path + bit-id…
d-burg 6d07c07
EQUIL - REFACTOR - Rename TJ → TJ-like with Fitzpatrick citation ever…
d-burg 085de13
EXAMPLES - CLEANUP - LAR scans: single-file gpec.toml, per-line annot…
d-burg 5a4c2c2
EXAMPLES - CLEANUP - Remove TJ_epsilon_pole_example and its regressio…
d-burg cc2affe
EQUIL - REFACTOR - Rename tj_like → tj_analytic (cleaner, less hedge-y)
d-burg 8073c12
ForceFreeStates - BUG FIX - Preserve Riccati-gauge ca_l/ca_r across d…
d-burg 3653a15
DOCS - CLEANUP - Move stride dev notes out of repo to CTM-processing
d-burg 8bbe836
ForceFreeStates - CLEANUP - Address pre-merge review items
d-burg 7efb15d
ForceFreeStates - TEST - Tighten Solovev kinetic multi-n rtol (drift …
d-burg c6c379c
ForceFreeStates - REFACTOR - Address PR 178 review: flag surfacing + …
d-burg 0296956
ForceFreeStates / PerturbedEquilibrium - REFACTOR - De-emphasize per-…
d-burg a89bd5d
ForceFreeStates - CLEANUP - Pre-merge audit response (H1-H5, D1-D3, V…
d-burg ace5e21
Merge remote-tracking branch 'origin/develop' into perf/riccati
d-burg 4fbd882
ForceFreeStates - CLEANUP - Pre-merge audit fixes (B1 thread-safety, …
d-burg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # Sanity check: compute_delta_prime_from_ca! vs inline Δ' from riccati_cross_ideal_singular_surf! | ||
| # | ||
| # riccati_cross_ideal_singular_surf! computes Δ' inline at each singular surface crossing | ||
| # using the diagonal formula (no Gaussian reduction permutation): | ||
| # Δ'[s] = (ca_r[ipert_res, ipert_res, 2, s] - ca_l[ipert_res, ipert_res, 2, s]) / (4π²·ψ₀) | ||
| # | ||
| # compute_delta_prime_from_ca! applies the identical formula post-hoc from the stored | ||
| # ca_l/ca_r arrays. Since both operate on the same data with the same formula, results | ||
| # should match to floating-point precision (not just approximately — exactly). | ||
| # | ||
| # This verifies that compute_delta_prime_from_ca! is a correct standalone implementation | ||
| # of the Δ' formula that can be used for testing or alternative integration drivers. | ||
| # | ||
| # Usage (from JPEC_main root): | ||
| # julia --project=. benchmarks/benchmark_delta_prime_methods.jl | ||
|
|
||
| using LinearAlgebra, Printf, TOML | ||
| using GeneralizedPerturbedEquilibrium | ||
|
|
||
| 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"]["use_riccati"] = true | ||
| 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) | ||
| equil = GeneralizedPerturbedEquilibrium.Equilibrium.setup_equilibrium(eq_config) | ||
| intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.WallShapeSettings(; | ||
| (Symbol(k) => v for (k, v) in inputs["Wall"])...) | ||
| FFS.sing_lim!(intr, ctrl, equil) | ||
| intr.nlow = ctrl.nn_low; intr.nhigh = ctrl.nn_high; intr.npert = 1 | ||
| FFS.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.mband = intr.mpert - 1 | ||
| intr.numpert_total = intr.mpert * intr.npert | ||
| metric = FFS.make_metric(equil; mband=intr.mband, fft_flag=ctrl.fft_flag) | ||
| ffit = FFS.make_matrix(equil, intr, metric) | ||
| odet = FFS.riccati_eulerlagrange_integration(ctrl, equil, ffit, intr) | ||
| return ctrl, equil, ffit, intr, odet | ||
| end | ||
|
|
||
| println("\n=== compute_delta_prime_from_ca! consistency check ===") | ||
| println("Verifies the standalone Δ' formula matches the inline Riccati crossing computation.") | ||
| println("Expected error: exactly zero (same formula, same data).\n") | ||
|
|
||
| ctrl, equil, ffit, intr, odet = setup_and_run_solovev() | ||
| msing = intr.msing | ||
|
|
||
| # Capture Δ' values set inline by riccati_cross_ideal_singular_surf! during integration | ||
| delta_prime_inline = [copy(intr.sing[s].delta_prime) for s in 1:msing] | ||
|
|
||
| # Now call compute_delta_prime_from_ca! — it reads the same ca_l/ca_r arrays and | ||
| # overwrites intr.sing[s].delta_prime using the identical diagonal formula | ||
| FFS.compute_delta_prime_from_ca!(odet, intr, equil) | ||
|
|
||
| println(" N=$(intr.numpert_total) modes, $msing singular surfaces\n") | ||
| @printf(" %6s %4s %4s %22s %22s %12s\n", | ||
| "Surf", "m", "n", "Δ' (inline)", "Δ' (from_ca)", "abs diff") | ||
| println(" " * "-"^76) | ||
|
|
||
| max_absdiff = let max_absdiff = 0.0 | ||
| for s in 1:msing | ||
| sing = intr.sing[s] | ||
| dp_from_ca = intr.sing[s].delta_prime | ||
| for i in eachindex(delta_prime_inline[s]) | ||
| dp_il = delta_prime_inline[s][i] | ||
| dp_fc = dp_from_ca[i] | ||
| absdiff = abs(dp_fc - dp_il) | ||
| max_absdiff = max(max_absdiff, absdiff) | ||
| @printf(" %6d %4d %4d %22.6f%+.6fi %22.6f%+.6fi %12.4e\n", | ||
| s, sing.m[i], sing.n[i], | ||
| real(dp_il), imag(dp_il), | ||
| real(dp_fc), imag(dp_fc), | ||
| absdiff) | ||
| end | ||
| end | ||
| max_absdiff | ||
| end | ||
|
|
||
| println() | ||
| if max_absdiff == 0.0 | ||
| println("PASSED — Δ' values are bit-for-bit identical (max abs diff = 0.0)") | ||
| elseif max_absdiff < 1e-14 | ||
| @printf("PASSED — max abs diff = %.2e (floating-point rounding only)\n", max_absdiff) | ||
| else | ||
| @printf("FAILED — max abs diff = %.2e (expected exact agreement)\n", max_absdiff) | ||
| exit(1) | ||
| end | ||
| println() |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # Sanity check: riccati_der! correctly evaluates the explicit Riccati ODE. | ||
| # | ||
| # riccati_der! implements [Glasser 2018 Phys. Plasmas 25, 032507, Eq. 19]: | ||
| # dS/dψ = w†·F̄⁻¹·w - S·Ḡ·S, w = Q - K̄·S | ||
| # | ||
| # where Q = diag(1/(m - n·q)), F̄ = L·L† (Cholesky), K̄ and Ḡ are the MHD | ||
| # metric matrices evaluated at ψ. | ||
| # | ||
| # NOTE: The identity between this Riccati ODE and the EL chain rule | ||
| # dS/dψ = dU₁·U₂⁻¹ - S·dU₂·U₂⁻¹ | ||
| # holds ONLY for Hermitian S (physical states evolved from the axis, where | ||
| # S†=S is preserved by the EL symmetry). For arbitrary non-Hermitian (U₁, U₂), | ||
| # the two expressions differ — so this script compares riccati_der! against the | ||
| # explicit formula rather than against sing_der!. | ||
| # | ||
| # Usage (from JPEC_main root): | ||
| # julia --project=. benchmarks/benchmark_riccati_der.jl | ||
|
|
||
| using LinearAlgebra, Random, Printf, TOML | ||
| using GeneralizedPerturbedEquilibrium | ||
|
|
||
| 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) | ||
| equil = GeneralizedPerturbedEquilibrium.Equilibrium.setup_equilibrium(eq_config) | ||
| intr.wall_settings = GeneralizedPerturbedEquilibrium.Vacuum.WallShapeSettings(; | ||
| (Symbol(k) => v for (k, v) in inputs["Wall"])...) | ||
| FFS.sing_lim!(intr, ctrl, equil) | ||
| intr.nlow = ctrl.nn_low; intr.nhigh = ctrl.nn_high; intr.npert = 1 | ||
| FFS.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.mband = intr.mpert - 1 | ||
| intr.numpert_total = intr.mpert * intr.npert | ||
| metric = FFS.make_metric(equil; mband=intr.mband, fft_flag=ctrl.fft_flag) | ||
| ffit = FFS.make_matrix(equil, intr, metric) | ||
| return ctrl, equil, ffit, intr | ||
| end | ||
|
|
||
| # Evaluate the Riccati RHS explicitly from splines: dS = w†·F̄⁻¹·w - S·Ḡ·S | ||
| function riccati_rhs_manual(S, psi, equil, ffit, intr) | ||
| N = intr.numpert_total | ||
| L = zeros(ComplexF64, N, N) | ||
| Kmat = zeros(ComplexF64, N, N) | ||
| Gmat = zeros(ComplexF64, N, N) | ||
| ffit.fmats_lower(vec(L), psi; hint=ffit._hint) | ||
| ffit.kmats(vec(Kmat), psi; hint=ffit._hint) | ||
| ffit.gmats(vec(Gmat), psi; hint=ffit._hint) | ||
|
|
||
| q = equil.profiles.q_spline(psi) | ||
| singfac = vec(1.0 ./ ((intr.mlow:intr.mhigh) .- q .* (intr.nlow:intr.nhigh)')) | ||
|
|
||
| # w = Q - K̄·S (Q is diagonal; add only the diagonal entries) | ||
| w = -Kmat * S | ||
| for i in 1:N | ||
| w[i, i] += singfac[i] | ||
| end | ||
|
|
||
| # v = F̄⁻¹·w via stored Cholesky factor L (L·L† = F̄) | ||
| v = copy(w) | ||
| ldiv!(LowerTriangular(L), v) | ||
| ldiv!(UpperTriangular(L'), v) | ||
|
|
||
| return adjoint(w) * v - S * Gmat * S | ||
| end | ||
|
|
||
| println("\n=== riccati_der! formula verification ===") | ||
| println("Verifies riccati_der! output matches manual evaluation of Glasser 2018 Eq. 19.") | ||
| println("Test state: Hermitian S (physical constraint). Expected error: ~machine epsilon.\n") | ||
|
|
||
| ctrl, equil, ffit, intr = setup_solovev() | ||
| N = intr.numpert_total | ||
|
|
||
| odet = FFS.OdeState(N, ctrl.numsteps_init, ctrl.numunorms_init, intr.msing) | ||
| FFS.initialize_el_at_axis!(odet, ctrl, equil.profiles, intr) | ||
| chunks = FFS.chunk_el_integration_bounds(odet, ctrl, intr) | ||
|
|
||
| # 30% into each chunk: well inside the interval, away from singularities at psi_end | ||
| test_psis = [c.psi_start + 0.3 * (c.psi_end - c.psi_start) for c in chunks] | ||
|
|
||
| println(" N=$N modes, $(length(test_psis)) test ψ points (30% into each chunk)\n") | ||
| @printf(" %8s %14s %14s %12s\n", "ψ", "‖dS_manual‖", "‖dS_ric‖", "rel error") | ||
| println(" " * "-"^54) | ||
|
|
||
| rng = Random.MersenneTwister(42) | ||
| threshold = 1e-10 | ||
|
|
||
| max_err = let max_err = 0.0 | ||
| for psi in test_psis | ||
| # Hermitian S: physical Riccati matrix is Hermitian (preserved by EL symmetry) | ||
| A = randn(rng, ComplexF64, N, N) | ||
| S = (A + A') / 2 # Hermitian by construction | ||
|
|
||
| # Manual RHS | ||
| dS_manual = riccati_rhs_manual(S, psi, equil, ffit, intr) | ||
|
|
||
| # riccati_der! RHS | ||
| u_ric = zeros(ComplexF64, N, N, 2) | ||
| du_ric = zeros(ComplexF64, N, N, 2) | ||
| u_ric[:, :, 1] .= S | ||
| u_ric[:, :, 2] .= Matrix{ComplexF64}(I, N, N) | ||
| dummy_chunk = FFS.IntegrationChunk(psi, psi, false, 0, 1) | ||
| params = (ctrl, equil, ffit, intr, odet, dummy_chunk) | ||
| FFS.riccati_der!(du_ric, u_ric, params, psi) | ||
| dS_ric = du_ric[:, :, 1] | ||
|
|
||
| ref = max(norm(dS_manual), 1e-10) | ||
| err = norm(dS_ric - dS_manual) / ref | ||
| max_err = max(max_err, err) | ||
| status = err < threshold ? "" : " ← FAIL" | ||
| @printf(" %8.4f %14.4e %14.4e %12.4e%s\n", psi, norm(dS_manual), norm(dS_ric), err, status) | ||
| end | ||
| max_err | ||
| end | ||
|
|
||
| println() | ||
| if max_err < threshold | ||
| @printf("PASSED — max rel error = %.2e (threshold %.0e)\n", max_err, threshold) | ||
| else | ||
| @printf("FAILED — max rel error = %.2e exceeds threshold %.0e\n", max_err, threshold) | ||
| exit(1) | ||
| end | ||
| println() |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # Thread-scaling benchmark for the bidirectional parallel FM integration. | ||
| # Runs the Solovev (N=8) and DIIID-like (N=26) examples with use_parallel=true | ||
| # across 1, 2, 4, 8 threads and compares against the serial Riccati path. | ||
| # | ||
| # Usage (from JPEC_main root): | ||
| # for t in 1 2 4 8; do julia -t $t --project=. benchmarks/benchmark_threads.jl; done | ||
|
|
||
| using GeneralizedPerturbedEquilibrium, TOML, Printf, Statistics | ||
|
|
||
| function run_ffs(ex; use_parallel, use_riccati=false) | ||
| inputs = TOML.parsefile(joinpath(ex, "gpec.toml")) | ||
| inputs["ForceFreeStates"]["verbose"] = false | ||
| inputs["ForceFreeStates"]["use_parallel"] = use_parallel | ||
| inputs["ForceFreeStates"]["use_riccati"] = use_riccati | ||
| 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.setup_equilibrium(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.mband = intr.mpert - 1 | ||
| intr.numpert_total = intr.mpert * intr.npert | ||
| metric = GeneralizedPerturbedEquilibrium.ForceFreeStates.make_metric(equil; mband=intr.mband, fft_flag=ctrl.fft_flag) | ||
| ffit = GeneralizedPerturbedEquilibrium.ForceFreeStates.make_matrix(equil, intr, metric) | ||
| odet, _, _, _ = GeneralizedPerturbedEquilibrium.ForceFreeStates.eulerlagrange_integration(ctrl, equil, ffit, intr) | ||
| vac = GeneralizedPerturbedEquilibrium.ForceFreeStates.free_run!(odet, ctrl, equil, ffit, intr) | ||
| return real(vac.et[1]), intr.numpert_total | ||
| end | ||
|
|
||
| function timed_run(ex; use_parallel, use_riccati=false, nwarm=1, nrep=2) | ||
| # Warmup | ||
| for _ in 1:nwarm | ||
| run_ffs(ex; use_parallel, use_riccati) | ||
| end | ||
| # Timed runs | ||
| times = Float64[] | ||
| local et1, N | ||
| for _ in 1:nrep | ||
| t0 = time() | ||
| et1, N = run_ffs(ex; use_parallel, use_riccati) | ||
| push!(times, time() - t0) | ||
| end | ||
| return mean(times), et1, N | ||
| end | ||
|
|
||
| nthreads = Threads.nthreads() | ||
| root = joinpath(@__DIR__, "..") | ||
| sol_ex = joinpath(root, "test", "test_data", "regression_solovev_ideal_example") | ||
| 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_std, et_std, N = timed_run(ex; use_parallel=false, use_riccati=false) | ||
| t_ric, et_ric, _ = timed_run(ex; use_parallel=false, use_riccati=true) | ||
| t_par, et_par, _ = timed_run(ex; use_parallel=true, use_riccati=false) | ||
|
|
||
| err_ric = abs(et_ric - et_std) / abs(et_std) * 100 | ||
| err_par = abs(et_par - et_std) / abs(et_std) * 100 | ||
|
|
||
| println("$label (N=$N, nthreads=$nthreads)") | ||
| @printf(" standard et[1]=%.5f t=%.2fs speedup=1.00×\n", et_std, t_std) | ||
| @printf(" riccati et[1]=%.5f t=%.2fs speedup=%.2f× err=%.4f%%\n", | ||
| et_ric, t_ric, t_std/t_ric, err_ric) | ||
| @printf(" parallel et[1]=%.5f t=%.2fs speedup=%.2f× err=%.4f%%\n", | ||
| et_par, t_par, t_std/t_par, err_par) | ||
| println() | ||
| end |
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about all these other md files outside of docs/src (just in docs)? What was the intent here?