Skip to content

Commit 7ca76be

Browse files
committed
Improve order estimation utility
1 parent 86fed73 commit 7ca76be

3 files changed

Lines changed: 44 additions & 41 deletions

File tree

examples/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
66
GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2"
77
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
88
LayeredLayouts = "f4a74d36-062a-4d48-97cd-1356bad1de4e"
9+
LinearRegression = "92481ed7-9fb7-40fd-80f2-46fd0f076581"
910
NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a"
1011
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
1112
ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5"
1213
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
14+
OrdinaryDiffEqRosenbrock = "43230ef6-c299-4910-a778-202eb28ce4ce"
1315
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
1416
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1517
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"

examples/implicit_integration.jl

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
include("integration.jl")
22

3-
using NonlinearSolve, ODEProblemLibrary, LinearAlgebra
3+
using NonlinearSolve, ODEProblemLibrary, LinearAlgebra, LinearRegression
4+
using OrdinaryDiffEq, OrdinaryDiffEqRosenbrock
45

56
# a simple fixed time-step driver for rapid algorithm prototyping
67
function integrate(prob, solver; h)
@@ -46,18 +47,19 @@ struct MuTaylorExtrapolation{P, T1, T2, T3, T4}
4647
end
4748

4849
function prepare(prob, solver::MuTaylorExtrapolation{P, T1, T2, T3, T4}) where {P, T1, T2, T3, T4}
49-
propagator_all, _ = build_propagator(prob.f, prob.p, ntuple(_ -> 1.0, solver.order), length(prob.u0))
50+
propagator_all, d_propagator_all = build_propagator(prob.f, prob.p, ntuple(_ -> 1.0, solver.order), length(prob.u0))
5051
propagator, _ = propagator_all
51-
return (; propagator)
52+
d_propagator, _ = d_propagator_all
53+
return (; propagator, d_propagator)
5254
end
5355

