Skip to content

Commit b7f5762

Browse files
committed
MIRKN work fine
1 parent a041b90 commit b7f5762

7 files changed

Lines changed: 49 additions & 53 deletions

File tree

lib/BoundaryValueDiffEqCore/src/utils.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,12 @@ end
471471
return prob
472472
end
473473

474+
@inline function __internal_optimization_problem(::SecondOrderBVProblem{uType, tType, iip},
475+
args...; kwargs...) where {uType, tType, iip}
476+
prob = OptimizationProblem(args...; kwargs...)
477+
return prob
478+
end
479+
474480
# Handling Initial Guesses
475481
"""
476482
__extract_u0(u₀, t₀)
@@ -630,15 +636,15 @@ Constructs the internal problem based on the type of the boundary value problem
630636
algorithm used. It returns either a `NonlinearProblem` or an `OptimizationProblem`.
631637
"""
632638
function __construct_internal_problem(
633-
prob::BVProblem, alg, loss, jac, jac_prototype, resid_prototype, y, p, M, N)
639+
prob::AbstractBVProblem, alg, loss, jac, jac_prototype, resid_prototype, y, p, M, N)
634640
T = eltype(y)
635641
iip = SciMLBase.isinplace(prob)
636642
if !isnothing(alg.nlsolve) || (isnothing(alg.nlsolve) && isnothing(alg.optimize))
637643
nlf = NonlinearFunction{iip}(loss; jac = jac, resid_prototype = resid_prototype,
638644
jac_prototype = jac_prototype)
639645
return __internal_nlsolve_problem(prob, resid_prototype, y, nlf, y, p)
640646
else
641-
optf = OptimizationFunction{true}(__default_cost(prob.f), AutoFiniteDiff(), # Need to investigate the ForwardDiff dual problem
647+
optf = OptimizationFunction{true}((x, p) -> 0.0, AutoFiniteDiff(), # Need to investigate the ForwardDiff dual problem
642648
cons = loss,
643649
cons_j = jac, cons_jac_prototype = jac_prototype)
644650
lcons = zeros(T, N*M)
@@ -658,7 +664,7 @@ function __construct_internal_problem(
658664
return __internal_nlsolve_problem(prob, resid_prototype, y, nlf, y, p)
659665
else
660666
optf = OptimizationFunction{true}(
661-
__default_cost(prob.f), get_dense_ad(diffmode), cons = loss,
667+
(x, p) -> 0.0, get_dense_ad(diffmode), cons = loss,
662668
cons_j = jac, cons_jac_prototype = jac_prototype)
663669
lcons = zeros(T, N*M)
664670
ucons = zeros(T, N*M)

lib/BoundaryValueDiffEqFIRK/test/expanded/firk_basic_tests.jl

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -307,30 +307,6 @@ end
307307
testTol = 1e-6
308308
nested = false
309309

310-
for stage in (2, 3, 5, 7)
311-
s = Symbol("RadauIIa$(stage)")
312-
@eval radau_solver(::Val{$stage}) = $(s)(
313-
NewtonRaphson(), BVPJacobianAlgorithm(); nested)
314-
end
315-
316-
for stage in (3, 4, 5)
317-
s = Symbol("LobattoIIIa$(stage)")
318-
@eval lobattoIIIa_solver(::Val{$stage}) = $(s)(
319-
NewtonRaphson(), BVPJacobianAlgorithm(); nested)
320-
end
321-
322-
for stage in (3, 4, 5)
323-
s = Symbol("LobattoIIIb$(stage)")
324-
@eval lobattoIIIb_solver(::Val{$stage}) = $(s)(
325-
NewtonRaphson(), BVPJacobianAlgorithm(); nested)
326-
end
327-
328-
for stage in (3, 4, 5)
329-
s = Symbol("LobattoIIIc$(stage)")
330-
@eval lobattoIIIc_solver(::Val{$stage}) = $(s)(
331-
NewtonRaphson(), BVPJacobianAlgorithm(); nested)
332-
end
333-
334310
@testset "Radau interpolations" begin
335311
@testset "Interpolation tests for RadauIIa$stage" for stage in (2, 3, 5, 7)
336312
@time sol = solve(prob_bvp_linear, radau_solver(Val(stage)); dt = 0.001)
@@ -356,10 +332,11 @@ end
356332
for (id, lobatto_solver) in zip(("a", "b", "c"),
357333
(lobattoIIIa_solver, lobattoIIIb_solver, lobattoIIIc_solver))
358334
begin
359-
@testset "Interpolation tests for LobattoIII$(id)$stage" for stage in
360-
(3, 4, 5)
361-
@time sol = solve(
362-
prob_bvp_linear, lobatto_solver(Val(stage)); dt = 0.001)
335+
@testset "Interpolation tests for LobattoIII$(id)$stage" for stage in (
336+
2, 3, 4, 5)
337+
adaptive = ifelse(stage == 2, false, true) # LobattoIIIa2 is not adaptive
338+
@time sol = solve(prob_bvp_linear, lobatto_solver(Val(stage));
339+
dt = 0.001, adaptive = adaptive)
363340
@test sol(0.001)[0.998687464, -1.312035941] atol=testTol
364341
@test sol(0.001; idxs = [1, 2])[0.998687464, -1.312035941] atol=testTol
365342
@test sol(0.001; idxs = 1)0.998687464 atol=testTol
@@ -368,9 +345,10 @@ end
368345

369346
@testset "Derivative Interpolation tests for lobatto$(id)$stage" for stage in
370347
(
371-
3, 4, 5)
372-
@time sol = solve(
373-
prob_bvp_linear, lobatto_solver(Val(stage)); dt = 0.001)
348+
2, 3, 4, 5)
349+
adaptive = ifelse(stage == 2, false, true) # LobattoIIIa2 is not adaptive
350+
@time sol = solve(prob_bvp_linear, lobatto_solver(Val(stage));
351+
dt = 0.001, adaptive = adaptive)
374352
sol_analytic = prob_bvp_linear_analytic(nothing, λ, 0.04)
375353
dsol_analytic = prob_bvp_linear_analytic_derivative(
376354
nothing, λ, 0.04)

lib/BoundaryValueDiffEqMIRKN/src/BoundaryValueDiffEqMIRKN.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ using BoundaryValueDiffEqCore: AbstractBoundaryValueDiffEqAlgorithm,
1919
__default_sparse_ad, __default_nonsparse_ad, get_dense_ad,
2020
concrete_jacobian_algorithm, __default_coloring_algorithm,
2121
__default_sparsity_detector, interval, __split_kwargs,
22-
NoErrorControl
22+
NoErrorControl, __construct_internal_problem,
23+
__concrete_kwargs
2324

2425
using ConcreteStructs: @concrete
2526
using DiffEqBase: DiffEqBase

lib/BoundaryValueDiffEqMIRKN/src/algorithms.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ for order in (4, 6)
66

77
@eval begin
88
"""
9-
$($alg)(; nlsolve = NewtonRaphson(), jac_alg = BVPJacobianAlgorithm(),
9+
$($alg)(; nlsolve = NewtonRaphson(), optimize = nothing, jac_alg = BVPJacobianAlgorithm(),
1010
defect_threshold = 0.1, max_num_subintervals = 3000)
1111
1212
$($order)th order Monotonic Implicit Runge Kutta Nyström method.
@@ -16,6 +16,10 @@ for order in (4, 6)
1616
- `nlsolve`: Internal Nonlinear solver. Any solver which conforms to the SciML
1717
`NonlinearProblem` interface can be used. Note that any autodiff argument for
1818
the solver will be ignored and a custom jacobian algorithm will be used.
19+
- `optimize`: Internal Optimization solver. Any solver which conforms to the SciML
20+
`OptimizationProblem` interface can be used. Note that any autodiff argument for
21+
the solver will be ignored and a custom jacobian algorithm will be used. Optimization
22+
solvers should first be loaded to allow this functionality.
1923
- `jac_alg`: Jacobian Algorithm used for the nonlinear solver. Defaults to
2024
`BVPJacobianAlgorithm()`, which automatically decides the best algorithm to
2125
use based on the input types and problem type.
@@ -46,8 +50,9 @@ for order in (4, 6)
4650
}
4751
```
4852
"""
49-
@kwdef struct $(alg){N, J <: BVPJacobianAlgorithm, T} <: AbstractMIRKN
53+
@kwdef struct $(alg){N, O, J <: BVPJacobianAlgorithm, T} <: AbstractMIRKN
5054
nlsolve::N = nothing
55+
optimize::O = nothing
5156
jac_alg::J = BVPJacobianAlgorithm()
5257
defect_threshold::T = 0.1
5358
max_num_subintervals::Int = 3000

lib/BoundaryValueDiffEqMIRKN/src/mirkn.jl

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@
2121
fᵢ₂_cache
2222
resid_size
2323
nlsolve_kwargs
24+
optimize_kwargs
2425
kwargs
2526
end
2627

2728
Base.eltype(::MIRKNCache{iip, T}) where {iip, T} = T
2829

29-
function SciMLBase.__init(prob::SecondOrderBVProblem, alg::AbstractMIRKN; dt = 0.0,
30-
adaptive = false, abstol = 1e-6, controller = NoErrorControl(),
31-
nlsolve_kwargs = (; abstol = abstol), kwargs...)
30+
function SciMLBase.__init(prob::SecondOrderBVProblem, alg::AbstractMIRKN;
31+
dt = 0.0, adaptive = false, abstol = 1e-6,
32+
controller = NoErrorControl(), nlsolve_kwargs = (; abstol = abstol),
33+
optimize_kwargs = (; abstol = abstol), kwargs...)
3234
@set! alg.jac_alg = concrete_jacobian_algorithm(alg.jac_alg, prob, alg)
3335
iip = isinplace(prob)
36+
@assert (iip || isnothing(alg.optimize)) "Out-of-place constraints don't allow optimization solvers "
3437
t₀, t₁ = prob.tspan
3538
ig, T, M, Nig, X = __extract_problem_details(prob; dt, check_positive_dt = true)
3639
mesh = __extract_mesh(prob.u0, t₀, t₁, Nig)
@@ -93,9 +96,10 @@ function SciMLBase.__init(prob::SecondOrderBVProblem, alg::AbstractMIRKN; dt = 0
9396
prob_ = !(prob.u0 isa AbstractArray) ? remake(prob; u0 = X) : prob
9497

9598
return MIRKNCache{iip, T}(
96-
alg_order(alg), stage, M, size(X), f, bc, prob_, prob.problem_type, prob.p, alg, TU,
97-
bcresid_prototype, mesh, mesh_dt, k_discrete, y, y₀, residual, fᵢ_cache, fᵢ₂_cache,
98-
resid_size, nlsolve_kwargs, (; abstol, dt, adaptive, controller, kwargs...))
99+
alg_order(alg), stage, M, size(X), f, bc, prob_, prob.problem_type,
100+
prob.p, alg, TU, bcresid_prototype, mesh, mesh_dt, k_discrete,
101+
y, y₀, residual, fᵢ_cache, fᵢ₂_cache, resid_size, nlsolve_kwargs,
102+
optimize_kwargs, (; abstol, dt, adaptive, controller, kwargs...))
99103
end
100104

101105
function SciMLBase.solve!(cache::MIRKNCache{iip, T}) where {iip, T}
@@ -112,9 +116,11 @@ function SciMLBase.solve!(cache::MIRKNCache{iip, T}) where {iip, T}
112116
end
113117

114118
function __perform_mirkn_iteration(cache::MIRKNCache)
115-
nlprob::NonlinearProblem = __construct_nlproblem(cache, vec(cache.y₀), copy(cache.y₀))
116-
nlsolve_alg = __concrete_solve_algorithm(nlprob, cache.alg.nlsolve)
117-
sol_nlprob = __solve(nlprob, nlsolve_alg; cache.nlsolve_kwargs..., alias_u0 = true)
119+
nlprob = __construct_nlproblem(cache, vec(cache.y₀), copy(cache.y₀))
120+
solve_alg = __concrete_solve_algorithm(nlprob, cache.alg.nlsolve, cache.alg.optimize)
121+
kwargs = __concrete_kwargs(
122+
cache.alg.nlsolve, cache.alg.optimize, cache.nlsolve_kwargs, cache.optimize_kwargs)
123+
sol_nlprob = solve(nlprob, solve_alg, kwargs...)
118124
recursive_unflatten!(cache.y₀, sol_nlprob.u)
119125

120126
return sol_nlprob, sol_nlprob.retcode
@@ -227,9 +233,8 @@ function __construct_nlproblem(cache::MIRKNCache{iip}, y, loss_bc::BC, loss_coll
227233
cache_collocation, loss_bc, loss_collocation, L, cache.p)
228234
end
229235
resid_prototype = vcat(resid_bc, resid_collocation)
230-
nlf = NonlinearFunction{iip}(
231-
loss; jac = jac, resid_prototype = resid_prototype, jac_prototype = jac_prototype)
232-
__internal_nlsolve_problem(cache.prob, resid_prototype, y, nlf, y, cache.p)
236+
return __construct_internal_problem(cache.prob, cache.alg, loss, jac, jac_prototype,
237+
resid_prototype, y, cache.p, cache.M, 2 * N)
233238
end
234239

235240
function __construct_nlproblem(cache::MIRKNCache{iip}, y, loss_bc::BC, loss_collocation::C,
@@ -270,9 +275,8 @@ function __construct_nlproblem(cache::MIRKNCache{iip}, y, loss_bc::BC, loss_coll
270275
end
271276

272277
resid_prototype = copy(resid)
273-
nlf = NonlinearFunction{iip}(
274-
loss; jac = jac, resid_prototype = resid_prototype, jac_prototype = jac_prototype)
275-
return __internal_nlsolve_problem(cache.prob, resid_prototype, y, nlf, y, cache.p)
278+
return __construct_internal_problem(cache.prob, cache.alg, loss, jac, jac_prototype,
279+
resid_prototype, y, cache.p, cache.M, 2 * N)
276280
end
277281

278282
function __mirkn_2point_jacobian!(J, x, diffmode, diffcache, loss_fn::L, resid, p) where {L}

lib/BoundaryValueDiffEqShooting/src/multiple_shooting.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ function SciMLBase.__solve(prob::BVProblem, _alg::MultipleShooting; odesolve_kwa
77
throw(ArgumentError("Currently MultipleShooting only supports `EnsembleSerial` and \
88
`EnsembleThreads`!"))
99
end
10+
@assert (iip || isnothing(_alg.optimize)) "Out-of-place constraints don't allow optimization solvers "
1011

1112
ig, T, N, Nig, u0 = __extract_problem_details(prob; dt = 0.1)
1213
has_initial_guess = _unwrap_val(ig)
@@ -221,7 +222,7 @@ function __solve_nlproblem!(::StandardBVProblem, alg::MultipleShooting, bcresid_
221222
nlprob = __construct_internal_problem(prob, alg, loss_fn, jac_fn, jac_prototype,
222223
resid_prototype, u_at_nodes, prob.p, M, length(nodes))
223224
nlsolve_alg = __concrete_solve_algorithm(nlprob, alg.nlsolve, alg.optimize)
224-
kwargs = __concrete_kwargs(alg.nlsolve, alg.optimize, kwargs...)
225+
kwargs = __concrete_kwargs(alg.nlsolve, alg.optimize, nlsolve_kwargs, optimize_kwargs)
225226
solve(nlprob, nlsolve_alg; kwargs...)
226227

227228
return nothing

lib/BoundaryValueDiffEqShooting/src/single_shooting.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ function SciMLBase.__solve(prob::BVProblem, alg_::Shooting; odesolve_kwargs = (;
77
verbose && @warn "Initial guess provided, but will be ignored for Shooting."
88
u0 = __extract_u0(prob.u0, prob.p, first(prob.tspan))
99
end
10+
@assert (iip || isnothing(alg_.optimize)) "Out-of-place constraints don't allow optimization solvers "
1011

1112
alg = concretize_jacobian_algorithm(alg_, prob)
1213
(; diffmode) = alg.jac_alg

0 commit comments

Comments
 (0)