Code
"""
rk23(ivp,tol)
Apply an adaptive embedded RK formula pair to solve given IVP with
estimated error `tol`. Returns a vector of times and a vector of
solution values.
"""
function rk23(ivp,tol)
# Initialize for the first time step.
a,b = ivp.tspan
t = [a]
u = [float(ivp.u0)]; i = 1;
h = 0.5*tol^(1/3)
s₁ = ivp.f(ivp.u0,ivp.p,a)
# Time stepping.
while t[i] < b
# Detect underflow of the step size.
if t[i]+h == t[i]
@warn "Stepsize too small near t=$(t[i])"
break # quit time stepping loop
end
# New RK stages.
s₂ = ivp.f( u[i]+(h/2)*s₁, ivp.p, t[i]+h/2 )
s₃ = ivp.f( u[i]+(3h/4)*s₂, ivp.p, t[i]+3h/4 )
unew2 = u[i] + h*(2s₁ + 3s₂ + 4s₃)/9 # 2rd order solution
s₄ = ivp.f( unew2, ivp.p, t[i]+h )
err = h*(-5s₁/72 + s₂/12 + s₃/9 - s₄/8) # 2nd/3rd difference
E = norm(err,Inf) # error estimate
maxerr = tol*(1 + norm(u[i],Inf)) # relative/absolute blend
# Accept the proposed step?
if E < maxerr # yes
push!(t,t[i]+h)
push!(u,unew2)
i += 1
s₁ = s₄ # use FSAL property
end
# Adjust step size.
q = 0.8*(maxerr/E)^(1/3) # conservative optimal step factor
q = min(q,4) # limit stepsize growth
h = min(q*h,b-t[i]) # don't step past the end
end
return t,u
end
rk23