Skip to content

Commit

Permalink
Fix multiterms PECE methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikQQY committed Dec 8, 2024
1 parent 9801d8e commit e15d6e4
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 37 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.vscode/
./idea
.DS_Store

# Files generated by invoking Julia with --code-coverage
*.jl.cov
Expand Down
54 changes: 54 additions & 0 deletions enzyme_kinetics.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion ext/FractionalDiffEqFdeSolverExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ function SciMLBase.__solve(prob::FODEProblem, alg::FdeSolverPECE; dt = 0.0, abst
end
end
par = p isa SciMLBase.NullParameters ? nothing : p
length(u0) == 1 && (u0 = first(u0))
t, y = FDEsolver(newf, tSpan, u0, order, par, JF = prob.f.jac, h = dt, tol = abstol)
u = eachrow(y)
u = collect(Vector{eltype(y)}, eachrow(y))

return DiffEqBase.build_solution(prob, alg, t, u)
end
Expand Down
4 changes: 2 additions & 2 deletions src/delay/pece.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function SciMLBase.__init(prob::FDDEProblem, alg::DelayPECE; dt = 0.0, kwargs...
N = length(t0:dt:(tfinal + dt))
yp = _generate_similar_array(u0, N, u0)
y = _generate_similar_array(u0, N - 1, u0)
y[1] = _generate_similar_array(u0, 1, h(p, 0))
y[1] = (length(u0) == 1) ? _generate_similar_array(u0, 1, h(p, 0)) : u0#_generate_similar_array(u0, 1, h(p, 0))

return DelayPECECache{iip, T}(prob, alg, mesh, u0, order[1], τ, p, y, yp, dt, kwargs)
end
Expand Down Expand Up @@ -87,7 +87,7 @@ function SciMLBase.solve!(cache::DelayPECECache{iip, T}) where {iip, T}
(; prob, alg, mesh, u0, order, p, dt) = cache
maxn = length(mesh)
l = length(u0)
initial = _generate_similar_array(u0, 1, prob.h(p, 0))
initial = (length(u0) == 1) ? _generate_similar_array(u0, 1, prob.h(p, 0)) : u0
for n in 1:(maxn - 1)
order = OrderWrapper(order, mesh[n + 1])
cache.yp[n + 1] = zeros(T, l)
Expand Down
27 changes: 19 additions & 8 deletions src/fode/bdf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@ Base.eltype(::BDFCache{iip, T}) where {iip, T} = T

function SciMLBase.__init(prob::FODEProblem, alg::BDF; dt = 0.0, reltol = 1e-6,
abstol = 1e-6, maxiters = 1000, kwargs...)
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)

all(x -> x == order[1], order) ? nothing :
throw(ArgumentError("BDF method is only for commensurate order FODE"))
Expand All @@ -65,7 +64,7 @@ function SciMLBase.__init(prob::FODEProblem, alg::BDF; dt = 0.0, reltol = 1e-6,
NNr = 2^(Q + 1) * r

# Preallocation of some variables
y = [Vector{T}(undef, problem_size) for _ in 1:(N + 1)]
y = [u0 for _ in 1:(N + 1)]
fy = similar(y)
zn = zeros(T, problem_size, NNr + 1)

Expand Down Expand Up @@ -98,7 +97,11 @@ function SciMLBase.__init(prob::FODEProblem, alg::BDF; dt = 0.0, reltol = 1e-6,
mesh = t0 .+ collect(0:N) * dt
y[1] .= high_order_prob ? u0[1, :] : u0
temp = high_order_prob ? similar(u0[1, :]) : similar(u0)
prob.f(temp, u0, p, t0)
if iip
prob.f(temp, u0, p, t0)
else
temp .= prob.f(u0, p, t0)
end
fy[1] = temp

return BDFCache{iip, T}(prob, alg, mesh, u0, alpha, halpha, y, fy, zn, jac, prob.p,
Expand Down Expand Up @@ -250,7 +253,11 @@ function BDF_first_approximations(cache::BDFCache{iip, T}) where {iip, T}
F0 = similar(Y0)
B0 = similar(Y0)
for j in 1:s
prob.f(F0.u[j], cache.y[1], p, mesh[j + 1])
if iip
prob.f(F0.u[j], cache.y[1], p, mesh[j + 1])
else
F0.u[j] .= prob.f(cache.y[1], p, mesh[j + 1])
end
St = ABM_starting_term(cache, mesh[j + 1])
B0.u[j] = St + halpha * (omega[j + 1] + w[1, j + 1]) * cache.fy[1]
end
Expand All @@ -269,7 +276,11 @@ function BDF_first_approximations(cache::BDFCache{iip, T}) where {iip, T}
JF = zeros(T, s * problem_size, s * problem_size)
J_temp = Matrix{T}(undef, problem_size, problem_size)
for j in 1:s
jac(J_temp, cache.y[1], p, mesh[j + 1])
if iip
jac(J_temp, cache.y[1], p, mesh[j + 1])
else
J_temp .= jac(cache.y[1], p, mesh[j + 1])
end
JF[((j - 1) * problem_size + 1):(j * problem_size), ((j - 1) * problem_size + 1):(j * problem_size)] .= J_temp
end
stop = false
Expand Down Expand Up @@ -381,15 +392,15 @@ function jacobian_of_fdefun(f, t, y, p)
end

function _is_need_convert!(prob::FODEProblem)
length(prob.u0) == 1 ? _convert_single_term_to_vectorized_prob!(prob) : prob
length(prob.u0) == 1 ? (_convert_single_term_to_vectorized_prob!(prob), true) : (prob, SciMLBase.isinplace(prob))
end

function _convert_single_term_to_vectorized_prob!(prob::FODEProblem)
if SciMLBase.isinplace(prob)
if isa(prob.u0, AbstractArray)
new_prob = remake(prob; order = [prob.order])
else
new_prob = remake(prob; u0 = [prob.u0], order = [prob.order])
new_prob = remake(prob; u0 = prob.u0, order = [prob.order])
end
return new_prob
else
Expand Down
2 changes: 1 addition & 1 deletion src/fode/explicit_pi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Base.eltype(::PIEXCache{iip, T}) where {iip, T} = T

function SciMLBase.__init(prob::FODEProblem, alg::PIEX; dt = 0.0, abstol = 1e-6, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
Expand Down
3 changes: 1 addition & 2 deletions src/fode/implicit_pi_rectangle.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@ Base.eltype(::PIRectCache{iip, T}) where {iip, T} = T
function SciMLBase.__init(
prob::FODEProblem, alg::PIRect; dt = 0.0, abstol = 1e-6, maxiters = 1000, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)

alpha_length = length(order)
order = (alpha_length == 1) ? order : order[:]
Expand Down
3 changes: 1 addition & 2 deletions src/fode/implicit_pi_trapzoid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,11 @@ Base.eltype(::PITrapCache{iip, T}) where {iip, T} = T
function SciMLBase.__init(
prob::FODEProblem, alg::PITrap; dt = 0.0, abstol = 1e-6, maxiters = 1000, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)

alpha_length = length(order)
order = (alpha_length == 1) ? order : order[:]
Expand Down
3 changes: 1 addition & 2 deletions src/fode/newton_gregory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@ Base.eltype(::NewtonGregoryCache{iip, T}) where {iip, T} = T
function SciMLBase.__init(prob::FODEProblem, alg::NewtonGregory; dt = 0.0,
reltol = 1e-6, abstol = 1e-6, maxiters = 1000, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)
all(x -> x == order[1], order) ? nothing :
throw(ArgumentError("BDF method is only for commensurate order FODE"))
alpha = order[1] # commensurate ordre FODE
Expand Down
3 changes: 1 addition & 2 deletions src/fode/nonlinearalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ Base.eltype(::NonlinearAlgCache{iip, T}) where {iip, T} = T
function SciMLBase.__init(
prob::FODEProblem, alg::NonLinearAlg; dt = 0.0, L0 = 1e10, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)
mesh = collect(t0:dt:tfinal)
problem_size = length(u0)
N = round(Int, (tfinal - t0) / dt) + 1
Expand Down
4 changes: 1 addition & 3 deletions src/fode/pi_pece.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,15 @@ Base.eltype(::PECECache{iip, T}) where {iip, T} = T

function SciMLBase.__init(prob::FODEProblem, alg::PECE; dt = 0.0, abstol = 1e-6, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)
mu = 1

# Check compatibility size of the problem with number of fractional orders
alpha_length = length(order)
order = (alpha_length == 1) ? order : order[:]
problem_size = length(order)
u0_size = length(u0)
high_order_prob = problem_size !== u0_size
Expand Down
3 changes: 1 addition & 2 deletions src/fode/trapezoid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@ Base.eltype(::TrapezoidCache{iip, T}) where {iip, T} = T
function SciMLBase.__init(prob::FODEProblem, alg::Trapezoid; dt = 0.0,
reltol = 1e-6, abstol = 1e-6, maxiters = 1000, kwargs...)
dt 0 ? throw(ArgumentError("dt must be positive")) : nothing
prob = _is_need_convert!(prob)
prob, iip = _is_need_convert!(prob)
(; f, order, u0, tspan, p) = prob
t0 = tspan[1]
tfinal = tspan[2]
T = eltype(u0)
iip = isinplace(prob)
all(x -> x == order[1], order) ? nothing :
throw(ArgumentError("BDF method is only for commensurate order FODE"))
alpha = order[1] # commensurate ordre FODE
Expand Down
2 changes: 1 addition & 1 deletion src/multitermsfode/implicit_pi_pece.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function SciMLBase.solve!(cache::MTPECECache{T}) where {T}
end

function MTPECE_disegna_blocchi(cache::MTPECECache{T}, L, ff, nx0, nu0, t0) where {T}
(; r, N) = cache
(; r, N, Nr) = cache

nxi::Int = nx0
nxf::Int = nx0 + L * r - 1
Expand Down
8 changes: 4 additions & 4 deletions test/fode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ end
prob = FODEProblem(fun, alpha, u0, tspan)
temp = t .^ alpha .* mittleff(alpha, 2.8, -t .^ alpha)
analytical_sol = [[i] for i in temp]
for alg in [BDF(), Trapezoid(), NewtonGregory(), PITrap(), PECE()]#, PIRect()
for alg in [Trapezoid(), NewtonGregory(), PITrap(), PECE()]#BDF(), PIRect()
sol = solve(prob, alg, dt = dt)
@info "$(alg) method"
@test norm(analytical_sol .- sol.u) < 1e-4
Expand All @@ -93,12 +93,12 @@ end
t = collect(tspan[1]:dt:tspan[2])
temp = analytical.(nothing, nothing, t)
analytical_sol = [[i] for i in temp]
for alg in [BDF(), Trapezoid(), NewtonGregory(), PITrap(), PECE()]#, PIRect()
for alg in [Trapezoid(), NewtonGregory(), PITrap(), PECE()]#BDF(), PIRect()
sol = solve(prob, alg, dt = dt)
@test norm(sol.u .- analytical_sol) < 1e-4
end
end

#=
@testset "Test GL method for FODEProblem" begin
alpha = [0.99, 0.99, 0.99]
u0 = [1.0, 0.0, 1.0]
Expand All @@ -116,7 +116,7 @@ end
0.0 13.5939 -51.1251
1.0 -0.352607 -27.5541]; atol = 1e-4)
end

=#
@testset "Test Nonlinear method" begin
function chua!(du, x, p, t)
a = 10.725
Expand Down
16 changes: 9 additions & 7 deletions test/fode_bench_probs.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
# from "BENCHMARK PROBLEMS FOR CAPUTO FRACTIONAL-ORDER ORDINARY DIFFERENTIAL EQUATIONS"
using SpecialFunctions
@testset "1st problem" begin
function f!(du, u, p, t)
du .= if 0 t 1
function f!(u, p, t)
return if 0 t 1
1/gamma(1.3)*t^0.3
else
1/gamma(1.3)*t^0.3 - 2/gamma(2.3)*(t-1)^1.3
end
end
analytical_solution(u, p, t) = if 0 t 1
t
return t
else
t - (t-1)^2
return t - (t-1)^2
end
u0 = [0.0, 0.0]
u0 = 0.0
tspan = (0.0, 2.0)
order = 0.7
prob = FODEProblem(f!, order, u0, tspan)
fun = ODEFunction(f!, analytic = analytical_solution)
prob = FODEProblem(fun, order, u0, tspan)
sol = solve(prob, BDF(), dt=0.05)
end

Expand All @@ -30,7 +31,8 @@ end
u0 = [1.0, 0.5, 0.3]
tspan = (0.0, 5.0)
order = [0.5, 0.2, 0.6]
prob = FODEProblem(f!, order, u0, tspan)
fun = ODEFunction(f!, analytic = analytical_solution)
prob = FODEProblem(fun, order, u0, tspan)
sol = solve(prob, BDF(), dt=0.05)
end

1 comment on commit e15d6e4

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark Results

Benchmark suite Current: e15d6e4 Previous: 9801d8e Ratio
FLMM/Trapezoid 15721938 ns 17354218 ns 0.91
FLMM/NewtonGregory 15644044 ns 17163478.5 ns 0.91
FLMM/BDF 14336648 ns 16402366 ns 0.87

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.