Skip to content

Commit efaef08

Browse files
committed
Fix eval_sol in MIRK for multi-point BVPs
1 parent cd89ddb commit efaef08

5 files changed

Lines changed: 516 additions & 426 deletions

File tree

lib/BoundaryValueDiffEqMIRK/src/BoundaryValueDiffEqMIRK.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const DI = DifferentiationInterface
5151

5252
include("types.jl")
5353
include("algorithms.jl")
54+
include("solution_utils.jl")
5455
include("mirk.jl")
5556
include("adaptivity.jl")
5657
include("alg_utils.jl")

lib/BoundaryValueDiffEqMIRK/src/interpolation.jl

Lines changed: 1 addition & 340 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ end
7070
end
7171

7272
@inline function interpolant!(
73-
z::AbstractArray, id, cache::MIRKCache, t, mesh, mesh_dt, T::Type{Val{0}}
73+
z::AbstractArray, id::MIRKInterpolation, cache::MIRKCache, t, mesh, mesh_dt, T::Type{Val{0}}
7474
)
7575
i = interval(mesh, t)
7676
dt = mesh_dt[i]
@@ -199,342 +199,3 @@ end
199199
end
200200

201201
@inline __build_interpolation(cache::MIRKCache, u::AbstractVector) = MIRKInterpolation(cache.mesh, u, cache)
202-
203-
# Intermediate solution for evaluating boundary conditions
204-
# basically simplified version of the interpolation for MIRK
205-
function (s::EvalSol{C})(tval::Number) where {C <: MIRKCache}
206-
(; t, u, cache) = s
207-
(; alg, stage, k_discrete, M) = cache
208-
# Quick handle for the case where tval is at the boundary
209-
(tval == t[1]) && return first(u)
210-
(tval == t[end]) && return last(u)
211-
z = zero(last(u))
212-
has_control = !isnothing(cache.prob.f.f_prototype)
213-
length_z = has_control ? length(cache.prob.f.f_prototype) : length(z)
214-
ii = interval(t, tval)
215-
dt = cache.mesh_dt[ii]
216-
τ = (tval - t[ii]) / dt
217-
w, _ = evalsol_interp_weights(τ, alg)
218-
K = __needs_diffcache(alg.jac_alg) ? @view(k_discrete[ii].du[:, 1:stage]) :
219-
@view(k_discrete[ii][:, 1:stage])
220-
__maybe_matmul!(z[1:length_z], K, @view(w[1:stage]))
221-
222-
# control variable just use linear interpolation
223-
if has_control
224-
inc = τ / dt .* (u[ii + 1] .- u[ii])
225-
copyto!(z, (length_z + 1):M, inc, (length_z + 1):M)
226-
end
227-
228-
z .= z .* dt .+ u[ii]
229-
230-
return z
231-
end
232-
233-
# Interpolate intermediate solution at multiple points
234-
function (s::EvalSol{C})(tvals::AbstractArray{<:Number}) where {C <: MIRKCache}
235-
(; t, u, cache) = s
236-
(; alg, stage, k_discrete, mesh_dt, M) = cache
237-
# Quick handle for the case where tval is at the boundary
238-
zvals = [zero(last(u)) for _ in tvals]
239-
has_control = !isnothing(cache.prob.f.f_prototype)
240-
length_z = has_control ? length(cache.prob.f.f_prototype) : length(first(zvals))
241-
for (i, tval) in enumerate(tvals)
242-
(tval == t[1]) && return first(u)
243-
(tval == t[end]) && return last(u)
244-
ii = interval(t, tval)
245-
dt = mesh_dt[ii]
246-
τ = (tval - t[ii]) / dt
247-
w, _ = evalsol_interp_weights(τ, alg)
248-
K = __needs_diffcache(alg.jac_alg) ? @view(k_discrete[ii].du[:, 1:stage]) :
249-
@view(k_discrete[ii][:, 1:stage])
250-
__maybe_matmul!(zvals[i][1:length_z], K, @view(w[1:stage]))
251-
252-
# control variable just use linear interpolation
253-
if has_control
254-
inc = τ / dt .* (u[ii + 1] .- u[ii])
255-
copyto!(zvals[i], (length_z + 1):M, inc, (length_z + 1):M)
256-
end
257-
zvals[i] .= zvals[i] .* dt .+ u[ii]
258-
end
259-
return zvals
260-
end
261-
262-
# Intermediate derivative solution for evaluating boundary conditions
263-
function (s::EvalSol{C})(tval::Number, ::Type{Val{1}}) where {C <: MIRKCache}
264-
(; t, u, cache) = s
265-
(; alg, stage, k_discrete, mesh_dt) = cache
266-
z′ = zeros(typeof(tval), 2)
267-
ii = interval(t, tval)
268-
dt = mesh_dt[ii]
269-
τ = (tval - t[ii]) / dt
270-
_, w′ = interp_weights(τ, alg)
271-
__maybe_matmul!(z′, @view(k_discrete[ii].du[:, 1:stage]), @view(w′[1:stage]))
272-
return z′
273-
end
274-
275-
"""
276-
Construct n root-finding problems and solve them to find the critical points with continuous derivative polynomials
277-
"""
278-
function __construct_then_solve_root_problem(sol::EvalSol{C}, tspan::Tuple) where {
279-
C <:
280-
MIRKCache,
281-
}
282-
(; alg) = sol.cache
283-
n = first(size(sol))
284-
nlprobs = Vector{SciMLBase.NonlinearProblem}(undef, n)
285-
nlsols = Vector{SciMLBase.NonlinearSolution}(undef, length(nlprobs))
286-
nlsolve_alg = __FastShortcutNonlinearPolyalg(eltype(sol.cache))
287-
for i in 1:n
288-
f = @closure (t, p) -> sol(t, Val{1})[i]
289-
nlprob = NonlinearProblem(f, sol.cache.prob.u0[i], tspan)
290-
nlsols[i] = solve(nlprob, nlsolve_alg)
291-
end
292-
return nlsols
293-
end
294-
295-
# It turns out the critical points can't cover all possible maximum/minimum values
296-
# especially when the solution are monotonic, we still need to compare the extremes with
297-
# value at critical points to find the maximum/minimum
298-
299-
"""
300-
maxsol(sol::EvalSol, tspan::Tuple)
301-
302-
Find the maximum of the solution over the time span `tspan`.
303-
"""
304-
function maxsol(sol::EvalSol{C}, tspan::Tuple) where {C <: MIRKCache}
305-
nlsols = __construct_then_solve_root_problem(sol, tspan)
306-
tvals = map(nlsol -> (SciMLBase.successful_retcode(nlsol); return nlsol.u), nlsols)
307-
u = sol(tvals)
308-
return max(maximum(sol), maximum(Iterators.flatten(u)))
309-
end
310-
311-
"""
312-
minsol(sol::EvalSol, tspan::Tuple)
313-
314-
Find the minimum of the solution over the time span `tspan`.
315-
"""
316-
function minsol(sol::EvalSol{C}, tspan::Tuple) where {C <: MIRKCache}
317-
nlsols = __construct_then_solve_root_problem(sol, tspan)
318-
tvals = map(nlsol -> (SciMLBase.successful_retcode(nlsol); return nlsol.u), nlsols)
319-
u = sol(tvals)
320-
return min(minimum(sol), minimum(Iterators.flatten(u)))
321-
end
322-
323-
@inline function evalsol_interp_weights::T, ::MIRK2) where {T}
324-
w = [0, τ * (1 - τ / 2), τ^2 / 2]
325-
326-
# Derivative polynomials.
327-
328-
wp = [0, 1 - τ, τ]
329-
return T.(w), T.(wp)
330-
end
331-
@inline function evalsol_interp_weights::T, ::MIRK3) where {T}
332-
w = [
333-
τ / 4.0 * (2.0 * τ^2 - 5.0 * τ + 4.0), -3.0 / 4.0 * τ^2 * (2.0 * τ - 3.0), τ^2 *
334-
(
335-
τ -
336-
1.0
337-
),
338-
]
339-
340-
# Derivative polynomials.
341-
342-
wp = [
343-
3.0 / 2.0 *- 2.0 / 3.0) *- 1.0),
344-
-9.0 / 2.0 * τ *- 1.0), 3.0 * τ *- 2.0 / 3.0),
345-
]
346-
return T.(w), T.(wp)
347-
end
348-
@inline function evalsol_interp_weights::T, ::MIRK4) where {T}
349-
t2 = τ * τ
350-
tm1 = τ - 1.0
351-
t4m3 = τ * 4.0 - 3.0
352-
t2m1 = τ * 2.0 - 1.0
353-
354-
w = [
355-
-τ * (2.0 * τ - 3.0) * (2.0 * t2 - 3.0 * τ + 2.0) / 6.0,
356-
t2 * (12.0 * t2 - 20.0 * τ + 9.0) / 6.0,
357-
2.0 * t2 * (6.0 * t2 - 14.0 * τ + 9.0) / 3.0, -16.0 * t2 * tm1 * tm1 / 3.0,
358-
]
359-
360-
# Derivative polynomials
361-
362-
wp = [
363-
-tm1 * t4m3 * t2m1 / 3.0, τ * t2m1 * t4m3,
364-
4.0 * τ * t4m3 * tm1, -32.0 * τ * t2m1 * tm1 / 3.0,
365-
]
366-
return T.(w), T.(wp)
367-
end
368-
@inline function evalsol_interp_weights::T, ::MIRK5) where {T}
369-
w = [
370-
τ * (22464.0 - 83910.0 * τ + 143041.0 * τ^2 - 113808.0 * τ^3 + 33256.0 * τ^4) /
371-
22464.0,
372-
τ^2 * (-2418.0 + 12303.0 * τ - 19512.0 * τ^2 + 10904.0 * τ^3) / 3360.0,
373-
-8 / 81 * τ^2 * (-78.0 + 209.0 * τ - 204.0 * τ^2 + 8.0 * τ^3),
374-
-25 / 1134 * τ^2 * (-390.0 + 1045.0 * τ - 1020.0 * τ^2 + 328.0 * τ^3),
375-
-25 / 5184 * τ^2 * (390.0 + 255.0 * τ - 1680.0 * τ^2 + 2072.0 * τ^3),
376-
279841 / 168480 * τ^2 * (-6.0 + 21.0 * τ - 24.0 * τ^2 + 8.0 * τ^3),
377-
]
378-
379-
# Derivative polynomials
380-
381-
wp = [
382-
1.0 - 13985 // 1872 * τ + 143041 // 7488 * τ^2 - 2371 // 117 * τ^3 +
383-
20785 // 2808 * τ^4,
384-
-403 // 280 * τ + 12303 // 1120 * τ^2 - 813 // 35 * τ^3 + 1363 // 84 * τ^4,
385-
416 // 27 * τ - 1672 // 27 * τ^2 + 2176 // 27 * τ^3 - 320 // 81 * τ^4,
386-
3250 // 189 * τ - 26125 // 378 * τ^2 + 17000 // 189 * τ^3 - 20500 // 567 * τ^4,
387-
-1625 // 432 * τ - 2125 // 576 * τ^2 + 875 // 27 * τ^3 - 32375 // 648 * τ^4,
388-
-279841 // 14040 * τ + 1958887 // 18720 * τ^2 - 279841 // 1755 * τ^3 +
389-
279841 // 4212 * τ^4,
390-
]
391-
return T.(w), T.(wp)
392-
end
393-
@inline function evalsol_interp_weights::T, ::MIRK6) where {T}
394-
w = [
395-
τ - 28607 // 7434 * τ^2 - 166210 // 33453 * τ^3 + 334780 // 11151 * τ^4 -
396-
1911296 // 55755 * τ^5 + 406528 // 33453 * τ^6,
397-
777 // 590 * τ^2 - 2534158 // 234171 * τ^3 + 2088580 // 78057 * τ^4 -
398-
10479104 // 390285 * τ^5 + 11328512 // 1170855 * τ^6,
399-
-1008 // 59 * τ^2 + 222176 // 1593 * τ^3 - 180032 // 531 * τ^4 +
400-
876544 // 2655 * τ^5 - 180224 // 1593 * τ^6,
401-
-1008 // 59 * τ^2 + 222176 // 1593 * τ^3 - 180032 // 531 * τ^4 +
402-
876544 // 2655 * τ^5 - 180224 // 1593 * τ^6,
403-
-378 // 59 * τ^2 + 27772 // 531 * τ^3 - 22504 // 177 * τ^4 + 109568 // 885 * τ^5 -
404-
22528 // 531 * τ^6,
405-
-95232 // 413 * τ^2 + 62384128 // 33453 * τ^3 - 49429504 // 11151 * τ^4 +
406-
46759936 // 11151 * τ^5 - 46661632 // 33453 * τ^6,
407-
896 // 5 * τ^2 - 4352 // 3 * τ^3 + 3456 * τ^4 - 16384 // 5 * τ^5 +
408-
16384 // 15 * τ^6,
409-
50176 // 531 * τ^2 - 179554304 // 234171 * τ^3 + 143363072 // 78057 * τ^4 -
410-
136675328 // 78057 * τ^5 + 137363456 // 234171 * τ^6,
411-
16384 // 441 * τ^3 - 16384 // 147 * τ^4 + 16384 // 147 * τ^5 - 16384 // 441 * τ^6,
412-
]
413-
414-
# Derivative polynomials.
415-
416-
wp = [
417-
1 - 28607 // 3717 * τ - 166210 // 11151 * τ^2 + 1339120 // 11151 * τ^3 -
418-
1911296 // 11151 * τ^4 + 813056 // 11151 * τ^5,
419-
777 // 295 * τ - 2534158 // 78057 * τ^2 + 8354320 // 78057 * τ^3 -
420-
10479104 // 78057 * τ^4 + 22657024 // 390285 * τ^5,
421-
-2016 // 59 * τ + 222176 // 531 * τ^2 - 720128 // 531 * τ^3 + 876544 // 531 * τ^4 -
422-
360448 // 531 * τ^5,
423-
-2016 // 59 * τ + 222176 // 531 * τ^2 - 720128 // 531 * τ^3 + 876544 // 531 * τ^4 -
424-
360448 // 531 * τ^5,
425-
-756 // 59 * τ + 27772 // 177 * τ^2 - 90016 // 177 * τ^3 + 109568 // 177 * τ^4 -
426-
45056 // 177 * τ^5,
427-
-190464 // 413 * τ + 62384128 // 11151 * τ^2 - 197718016 // 11151 * τ^3 +
428-
233799680 // 11151 * τ^4 - 93323264 // 11151 * τ^5,
429-
1792 // 5 * τ - 4352 * τ^2 + 13824 * τ^3 - 16384 * τ^4 + 32768 // 5 * τ^5,
430-
100352 // 531 * τ - 179554304 // 78057 * τ^2 + 573452288 // 78057 * τ^3 -
431-
683376640 // 78057 * τ^4 + 274726912 // 78057 * τ^5,
432-
16384 // 147 * τ^2 - 65536 // 147 * τ^3 + 81920 // 147 * τ^4 - 32768 // 147 * τ^5,
433-
]
434-
return T.(w), T.(wp)
435-
end
436-
437-
@inline function evalsol_interp_weights::T, ::MIRK6I) where {T}
438-
w = [
439-
-(12233 + 1450 * sqrt(7)) *
440-
(
441-
800086000 * τ^5 + 63579600 * sqrt(7) * τ^4 - 2936650584 * τ^4 + 4235152620 * τ^3 -
442-
201404565 * sqrt(7) * τ^3 + 232506630 * sqrt(7) * τ^2 - 3033109390 * τ^2 +
443-
1116511695 * τ - 116253315 * sqrt(7) * τ + 22707000 * sqrt(7) - 191568780
444-
) *
445-
τ / 2112984835740,
446-
-(-10799 + 650 * sqrt(7)) *
447-
(
448-
24962000 * τ^4 + 473200 * sqrt(7) * τ^3 - 67024328 * τ^3 - 751855 * sqrt(7) * τ^2 +
449-
66629600 * τ^2 - 29507250 * τ +
450-
236210 * sqrt(7) * τ +
451-
5080365 +
452-
50895 * sqrt(7)
453-
) *
454-
τ^2 / 29551834260,
455-
7 / 1274940 *
456-
(259 + 50 * sqrt(7)) *
457-
(
458-
14000 * τ^4 - 48216 * τ^3 + 1200 * sqrt(7) * τ^3 - 3555 * sqrt(7) * τ^2 +
459-
62790 * τ^2 +
460-
3610 * sqrt(7) * τ - 37450 * τ + 9135 - 1305 * sqrt(7)
461-
) *
462-
τ^2,
463-
7 / 1274940 *
464-
(259 + 50 * sqrt(7)) *
465-
(
466-
14000 * τ^4 - 48216 * τ^3 + 1200 * sqrt(7) * τ^3 - 3555 * sqrt(7) * τ^2 +
467-
62790 * τ^2 +
468-
3610 * sqrt(7) * τ - 37450 * τ + 9135 - 1305 * sqrt(7)
469-
) *
470-
τ^2,
471-
16 / 2231145 *
472-
(259 + 50 * sqrt(7)) *
473-
(
474-
14000 * τ^4 - 48216 * τ^3 + 1200 * sqrt(7) * τ^3 - 3555 * sqrt(7) * τ^2 +
475-
62790 * τ^2 +
476-
3610 * sqrt(7) * τ - 37450 * τ + 9135 - 1305 * sqrt(7)
477-
) *
478-
τ^2,
479-
4 / 1227278493 *
480-
(740 * sqrt(7) - 6083) *
481-
(1561000 * τ^2 - 2461284 * τ - 109520 * sqrt(7) * τ + 979272 + 86913 * sqrt(7)) *
482-
- 1)^2 *
483-
τ^2,
484-
-49 / 63747 * sqrt(7) * (20000 * τ^2 - 20000 * τ + 3393) *- 1)^2 * τ^2,
485-
-1250000000 / 889206903 * (28 * τ^2 - 28 * τ + 9) *- 1)^2 * τ^2,
486-
]
487-
488-
# Derivative polynomials.
489-
490-
wp = [
491-
(1450 * sqrt(7) + 12233) *
492-
(14 * τ - 7 + sqrt(7)) *
493-
- 1) *
494-
(-400043 * τ + 75481 + 2083 * sqrt(7)) *
495-
(100 * τ - 87) *
496-
(2 * τ - 1) / 493029795006,
497-
-(650 * sqrt(7) - 10799) *
498-
(14 * τ - 7 + sqrt(7)) *
499-
(37443 * τ - 13762 - 2083 * sqrt(7)) *
500-
(100 * τ - 87) *
501-
(2 * τ - 1) *
502-
τ / 20686283982,
503-
7 / 42498 *
504-
(259 + 50 * sqrt(7)) *
505-
(14 * τ - 7 + sqrt(7)) *
506-
- 1) *
507-
(100 * τ - 87) *
508-
(2 * τ - 1) *
509-
τ,
510-
7 / 42498 *
511-
(259 + 50 * sqrt(7)) *
512-
(14 * τ - 7 + sqrt(7)) *
513-
- 1) *
514-
(100 * τ - 87) *
515-
(2 * τ - 1) *
516-
τ,
517-
32 / 148743 *
518-
(259 + 50 * sqrt(7)) *
519-
(14 * τ - 7 + sqrt(7)) *
520-
- 1) *
521-
(100 * τ - 87) *
522-
(2 * τ - 1) *
523-
τ,
524-
4 / 1227278493 *
525-
(740 * sqrt(7) - 6083) *
526-
(14 * τ - 7 + sqrt(7)) *
527-
- 1) *
528-
(100 * τ - 87) *
529-
(6690 * τ - 4085 - 869 * sqrt(7)) *
530-
τ,
531-
-98 / 21249 * sqrt(7) *- 1) * (100 * τ - 13) * (100 * τ - 87) * (2 * τ - 1) * τ,
532-
-1250000000 / 2074816107 *
533-
(14 * τ - 7 + sqrt(7)) *
534-
- 1) *
535-
(14 * τ - 7 - sqrt(7)) *
536-
(2 * τ - 1) *
537-
τ,
538-
]
539-
return T.(w), T.(wp)
540-
end

0 commit comments

Comments
 (0)