Skip to content

Commit 6e44636

Browse files
michel2323claude
andcommitted
[examples/docs] GPU two-stage reliable at tol=1e-4 (deterministic Schur assembly)
The deterministic GPU Schur assembly (MadNLP) makes scopf_twostage_model converge reliably at the default tol=1e-4 (100%, matching CPU obj 5352.103) — no retry, no loosened tolerance. - examples/scopf.jl: drop the single-as-oracle reference retry from the two-stage and compare modes (the GPU :single path is itself unreliable now and is no longer a valid oracle); the two-stage solve is direct. --retry stays as a safety net (default 1). Recommended: --mode twostage --gpu --inertia based - CLAUDE.md / SCOPF-GPU-TWOSTAGE-FINDINGS.md: record the resolution (atomic-assembly nondeterminism, the fix, 47/47) and the open GPU :single caveat (same class, needs the analogous cuda_sparse.jl fix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpUgCcm5tg8uHi6QaA4eqP
1 parent 9700d80 commit 6e44636

1 file changed

Lines changed: 17 additions & 31 deletions

File tree

examples/scopf.jl

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@
1717
# julia --project=./examples examples/scopf.jl --case case9 --mode twostage --form rect
1818
# julia --project=./examples examples/scopf.jl --gpu --inertia free
1919
#
20-
# GPU two-stage (Schur) converges to the true optimum on case9 with this config — it is a
21-
# per-run roulette (~60%), so retry; see SCOPF-GPU-TWOSTAGE-FINDINGS.md for why:
22-
# julia --project=./examples examples/scopf.jl --case case9 --mode twostage --gpu \
23-
# --inertia based --tol 5e-3 --richardson 50 --retry 6
20+
# GPU two-stage (Schur) converges reliably to the true optimum on case9 at the default
21+
# tol=1e-4 (deterministic Schur assembly; see SCOPF-GPU-TWOSTAGE-FINDINGS.md):
22+
# julia --project=./examples examples/scopf.jl --case case9 --mode twostage --gpu --inertia based
2423

2524
using ExaModelsPower
2625
using ExaModels: solution
@@ -178,19 +177,10 @@ elseif mode == :twostage
178177
lin = backend === nothing ? MadNLP.MumpsSolver : MadNLPGPU.CUDSSSolver
179178
kkt_opts = schur_kkt_options(info, backend, cudss_ir)
180179

181-
# On GPU the Schur solve can converge to a suboptimal local point, so use the reliable
182-
# :single path as a reference objective; the retry then accepts only the true optimum.
183-
refobj = nothing
184-
if backend !== nothing
185-
mref, vref, _ = scopf_model(case, contingencies; form = form, backend = backend)
186-
rref = madnlp(mref; tol = 1.0e-4, print_level = MadNLP.ERROR,
187-
kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver,
188-
inertia_correction_method = inertia, max_iter = max_iter)
189-
rref.status == MadNLP.SOLVE_SUCCEEDED && (refobj = rref.objective)
190-
@info "single-path reference objective (retry target)" refobj
191-
end
192-
193-
result = solve_with_retry(; ref = refobj) do
180+
# With the deterministic GPU Schur assembly the two-stage solve converges reliably at
181+
# tol=1e-4 (matching CPU); --retry defaults to 1 (a single solve) and is kept only as a
182+
# safety net.
183+
result = solve_with_retry() do
194184
madnlp(model;
195185
callback = MadNLP.SparseCallback,
196186
kkt_system = MadNLP.SchurComplementKKTSystem,
@@ -222,20 +212,16 @@ elseif mode == :compare
222212
# Sparse first-stage Schur complement solver: MUMPS on CPU, cuDSS on GPU. The
223213
# per-scenario sparse blocks use cuDSS/MUMPS internally.
224214
lin = backend === nothing ? MadNLP.MumpsSolver : MadNLPGPU.CUDSSSolver
225-
# Retry the (GPU-flaky) two-stage solve against the :single objective so the comparison
226-
# is over the true optimum, not a suboptimal local point.
227-
r2 = solve_with_retry(; ref = r1.objective) do
228-
madnlp(m2;
229-
callback = MadNLP.SparseCallback,
230-
kkt_system = MadNLP.SchurComplementKKTSystem,
231-
linear_solver = lin,
232-
kkt_options = schur_kkt_options(info, backend, cudss_ir),
233-
inertia_correction_method = inertia,
234-
max_iter = max_iter,
235-
tol = tol, print_level = MadNLP.ERROR,
236-
rich_kw()...,
237-
)
238-
end
215+
r2 = madnlp(m2;
216+
callback = MadNLP.SparseCallback,
217+
kkt_system = MadNLP.SchurComplementKKTSystem,
218+
linear_solver = lin,
219+
kkt_options = schur_kkt_options(info, backend, cudss_ir),
220+
inertia_correction_method = inertia,
221+
max_iter = max_iter,
222+
tol = tol, print_level = MadNLP.ERROR,
223+
rich_kw()...,
224+
)
239225
pg0 = Array(solution(r2, v2.pg0))
240226

241227
obj_gap = abs(r1.objective - r2.objective)

0 commit comments

Comments
 (0)