From 3bc83195924dab5bc6b447b88c5480ac42f68e24 Mon Sep 17 00:00:00 2001 From: LaSalle Date: Tue, 24 Mar 2026 12:16:16 -0400 Subject: [PATCH] added retcodes, still need test for failed correction step. --- src/PALC/continuation.jl | 9 +++-- src/PALC/correction.jl | 17 ++++++++- src/PALC/palc.jl | 9 ++++- test/test_retcodes.jl | 82 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 test/test_retcodes.jl diff --git a/src/PALC/continuation.jl b/src/PALC/continuation.jl index 4c79113..92819ce 100644 --- a/src/PALC/continuation.jl +++ b/src/PALC/continuation.jl @@ -85,16 +85,19 @@ function continuation!( palc_prediction!(cache, alg, p, solvers, trace) # Perform correction step - success, hit_bnd = palc_correction!( + success, terminate_continuation = palc_correction!( cache, alg, p, solvers, dsmin, dsmax, term_callback, analysis_callback, trace ) if iter >= max_cont_steps done = true - elseif !success + cache.ret = :Maxiters + elseif !success # If correction step failed, end the process done = true - elseif success && hit_bnd + # cache ret should be set within correction to determine failure condition (currently this is limited to min stepsize) + elseif success && terminate_continuation # termination is due to callback or hitting bound, consider successful done = true + # cache ret should be set within correction to determine termination condition end end return nothing diff --git a/src/PALC/correction.jl b/src/PALC/correction.jl index 7143d8a..4241669 100644 --- a/src/PALC/correction.jl +++ b/src/PALC/correction.jl @@ -115,10 +115,11 @@ function palc_correction!( scale_and_clamp_ds!(cache, 0.5, dsmin, dsmax) end end - else + else # solve is not successful if abs(cache.ds) == dsmin done = true success = false + cache.ret = :MinimumStepSize # update ret with 'done' condition. This won't be overwritten since success=false (see continuation.jl) else # Reduce step-size and reattempt scale_and_clamp_ds!(cache, 0.5, dsmin, dsmax) @@ -137,7 +138,11 @@ function palc_correction!( success && call!(analysis_callback, cache) # Handle termination flag - terminate_continuation = !isnan(hit_bnd) || cb_trig + terminate_continuation = !isnan(hit_bnd) || cb_trig # hit bound or triggered callback + + if terminate_continuation + set_successful_retcode!(cache, hit_bnd, cb_trig) + end return success, terminate_continuation end @@ -393,3 +398,11 @@ function palc_correction_jacobian!(J, uλ, p) return nothing end + +function set_successful_retcode!(cache, hit_bnd, cb_trig) + if isnan(hit_bnd) && cb_trig + cache.ret = :CallbackTermination + elseif !cb_trig + cache.ret = :HitBound + end +end \ No newline at end of file diff --git a/src/PALC/palc.jl b/src/PALC/palc.jl index 77a4615..09e1a7d 100644 --- a/src/PALC/palc.jl +++ b/src/PALC/palc.jl @@ -79,6 +79,9 @@ mutable struct PALCCache{MT<:Union{Matrix{Float64},SparseMatrixCSC{Float64,Int}} u_0::Vector{Float64} u_1::Vector{Float64} u_t::Vector{Float64} + + # Return code + ret::Symbol # could also do a custom type for pretty viewing like sciml but symbols should work just fine end function PALCCache( @@ -118,7 +121,7 @@ function PALCCache( u_0 = similar(u0) u_1 = similar(u0) u_t = similar(u0) - + ret = :None # init return code (should always be overwritten) return PALCCache{Matrix{Float64}}( ds0, br, @@ -139,6 +142,7 @@ function PALCCache( u_0, u_1, u_t, + ret ) end function PALCCache( @@ -183,6 +187,8 @@ function PALCCache( u_1 = similar(u0) u_t = similar(u0) + ret = :None # init return code + return PALCCache{SparseMatrixCSC{Float64,Int}}( ds0, br, @@ -203,6 +209,7 @@ function PALCCache( u_0, u_1, u_t, + ret ) end diff --git a/test/test_retcodes.jl b/test/test_retcodes.jl new file mode 100644 index 0000000..92f12aa --- /dev/null +++ b/test/test_retcodes.jl @@ -0,0 +1,82 @@ +using SimpleContinuation +using Test + +const SC = SimpleContinuation + +function scalar_test_fun!(F, x, λ) + F[1] = (λ + x[1] - x[1]^3 / 3) +end + +function scalar_fun_ujac!(J, F, x, λ) + scalar_test_fun!(F, x, λ) + J[1,1] = 1 - x[1]^2 +end + +function scalar_fun_jac!(J, F, x, λ) + scalar_test_fun!(F, x, λ) + J[1,1] = 1 - x[1]^2 + J[1,2] = 1 +end + +u0 = [-2.] +λ0 = -1. + +f_min_time = (F, u, s) -> scalar_test_fun!(F, u, s) +Jz_min_time = (J, F, u, s) -> scalar_fun_ujac!(J, F, u, s) +J_min_time = (J, F, u, s) -> scalar_fun_jac!(J, F, u, s) + +# Should term due to callback +cache = continuation( + ContinuationProblem( + ContinuationFunction{Val{true}}(f_min_time, Jz_min_time, J_min_time), + u0, + λ0, + (λ0, 1.0), + ), + PALC(; predicter=Bordered()); + both_sides=false, + ds0=0.01, + dsmin=1e-1, + dsmax=0.01, + max_cont_steps=10e3, + #trace=ContinuationSteps(), + term_callback=FoldBifurcationTerminationCallback(), +) +@test cache.ret == :CallbackTermination + +# Should term due to hitting boundary +cache = continuation( + ContinuationProblem( + ContinuationFunction{Val{true}}(f_min_time, Jz_min_time, J_min_time), + u0, + λ0, + (λ0, 1.0), + ), + PALC(; predicter=Bordered()); + both_sides=false, + ds0=0.01, + dsmin=1e-1, + dsmax=0.01, + max_cont_steps=10e3, + #trace=ContinuationSteps(), +) +@test cache.ret == :HitBound + +# Should term due to maxiters +cache = continuation( + ContinuationProblem( + ContinuationFunction{Val{true}}(f_min_time, Jz_min_time, J_min_time), + u0, + λ0, + (λ0, 1.0), + ), + PALC(; predicter=Bordered()); + both_sides=false, + ds0=0.01, + dsmin=1e-1, + dsmax=0.01, + max_cont_steps=10, + #trace=ContinuationSteps(), +) +@test cache.ret == :Maxiters +