From ad0c0f6fa302681b88d7434b6a3e82c3532dfade Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 6 Apr 2023 16:12:15 -0400 Subject: [PATCH 1/2] add custom/abstract controller description --- docs/src/extras/timestepping.md | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/src/extras/timestepping.md b/docs/src/extras/timestepping.md index 8c167f4e0..beb14eb00 100644 --- a/docs/src/extras/timestepping.md +++ b/docs/src/extras/timestepping.md @@ -150,3 +150,63 @@ end ```@docs PredictiveController ``` + +## Abstract Controller + +The `AbstractController` type allows one to implement custom adaptive +timestepping schemes easily. This can be useful if one wants to use +a priori error estimates, for instance. + +To implement a custom controller, subtype `AbstractController` for the +specific DE system. + +```julia +struct CustomController <: AbstractController +end +``` + +and overload + +```julia +function stepsize_controller!(integrator, controller::CustomController, alg) + ... + nothing +end +function step_accept_controller!(integrator, controller::CustomController, alg) + ... + nothing +end +function step_reject_controller!(integrator, controller::CustomController, alg) + ... + nothing +end +``` + +For instance, the PI controller for SDEs can be reproduced by + +```julia +struct CustomController <: StochasticDiffEq.AbstractController +end + +function StochasticDiffEq.stepsize_controller!(integrator::StochasticDiffEq.SDEIntegrator, controller::CustomController, alg) + integrator.q11 = DiffEqBase.value(DiffEqBase.fastpow(integrator.EEst, controller.beta1)) + integrator.q = DiffEqBase.value(integrator.q11 / DiffEqBase.fastpow(integrator.qold, controller.beta2)) + integrator.q = DiffEqBase.value(max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), integrator.q / integrator.opts.gamma))) + nothing +end + +function StochasticDiffEq.step_accept_controller!(integrator::StochasticDiffEq.SDEIntegrator, controller::CustomController, alg) + integrator.dtnew = DiffEqBase.value(integrator.dt/integrator.q) * oneunit(integrator.dt) + nothing +end + +function step_reject_controller!(integrator::StochasticDiffEq.SDEIntegrator, controller::CustomController, alg) + integrator.dtnew = integrator.dt / min(inv(integrator.opts.qmin), integrator.q11 / integrator.opts.gamma) +end +``` + +and used via + +```julia +sol = solve(prob, EM(), dt=dt, adaptive=true, controller=CustomController()) +``` From 1d8a248ce78ccd3c1079f40b3639923e0382af86 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 6 Apr 2023 17:06:26 -0400 Subject: [PATCH 2/2] run formatter --- docs/src/extras/timestepping.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/src/extras/timestepping.md b/docs/src/extras/timestepping.md index beb14eb00..15441095f 100644 --- a/docs/src/extras/timestepping.md +++ b/docs/src/extras/timestepping.md @@ -188,25 +188,33 @@ For instance, the PI controller for SDEs can be reproduced by struct CustomController <: StochasticDiffEq.AbstractController end -function StochasticDiffEq.stepsize_controller!(integrator::StochasticDiffEq.SDEIntegrator, controller::CustomController, alg) +function StochasticDiffEq.stepsize_controller!(integrator::StochasticDiffEq.SDEIntegrator, + controller::CustomController, alg) integrator.q11 = DiffEqBase.value(DiffEqBase.fastpow(integrator.EEst, controller.beta1)) - integrator.q = DiffEqBase.value(integrator.q11 / DiffEqBase.fastpow(integrator.qold, controller.beta2)) - integrator.q = DiffEqBase.value(max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), integrator.q / integrator.opts.gamma))) + integrator.q = DiffEqBase.value(integrator.q11 / + DiffEqBase.fastpow(integrator.qold, controller.beta2)) + integrator.q = DiffEqBase.value(max(inv(integrator.opts.qmax), + min(inv(integrator.opts.qmin), + integrator.q / integrator.opts.gamma))) nothing end -function StochasticDiffEq.step_accept_controller!(integrator::StochasticDiffEq.SDEIntegrator, controller::CustomController, alg) - integrator.dtnew = DiffEqBase.value(integrator.dt/integrator.q) * oneunit(integrator.dt) +function StochasticDiffEq.step_accept_controller!(integrator::StochasticDiffEq.SDEIntegrator, + controller::CustomController, alg) + integrator.dtnew = DiffEqBase.value(integrator.dt / integrator.q) * + oneunit(integrator.dt) nothing end -function step_reject_controller!(integrator::StochasticDiffEq.SDEIntegrator, controller::CustomController, alg) - integrator.dtnew = integrator.dt / min(inv(integrator.opts.qmin), integrator.q11 / integrator.opts.gamma) +function step_reject_controller!(integrator::StochasticDiffEq.SDEIntegrator, + controller::CustomController, alg) + integrator.dtnew = integrator.dt / min(inv(integrator.opts.qmin), + integrator.q11 / integrator.opts.gamma) end ``` and used via ```julia -sol = solve(prob, EM(), dt=dt, adaptive=true, controller=CustomController()) +sol = solve(prob, EM(), dt = dt, adaptive = true, controller = CustomController()) ```