5456
function update!(u, prob, solver::MuTaylorExtrapolation{P, T1, T2, T3, T4}, cache, t, h) where {T1, T2, T3, T4, P}
5557
(; μ1, c1, μ2, c2) = solver
5658
(; propagator) = cache
5759
tm1 = t + μ1 * h
5860
tm2 = t + μ2 * h
59-
nlf = (u_next, u_curr) -> propagator(u_next, tm1, -μ1 * h) - u_curr
60-
nlprob1 = NonlinearProblem(nlf, copy(u), u)
61+
nlf1 = (u_next, u_curr) -> propagator(u_next, tm1, -μ1 * h) - u_curr
62+
nlprob1 = NonlinearProblem(nlf1, copy(u), u)
6163
sol1 = solve(nlprob1)
6264
u_trial1 = real(propagator(sol1.u, tm1, (1 - μ1) * h))
6365
nlf2 = (u_next, u_curr) -> propagator(u_next, tm2, -μ2 * h) - u_curr
@@ -67,27 +69,22 @@ function update!(u, prob, solver::MuTaylorExtrapolation{P, T1, T2, T3, T4}, cach
6769
return u .= (c1 * u_trial1 + c2 * u_trial2)
6870
end
6971

70-
function estimate_order(solver, prob; dt1 = 1/12, dt2 = 1/16)
71-
ref = prob.f.analytic(prob.u0, prob.p, prob.tspan[2])
72-
println("Reference: ", ref)
73-
u1 = integrate(prob, solver; h = dt1)
74-
println("u1: ", u1)
75-
u2 = integrate(prob, solver; h = dt2)
76-
println("u2: ", u2)
77-
err1 = norm(u1 - ref)
78-
err2 = norm(u2 - ref)
79-
order = log(err1 / err2) / log(dt1 / dt2)
80-
return order
81-
end
72+
prob = ODEProblemLibrary.prob_ode_lotkavolterra
73+
refsol = solve(prob, Tsit5(); reltol = 1e-14, abstol = 1e-14)
8274

83-
u0 = rand(2)
84-
linear_f = ODEFunction(
85-
ODEProblemLibrary.f_2dlinear, analytic = ODEProblemLibrary.f_2dlinear_analytic
86-
)
87-
prob = ODEProblem(linear_f, u0, (0.0, 1.0), 1.01)
88-
prob_complex = ODEProblem(
89-
linear_f, complex(u0), (0.0, 1.0), 1.01
90-
)
75+
function estimate_order(solver, prob; dts = 2. .^ (-10:-4))
76+
println("Reference: ", refsol.u[end])
77+
errs = Float64[]
78+
for dt in dts
79+
u = integrate(prob, solver; h = dt)
80+
err = norm(u - refsol.u[end])
81+
push!(errs, err)
82+
end
83+
logdts = log.(dts)
84+
logerrs = log.(errs)
85+
lr = linregress(logdts, logerrs)
86+
return LinearRegression.slope(lr)
87+
end
9188

9289
ImplicitTaylor = MuTaylor(Val(1), 1.0)
9390
ImplicitTaylorMidpoint = MuTaylor(Val(1), 0.5)
@@ -119,9 +116,9 @@ function normalized_pade(p::Int, q::Int)
119116
RI = Rational{BigInt}
120117
N = p + q
121118
c = Vector{RI}(undef, N + 1)
122-
c[1] = big(1) // big(1)
119+
c[1] = 1 // 1
123120
for k in 1:N
124-
c[k + 1] = c[k] // big(k)
121+
c[k + 1] = c[k] // k
125122
end
126123
if q == 0
127124
dres = RI[]
@@ -133,7 +130,7 @@ function normalized_pade(p::Int, q::Int)
133130
rhs[i] = -c[k + 1] # -c_k
134131
for j in 1:q
135132
idx = k - j # 0-indexed Taylor index
136-
A[i, j] = idx >= 0 ? c[idx + 1] : big(0) // big(1)
133+
A[i, j] = idx >= 0 ? c[idx + 1] : 0 // 1
137134
end
138135
end
139136
dres = A \ rhs # Rational 精确求解
@@ -145,7 +142,7 @@ function normalized_pade(p::Int, q::Int)
145142
n[k + 1] += dres[j] * c[k - j + 1]
146143
end
147144
end
148-
d = vcat(big(1) // big(1), dres)
145+
d = vcat(1 // 1, dres)
149146
normalized_n = [x * factorial(k - 1) for (k, x) in enumerate(n)]
150147
normalized_d = [x * factorial(k - 1) for (k, x) in enumerate(d)]
151148
return normalized_n, normalized_d
@@ -159,22 +156,25 @@ end
159156

160157
function prepare(prob, solver::TaylorPade{P, Q}) where {P, Q}
161158
polynomial_p, polynomial_q = normalized_pade(P, Q)
162-
tuple_p = Base.tail(tuple(map(Float64, polynomial_p)...))
163-
tuple_q = Base.tail(tuple(map(Float64, polynomial_q)...))
164-
println("Pade coefficients (numerator): ", tuple_p)
165-
println("Pade coefficients (denominator): ", tuple_q)
166-
propagator_p_all, _ = build_propagator(prob.f, prob.p, tuple_p, length(prob.u0))
167-
propagator_q_all, _ = build_propagator(prob.f, prob.p, tuple_q, length(prob.u0))
159+
println("Pade coefficients: P = $polynomial_p, Q = $polynomial_q")
160+
tuple_p = tuple(map(Float64, polynomial_p)...)
161+
tuple_q = tuple(map(Float64, polynomial_q)...)
162+
propagator_p_all, d_propagator_p_all = build_propagator(prob.f, prob.p, tuple_p, length(prob.u0))
163+
propagator_q_all, d_propagator_q_all = build_propagator(prob.f, prob.p, tuple_q, length(prob.u0))
168164
propagator_p, _ = propagator_p_all
169165
propagator_q, _ = propagator_q_all
170-
return (; propagator_p, propagator_q)
166+
d_propagator_p, _ = d_propagator_p_all
167+
d_propagator_q, _ = d_propagator_q_all
168+
return (; propagator_p, propagator_q, d_propagator_p, d_propagator_q)
171169
end
172170

173171
function update!(u, prob, solver::TaylorPade{P, Q}, cache, t, h) where {P, Q}
174-
(; propagator_p, propagator_q) = cache
172+
(; propagator_p, propagator_q, d_propagator_p, d_propagator_q) = cache
175173
rhs = propagator_p(u, t, h)
176174
nlf = (u_next, rhs) -> propagator_q(u_next, t + h, h) .- rhs
177-
nlprob = NonlinearProblem(nlf, copy(u), rhs)
175+
jac = (u_next, rhs) -> d_propagator_q(u_next, t + h, h)
176+
nlf_wrapped = NonlinearFunction(nlf; jac)
177+
nlprob = NonlinearProblem(nlf_wrapped, copy(u), rhs)
178178
sol = solve(nlprob)
179179
return u .= sol.u
180180
end

examples/integration.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,13 @@ function build_jet(f, ::Val{iip}, p, order::Val{P}, length = nothing) where {P,
122122
return jet
123123
end
124124

125-
function build_propagator(f::ODEFunction{iip}, p, coeffs::NTuple{P, Float64}, length = nothing) where {P, iip}
125+
function build_propagator(f::ODEFunction{iip}, p, coeffs::NTuple{P1, Float64}, length = nothing) where {P1, iip}
126126
f = unwrapped_f(f)
127127
return build_propagator(f, Val{iip}(), p, coeffs, length)
128128
end
129129

130-
function build_propagator(f, ::Val{iip}, p, coeffs::NTuple{P, Float64}, length = nothing) where {P, iip}
130+
function build_propagator(f, ::Val{iip}, p, coeffs::NTuple{P1, Float64}, length = nothing) where {P1, iip}
131+
P = P1 - 1
131132
@variables t0::Real dt::Real
132133
u0 = isnothing(length) ? Symbolics.variable(:u0) : Symbolics.variables(:u0, 1:length)
133134
if iip
@@ -148,7 +149,7 @@ function build_propagator(f, ::Val{iip}, p, coeffs::NTuple{P, Float64}, length =
148149
d = get_coefficient(fu, index - 1) / index
149150
u = append_coefficient(u, d)
150151
end
151-
ut = eval_taylor_polynomial(u, (1., coeffs...), dt)
152+
ut = eval_taylor_polynomial(u, coeffs, dt)
152153
propagator = build_function(ut, u0, t0, dt; expression = Val(false), cse = true)
153154
jacobian = Symbolics.jacobian(ut, u0)
154155
d_propagator = build_function(jacobian, u0, t0, dt; expression = Val(false), cse = true)

0 commit comments

Comments
 (0)