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
34 changes: 31 additions & 3 deletions src/PETScDiffEq.jl
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ mutable struct TSContext{R, S, A, F, F2, JAC, JBUF, P, L, V}
inner::Any
mass_slope::Bool
tend::R
attempt_margin::Int
end

_distributed(alg::AnyPETScTS) = alg.comm != MPI.COMM_SELF
Expand Down Expand Up @@ -2759,6 +2760,19 @@ function _check_attempts!(
return LibPETSc.PetscErrorCode(0)
end

const _MAX_REJECT_OPTIONS = ("ts_max_reject", "ts_max_step_rejections")

function _arm_attempts!(ctx, ts_ptr)
ctx.attempt_margin < 0 && return nothing
pl = ctx.petsclib
code, taken = _taken(pl, ts_ptr)
_check_code(code)
ctx.maxiters - (taken + ctx.nreject + ctx.nfail) > ctx.attempt_margin && return nothing
ctx.attempt_margin = -1
_set_stage_check!(pl, LibPETSc.TS(ts_ptr, pl), ctx, _callbacks(ctx).attempt_check)
return nothing
end

function _set_stage_check!(pl, ts, ctx, ptr)
POST_STEP_CTX[ts.ptr] = (ctx, ts)
_check_code(
Expand Down Expand Up @@ -4436,6 +4450,7 @@ end

function _monitor_at!(ctx, ts_ptr, step, t, x)
try
_arm_attempts!(ctx, ts_ptr)
(ctx.retry_fp || ctx.comm !== nothing) && ctx.workvec == C_NULL &&
_hold_work_vec!(ctx, ts_ptr)
tol = _near(t, ctx.tbound)
Expand Down Expand Up @@ -6159,7 +6174,7 @@ function _setup(
force_dtmin && dtmin !== nothing && dtmin != 0,
nothing, 0, 0, bound,
false, false, step_limit, false, nothing, nothing, 0, 0, false, shape, nothing,
nothing, mass_slope, tf,
nothing, mass_slope, tf, -1,
)::TSContext
h = Base.inferencebarrier(TSHandles)(
ctx, petsclib, LibPETSc.TS(petsclib), uvec, nothing, nothing, ad_calls, nothing,
Expand Down Expand Up @@ -6519,8 +6534,19 @@ function _setup(
!fixed && running == "bdf" &&
!any(o -> _names_option(o, "snes_lag_jacobian"), effective_options) &&
_set_jacobian_lag!(petsclib, _snes(petsclib, ts.ptr), 5)
fixed || _uses_ifunction(alg) ||
_set_stage_check!(petsclib, ts, ctx, ptrs.attempt_check)
if !fixed && !_uses_ifunction(alg)
# PETSc 3.25 renames -ts_max_reject; the pushed options are the only source.
raised = any(effective_options) do o
any(n -> _names_option(o, n), _MAX_REJECT_OPTIONS)
end
if raised
_set_stage_check!(petsclib, ts, ctx, ptrs.attempt_check)
else
# A TSStep makes at most PETSc's default 11 attempts, so the check, which
# runs at every stage, is installed only once maxiters is that close.
ctx.attempt_margin = 13
end
end
ctx.linear = _uses_ifunction(alg) &&
_snes_type(petsclib, ts.ptr) in ("ksponly", "ksptransposeonly")
if running != ctx.alg_name
Expand Down Expand Up @@ -8221,6 +8247,7 @@ function _reuse!(h::TSHandles{<:Any, <:Any, R, S}, prob, tstops) where {R, S}
for i in eachindex(fresh)
setfield!(ctx, i, fresh[i])
end
ctx.attempt_margin < 0 || _set_stage_check!(pl, ts, ctx, C_NULL)
# PETSc's counts run on over the solves of one TS; these offsets take back the earlier ones.
fails = Int(LibPETSc.TSGetSNESFailures(pl, ts))
ctx.nreject = fails - Int(LibPETSc.TSGetStepRejections(pl, ts))
Expand Down Expand Up @@ -8663,6 +8690,7 @@ function _step_unlocked(integ::PETScIntegrator, outer = nothing)
h.stopped = 0
(ctx.retry_fp || ctx.comm !== nothing) && ctx.workvec == C_NULL &&
_hold_work_vec!(ctx, h.ts)
_arm_attempts!(ctx, h.ts.ptr)
failure = _run!(h) do
LibPETSc.TSStep(pl, h.ts)
_linear_bdf_slope!(h)
Expand Down
18 changes: 18 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,24 @@ const ALL_TESTS = Test.DefaultTestSet("PETScDiffEq.jl")
@test counts(integ.sol) == counts(sol)
@test integ.sol.t == sol.t && integ.sol.u == sol.u
end
# A raised reject limit lets one step make more attempts than maxiters has left.
stiff = SciMLBase.ODEProblem(
(du, u, p, t) -> (du[1] = -2.0e3 * (u[1] - cos(t)); du[2] = u[1] - u[2]),
[0.0, 1.0], (0.0, 2.0),
)
# PETSc 3.25 renames -ts_max_reject; 3.22 knows only the old name.
for name in ("-ts_max_reject", "-ts_max_step_rejections")
opts = ["-ts_adapt_clip", "0.95,10", name, "50"]
push!(opts, "-options_suppress_deprecated_warnings")
alg = PETScDiffEq.TSRK("5dp", opts)
sol = SciMLBase.solve(stiff, alg; dt = 1.0, maxiters = 20)
@test sum(counts(sol)) <= 20
name == "-ts_max_reject" && @test sol.retcode == SciMLBase.ReturnCode.MaxIters
integ = SciMLBase.init(stiff, alg; dt = 1.0, maxiters = 20)
SciMLBase.solve!(integ)
@test counts(integ.sol) == counts(sol)
@test integ.sol.retcode == sol.retcode
end
end

@testset "the nonlinear counters come from the solver, not the stepper" begin
Expand Down
Loading