diff --git a/Project.toml b/Project.toml index 562953a4e8..b84a1259e3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "OrdinaryDiffEq" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" authors = ["Chris Rackauckas ", "Yingbo Ma "] -version = "6.74.1" +version = "6.80.1" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" @@ -10,6 +10,7 @@ ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56" ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" @@ -34,6 +35,7 @@ RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" +SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7" SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" @@ -49,8 +51,9 @@ ArrayInterface = "7" DataStructures = "0.18" DiffEqBase = "6.147" DocStringExtensions = "0.9" +EnumX = "1" ExponentialUtilities = "1.22" -FastBroadcast = "0.2" +FastBroadcast = "0.2, 0.3" FastClosures = "0.3" FillArrays = "1.9" FiniteDiff = "2" @@ -74,6 +77,7 @@ RecursiveArrayTools = "2.36, 3" Reexport = "1.0" SciMLBase = "2.27.1" SciMLOperators = "0.3" +SciMLStructures = "1" SimpleNonlinearSolve = "1" SimpleUnPack = "1" SparseArrays = "1.9" diff --git a/docs/Project.toml b/docs/Project.toml index 6bb99e1024..cf0665b82a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -3,4 +3,5 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" [compat] -Documenter = "0.27" +Documenter = "0.27, 1" +OrdinaryDiffEq = "6" diff --git a/docs/src/stiff/rosenbrock.md b/docs/src/stiff/rosenbrock.md index a72026da5a..4d45be7d10 100644 --- a/docs/src/stiff/rosenbrock.md +++ b/docs/src/stiff/rosenbrock.md @@ -3,13 +3,6 @@ ## Standard Rosenbrock Methods ```@docs -ROS2 -ROS3 -ROS2PR -ROS3PR -Scholz47 -ROS3PRL -ROS3PRL2 ROS3P Rodas3 Rodas3P @@ -25,7 +18,6 @@ Rodas4P Rodas4P2 Rodas5 Rodas5P -GeneralRosenbrock ``` ## Rosenbrock W-Methods @@ -39,6 +31,13 @@ ROS34PW1b ROS34PW2 ROS34PW3 ROS34PRw +ROS2 +ROS3 ROS2S RosenbrockW6S4OS +ROS2PR +ROS3PR +Scholz4_7 +ROS3PRL +ROS3PRL2 ``` diff --git a/src/OrdinaryDiffEq.jl b/src/OrdinaryDiffEq.jl index a73e17bf6f..cf69de6b69 100644 --- a/src/OrdinaryDiffEq.jl +++ b/src/OrdinaryDiffEq.jl @@ -26,7 +26,9 @@ using LinearSolve, SimpleNonlinearSolve using LineSearches -import FillArrays: Trues +import EnumX + +import FillArrays: Trues, Falses # Interfaces import DiffEqBase: solve!, step!, initialize!, isadaptive @@ -108,6 +110,8 @@ import ADTypes: AbstractADType, import Polyester using MacroTools, Adapt +using SciMLStructures: canonicalize, Tunable, isscimlstructure + const CompiledFloats = Union{Float32, Float64, ForwardDiff.Dual{ ForwardDiff.Tag{T, W}, @@ -124,6 +128,7 @@ import Preferences DEFAULT_PRECS(W, du, u, p, t, newW, Plprev, Prprev, solverdata) = nothing, nothing +include("doc_utils.jl") include("misc_utils.jl") include("algorithms.jl") @@ -139,6 +144,7 @@ include("nlsolve/functional.jl") include("nlsolve/newton.jl") include("generic_rosenbrock.jl") +include("composite_algs.jl") include("caches/basic_caches.jl") include("caches/low_order_rk_caches.jl") @@ -233,7 +239,6 @@ include("constants.jl") include("solve.jl") include("initdt.jl") include("interp_func.jl") -include("composite_algs.jl") import PrecompileTools @@ -252,9 +257,18 @@ PrecompileTools.@compile_workload begin Tsit5(), Vern7() ] - stiff = [Rosenbrock23(), Rosenbrock23(autodiff = false), - Rodas5P(), Rodas5P(autodiff = false), - FBDF(), FBDF(autodiff = false) + stiff = [Rosenbrock23(), + Rodas5P(), + FBDF() + ] + + default_ode = [ + DefaultODEAlgorithm(autodiff = false), + ] + + + default_autodiff_ode = [ + DefaultODEAlgorithm(), ] autoswitch = [ @@ -275,15 +289,24 @@ PrecompileTools.@compile_workload begin solver_list = [] solver_list_nonadaptive = [] - if Preferences.@load_preference("PrecompileNonStiff", true) + + if Preferences.@load_preference("PrecompileDefault", true) + append!(solver_list, default_ode) + end + + if Preferences.@load_preference("PrecompileAutodiffDefault", true) + append!(solver_list, default_autodiff_ode) + end + + if Preferences.@load_preference("PrecompileNonStiff", false) append!(solver_list, nonstiff) end - if Preferences.@load_preference("PrecompileStiff", true) + if Preferences.@load_preference("PrecompileStiff", false) append!(solver_list, stiff) end - if Preferences.@load_preference("PrecompileAutoSwitch", true) + if Preferences.@load_preference("PrecompileAutoSwitch", false) append!(solver_list, autoswitch) end @@ -355,7 +378,7 @@ export FunctionMap, Euler, Heun, Ralston, Midpoint, RK4, ExplicitRK, OwrenZen3, OwrenZen5, BS3, BS5, RK46NL, DP5, Tsit5, DP8, Vern6, Vern7, Vern8, TanYam7, TsitPap8, Vern9, Feagin10, Feagin12, Feagin14, CompositeAlgorithm, Anas5, RKO65, FRK65, PFRK87, - RKM, MSRK5, MSRK6, Stepanov5, SIR54, QPRK98, Tsit5_for_relaxation + RKM, MSRK5, MSRK6, Stepanov5, SIR54, QPRK98, PSRK4p7q6, PSRK3p6q5, PSRK3p5q4, Tsit5_for_relaxation export SSPRK22, SSPRK33, KYKSSPRK42, SSPRK53, SSPRK53_2N1, SSPRK53_2N2, SSPRK53_H, SSPRK63, SSPRK73, SSPRK83, SSPRK43, SSPRK432, @@ -407,7 +430,8 @@ export SplitEuler export Nystrom4, FineRKN4, FineRKN5, Nystrom4VelocityIndependent, Nystrom5VelocityIndependent, - IRKN3, IRKN4, DPRKN4, DPRKN5, DPRKN6, DPRKN6FM, DPRKN8, DPRKN12, ERKN4, ERKN5, ERKN7 + IRKN3, IRKN4, DPRKN4, DPRKN5, DPRKN6, DPRKN6FM, DPRKN8, DPRKN12, ERKN4, ERKN5, ERKN7, + RKN4 export ROCK2, ROCK4, RKC, IRKC, ESERK4, ESERK5, SERK2 @@ -441,7 +465,7 @@ export KuttaPRK2p5, PDIRK44, DImplicitEuler, DABDF2, DFBDF export ShampineCollocationInit, BrownFullBasicInit, NoInit -export NLNewton, NLAnderson, NLFunctional +export NLNewton, NLAnderson, NLFunctional, NonlinearSolveAlg export IController, PIController, PIDController end # module diff --git a/src/alg_utils.jl b/src/alg_utils.jl index d44904bb8f..a53410d410 100644 --- a/src/alg_utils.jl +++ b/src/alg_utils.jl @@ -78,6 +78,10 @@ isfsal(alg::SSPRK932) = false isfsal(alg::SSPRK54) = false isfsal(alg::SSPRK104) = false +isfsal(alg::PSRK3p5q4) = false +isfsal(alg::PSRK3p6q5) = false +isfsal(alg::PSRK4p7q6) = false + get_current_isfsal(alg, cache) = isfsal(alg) # evaluates f(t[i]) @@ -168,6 +172,7 @@ isimplicit(alg::CompositeAlgorithm) = any(isimplicit.(alg.algs)) isdtchangeable(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = true isdtchangeable(alg::CompositeAlgorithm) = all(isdtchangeable.(alg.algs)) + function isdtchangeable(alg::Union{LawsonEuler, NorsettEuler, LieEuler, MagnusGauss4, CayleyEuler, ETDRK2, ETDRK3, ETDRK4, HochOst4, ETD2}) false @@ -201,31 +206,35 @@ qmax_default(alg::CompositeAlgorithm) = minimum(qmax_default.(alg.algs)) qmax_default(alg::DP8) = 6 qmax_default(alg::Union{RadauIIA3, RadauIIA5}) = 8 +function has_chunksize(alg::OrdinaryDiffEqAlgorithm) + return alg isa Union{OrdinaryDiffEqExponentialAlgorithm, + OrdinaryDiffEqAdaptiveExponentialAlgorithm, + OrdinaryDiffEqImplicitAlgorithm, + OrdinaryDiffEqAdaptiveImplicitAlgorithm, + DAEAlgorithm, + CompositeAlgorithm} +end function get_chunksize(alg::OrdinaryDiffEqAlgorithm) error("This algorithm does not have a chunk size defined.") end -get_chunksize(alg::OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD}) where {CS, AD} = Val(CS) -get_chunksize(alg::OrdinaryDiffEqImplicitAlgorithm{CS, AD}) where {CS, AD} = Val(CS) -get_chunksize(alg::DAEAlgorithm{CS, AD}) where {CS, AD} = Val(CS) -function get_chunksize(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS, AD}, - OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS, AD}}) where { - CS, - AD -} +function get_chunksize(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS}, + OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS}, + OrdinaryDiffEqImplicitAlgorithm{CS}, + OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS}, + DAEAlgorithm{CS}, + CompositeAlgorithm{CS}}) where {CS} Val(CS) end function get_chunksize_int(alg::OrdinaryDiffEqAlgorithm) error("This algorithm does not have a chunk size defined.") end -get_chunksize_int(alg::OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD}) where {CS, AD} = CS -get_chunksize_int(alg::OrdinaryDiffEqImplicitAlgorithm{CS, AD}) where {CS, AD} = CS -get_chunksize_int(alg::DAEAlgorithm{CS, AD}) where {CS, AD} = CS -function get_chunksize_int(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS, AD}, - OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS, AD}}) where { - CS, - AD -} +function get_chunksize_int(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS}, + OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS}, + OrdinaryDiffEqImplicitAlgorithm{CS}, + OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS}, + DAEAlgorithm{CS}, + CompositeAlgorithm{CS}}) where {CS} CS end # get_chunksize(alg::CompositeAlgorithm) = get_chunksize(alg.algs[alg.current_alg]) @@ -494,6 +503,7 @@ alg_order(alg::DPRKN12) = 12 alg_order(alg::ERKN4) = 4 alg_order(alg::ERKN5) = 5 alg_order(alg::ERKN7) = 7 +alg_order(alg::RKN4) = 4 alg_order(alg::Midpoint) = 2 @@ -567,6 +577,9 @@ alg_order(alg::MSRK5) = 5 alg_order(alg::MSRK6) = 6 alg_order(alg::Stepanov5) = 5 alg_order(alg::SIR54) = 5 +alg_order(alg::PSRK4p7q6) = 4 +alg_order(alg::PSRK3p6q5) = 3 +alg_order(alg::PSRK3p5q4) = 3 alg_order(alg::BS3) = 3 alg_order(alg::BS5) = 5 @@ -958,10 +971,12 @@ alg_can_repeat_jac(alg::OrdinaryDiffEqNewtonAdaptiveAlgorithm) = true alg_can_repeat_jac(alg::IRKC) = false function unwrap_alg(alg::SciMLBase.DEAlgorithm, is_stiff) - iscomp = alg isa CompositeAlgorithm - if !iscomp + if !(alg isa CompositeAlgorithm) return alg elseif alg.choice_function isa AutoSwitchCache + if length(alg.algs) > 2 + return alg.algs[alg.choice_function.current] + end if is_stiff === nothing throwautoswitch(alg) end @@ -978,18 +993,21 @@ end function unwrap_alg(integrator, is_stiff) alg = integrator.alg - iscomp = alg isa CompositeAlgorithm - if !iscomp + if !(alg isa CompositeAlgorithm) return alg elseif alg.choice_function isa AutoSwitchCache - if is_stiff === nothing - throwautoswitch(alg) - end - num = is_stiff ? 2 : 1 - if num == 1 - return alg.algs[1] + if length(alg.algs) > 2 + alg.algs[alg.choice_function.current] else - return alg.algs[2] + if is_stiff === nothing + throwautoswitch(alg) + end + num = is_stiff ? 2 : 1 + if num == 1 + return alg.algs[1] + else + return alg.algs[2] + end end else return _eval_index(identity, alg.algs, integrator.cache.current) @@ -1064,3 +1082,8 @@ is_mass_matrix_alg(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = false is_mass_matrix_alg(alg::CompositeAlgorithm) = all(is_mass_matrix_alg, alg.algs) is_mass_matrix_alg(alg::RosenbrockAlgorithm) = true is_mass_matrix_alg(alg::NewtonAlgorithm) = !isesdirk(alg) +# hack for the default alg +function is_mass_matrix_alg(alg::CompositeAlgorithm{ + <:Any, <:Tuple{Tsit5, Vern7, Rosenbrock23, Rodas5P, FBDF, FBDF}}) + true +end diff --git a/src/algorithms.jl b/src/algorithms.jl index b8ff73dee7..68c6b77a49 100644 --- a/src/algorithms.jl +++ b/src/algorithms.jl @@ -1211,6 +1211,28 @@ pages={113753} """ struct ERKN7 <: OrdinaryDiffEqAdaptivePartitionedAlgorithm end +""" +3 stage fourth order Runge-Kutta Nystrom method to solve second order linear inhomogenous IVPs. + +Does not include an adaptive method. Solves for for d-dimensional differential systems of second order linear inhomogeneous equations. + +!!! warn + + This method is only fourth order for these systems, the method is second order otherwise! + +## References + +@article{MONTIJANO2024115533, +title = {Explicit Runge–Kutta–Nyström methods for the numerical solution of second order linear inhomogeneous IVPs}, +author = {J.I. Montijano and L. Rández and M. Calvo}, +journal = {Journal of Computational and Applied Mathematics}, +volume = {438}, +pages = {115533}, +year = {2024}, +} +""" +struct RKN4 <: OrdinaryDiffEqAlgorithm end + ################################################################################ # Adams Bashforth and Adams moulton methods @@ -1403,7 +1425,7 @@ Optional parameter kappa defaults to Shampine's accuracy-optimal -0.1850. See also `QNDF`. """ -struct QNDF1{CS, AD, F, F2, P, FDT, ST, CJ, κType} <: +struct QNDF1{CS, AD, F, F2, P, FDT, ST, CJ, κType, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -1411,22 +1433,24 @@ struct QNDF1{CS, AD, F, F2, P, FDT, ST, CJ, κType} <: extrapolant::Symbol kappa::κType controller::Symbol + step_limiter!::StepLimiter end function QNDF1(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, kappa = -0.1850, - controller = :Standard) + controller = :Standard, step_limiter! = trivial_limiter!) QNDF1{ _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(kappa)}(linsolve, + typeof(kappa), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, kappa, - controller) + controller, + step_limiter!) end """ @@ -1442,7 +1466,7 @@ An adaptive order 2 quasi-constant timestep L-stable numerical differentiation f See also `QNDF`. """ -struct QNDF2{CS, AD, F, F2, P, FDT, ST, CJ, κType} <: +struct QNDF2{CS, AD, F, F2, P, FDT, ST, CJ, κType, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -1450,22 +1474,24 @@ struct QNDF2{CS, AD, F, F2, P, FDT, ST, CJ, κType} <: extrapolant::Symbol kappa::κType controller::Symbol + step_limiter!::StepLimiter end function QNDF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, kappa = -1 // 9, - controller = :Standard) + controller = :Standard, step_limiter! = trivial_limiter!) QNDF2{ _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(kappa)}(linsolve, + typeof(kappa), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, kappa, - controller) + controller, + step_limiter!) end """ @@ -1491,7 +1517,7 @@ year={1997}, publisher={SIAM} } """ -struct QNDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T, κType} <: +struct QNDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T, κType, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} max_order::Val{MO} linsolve::F @@ -1502,6 +1528,7 @@ struct QNDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T, κType} <: extrapolant::Symbol kappa::κType controller::Symbol + step_limiter!::StepLimiter end function QNDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), @@ -1510,12 +1537,13 @@ function QNDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, kappa = promote(-0.1850, -1 // 9, -0.0823, -0.0415, 0), - controller = :Standard) where {MO} + controller = :Standard, step_limiter! = trivial_limiter!) where {MO} QNDF{MO, _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(κ), typeof(tol), typeof(kappa)}(max_order, linsolve, nlsolve, precs, κ, tol, - extrapolant, kappa, controller) + typeof(κ), typeof(tol), typeof(kappa), typeof(step_limiter!)}( + max_order, linsolve, nlsolve, precs, κ, tol, + extrapolant, kappa, controller, step_limiter!) end TruncatedStacktraces.@truncate_stacktrace QNDF @@ -1540,7 +1568,7 @@ year={2002}, publisher={Walter de Gruyter GmbH \\& Co. KG} } """ -struct FBDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T} <: +struct FBDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} max_order::Val{MO} linsolve::F @@ -1550,6 +1578,7 @@ struct FBDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T} <: tol::T extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function FBDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), @@ -1557,12 +1586,13 @@ function FBDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, - extrapolant = :linear, controller = :Standard) where {MO} + extrapolant = :linear, controller = :Standard, step_limiter! = trivial_limiter!) where {MO} FBDF{MO, _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(κ), typeof(tol)}(max_order, linsolve, nlsolve, precs, κ, tol, extrapolant, - controller) + typeof(κ), typeof(tol), typeof(step_limiter!)}( + max_order, linsolve, nlsolve, precs, κ, tol, extrapolant, + controller, step_limiter!) end TruncatedStacktraces.@truncate_stacktrace FBDF @@ -1958,7 +1988,7 @@ publisher={Elsevier} RadauIIA3: Fully-Implicit Runge-Kutta Method An A-B-L stable fully implicit Runge-Kutta method with internal tableau complex basis transform for efficiency. """ -struct RadauIIA3{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2} <: +struct RadauIIA3{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F precs::P @@ -1968,6 +1998,7 @@ struct RadauIIA3{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2} <: fast_convergence_cutoff::C1 new_W_γdt_cutoff::C2 controller::Symbol + step_limiter!::StepLimiter end function RadauIIA3(; chunk_size = Val{0}(), autodiff = Val{true}(), @@ -1976,17 +2007,20 @@ function RadauIIA3(; chunk_size = Val{0}(), autodiff = Val{true}(), linsolve = nothing, precs = DEFAULT_PRECS, extrapolant = :dense, fast_convergence_cutoff = 1 // 5, new_W_γdt_cutoff = 1 // 5, - controller = :Predictive, κ = nothing, maxiters = 10) + controller = :Predictive, κ = nothing, maxiters = 10, + step_limiter! = trivial_limiter!) RadauIIA3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(κ), typeof(fast_convergence_cutoff), typeof(new_W_γdt_cutoff)}(linsolve, + typeof(κ), typeof(fast_convergence_cutoff), + typeof(new_W_γdt_cutoff), typeof(step_limiter!)}(linsolve, precs, extrapolant, κ, maxiters, fast_convergence_cutoff, new_W_γdt_cutoff, - controller) + controller, + step_limiter!) end TruncatedStacktraces.@truncate_stacktrace RadauIIA3 @@ -2006,7 +2040,7 @@ publisher={Elsevier} RadauIIA5: Fully-Implicit Runge-Kutta Method An A-B-L stable fully implicit Runge-Kutta method with internal tableau complex basis transform for efficiency. """ -struct RadauIIA5{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2} <: +struct RadauIIA5{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F precs::P @@ -2017,6 +2051,7 @@ struct RadauIIA5{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2} <: fast_convergence_cutoff::C1 new_W_γdt_cutoff::C2 controller::Symbol + step_limiter!::StepLimiter end function RadauIIA5(; chunk_size = Val{0}(), autodiff = Val{true}(), @@ -2025,10 +2060,12 @@ function RadauIIA5(; chunk_size = Val{0}(), autodiff = Val{true}(), linsolve = nothing, precs = DEFAULT_PRECS, extrapolant = :dense, fast_convergence_cutoff = 1 // 5, new_W_γdt_cutoff = 1 // 5, - controller = :Predictive, κ = nothing, maxiters = 10, smooth_est = true) + controller = :Predictive, κ = nothing, maxiters = 10, smooth_est = true, + step_limiter! = trivial_limiter!) RadauIIA5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(κ), typeof(fast_convergence_cutoff), typeof(new_W_γdt_cutoff)}(linsolve, + typeof(κ), typeof(fast_convergence_cutoff), + typeof(new_W_γdt_cutoff), typeof(step_limiter!)}(linsolve, precs, smooth_est, extrapolant, @@ -2036,7 +2073,8 @@ function RadauIIA5(; chunk_size = Val{0}(), autodiff = Val{true}(), maxiters, fast_convergence_cutoff, new_W_γdt_cutoff, - controller) + controller, + step_limiter!) end TruncatedStacktraces.@truncate_stacktrace RadauIIA5 @@ -2048,13 +2086,14 @@ ImplicitEuler: SDIRK Method A 1st order implicit solver. A-B-L-stable. Adaptive timestepping through a divided differences estimate via memory. Strong-stability preserving (SSP). """ -struct ImplicitEuler{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct ImplicitEuler{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 precs::P extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function ImplicitEuler(; chunk_size = Val{0}(), autodiff = Val{true}(), @@ -2062,36 +2101,38 @@ function ImplicitEuler(; chunk_size = Val{0}(), autodiff = Val{true}(), diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :constant, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) ImplicitEuler{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, - nlsolve, precs, extrapolant, controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, + nlsolve, precs, extrapolant, controller, step_limiter!) end """ ImplicitMidpoint: SDIRK Method A second order A-stable symplectic and symmetric implicit solver. Good for highly stiff equations which need symplectic integration. """ -struct ImplicitMidpoint{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct ImplicitMidpoint{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 precs::P extrapolant::Symbol + step_limiter!::StepLimiter end function ImplicitMidpoint(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), - extrapolant = :linear) + extrapolant = :linear, step_limiter! = trivial_limiter!) ImplicitMidpoint{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + step_limiter!) end """ @@ -2105,13 +2146,14 @@ Also known as Crank-Nicolson when applied to PDEs. Adaptive timestepping via div differences approximation to the second derivative terms in the local truncation error estimate (the SPICE approximation strategy). """ -struct Trapezoid{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct Trapezoid{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 precs::P extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function Trapezoid(; chunk_size = Val{0}(), autodiff = Val{true}(), @@ -2119,14 +2161,15 @@ function Trapezoid(; chunk_size = Val{0}(), autodiff = Val{true}(), diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) Trapezoid{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, + step_limiter!) end """ @@ -2145,7 +2188,7 @@ TRBDF2: SDIRK Method A second order A-B-L-S-stable one-step ESDIRK method. Includes stiffness-robust error estimates for accurate adaptive timestepping, smoothed derivatives for highly stiff and oscillatory problems. """ -struct TRBDF2{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct TRBDF2{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2153,17 +2196,18 @@ struct TRBDF2{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function TRBDF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) TRBDF2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end TruncatedStacktraces.@truncate_stacktrace TRBDF2 @@ -2183,7 +2227,7 @@ publisher={ACM} SDIRK2: SDIRK Method An A-B-L stable 2nd order SDIRK method """ -struct SDIRK2{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct SDIRK2{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2191,26 +2235,30 @@ struct SDIRK2{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function SDIRK2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) SDIRK2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}( + linsolve, nlsolve, precs, smooth_est, extrapolant, + controller, + step_limiter!) end -struct SDIRK22{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct SDIRK22{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 precs::P extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function SDIRK22(; @@ -2218,14 +2266,15 @@ function SDIRK22(; concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) Trapezoid{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, + step_limiter!) end struct SSPSDIRK2{CS, AD, F, F2, P, FDT, ST, CJ} <: @@ -2265,7 +2314,7 @@ publisher={Springer} Kvaerno3: SDIRK Method An A-L stable stiffly-accurate 3rd order ESDIRK method """ -struct Kvaerno3{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct Kvaerno3{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2273,17 +2322,18 @@ struct Kvaerno3{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function Kvaerno3(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) Kvaerno3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end """ @@ -2297,7 +2347,7 @@ publisher={National Aeronautics and Space Administration, Langley Research Cente KenCarp3: SDIRK Method An A-L stable stiffly-accurate 3rd order ESDIRK method with splitting """ -struct KenCarp3{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct KenCarp3{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2305,17 +2355,18 @@ struct KenCarp3{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function KenCarp3(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) KenCarp3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end struct CFNLIRK3{CS, AD, F, F2, P, FDT, ST, CJ} <: @@ -2557,7 +2608,7 @@ publisher={Springer} Kvaerno4: SDIRK Method An A-L stable stiffly-accurate 4th order ESDIRK method. """ -struct Kvaerno4{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct Kvaerno4{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2565,17 +2616,18 @@ struct Kvaerno4{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function Kvaerno4(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) Kvaerno4{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end """ @@ -2593,7 +2645,7 @@ publisher={Springer} Kvaerno5: SDIRK Method An A-L stable stiffly-accurate 5th order ESDIRK method """ -struct Kvaerno5{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct Kvaerno5{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2601,17 +2653,18 @@ struct Kvaerno5{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function Kvaerno5(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) Kvaerno5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end """ @@ -2625,7 +2678,7 @@ publisher={National Aeronautics and Space Administration, Langley Research Cente KenCarp4: SDIRK Method An A-L stable stiffly-accurate 4th order ESDIRK method with splitting """ -struct KenCarp4{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct KenCarp4{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2633,17 +2686,18 @@ struct KenCarp4{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function KenCarp4(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) KenCarp4{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end TruncatedStacktraces.@truncate_stacktrace KenCarp4 @@ -2694,7 +2748,7 @@ publisher={National Aeronautics and Space Administration, Langley Research Cente KenCarp5: SDIRK Method An A-L stable stiffly-accurate 5th order ESDIRK method with splitting """ -struct KenCarp5{CS, AD, F, F2, P, FDT, ST, CJ} <: +struct KenCarp5{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -2702,17 +2756,18 @@ struct KenCarp5{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function KenCarp5(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :PI) + controller = :PI, step_limiter! = trivial_limiter!) KenCarp5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, + smooth_est, extrapolant, controller, step_limiter!) end """ @article{kennedy2019higher, @@ -2914,7 +2969,7 @@ Scientific Computing, 18 (1), pp. 1-22. differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) #### ROS2PR, ROS2S, ROS3PR, Scholz4_7 --Rang, Joachim (2014): The Prothero and Robinson example: +-Rang, Joachim (2014): The Prothero and Robinson example: Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. https://doi.org/10.24355/dbbs.084-201408121139-0 @@ -2959,32 +3014,28 @@ University of Geneva, Switzerland. https://doi.org/10.1016/j.cam.2015.03.010 #### ROS3PRL, ROS3PRL2 --Rang, Joachim (2014): The Prothero and Robinson example: +-Rang, Joachim (2014): The Prothero and Robinson example: Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. https://doi.org/10.24355/dbbs.084-201408121139-0 #### Rodas5P -- Steinebach G. Construction of Rosenbrock–Wanner method Rodas5P and numerical benchmarks within the Julia Differential Equations package. +- Steinebach G. Construction of Rosenbrock–Wanner method Rodas5P and numerical benchmarks within the Julia Differential Equations package. In: BIT Numerical Mathematics, 63(2), 2023 #### Rodas23W, Rodas3P, Rodas5Pe, Rodas5Pr -- Steinebach G. Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications - +- Steinebach G. Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications - Preprint 2024 https://github.com/hbrs-cse/RosenbrockMethods/blob/main/paper/JuliaPaper.pdf =# for Alg in [ - :Rosenbrock23, - :Rosenbrock32, :ROS2, :ROS2PR, :ROS2S, :ROS3, :ROS3PR, :Scholz4_7, - :ROS3P, - :Rodas3, :ROS34PW1a, :ROS34PW1b, :ROS34PW2, @@ -2997,7 +3048,32 @@ for Alg in [ :Velds4, :GRK4T, :GRK4A, - :Ros4LStab, + :Ros4LStab] + @eval begin + struct $Alg{CS, AD, F, P, FDT, ST, CJ} <: + OrdinaryDiffEqRosenbrockAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} + linsolve::F + precs::P + end + function $Alg(; chunk_size = Val{0}(), autodiff = Val{true}(), + standardtag = Val{true}(), concrete_jac = nothing, + diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS) + $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + typeof(precs), diff_type, _unwrap_val(standardtag), + _unwrap_val(concrete_jac)}(linsolve, + precs) + end + end + + @eval TruncatedStacktraces.@truncate_stacktrace $Alg 1 2 +end + +# for Rosenbrock methods with step_limiter +for Alg in [ + :Rosenbrock23, + :Rosenbrock32, + :ROS3P, + :Rodas3, :Rodas23W, :Rodas3P, :Rodas4, @@ -3007,27 +3083,30 @@ for Alg in [ :Rodas5, :Rodas5P, :Rodas5Pe, - :Rodas5Pr -] + :Rodas5Pr] @eval begin - struct $Alg{CS, AD, F, P, FDT, ST, CJ} <: + struct $Alg{CS, AD, F, P, FDT, ST, CJ, StepLimiter, StageLimiter} <: OrdinaryDiffEqRosenbrockAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F precs::P + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end function $Alg(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS) + diff_type = Val{:forward}, linsolve = nothing, + precs = DEFAULT_PRECS, step_limiter! = trivial_limiter!, + stage_limiter! = trivial_limiter!) $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), - _unwrap_val(concrete_jac)}(linsolve, - precs) + _unwrap_val(concrete_jac), typeof(step_limiter!), + typeof(stage_limiter!)}(linsolve, precs, step_limiter!, + stage_limiter!) end end @eval TruncatedStacktraces.@truncate_stacktrace $Alg 1 2 end - struct GeneralRosenbrock{CS, AD, F, ST, CJ, TabType} <: OrdinaryDiffEqRosenbrockAdaptiveAlgorithm{CS, AD, Val{:forward}, ST, CJ} tableau::TabType @@ -3042,10 +3121,15 @@ function GeneralRosenbrock(; chunk_size = Val{0}(), autodiff = true, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(tableau)}(tableau, factorization) end + +@doc rosenbrock_wanner_docstring( """ -RosenbrockW6S4OS: Rosenbrock-W Method A 4th order L-stable Rosenbrock-W method (fixed step only). -""" +""", +"RosenbrockW6S4OS", +references = """ +https://doi.org/10.1016/j.cam.2009.09.017 +""") struct RosenbrockW6S4OS{CS, AD, F, P, FDT, ST, CJ} <: OrdinaryDiffEqRosenbrockAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F @@ -3136,7 +3220,7 @@ an Adaptive BDF2 Formula and Comparison with The MATLAB Ode15s. Procedia Compute ABDF2: Multistep Method An adaptive order 2 L-stable fixed leading coefficient multistep BDF method. """ -struct ABDF2{CS, AD, F, F2, P, FDT, ST, CJ, K, T} <: +struct ABDF2{CS, AD, F, F2, P, FDT, ST, CJ, K, T, StepLimiter} <: OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F nlsolve::F2 @@ -3146,25 +3230,30 @@ struct ABDF2{CS, AD, F, F2, P, FDT, ST, CJ, K, T} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + step_limiter!::StepLimiter end function ABDF2(; chunk_size = Val{0}(), autodiff = true, standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, κ = nothing, tol = nothing, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, - controller = :Standard) + controller = :Standard, step_limiter! = trivial_limiter!) ABDF2{ _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(κ), typeof(tol)}(linsolve, nlsolve, precs, κ, tol, smooth_est, extrapolant, - controller) + typeof(κ), typeof(tol), typeof(step_limiter!)}(linsolve, nlsolve, precs, κ, tol, + smooth_est, extrapolant, controller, step_limiter!) end ######################################### -struct CompositeAlgorithm{T, F} <: OrdinaryDiffEqCompositeAlgorithm +struct CompositeAlgorithm{CS, T, F} <: OrdinaryDiffEqCompositeAlgorithm algs::T choice_function::F + function CompositeAlgorithm(algs::T, choice_function::F) where {T, F} + CS = mapreduce(alg -> has_chunksize(alg) ? get_chunksize_int(alg) : 0, max, algs) + new{CS, T, F}(algs, choice_function) + end end TruncatedStacktraces.@truncate_stacktrace CompositeAlgorithm 1 @@ -3173,6 +3262,61 @@ if isdefined(Base, :Experimental) && isdefined(Base.Experimental, :silence!) Base.Experimental.silence!(CompositeAlgorithm) end +mutable struct AutoSwitchCache{nAlg, sAlg, tolType, T} + count::Int + successive_switches::Int + nonstiffalg::nAlg + stiffalg::sAlg + is_stiffalg::Bool + maxstiffstep::Int + maxnonstiffstep::Int + nonstifftol::tolType + stifftol::tolType + dtfac::T + stiffalgfirst::Bool + switch_max::Int + current::Int + function AutoSwitchCache(count::Int, + successive_switches::Int, + nonstiffalg::nAlg, + stiffalg::sAlg, + is_stiffalg::Bool, + maxstiffstep::Int, + maxnonstiffstep::Int, + nonstifftol::tolType, + stifftol::tolType, + dtfac::T, + stiffalgfirst::Bool, + switch_max::Int, + current::Int = 0) where {nAlg, sAlg, tolType, T} + new{nAlg, sAlg, tolType, T}(count, + successive_switches, + nonstiffalg, + stiffalg, + is_stiffalg, + maxstiffstep, + maxnonstiffstep, + nonstifftol, + stifftol, + dtfac, + stiffalgfirst, + switch_max, + current) + end +end + +struct AutoSwitch{nAlg, sAlg, tolType, T} + nonstiffalg::nAlg + stiffalg::sAlg + maxstiffstep::Int + maxnonstiffstep::Int + nonstifftol::tolType + stifftol::tolType + dtfac::T + stiffalgfirst::Bool + switch_max::Int +end + ################################################################################ """ MEBDF2: Multistep Method diff --git a/src/algorithms/explicit_rk.jl b/src/algorithms/explicit_rk.jl index 4e5c99e45f..c2a5573332 100644 --- a/src/algorithms/explicit_rk.jl +++ b/src/algorithms/explicit_rk.jl @@ -5,37 +5,6 @@ function Base.show(io::IO, alg::OrdinaryDiffEqAlgorithm) end print(io, ")") end -function explicit_rk_docstring(description::String, - name::String; - references::String = "", - extra_keyword_description = "", - extra_keyword_default = "") - if !isempty(extra_keyword_default) - extra_keyword_default = "\n" * repeat(" ", 8) * extra_keyword_default - end - start_docstring = """ - ```julia - $name(; stage_limiter! = OrdinaryDiffEq.trivial_limiter!, - step_limiter! = OrdinaryDiffEq.trivial_limiter!, - thread = OrdinaryDiffEq.False(),$extra_keyword_default) - ``` - - Explicit Runge-Kutta Method. - """ - keyword_docstring = """ - - ### Keyword Arguments - - - `stage_limiter!`: function of the form `limiter!(u, integrator, p, t)` - - `step_limiter!`: function of the form `limiter!(u, integrator, p, t)` - - `thread`: determines whether internal broadcasting on - appropriate CPU arrays should be serial (`thread = OrdinaryDiffEq.False()`, - default) or use multiple threads (`thread = OrdinaryDiffEq.True()`) when - Julia is started with multiple threads. - """ - start_docstring * description * keyword_docstring * extra_keyword_description * - "## References\n" * references -end @doc explicit_rk_docstring( "The second order Heun's method. Uses embedded Euler method for adaptivity.", @@ -113,6 +82,66 @@ function RKM(stage_limiter!, step_limiter! = trivial_limiter!) RKM(stage_limiter!, step_limiter!, False()) end +@doc explicit_rk_docstring("4-stage Pseudo-Symplectic Explicit RK method.", "3p5q(4)", + references = "@article{Aubry1998, + author = {A. Aubry and P. Chartier}, + journal = {BIT Numer. Math.}, + title = {Pseudo-symplectic {R}unge-{K}utta methods}, + year = {1998}, + }, + @article{Capuano2017, + title = {Explicit {R}unge–{K}utta schemes for incompressible flow with improved energy-conservation properties}, + journal = {J. Comput. Phys.}, + year = {2017}, + author = {F. Capuano and G. Coppola and L. Rández and L. {de Luca}},}") +Base.@kwdef struct PSRK3p5q4{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAlgorithm + stage_limiter!::StageLimiter = trivial_limiter! + step_limiter!::StepLimiter = trivial_limiter! + thread::Thread = False() +end + +@doc explicit_rk_docstring("5-stage Pseudo-Symplectic Explicit RK method.", "3p6q(5)", + references = "@article{Aubry1998, + author = {A. Aubry and P. Chartier}, + journal = {BIT Numer. Math.}, + title = {Pseudo-symplectic {R}unge-{K}utta methods}, + year = {1998}, + }, + @article{Capuano2017, + title = {Explicit {R}unge–{K}utta schemes for incompressible flow with improved energy-conservation properties}, + journal = {J. Comput. Phys.}, + year = {2017}, + author = {F. Capuano and G. Coppola and L. Rández and L. {de Luca}},}") +Base.@kwdef struct PSRK3p6q5{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAlgorithm + stage_limiter!::StageLimiter = trivial_limiter! + step_limiter!::StepLimiter = trivial_limiter! + thread::Thread = False() +end + +@doc explicit_rk_docstring("6-stage Pseudo-Symplectic Explicit RK method.", "4p7q(6)", + references = "@article{Aubry1998, + author = {A. Aubry and P. Chartier}, + journal = {BIT Numer. Math.}, + title = {Pseudo-symplectic {R}unge-{K}utta methods}, + volume = {38}, + PAGES = {439-461}, + year = {1998}, + }, + @article{Capuano2017, + title = {Explicit {R}unge–{K}utta schemes for incompressible flow with improved energy-conservation properties}, + journal = {J. Comput. Phys.}, + volume = {328}, + pages = {86-94}, + year = {2017}, + issn = {0021-9991}, + doi = {https://doi.org/10.1016/j.jcp.2016.10.040}, + author = {F. Capuano and G. Coppola and L. Rández and L. {de Luca}},}") +Base.@kwdef struct PSRK4p7q6{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAlgorithm + stage_limiter!::StageLimiter = trivial_limiter! + step_limiter!::StepLimiter = trivial_limiter! + thread::Thread = False() +end + @doc explicit_rk_docstring("5th order Explicit RK method.", "MSRK5", references = "Misha Stepanov - https://arxiv.org/pdf/2202.08443.pdf : Figure 3.") Base.@kwdef struct MSRK5{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAlgorithm @@ -401,7 +430,9 @@ publisher={Neural, Parallel \\& Scientific Computations} Feagin10: Explicit Runge-Kutta Method Feagin's 10th-order Runge-Kutta method. """ -struct Feagin10 <: OrdinaryDiffEqAdaptiveAlgorithm end +Base.@kwdef struct Feagin10{StepLimiter} <: OrdinaryDiffEqAdaptiveAlgorithm + step_limiter!::StepLimiter = trivial_limiter! +end """ @article{feagin2012high, @@ -414,7 +445,9 @@ publisher={Neural, Parallel \\& Scientific Computations} Feagin12: Explicit Runge-Kutta Method Feagin's 12th-order Runge-Kutta method. """ -struct Feagin12 <: OrdinaryDiffEqAdaptiveAlgorithm end +Base.@kwdef struct Feagin12{StepLimiter} <: OrdinaryDiffEqAdaptiveAlgorithm + step_limiter!::StepLimiter = trivial_limiter! +end """ Feagin, T., “An Explicit Runge-Kutta Method of Order Fourteen,” Numerical @@ -423,7 +456,9 @@ Algorithms, 2009 Feagin14: Explicit Runge-Kutta Method Feagin's 14th-order Runge-Kutta method. """ -struct Feagin14 <: OrdinaryDiffEqAdaptiveAlgorithm end +Base.@kwdef struct Feagin14{StepLimiter} <: OrdinaryDiffEqAdaptiveAlgorithm + step_limiter!::StepLimiter = trivial_limiter! +end @doc explicit_rk_docstring("Zero Dissipation Runge-Kutta of 6th order.", "FRK65", extra_keyword_description = """- `omega`: a periodicity phase estimate, diff --git a/src/cache_utils.jl b/src/cache_utils.jl index bb9810562a..0297e8578f 100644 --- a/src/cache_utils.jl +++ b/src/cache_utils.jl @@ -8,6 +8,21 @@ function DiffEqBase.unwrap_cache(integrator::ODEIntegrator, is_stiff) iscomp = alg isa CompositeAlgorithm if !iscomp return cache + elseif cache isa DefaultCache + current = integrator.cache.current + if current == 1 + return cache.cache1 + elseif current == 2 + return cache.cache2 + elseif current == 3 + return cache.cache3 + elseif current == 4 + return cache.cache4 + elseif current == 5 + return cache.cache5 + elseif current == 6 + return cache.cache6 + end elseif alg.choice_function isa AutoSwitch num = is_stiff ? 2 : 1 return cache.caches[num] diff --git a/src/caches/basic_caches.jl b/src/caches/basic_caches.jl index fa492dbe7a..b5dd5edb7a 100644 --- a/src/caches/basic_caches.jl +++ b/src/caches/basic_caches.jl @@ -12,24 +12,27 @@ end TruncatedStacktraces.@truncate_stacktrace CompositeCache 1 -if isdefined(Base, :Experimental) && isdefined(Base.Experimental, :silence!) - Base.Experimental.silence!(CompositeCache) +mutable struct DefaultCache{T1, T2, T3, T4, T5, T6, A, F} <: OrdinaryDiffEqCache + args::A + choice_function::F + current::Int + cache1::T1 + cache2::T2 + cache3::T3 + cache4::T4 + cache5::T5 + cache6::T6 + function DefaultCache{T1, T2, T3, T4, T5, T6, F}( + args, choice_function, current) where {T1, T2, T3, T4, T5, T6, F} + new{T1, T2, T3, T4, T5, T6, typeof(args), F}(args, choice_function, current) + end end -function alg_cache(alg::CompositeAlgorithm{Tuple{T1, T2}, F}, u, rate_prototype, - ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, - ::Type{tTypeNoUnits}, uprev, - uprev2, f, t, dt, reltol, p, calck, - ::Val{V}) where {T1, T2, F, V, uEltypeNoUnits, uBottomEltypeNoUnits, - tTypeNoUnits} - caches = ( - alg_cache(alg.algs[1], u, rate_prototype, uEltypeNoUnits, - uBottomEltypeNoUnits, - tTypeNoUnits, uprev, uprev2, f, t, dt, reltol, p, calck, Val(V)), - alg_cache(alg.algs[2], u, rate_prototype, uEltypeNoUnits, - uBottomEltypeNoUnits, - tTypeNoUnits, uprev, uprev2, f, t, dt, reltol, p, calck, Val(V))) - CompositeCache(caches, alg.choice_function, 1) +TruncatedStacktraces.@truncate_stacktrace DefaultCache 1 + +if isdefined(Base, :Experimental) && isdefined(Base.Experimental, :silence!) + Base.Experimental.silence!(CompositeCache) + Base.Experimental.silence!(DefaultCache) end function alg_cache(alg::CompositeAlgorithm, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -41,6 +44,46 @@ function alg_cache(alg::CompositeAlgorithm, u, rate_prototype, ::Type{uEltypeNoU CompositeCache(caches, alg.choice_function, 1) end +function alg_cache(alg::CompositeAlgorithm{CS, Tuple{A1, A2, A3, A4, A5, A6}}, u, + rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, + uprev, uprev2, f, t, dt, reltol, p, calck, + ::Val{V}) where { + CS, V, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, A1, A2, A3, A4, A5, A6} + args = (u, rate_prototype, uEltypeNoUnits, + uBottomEltypeNoUnits, tTypeNoUnits, uprev, uprev2, f, t, dt, + reltol, p, calck, Val(V)) + argT = map(typeof, args) + T1 = Base.promote_op(alg_cache, A1, argT...) + T2 = Base.promote_op(alg_cache, A2, argT...) + T3 = Base.promote_op(alg_cache, A3, argT...) + T4 = Base.promote_op(alg_cache, A4, argT...) + T5 = Base.promote_op(alg_cache, A5, argT...) + T6 = Base.promote_op(alg_cache, A6, argT...) + cache = DefaultCache{T1, T2, T3, T4, T5, T6, typeof(alg.choice_function)}( + args, alg.choice_function, 1) + algs = alg.algs + # If the type is a bitstype we need to initialize it correctly here since isdefined will always return true. + if isbitstype(T1) + cache.cache1 = alg_cache(algs[1], args...) + end + if isbitstype(T2) + cache.cache2 = alg_cache(algs[2], args...) + end + if isbitstype(T3) + cache.cache3 = alg_cache(algs[3], args...) + end + if isbitstype(T4) + cache.cache4 = alg_cache(algs[4], args...) + end + if isbitstype(T5) + cache.cache5 = alg_cache(algs[5], args...) + end + if isbitstype(T6) + cache.cache6 = alg_cache(algs[6], args...) + end + cache +end + # map + closure approach doesn't infer @generated function __alg_cache(algs::T, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, diff --git a/src/caches/bdf_caches.jl b/src/caches/bdf_caches.jl index 1b356f8cac..78a64c7c7b 100644 --- a/src/caches/bdf_caches.jl +++ b/src/caches/bdf_caches.jl @@ -21,7 +21,7 @@ function alg_cache(alg::ABDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, ABDF2ConstantCache(nlsolver, eulercache, dtₙ₋₁, fsalfirstprev) end -@cache mutable struct ABDF2Cache{uType, rateType, uNoUnitsType, N, dtType} <: +@cache mutable struct ABDF2Cache{uType, rateType, uNoUnitsType, N, dtType, StepLimiter} <: OrdinaryDiffEqMutableCache uₙ::uType uₙ₋₁::uType @@ -33,6 +33,7 @@ end nlsolver::N eulercache::ImplicitEulerCache dtₙ₋₁::dtType + step_limiter!::StepLimiter end function alg_cache(alg::ABDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -51,13 +52,13 @@ function alg_cache(alg::ABDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, [all(iszero, x) for x in eachcol(f.mass_matrix)] eulercache = ImplicitEulerCache( - u, uprev, uprev2, fsalfirst, atmp, nlsolver, algebraic_vars) + u, uprev, uprev2, fsalfirst, atmp, nlsolver, algebraic_vars, alg.step_limiter!) dtₙ₋₁ = one(dt) zₙ₋₁ = zero(u) ABDF2Cache(u, uprev, uprev2, fsalfirst, fsalfirstprev, zₙ₋₁, atmp, - nlsolver, eulercache, dtₙ₋₁) + nlsolver, eulercache, dtₙ₋₁, alg.step_limiter!) end # SBDF @@ -163,7 +164,7 @@ end end @cache mutable struct QNDF1Cache{uType, rateType, coefType, coefType1, coefType2, - uNoUnitsType, N, dtType} <: OrdinaryDiffEqMutableCache + uNoUnitsType, N, dtType, StepLimiter} <: OrdinaryDiffEqMutableCache uprev2::uType fsalfirst::rateType D::coefType1 @@ -174,6 +175,7 @@ end utilde::uType nlsolver::N dtₙ₋₁::dtType + step_limiter!::StepLimiter end function alg_cache(alg::QNDF1, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -224,7 +226,8 @@ function alg_cache(alg::QNDF1, u, rate_prototype, ::Type{uEltypeNoUnits}, uprev2 = zero(u) dtₙ₋₁ = zero(dt) - QNDF1Cache(uprev2, fsalfirst, D, D2, R, U, atmp, utilde, nlsolver, dtₙ₋₁) + QNDF1Cache( + uprev2, fsalfirst, D, D2, R, U, atmp, utilde, nlsolver, dtₙ₋₁, alg.step_limiter!) end # QNDF2 @@ -249,7 +252,7 @@ end end @cache mutable struct QNDF2Cache{uType, rateType, coefType, coefType1, coefType2, - uNoUnitsType, N, dtType} <: OrdinaryDiffEqMutableCache + uNoUnitsType, N, dtType, StepLimiter} <: OrdinaryDiffEqMutableCache uprev2::uType uprev3::uType fsalfirst::rateType @@ -262,6 +265,7 @@ end nlsolver::N dtₙ₋₁::dtType dtₙ₋₂::dtType + step_limiter!::StepLimiter end function alg_cache(alg::QNDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -317,7 +321,8 @@ function alg_cache(alg::QNDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, dtₙ₋₁ = zero(dt) dtₙ₋₂ = zero(dt) - QNDF2Cache(uprev2, uprev3, fsalfirst, D, D2, R, U, atmp, utilde, nlsolver, dtₙ₋₁, dtₙ₋₂) + QNDF2Cache(uprev2, uprev3, fsalfirst, D, D2, R, U, atmp, + utilde, nlsolver, dtₙ₋₁, dtₙ₋₂, alg.step_limiter!) end @cache mutable struct QNDFConstantCache{ @@ -377,7 +382,7 @@ function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, end @cache mutable struct QNDFCache{MO, UType, RUType, rateType, N, coefType, dtType, EEstType, - gammaType, uType, uNoUnitsType} <: + gammaType, uType, uNoUnitsType, StepLimiter} <: OrdinaryDiffEqMutableCache fsalfirst::rateType dd::uType @@ -405,6 +410,7 @@ end atmp::uNoUnitsType atmpm1::uNoUnitsType atmpp1::uNoUnitsType + step_limiter!::StepLimiter end TruncatedStacktraces.@truncate_stacktrace QNDFCache 1 @@ -452,7 +458,7 @@ function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, QNDFCache(fsalfirst, dd, utilde, utildem1, utildep1, ϕ, u₀, nlsolver, U, RU, D, Dtmp, tmp2, prevD, 1, 1, Val(max_order), dtprev, 0, 0, EEst1, EEst2, γₖ, atmp, - atmpm1, atmpp1) + atmpm1, atmpp1, alg.step_limiter!) end @cache mutable struct MEBDF2Cache{uType, rateType, uNoUnitsType, N} <: @@ -567,7 +573,7 @@ end @cache mutable struct FBDFCache{ MO, N, rateType, uNoUnitsType, tsType, tType, uType, uuType, - coeffType, EEstType, rType, wType} <: + coeffType, EEstType, rType, wType, StepLimiter} <: OrdinaryDiffEqMutableCache fsalfirst::rateType nlsolver::N @@ -595,6 +601,7 @@ end weights::wType #weights of Lagrangian formula equi_ts::tsType iters_from_event::Int + step_limiter!::StepLimiter end TruncatedStacktraces.@truncate_stacktrace FBDFCache 1 @@ -647,5 +654,5 @@ function alg_cache(alg::FBDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, FBDFCache(fsalfirst, nlsolver, ts, ts_tmp, t_old, u_history, order, prev_order, u_corrector, u₀, bdf_coeffs, Val(5), nconsteps, consfailcnt, tmp, atmp, terkm2, terkm1, terk, terkp1, terk_tmp, terkp1_tmp, r, weights, equi_ts, - iters_from_event) + iters_from_event, alg.step_limiter!) end diff --git a/src/caches/feagin_caches.jl b/src/caches/feagin_caches.jl index 47defa81a2..ad0b7551d2 100644 --- a/src/caches/feagin_caches.jl +++ b/src/caches/feagin_caches.jl @@ -1,4 +1,4 @@ -@cache struct Feagin10Cache{uType, uNoUnitsType, rateType, TabType} <: +@cache struct Feagin10Cache{uType, uNoUnitsType, rateType, TabType, StepLimiter} <: OrdinaryDiffEqMutableCache u::uType uprev::uType @@ -23,6 +23,7 @@ atmp::uNoUnitsType k::rateType tab::TabType + step_limiter!::StepLimiter end function alg_cache(alg::Feagin10, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -53,7 +54,7 @@ function alg_cache(alg::Feagin10, u, rate_prototype, ::Type{uEltypeNoUnits}, k = zero(rate_prototype) Feagin10Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, - k15, k16, k17, tmp, atmp, k, tab) + k15, k16, k17, tmp, atmp, k, tab, alg.step_limiter!) end function alg_cache(alg::Feagin10, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -63,7 +64,7 @@ function alg_cache(alg::Feagin10, u, rate_prototype, ::Type{uEltypeNoUnits}, Feagin10ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) end -@cache struct Feagin12Cache{uType, uNoUnitsType, rateType, TabType} <: +@cache struct Feagin12Cache{uType, uNoUnitsType, rateType, TabType, StepLimiter} <: OrdinaryDiffEqMutableCache u::uType uprev::uType @@ -96,6 +97,7 @@ end atmp::uNoUnitsType k::rateType tab::TabType + step_limiter!::StepLimiter end function alg_cache(alg::Feagin12, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -134,7 +136,8 @@ function alg_cache(alg::Feagin12, u, rate_prototype, ::Type{uEltypeNoUnits}, k = zero(rate_prototype) Feagin12Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, - k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, tmp, atmp, k, tab) + k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, + k25, tmp, atmp, k, tab, alg.step_limiter!) end function alg_cache(alg::Feagin12, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -144,7 +147,7 @@ function alg_cache(alg::Feagin12, u, rate_prototype, ::Type{uEltypeNoUnits}, Feagin12ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) end -@cache struct Feagin14Cache{uType, uNoUnitsType, rateType, TabType} <: +@cache struct Feagin14Cache{uType, uNoUnitsType, rateType, TabType, StepLimiter} <: OrdinaryDiffEqMutableCache u::uType uprev::uType @@ -187,6 +190,7 @@ end atmp::uNoUnitsType k::rateType tab::TabType + step_limiter!::StepLimiter end function alg_cache(alg::Feagin14, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -237,7 +241,7 @@ function alg_cache(alg::Feagin14, u, rate_prototype, ::Type{uEltypeNoUnits}, Feagin14Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, - k31, k32, k33, k34, k35, tmp, atmp, k, tab) + k31, k32, k33, k34, k35, tmp, atmp, k, tab, alg.step_limiter!) end function alg_cache(alg::Feagin14, u, rate_prototype, ::Type{uEltypeNoUnits}, diff --git a/src/caches/firk_caches.jl b/src/caches/firk_caches.jl index 23a0c5de54..f294ad9798 100644 --- a/src/caches/firk_caches.jl +++ b/src/caches/firk_caches.jl @@ -30,7 +30,7 @@ function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, end mutable struct RadauIIA3Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Type, UF, JC, - F1, Tab, Tol, Dt, rTol, aTol} <: OrdinaryDiffEqMutableCache + F1, Tab, Tol, Dt, rTol, aTol, StepLimiter} <: OrdinaryDiffEqMutableCache u::uType uprev::uType z1::uType @@ -63,6 +63,7 @@ mutable struct RadauIIA3Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Ty dtprev::Dt W_γdt::Dt status::NLStatus + step_limiter!::StepLimiter end function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -119,7 +120,7 @@ function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, J, W1, uf, tab, κ, one(uToltype), 10000, tmp, atmp, jac_config, linsolve, rtol, atol, dt, dt, - Convergence) + Convergence, alg.step_limiter!) end mutable struct RadauIIA5ConstantCache{F, Tab, Tol, Dt, U, JType} <: @@ -154,7 +155,7 @@ function alg_cache(alg::RadauIIA5, u, rate_prototype, ::Type{uEltypeNoUnits}, end mutable struct RadauIIA5Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Type, W2Type, - UF, JC, F1, F2, Tab, Tol, Dt, rTol, aTol} <: + UF, JC, F1, F2, Tab, Tol, Dt, rTol, aTol, StepLimiter} <: OrdinaryDiffEqMutableCache u::uType uprev::uType @@ -197,6 +198,7 @@ mutable struct RadauIIA5Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Ty dtprev::Dt W_γdt::Dt status::NLStatus + step_limiter!::StepLimiter end TruncatedStacktraces.@truncate_stacktrace RadauIIA5Cache 1 @@ -269,5 +271,5 @@ function alg_cache(alg::RadauIIA5, u, rate_prototype, ::Type{uEltypeNoUnits}, J, W1, W2, uf, tab, κ, one(uToltype), 10000, tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol, dt, dt, - Convergence) + Convergence, alg.step_limiter!) end diff --git a/src/caches/kencarp_kvaerno_caches.jl b/src/caches/kencarp_kvaerno_caches.jl index 533b68b3f1..e239a42f10 100644 --- a/src/caches/kencarp_kvaerno_caches.jl +++ b/src/caches/kencarp_kvaerno_caches.jl @@ -1,3 +1,55 @@ +mutable struct Kvaerno3ConstantCache{Tab, N} <: OrdinaryDiffEqConstantCache + nlsolver::N + tab::Tab +end + +function alg_cache(alg::Kvaerno3, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, + uprev, uprev2, f, t, dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + tab = Kvaerno3Tableau(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) + γ, c = tab.γ, 2tab.γ + nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, + uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) + Kvaerno3ConstantCache(nlsolver, tab) +end + +@cache mutable struct Kvaerno3Cache{uType, rateType, uNoUnitsType, Tab, N, StepLimiter} <: + SDIRKMutableCache + u::uType + uprev::uType + fsalfirst::rateType + z₁::uType + z₂::uType + z₃::uType + z₄::uType + atmp::uNoUnitsType + nlsolver::N + tab::Tab + step_limiter!::StepLimiter +end + +function alg_cache(alg::Kvaerno3, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, + ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + tab = Kvaerno3Tableau(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) + γ, c = tab.γ, 2tab.γ + nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, + uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) + fsalfirst = zero(rate_prototype) + + z₁ = zero(u) + z₂ = zero(u) + z₃ = zero(u) + z₄ = nlsolver.z + atmp = similar(u, uEltypeNoUnits) + recursivefill!(atmp, false) + + Kvaerno3Cache( + u, uprev, fsalfirst, z₁, z₂, z₃, z₄, atmp, nlsolver, tab, alg.step_limiter!) +end + @cache mutable struct KenCarp3ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache nlsolver::N tab::Tab @@ -15,7 +67,8 @@ function alg_cache(alg::KenCarp3, u, rate_prototype, ::Type{uEltypeNoUnits}, KenCarp3ConstantCache(nlsolver, tab) end -@cache mutable struct KenCarp3Cache{uType, rateType, uNoUnitsType, N, Tab, kType} <: +@cache mutable struct KenCarp3Cache{ + uType, rateType, uNoUnitsType, N, Tab, kType, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -31,6 +84,7 @@ end atmp::uNoUnitsType nlsolver::N tab::Tab + step_limiter!::StepLimiter end function alg_cache(alg::KenCarp3, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -63,7 +117,8 @@ function alg_cache(alg::KenCarp3, u, rate_prototype, ::Type{uEltypeNoUnits}, atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - KenCarp3Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, k1, k2, k3, k4, atmp, nlsolver, tab) + KenCarp3Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, k1, k2, + k3, k4, atmp, nlsolver, tab, alg.step_limiter!) end @cache mutable struct CFNLIRK3ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache @@ -142,7 +197,7 @@ function alg_cache(alg::Kvaerno4, u, rate_prototype, ::Type{uEltypeNoUnits}, Kvaerno4ConstantCache(nlsolver, tab) end -@cache mutable struct Kvaerno4Cache{uType, rateType, uNoUnitsType, N, Tab} <: +@cache mutable struct Kvaerno4Cache{uType, rateType, uNoUnitsType, N, Tab, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -155,6 +210,7 @@ end atmp::uNoUnitsType nlsolver::N tab::Tab + step_limiter!::StepLimiter end function alg_cache(alg::Kvaerno4, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -175,7 +231,8 @@ function alg_cache(alg::Kvaerno4, u, rate_prototype, ::Type{uEltypeNoUnits}, atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - Kvaerno4Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, z₅, atmp, nlsolver, tab) + Kvaerno4Cache( + u, uprev, fsalfirst, z₁, z₂, z₃, z₄, z₅, atmp, nlsolver, tab, alg.step_limiter!) end @cache mutable struct KenCarp4ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache @@ -194,7 +251,8 @@ function alg_cache(alg::KenCarp4, u, rate_prototype, ::Type{uEltypeNoUnits}, KenCarp4ConstantCache(nlsolver, tab) end -@cache mutable struct KenCarp4Cache{uType, rateType, uNoUnitsType, N, Tab, kType} <: +@cache mutable struct KenCarp4Cache{ + uType, rateType, uNoUnitsType, N, Tab, kType, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -214,6 +272,7 @@ end atmp::uNoUnitsType nlsolver::N tab::Tab + step_limiter!::StepLimiter end TruncatedStacktraces.@truncate_stacktrace KenCarp4Cache 1 @@ -256,7 +315,7 @@ function alg_cache(alg::KenCarp4, u, rate_prototype, ::Type{uEltypeNoUnits}, KenCarp4Cache( u, uprev, fsalfirst, z₁, z₂, z₃, z₄, z₅, z₆, k1, k2, k3, k4, k5, k6, atmp, - nlsolver, tab) + nlsolver, tab, alg.step_limiter!) end @cache mutable struct Kvaerno5ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache @@ -276,7 +335,7 @@ function alg_cache(alg::Kvaerno5, u, rate_prototype, ::Type{uEltypeNoUnits}, Kvaerno5ConstantCache(nlsolver, tab) end -@cache mutable struct Kvaerno5Cache{uType, rateType, uNoUnitsType, N, Tab} <: +@cache mutable struct Kvaerno5Cache{uType, rateType, uNoUnitsType, N, Tab, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -291,6 +350,7 @@ end atmp::uNoUnitsType nlsolver::N tab::Tab + step_limiter!::StepLimiter end function alg_cache(alg::Kvaerno5, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -313,7 +373,8 @@ function alg_cache(alg::Kvaerno5, u, rate_prototype, ::Type{uEltypeNoUnits}, atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - Kvaerno5Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, z₅, z₆, z₇, atmp, nlsolver, tab) + Kvaerno5Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, z₅, z₆, + z₇, atmp, nlsolver, tab, alg.step_limiter!) end @cache mutable struct KenCarp5ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache @@ -333,7 +394,8 @@ function alg_cache(alg::KenCarp5, u, rate_prototype, ::Type{uEltypeNoUnits}, KenCarp5ConstantCache(nlsolver, tab) end -@cache mutable struct KenCarp5Cache{uType, rateType, uNoUnitsType, N, Tab, kType} <: +@cache mutable struct KenCarp5Cache{ + uType, rateType, uNoUnitsType, N, Tab, kType, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -357,6 +419,7 @@ end atmp::uNoUnitsType nlsolver::N tab::Tab + step_limiter!::StepLimiter end function alg_cache(alg::KenCarp5, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -401,7 +464,7 @@ function alg_cache(alg::KenCarp5, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(atmp, false) KenCarp5Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, z₅, z₆, z₇, z₈, - k1, k2, k3, k4, k5, k6, k7, k8, atmp, nlsolver, tab) + k1, k2, k3, k4, k5, k6, k7, k8, atmp, nlsolver, tab, alg.step_limiter!) end @cache mutable struct KenCarp47ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache diff --git a/src/caches/low_order_rk_caches.jl b/src/caches/low_order_rk_caches.jl index bb9ef7df1f..8e7685e2e6 100644 --- a/src/caches/low_order_rk_caches.jl +++ b/src/caches/low_order_rk_caches.jl @@ -1384,6 +1384,123 @@ function alg_cache(alg::MSRK6, u, rate_prototype, ::Type{uEltypeNoUnits}, alg.stage_limiter!, alg.step_limiter!, alg.thread) end +@cache struct PSRK4p7q6Cache{uType, rateType, TabType, StageLimiter, StepLimiter, Thread} <: + OrdinaryDiffEqMutableCache + u::uType + uprev::uType + k1::rateType + k2::rateType + k3::rateType + k4::rateType + k5::rateType + k6::rateType + tmp::uType + tab::TabType + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function alg_cache(alg::PSRK4p7q6, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + return PSRK4p7q6ConstantCache( + constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) +end + +function alg_cache(alg::PSRK4p7q6, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + k1 = zero(rate_prototype) + k2 = zero(rate_prototype) + k3 = zero(rate_prototype) + k4 = zero(rate_prototype) + k5 = zero(rate_prototype) + k6 = zero(rate_prototype) + tmp = zero(u) + tab = PSRK4p7q6ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) + PSRK4p7q6Cache(u, uprev, k1, k2, k3, k4, k5, k6, tmp, tab, + alg.stage_limiter!, alg.step_limiter!, alg.thread) +end + +@cache struct PSRK3p6q5Cache{uType, rateType, TabType, StageLimiter, StepLimiter, Thread} <: + OrdinaryDiffEqMutableCache + u::uType + uprev::uType + k1::rateType + k2::rateType + k3::rateType + k4::rateType + k5::rateType + tmp::uType + tab::TabType + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function alg_cache(alg::PSRK3p6q5, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + return PSRK3p6q5ConstantCache( + constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) +end + +function alg_cache(alg::PSRK3p6q5, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + k1 = zero(rate_prototype) + k2 = zero(rate_prototype) + k3 = zero(rate_prototype) + k4 = zero(rate_prototype) + k5 = zero(rate_prototype) + tmp = zero(u) + tab = PSRK3p6q5ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) + PSRK3p6q5Cache(u, uprev, tmp, k1, k2, k3, k4, k5, tab, + alg.stage_limiter!, alg.step_limiter!, alg.thread) +end + +@cache struct PSRK3p5q4Cache{uType, rateType, TabType, StageLimiter, StepLimiter, Thread} <: + OrdinaryDiffEqMutableCache + u::uType + uprev::uType + k1::rateType + k2::rateType + k3::rateType + k4::rateType + tmp::uType + tab::TabType + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function alg_cache(alg::PSRK3p5q4, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + return PSRK3p5q4ConstantCache( + constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) +end + +function alg_cache(alg::PSRK3p5q4, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + k1 = zero(rate_prototype) + k2 = zero(rate_prototype) + k3 = zero(rate_prototype) + k4 = zero(rate_prototype) + tmp = zero(u) + tab = PSRK3p5q4ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) + PSRK3p5q4Cache(u, uprev, tmp, k1, k2, k3, k4, tab, + alg.stage_limiter!, alg.step_limiter!, alg.thread) +end + @cache struct Stepanov5Cache{uType, rateType, TabType, StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqMutableCache u::uType diff --git a/src/caches/rkn_caches.jl b/src/caches/rkn_caches.jl index 7582e1f498..02014deef1 100644 --- a/src/caches/rkn_caches.jl +++ b/src/caches/rkn_caches.jl @@ -681,3 +681,35 @@ function alg_cache(alg::ERKN7, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} ERKN7ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) end + +@cache struct RKN4Cache{uType, rateType, reducedRateType} <: OrdinaryDiffEqMutableCache + u::uType + uprev::uType + fsalfirst::rateType + k₂::reducedRateType + k₃::reducedRateType + k::rateType + tmp::uType +end + +function alg_cache(alg::RKN4, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + reduced_rate_prototype = rate_prototype.x[2] + k₁ = zero(rate_prototype) + k₂ = zero(reduced_rate_prototype) + k₃ = zero(reduced_rate_prototype) + k = zero(rate_prototype) + tmp = zero(u) + RKN4Cache(u, uprev, k₁, k₂, k₃, k, tmp) +end + +struct RKN4ConstantCache <: OrdinaryDiffEqConstantCache end + +function alg_cache(alg::RKN4, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + RKN4ConstantCache() +end diff --git a/src/caches/rosenbrock_caches.jl b/src/caches/rosenbrock_caches.jl index 7aeac95ebe..e2eb013809 100644 --- a/src/caches/rosenbrock_caches.jl +++ b/src/caches/rosenbrock_caches.jl @@ -5,7 +5,7 @@ abstract type RosenbrockMutableCache <: OrdinaryDiffEqMutableCache end @cache mutable struct Rosenbrock23Cache{uType, rateType, uNoUnitsType, JType, WType, TabType, TFType, UFType, F, JCType, GCType, - RTolType, A, AV} <: RosenbrockMutableCache + RTolType, A, AV, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType k₁::rateType @@ -32,13 +32,15 @@ abstract type RosenbrockMutableCache <: OrdinaryDiffEqMutableCache end reltol::RTolType alg::A algebraic_vars::AV + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end TruncatedStacktraces.@truncate_stacktrace Rosenbrock23Cache 1 @cache mutable struct Rosenbrock32Cache{uType, rateType, uNoUnitsType, JType, WType, TabType, TFType, UFType, F, JCType, GCType, - RTolType, A, AV} <: RosenbrockMutableCache + RTolType, A, AV, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType k₁::rateType @@ -65,6 +67,8 @@ TruncatedStacktraces.@truncate_stacktrace Rosenbrock23Cache 1 reltol::RTolType alg::A algebraic_vars::AV + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end function alg_cache(alg::Rosenbrock23, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -108,7 +112,8 @@ function alg_cache(alg::Rosenbrock23, u, rate_prototype, ::Type{uEltypeNoUnits}, Rosenbrock23Cache(u, uprev, k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg, algebraic_vars) + linsolve, jac_config, grad_config, reltol, alg, algebraic_vars, alg.step_limiter!, + alg.stage_limiter!) end function alg_cache(alg::Rosenbrock32, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -151,7 +156,7 @@ function alg_cache(alg::Rosenbrock32, u, rate_prototype, ::Type{uEltypeNoUnits}, Rosenbrock32Cache(u, uprev, k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, linsolve, jac_config, - grad_config, reltol, alg, algebraic_vars) + grad_config, reltol, alg, algebraic_vars, alg.step_limiter!, alg.stage_limiter!) end struct Rosenbrock23ConstantCache{T, TF, UF, JType, WType, F, AD} <: @@ -230,7 +235,7 @@ end @cache mutable struct Rosenbrock33Cache{uType, rateType, uNoUnitsType, JType, WType, TabType, TFType, UFType, F, JCType, GCType, - RTolType, A} <: RosenbrockMutableCache + RTolType, A, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType du::rateType @@ -257,6 +262,8 @@ end grad_config::GCType reltol::RTolType alg::A + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -295,7 +302,8 @@ function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, Rosenbrock33Cache(u, uprev, du, du1, du2, k1, k2, k3, k4, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -313,7 +321,7 @@ function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, end @cache mutable struct Rosenbrock34Cache{uType, rateType, uNoUnitsType, JType, WType, - TabType, TFType, UFType, F, JCType, GCType} <: + TabType, TFType, UFType, F, JCType, GCType, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType @@ -339,6 +347,8 @@ end linsolve::F jac_config::JCType grad_config::GCType + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end function alg_cache(alg::Rodas3, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -378,7 +388,8 @@ function alg_cache(alg::Rodas3, u, rate_prototype, ::Type{uEltypeNoUnits}, Rosenbrock34Cache(u, uprev, du, du1, du2, k1, k2, k3, k4, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config) + linsolve, jac_config, grad_config, alg.step_limiter!, + alg.stage_limiter!) end struct Rosenbrock34ConstantCache{TF, UF, Tab, JType, WType, F} <: @@ -456,7 +467,7 @@ struct Rodas3PConstantCache{TF, UF, Tab, JType, WType, F, AD} <: OrdinaryDiffEqC end @cache mutable struct Rodas23WCache{uType, rateType, uNoUnitsType, JType, WType, TabType, - TFType, UFType, F, JCType, GCType, RTolType, A} <: + TFType, UFType, F, JCType, GCType, RTolType, A, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType @@ -488,10 +499,12 @@ end grad_config::GCType reltol::RTolType alg::A + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end @cache mutable struct Rodas3PCache{uType, rateType, uNoUnitsType, JType, WType, TabType, - TFType, UFType, F, JCType, GCType, RTolType, A} <: + TFType, UFType, F, JCType, GCType, RTolType, A, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType @@ -523,6 +536,8 @@ end grad_config::GCType reltol::RTolType alg::A + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end function alg_cache(alg::Rodas23W, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -565,7 +580,8 @@ function alg_cache(alg::Rodas23W, u, rate_prototype, ::Type{uEltypeNoUnits}, jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) Rodas23WCache(u, uprev, dense1, dense2, dense3, du, du1, du2, k1, k2, k3, k4, k5, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end TruncatedStacktraces.@truncate_stacktrace Rodas23WCache 1 @@ -609,7 +625,8 @@ function alg_cache(alg::Rodas3P, u, rate_prototype, ::Type{uEltypeNoUnits}, jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) Rodas3PCache(u, uprev, dense1, dense2, dense3, du, du1, du2, k1, k2, k3, k4, k5, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end TruncatedStacktraces.@truncate_stacktrace Rodas3PCache 1 @@ -657,7 +674,7 @@ struct Rodas4ConstantCache{TF, UF, Tab, JType, WType, F, AD} <: OrdinaryDiffEqCo end @cache mutable struct Rodas4Cache{uType, rateType, uNoUnitsType, JType, WType, TabType, - TFType, UFType, F, JCType, GCType, RTolType, A} <: + TFType, UFType, F, JCType, GCType, RTolType, A, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType @@ -689,6 +706,8 @@ end grad_config::GCType reltol::RTolType alg::A + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end function alg_cache(alg::Rodas4, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -732,7 +751,8 @@ function alg_cache(alg::Rodas4, u, rate_prototype, ::Type{uEltypeNoUnits}, Rodas4Cache(u, uprev, dense1, dense2, du, du1, du2, k1, k2, k3, k4, k5, k6, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end TruncatedStacktraces.@truncate_stacktrace Rodas4Cache 1 @@ -793,7 +813,8 @@ function alg_cache(alg::Rodas42, u, rate_prototype, ::Type{uEltypeNoUnits}, Rodas4Cache(u, uprev, dense1, dense2, du, du1, du2, k1, k2, k3, k4, k5, k6, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end function alg_cache(alg::Rodas42, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -852,7 +873,8 @@ function alg_cache(alg::Rodas4P, u, rate_prototype, ::Type{uEltypeNoUnits}, Rodas4Cache(u, uprev, dense1, dense2, du, du1, du2, k1, k2, k3, k4, k5, k6, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end function alg_cache(alg::Rodas4P, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -911,7 +933,8 @@ function alg_cache(alg::Rodas4P2, u, rate_prototype, ::Type{uEltypeNoUnits}, Rodas4Cache(u, uprev, dense1, dense2, du, du1, du2, k1, k2, k3, k4, k5, k6, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end function alg_cache(alg::Rodas4P2, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -944,7 +967,7 @@ end @cache mutable struct Rosenbrock5Cache{ uType, rateType, uNoUnitsType, JType, WType, TabType, - TFType, UFType, F, JCType, GCType, RTolType, A} <: + TFType, UFType, F, JCType, GCType, RTolType, A, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType uprev::uType @@ -979,6 +1002,8 @@ end grad_config::GCType reltol::RTolType alg::A + step_limiter!::StepLimiter + stage_limiter!::StageLimiter end TruncatedStacktraces.@truncate_stacktrace Rosenbrock5Cache 1 @@ -1028,7 +1053,8 @@ function alg_cache(alg::Rodas5, u, rate_prototype, ::Type{uEltypeNoUnits}, k5, k6, k7, k8, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end function alg_cache(alg::Rodas5, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -1045,7 +1071,8 @@ function alg_cache(alg::Rodas5, u, rate_prototype, ::Type{uEltypeNoUnits}, constvalue(tTypeNoUnits)), J, W, linsolve) end -function alg_cache(alg::Union{Rodas5P, Rodas5Pe, Rodas5Pr}, u, rate_prototype, ::Type{uEltypeNoUnits}, +function alg_cache( + alg::Union{Rodas5P, Rodas5Pe, Rodas5Pr}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} @@ -1090,10 +1117,12 @@ function alg_cache(alg::Union{Rodas5P, Rodas5Pe, Rodas5Pr}, u, rate_prototype, : k5, k6, k7, k8, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, - linsolve, jac_config, grad_config, reltol, alg) + linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, + alg.stage_limiter!) end -function alg_cache(alg::Union{Rodas5P, Rodas5Pe, Rodas5Pr}, u, rate_prototype, ::Type{uEltypeNoUnits}, +function alg_cache( + alg::Union{Rodas5P, Rodas5Pe, Rodas5Pr}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} diff --git a/src/caches/sdirk_caches.jl b/src/caches/sdirk_caches.jl index c42000616b..5664341626 100644 --- a/src/caches/sdirk_caches.jl +++ b/src/caches/sdirk_caches.jl @@ -1,6 +1,7 @@ abstract type SDIRKMutableCache <: OrdinaryDiffEqMutableCache end -@cache mutable struct ImplicitEulerCache{uType, rateType, uNoUnitsType, N, AV} <: +@cache mutable struct ImplicitEulerCache{ + uType, rateType, uNoUnitsType, N, AV, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -9,6 +10,7 @@ abstract type SDIRKMutableCache <: OrdinaryDiffEqMutableCache end atmp::uNoUnitsType nlsolver::N algebraic_vars::AV + step_limiter!::StepLimiter end function alg_cache(alg::ImplicitEuler, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -26,7 +28,8 @@ function alg_cache(alg::ImplicitEuler, u, rate_prototype, ::Type{uEltypeNoUnits} algebraic_vars = f.mass_matrix === I ? nothing : [all(iszero, x) for x in eachcol(f.mass_matrix)] - ImplicitEulerCache(u, uprev, uprev2, fsalfirst, atmp, nlsolver, algebraic_vars) + ImplicitEulerCache( + u, uprev, uprev2, fsalfirst, atmp, nlsolver, algebraic_vars, alg.step_limiter!) end mutable struct ImplicitEulerConstantCache{N} <: OrdinaryDiffEqConstantCache @@ -57,11 +60,13 @@ function alg_cache(alg::ImplicitMidpoint, u, rate_prototype, ::Type{uEltypeNoUni ImplicitMidpointConstantCache(nlsolver) end -@cache mutable struct ImplicitMidpointCache{uType, rateType, N} <: SDIRKMutableCache +@cache mutable struct ImplicitMidpointCache{uType, rateType, N, StepLimiter} <: + SDIRKMutableCache u::uType uprev::uType fsalfirst::rateType nlsolver::N + step_limiter!::StepLimiter end function alg_cache(alg::ImplicitMidpoint, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -72,7 +77,7 @@ function alg_cache(alg::ImplicitMidpoint, u, rate_prototype, ::Type{uEltypeNoUni nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) fsalfirst = zero(rate_prototype) - ImplicitMidpointCache(u, uprev, fsalfirst, nlsolver) + ImplicitMidpointCache(u, uprev, fsalfirst, nlsolver, alg.step_limiter!) end mutable struct TrapezoidConstantCache{uType, tType, N} <: OrdinaryDiffEqConstantCache @@ -95,7 +100,8 @@ function alg_cache(alg::Trapezoid, u, rate_prototype, ::Type{uEltypeNoUnits}, TrapezoidConstantCache(uprev3, tprev2, nlsolver) end -@cache mutable struct TrapezoidCache{uType, rateType, uNoUnitsType, tType, N} <: +@cache mutable struct TrapezoidCache{ + uType, rateType, uNoUnitsType, tType, N, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -105,6 +111,7 @@ end uprev3::uType tprev2::tType nlsolver::N + step_limiter!::StepLimiter end function alg_cache(alg::Trapezoid, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -121,7 +128,8 @@ function alg_cache(alg::Trapezoid, u, rate_prototype, ::Type{uEltypeNoUnits}, atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - TrapezoidCache(u, uprev, uprev2, fsalfirst, atmp, uprev3, tprev2, nlsolver) + TrapezoidCache( + u, uprev, uprev2, fsalfirst, atmp, uprev3, tprev2, nlsolver, alg.step_limiter!) end mutable struct TRBDF2ConstantCache{Tab, N} <: OrdinaryDiffEqConstantCache @@ -140,7 +148,7 @@ function alg_cache(alg::TRBDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, TRBDF2ConstantCache(nlsolver, tab) end -@cache mutable struct TRBDF2Cache{uType, rateType, uNoUnitsType, Tab, N} <: +@cache mutable struct TRBDF2Cache{uType, rateType, uNoUnitsType, Tab, N, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -150,6 +158,7 @@ end atmp::uNoUnitsType nlsolver::N tab::Tab + step_limiter!::StepLimiter end function alg_cache(alg::TRBDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -167,7 +176,7 @@ function alg_cache(alg::TRBDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, zprev = zero(u) zᵧ = zero(u) - TRBDF2Cache(u, uprev, fsalfirst, zprev, zᵧ, atmp, nlsolver, tab) + TRBDF2Cache(u, uprev, fsalfirst, zprev, zᵧ, atmp, nlsolver, tab, alg.step_limiter!) end mutable struct SDIRK2ConstantCache{N} <: OrdinaryDiffEqConstantCache @@ -184,7 +193,8 @@ function alg_cache(alg::SDIRK2, u, rate_prototype, ::Type{uEltypeNoUnits}, SDIRK2ConstantCache(nlsolver) end -@cache mutable struct SDIRK2Cache{uType, rateType, uNoUnitsType, N} <: SDIRKMutableCache +@cache mutable struct SDIRK2Cache{uType, rateType, uNoUnitsType, N, StepLimiter} <: + SDIRKMutableCache u::uType uprev::uType fsalfirst::rateType @@ -192,6 +202,7 @@ end z₂::uType atmp::uNoUnitsType nlsolver::N + step_limiter!::StepLimiter end function alg_cache(alg::SDIRK2, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -208,7 +219,7 @@ function alg_cache(alg::SDIRK2, u, rate_prototype, ::Type{uEltypeNoUnits}, atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - SDIRK2Cache(u, uprev, fsalfirst, z₁, z₂, atmp, nlsolver) + SDIRK2Cache(u, uprev, fsalfirst, z₁, z₂, atmp, nlsolver, alg.step_limiter!) end struct SDIRK22ConstantCache{uType, tType, N, Tab} <: OrdinaryDiffEqConstantCache @@ -233,7 +244,8 @@ function alg_cache(alg::SDIRK22, u, rate_prototype, ::Type{uEltypeNoUnits}, SDIRK22ConstantCache(uprev3, tprev2, nlsolver) end -@cache mutable struct SDIRK22Cache{uType, rateType, uNoUnitsType, tType, N, Tab} <: +@cache mutable struct SDIRK22Cache{ + uType, rateType, uNoUnitsType, tType, N, Tab, StepLimiter} <: SDIRKMutableCache u::uType uprev::uType @@ -244,6 +256,7 @@ end tprev2::tType nlsolver::N tab::Tab + step_limiter!::StepLimiter end function alg_cache(alg::SDIRK22, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -261,7 +274,8 @@ function alg_cache(alg::SDIRK22, u, rate_prototype, ::Type{uEltypeNoUnits}, atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - SDIRK22(u, uprev, uprev2, fsalfirst, atmp, uprev3, tprev2, nlsolver, tab) + SDIRK22Cache( + u, uprev, uprev2, fsalfirst, atmp, uprev3, tprev2, nlsolver, tab, alg.step_limiter!) # shouldn't this be SDIRK22Cache instead of SDIRK22? end mutable struct SSPSDIRK2ConstantCache{N} <: OrdinaryDiffEqConstantCache @@ -304,56 +318,6 @@ function alg_cache(alg::SSPSDIRK2, u, rate_prototype, ::Type{uEltypeNoUnits}, SSPSDIRK2Cache(u, uprev, fsalfirst, z₁, z₂, nlsolver) end -mutable struct Kvaerno3ConstantCache{Tab, N} <: OrdinaryDiffEqConstantCache - nlsolver::N - tab::Tab -end - -function alg_cache(alg::Kvaerno3, u, rate_prototype, ::Type{uEltypeNoUnits}, - ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, - uprev, uprev2, f, t, dt, reltol, p, calck, - ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - tab = Kvaerno3Tableau(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) - γ, c = tab.γ, 2tab.γ - nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, - uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) - Kvaerno3ConstantCache(nlsolver, tab) -end - -@cache mutable struct Kvaerno3Cache{uType, rateType, uNoUnitsType, Tab, N} <: - SDIRKMutableCache - u::uType - uprev::uType - fsalfirst::rateType - z₁::uType - z₂::uType - z₃::uType - z₄::uType - atmp::uNoUnitsType - nlsolver::N - tab::Tab -end - -function alg_cache(alg::Kvaerno3, u, rate_prototype, ::Type{uEltypeNoUnits}, - ::Type{uBottomEltypeNoUnits}, - ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, - ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - tab = Kvaerno3Tableau(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) - γ, c = tab.γ, 2tab.γ - nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, - uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) - fsalfirst = zero(rate_prototype) - - z₁ = zero(u) - z₂ = zero(u) - z₃ = zero(u) - z₄ = nlsolver.z - atmp = similar(u, uEltypeNoUnits) - recursivefill!(atmp, false) - - Kvaerno3Cache(u, uprev, fsalfirst, z₁, z₂, z₃, z₄, atmp, nlsolver, tab) -end - mutable struct Cash4ConstantCache{N, Tab} <: OrdinaryDiffEqConstantCache nlsolver::N tab::Tab diff --git a/src/caches/verner_caches.jl b/src/caches/verner_caches.jl index 08b1de0919..6de34d0559 100644 --- a/src/caches/verner_caches.jl +++ b/src/caches/verner_caches.jl @@ -20,6 +20,7 @@ stage_limiter!::StageLimiter step_limiter!::StepLimiter thread::Thread + lazy::Bool end TruncatedStacktraces.@truncate_stacktrace Vern6Cache 1 @@ -44,11 +45,12 @@ function alg_cache(alg::Vern6, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(atmp, false) rtmp = uEltypeNoUnits === eltype(u) ? utilde : zero(rate_prototype) Vern6Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, utilde, tmp, rtmp, atmp, tab, - alg.stage_limiter!, alg.step_limiter!, alg.thread) + alg.stage_limiter!, alg.step_limiter!, alg.thread, alg.lazy) end struct Vern6ConstantCache{TabType} <: OrdinaryDiffEqConstantCache tab::TabType + lazy::Bool end function alg_cache(alg::Vern6, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -56,7 +58,7 @@ function alg_cache(alg::Vern6, u, rate_prototype, ::Type{uEltypeNoUnits}, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tab = Vern6Tableau(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) - Vern6ConstantCache(tab) + Vern6ConstantCache(tab, alg.lazy) end @cache struct Vern7Cache{uType, rateType, uNoUnitsType, StageLimiter, StepLimiter, @@ -81,6 +83,7 @@ end stage_limiter!::StageLimiter step_limiter!::StepLimiter thread::Thread + lazy::Bool end TruncatedStacktraces.@truncate_stacktrace Vern7Cache 1 @@ -105,16 +108,18 @@ function alg_cache(alg::Vern7, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(atmp, false) rtmp = uEltypeNoUnits === eltype(u) ? utilde : zero(rate_prototype) Vern7Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, utilde, tmp, rtmp, atmp, - alg.stage_limiter!, alg.step_limiter!, alg.thread) + alg.stage_limiter!, alg.step_limiter!, alg.thread, alg.lazy) end -struct Vern7ConstantCache <: OrdinaryDiffEqConstantCache end +struct Vern7ConstantCache <: OrdinaryDiffEqConstantCache + lazy::Bool +end function alg_cache(alg::Vern7, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - Vern7ConstantCache() + Vern7ConstantCache(alg.lazy) end @cache struct Vern8Cache{uType, rateType, uNoUnitsType, TabType, StageLimiter, StepLimiter, @@ -143,6 +148,7 @@ end stage_limiter!::StageLimiter step_limiter!::StepLimiter thread::Thread + lazy::Bool end TruncatedStacktraces.@truncate_stacktrace Vern8Cache 1 @@ -171,11 +177,12 @@ function alg_cache(alg::Vern8, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(atmp, false) rtmp = uEltypeNoUnits === eltype(u) ? utilde : zero(rate_prototype) Vern8Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, utilde, - tmp, rtmp, atmp, tab, alg.stage_limiter!, alg.step_limiter!, alg.thread) + tmp, rtmp, atmp, tab, alg.stage_limiter!, alg.step_limiter!, alg.thread, alg.lazy) end struct Vern8ConstantCache{TabType} <: OrdinaryDiffEqConstantCache tab::TabType + lazy::Bool end function alg_cache(alg::Vern8, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -183,7 +190,7 @@ function alg_cache(alg::Vern8, u, rate_prototype, ::Type{uEltypeNoUnits}, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tab = Vern8Tableau(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) - Vern8ConstantCache(tab) + Vern8ConstantCache(tab, alg.lazy) end @cache struct Vern9Cache{uType, rateType, uNoUnitsType, StageLimiter, StepLimiter, @@ -214,6 +221,7 @@ end stage_limiter!::StageLimiter step_limiter!::StepLimiter thread::Thread + lazy::Bool end TruncatedStacktraces.@truncate_stacktrace Vern9Cache 1 @@ -245,14 +253,16 @@ function alg_cache(alg::Vern9, u, rate_prototype, ::Type{uEltypeNoUnits}, rtmp = uEltypeNoUnits === eltype(u) ? utilde : zero(rate_prototype) Vern9Cache(u, uprev, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, utilde, tmp, rtmp, atmp, alg.stage_limiter!, alg.step_limiter!, - alg.thread) + alg.thread, alg.lazy) end -struct Vern9ConstantCache <: OrdinaryDiffEqConstantCache end +struct Vern9ConstantCache <: OrdinaryDiffEqConstantCache + lazy::Bool +end function alg_cache(alg::Vern9, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - Vern9ConstantCache() + Vern9ConstantCache(alg.lazy) end diff --git a/src/composite_algs.jl b/src/composite_algs.jl index 9f1d4dcf6b..34a64aa502 100644 --- a/src/composite_algs.jl +++ b/src/composite_algs.jl @@ -1,30 +1,8 @@ -mutable struct AutoSwitchCache{nAlg, sAlg, tolType, T} - count::Int - successive_switches::Int - nonstiffalg::nAlg - stiffalg::sAlg - is_stiffalg::Bool - maxstiffstep::Int - maxnonstiffstep::Int - nonstifftol::tolType - stifftol::tolType - dtfac::T - stiffalgfirst::Bool - switch_max::Int -end +### AutoSwitch +### Designed to switch between two solvers, stiff and non-stiff -struct AutoSwitch{nAlg, sAlg, tolType, T} - nonstiffalg::nAlg - stiffalg::sAlg - maxstiffstep::Int - maxnonstiffstep::Int - nonstifftol::tolType - stifftol::tolType - dtfac::T - stiffalgfirst::Bool - switch_max::Int -end -function AutoSwitch(nonstiffalg, stiffalg; maxstiffstep = 10, maxnonstiffstep = 3, +function AutoSwitch(nonstiffalg, stiffalg; + maxstiffstep = 10, maxnonstiffstep = 3, nonstifftol = 9 // 10, stifftol = 9 // 10, dtfac = 2, stiffalgfirst = false, switch_max = 5) @@ -41,7 +19,6 @@ function is_stiff(integrator, alg, ntol, stol, is_stiffalg) if !bool integrator.alg.choice_function.successive_switches += 1 - integrator.do_error_check = false else integrator.alg.choice_function.successive_switches = 0 end @@ -53,7 +30,17 @@ function is_stiff(integrator, alg, ntol, stol, is_stiffalg) end function (AS::AutoSwitchCache)(integrator) - integrator.iter == 0 && return Int(AS.stiffalgfirst) + 1 + #horrible awful hack + isdefault = integrator.alg isa CompositeAlgorithm{ + <:Any, <:Tuple{Tsit5, Vern7, Rosenbrock23, Rodas5P, FBDF, FBDF}} + if isdefault + return default_autoswitch(AS, integrator) + end + if AS.current == 0 + AS.current = Int(AS.stiffalgfirst) + 1 + return AS.current + end + dt = integrator.dt # Successive stiffness test positives are counted by a positive integer, # and successive stiffness test negatives are counted by a negative integer @@ -68,17 +55,140 @@ function (AS::AutoSwitchCache)(integrator) integrator.dt = dt / AS.dtfac AS.is_stiffalg = false end - return Int(AS.is_stiffalg) + 1 + AS.current = Int(AS.is_stiffalg) + 1 + return AS.current end -function AutoAlgSwitch(nonstiffalg, stiffalg; kwargs...) +function AutoAlgSwitch( + nonstiffalg::OrdinaryDiffEqAlgorithm, stiffalg::OrdinaryDiffEqAlgorithm; kwargs...) AS = AutoSwitch(nonstiffalg, stiffalg; kwargs...) CompositeAlgorithm((nonstiffalg, stiffalg), AS) end +function AutoAlgSwitch(nonstiffalg::Tuple, stiffalg::Tuple; kwargs...) + AS = AutoSwitch(nonstiffalg, stiffalg; kwargs...) + CompositeAlgorithm((nonstiffalg..., stiffalg...), AS) +end + AutoTsit5(alg; kwargs...) = AutoAlgSwitch(Tsit5(), alg; kwargs...) AutoDP5(alg; kwargs...) = AutoAlgSwitch(DP5(), alg; kwargs...) AutoVern6(alg; lazy = true, kwargs...) = AutoAlgSwitch(Vern6(lazy = lazy), alg; kwargs...) AutoVern7(alg; lazy = true, kwargs...) = AutoAlgSwitch(Vern7(lazy = lazy), alg; kwargs...) AutoVern8(alg; lazy = true, kwargs...) = AutoAlgSwitch(Vern8(lazy = lazy), alg; kwargs...) AutoVern9(alg; lazy = true, kwargs...) = AutoAlgSwitch(Vern9(lazy = lazy), alg; kwargs...) + +### Default ODE Solver + +EnumX.@enumx DefaultSolverChoice begin + Tsit5 = 1 + Vern7 = 2 + Rosenbrock23 = 3 + Rodas5P = 4 + FBDF = 5 + KrylovFBDF = 6 +end + +const NUM_NONSTIFF = 2 +const NUM_STIFF = 4 +const LOW_TOL = 1e-6 +const MED_TOL = 1e-2 +const EXTREME_TOL = 1e-9 +const SMALLSIZE = 50 +const MEDIUMSIZE = 500 +const STABILITY_SIZES = (alg_stability_size(Tsit5()), alg_stability_size(Vern7())) +const DEFAULTBETA2S = ( + beta2_default(Tsit5()), beta2_default(Vern7()), beta2_default(Rosenbrock23()), + beta2_default(Rodas5P()), beta2_default(FBDF()), beta2_default(FBDF())) +const DEFAULTBETA1S = ( + beta1_default(Tsit5(), DEFAULTBETA2S[1]), beta1_default(Vern7(), DEFAULTBETA2S[2]), + beta1_default(Rosenbrock23(), DEFAULTBETA2S[3]), beta1_default( + Rodas5P(), DEFAULTBETA2S[4]), + beta1_default(FBDF(), DEFAULTBETA2S[5]), beta1_default(FBDF(), DEFAULTBETA2S[6])) + +callbacks_exists(integrator) = !isempty(integrator.opts.callbacks) +current_nonstiff(current) = ifelse(current <= NUM_NONSTIFF, current, current - NUM_STIFF) + +function DefaultODEAlgorithm(; lazy = true, stiffalgfirst = false, kwargs...) + nonstiff = (Tsit5(), Vern7(lazy = lazy)) + stiff = (Rosenbrock23(; kwargs...), Rodas5P(; kwargs...), FBDF(; kwargs...), + FBDF(; linsolve = LinearSolve.KrylovJL_GMRES())) + AutoAlgSwitch(nonstiff, stiff; stiffalgfirst) +end + +function is_stiff(integrator, alg, ntol, stol, is_stiffalg, current) + eigen_est, dt = integrator.eigen_est, integrator.dt + stiffness = abs(eigen_est * dt / + STABILITY_SIZES[nonstiffchoice(integrator.opts.reltol)]) # `abs` here is just for safety + tol = is_stiffalg ? stol : ntol + os = oneunit(stiffness) + bool = stiffness > os * tol + + if !bool + integrator.alg.choice_function.successive_switches += 1 + else + integrator.alg.choice_function.successive_switches = 0 + end + + integrator.do_error_check = (integrator.alg.choice_function.successive_switches > + integrator.alg.choice_function.switch_max || !bool) || + is_stiffalg + bool +end + +function nonstiffchoice(reltol) + x = if reltol < LOW_TOL + DefaultSolverChoice.Vern7 + else + DefaultSolverChoice.Tsit5 + end + Int(x) +end + +function stiffchoice(reltol, len) + x = if len > MEDIUMSIZE + DefaultSolverChoice.KrylovFBDF + elseif len > SMALLSIZE + DefaultSolverChoice.FBDF + else + if reltol < LOW_TOL + DefaultSolverChoice.Rodas5P + else + DefaultSolverChoice.Rosenbrock23 + end + end + Int(x) +end + +function default_autoswitch(AS::AutoSwitchCache, integrator) + len = length(integrator.u) + reltol = integrator.opts.reltol + + # Chooose the starting method + if AS.current == 0 + choice = if AS.stiffalgfirst || integrator.f.mass_matrix != I + stiffchoice(reltol, len) + else + nonstiffchoice(reltol) + end + AS.current = choice + return AS.current + end + + dt = integrator.dt + # Successive stiffness test positives are counted by a positive integer, + # and successive stiffness test negatives are counted by a negative integer + AS.count = is_stiff(integrator, AS.nonstiffalg, AS.nonstifftol, AS.stifftol, + AS.is_stiffalg, AS.current) ? + AS.count < 0 ? 1 : AS.count + 1 : + AS.count > 0 ? -1 : AS.count - 1 + if integrator.f.mass_matrix != I || (!AS.is_stiffalg && AS.count > AS.maxstiffstep) + integrator.dt = dt * AS.dtfac + AS.is_stiffalg = true + AS.current = stiffchoice(reltol, len) + elseif (AS.is_stiffalg && AS.count < -AS.maxnonstiffstep) + integrator.dt = dt / AS.dtfac + AS.is_stiffalg = false + AS.current = nonstiffchoice(reltol) + end + return AS.current +end diff --git a/src/dense/generic_dense.jl b/src/dense/generic_dense.jl index 1a45aa5855..26624a1987 100644 --- a/src/dense/generic_dense.jl +++ b/src/dense/generic_dense.jl @@ -59,48 +59,71 @@ end @inline function ode_addsteps!(integrator, f = integrator.f, always_calc_begin = false, allow_calc_end = true, force_calc_end = false) cache = integrator.cache - if !(cache isa CompositeCache) - _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, integrator.u, - integrator.dt, f, integrator.p, cache, - always_calc_begin, allow_calc_end, force_calc_end) - else + if cache isa CompositeCache cache_current = cache.current - if length(integrator.cache.caches) == 2 - if cache_current == 1 - _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, - integrator.u, - integrator.dt, f, integrator.p, - cache.caches[1], - always_calc_begin, allow_calc_end, force_calc_end) - else - @assert cache_current == 2 - _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, - integrator.u, - integrator.dt, f, integrator.p, - cache.caches[2], - always_calc_begin, allow_calc_end, force_calc_end) - end + if cache_current == 1 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.caches[1], + always_calc_begin, allow_calc_end, force_calc_end) + elseif cache_current == 2 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.caches[2], + always_calc_begin, allow_calc_end, force_calc_end) else - if cache_current == 1 - _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, - integrator.u, - integrator.dt, f, integrator.p, - cache.caches[1], - always_calc_begin, allow_calc_end, force_calc_end) - elseif cache_current == 2 - _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, - integrator.u, - integrator.dt, f, integrator.p, - cache.caches[2], - always_calc_begin, allow_calc_end, force_calc_end) - else - _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, - integrator.u, - integrator.dt, f, integrator.p, - cache.caches[cache_current], - always_calc_begin, allow_calc_end, force_calc_end) - end + @assert length(integrator.cache.caches) >= cache_current + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.caches[cache_current], + always_calc_begin, allow_calc_end, force_calc_end) end + elseif cache isa DefaultCache + cache_current = cache.current + if cache_current == 1 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.cache1, + always_calc_begin, allow_calc_end, force_calc_end) + elseif cache_current == 2 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.cache2, + always_calc_begin, allow_calc_end, force_calc_end) + elseif cache_current == 3 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.cache3, + always_calc_begin, allow_calc_end, force_calc_end) + elseif cache_current == 4 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.cache5, + always_calc_begin, allow_calc_end, force_calc_end) + elseif cache_current == 5 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.cache1, + always_calc_begin, allow_calc_end, force_calc_end) + elseif cache_current == 6 + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, + integrator.u, + integrator.dt, f, integrator.p, + cache.cache6, + always_calc_begin, allow_calc_end, force_calc_end) + end + else + _ode_addsteps!(integrator.k, integrator.tprev, integrator.uprev, integrator.u, + integrator.dt, f, integrator.p, cache, + always_calc_begin, allow_calc_end, force_calc_end) end return nothing end @@ -620,77 +643,51 @@ end ##################### Hermite Interpolants -const HERMITE_CASE_NOT_DEFINED_MESSAGE = """ - Hermite interpolation is not defined in this case. The Hermite interpolation - fallback only supports diagonal mass matrices. If you have a DAE with a - non-diagonal mass matrix, then the dense output is not supported with this - ODE solver. Either use a method which has a specialized interpolation, - such as Rodas5P, or use `dense=false` - - You can find the list of available DAE solvers with their documented interpolations at: - https://docs.sciml.ai/DiffEqDocs/stable/solvers/dae_solve/ - """ - -struct HermiteInterpolationNonDiagonalError <: Exception end - -function Base.showerror(io::IO, e::HermiteInterpolationNonDiagonalError) - print(io, HERMITE_CASE_NOT_DEFINED_MESSAGE) - println(io, TruncatedStacktraces.VERBOSE_MSG) -end - -# If no dispatch found, assume Hermite -function _ode_interpolant( - Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{TI}}, differential_vars) where {TI} - differential_vars isa DifferentialVarsUndefined && - throw(HermiteInterpolationNonDiagonalError()) - TI > 3 && throw(DerivativeOrderNotPossibleError()) - - differential_vars = if differential_vars === nothing +function interpolation_differential_vars(differential_vars, y₀, idxs) + if isnothing(differential_vars) + if y₀ isa Number + return true + elseif idxs === nothing + return Trues(size(y₀)) + elseif idxs isa Number + return true + else + return Trues(size(idxs)) + end + elseif differential_vars isa DifferentialVarsUndefined #for non diagonal mass matrices, use linear interpolation. if y₀ isa Number - differential_vars = true + return false elseif idxs === nothing - differential_vars = Trues(size(y₀)) + return Falses(size(y₀)) elseif idxs isa Number - differential_vars = true + return false else - differential_vars = Trues(size(idxs)) + return Falses(size(idxs)) end elseif idxs isa Number - differential_vars[idxs] + return return differential_vars[idxs] elseif idxs === nothing - differential_vars + return differential_vars else - @view differential_vars[idxs] + return @view differential_vars[idxs] end +end + +# If no dispatch found, assume Hermite +function _ode_interpolant( + Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{TI}}, differential_vars) where {TI} + TI > 3 && throw(DerivativeOrderNotPossibleError()) + differential_vars = interpolation_differential_vars(differential_vars, y₀, idxs) hermite_interpolant(Θ, dt, y₀, y₁, k, Val{cache isa OrdinaryDiffEqMutableCache}, idxs, T, differential_vars) end function _ode_interpolant!( out, Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{TI}}, differential_vars) where {TI} - differential_vars isa DifferentialVarsUndefined && - throw(HermiteInterpolationNonDiagonalError()) TI > 3 && throw(DerivativeOrderNotPossibleError()) - differential_vars = if differential_vars === nothing - if y₀ isa Number - differential_vars = true - elseif idxs === nothing - differential_vars = Trues(size(out)) - elseif idxs isa Number - differential_vars = true - else - differential_vars = Trues(size(idxs)) - end - elseif idxs isa Number - differential_vars[idxs] - elseif idxs === nothing - differential_vars - else - @view differential_vars[idxs] - end - + differential_vars = interpolation_differential_vars(differential_vars, y₀, idxs) hermite_interpolant!(out, Θ, dt, y₀, y₁, k, idxs, T, differential_vars) end @@ -700,7 +697,7 @@ Hairer Norsett Wanner Solving Ordinary Differential Euations I - Nonstiff Proble Herimte Interpolation, chosen if no other dispatch for ode_interpolant """ @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{false}}, idxs::Nothing, - T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{0}}, differential_vars) #@.. broadcast=false (1-Θ)*y₀+Θ*y₁+Θ*(Θ-1)*((1-2Θ)*(y₁-y₀)+(Θ-1)*dt*k[1] + Θ*dt*k[2]) if all(differential_vars) @inbounds (1 - Θ) * y₀ + Θ * y₁ + @@ -714,15 +711,21 @@ Herimte Interpolation, chosen if no other dispatch for ode_interpolant end @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{true}}, idxs::Nothing, - T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{0}}, differential_vars) #@.. broadcast=false (1-Θ)*y₀+Θ*y₁+Θ*(Θ-1)*((1-2Θ)*(y₁-y₀)+(Θ-1)*dt*k[1] + Θ*dt*k[2]) - @inbounds @.. broadcast=false (1 - Θ)*y₀+Θ*y₁+ - differential_vars*Θ*(Θ-1)* - ((1 - 2Θ)*(y₁ - y₀)+(Θ-1)*dt*k[1]+Θ*dt*k[2]) + if all(differential_vars) + @inbounds @.. broadcast=false (1 - Θ)*y₀+Θ*y₁+ + Θ*(Θ-1)* + ((1 - 2Θ)*(y₁ - y₀)+(Θ-1)*dt*k[1]+Θ*dt*k[2]) + else + @inbounds @.. broadcast=false (1 - Θ)*y₀+Θ*y₁+ + differential_vars*Θ*(Θ-1)* + ((1 - 2Θ)*(y₁ - y₀)+(Θ-1)*dt*k[1]+Θ*dt*k[2]) + end end @muladd function hermite_interpolant(Θ, dt, y₀::Array, y₁, k, ::Type{Val{true}}, - idxs::Nothing, T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite + idxs::Nothing, T::Type{Val{0}}, differential_vars) out = similar(y₀) @inbounds @simd ivdep for i in eachindex(y₀) out[i] = (1 - Θ) * y₀[i] + Θ * y₁[i] + @@ -732,24 +735,39 @@ end end @muladd function hermite_interpolant( - Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite + Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{0}}, differential_vars) # return @.. broadcast=false (1-Θ)*y₀[idxs]+Θ*y₁[idxs]+Θ*(Θ-1)*((1-2Θ)*(y₁[idxs]-y₀[idxs])+(Θ-1)*dt*k[1][idxs] + Θ*dt*k[2][idxs]) - return (1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + - differential_vars .* (Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + (Θ - 1) * dt * k[1][idxs] + - Θ * dt * k[2][idxs])) + if all(differential_vars) + return (1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + + (Θ * (Θ - 1) * + ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + (Θ - 1) * dt * k[1][idxs] + + Θ * dt * k[2][idxs])) + else + return (1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + + differential_vars .* (Θ * (Θ - 1) * + ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + (Θ - 1) * dt * k[1][idxs] + + Θ * dt * k[2][idxs])) + end end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite - @inbounds @.. broadcast=false out=(1 - Θ) * y₀ + Θ * y₁ + - differential_vars * Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁ - y₀) + (Θ - 1) * dt * k[1] + - Θ * dt * k[2]) + out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{0}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false out=(1 - Θ) * y₀ + Θ * y₁ + + Θ * (Θ - 1) * + ((1 - 2Θ) * (y₁ - y₀) + (Θ - 1) * dt * k[1] + + Θ * dt * k[2]) + else + @inbounds @.. broadcast=false out=(1 - Θ) * y₀ + Θ * y₁ + + differential_vars * Θ * (Θ - 1) * + ((1 - 2Θ) * (y₁ - y₀) + (Θ - 1) * dt * k[1] + + Θ * dt * k[2]) + end + out end @muladd function hermite_interpolant!(out::Array, Θ, dt, y₀, y₁, k, idxs::Nothing, - T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{0}}, differential_vars) @inbounds @simd ivdep for i in eachindex(out) out[i] = (1 - Θ) * y₀[i] + Θ * y₁[i] + differential_vars[i] * Θ * (Θ - 1) * @@ -759,15 +777,23 @@ end end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite - @views @.. broadcast=false out=(1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + - differential_vars * Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + - (Θ - 1) * dt * k[1][idxs] + Θ * dt * k[2][idxs]) + out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{0}}, differential_vars) + if all(differential_vars) + @views @.. broadcast=false out=(1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + + Θ * (Θ - 1) * + ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + + (Θ - 1) * dt * k[1][idxs] + Θ * dt * k[2][idxs]) + else + @views @.. broadcast=false out=(1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + + differential_vars * Θ * (Θ - 1) * + ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + + (Θ - 1) * dt * k[1][idxs] + Θ * dt * k[2][idxs]) + end + out end @muladd function hermite_interpolant!( - out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{0}}, differential_vars) # Default interpolant is Hermite + out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{0}}, differential_vars) @inbounds for (j, i) in enumerate(idxs) out[j] = (1 - Θ) * y₀[i] + Θ * y₁[i] + differential_vars[j] * Θ * (Θ - 1) * @@ -780,7 +806,7 @@ end Herimte Interpolation, chosen if no other dispatch for ode_interpolant """ @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{false}}, idxs::Nothing, - T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{1}}, differential_vars) #@.. broadcast=false k[1] + Θ*(-4*dt*k[1] - 2*dt*k[2] - 6*y₀ + Θ*(3*dt*k[1] + 3*dt*k[2] + 6*y₀ - 6*y₁) + 6*y₁)/dt if all(differential_vars) @inbounds ( @@ -797,41 +823,69 @@ Herimte Interpolation, chosen if no other dispatch for ode_interpolant end @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{true}}, idxs::Nothing, - T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite - @inbounds @.. broadcast=false !differential_vars * - ((y₁ - y₀) / - dt)+differential_vars * ( - k[1] + - Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + - 6 * y₁) / dt) + T::Type{Val{1}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false !differential_vars * + ((y₁ - y₀) / + dt)+( + k[1] + + Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + + 6 * y₁) / dt) + else + @inbounds @.. broadcast=false !differential_vars * + ((y₁ - y₀) / + dt)+differential_vars * ( + k[1] + + Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + + 6 * y₁) / dt) + end end @muladd function hermite_interpolant( - Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite - # return @.. broadcast=false k[1][idxs] + Θ*(-4*dt*k[1][idxs] - 2*dt*k[2][idxs] - 6*y₀[idxs] + Θ*(3*dt*k[1][idxs] + 3*dt*k[2][idxs] + 6*y₀[idxs] - 6*y₁[idxs]) + 6*y₁[idxs])/dt - return (.!differential_vars) .* ((y₁[idxs] - y₀[idxs]) / dt) + - differential_vars .* ( - k[1][idxs] + - Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + - Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + 6 * y₀[idxs] - 6 * y₁[idxs]) + - 6 * y₁[idxs]) / dt) + Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{1}}, differential_vars) + if all(differential_vars) + ( + k[1][idxs] + + Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + + Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + 6 * y₀[idxs] - 6 * y₁[idxs]) + + 6 * y₁[idxs]) / dt) + else + (.!differential_vars) .* ((y₁[idxs] - y₀[idxs]) / dt) + + differential_vars .* ( + k[1][idxs] + + Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + + Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + 6 * y₀[idxs] - 6 * y₁[idxs]) + + 6 * y₁[idxs]) / dt) + end end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite - @inbounds @.. broadcast=false out=!differential_vars * ((y₁ - y₀) / dt) + - differential_vars * ( - k[1] + - Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + - 6 * y₁) / dt) + out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{1}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false out=( + k[1] + + Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + + 6 * y₁) / dt) + else + @inbounds @.. broadcast=false out=!differential_vars * ((y₁ - y₀) / dt) + + differential_vars * ( + k[1] + + Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + + 6 * y₁) / dt) + end + out end @muladd function hermite_interpolant!(out::Array, Θ, dt, y₀, y₁, k, idxs::Nothing, - T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{1}}, differential_vars) @inbounds @simd ivdep for i in eachindex(out) out[i] = !differential_vars[i] * ((y₁[i] - y₀[i]) / dt) + differential_vars[i] * ( @@ -844,18 +898,27 @@ end end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite - @views @.. broadcast=false out=!differential_vars * ((y₁ - y₀) / dt) + - differential_vars * ( - k[1][idxs] + - Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - - 6 * y₀[idxs] + - Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + - 6 * y₀[idxs] - 6 * y₁[idxs]) + 6 * y₁[idxs]) / dt) + out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{1}}, differential_vars) + if all(differential_vars) + @views @.. broadcast=false out=( + k[1][idxs] + + Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - + 6 * y₀[idxs] + + Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + + 6 * y₀[idxs] - 6 * y₁[idxs]) + 6 * y₁[idxs]) / dt) + else + @views @.. broadcast=false out=!differential_vars * ((y₁ - y₀) / dt) + + differential_vars * ( + k[1][idxs] + + Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - + 6 * y₀[idxs] + + Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + + 6 * y₀[idxs] - 6 * y₁[idxs]) + 6 * y₁[idxs]) / dt) + end end @muladd function hermite_interpolant!( - out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{1}}, differential_vars) # Default interpolant is Hermite + out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{1}}, differential_vars) @inbounds for (j, i) in enumerate(idxs) out[j] = !differential_vars[j] * ((y₁[i] - y₀[i]) / dt) + differential_vars[j] * ( @@ -871,8 +934,7 @@ end Herimte Interpolation, chosen if no other dispatch for ode_interpolant """ @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{false}}, idxs::Nothing, - T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite - #@.. broadcast=false (-4*dt*k[1] - 2*dt*k[2] - 6*y₀ + Θ*(6*dt*k[1] + 6*dt*k[2] + 12*y₀ - 12*y₁) + 6*y₁)/(dt*dt) + T::Type{Val{2}}, differential_vars) if all(differential_vars) @inbounds (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + Θ * (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) + 6 * y₁) / @@ -885,36 +947,57 @@ Herimte Interpolation, chosen if no other dispatch for ode_interpolant end @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{true}}, idxs::Nothing, - T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite - #@.. broadcast=false (-4*dt*k[1] - 2*dt*k[2] - 6*y₀ + Θ*(6*dt*k[1] + 6*dt*k[2] + 12*y₀ - 12*y₁) + 6*y₁)/(dt*dt) - @inbounds @.. broadcast=false differential_vars * - (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) + - 6 * y₁)/(dt * dt) + T::Type{Val{2}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) + + 6 * y₁)/(dt * dt) + else + @inbounds @.. broadcast=false differential_vars * + (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) + + 6 * y₁)/(dt * dt) + end end @muladd function hermite_interpolant( - Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite - #out = similar(y₀,axes(idxs)) - #@views @.. broadcast=false out = (-4*dt*k[1][idxs] - 2*dt*k[2][idxs] - 6*y₀[idxs] + Θ*(6*dt*k[1][idxs] + 6*dt*k[2][idxs] + 12*y₀[idxs] - 12*y₁[idxs]) + 6*y₁[idxs])/(dt*dt) - @views out = differential_vars .* - (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + - Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - - 12 * y₁[idxs]) + 6 * y₁[idxs]) / (dt * dt) + Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{2}}, differential_vars) + if all(differential_vars) + @views out = (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + + Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - + 12 * y₁[idxs]) + 6 * y₁[idxs]) / (dt * dt) + else + @views out = differential_vars .* + (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + + Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - + 12 * y₁[idxs]) + 6 * y₁[idxs]) / (dt * dt) + end out end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite - @inbounds @.. broadcast=false out=differential_vars * - (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) + - 6 * y₁) / (dt * dt) + out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{2}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false out=(-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - + 12 * y₁) + + 6 * y₁) / (dt * dt) + else + @inbounds @.. broadcast=false out=differential_vars * + (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + + Θ * + (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - + 12 * y₁) + + 6 * y₁) / (dt * dt) + end + out end @muladd function hermite_interpolant!(out::Array, Θ, dt, y₀, y₁, k, idxs::Nothing, - T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{2}}, differential_vars) @inbounds @simd ivdep for i in eachindex(out) out[i] = differential_vars[i] * (-4 * dt * k[1][i] - 2 * dt * k[2][i] - 6 * y₀[i] + @@ -925,17 +1008,26 @@ end end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite - @views @.. broadcast=false out=differential_vars * - (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - - 6 * y₀[idxs] + - Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + - 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / - (dt * dt) + out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{2}}, differential_vars) + if all(differential_vars) + @views @.. broadcast=false out=(-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - + 6 * y₀[idxs] + + Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + + 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / + (dt * dt) + else + @views @.. broadcast=false out=differential_vars * + (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - + 6 * y₀[idxs] + + Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + + 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / + (dt * dt) + end + out end @muladd function hermite_interpolant!( - out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{2}}, differential_vars) # Default interpolant is Hermite + out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{2}}, differential_vars) @inbounds for (j, i) in enumerate(idxs) out[j] = differential_vars[j] * (-4 * dt * k[1][i] - 2 * dt * k[2][i] - 6 * y₀[i] + @@ -949,7 +1041,7 @@ end Herimte Interpolation, chosen if no other dispatch for ode_interpolant """ @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{false}}, idxs::Nothing, - T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{3}}, differential_vars) #@.. broadcast=false (6*dt*k[1] + 6*dt*k[2] + 12*y₀ - 12*y₁)/(dt*dt*dt) if all(differential_vars) @inbounds (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) / (dt * dt * dt) @@ -960,39 +1052,53 @@ Herimte Interpolation, chosen if no other dispatch for ode_interpolant end @muladd function hermite_interpolant(Θ, dt, y₀, y₁, k, ::Type{Val{true}}, idxs::Nothing, - T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite - #@.. broadcast=false (6*dt*k[1] + 6*dt*k[2] + 12*y₀ - 12*y₁)/(dt*dt*dt) - @inbounds @.. broadcast=false differential_vars * - (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - - 12 * y₁)/(dt * - dt * - dt) + T::Type{Val{3}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - + 12 * y₁)/(dt * + dt * + dt) + else + @inbounds @.. broadcast=false differential_vars * + (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - + 12 * y₁)/(dt * + dt * + dt) + end end @muladd function hermite_interpolant( - Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite - #out = similar(y₀,axes(idxs)) - #@views @.. broadcast=false out = (6*dt*k[1][idxs] + 6*dt*k[2][idxs] + 12*y₀[idxs] - 12*y₁[idxs])/(dt*dt*dt) - @views out = differential_vars .* - (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - - 12 * y₁[idxs]) / - (dt * dt * dt) + Θ, dt, y₀, y₁, k, cache, idxs, T::Type{Val{3}}, differential_vars) + if all(differential_vars) + @views out = (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - + 12 * y₁[idxs]) / + (dt * dt * dt) + else + @views out = differential_vars .* + (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - + 12 * y₁[idxs]) / + (dt * dt * dt) + end out end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite - @inbounds @.. broadcast=false out=differential_vars * - (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - 12 * y₁) / - (dt * dt * dt) - #for i in eachindex(out) - # out[i] = (6*dt*k[1][i] + 6*dt*k[2][i] + 12*y₀[i] - 12*y₁[i])/(dt*dt*dt) - #end - #out + out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{3}}, differential_vars) + if all(differential_vars) + @inbounds @.. broadcast=false out=(6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - + 12 * y₁) / + (dt * dt * dt) + else + @inbounds @.. broadcast=false out=differential_vars * + (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - + 12 * y₁) / + (dt * dt * dt) + end + out end @muladd function hermite_interpolant!(out::Array, Θ, dt, y₀, y₁, k, idxs::Nothing, - T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite + T::Type{Val{3}}, differential_vars) @inbounds @simd ivdep for i in eachindex(out) out[i] = differential_vars[i] * (6 * dt * k[1][i] + 6 * dt * k[2][i] + 12 * y₀[i] - 12 * y₁[i]) / @@ -1002,13 +1108,20 @@ end end @muladd function hermite_interpolant!( - out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite - @views @.. broadcast=false out=(6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + - 12 * y₀[idxs] - 12 * y₁[idxs]) / (dt * dt * dt) + out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{3}}, differential_vars) + if all(differential_vars) + @views @.. broadcast=false out=(6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + + 12 * y₀[idxs] - 12 * y₁[idxs]) / (dt * dt * dt) + else + @views @.. broadcast=false out=differential_vars * + (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + + 12 * y₀[idxs] - 12 * y₁[idxs]) / (dt * dt * dt) + end + out end @muladd function hermite_interpolant!( - out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{3}}, differential_vars) # Default interpolant is Hermite + out::Array, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{3}}, differential_vars) @inbounds for (j, i) in enumerate(idxs) out[j] = differential_vars[j] * (6 * dt * k[1][i] + 6 * dt * k[2][i] + 12 * y₀[i] - 12 * y₁[i]) / diff --git a/src/dense/interpolants.jl b/src/dense/interpolants.jl index 92ba6650af..9a658997bd 100644 --- a/src/dense/interpolants.jl +++ b/src/dense/interpolants.jl @@ -2947,6 +2947,28 @@ end b4Θ * k4[idxs] + b5Θ * k5[idxs] + b6Θ * k6[idxs]))) end +@muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, + cache::Union{DPRKN6ConstantCache, DPRKN6Cache}, idxs::Number, + T::Type{Val{0}}, differential_vars::Nothing) + @dprkn6pre0 + halfsize = length(y₀) ÷ 2 + if idxs <= halfsize + duprev[idxs] + + dt * Θ * + (bp1Θ * k1[idxs] + bp3Θ * k3[idxs] + + bp4Θ * k4[idxs] + bp5Θ * k5[idxs] + bp6Θ * k6[idxs]) + else + idxs = idxs - halfsize + uprev[idxs] + + dt * Θ * + (duprev[idxs] + + dt * Θ * + (b1Θ * k1[idxs] + + b3Θ * k3[idxs] + + b4Θ * k4[idxs] + b5Θ * k5[idxs] + b6Θ * k6[idxs])) + end +end + @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{DPRKN6ConstantCache, DPRKN6Cache}, idxs::Nothing, T::Type{Val{0}}, differential_vars::Nothing) @@ -2976,25 +2998,28 @@ end cache::Union{DPRKN6ConstantCache, DPRKN6Cache}, idxs, T::Type{Val{0}}, differential_vars::Nothing) @dprkn6pre0 - @inbounds @.. broadcast=false out.x[2]=uprev[idxs] + - dt * Θ * - (duprev[idxs] + - dt * Θ * - (b1Θ * k1[idxs] + - b3Θ * k3[idxs] + - b4Θ * k4[idxs] + b5Θ * k5[idxs] + - b6Θ * k6[idxs])) - @inbounds @.. broadcast=false out.x[1]=duprev[idxs] + - dt * Θ * - (bp1Θ * k1[idxs] + bp3Θ * k3[idxs] + - bp4Θ * k4[idxs] + bp5Θ * k5[idxs] + - bp6Θ * k6[idxs]) - #for (j,i) in enumerate(idxs) - # out.x[2][j] = uprev[i] + dt*Θ*(duprev[i] + dt*Θ*(b1Θ*k1[i] + - # b3Θ*k3[i] + - # b4Θ*k4[i] + b5Θ*k5[i] + b6Θ*k6[i])) - # out.x[1][j] = duprev[i] + dt*Θ*(bp1Θ*k1[i] + bp3Θ*k3[i] + - # bp4Θ*k4[i] + bp5Θ*k5[i] + bp6Θ*k6[i]) - #end + halfsize = length(y₀) ÷ 2 + isfirsthalf = idxs .<= halfsize + secondhalf = idxs .> halfsize + firstidxs = idxs[isfirsthalf] + secondidxs_shifted = idxs[secondhalf] + secondidxs = secondidxs_shifted .- halfsize + + @views @.. broadcast=false out[secondhalf]=uprev[secondidxs] + + dt * Θ * + (duprev[secondidxs] + + dt * Θ * + (b1Θ * k1[secondidxs] + + b3Θ * k3[secondidxs] + + b4Θ * k4[secondidxs] + + b5Θ * k5[secondidxs] + + b6Θ * k6[secondidxs])) + @views @.. broadcast=false out[isfirsthalf]=duprev[firstidxs] + + dt * Θ * + (bp1Θ * k1[firstidxs] + + bp3Θ * k3[firstidxs] + + bp4Θ * k4[firstidxs] + + bp5Θ * k5[firstidxs] + + bp6Θ * k6[firstidxs]) out end diff --git a/src/derivative_utils.jl b/src/derivative_utils.jl index 272482dfc2..82fb00fc6d 100644 --- a/src/derivative_utils.jl +++ b/src/derivative_utils.jl @@ -750,7 +750,8 @@ end if J isa StaticArray && integrator.alg isa Union{ - Rosenbrock23, Rodas23W, Rodas3P, Rodas4, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr} + Rosenbrock23, Rodas23W, Rodas3P, Rodas4, Rodas4P, Rodas4P2, + Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr} W = W_transform ? J - mass_matrix * inv(dtgamma) : dtgamma * J - mass_matrix else @@ -775,7 +776,8 @@ end W_full elseif len !== nothing && integrator.alg isa - Union{Rosenbrock23, Rodas23W, Rodas3P, Rodas4, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr} + Union{Rosenbrock23, Rodas23W, Rodas3P, Rodas4, Rodas4P, + Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr} StaticWOperator(W_full) else DiffEqBase.default_factorize(W_full) @@ -923,7 +925,8 @@ function build_J_W(alg, u, uprev, p, t, dt, f::F, ::Type{uEltypeNoUnits}, len = StaticArrayInterface.known_length(typeof(J)) if len !== nothing && alg isa - Union{Rosenbrock23, Rodas23W, Rodas3P, Rodas4, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr} + Union{Rosenbrock23, Rodas23W, Rodas3P, Rodas4, Rodas4P, + Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr} StaticWOperator(J, false) else ArrayInterface.lu_instance(J) diff --git a/src/derivative_wrappers.jl b/src/derivative_wrappers.jl index 236b9a82b0..13306d9bd2 100644 --- a/src/derivative_wrappers.jl +++ b/src/derivative_wrappers.jl @@ -284,7 +284,6 @@ function build_jac_config(alg, f::F1, uf::F2, du1, uprev, u, tmp, du2, if alg_autodiff(alg) isa AutoForwardDiff _chunksize = get_chunksize(alg) === Val(0) ? nothing : get_chunksize(alg) # SparseDiffEq uses different convection... - T = if standardtag(alg) typeof(ForwardDiff.Tag(OrdinaryDiffEqTag(), eltype(u))) else diff --git a/src/doc_utils.jl b/src/doc_utils.jl new file mode 100644 index 0000000000..ac070d969b --- /dev/null +++ b/src/doc_utils.jl @@ -0,0 +1,140 @@ +""" +Utility function to help generating consistent docstrings across the package. +""" +# TODO we should add a consistency check using the string $name(; $keyword_default) against the standard console output of name() +function generic_solver_docstring(description::String, + name::String, + solver_class::String, + references::String, + keyword_description::String, + keyword_default::String) + if !isempty(keyword_default) + # Chunk string and remove empty lines + kws = split(keyword_default, "\n") + keywords_split = [kw for kw in kws if !isempty(rstrip(kw))] + + # Indent the keywords properly + indentation = repeat(" ", length(name)+3) + # We do not indent the first kw and no newline for the last one + if length(keyword_default) > 1 + keywords_split[1] = keywords_split[1] * "\n" + for i in 2:(length(keywords_split)-1) + keywords_split[i] = indentation * keywords_split[i] * "\n" + end + keywords_split[end] = indentation * keywords_split[end] + end + # Flatten into string + keyword_default = join(keywords_split) + # Remove trailing comma + keyword_default = strip(keyword_default, [',']) + end + start_docstring = !isempty(keyword_default) ? """ + ```julia + $name(; $keyword_default) + ``` + + $solver_class + """ : + """ + ```julia + $name() + ``` + + $solver_class + """ + + keyword_docstring = """ + + ### Keyword Arguments + + $keyword_description + """ + + return start_docstring * description * keyword_docstring * + "## References\n" * references +end + +function explicit_rk_docstring(description::String, + name::String; + references::String = "", + extra_keyword_description::String = "", + extra_keyword_default::String = "") + keyword_default = """ + stage_limiter! = OrdinaryDiffEq.trivial_limiter!, + step_limiter! = OrdinaryDiffEq.trivial_limiter!, + """ * extra_keyword_default + + keyword_default_description = """ + - `stage_limiter!`: function of the form `limiter!(u, integrator, p, t)` + - `step_limiter!`: function of the form `limiter!(u, integrator, p, t)` + """ * extra_keyword_description + + generic_solver_docstring( + description, name, "Explicit Runge-Kutta Method. ", references, + keyword_default_description, keyword_default + ) +end + +function rosenbrock_docstring(description::String, + name::String; + references::String = "", + extra_keyword_description = "", + extra_keyword_default = "", + with_step_limiter = false) + keyword_default = """ + autodiff = Val{true}(), + concrete_jac = nothing, + linsolve = nothing, + precs = DEFAULT_PRECS, + """ * extra_keyword_default + + keyword_default_description = """ + - `autodiff`: boolean to control if the Jacobian should be computed via AD or not + - `concrete_jac`: function of the form `jac!(J, u, p, t)` + - `linsolve`: custom solver for the inner linear systems + - `precs`: custom preconditioner for the inner linear solver + """ * extra_keyword_description + + if with_step_limiter + keyword_default *= "step_limiter! = OrdinaryDiffEq.trivial_limiter!,\n" + keyword_default_description *= "- `step_limiter!`: function of the form `limiter!(u, integrator, p, t)`\n" + end + + generic_solver_docstring( + description, name, "Rosenbrock Method. ", references, + keyword_default_description, keyword_default + ) +end + +function rosenbrock_wanner_docstring(description::String, + name::String; + references::String = "", + extra_keyword_description = "", + extra_keyword_default = "", + with_step_limiter = false) + keyword_default = """ + autodiff = Val{true}(), + concrete_jac = nothing, + linsolve = nothing, + precs = DEFAULT_PRECS, + """ * extra_keyword_default + + keyword_default_description = """ + - `autodiff`: boolean to control if the Jacobian should be computed via AD or not + - `concrete_jac`: function of the form `jac!(J, u, p, t)` + - `linsolve`: custom solver for the inner linear systems + - `precs`: custom preconditioner for the inner linear solver + """ * extra_keyword_description + + if with_step_limiter + keyword_default *= "step_limiter! = OrdinaryDiffEq.trivial_limiter!,\n" + keyword_default_description *= "- `step_limiter!`: function of the form `limiter!(u, integrator, p, t)`\n" + end + + generic_solver_docstring( + description, name, "Rosenbrock-Wanner Method. ", references, + keyword_default_description, keyword_default + ) +end + +# TODO other classes diff --git a/src/generic_rosenbrock.jl b/src/generic_rosenbrock.jl index 44ecf3c2ae..baff366ee6 100644 --- a/src/generic_rosenbrock.jl +++ b/src/generic_rosenbrock.jl @@ -911,16 +911,265 @@ function ROS2Tableau() # 2nd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ - ROS2() - -2nd order stiffly accurate Rosenbrock-Wanner method with 2 internal stages with (Rinf=0). -The embedded method is taken from Kinetic PreProcessor (KPP). -J. G. Verwer et al. (1999): A second-order Rosenbrock method applied to photochemical dispersion problems -More Information at https://doi.org/10.1137/S1064827597326651 -""" ROS2 - - +@doc rosenbrock_wanner_docstring( +""" +An Order 2/3 L-Stable Rosenbrock-W method which is good for very stiff equations with oscillations at low tolerances. 2nd order stiff-aware interpolation. +""", +"Rosenbrock23", +references = """ +- Shampine L.F. and Reichelt M., (1997) The MATLAB ODE Suite, SIAM Journal of +Scientific Computing, 18 (1), pp. 1-22. +""", +with_step_limiter = true) Rosenbrock23 + +@doc rosenbrock_wanner_docstring( +""" +An Order 3/2 A-Stable Rosenbrock-W method which is good for mildly stiff equations without oscillations at low tolerances. Note that this method is prone to instability in the presence of oscillations, so use with caution. 2nd order stiff-aware interpolation. +""", +"Rosenbrock32", +references = """ +- Shampine L.F. and Reichelt M., (1997) The MATLAB ODE Suite, SIAM Journal of +Scientific Computing, 18 (1), pp. 1-22. +""", +with_step_limiter = true) Rosenbrock32 + +@doc rosenbrock_docstring( +""" +3rd order A-stable and stiffly stable Rosenbrock method. Keeps high accuracy on discretizations of nonlinear parabolic PDEs. +""", +"ROS3P", +references = """ +- Lang, J. & Verwer, ROS3P—An Accurate Third-Order Rosenbrock Solver Designed for + Parabolic Problems J. BIT Numerical Mathematics (2001) 41: 731. doi:10.1023/A:1021900219772 +""", +with_step_limiter = true) ROS3P + +@doc rosenbrock_wanner_docstring( +""" +An Order 2/3 L-Stable Rosenbrock-W method for stiff ODEs and DAEs in mass matrix form. 2nd order stiff-aware interpolation and additional error test for interpolation. +""", +"Rodas23W", +references = """ +- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate for dense output and Julia implementation, + In progress. +""", +with_step_limiter = true) Rodas23W + +@doc rosenbrock_wanner_docstring( +""" +A 4th order L-stable Rosenbrock-W method. +""", +"ROS34PW1a") ROS34PW1a + +@doc rosenbrock_wanner_docstring( +""" +A 4th order L-stable Rosenbrock-W method. +""", +"ROS34PW1b") ROS34PW1b + +@doc rosenbrock_wanner_docstring( +""" +A 4th order stiffy accurate Rosenbrock-W method for PDAEs. +""", +"ROS34PW2") ROS34PW2 + +@doc rosenbrock_wanner_docstring( +""" +A 4th order strongly A-stable (Rinf~0.63) Rosenbrock-W method. +""", +"ROS34PW3") ROS34PW3 + +@doc rosenbrock_docstring( +""" +An A-stable 4th order Rosenbrock method. +""", +"RosShamp4", +references = """ +- L. F. Shampine, Implementation of Rosenbrock Methods, ACM Transactions on + Mathematical Software (TOMS), 8: 2, 93-113. doi:10.1145/355993.355994 +""") RosShamp4 + +@doc rosenbrock_docstring( +""" +3rd order A-stable and stiffly stable Rosenbrock method. +""", +"Rodas3", +references = """ +- Steinebach G. Construction of Rosenbrock–Wanner method Rodas5P and numerical benchmarks + within the Julia Differential Equations package. + In: BIT Numerical Mathematics, 63(2), 2023 +""", +with_step_limiter=true) Rodas3 + +@doc rosenbrock_docstring( +""" +3rd order A-stable and stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant +and additional error test for interpolation. Keeps accuracy on discretizations of linear parabolic PDEs. +""", +"Rodas3P", +references = """ +- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate + for dense output and Julia implementation, + In progress. +""", +with_step_limiter=true) Rodas3P + +@doc rosenbrock_docstring( +""" +A 4th order L-stable Rosenbrock method. +""", +"Rodas4", +references = """ +- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and + differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) +""", +with_step_limiter=true) Rodas4 + +@doc rosenbrock_docstring( +""" +A 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant +""", +"Ros4LStab", +references = """ +- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and + differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) +""", +with_step_limiter=true) Ros4LStab + + +@doc rosenbrock_docstring( +""" +A 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant +""", +"Rodas42", +references = """ +- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and + differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) +""", +with_step_limiter=true) Rodas42 + +@doc rosenbrock_wanner_docstring( +""" +4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant. 4th order +on linear parabolic problems and 3rd order accurate on nonlinear parabolic problems (as opposed to +lower if not corrected). +""", +"Rodas4P", +references = """ +- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate + for dense output and Julia implementation, + In progress. +""", +with_step_limiter=true) Rodas4P + +@doc rosenbrock_wanner_docstring( +""" +A 4th order L-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant. 4th order +on linear parabolic problems and 3rd order accurate on nonlinear parabolic problems. It is an improvement +of Roadas4P and in case of inexact Jacobians a second order W method. +""", +"Rodas4P2", +references = """ +- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate + for dense output and Julia implementation, + In progress. +""", +with_step_limiter=true) Rodas4P2 + +@doc rosenbrock_docstring( +""" +A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. +""", +"Rodas5", +references = """ +- Di Marzo G. RODAS5(4) – Méthodes de Rosenbrock d’ordre 5(4) adaptées aux problemes + différentiels-algébriques. MSc mathematics thesis, Faculty of Science, + University of Geneva, Switzerland. +""", +with_step_limiter=true) Rodas5 + +@doc rosenbrock_docstring( +""" +A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. +Has improved stability in the adaptive time stepping embedding. +""", +"Rodas5P", +references = """ +- Steinebach G. Construction of Rosenbrock–Wanner method Rodas5P and numerical benchmarks + within the Julia Differential Equations package. + In: BIT Numerical Mathematics, 63(2), 2023 +""", +with_step_limiter=true) Rodas5P + +@doc rosenbrock_docstring( +""" +A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. +Has improved stability in the adaptive time stepping embedding. +""", +"Rodas5Pr", +references = """ +- Steinebach G. Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications - + Preprint 2024 + https://github.com/hbrs-cse/RosenbrockMethods/blob/main/paper/JuliaPaper.pdf +""", +with_step_limiter=true) Rodas5Pr + +@doc rosenbrock_docstring( +""" +A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. +Has improved stability in the adaptive time stepping embedding. +""", +"Rodas5Pe", +references = """ +- Steinebach G. Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications - + Preprint 2024 + https://github.com/hbrs-cse/RosenbrockMethods/blob/main/paper/JuliaPaper.pdf +""", +with_step_limiter=true) Rodas5Pe + +@doc rosenbrock_docstring( +""" +An efficient 4th order Rosenbrock method. +""", +"GRK4T", +references = """ +- Kaps, P. & Rentrop, Generalized Runge-Kutta methods of order four with stepsize control + for stiff ordinary differential equations. P. Numer. Math. (1979) 33: 55. doi:10.1007/BF01396495 +""", +with_step_limiter=true) GRK4T + +@doc rosenbrock_docstring( +""" +An A-stable 4th order Rosenbrock method. Essentially "anti-L-stable" but efficient. +""", +"GRK4A", +references = """ +- Kaps, P. & Rentrop, Generalized Runge-Kutta methods of order four with stepsize control + for stiff ordinary differential equations. P. Numer. Math. (1979) 33: 55. doi:10.1007/BF01396495 +""", +with_step_limiter=true) GRK4A + +@doc rosenbrock_docstring( +""" +A 4th order D-stable Rosenbrock method. +""", +"Veldd4", +references = """ +- van Veldhuizen, D-stability and Kaps-Rentrop-methods, M. Computing (1984) 32: 229. + doi:10.1007/BF02243574 +""", +with_step_limiter=true) Veldd4 + +@doc rosenbrock_docstring( +""" +A 4th order A-stable Rosenbrock method. +""", +"Velds4", +references = """ +- van Veldhuizen, D-stability and Kaps-Rentrop-methods, M. Computing (1984) 32: 229. + doi:10.1007/BF02243574 +""", +with_step_limiter=true) Velds4 """ @ROS2(part) @@ -961,7 +1210,15 @@ macro ROS2(part) end end - +@doc rosenbrock_wanner_docstring( +""" +A 2nd order L-stable Rosenbrock-Wanner method with 2 internal stages. +""", +"ROS2", +references = """ +- J. G. Verwer et al. (1999): A second-order Rosenbrock method applied to photochemical dispersion problems + https://doi.org/10.1137/S1064827597326651 +""") ROS2 # 3 step ROS Methods """ @@ -988,12 +1245,19 @@ function ROS2PRTableau() # 2nd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ +@doc rosenbrock_wanner_docstring( +""" 2nd order stiffly accurate Rosenbrock-Wanner method with 3 internal stages with (Rinf=0). For problems with medium stiffness the convergence behaviour is very poor and it is recommended to use [`ROS2S`](@ref) instead. -More Information at https://doi.org/10.24355/dbbs.084-201408121139-0 -""" ROS2PR +""", +"ROS2PR", +references = """ +- Rang, Joachim (2014): The Prothero and Robinson example: + Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. + https://doi.org/10.24355/dbbs.084-201408121139-0 +""") +ROS2PR @@ -1020,10 +1284,17 @@ function ROS2STableau() # 2nd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ +@doc rosenbrock_wanner_docstring( +""" 2nd order stiffly accurate Rosenbrock-Wanner W-method with 3 internal stages with B_PR consistent of order 2 with (Rinf=0). -More Information at https://doi.org/10.24355/dbbs.084-201408121139-0 -""" ROS2S +""", +"ROS2S", +references = """ +- Rang, Joachim (2014): The Prothero and Robinson example: + Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. + https://doi.org/10.24355/dbbs.084-201408121139-0 +""") +ROS2S """ @@ -1047,10 +1318,16 @@ function ROS3Tableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ -3rd order L-stable Rosenbrock-Wanner method with 3 internal stages with an embedded strongly A-stable 2nd order method -More Information at https://link.springer.com/book/10.1007/978-3-662-09947-6 -""" ROS3 +@doc rosenbrock_wanner_docstring( +""" +3rd order L-stable Rosenbrock-Wanner method with 3 internal stages with an embedded strongly +A-stable 2nd order method. +""", +"ROS3", +references = """ +- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and + differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) +""") ROS3 """ @@ -1075,10 +1352,18 @@ function ROS3PRTableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ +@doc rosenbrock_wanner_docstring( +""" 3nd order stiffly accurate Rosenbrock-Wanner method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73. -More Information at https://doi.org/10.24355/dbbs.084-201408121139-0 -""" ROS3PR +""", +"ROS3PR", +references = """ +- Rang, Joachim (2014): The Prothero and Robinson example: + Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. + https://doi.org/10.24355/dbbs.084-201408121139-0 +""") ROS3PR + + """ Scholz4_7Tableau() @@ -1103,11 +1388,17 @@ function Scholz4_7Tableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ -3nd order stiffly accurate Rosenbrock-Wanner method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73 +@doc rosenbrock_wanner_docstring( +""" +3nd order stiffly accurate Rosenbrock-Wanner method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73. Convergence with order 4 for the stiff case, but has a poor accuracy. -More Information at https://doi.org/10.24355/dbbs.084-201408121139-0 -""" Scholz4_7 +""", +"Scholz4_7", +references = """ +- Rang, Joachim (2014): The Prothero and Robinson example: + Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. + https://doi.org/10.24355/dbbs.084-201408121139-0 +""") Scholz4_7 """ @@ -1288,12 +1579,18 @@ function ROS34PRwTableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ +@doc rosenbrock_wanner_docstring( +""" 3rd order stiffly accurate Rosenbrock-Wanner W-method with 4 internal stages, B_PR consistent of order 2. The order of convergence decreases if medium stiff problems are considered. -More Information at https://doi.org/10.1016/j.cam.2015.03.010 -""" ROS34PRw +""", +"ROS34PRw", +references = """ +- Joachim Rang, Improved traditional Rosenbrock–Wanner methods for stiff ODEs and DAEs, + Journal of Computational and Applied Mathematics, + https://doi.org/10.1016/j.cam.2015.03.010 +""") ROS34PRw """ ROS3PRLTableau() @@ -1321,12 +1618,18 @@ function ROS3PRLTableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ +@doc rosenbrock_wanner_docstring( +""" 3rd order stiffly accurate Rosenbrock-Wanner method with 4 internal stages, B_PR consistent of order 2 with Rinf=0. The order of convergence decreases if medium stiff problems are considered, but it has good results for very stiff cases. -More Information at https://doi.org/10.24355/dbbs.084-201408121139-0 -""" ROS3PRL +""", +"ROS3PRL", +references = """ +- Rang, Joachim (2014): The Prothero and Robinson example: + Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. + https://doi.org/10.24355/dbbs.084-201408121139-0 +""") ROS3PRL """ @@ -1355,12 +1658,18 @@ function ROS3PRL2Tableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc """ +@doc rosenbrock_wanner_docstring( +""" 3rd order stiffly accurate Rosenbrock-Wanner method with 4 internal stages, B_PR consistent of order 3. The order of convergence does NOT decreases if medium stiff problems are considered as it does for [`ROS3PRL`](@ref). -More Information at https://doi.org/10.24355/dbbs.084-201408121139-0 -""" ROS3PRL2 +""", +"ROS3PRL2", +references = """ +- Rang, Joachim (2014): The Prothero and Robinson example: + Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. + https://doi.org/10.24355/dbbs.084-201408121139-0 +""") ROS3PRL2 diff --git a/src/initdt.jl b/src/initdt.jl index 0b9895ec3f..d8777e898a 100644 --- a/src/initdt.jl +++ b/src/initdt.jl @@ -44,11 +44,11 @@ else # TODO: use more caches if u0 isa Array && eltype(u0) isa Number - T = eltype(first(u0) / t) + T = eltype(first(u0) / oneunit_tType) f₀ = similar(u0, T) fill!(f₀, zero(T)) else - f₀ = zero.(u0 ./ t) + f₀ = zero.(u0 ./ oneunit_tType) end f(f₀, u0, p, t) end diff --git a/src/initialize_dae.jl b/src/initialize_dae.jl index a12b68b455..9404d9531f 100644 --- a/src/initialize_dae.jl +++ b/src/initialize_dae.jl @@ -528,9 +528,10 @@ function _initialize_dae!(integrator, prob::ODEProblem, if isAD csize = count(algebraic_vars) if !(p isa SciMLBase.NullParameters) && typeof(_u) !== typeof(u) - try + if isscimlstructure(p) + csize = max(csize, length(canonicalize(Tunable(), p)[1])) + else csize = max(csize, length(p)) - catch end end chunk = ForwardDiff.pickchunksize(csize) diff --git a/src/integrators/integrator_interface.jl b/src/integrators/integrator_interface.jl index b5df01e109..4ba6935cb3 100644 --- a/src/integrators/integrator_interface.jl +++ b/src/integrators/integrator_interface.jl @@ -180,14 +180,35 @@ end cache::CompositeCache) get_tmp_cache(integrator, integrator.alg.algs[1], cache.caches[1]) end +@inline function DiffEqBase.get_tmp_cache(integrator, alg::CompositeAlgorithm, + cache::DefaultCache) + get_tmp_cache(integrator, integrator.alg.algs[1], cache.cache1) +end @inline function DiffEqBase.get_tmp_cache(integrator, alg::DAEAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.nlsolver.cache.dz, cache.atmp) end -full_cache(integrator::ODEIntegrator) = full_cache(integrator.cache) -function full_cache(integrator::CompositeCache) - Iterators.flatten(full_cache(c) for c in integrator.caches) +function full_cache(integrator::ODEIntegrator) + # for DefaultCache, we need to make sure to initialize all the caches in case they get switched to later + if integrator.cache isa DefaultCache + @unpack alg, cache = integrator + algs = alg.algs + init_ith_default_cache(cache, algs, 1) + init_ith_default_cache(cache, algs, 2) + init_ith_default_cache(cache, algs, 3) + init_ith_default_cache(cache, algs, 4) + init_ith_default_cache(cache, algs, 5) + init_ith_default_cache(cache, algs, 6) + end + full_cache(integrator.cache) +end +function full_cache(cache::CompositeCache) + Iterators.flatten(full_cache(c) for c in cache.caches) +end +function full_cache(cache::DefaultCache) + caches = (cache.cache1, cache.cache2, cache.cache3, cache.cache4, cache.cache5, cache.cache6) + Iterators.flatten(full_cache(c) for c in caches) end function DiffEqBase.add_tstop!(integrator::ODEIntegrator, t) @@ -209,7 +230,7 @@ end function resize!(integrator::ODEIntegrator, i::Int) @unpack cache = integrator - for c in full_cache(cache) + for c in full_cache(integrator) # Skip nothings which may exist in the cache since extra variables # may be required for things like units c !== nothing && resize!(c, i) diff --git a/src/integrators/integrator_utils.jl b/src/integrators/integrator_utils.jl index 67d9ee0593..0527d3f425 100644 --- a/src/integrators/integrator_utils.jl +++ b/src/integrators/integrator_utils.jl @@ -381,8 +381,6 @@ function update_uprev!(integrator) end function apply_step!(integrator) - integrator.accept_step = false # yay we got here, don't need this no more - update_uprev!(integrator) #Update dt if adaptive or if fixed and the dt is allowed to change @@ -489,7 +487,9 @@ function reset_fsal!(integrator) if !(integrator.sol.prob isa DAEProblem) if integrator.cache isa OrdinaryDiffEqMutableCache || (integrator.cache isa CompositeCache && - integrator.cache.caches[1] isa OrdinaryDiffEqMutableCache) + integrator.cache.caches[1] isa OrdinaryDiffEqMutableCache) || + (integrator.cache isa DefaultCache && + integrator.cache.cache1 isa OrdinaryDiffEqMutableCache) integrator.f(integrator.fsalfirst, integrator.u, integrator.p, integrator.t) else integrator.fsalfirst = integrator.f(integrator.u, integrator.p, integrator.t) diff --git a/src/misc_utils.jl b/src/misc_utils.jl index aab109f6c6..c1a55741a0 100644 --- a/src/misc_utils.jl +++ b/src/misc_utils.jl @@ -188,7 +188,7 @@ function get_differential_vars(f, u) mm = f.mass_matrix mm = mm isa MatrixOperator ? mm.A : mm - if mm isa UniformScaling + if mm isa UniformScaling || all(!iszero, mm) return nothing elseif !(mm isa SciMLOperators.AbstractSciMLOperator) && isdiag(mm) differential_vars = reshape(diag(mm) .!= 0, size(u)) diff --git a/src/nlsolve/newton.jl b/src/nlsolve/newton.jl index 2482b41a49..3d4cff337f 100644 --- a/src/nlsolve/newton.jl +++ b/src/nlsolve/newton.jl @@ -25,8 +25,100 @@ end nothing end +function initialize!(nlsolver::NLSolver{<:NonlinearSolveAlg, false}, + integrator::DiffEqBase.DEIntegrator) + @unpack uprev, t, p, dt, opts, f = integrator + @unpack z, tmp, ztmp, γ, α, iter, cache, method, alg = nlsolver + cache.invγdt = inv(dt * nlsolver.γ) + cache.tstep = integrator.t + nlsolver.c * dt + + @unpack ustep, tstep, k, invγdt = cache + if DiffEqBase.has_stats(integrator) + integrator.stats.nf += cache.cache.nf + integrator.stats.nnonliniter += cache.cache.nsteps + integrator.stats.njacs += cache.cache.jac_cache.njacs + end + if f isa DAEFunction + nlp_params = (tmp, α, tstep, invγdt, p, dt, uprev, f) + else + nlp_params = (tmp, γ, α, tstep, invγdt, method, p, dt, f) + end + new_prob = remake(cache.prob, p = nlp_params, u0 = z) + cache.cache = init(new_prob, alg.alg) + nothing +end + +function initialize!(nlsolver::NLSolver{<:NonlinearSolveAlg, true}, + integrator::DiffEqBase.DEIntegrator) + @unpack uprev, t, p, dt, opts, f = integrator + @unpack z, tmp, ztmp, γ, α, iter, cache, method, alg = nlsolver + + cache.invγdt = inv(dt * nlsolver.γ) + cache.tstep = integrator.t + nlsolver.c * dt + + @unpack ustep, tstep, k, invγdt = cache + + if DiffEqBase.has_stats(integrator) + integrator.stats.nf += cache.cache.nf + integrator.stats.nnonliniter += cache.cache.nsteps + integrator.stats.njacs += cache.cache.jac_cache.njacs + end + if f isa DAEFunction + nlp_params = (tmp, ztmp, ustep, γ, α, tstep, k, invγdt, p, dt, f) + else + nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, method, p, dt, f) + end + new_prob = remake(cache.prob, p = nlp_params, u0 = z) + cache.cache = init(new_prob, alg.alg) + nothing +end + ## compute_step! +@muladd function compute_step!(nlsolver::NLSolver{<:NonlinearSolveAlg, false}, integrator) + @unpack uprev, t, p, dt, opts = integrator + @unpack z, tmp, ztmp, γ, α, cache, method = nlsolver + @unpack tstep, invγdt = cache + + nlcache = nlsolver.cache.cache + step!(nlcache) + nlsolver.ztmp = nlcache.u + + ustep = compute_ustep(tmp, γ, z, method) + atmp = calculate_residuals(nlcache.fu, uprev, ustep, opts.abstol, opts.reltol, + opts.internalnorm, t) + ndz = opts.internalnorm(atmp, t) + #ndz = opts.internalnorm(nlcache.fu, t) + # NDF and BDF are special because the truncation error is directly + # proportional to the total displacement. + if integrator.alg isa QNDF + ndz *= error_constant(integrator, alg_order(integrator.alg)) + end + return ndz +end + +@muladd function compute_step!(nlsolver::NLSolver{<:NonlinearSolveAlg, true}, integrator) + @unpack uprev, t, p, dt, opts = integrator + @unpack z, tmp, ztmp, γ, α, cache, method = nlsolver + @unpack tstep, invγdt, atmp, ustep = cache + + nlcache = nlsolver.cache.cache + step!(nlcache) + @.. broadcast=false ztmp=nlcache.u + + ustep = compute_ustep!(ustep, tmp, γ, z, method) + calculate_residuals!(atmp, nlcache.fu, uprev, ustep, opts.abstol, opts.reltol, + opts.internalnorm, t) + ndz = opts.internalnorm(atmp, t) + #ndz = opts.internalnorm(nlcache.fu, t) + # NDF and BDF are special because the truncation error is directly + # proportional to the total displacement. + if integrator.alg isa QNDF + ndz *= error_constant(integrator, alg_order(integrator.alg)) + end + ndz +end + """ compute_step!(nlsolver::NLSolver{<:NLNewton}, integrator) @@ -51,12 +143,17 @@ Equations II, Springer Series in Computational Mathematics. ISBN """ @muladd function compute_step!(nlsolver::NLSolver{<:NLNewton, false}, integrator, γW) @unpack uprev, t, p, dt, opts = integrator - @unpack z, tmp, γ, α, cache = nlsolver + @unpack z, tmp, ztmp, γ, α, cache, method = nlsolver @unpack tstep, W, invγdt = cache f = nlsolve_f(integrator) - ztmp, ustep = _compute_rhs(nlsolver, integrator, f, z) + if f isa DAEFunction + _uprev = get_dae_uprev(integrator, uprev) + ztmp, ustep = _compute_rhs(tmp, α, tstep, invγdt, p, _uprev, f, z) + else + ztmp, ustep = _compute_rhs(tmp, γ, α, tstep, invγdt, method, p, dt, f, z) + end if DiffEqBase.has_stats(integrator) integrator.stats.nf += 1 @@ -68,7 +165,6 @@ Equations II, Springer Series in Computational Mathematics. ISBN elseif W isa AbstractSciMLOperator error("Non-concrete Jacobian not yet supported by out-of-place Newton solve.") end - dz = _reshape(W \ _vec(ztmp), axes(ztmp)) dz = relax(dz, nlsolver, integrator, f) if DiffEqBase.has_stats(integrator) @@ -92,7 +188,7 @@ end @muladd function compute_step!(nlsolver::NLSolver{<:NLNewton, true}, integrator, γW) @unpack uprev, t, p, dt, opts = integrator - @unpack z, tmp, ztmp, γ, α, iter, cache = nlsolver + @unpack z, tmp, ztmp, γ, α, iter, cache, method = nlsolver @unpack W_γdt, ustep, tstep, k, atmp, dz, W, new_W, invγdt, linsolve, weight = cache f = nlsolve_f(integrator) @@ -102,7 +198,13 @@ end integrator.stats.nf += 1 end - b, ustep = _compute_rhs!(nlsolver, integrator, f, z) + if isdae + _uprev = get_dae_uprev(integrator, uprev) + b, ustep = _compute_rhs!(tmp, ztmp, ustep, α, tstep, k, invγdt, p, _uprev, f, z) + else + b, ustep = _compute_rhs!( + tmp, ztmp, ustep, γ, α, tstep, k, invγdt, method, p, dt, f, z) + end # update W if W isa Union{WOperator, StaticWOperator} @@ -137,11 +239,7 @@ end # Diagonally Implicit Runge-Kutta Methods for Ordinary Differential # Equations. A Review, by Christopher A. Kennedy and Mark H. Carpenter # page 54. - if isdae - γdt = α * invγdt - else - γdt = γ * dt - end + γdt = isdae ? α * invγdt : γ * dt !(W_γdt ≈ γdt) && (rmul!(dz, 2 / (1 + γdt / W_γdt))) relax!(dz, nlsolver, integrator, f) @@ -165,17 +263,21 @@ end integrator, γW) @unpack uprev, t, p, dt, opts = integrator - @unpack z, tmp, ztmp, γ, α, iter, cache = nlsolver + @unpack z, tmp, ztmp, γ, α, iter, cache, method = nlsolver @unpack W_γdt, ustep, tstep, k, atmp, dz, W, new_W, invγdt, linsolve, weight = cache f = nlsolve_f(integrator) isdae = f isa DAEFunction - if DiffEqBase.has_stats(integrator) integrator.stats.nf += 1 end - b, ustep = _compute_rhs!(nlsolver, integrator, f, z) - + if isdae + _uprev = get_dae_uprev(integrator, uprev) + b, ustep = _compute_rhs!(tmp, ztmp, ustep, α, tstep, k, invγdt, p, _uprev, f, z) + else + b, ustep = _compute_rhs!( + tmp, ztmp, ustep, γ, α, tstep, k, invγdt, method, p, dt, f, z) + end # update W if W isa Union{WOperator, StaticWOperator} update_coefficients!(W, ustep, p, tstep) @@ -209,11 +311,7 @@ end # Diagonally Implicit Runge-Kutta Methods for Ordinary Differential # Equations. A Review, by Christopher A. Kennedy and Mark H. Carpenter # page 54. - if isdae - γdt = α * invγdt - else - γdt = γ * dt - end + γdt = isdae ? α * invγdt : γ * dt !(W_γdt ≈ γdt) && (rmul!(dz, 2 / (1 + γdt / W_γdt))) relax!(dz, nlsolver, integrator, f) @@ -235,148 +333,142 @@ end ndz end -@inline function _compute_rhs(nlsolver::NLSolver{<:NLNewton, false}, integrator, f::TF, - z) where {TF} - @unpack uprev, t, p, dt = integrator - @unpack tmp, ztmp, γ, α, cache = nlsolver - @unpack tstep, invγdt = cache - isdae = TF <: DAEFunction - if isdae - # not all predictors are uprev, for other forms of predictors, defined in u₀ - if isdefined(integrator.cache, :u₀) - ustep = @.. broadcast=false integrator.cache.u₀+z +function get_dae_uprev(integrator, uprev) + # not all predictors are uprev, for other forms of predictors, defined in u₀ + if isdefined(integrator.cache, :u₀) + integrator.cache.u₀ + else + uprev + end +end + +function _compute_rhs(tmp, α, tstep, invγdt, p, uprev, f::TF, z) where {TF <: DAEFunction} + ustep = @.. uprev + z + dustep = @. (tmp + α * z) * invγdt + ztmp = f(dustep, ustep, p, tstep) + return ztmp, ustep +end + +function compute_ustep(tmp, γ, z, method) + if method === COEFFICIENT_MULTISTEP + z + else + @. tmp + γ * z + end +end + +function compute_ustep!(ustep, tmp, γ, z, method) + if method === COEFFICIENT_MULTISTEP + ustep = z + else + @.. ustep = tmp + γ * z + end + ustep +end + +function _compute_rhs(tmp, γ, α, tstep, invγdt, method::MethodType, p, dt, f, z) + mass_matrix = f.mass_matrix + ustep = compute_ustep(tmp, γ, z, method) + if method === COEFFICIENT_MULTISTEP + # tmp = outertmp ./ hγ + if mass_matrix === I + ztmp = tmp .+ f(z, p, tstep) .- (α * invγdt) .* z else - ustep = @.. broadcast=false uprev+z + update_coefficients!(mass_matrix, ustep, p, tstep) + ztmp = tmp .+ f(z, p, tstep) .- (mass_matrix * z) .* (α * invγdt) end - dustep = @. (tmp + α * z) * invγdt - ztmp = f(dustep, ustep, p, t) else - mass_matrix = integrator.f.mass_matrix - if nlsolver.method === COEFFICIENT_MULTISTEP - ustep = z - # tmp = outertmp ./ hγ - if mass_matrix === I - ztmp = tmp .+ f(z, p, tstep) .- (α * invγdt) .* z - else - update_coefficients!(mass_matrix, ustep, p, tstep) - ztmp = tmp .+ f(z, p, tstep) .- (mass_matrix * z) .* (α * invγdt) - end + if mass_matrix === I + ztmp = (dt * f(ustep, p, tstep) - z) * invγdt else - ustep = @. tmp + γ * z - if mass_matrix === I - ztmp = (dt * f(ustep, p, tstep) - z) * invγdt - else - update_coefficients!(mass_matrix, ustep, p, tstep) - ztmp = (dt * f(ustep, p, tstep) - mass_matrix * z) * invγdt - end + update_coefficients!(mass_matrix, ustep, p, tstep) + ztmp = (dt * f(ustep, p, tstep) - mass_matrix * z) * invγdt end end return ztmp, ustep end -@inline function _compute_rhs!(nlsolver::NLSolver{<:NLNewton, true}, integrator, f::TF, - z) where {TF} - @unpack uprev, t, p, dt = integrator - @unpack tmp, ztmp, γ, α, cache = nlsolver - @unpack ustep, tstep, k, invγdt = cache - isdae = TF <: DAEFunction - b = if isdae - @.. broadcast=false ztmp=(tmp + α * z) * invγdt - # not all predictors are uprev, for other forms of predictors, defined in u₀ - if isdefined(integrator.cache, :u₀) - @.. broadcast=false ustep=integrator.cache.u₀ + z +function _compute_rhs!(tmp, ztmp, ustep, α, tstep, k, + invγdt, p, uprev, f::TF, z) where {TF <: DAEFunction} + @.. broadcast=false ztmp=(tmp + α * z) * invγdt + @.. ustep = uprev + z + f(k, ztmp, ustep, p, tstep) + return _vec(k), ustep +end + +function _compute_rhs!(tmp, ztmp, ustep, γ, α, tstep, k, + invγdt, method::MethodType, p, dt, f, z) + mass_matrix = f.mass_matrix + ustep = compute_ustep!(ustep, tmp, γ, z, method) + if method === COEFFICIENT_MULTISTEP + f(k, z, p, tstep) + if mass_matrix === I + @.. broadcast=false ztmp=tmp + k - (α * invγdt) * z else - @.. broadcast=false ustep=uprev + z + update_coefficients!(mass_matrix, ustep, p, tstep) + mul!(_vec(ztmp), mass_matrix, _vec(z)) + @.. broadcast=false ztmp=tmp + k - (α * invγdt) * ztmp end - f(k, ztmp, ustep, p, tstep) - _vec(k) else - mass_matrix = integrator.f.mass_matrix - if nlsolver.method === COEFFICIENT_MULTISTEP - ustep = z - f(k, z, p, tstep) - if mass_matrix === I - @.. broadcast=false ztmp=tmp + k - (α * invγdt) * z - else - update_coefficients!(mass_matrix, ustep, p, tstep) - mul!(_vec(ztmp), mass_matrix, _vec(z)) - @.. broadcast=false ztmp=tmp + k - (α * invγdt) * ztmp - end + f(k, ustep, p, tstep) + if mass_matrix === I + @.. ztmp = (dt * k - z) * invγdt else - @.. broadcast=false ustep=tmp + γ * z - f(k, ustep, p, tstep) - if mass_matrix === I - @.. broadcast=false ztmp=(dt * k - z) * invγdt - else - update_coefficients!(mass_matrix, ustep, p, tstep) - mul!(_vec(ztmp), mass_matrix, _vec(z)) - @.. broadcast=false ztmp=(dt * k - ztmp) * invγdt - end + update_coefficients!(mass_matrix, ustep, p, tstep) + mul!(_vec(ztmp), mass_matrix, _vec(z)) + @.. ztmp = (dt * k - ztmp) * invγdt end - _vec(ztmp) end - return b, ustep + return _vec(ztmp), ustep end -@inline function _compute_rhs!(nlsolver::NLSolver{<:NLNewton, true, <:Array}, integrator, - f::TF, z) where {TF} - @unpack uprev, t, p, dt = integrator - @unpack tmp, ztmp, γ, α, cache = nlsolver - @unpack ustep, tstep, k, invγdt = cache - isdae = TF <: DAEFunction - b = if isdae - @inbounds @simd ivdep for i in eachindex(z) - ztmp[i] = (tmp[i] + α * z[i]) * invγdt - end - if isdefined(integrator.cache, :u₀) +function _compute_rhs!(tmp::Array, ztmp::Array, ustep::Array, α, tstep, k, + invγdt, p, uprev, f::TF, z) where {TF <: DAEFunction} + @inbounds @simd ivdep for i in eachindex(z) + ztmp[i] = (tmp[i] + α * z[i]) * invγdt + end + @inbounds @simd ivdep for i in eachindex(z) + ustep[i] = uprev[i] + z[i] + end + f(k, ztmp, ustep, p, tstep) + + return _vec(k), ustep +end + +function _compute_rhs!(tmp::Array, ztmp::Array, ustep::Array, γ, α, tstep, k, + invγdt, method::MethodType, p, dt, f, z) + mass_matrix = f.mass_matrix + ustep = compute_ustep!(ustep, tmp, γ, z, method) + if method === COEFFICIENT_MULTISTEP + f(k, z, p, tstep) + if mass_matrix === I @inbounds @simd ivdep for i in eachindex(z) - ustep[i] = integrator.cache.u₀[i] + z[i] + ztmp[i] = tmp[i] + k[i] - (α * invγdt) * z[i] end - #@.. broadcast=false ustep = integrator.cache.u₀ + z else + update_coefficients!(mass_matrix, ustep, p, tstep) + mul!(_vec(ztmp), mass_matrix, _vec(z)) + @inbounds @simd ivdep for i in eachindex(z) - ustep[i] = uprev[i] + z[i] + ztmp[i] = tmp[i] + k[i] - (α * invγdt) * ztmp[i] end end - f(k, ztmp, ustep, p, tstep) - _vec(k) else - mass_matrix = integrator.f.mass_matrix - if nlsolver.method === COEFFICIENT_MULTISTEP - ustep = z - f(k, z, p, tstep) - if mass_matrix === I - @inbounds @simd ivdep for i in eachindex(z) - ztmp[i] = tmp[i] + k[i] - (α * invγdt) * z[i] - end - else - update_coefficients!(mass_matrix, ustep, p, tstep) - mul!(_vec(ztmp), mass_matrix, _vec(z)) - - @inbounds @simd ivdep for i in eachindex(z) - ztmp[i] = tmp[i] + k[i] - (α * invγdt) * ztmp[i] - end + f(k, ustep, p, tstep) + if mass_matrix === I + @inbounds @simd ivdep for i in eachindex(z) + ztmp[i] = (dt * k[i] - z[i]) * invγdt end else + update_coefficients!(mass_matrix, ustep, p, tstep) + mul!(_vec(ztmp), mass_matrix, _vec(z)) @inbounds @simd ivdep for i in eachindex(z) - ustep[i] = tmp[i] + γ * z[i] - end - f(k, ustep, p, tstep) - if mass_matrix === I - @inbounds @simd ivdep for i in eachindex(z) - ztmp[i] = (dt * k[i] - z[i]) * invγdt - end - else - update_coefficients!(mass_matrix, ustep, p, tstep) - mul!(_vec(ztmp), mass_matrix, _vec(z)) - @inbounds @simd ivdep for i in eachindex(z) - ztmp[i] = (dt * k[i] - ztmp[i]) * invγdt - end + ztmp[i] = (dt * k[i] - ztmp[i]) * invγdt end end - _vec(ztmp) end - return b, ustep + + return _vec(ztmp), ustep end ## relax! @@ -401,12 +493,19 @@ function relax!(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, f = f, linesearch = linesearch - @unpack uprev, t, p, dt, opts = integrator - @unpack z, tmp, ztmp, γ, iter, cache = nlsolver - @unpack ustep, atmp = cache + @unpack uprev, t, p, dt, opts, isdae = integrator + @unpack z, tmp, ztmp, γ, iter, α, cache, method = nlsolver + @unpack ustep, atmp, tstep, k, invγdt, tstep, k, invγdt = cache function resid(z) # recompute residual (rhs) - b, ustep2 = _compute_rhs!(nlsolver, integrator, f, z) + if isdae + _uprev = get_dae_uprev(integrator, uprev) + b, ustep2 = _compute_rhs!( + tmp, ztmp, ustep, α, tstep, k, invγdt, p, _uprev, f::TF, z) + else + b, ustep2 = _compute_rhs!( + tmp, ztmp, ustep, γ, α, tstep, k, invγdt, method, p, dt, f, z) + end calculate_residuals!(atmp, b, uprev, ustep2, opts.abstol, opts.reltol, opts.internalnorm, t) ndz = opts.internalnorm(atmp, t) @@ -456,7 +555,12 @@ function relax(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, @unpack z, tmp, ztmp, γ, iter, cache = nlsolver function resid(z) # recompute residual (rhs) - b, ustep2 = _compute_rhs(nlsolver, integrator, f, z) + if f isa DAEFunction + _uprev = get_dae_uprev(integrator, uprev) + ztmp, ustep2 = _compute_rhs(tmp, α, tstep, invγdt, p, dt, _uprev, f, z) + else + ztmp, ustep2 = _compute_rhs(tmp, γ, α, tstep, invγdt, method, p, f, z) + end atmp = calculate_residuals(b, uprev, ustep2, opts.abstol, opts.reltol, opts.internalnorm, t) ndz = opts.internalnorm(atmp, t) diff --git a/src/nlsolve/type.jl b/src/nlsolve/type.jl index d964a41615..2b299b35cd 100644 --- a/src/nlsolve/type.jl +++ b/src/nlsolve/type.jl @@ -65,6 +65,28 @@ function NLNewton(; κ = 1 // 100, max_iter = 10, fast_convergence_cutoff = 1 // relax) end +struct NonlinearSolveAlg{K, C1, C2, A} <: AbstractNLSolverAlgorithm + κ::K + max_iter::Int + fast_convergence_cutoff::C1 + new_W_dt_cutoff::C2 + always_new::Bool + check_div::Bool + alg::A +end + +function NonlinearSolveAlg(alg = NewtonRaphson(autodiff = AutoFiniteDiff()); + κ = 1 // 100, max_iter = 10, fast_convergence_cutoff = 1 // 5, + new_W_dt_cutoff = 1 // 5, always_new = false, check_div = true) + if relax isa Number && !(0 <= relax < 1) + throw(ArgumentError("The relaxation parameter must be in [0, 1), got `relax = $relax`")) + end + + NonlinearSolveAlg( + κ, max_iter, fast_convergence_cutoff, new_W_dt_cutoff, always_new, check_div, + alg) +end + # solver abstract type AbstractNLSolver{algType, iip} end @@ -99,17 +121,12 @@ function NLSolver{iip, tType}(z, tmp, ztmp, γ, c, α, alg, κ, fast_convergence tmp2, ztmp, γ, - convert(tType, - c), - convert(tType, - α), + convert(tType, c), + convert(tType, α), alg, - convert(tType, - κ), - convert(tType, - fast_convergence_cutoff), - convert(tType, - ηold), + convert(tType, κ), + convert(tType, fast_convergence_cutoff), + convert(tType, ηold), iter, maxiters, status, @@ -214,3 +231,14 @@ mutable struct NLAndersonConstantCache{uType, tType, uEltypeNoUnits} <: aa_start::Int droptol::Union{Nothing, tType} end + +mutable struct NonlinearSolveCache{uType, tType, rateType, tType2, P, C} <: + AbstractNLSolverCache + ustep::uType + tstep::tType + k::rateType + atmp::uType + invγdt::tType2 + prob::P + cache::C +end diff --git a/src/nlsolve/utils.jl b/src/nlsolve/utils.jl index b2515d6340..3ab9ae22ba 100644 --- a/src/nlsolve/utils.jl +++ b/src/nlsolve/utils.jl @@ -147,8 +147,9 @@ function build_nlsolver(alg, u, uprev, p, t, dt, f::F, rate_prototype, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, α, iip) end -function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u, uprev, p, - t, dt, +function build_nlsolver( + alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton, NonlinearSolveAlg}, + u, uprev, p, t, dt, f::F, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, γ, c, α, @@ -172,7 +173,7 @@ function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u atmp = similar(u, uEltypeNoUnits) dz = zero(u) - if nlalg isa NLNewton + if nlalg isa Union{NLNewton, NonlinearSolveAlg} nf = nlsolve_f(f, alg) J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) @@ -204,9 +205,31 @@ function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u tType = typeof(t) invγdt = inv(oneunit(t) * one(uTolType)) - nlcache = NLNewtonCache(ustep, tstep, k, atmp, dz, J, W, true, true, true, - tType(dt), du1, uf, jac_config, - linsolve, weight, invγdt, tType(nlalg.new_W_dt_cutoff), t) + if nlalg isa NonlinearSolveAlg + α = tTypeNoUnits(α) + dt = tTypeNoUnits(dt) + if isdae + nlf = (ztmp, z, p) -> begin + tmp, ustep, γ, α, tstep, k, invγdt, _p, dt, f = p + _compute_rhs!(tmp, ztmp, ustep, γ, α, tstep, k, invγdt, _p, dt, f, z)[1] + end + nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, p, dt, f) + else + nlf = (ztmp, z, p) -> begin + tmp, ustep, γ, α, tstep, k, invγdt, method, _p, dt, f = p + _compute_rhs!( + tmp, ztmp, ustep, γ, α, tstep, k, invγdt, method, _p, dt, f, z)[1] + end + nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, DIRK, p, dt, f) + end + prob = NonlinearProblem(NonlinearFunction(nlf), ztmp, nlp_params) + cache = init(prob, nlalg.alg) + nlcache = NonlinearSolveCache(ustep, tstep, k, atmp, invγdt, prob, cache) + else + nlcache = NLNewtonCache(ustep, tstep, k, atmp, dz, J, W, true, + true, true, tType(dt), du1, uf, jac_config, + linsolve, weight, invγdt, tType(nlalg.new_W_dt_cutoff), t) + end elseif nlalg isa NLFunctional nlcache = NLFunctionalCache(ustep, tstep, k, atmp, dz) elseif nlalg isa NLAnderson @@ -229,11 +252,12 @@ function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u NLSolver{true, tTypeNoUnits}(z, tmp, ztmp, γ, c, α, nlalg, nlalg.κ, nlalg.fast_convergence_cutoff, ηold, 0, nlalg.max_iter, - Divergence, - nlcache) + Divergence, nlcache) end -function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u, uprev, p, +function build_nlsolver( + alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton, NonlinearSolveAlg}, + u, uprev, p, t, dt, f::F, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, @@ -254,7 +278,7 @@ function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u # build cache of non-linear solver tstep = zero(t) - if nlalg isa NLNewton + if nlalg isa Union{NLNewton, NonlinearSolveAlg} nf = nlsolve_f(f, alg) if isdae uf = DAEResidualDerivativeWrapper(f, p, α, inv(γ * dt), tmp, uprev, t) @@ -266,9 +290,30 @@ function build_nlsolver(alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton}, u invγdt = inv(oneunit(t) * one(uTolType)) J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) - - nlcache = NLNewtonConstantCache(tstep, J, W, true, true, true, tType(dt), uf, - invγdt, tType(nlalg.new_W_dt_cutoff), t) + if nlalg isa NonlinearSolveAlg + α = tTypeNoUnits(α) + dt = tTypeNoUnits(dt) + if isdae + nlf = (z, p) -> begin + tmp, α, tstep, invγdt, _p, dt, uprev, f = p + _compute_rhs(tmp, α, tstep, invγdt, p, dt, uprev, f, z)[1] + end + nlp_params = (tmp, α, tstep, invγdt, _p, dt, uprev, f) + else + nlf = (z, p) -> begin + tmp, γ, α, tstep, invγdt, method, _p, dt, f = p + _compute_rhs(tmp, γ, α, tstep, invγdt, method, _p, dt, f, z)[1] + end + nlp_params = (tmp, γ, α, tstep, invγdt, DIRK, p, dt, f) + end + prob = NonlinearProblem(NonlinearFunction(nlf), copy(ztmp), nlp_params) + cache = init(prob, nlalg.alg) + nlcache = NonlinearSolveCache( + nothing, tstep, nothing, nothing, invγdt, prob, cache) + else + nlcache = NLNewtonConstantCache(tstep, J, W, true, true, true, tType(dt), uf, + invγdt, tType(nlalg.new_W_dt_cutoff), t) + end elseif nlalg isa NLFunctional nlcache = NLFunctionalConstantCache(tstep) elseif nlalg isa NLAnderson diff --git a/src/perform_step/bdf_perform_step.jl b/src/perform_step/bdf_perform_step.jl index 34e2c5b003..14bcd01f46 100644 --- a/src/perform_step/bdf_perform_step.jl +++ b/src/perform_step/bdf_perform_step.jl @@ -99,7 +99,7 @@ end @muladd function perform_step!(integrator, cache::ABDF2Cache, repeat_step = false) @unpack t, dt, f, p = integrator #TODO: remove zₙ₋₁ from the cache - @unpack atmp, dtₙ₋₁, zₙ₋₁, nlsolver = cache + @unpack atmp, dtₙ₋₁, zₙ₋₁, nlsolver, step_limiter! = cache @unpack z, tmp, ztmp = nlsolver alg = unwrap_alg(integrator, true) uₙ, uₙ₋₁, uₙ₋₂, dtₙ = integrator.u, integrator.uprev, integrator.uprev2, integrator.dt @@ -149,6 +149,8 @@ end @.. broadcast=false uₙ=z + step_limiter!(uₙ, integrator, p, t + dtₙ) + f(integrator.fsallast, uₙ, p, t + dtₙ) integrator.stats.nf += 1 if integrator.opts.adaptive @@ -422,7 +424,7 @@ end function perform_step!(integrator, cache::QNDF1Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack uprev2, D, D2, R, U, dtₙ₋₁, utilde, atmp, nlsolver = cache + @unpack uprev2, D, D2, R, U, dtₙ₋₁, utilde, atmp, nlsolver, step_limiter! = cache @unpack z, tmp, ztmp = nlsolver alg = unwrap_alg(integrator, true) κ = alg.kappa @@ -471,6 +473,8 @@ function perform_step!(integrator, cache::QNDF1Cache, repeat_step = false) nlsolvefail(nlsolver) && return @.. broadcast=false u=z + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive if integrator.success_iter == 0 integrator.EEst = one(integrator.EEst) @@ -616,7 +620,7 @@ end function perform_step!(integrator, cache::QNDF2Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack uprev2, uprev3, dtₙ₋₁, dtₙ₋₂, D, D2, R, U, utilde, atmp, nlsolver = cache + @unpack uprev2, uprev3, dtₙ₋₁, dtₙ₋₂, D, D2, R, U, utilde, atmp, nlsolver, step_limiter! = cache @unpack z, tmp, ztmp = nlsolver alg = unwrap_alg(integrator, true) cnt = integrator.iter @@ -680,6 +684,8 @@ function perform_step!(integrator, cache::QNDF2Cache, repeat_step = false) nlsolvefail(nlsolver) && return @.. broadcast=false u=z + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive if integrator.success_iter == 0 integrator.EEst = one(integrator.EEst) @@ -840,7 +846,7 @@ end function perform_step!(integrator, cache::QNDFCache{max_order}, repeat_step = false) where {max_order} @unpack t, dt, uprev, u, f, p = integrator - @unpack dtprev, order, D, nlsolver, γₖ, dd, atmp, atmpm1, atmpp1, utilde, utildem1, utildep1, ϕ, u₀ = cache + @unpack dtprev, order, D, nlsolver, γₖ, dd, atmp, atmpm1, atmpp1, utilde, utildem1, utildep1, ϕ, u₀, step_limiter! = cache alg = unwrap_alg(integrator, true) if integrator.u_modified @@ -908,6 +914,9 @@ function perform_step!(integrator, cache::QNDFCache{max_order}, @.. broadcast=false u=z @.. broadcast=false dd=u - u₀ update_D!(D, dd, k) + + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive @unpack abstol, reltol, internalnorm = integrator.opts if cache.consfailcnt > 1 && mass_matrix !== I @@ -1221,7 +1230,7 @@ end function perform_step!(integrator, cache::FBDFCache{max_order}, repeat_step = false) where {max_order} - @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, terk_tmp, terkp1_tmp, atmp, tmp, equi_ts, u₀, ts_tmp = cache + @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, terk_tmp, terkp1_tmp, atmp, tmp, equi_ts, u₀, ts_tmp, step_limiter! = cache @unpack t, dt, u, f, p, uprev = integrator reinitFBDF!(integrator, cache) @@ -1269,6 +1278,8 @@ function perform_step!(integrator, cache::FBDFCache{max_order}, nlsolvefail(nlsolver) && return @.. broadcast=false u=z + step_limiter!(u, integrator, p, t + dt) + #This is to correct the interpolation error of error estimation. for j in 2:k r[j] = (1 - j) diff --git a/src/perform_step/composite_perform_step.jl b/src/perform_step/composite_perform_step.jl index 75057a3adc..2eb19e1688 100644 --- a/src/perform_step/composite_perform_step.jl +++ b/src/perform_step/composite_perform_step.jl @@ -1,38 +1,61 @@ -#= - -Maybe do generated functions to reduce dispatch times? - -f(x) = x -g(x,i) = f(x[i]) -g{i}(x,::Type{Val{i}}) = f(x[i]) -@generated function gg(tup::Tuple, num) - N = length(tup.parameters) - :(@nif $(N+1) i->(i == num) i->(f(tup[i])) i->error("unreachable")) - end -h(i) = g((1,1.0,"foo"), i) -h2{i}(::Type{Val{i}}) = g((1,1.0,"foo"), Val{i}) -h3(i) = gg((1,1.0,"foo"), i) -@benchmark h(1) -mean time: 31.822 ns (0.00% GC) -@benchmark h2(Val{1}) -mean time: 1.585 ns (0.00% GC) -@benchmark h3(1) -mean time: 6.423 ns (0.00% GC) - -@generated function foo(tup::Tuple, num) - N = length(tup.parameters) - :(@nif $(N+1) i->(i == num) i->(tup[i]) i->error("unreachable")) +function init_ith_default_cache(cache::DefaultCache, algs, i) + if i == 1 + if !isdefined(cache, :cache1) + cache.cache1 = alg_cache(algs[1], cache.args...) + end + elseif i == 2 + if !isdefined(cache, :cache2) + cache.cache2 = alg_cache(algs[2], cache.args...) + end + elseif i == 3 + if !isdefined(cache, :cache3) + cache.cache3 = alg_cache(algs[3], cache.args...) + end + elseif i == 4 + if !isdefined(cache, :cache4) + cache.cache4 = alg_cache(algs[4], cache.args...) + end + elseif i == 5 + if !isdefined(cache, :cache5) + cache.cache5 = alg_cache(algs[5], cache.args...) + end + elseif i == 6 + if !isdefined(cache, :cache6) + cache.cache6 = alg_cache(algs[6], cache.args...) + end + end end -@code_typed foo((1,1.0), 1) - -@generated function perform_step!(integrator, cache::CompositeCache, repeat_step=false) - N = length(cache.parameters) - :(@nif $(N+1) i->(i == num) i->(tup[i]) i->error("unreachable")) +function initialize!(integrator, cache::DefaultCache) + cache.current = cache.choice_function(integrator) + algs = integrator.alg.algs + init_ith_default_cache(cache, algs, cache.current) + if cache.current == 1 + initialize!(integrator, cache.cache1) + elseif cache.current == 2 + initialize!(integrator, cache.cache2) + # the controller was initialized by default for algs[1] + reset_alg_dependent_opts!(integrator.opts.controller, algs[1], algs[2]) + elseif cache.current == 3 + initialize!(integrator, cache.cache3) + # the controller was initialized by default for algs[1] + reset_alg_dependent_opts!(integrator.opts.controller, algs[1], algs[3]) + elseif cache.current == 4 + initialize!(integrator, cache.cache4) + # the controller was initialized by default for algs[1] + reset_alg_dependent_opts!(integrator.opts.controller, algs[1], algs[4]) + elseif cache.current == 5 + initialize!(integrator, cache.cache5) + # the controller was initialized by default for algs[1] + reset_alg_dependent_opts!(integrator.opts.controller, algs[1], algs[5]) + elseif cache.current == 6 + initialize!(integrator, cache.cache6) + # the controller was initialized by default for algs[1] + reset_alg_dependent_opts!(integrator.opts.controller, algs[1], algs[6]) + end + resize!(integrator.k, integrator.kshortsize) end -=# - function initialize!(integrator, cache::CompositeCache) cache.current = cache.choice_function(integrator) if cache.current == 1 @@ -69,28 +92,37 @@ the behaviour is consistent. In particular, prevents dt ⟶ 0 if starting with non-adaptive alg and opts.adaptive=true, and dt=cst if starting with adaptive alg and opts.adaptive=false. """ -function ensure_behaving_adaptivity!(integrator, cache::CompositeCache) +function ensure_behaving_adaptivity!(integrator, cache::Union{DefaultCache, CompositeCache}) if anyadaptive(integrator.alg) && !isadaptive(integrator.alg) integrator.opts.adaptive = isadaptive(integrator.alg.algs[cache.current]) end end -function perform_step!(integrator, cache::CompositeCache, repeat_step = false) +function perform_step!(integrator, cache::DefaultCache, repeat_step = false) + algs = integrator.alg.algs + init_ith_default_cache(cache, algs, cache.current) if cache.current == 1 - perform_step!(integrator, @inbounds(cache.caches[1]), repeat_step) + perform_step!(integrator, @inbounds(cache.cache1), repeat_step) elseif cache.current == 2 - perform_step!(integrator, @inbounds(cache.caches[2]), repeat_step) - else - perform_step!(integrator, @inbounds(cache.caches[cache.current]), repeat_step) + perform_step!(integrator, @inbounds(cache.cache2), repeat_step) + elseif cache.current == 3 + perform_step!(integrator, @inbounds(cache.cache3), repeat_step) + elseif cache.current == 4 + perform_step!(integrator, @inbounds(cache.cache4), repeat_step) + elseif cache.current == 5 + perform_step!(integrator, @inbounds(cache.cache5), repeat_step) + elseif cache.current == 6 + perform_step!(integrator, @inbounds(cache.cache6), repeat_step) end end -function perform_step!(integrator, cache::CompositeCache{Tuple{T1, T2}, F}, - repeat_step = false) where {T1, T2, F} +function perform_step!(integrator, cache::CompositeCache, repeat_step = false) if cache.current == 1 perform_step!(integrator, @inbounds(cache.caches[1]), repeat_step) elseif cache.current == 2 perform_step!(integrator, @inbounds(cache.caches[2]), repeat_step) + else + perform_step!(integrator, @inbounds(cache.caches[cache.current]), repeat_step) end end @@ -121,34 +153,52 @@ function choose_algorithm!(integrator, end end -function choose_algorithm!(integrator, cache::CompositeCache) +function choose_algorithm!(integrator, cache::DefaultCache) new_current = cache.choice_function(integrator) old_current = cache.current @inbounds if new_current != old_current + algs = integrator.alg.algs cache.current = new_current + init_ith_default_cache(cache, algs, new_current) if new_current == 1 - initialize!(integrator, @inbounds(cache.caches[1])) + initialize!(integrator, @inbounds(cache.cache1)) + new_cache = cache.cache1 elseif new_current == 2 - initialize!(integrator, @inbounds(cache.caches[2])) - else - initialize!(integrator, @inbounds(cache.caches[new_current])) + initialize!(integrator, @inbounds(cache.cache2)) + new_cache = cache.cache2 + elseif new_current == 3 + initialize!(integrator, @inbounds(cache.cache3)) + new_cache = cache.cache3 + elseif new_current == 4 + initialize!(integrator, @inbounds(cache.cache4)) + new_cache = cache.cache4 + elseif new_current == 5 + initialize!(integrator, @inbounds(cache.cache5)) + new_cache = cache.cache5 + elseif new_current == 6 + initialize!(integrator, @inbounds(cache.cache6)) + new_cache = cache.cache6 end - if old_current == 1 && new_current == 2 - reset_alg_dependent_opts!(integrator, integrator.alg.algs[1], - integrator.alg.algs[2]) - transfer_cache!(integrator, integrator.cache.caches[1], - integrator.cache.caches[2]) - elseif old_current == 2 && new_current == 1 - reset_alg_dependent_opts!(integrator, integrator.alg.algs[2], - integrator.alg.algs[1]) - transfer_cache!(integrator, integrator.cache.caches[2], - integrator.cache.caches[1]) - else - reset_alg_dependent_opts!(integrator, integrator.alg.algs[old_current], - integrator.alg.algs[new_current]) - transfer_cache!(integrator, integrator.cache.caches[old_current], - integrator.cache.caches[new_current]) + + if old_current == 1 + old_cache = cache.cache1 + elseif old_current == 2 + old_cache = cache.cache2 + elseif old_current == 3 + old_cache = cache.cache3 + elseif old_current == 4 + old_cache = cache.cache4 + elseif old_current == 5 + old_cache = cache.cache5 + elseif old_current == 6 + old_cache = cache.cache6 end + + integrator.opts.controller.beta2 = beta2 = beta2_default(algs[new_current]) + integrator.opts.controller.beta1 = beta1_default(algs[new_current], beta2) + + reset_alg_dependent_opts!(integrator, algs[old_current], algs[new_current]) + transfer_cache!(integrator, old_cache, new_cache) end end @@ -170,6 +220,7 @@ function reset_alg_dependent_opts!(integrator, alg1, alg2) integrator.opts.qmax == qmax_default(alg2) end reset_alg_dependent_opts!(integrator.opts.controller, alg1, alg2) + nothing end # Write how to transfer the cache variables from one cache to the other diff --git a/src/perform_step/feagin_rk_perform_step.jl b/src/perform_step/feagin_rk_perform_step.jl index a0ded6fa0b..73dd68e2cf 100644 --- a/src/perform_step/feagin_rk_perform_step.jl +++ b/src/perform_step/feagin_rk_perform_step.jl @@ -149,7 +149,7 @@ end @unpack t, dt, uprev, u, f, p = integrator uidx = eachindex(integrator.uprev) @unpack adaptiveConst, a0100, a0200, a0201, a0300, a0302, a0400, a0402, a0403, a0500, a0503, a0504, a0600, a0603, a0604, a0605, a0700, a0704, a0705, a0706, a0800, a0805, a0806, a0807, a0900, a0905, a0906, a0907, a0908, a1000, a1005, a1006, a1007, a1008, a1009, a1100, a1105, a1106, a1107, a1108, a1109, a1110, a1200, a1203, a1204, a1205, a1206, a1207, a1208, a1209, a1210, a1211, a1300, a1302, a1303, a1305, a1306, a1307, a1308, a1309, a1310, a1311, a1312, a1400, a1401, a1404, a1406, a1412, a1413, a1500, a1502, a1514, a1600, a1601, a1602, a1604, a1605, a1606, a1607, a1608, a1609, a1610, a1611, a1612, a1613, a1614, a1615, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16 = cache.tab - @unpack k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, tmp, atmp, uprev, k = cache + @unpack k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, tmp, atmp, uprev, k, step_limiter! = cache k1 = cache.fsalfirst a = dt * a0100 @tight_loop_macros for i in uidx @@ -257,6 +257,9 @@ end b17 * k17[i]) end integrator.stats.nf += 16 + + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive @tight_loop_macros for i in uidx @inbounds tmp[i] = dt * (k2[i] - k16[i]) * adaptiveConst @@ -494,7 +497,7 @@ end @unpack t, dt, uprev, u, f, p = integrator uidx = eachindex(integrator.uprev) @unpack adaptiveConst, a0100, a0200, a0201, a0300, a0302, a0400, a0402, a0403, a0500, a0503, a0504, a0600, a0603, a0604, a0605, a0700, a0704, a0705, a0706, a0800, a0805, a0806, a0807, a0900, a0905, a0906, a0907, a0908, a1000, a1005, a1006, a1007, a1008, a1009, a1100, a1105, a1106, a1107, a1108, a1109, a1110, a1200, a1208, a1209, a1210, a1211, a1300, a1308, a1309, a1310, a1311, a1312, a1400, a1408, a1409, a1410, a1411, a1412, a1413, a1500, a1508, a1509, a1510, a1511, a1512, a1513, a1514, a1600, a1608, a1609, a1610, a1611, a1612, a1613, a1614, a1615, a1700, a1705, a1706, a1707, a1708, a1709, a1710, a1711, a1712, a1713, a1714, a1715, a1716, a1800, a1805, a1806, a1807, a1808, a1809, a1810, a1811, a1812, a1813, a1814, a1815, a1816, a1817, a1900, a1904, a1905, a1906, a1908, a1909, a1910, a1911, a1912, a1913, a1914, a1915, a1916, a1917, a1918, a2000, a2003, a2004, a2005, a2007, a2009, a2010, a2017, a2018, a2019, a2100, a2102, a2103, a2106, a2107, a2109, a2110, a2117, a2118, a2119, a2120, a2200, a2201, a2204, a2206, a2220, a2221, a2300, a2302, a2322, a2400, a2401, a2402, a2404, a2406, a2407, a2408, a2409, a2410, a2411, a2412, a2413, a2414, a2415, a2416, a2417, a2418, a2419, a2420, a2421, a2422, a2423, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25 = cache.tab - @unpack k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, tmp, atmp, uprev, k = cache + @unpack k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, tmp, atmp, uprev, k, step_limiter! = cache k1 = cache.fsalfirst a = dt * a0100 @tight_loop_macros for i in uidx @@ -670,6 +673,9 @@ end (b24 * k24[i] + b25 * k25[i])) end integrator.stats.nf += 24 + + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive @tight_loop_macros for i in uidx @inbounds tmp[i] = dt * (k2[i] - k24[i]) * adaptiveConst @@ -1003,7 +1009,7 @@ end @unpack t, dt, uprev, u, f, p = integrator uidx = eachindex(integrator.uprev) @unpack adaptiveConst, a0100, a0200, a0201, a0300, a0302, a0400, a0402, a0403, a0500, a0503, a0504, a0600, a0603, a0604, a0605, a0700, a0704, a0705, a0706, a0800, a0805, a0806, a0807, a0900, a0905, a0906, a0907, a0908, a1000, a1005, a1006, a1007, a1008, a1009, a1100, a1105, a1106, a1107, a1108, a1109, a1110, a1200, a1208, a1209, a1210, a1211, a1300, a1308, a1309, a1310, a1311, a1312, a1400, a1408, a1409, a1410, a1411, a1412, a1413, a1500, a1508, a1509, a1510, a1511, a1512, a1513, a1514, a1600, a1608, a1609, a1610, a1611, a1612, a1613, a1614, a1615, a1700, a1712, a1713, a1714, a1715, a1716, a1800, a1812, a1813, a1814, a1815, a1816, a1817, a1900, a1912, a1913, a1914, a1915, a1916, a1917, a1918, a2000, a2012, a2013, a2014, a2015, a2016, a2017, a2018, a2019, a2100, a2112, a2113, a2114, a2115, a2116, a2117, a2118, a2119, a2120, a2200, a2212, a2213, a2214, a2215, a2216, a2217, a2218, a2219, a2220, a2221, a2300, a2308, a2309, a2310, a2311, a2312, a2313, a2314, a2315, a2316, a2317, a2318, a2319, a2320, a2321, a2322, a2400, a2408, a2409, a2410, a2411, a2412, a2413, a2414, a2415, a2416, a2417, a2418, a2419, a2420, a2421, a2422, a2423, a2500, a2508, a2509, a2510, a2511, a2512, a2513, a2514, a2515, a2516, a2517, a2518, a2519, a2520, a2521, a2522, a2523, a2524, a2600, a2605, a2606, a2607, a2608, a2609, a2610, a2612, a2613, a2614, a2615, a2616, a2617, a2618, a2619, a2620, a2621, a2622, a2623, a2624, a2625, a2700, a2705, a2706, a2707, a2708, a2709, a2711, a2712, a2713, a2714, a2715, a2716, a2717, a2718, a2719, a2720, a2721, a2722, a2723, a2724, a2725, a2726, a2800, a2805, a2806, a2807, a2808, a2810, a2811, a2813, a2814, a2815, a2823, a2824, a2825, a2826, a2827, a2900, a2904, a2905, a2906, a2909, a2910, a2911, a2913, a2914, a2915, a2923, a2924, a2925, a2926, a2927, a2928, a3000, a3003, a3004, a3005, a3007, a3009, a3010, a3013, a3014, a3015, a3023, a3024, a3025, a3027, a3028, a3029, a3100, a3102, a3103, a3106, a3107, a3109, a3110, a3113, a3114, a3115, a3123, a3124, a3125, a3127, a3128, a3129, a3130, a3200, a3201, a3204, a3206, a3230, a3231, a3300, a3302, a3332, a3400, a3401, a3402, a3404, a3406, a3407, a3409, a3410, a3411, a3412, a3413, a3414, a3415, a3416, a3417, a3418, a3419, a3420, a3421, a3422, a3423, a3424, a3425, a3426, a3427, a3428, a3429, a3430, a3431, a3432, a3433, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33, b34, b35 = cache.tab - @unpack k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, tmp, atmp, uprev, k = cache + @unpack k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, tmp, atmp, uprev, k, step_limiter! = cache k1 = cache.fsalfirst a = dt * a0100 @tight_loop_macros for i in uidx @@ -1275,6 +1281,9 @@ end b35 * k35[i]) end integrator.stats.nf += 35 + + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive @tight_loop_macros for i in uidx @inbounds tmp[i] = dt * (k2[i] - k34[i]) * adaptiveConst diff --git a/src/perform_step/firk_perform_step.jl b/src/perform_step/firk_perform_step.jl index 594af3eb8b..f49444eff4 100644 --- a/src/perform_step/firk_perform_step.jl +++ b/src/perform_step/firk_perform_step.jl @@ -207,7 +207,7 @@ end dw12, cubuff, k, k2, fw1, fw2, J, W1, - tmp, atmp, jac_config, rtol, atol = cache + tmp, atmp, jac_config, rtol, atol, step_limiter! = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @unpack maxiters = alg @@ -327,13 +327,14 @@ end cache.iter = iter @. u = uprev + z2 + step_limiter!(u, integrator, p, t + dt) + if adaptive utilde = w2 @. utilde = dt * (e1 * fsallast + e2 * k2) calculate_residuals!(atmp, utilde, uprev, u, atol, rtol, internalnorm, t) integrator.EEst = internalnorm(atmp, t) end - f(fsallast, u, p, t + dt) integrator.stats.nf += 1 return @@ -522,7 +523,7 @@ end dw1, ubuff, dw23, cubuff, k, k2, k3, fw1, fw2, fw3, J, W1, W2, - tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol = cache + tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol, step_limiter! = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @unpack maxiters = alg @@ -695,6 +696,7 @@ end cache.iter = iter @.. broadcast=false u=uprev + z3 + step_limiter!(u, integrator, p, t + dt) if adaptive utilde = w2 @@ -743,7 +745,6 @@ end @.. broadcast=false cache.cont3=cache.cont2 - (tmp - z1 / c1) / c2 end end - f(fsallast, u, p, t + dt) integrator.stats.nf += 1 return diff --git a/src/perform_step/kencarp_kvaerno_perform_step.jl b/src/perform_step/kencarp_kvaerno_perform_step.jl index 2d73630491..1b3d6f1a7b 100644 --- a/src/perform_step/kencarp_kvaerno_perform_step.jl +++ b/src/perform_step/kencarp_kvaerno_perform_step.jl @@ -108,7 +108,7 @@ end @muladd function perform_step!(integrator, cache::Kvaerno3Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack z₁, z₂, z₃, z₄, atmp, nlsolver = cache + @unpack z₁, z₂, z₃, z₄, atmp, nlsolver, step_limiter! = cache @unpack tmp = nlsolver @unpack γ, a31, a32, a41, a42, a43, btilde1, btilde2, btilde3, btilde4, c3, α31, α32 = cache.tab alg = unwrap_alg(integrator, true) @@ -161,6 +161,7 @@ end @.. broadcast=false u=tmp + γ * z₄ + step_limiter!(u, integrator, p, t + dt) ################################### Finalize if integrator.opts.adaptive @@ -311,7 +312,7 @@ end @muladd function perform_step!(integrator, cache::KenCarp3Cache, repeat_step = false) @unpack t, dt, uprev, u, p = integrator - @unpack z₁, z₂, z₃, z₄, k1, k2, k3, k4, atmp, nlsolver = cache + @unpack z₁, z₂, z₃, z₄, k1, k2, k3, k4, atmp, nlsolver, step_limiter! = cache @unpack tmp = nlsolver @unpack γ, a31, a32, a41, a42, a43, btilde1, btilde2, btilde3, btilde4, c3, α31, α32 = cache.tab @unpack ea21, ea31, ea32, ea41, ea42, ea43, eb1, eb2, eb3, eb4 = cache.tab @@ -409,6 +410,8 @@ end eb2 * k2 + eb3 * k3 + eb4 * k4 end + step_limiter!(u, integrator, p, t + dt) + ################################### Finalize if integrator.opts.adaptive @@ -733,7 +736,7 @@ end @muladd function perform_step!(integrator, cache::Kvaerno4Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack z₁, z₂, z₃, z₄, z₅, atmp, nlsolver = cache + @unpack z₁, z₂, z₃, z₄, z₅, atmp, nlsolver, step_limiter! = cache @unpack tmp = nlsolver @unpack γ, a31, a32, a41, a42, a43, a51, a52, a53, a54, c3, c4 = cache.tab @unpack α21, α31, α32, α41, α42 = cache.tab @@ -795,6 +798,8 @@ end @.. broadcast=false u=tmp + γ * z₅ + step_limiter!(u, integrator, p, t + dt) + ################################### Finalize if integrator.opts.adaptive @@ -993,7 +998,7 @@ end @muladd function perform_step!(integrator, cache::KenCarp4Cache, repeat_step = false) @unpack t, dt, uprev, u, p = integrator - @unpack z₁, z₂, z₃, z₄, z₅, z₆, atmp, nlsolver = cache + @unpack z₁, z₂, z₃, z₄, z₅, z₆, atmp, nlsolver, step_limiter! = cache @unpack tmp = nlsolver @unpack k1, k2, k3, k4, k5, k6 = cache @unpack γ, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a63, a64, a65, c3, c4, c5 = cache.tab @@ -1137,6 +1142,7 @@ end eb1 * k1 + eb3 * k3 + eb4 * k4 + eb5 * k5 + eb6 * k6 end + step_limiter!(u, integrator, p, t + dt) ################################### Finalize if integrator.opts.adaptive @@ -1273,7 +1279,7 @@ end @muladd function perform_step!(integrator, cache::Kvaerno5Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack z₁, z₂, z₃, z₄, z₅, z₆, z₇, atmp, nlsolver = cache + @unpack z₁, z₂, z₃, z₄, z₅, z₆, z₇, atmp, nlsolver, step_limiter! = cache @unpack tmp = nlsolver @unpack γ, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a63, a64, a65, a71, a73, a74, a75, a76, c3, c4, c5, c6 = cache.tab @unpack btilde1, btilde3, btilde4, btilde5, btilde6, btilde7 = cache.tab @@ -1355,6 +1361,7 @@ end @.. broadcast=false u=tmp + γ * z₇ + step_limiter!(u, integrator, p, t + dt) ################################### Finalize if integrator.opts.adaptive @@ -1595,7 +1602,7 @@ end @muladd function perform_step!(integrator, cache::KenCarp5Cache, repeat_step = false) @unpack t, dt, uprev, u, p = integrator - @unpack z₁, z₂, z₃, z₄, z₅, z₆, z₇, z₈, atmp, nlsolver = cache + @unpack z₁, z₂, z₃, z₄, z₅, z₆, z₇, z₈, atmp, nlsolver, step_limiter! = cache @unpack k1, k2, k3, k4, k5, k6, k7, k8 = cache @unpack tmp = nlsolver @unpack γ, a31, a32, a41, a43, a51, a53, a54, a61, a63, a64, a65, a71, a73, a74, a75, a76, a81, a84, a85, a86, a87, c3, c4, c5, c6, c7 = cache.tab @@ -1781,6 +1788,7 @@ end eb7 * k7 + eb8 * k8 end + step_limiter!(u, integrator, p, t + dt) ################################### Finalize if integrator.opts.adaptive diff --git a/src/perform_step/low_order_rk_perform_step.jl b/src/perform_step/low_order_rk_perform_step.jl index 3378d44ff2..a9904c8f0e 100644 --- a/src/perform_step/low_order_rk_perform_step.jl +++ b/src/perform_step/low_order_rk_perform_step.jl @@ -829,8 +829,8 @@ end @.. broadcast=false thread=thread u=uprev + dt * (a71 * k1 + a72 * k2 + a73 * k3 + a74 * k4 + a75 * k5 + a76 * k6) - stage_limiter!(u, f, p, t + dt) - step_limiter!(u, f, p, t + dt) + stage_limiter!(u, integrator, p, t + dt) + step_limiter!(u, integrator, p, t + dt) f(k7, u, p, t + dt) integrator.stats.nf += 6 if integrator.alg isa CompositeAlgorithm @@ -1467,6 +1467,255 @@ end return nothing end +function initialize!(integrator, cache::PSRK4p7q6ConstantCache) + integrator.kshortsize = 6 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) + integrator.stats.nf += 1 + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = zero(integrator.fsalfirst) + integrator.k[3] = zero(integrator.fsalfirst) + integrator.k[4] = zero(integrator.fsalfirst) + integrator.k[5] = zero(integrator.fsalfirst) + integrator.k[6] = integrator.fsallast +end + +function perform_step!(integrator, cache::PSRK4p7q6ConstantCache, repeat_step = false) + @unpack u, uprev, f, p, dt, t = integrator + @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a62, a63, a64, a65, b1, b2, b3, b4, b5, b6, c2, c3, c4, c5, c6 = cache + + k1 = f(uprev, p, t) + tmp = uprev + dt * (a21 * k1) + k2 = f(tmp, p, t + c2 * dt) + tmp = uprev + dt * (a31 * k1 + a32 * k2) + k3 = f(tmp, p, t + c3 * dt) + tmp = uprev + dt * (a41 * k1 + a42 * k2 + a43 * k3) + k4 = f(tmp, p, t + dt * c4) + tmp = uprev + dt * (a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4) + k5 = f(tmp, p, t + dt * c5) + tmp = uprev + dt * (a61 * k1 + a62 * k2 + a63 * k3 + a64 * k4 + a65 * k5) + k6 = f(tmp, p, t + dt * c6) + u = uprev + dt * (b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 + b5 * k5 + b6 * k6) + + integrator.stats.nf += 6 + integrator.fsallast = k6 + + integrator.k[1] = k1 + integrator.k[2] = k2 + integrator.k[3] = k3 + integrator.k[4] = k4 + integrator.k[5] = k5 + integrator.k[6] = k6 + integrator.u = u +end + +function initialize!(integrator, cache::PSRK4p7q6Cache) + @unpack uprev, f, p, t = integrator + + integrator.kshortsize = 6 + resize!(integrator.k, integrator.kshortsize) + integrator.k[1] = cache.k1 + integrator.k[2] = cache.k2 + integrator.k[3] = cache.k3 + integrator.k[4] = cache.k4 + integrator.k[5] = cache.k5 + integrator.k[6] = cache.k6 + integrator.fsalfirst = cache.k1 + integrator.fsallast = cache.k6 +end + +function perform_step!(integrator, cache::PSRK4p7q6Cache, repeat_step = false) + @unpack k1, k2, k3, k4, k5, k6, tmp, stage_limiter!, step_limiter!, thread = cache + @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a62, a63, a64, a65, b1, b2, b3, b4, b5, b6, c2, c3, c4, c5, c6 = cache.tab + @unpack u, uprev, t, dt, f, p = integrator + + f(k1, uprev, p, t) + @.. broadcast=false thread=thread tmp=uprev + dt * (a21 * k1) + stage_limiter!(tmp, integrator, p, t + c2 * dt) + f(k2, tmp, p, t + c2 * dt) + @.. broadcast=false thread=thread tmp=uprev + dt * (a31 * k1 + a32 * k2) + stage_limiter!(tmp, integrator, p, t + c3 * dt) + f(k3, tmp, p, t + c3 * dt) + @.. broadcast=false thread=thread tmp=uprev + dt * (a41 * k1 + a42 * k2 + a43 * k3) + stage_limiter!(tmp, integrator, p, t + c4 * dt) + f(k4, tmp, p, t + c4 * dt) + @.. broadcast=false thread=thread tmp=uprev + + dt * (a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4) + stage_limiter!(tmp, integrator, p, t + c5 * dt) + f(k5, tmp, p, t + c5 * dt) + @.. broadcast=false thread=thread tmp=uprev + + dt * (a61 * k1 + a62 * k2 + a63 * k3 + a64 * k4 + + a65 * k5) + stage_limiter!(tmp, integrator, p, t + c6 * dt) + f(k6, tmp, p, t + c6 * dt) + @.. broadcast=false thread=thread u=uprev + + dt * + (b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 + b5 * k5 + + b6 * k6) + stage_limiter!(u, integrator, p, t + dt) + step_limiter!(u, integrator, p, t + dt) + integrator.stats.nf += 6 + integrator.fsallast = k6 + return nothing +end + +function initialize!(integrator, cache::PSRK3p6q5ConstantCache) + integrator.kshortsize = 5 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) + integrator.stats.nf += 1 + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = zero(integrator.fsalfirst) + integrator.k[3] = zero(integrator.fsalfirst) + integrator.k[4] = zero(integrator.fsalfirst) + integrator.k[5] = integrator.fsallast +end + +function perform_step!(integrator, cache::PSRK3p6q5ConstantCache, repeat_step = false) + @unpack u, uprev, f, p, dt, t = integrator + @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, b1, b2, b3, b4, b5, c2, c3, c4, c5 = cache + + k1 = f(uprev, p, t) + tmp = uprev + dt * (a21 * k1) + k2 = f(tmp, p, t + c2 * dt) + tmp = uprev + dt * (a31 * k1 + a32 * k2) + k3 = f(tmp, p, t + c3 * dt) + tmp = uprev + dt * (a41 * k1 + a42 * k2 + a43 * k3) + k4 = f(tmp, p, t + dt * c4) + tmp = uprev + dt * (a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4) + k5 = f(tmp, p, t + dt * c5) + u = uprev + dt * (b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 + b5 * k5) + + integrator.stats.nf += 5 + integrator.fsallast = k5 + + integrator.k[1] = k1 + integrator.k[2] = k2 + integrator.k[3] = k3 + integrator.k[4] = k4 + integrator.k[5] = k5 + integrator.u = u +end + +function initialize!(integrator, cache::PSRK3p6q5Cache) + @unpack uprev, f, p, t = integrator + + integrator.kshortsize = 5 + resize!(integrator.k, integrator.kshortsize) + integrator.k[1] = cache.k1 + integrator.k[2] = cache.k2 + integrator.k[3] = cache.k3 + integrator.k[4] = cache.k4 + integrator.k[5] = cache.k5 + integrator.fsalfirst = cache.k1 + integrator.fsallast = cache.k5 +end + +function perform_step!(integrator, cache::PSRK3p6q5Cache, repeat_step = false) + @unpack k1, k2, k3, k4, k5, tmp, stage_limiter!, step_limiter!, thread = cache + @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, b1, b2, b3, b4, b5, c2, c3, c4, c5 = cache.tab + @unpack u, uprev, t, dt, f, p = integrator + + f(k1, uprev, p, t) + @.. broadcast=false thread=thread tmp=uprev + dt * (a21 * k1) + stage_limiter!(tmp, integrator, p, t + c2 * dt) + f(k2, tmp, p, t + c2 * dt) + @.. broadcast=false thread=thread tmp=uprev + dt * (a31 * k1 + a32 * k2) + stage_limiter!(tmp, integrator, p, t + c3 * dt) + f(k3, tmp, p, t + c3 * dt) + @.. broadcast=false thread=thread tmp=uprev + dt * (a41 * k1 + a42 * k2 + a43 * k3) + stage_limiter!(tmp, integrator, p, t + c4 * dt) + f(k4, tmp, p, t + c4 * dt) + @.. broadcast=false thread=thread tmp=uprev + + dt * (a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4) + stage_limiter!(tmp, integrator, p, t + c5 * dt) + f(k5, tmp, p, t + c5 * dt) + @.. broadcast=false thread=thread u=uprev + + dt * + (b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 + b5 * k5) + stage_limiter!(u, integrator, p, t + dt) + step_limiter!(u, integrator, p, t + dt) + integrator.stats.nf += 5 + integrator.fsallast = k5 + return nothing +end + +function initialize!(integrator, cache::PSRK3p5q4ConstantCache) + integrator.kshortsize = 4 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) + integrator.stats.nf += 1 + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = zero(integrator.fsalfirst) + integrator.k[3] = zero(integrator.fsalfirst) + integrator.k[4] = integrator.fsallast +end + +function perform_step!(integrator, cache::PSRK3p5q4ConstantCache, repeat_step = false) + @unpack u, uprev, f, p, dt, t = integrator + @unpack a21, a31, a32, a41, a42, a43, b1, b2, b3, b4, c2, c3, c4 = cache + + k1 = f(uprev, p, t) + tmp = uprev + dt * (a21 * k1) + k2 = f(tmp, p, t + c2 * dt) + tmp = uprev + dt * (a31 * k1 + a32 * k2) + k3 = f(tmp, p, t + c3 * dt) + tmp = uprev + dt * (a41 * k1 + a42 * k2 + a43 * k3) + k4 = f(tmp, p, t + dt * c4) + u = uprev + dt * (b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4) + + integrator.fsallast = k4 + integrator.stats.nf += 4 + + integrator.k[1] = k1 + integrator.k[2] = k2 + integrator.k[3] = k3 + integrator.k[4] = k4 + integrator.u = u +end + +function initialize!(integrator, cache::PSRK3p5q4Cache) + @unpack uprev, f, p, t = integrator + + integrator.kshortsize = 4 + resize!(integrator.k, integrator.kshortsize) + integrator.k[1] = cache.k1 + integrator.k[2] = cache.k2 + integrator.k[3] = cache.k3 + integrator.k[4] = cache.k4 + integrator.fsalfirst = cache.k1 + integrator.fsallast = cache.k4 +end + +function perform_step!(integrator, cache::PSRK3p5q4Cache, repeat_step = false) + @unpack k1, k2, k3, k4, tmp, stage_limiter!, step_limiter!, thread = cache + @unpack a21, a31, a32, a41, a42, a43, b1, b2, b3, b4, c2, c3, c4 = cache.tab + @unpack u, uprev, t, dt, f, p = integrator + + f(k1, uprev, p, t) + @.. broadcast=false thread=thread tmp=uprev + dt * (a21 * k1) + stage_limiter!(tmp, integrator, p, t + c2 * dt) + f(k2, tmp, p, t + c2 * dt) + @.. broadcast=false thread=thread tmp=uprev + dt * (a31 * k1 + a32 * k2) + stage_limiter!(tmp, integrator, p, t + c3 * dt) + f(k3, tmp, p, t + c3 * dt) + @.. broadcast=false thread=thread tmp=uprev + dt * (a41 * k1 + a42 * k2 + a43 * k3) + stage_limiter!(tmp, integrator, p, t + c4 * dt) + f(k4, tmp, p, t + c4 * dt) + @.. broadcast=false thread=thread u=uprev + + dt * + (b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4) + stage_limiter!(u, integrator, p, t + dt) + step_limiter!(u, integrator, p, t + dt) + + integrator.stats.nf += 4 + integrator.fsallast = k4 + return nothing +end + function initialize!(integrator, cache::MSRK5ConstantCache) integrator.kshortsize = 9 integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) diff --git a/src/perform_step/low_storage_rk_perform_step.jl b/src/perform_step/low_storage_rk_perform_step.jl index 4ee07826a7..d9e42aea82 100644 --- a/src/perform_step/low_storage_rk_perform_step.jl +++ b/src/perform_step/low_storage_rk_perform_step.jl @@ -133,7 +133,7 @@ end integrator.stats.nf += 1 @.. broadcast=false thread=thread u=u + B2end[i] * dt * k end - + step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) integrator.stats.nf += 1 end @@ -203,6 +203,7 @@ end β2end[i] * dt * k end + step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) integrator.stats.nf += 1 end @@ -495,6 +496,7 @@ end integrator.EEst = integrator.opts.internalnorm(atmp, t) end + step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) integrator.stats.nf += 1 end @@ -591,6 +593,8 @@ end (@.. broadcast=false thread=thread tmp=tmp + (Bₗ - B̂ₗ) * dt * k) @.. broadcast=false thread=thread u=u + Bₗ * dt * k + step_limiter!(u, integrator, p, t + dt) + #Error estimate if integrator.opts.adaptive calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, @@ -706,6 +710,8 @@ end (@.. broadcast=false thread=thread tmp=tmp + (Bₗ - B̂ₗ) * dt * k) @.. broadcast=false thread=thread u=u + Bₗ * dt * k + step_limiter!(u, integrator, p, t + dt) + #Error estimate if integrator.opts.adaptive calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, @@ -829,6 +835,8 @@ end (@.. broadcast=false thread=thread tmp=tmp + (Bₗ - B̂ₗ) * dt * k) @.. broadcast=false thread=thread u=u + Bₗ * dt * k + step_limiter!(u, integrator, p, t + dt) + #Error estimate if integrator.opts.adaptive calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, diff --git a/src/perform_step/qprk_perform_step.jl b/src/perform_step/qprk_perform_step.jl index d0ea7d9f8e..0461a3cf65 100644 --- a/src/perform_step/qprk_perform_step.jl +++ b/src/perform_step/qprk_perform_step.jl @@ -171,7 +171,6 @@ end + b16_10 * k10 + b16_11 * k11 + b16_12 * k12 + b16_13 * k13 + b16_14 * k14) stage_limiter!(u, integrator, p, t + dt) - step_limiter!(u, integrator, p, t + dt) f(k16, tmp, p, t + dt) integrator.stats.nf += 16 diff --git a/src/perform_step/rkn_perform_step.jl b/src/perform_step/rkn_perform_step.jl index 1c29dc53e4..70077f9268 100644 --- a/src/perform_step/rkn_perform_step.jl +++ b/src/perform_step/rkn_perform_step.jl @@ -12,7 +12,7 @@ const NystromCCDefaultInitialization = Union{Nystrom4ConstantCache, FineRKN4Cons DPRKN4ConstantCache, DPRKN5ConstantCache, DPRKN6FMConstantCache, DPRKN8ConstantCache, DPRKN12ConstantCache, ERKN4ConstantCache, - ERKN5ConstantCache, ERKN7ConstantCache} + ERKN5ConstantCache, ERKN7ConstantCache, RKN4ConstantCache} function initialize!(integrator, cache::NystromCCDefaultInitialization) integrator.kshortsize = 2 @@ -1819,3 +1819,92 @@ end integrator.EEst = integrator.opts.internalnorm(atmp, t) end end + +function initialize!(integrator, cache::RKN4Cache) + @unpack fsalfirst, k = cache + duprev, uprev = integrator.uprev.x + integrator.fsalfirst = fsalfirst + integrator.fsallast = k + integrator.kshortsize = 2 + resize!(integrator.k, integrator.kshortsize) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + integrator.f.f1(integrator.k[1].x[1], duprev, uprev, integrator.p, integrator.t) + integrator.f.f2(integrator.k[1].x[2], duprev, uprev, integrator.p, integrator.t) + integrator.stats.nf += 1 + integrator.stats.nf2 += 1 +end + +@muladd function perform_step!(integrator, cache::RKN4ConstantCache, repeat_step = false) + @unpack t, dt, f, p = integrator + duprev, uprev = integrator.uprev.x + u, du = integrator.u.x + #define dt values + halfdt = dt / 2 + dtsq = dt^2 + eightdtsq = dtsq / 8 + halfdtsq = dtsq / 2 + sixthdtsq = dtsq / 6 + sixthdt = dt / 6 + ttmp = t + halfdt + + #perform operations to find k values + k₁ = integrator.fsalfirst.x[1] + ku = uprev + halfdt * duprev + eightdtsq * k₁ + kdu = duprev + halfdt * k₁ + + k₂ = f.f1(kdu, ku, p, ttmp) + ku = uprev + dt * duprev + halfdtsq * k₂ + kdu = duprev + dt * k₂ + + k₃ = f.f1(kdu, ku, p, t + dt) + + #perform final calculations to determine new y and y'. + u = uprev + sixthdtsq * (1 * k₁ + 2 * k₂ + 0 * k₃) + dt * duprev + du = duprev + sixthdt * (1 * k₁ + 4 * k₂ + 1 * k₃) + + integrator.u = ArrayPartition((du, u)) + integrator.fsallast = ArrayPartition((f.f1(du, u, p, t + dt), f.f2(du, u, p, t + dt))) + integrator.stats.nf += 2 + integrator.stats.nf2 += 1 + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast +end + +@muladd function perform_step!(integrator, cache::RKN4Cache, repeat_step = false) + @unpack t, dt, f, p = integrator + duprev, uprev = integrator.uprev.x + du, u = integrator.u.x + @unpack tmp, fsalfirst, k₂, k₃, k = cache + kdu, ku = integrator.cache.tmp.x[1], integrator.cache.tmp.x[2] + + #define dt values + halfdt = dt / 2 + dtsq = dt^2 + eightdtsq = dtsq / 8 + halfdtsq = dtsq / 2 + sixthdtsq = dtsq / 6 + sixthdt = dt / 6 + ttmp = t + halfdt + + #perform operations to find k values + k₁ = integrator.fsalfirst.x[1] + @.. broadcast=false ku=uprev + halfdt * duprev + eightdtsq * k₁ + @.. broadcast=false kdu=duprev + halfdt * k₁ + + f.f1(k₂, kdu, ku, p, ttmp) + @.. broadcast=false ku=uprev + dt * duprev + halfdtsq * k₂ + @.. broadcast=false kdu=duprev + dt * k₂ + + f.f1(k₃, kdu, ku, p, t + dt) + + #perform final calculations to determine new y and y'. + @.. broadcast=false u=uprev + sixthdtsq * (1 * k₁ + 2 * k₂ + 0 * k₃) + dt * duprev + @.. broadcast=false du=duprev + sixthdt * (1 * k₁ + 4 * k₂ + 1 * k₃) + + f.f1(k.x[1], du, u, p, t + dt) + f.f2(k.x[2], du, u, p, t + dt) + + integrator.stats.nf += 2 + integrator.stats.nf2 += 1 +end diff --git a/src/perform_step/rosenbrock_perform_step.jl b/src/perform_step/rosenbrock_perform_step.jl index 4937407918..0521dc9779 100644 --- a/src/perform_step/rosenbrock_perform_step.jl +++ b/src/perform_step/rosenbrock_perform_step.jl @@ -27,7 +27,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock23Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p, opts = integrator - @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack c₃₂, d = cache.tab # Assignments @@ -68,6 +68,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + dto2 * k₁ + stage_limiter!(u, integrator, p, t + dto2) f(f₁, u, p, t + dto2) integrator.stats.nf += 1 @@ -88,6 +89,8 @@ end @.. broadcast=false k₂+=k₁ @.. broadcast=false u=uprev + dt * k₂ + stage_limiter!(u, integrator, p, t + dt) + step_limiter!(u, integrator, p, t + dt) if integrator.opts.adaptive f(fsallast, u, p, t + dt) @@ -136,7 +139,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock23Cache{<:Array}, repeat_step = false) @unpack t, dt, uprev, u, f, p, opts = integrator - @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack c₃₂, d = cache.tab # Assignments @@ -180,6 +183,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + dto2 * k₁[i] end + stage_limiter!(u, integrator, p, t + dto2) f(f₁, u, p, t + dto2) integrator.stats.nf += 1 @@ -207,6 +211,8 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + dt * k₂[i] end + stage_limiter!(u, integrator, p, t + dt) + step_limiter!(u, integrator, p, t + dt) if integrator.opts.adaptive f(fsallast, u, p, t + dt) @@ -274,7 +280,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock32Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p, opts = integrator - @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack c₃₂, d = cache.tab # Assignments @@ -315,6 +321,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + dto2 * k₁ + stage_limiter!(u, integrator, p, t + dto2) f(f₁, u, p, t + dto2) integrator.stats.nf += 1 @@ -335,6 +342,7 @@ end @.. broadcast=false k₂+=k₁ @.. broadcast=false tmp=uprev + dt * k₂ + stage_limiter!(u, integrator, p, t + dt) f(fsallast, tmp, p, t + dt) integrator.stats.nf += 1 @@ -356,6 +364,8 @@ end @.. broadcast=false u=uprev + dto6 * (k₁ + 4k₂ + k₃) + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive @.. broadcast=false tmp=dto6 * (k₁ - 2 * k₂ + k₃) calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, @@ -628,7 +638,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock33Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, fsalfirst, fsallast, k1, k2, k3, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, fsalfirst, fsallast, k1, k2, k3, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a31, a32, C21, C31, C32, b1, b2, b3, btilde1, btilde2, btilde3, gamma, c2, c3, d1, d2, d3 = cache.tab # Assignments @@ -670,6 +680,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a21 * k1 + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + c2 * dt) integrator.stats.nf += 1 @@ -690,6 +701,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a31 * k1 + a32 * k2 + stage_limiter!(u, integrator, p, t + c3 * dt) f(du, u, p, t + c3 * dt) integrator.stats.nf += 1 @@ -710,6 +722,9 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + b1 * k1 + b2 * k2 + b3 * k3 + + step_limiter!(u, integrator, p, t + dt) + f(fsallast, u, p, t + dt) integrator.stats.nf += 1 @@ -813,7 +828,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock34Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, fsalfirst, fsallast, k1, k2, k3, k4, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, fsalfirst, fsallast, k1, k2, k3, k4, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a31, a32, a41, a42, a43, C21, C31, C32, C41, C42, C43, b1, b2, b3, b4, btilde1, btilde2, btilde3, btilde4, gamma, c2, c3, d1, d2, d3, d4 = cache.tab # Assignments @@ -881,6 +896,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a31 * k1 + a32 * k2 + stage_limiter!(u, integrator, p, t + c3 * dt) f(du, u, p, t + c3 * dt) integrator.stats.nf += 1 @@ -897,10 +913,7 @@ end @.. broadcast=false veck3=-vecu integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 - f(du, u, p, t + dt) #-- c4 = 1 - integrator.stats.nf += 1 - - @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) #-- c4 = 1 integrator.stats.nf += 1 @@ -919,6 +932,9 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 + + step_limiter!(u, integrator, p, t + dt) + f(fsallast, u, p, t + dt) integrator.stats.nf += 1 @@ -1068,16 +1084,18 @@ end integrator.k[2] = h31 * k1 + h32 * k2 + h33 * k3 + h34 * k4 + h35 * k5 integrator.k[3] = h2_21 * k1 + h2_22 * k2 + h2_23 * k3 + h2_24 * k4 + h2_25 * k5 if integrator.opts.adaptive - if isa(linsolve_tmp,AbstractFloat) - u_int, u_diff = calculate_interpoldiff(uprev, du, u, integrator.k[1], integrator.k[2], integrator.k[3]) + if isa(linsolve_tmp, AbstractFloat) + u_int, u_diff = calculate_interpoldiff( + uprev, du, u, integrator.k[1], integrator.k[2], integrator.k[3]) else - u_int = linsolve_tmp + u_int = linsolve_tmp u_diff = linsolve_tmp .+ 0 - calculate_interpoldiff!(u_int, u_diff, uprev, du, u, integrator.k[1], integrator.k[2], integrator.k[3]) + calculate_interpoldiff!(u_int, u_diff, uprev, du, u, integrator.k[1], + integrator.k[2], integrator.k[3]) end atmp = calculate_residuals(u_diff, uprev, u_int, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) - EEst = max(EEst,integrator.opts.internalnorm(atmp, t)) #-- role of t unclear + EEst = max(EEst, integrator.opts.internalnorm(atmp, t)) #-- role of t unclear end end @@ -1087,7 +1105,7 @@ end du = k1 .+ 0 if integrator.opts.calck integrator.k[1] = integrator.k[3] .+ 0 - integrator.k[2] = 0*integrator.k[2] + integrator.k[2] = 0 * integrator.k[2] end end @@ -1113,7 +1131,7 @@ end @muladd function perform_step!( integrator, cache::Union{Rodas23WCache, Rodas3PCache}, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a41, a42, a43, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, gamma, c2, c3, d1, d2, d3 = cache.tab # Assignments @@ -1163,6 +1181,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a21 * k1 + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + c2 * dt) integrator.stats.nf += 1 @@ -1192,6 +1211,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -1224,6 +1244,8 @@ end du = u + k4 #-- p=2 solution u .+= k5 + step_limiter!(u, integrator, p, t + dt) + EEst = 0.0 if integrator.opts.calck @unpack h21, h22, h23, h24, h25, h31, h32, h33, h34, h35, h2_21, h2_22, h2_23, h2_24, h2_25 = cache.tab @@ -1264,7 +1286,7 @@ end integrator, cache::Union{Rodas23WCache{<:Array}, Rodas3PCache{<:Array}}, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, linsolve_tmp, jac_config, atmp, weight, step_limiter! = cache @unpack a21, a41, a42, a43, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, gamma, c2, c3, d1, d2, d3 = cache.tab # Assignments @@ -1420,6 +1442,8 @@ end u[i] += k5[i] end + step_limiter!(u, integrator, p, t + dt) + EEst = 0.0 if integrator.opts.calck @unpack h21, h22, h23, h24, h25, h31, h32, h33, h34, h35, h2_21, h2_22, h2_23, h2_24, h2_25 = cache.tab @@ -1465,24 +1489,24 @@ function calculate_interpoldiff(uprev, up2, up3, c_koeff, d_koeff, c2_koeff) a1 = up3 + c_koeff - up2 - c2_koeff a2 = d_koeff - c_koeff + c2_koeff a3 = -d_koeff - dis = a2^2 - 3*a1*a3 + dis = a2^2 - 3 * a1 * a3 u_int = up3 u_diff = 0.0 if dis > 0.0 #-- Min/Max occurs - tau1 = (-a2 - sqrt(dis))/(3*a3) - tau2 = (-a2 + sqrt(dis))/(3*a3) - if tau1 > tau2 - tau1,tau2 = tau2,tau1 + tau1 = (-a2 - sqrt(dis)) / (3 * a3) + tau2 = (-a2 + sqrt(dis)) / (3 * a3) + if tau1 > tau2 + tau1, tau2 = tau2, tau1 end - for tau in (tau1,tau2) + for tau in (tau1, tau2) if (tau > 0.0) && (tau < 1.0) - y_tau = (1 - tau)*uprev + - tau*(up3 + (1 - tau)*(c_koeff + tau*d_koeff)) - dy_tau = ((a3*tau + a2)*tau + a1)*tau + y_tau = (1 - tau) * uprev + + tau * (up3 + (1 - tau) * (c_koeff + tau * d_koeff)) + dy_tau = ((a3 * tau + a2) * tau + a1) * tau if abs(dy_tau) > abs(u_diff) u_diff = dy_tau u_int = y_tau - end + end end end end @@ -1665,7 +1689,7 @@ end @muladd function perform_step!(integrator, cache::Rodas4Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, k6, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, k6, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, C61, C62, C63, C64, C65, gamma, c2, c3, c4, d1, d2, d3, d4 = cache.tab # Assignments @@ -1721,6 +1745,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a21 * k1 + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + c2 * dt) integrator.stats.nf += 1 @@ -1737,6 +1762,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a31 * k1 + a32 * k2 + stage_limiter!(u, integrator, p, t + c3 * dt) f(du, u, p, t + c3 * dt) integrator.stats.nf += 1 @@ -1753,6 +1779,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 + stage_limiter!(u, integrator, p, t + c4 * dt) f(du, u, p, t + c4 * dt) integrator.stats.nf += 1 @@ -1770,6 +1797,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4 + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -1806,6 +1834,8 @@ end u .+= k6 + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive calculate_residuals!(atmp, k6, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) @@ -1824,7 +1854,7 @@ end @muladd function perform_step!(integrator, cache::Rodas4Cache{<:Array}, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, k6, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, k6, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, C61, C62, C63, C64, C65, gamma, c2, c3, c4, d1, d2, d3, d4 = cache.tab # Assignments @@ -1883,6 +1913,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a21 * k1[i] end + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + c2 * dt) integrator.stats.nf += 1 @@ -1910,6 +1941,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a31 * k1[i] + a32 * k2[i] end + stage_limiter!(u, integrator, p, t + c3 * dt) f(du, u, p, t + c3 * dt) integrator.stats.nf += 1 @@ -1937,6 +1969,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a41 * k1[i] + a42 * k2[i] + a43 * k3[i] end + stage_limiter!(u, integrator, p, t + c4 * dt) f(du, u, p, t + c4 * dt) integrator.stats.nf += 1 @@ -1965,6 +1998,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a51 * k1[i] + a52 * k2[i] + a53 * k3[i] + a54 * k4[i] end + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -1993,6 +2027,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] += k5[i] end + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -2022,6 +2057,8 @@ end u[i] += k6[i] end + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive calculate_residuals!(atmp, k6, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) @@ -2215,10 +2252,12 @@ end linsolve_tmp = k8 if integrator.opts.adaptive - if (integrator.alg isa Rodas5Pe) - linsolve_tmp = 0.2606326497975715*k1 - 0.005158627295444251*k2 + 1.3038988631109731*k3 + 1.235000722062074*k4 + - - 0.7931985603795049*k5 - 1.005448461135913*k6 - 0.18044626132120234*k7 + 0.17051519239113755*k8 - end + if (integrator.alg isa Rodas5Pe) + linsolve_tmp = 0.2606326497975715 * k1 - 0.005158627295444251 * k2 + + 1.3038988631109731 * k3 + 1.235000722062074 * k4 + + -0.7931985603795049 * k5 - 1.005448461135913 * k6 - + 0.18044626132120234 * k7 + 0.17051519239113755 * k8 + end atmp = calculate_residuals(linsolve_tmp, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -2232,18 +2271,20 @@ end h37 * k7 + h38 * k8 integrator.k[3] = h41 * k1 + h42 * k2 + h43 * k3 + h44 * k4 + h45 * k5 + h46 * k6 + h47 * k7 + h48 * k8 - if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && (integrator.EEst < 1.0) - k2 = 0.5*(uprev + u + 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) - du1 = ( 0.25*(integrator.k[2] + integrator.k[3]) - uprev + u) / dt - du = f(k2, p, t + dt/2) + if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && + (integrator.EEst < 1.0) + k2 = 0.5 * (uprev + u + + 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) + du1 = (0.25 * (integrator.k[2] + integrator.k[3]) - uprev + u) / dt + du = f(k2, p, t + dt / 2) integrator.stats.nf += 1 if mass_matrix === I du2 = du1 - du else - du2 = mass_matrix*du1 - du + du2 = mass_matrix * du1 - du end - EEst = norm(du2) / (integrator.opts.abstol + integrator.opts.reltol*norm(k2)) - integrator.EEst = max(EEst,integrator.EEst) + EEst = norm(du2) / (integrator.opts.abstol + integrator.opts.reltol * norm(k2)) + integrator.EEst = max(EEst, integrator.EEst) end end @@ -2262,7 +2303,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock5Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, k1, k2, k3, k4, k5, k6, k7, k8, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, k1, k2, k3, k4, k5, k6, k7, k8, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a62, a63, a64, a65, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, C61, C62, C63, C64, C65, C71, C72, C73, C74, C75, C76, C81, C82, C83, C84, C85, C86, C87, gamma, d1, d2, d3, d4, d5, c2, c3, c4, c5 = cache.tab # Assignments @@ -2334,6 +2375,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a21 * k1 + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + c2 * dt) integrator.stats.nf += 1 @@ -2351,6 +2393,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a31 * k1 + a32 * k2 + stage_limiter!(u, integrator, p, t + c3 * dt) f(du, u, p, t + c3 * dt) integrator.stats.nf += 1 @@ -2368,6 +2411,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 + stage_limiter!(u, integrator, p, t + c4 * dt) f(du, u, p, t + c4 * dt) integrator.stats.nf += 1 @@ -2386,6 +2430,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4 + stage_limiter!(u, integrator, p, t + c5 * dt) f(du, u, p, t + c5 * dt) integrator.stats.nf += 1 @@ -2404,6 +2449,7 @@ end integrator.stats.nsolve += 1 @.. broadcast=false u=uprev + a61 * k1 + a62 * k2 + a63 * k3 + a64 * k4 + a65 * k5 + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -2423,6 +2469,7 @@ end integrator.stats.nsolve += 1 u .+= k6 + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -2463,11 +2510,15 @@ end du .= k8 u .+= k8 + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive - if (integrator.alg isa Rodas5Pe) - du = 0.2606326497975715*k1 - 0.005158627295444251*k2 + 1.3038988631109731*k3 + 1.235000722062074*k4 + - - 0.7931985603795049*k5 - 1.005448461135913*k6 - 0.18044626132120234*k7 + 0.17051519239113755*k8 - end + if (integrator.alg isa Rodas5Pe) + du = 0.2606326497975715 * k1 - 0.005158627295444251 * k2 + + 1.3038988631109731 * k3 + 1.235000722062074 * k4 + + -0.7931985603795049 * k5 - 1.005448461135913 * k6 - + 0.18044626132120234 * k7 + 0.17051519239113755 * k8 + end calculate_residuals!(atmp, du, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -2481,10 +2532,12 @@ end h35 * k5 + h36 * k6 + h37 * k7 + h38 * k8 @.. broadcast=false integrator.k[3]=h41 * k1 + h42 * k2 + h43 * k3 + h44 * k4 + h45 * k5 + h46 * k6 + h47 * k7 + h48 * k8 - if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && (integrator.EEst < 1.0) - k2 = 0.5*(uprev + u + 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) - du1 = ( 0.25*(integrator.k[2] + integrator.k[3]) - uprev + u) / dt - f(du, k2, p, t + dt/2) + if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && + (integrator.EEst < 1.0) + k2 = 0.5 * (uprev + u + + 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) + du1 = (0.25 * (integrator.k[2] + integrator.k[3]) - uprev + u) / dt + f(du, k2, p, t + dt / 2) integrator.stats.nf += 1 if mass_matrix === I du2 = du1 - du @@ -2492,8 +2545,8 @@ end mul!(_vec(du2), mass_matrix, _vec(du1)) du2 = du2 - du end - EEst = norm(du2) / (integrator.opts.abstol + integrator.opts.reltol*norm(k2)) - integrator.EEst = max(EEst,integrator.EEst) + EEst = norm(du2) / (integrator.opts.abstol + integrator.opts.reltol * norm(k2)) + integrator.EEst = max(EEst, integrator.EEst) end end cache.linsolve = linres.cache @@ -2502,7 +2555,7 @@ end @muladd function perform_step!(integrator, cache::Rosenbrock5Cache{<:Array}, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, k1, k2, k3, k4, k5, k6, k7, k8, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight = cache + @unpack du, du1, du2, k1, k2, k3, k4, k5, k6, k7, k8, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a62, a63, a64, a65, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, C61, C62, C63, C64, C65, C71, C72, C73, C74, C75, C76, C81, C82, C83, C84, C85, C86, C87, gamma, d1, d2, d3, d4, d5, c2, c3, c4, c5 = cache.tab # Assignments @@ -2579,6 +2632,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a21 * k1[i] end + stage_limiter!(u, integrator, p, t + c2 * dt) f(du, u, p, t + c2 * dt) integrator.stats.nf += 1 @@ -2607,6 +2661,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a31 * k1[i] + a32 * k2[i] end + stage_limiter!(u, integrator, p, t + c3 * dt) f(du, u, p, t + c3 * dt) integrator.stats.nf += 1 @@ -2634,6 +2689,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a41 * k1[i] + a42 * k2[i] + a43 * k3[i] end + stage_limiter!(u, integrator, p, t + c4 * dt) f(du, u, p, t + c4 * dt) integrator.stats.nf += 1 @@ -2662,6 +2718,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] = uprev[i] + a51 * k1[i] + a52 * k2[i] + a53 * k3[i] + a54 * k4[i] end + stage_limiter!(u, integrator, p, t + c5 * dt) f(du, u, p, t + c5 * dt) integrator.stats.nf += 1 @@ -2692,6 +2749,7 @@ end u[i] = uprev[i] + a61 * k1[i] + a62 * k2[i] + a63 * k3[i] + a64 * k4[i] + a65 * k5[i] end + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -2721,6 +2779,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] += k6[i] end + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -2750,6 +2809,7 @@ end @inbounds @simd ivdep for i in eachindex(u) u[i] += k7[i] end + stage_limiter!(u, integrator, p, t + dt) f(du, u, p, t + dt) integrator.stats.nf += 1 @@ -2782,12 +2842,16 @@ end du[i] = k8[i] end + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive - if (integrator.alg isa Rodas5Pe) - @inbounds @simd ivdep for i in eachindex(u) - du[i] = 0.2606326497975715*k1[i] - 0.005158627295444251*k2[i] + 1.3038988631109731*k3[i] + 1.235000722062074*k4[i] + - - 0.7931985603795049*k5[i] - 1.005448461135913*k6[i] - 0.18044626132120234*k7[i] + 0.17051519239113755*k8[i] - end + if (integrator.alg isa Rodas5Pe) + @inbounds @simd ivdep for i in eachindex(u) + du[i] = 0.2606326497975715 * k1[i] - 0.005158627295444251 * k2[i] + + 1.3038988631109731 * k3[i] + 1.235000722062074 * k4[i] + + -0.7931985603795049 * k5[i] - 1.005448461135913 * k6[i] - + 0.18044626132120234 * k7[i] + 0.17051519239113755 * k8[i] + end end calculate_residuals!(atmp, du, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) @@ -2803,13 +2867,17 @@ end h35 * k5[i] + h36 * k6[i] + h37 * k7[i] + h38 * k8[i] integrator.k[3][i] = h41 * k1[i] + h42 * k2[i] + h43 * k3[i] + h44 * k4[i] + h45 * k5[i] + h46 * k6[i] + h47 * k7[i] + h48 * k8[i] - if (integrator.alg isa Rodas5Pr) - k2[i] = 0.5*(uprev[i] + u[i] + 0.5 * (integrator.k[1][i] + 0.5 * (integrator.k[2][i] + 0.5 * integrator.k[3][i]))) - du1[i] = ( 0.25*(integrator.k[2][i] + integrator.k[3][i]) - uprev[i] + u[i]) / dt - end + if (integrator.alg isa Rodas5Pr) + k2[i] = 0.5 * (uprev[i] + u[i] + + 0.5 * (integrator.k[1][i] + + 0.5 * (integrator.k[2][i] + 0.5 * integrator.k[3][i]))) + du1[i] = (0.25 * (integrator.k[2][i] + integrator.k[3][i]) - uprev[i] + + u[i]) / dt + end end - if integrator.opts.adaptive && (integrator.EEst < 1.0) && (integrator.alg isa Rodas5Pr) - f(du, k2, p, t + dt/2) + if integrator.opts.adaptive && (integrator.EEst < 1.0) && + (integrator.alg isa Rodas5Pr) + f(du, k2, p, t + dt / 2) integrator.stats.nf += 1 if mass_matrix === I @inbounds @simd ivdep for i in eachindex(u) @@ -2821,8 +2889,8 @@ end du2[i] = du2[i] - du[i] end end - EEst = norm(du2) / (integrator.opts.abstol + integrator.opts.reltol*norm(k2)) - integrator.EEst = max(EEst,integrator.EEst) + EEst = norm(du2) / (integrator.opts.abstol + integrator.opts.reltol * norm(k2)) + integrator.EEst = max(EEst, integrator.EEst) end end cache.linsolve = linres.cache diff --git a/src/perform_step/sdirk_perform_step.jl b/src/perform_step/sdirk_perform_step.jl index 080bba100c..d94bf0085f 100644 --- a/src/perform_step/sdirk_perform_step.jl +++ b/src/perform_step/sdirk_perform_step.jl @@ -103,7 +103,7 @@ end integrator.fsallast = f(u, p, t + dt) - if integrator.opts.adaptive && integrator.f.mass_matrix !== I + if integrator.opts.adaptive && integrator.differential_vars !== nothing atmp = @. ifelse(!integrator.differential_vars, integrator.fsallast, false) ./ integrator.opts.abstol integrator.EEst += integrator.opts.internalnorm(atmp, t) @@ -117,7 +117,7 @@ end @muladd function perform_step!(integrator, cache::ImplicitEulerCache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack atmp, nlsolver = cache + @unpack atmp, nlsolver, step_limiter! = cache @unpack z, tmp = nlsolver alg = unwrap_alg(integrator, true) markfirststage!(nlsolver) @@ -135,6 +135,8 @@ end nlsolvefail(nlsolver) && return @.. broadcast=false u=uprev + z + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive && integrator.success_iter > 0 # local truncation error (LTE) bound by dt^2/2*max|y''(t)| # use 2nd divided differences (DD) a la SPICE and Shampine @@ -160,7 +162,7 @@ end integrator.stats.nf += 1 f(integrator.fsallast, u, p, t + dt) - if integrator.opts.adaptive && integrator.f.mass_matrix !== I + if integrator.opts.adaptive && integrator.differential_vars !== nothing @.. broadcast=false atmp=ifelse(cache.algebraic_vars, integrator.fsallast, false) / integrator.opts.abstol integrator.EEst += integrator.opts.internalnorm(atmp, t) @@ -197,7 +199,7 @@ end @muladd function perform_step!(integrator, cache::ImplicitMidpointCache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack nlsolver = cache + @unpack nlsolver, step_limiter! = cache @unpack z, tmp = nlsolver mass_matrix = integrator.f.mass_matrix alg = unwrap_alg(integrator, true) @@ -216,6 +218,8 @@ end nlsolvefail(nlsolver) && return @.. broadcast=false u=nlsolver.tmp + z + step_limiter!(u, integrator, p, t + dt) + integrator.stats.nf += 1 f(integrator.fsallast, u, p, t + dt) end @@ -293,7 +297,7 @@ end @muladd function perform_step!(integrator, cache::TrapezoidCache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack atmp, nlsolver = cache + @unpack atmp, nlsolver, step_limiter! = cache @unpack z, tmp = nlsolver alg = unwrap_alg(integrator, true) mass_matrix = integrator.f.mass_matrix @@ -319,6 +323,8 @@ end nlsolvefail(nlsolver) && return @.. broadcast=false u=z + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive if integrator.iter > 2 # local truncation error (LTE) bound by dt^3/12*max|y'''(t)| @@ -425,7 +431,7 @@ end @muladd function perform_step!(integrator, cache::TRBDF2Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack zprev, zᵧ, atmp, nlsolver = cache + @unpack zprev, zᵧ, atmp, nlsolver, step_limiter! = cache @unpack z, tmp = nlsolver W = isnewton(nlsolver) ? get_W(nlsolver) : nothing b = nlsolver.ztmp @@ -458,6 +464,8 @@ end @.. broadcast=false u=tmp + d * z + step_limiter!(u, integrator, p, t + dt) + ################################### Finalize if integrator.opts.adaptive @@ -481,7 +489,7 @@ end @muladd function perform_step!(integrator, cache::TRBDF2Cache{<:Array}, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack zprev, zᵧ, atmp, nlsolver = cache + @unpack zprev, zᵧ, atmp, nlsolver, step_limiter! = cache @unpack z, tmp = nlsolver W = isnewton(nlsolver) ? get_W(nlsolver) : nothing b = nlsolver.ztmp @@ -524,6 +532,8 @@ end u[i] = tmp[i] + d * z[i] end + step_limiter!(u, integrator, p, t + dt) + ################################### Finalize if integrator.opts.adaptive @@ -604,7 +614,7 @@ end @muladd function perform_step!(integrator, cache::SDIRK2Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack z₁, z₂, atmp, nlsolver = cache + @unpack z₁, z₂, atmp, nlsolver, step_limiter! = cache @unpack tmp = nlsolver W = isnewton(nlsolver) ? get_W(nlsolver) : nothing alg = unwrap_alg(integrator, true) @@ -640,6 +650,8 @@ end @.. broadcast=false u=uprev + z₁ / 2 + z₂ / 2 + step_limiter!(u, integrator, p, t + dt) + ################################### Finalize if integrator.opts.adaptive @@ -738,7 +750,7 @@ end @muladd function perform_step!(integrator, cache::SDIRK22Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack atmp, nlsolver = cache + @unpack atmp, nlsolver, step_limiter! = cache @unpack z, tmp = nlsolver @unpack a, α, β = cache.tab alg = unwrap_alg(integrator, true) @@ -765,6 +777,8 @@ end nlsolvefail(nlsolver) && return @.. broadcast=false u=nlsolver.tmp + step_limiter!(u, integrator, p, t + dt) + if integrator.opts.adaptive if integrator.iter > 2 # local truncation error (LTE) bound by dt^3/12*max|y'''(t)| diff --git a/src/perform_step/verner_rk_perform_step.jl b/src/perform_step/verner_rk_perform_step.jl index 0a44e217da..7c76e26719 100644 --- a/src/perform_step/verner_rk_perform_step.jl +++ b/src/perform_step/verner_rk_perform_step.jl @@ -2,7 +2,7 @@ function initialize!(integrator, cache::Vern6ConstantCache) integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal integrator.stats.nf += 1 alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 9) : (integrator.kshortsize = 12) + cache.lazy ? (integrator.kshortsize = 9) : (integrator.kshortsize = 12) integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) # Avoid undefined entries if k is an array of arrays @@ -13,7 +13,7 @@ function initialize!(integrator, cache::Vern6ConstantCache) end integrator.k[integrator.kshortsize] = integrator.fsallast - if !alg.lazy + if !cache.lazy @inbounds for i in 10:12 integrator.k[i] = zero(integrator.fsalfirst) end @@ -63,7 +63,7 @@ end integrator.k[9] = k9 alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @unpack c10, a1001, a1004, a1005, a1006, a1007, a1008, a1009, c11, a1101, a1104, a1105, a1106, a1107, a1108, a1109, a1110, c12, a1201, a1204, a1205, a1206, a1207, a1208, a1209, a1210, a1211 = cache.tab.extra @@ -94,7 +94,7 @@ end function initialize!(integrator, cache::Vern6Cache) alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 9) : (integrator.kshortsize = 12) + cache.lazy ? (integrator.kshortsize = 9) : (integrator.kshortsize = 12) integrator.fsalfirst = cache.k1 integrator.fsallast = cache.k9 @unpack k = integrator @@ -109,7 +109,7 @@ function initialize!(integrator, cache::Vern6Cache) k[8] = cache.k8 k[9] = cache.k9 # Set the pointers - if !alg.lazy + if !cache.lazy k[10] = similar(cache.k1) k[11] = similar(cache.k1) k[12] = similar(cache.k1) @@ -182,7 +182,7 @@ end end alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @unpack c10, a1001, a1004, a1005, a1006, a1007, a1008, a1009, c11, a1101, a1104, a1105, a1106, a1107, a1108, a1109, a1110, c12, a1201, a1204, a1205, a1206, a1207, a1208, a1209, a1210, a1211 = cache.tab.extra @@ -214,7 +214,7 @@ end function initialize!(integrator, cache::Vern7ConstantCache) alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 16) + cache.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 16) integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) # Avoid undefined entries if k is an array of arrays @@ -277,7 +277,7 @@ end integrator.u = u alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @OnDemandTableauExtract Vern7ExtraStages T T2 @@ -329,7 +329,7 @@ function initialize!(integrator, cache::Vern7Cache) @unpack k1, k2, k3, k4, k5, k6, k7, k8, k9, k10 = cache @unpack k = integrator alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 16) + cache.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 16) resize!(k, integrator.kshortsize) k[1] = k1 k[2] = k2 @@ -342,7 +342,7 @@ function initialize!(integrator, cache::Vern7Cache) k[9] = k9 k[10] = k10 # Setup pointers - if !alg.lazy + if !cache.lazy k[11] = similar(cache.k1) k[12] = similar(cache.k1) k[13] = similar(cache.k1) @@ -433,7 +433,7 @@ end integrator.EEst = integrator.opts.internalnorm(atmp, t) end alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @unpack tmp = cache @@ -489,7 +489,7 @@ end function initialize!(integrator, cache::Vern8ConstantCache) alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 13) : (integrator.kshortsize = 21) + cache.lazy ? (integrator.kshortsize = 13) : (integrator.kshortsize = 21) integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) # Avoid undefined entries if k is an array of arrays @@ -575,7 +575,7 @@ end integrator.u = u alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @unpack c14, a1401, a1406, a1407, a1408, a1409, a1410, a1411, a1412, c15, a1501, a1506, a1507, a1508, a1509, a1510, a1511, a1512, a1514, c16, a1601, a1606, a1607, a1608, a1609, a1610, a1611, a1612, a1614, a1615, c17, a1701, a1706, a1707, a1708, a1709, a1710, a1711, a1712, a1714, a1715, a1716, c18, a1801, a1806, a1807, a1808, a1809, a1810, a1811, a1812, a1814, a1815, a1816, a1817, c19, a1901, a1906, a1907, a1908, a1909, a1910, a1911, a1912, a1914, a1915, a1916, a1917, c20, a2001, a2006, a2007, a2008, a2009, a2010, a2011, a2012, a2014, a2015, a2016, a2017, c21, a2101, a2106, a2107, a2108, a2109, a2110, a2111, a2112, a2114, a2115, a2116, a2117 = cache.tab.extra @@ -642,7 +642,7 @@ function initialize!(integrator, cache::Vern8Cache) @unpack k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13 = cache @unpack k = integrator alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 13) : (integrator.kshortsize = 21) + cache.lazy ? (integrator.kshortsize = 13) : (integrator.kshortsize = 21) resize!(k, integrator.kshortsize) k[1] = k1 k[2] = k2 @@ -658,7 +658,7 @@ function initialize!(integrator, cache::Vern8Cache) k[12] = k12 k[13] = k13 # Setup pointers - if !alg.lazy + if !cache.lazy for i in 14:21 k[i] = similar(cache.k1) end @@ -764,7 +764,7 @@ end end alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @unpack c14, a1401, a1406, a1407, a1408, a1409, a1410, a1411, a1412, c15, a1501, a1506, a1507, a1508, a1509, a1510, a1511, a1512, a1514, c16, a1601, a1606, a1607, a1608, a1609, a1610, a1611, a1612, a1614, a1615, c17, a1701, a1706, a1707, a1708, a1709, a1710, a1711, a1712, a1714, a1715, a1716, c18, a1801, a1806, a1807, a1808, a1809, a1810, a1811, a1812, a1814, a1815, a1816, a1817, c19, a1901, a1906, a1907, a1908, a1909, a1910, a1911, a1912, a1914, a1915, a1916, a1917, c20, a2001, a2006, a2007, a2008, a2009, a2010, a2011, a2012, a2014, a2015, a2016, a2017, c21, a2101, a2106, a2107, a2108, a2109, a2110, a2111, a2112, a2114, a2115, a2116, a2117 = cache.tab.extra @@ -851,7 +851,7 @@ end function initialize!(integrator, cache::Vern9ConstantCache) alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 20) + cache.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 20) integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) # Avoid undefined entries if k is an array of arrays @@ -945,7 +945,7 @@ end integrator.u = u alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @OnDemandTableauExtract Vern9ExtraStages T T2 @@ -1032,7 +1032,7 @@ function initialize!(integrator, cache::Vern9Cache) @unpack k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16 = cache @unpack k = integrator alg = unwrap_alg(integrator, false) - alg.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 20) + cache.lazy ? (integrator.kshortsize = 10) : (integrator.kshortsize = 20) resize!(k, integrator.kshortsize) # k2, k3,k4,k5,k6,k7 are not used in the code (not even in interpolations), we dont need their pointers. # So we mapped k[2] (from integrator) with k8 (from cache), k[3] with k9 and so on. @@ -1047,7 +1047,7 @@ function initialize!(integrator, cache::Vern9Cache) k[9] = k15 k[10] = k16 # Setup pointers - if !alg.lazy + if !cache.lazy for i in 11:20 k[i] = similar(cache.k1) end @@ -1174,7 +1174,7 @@ end end alg = unwrap_alg(integrator, false) - if !alg.lazy && (integrator.opts.adaptive == false || + if !cache.lazy && (integrator.opts.adaptive == false || accept_step_controller(integrator, integrator.opts.controller)) k = integrator.k @unpack tmp = cache diff --git a/src/solve.jl b/src/solve.jl index d9e7918292..6085b64376 100644 --- a/src/solve.jl +++ b/src/solve.jl @@ -147,7 +147,7 @@ function DiffEqBase.__init( auto.stifftol, auto.dtfac, auto.stiffalgfirst, - auto.switch_max)) + auto.switch_max, 0)) else _alg = alg end @@ -422,8 +422,7 @@ function DiffEqBase.__init( id = InterpolationData( f, timeseries, ts, ks, alg_choice, dense, cache, differential_vars, false) sol = DiffEqBase.build_solution(prob, _alg, ts, timeseries, - dense = dense, k = ks, interp = id, - alg_choice = alg_choice, + dense = dense, k = ks, interp = id, alg_choice = alg_choice, calculate_error = false, stats = stats) if recompile_flag == true @@ -508,11 +507,12 @@ function DiffEqBase.__init( integrator.saveiter += 1 # Starts at 1 so first save is at 2 integrator.saveiter_dense += 1 copyat_or_push!(ts, 1, t) + # N.B.: integrator.u can be modified by initialized_dae! if save_idxs === nothing copyat_or_push!(timeseries, 1, integrator.u) copyat_or_push!(ks, 1, [rate_prototype]) else - copyat_or_push!(timeseries, 1, u_initial, Val{false}) + copyat_or_push!(timeseries, 1, integrator.u[save_idxs], Val{false}) copyat_or_push!(ks, 1, [ks_prototype]) end else @@ -540,6 +540,15 @@ function DiffEqBase.__init( integrator end +if !Sys.iswindows() #TODO delete this once https://github.com/JuliaLang/julia/pull/54572 is released +function DiffEqBase.__init(prob::ODEProblem, ::Nothing, args...; kwargs...) + DiffEqBase.init(prob, DefaultODEAlgorithm(autodiff = false), args...; kwargs...) +end +function DiffEqBase.__solve(prob::ODEProblem, ::Nothing, args...; kwargs...) + DiffEqBase.solve(prob, DefaultODEAlgorithm(autodiff = false), args...; kwargs...) +end +end + function DiffEqBase.solve!(integrator::ODEIntegrator) @inbounds while !isempty(integrator.opts.tstops) while integrator.tdir * integrator.t < first(integrator.opts.tstops) diff --git a/src/tableaus/low_order_rk_tableaus.jl b/src/tableaus/low_order_rk_tableaus.jl index 56765db150..c62d6527d6 100644 --- a/src/tableaus/low_order_rk_tableaus.jl +++ b/src/tableaus/low_order_rk_tableaus.jl @@ -1541,6 +1541,167 @@ function Anas5ConstantCache(T, T2) a65, c2, c3, c4, c5, c6, b1, b3, b4, b5, b6) end +struct PSRK4p7q6ConstantCache{T, T1} <: OrdinaryDiffEqConstantCache + a21::T + a31::T + a32::T + a41::T + a42::T + a43::T + a51::T + a52::T + a53::T + a54::T + a61::T + a62::T + a63::T + a64::T + a65::T + + b1::T + b2::T + b3::T + b4::T + b5::T + b6::T + + c2::T1 + c3::T1 + c4::T1 + c5::T1 + c6::T1 +end + +function PSRK4p7q6ConstantCache(T::Type{<:CompiledFloats}, T1::Type{<:CompiledFloats}) + a21 = convert(T, 0.23593376536652) + a31 = convert(T, 0.34750735658424) + a32 = convert(T, -0.13561935398346) + a41 = convert(T, -0.20592852403227) + a42 = convert(T, 1.89179076622108) + a43 = convert(T, -0.89775024478958) + a51 = convert(T, -0.09435493281455) + a52 = convert(T, 1.75617141223762) + a53 = convert(T, -0.96707850476948) + a54 = convert(T, 0.06932825997989) + a61 = convert(T, 0.14157883255197) + a62 = convert(T, -1.17039696277833) + a63 = convert(T, 1.30579112376331) + a64 = convert(T, -2.20354136855289) + a65 = convert(T, 2.92656837501595) + + b1 = convert(T, 0.07078941627598) + b2 = convert(T, 0.87808570611881) + b3 = convert(T, -0.44887512239479) + b4 = convert(T, -0.44887512239479) + b5 = convert(T, 0.87808570611881) + b6 = convert(T, 0.07078941627598) + + c2 = convert(T1, 0.23593376536652) + c3 = convert(T1, 0.21188800260078) + c4 = convert(T1, 0.78811199739923) + c5 = convert(T1, 0.76406623463348) + c6 = convert(T1, 1.0) + + PSRK4p7q6ConstantCache( + a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, a61, a62, a63, a64, a65, + b1, b2, b3, b4, b5, b6, + c2, c3, c4, c5, c6) +end + +struct PSRK3p6q5ConstantCache{T, T1} <: OrdinaryDiffEqConstantCache + a21::T + a31::T + a32::T + a41::T + a42::T + a43::T + a51::T + a52::T + a53::T + a54::T + + b1::T + b2::T + b3::T + b4::T + b5::T + + c2::T1 + c3::T1 + c4::T1 + c5::T1 +end + +function PSRK3p6q5ConstantCache(T::Type{<:CompiledFloats}, T1::Type{<:CompiledFloats}) + a21 = convert(T, 0.13502027922909) + a31 = convert(T, -0.47268213605237) + a32 = convert(T, 1.05980250415419) + a41 = convert(T, -1.21650460595689) + a42 = convert(T, 2.16217630216753) + a43 = convert(T, -0.37234592426536) + a51 = convert(T, 0.33274443036387) + a52 = convert(T, -0.20882668296587) + a53 = convert(T, 1.87865617737921) + a54 = convert(T, -1.00257392477721) + + b1 = convert(T, 0.04113894457092) + b2 = convert(T, 0.26732123194414) + b3 = convert(T, 0.86700906289955) + b4 = convert(T, -0.30547139552036) + b5 = convert(T, 0.13000215610576) + + c2 = convert(T1, 0.13502027922909) + c3 = convert(T1, 0.58712036810182) + c4 = convert(T1, 0.57332577194528) + c5 = convert(T1, 1.0) + + PSRK3p6q5ConstantCache( + a21, a31, a32, a41, a42, a43, a51, a52, a53, a54, + b1, b2, b3, b4, b5, + c2, c3, c4, c5) +end + +struct PSRK3p5q4ConstantCache{T, T1} <: OrdinaryDiffEqConstantCache + a21::T + a31::T + a32::T + a41::T + a42::T + a43::T + + b1::T + b2::T + b3::T + b4::T + + c2::T1 + c3::T1 + c4::T1 +end + +function PSRK3p5q4ConstantCache(T::Type, T1::Type) + a21 = T(3 // 8) + a31 = T(11 // 12) + a32 = T(-2 // 3) + a41 = T(-1 // 12) + a42 = T(11 // 6) + a43 = T(-3 // 4) + + b1 = T(1 // 9) + b2 = T(8 // 9) + b3 = T(-2 // 9) + b4 = T(2 // 9) + + c2 = T1(3 // 8) + c3 = T1(1 // 4) + c4 = T1(1) + + PSRK3p5q4ConstantCache( + a21, a31, a32, a41, a42, a43, + b1, b2, b3, b4, + c2, c3, c4) +end + struct MSRK5ConstantCache{T, T1} <: OrdinaryDiffEqConstantCache a21::T a31::T diff --git a/test/algconvergence/ode_convergence_tests.jl b/test/algconvergence/ode_convergence_tests.jl index 418d495998..cb854b373e 100644 --- a/test/algconvergence/ode_convergence_tests.jl +++ b/test/algconvergence/ode_convergence_tests.jl @@ -12,6 +12,13 @@ dts5 = 1 .// 2 .^ (3:-1:1) dts6 = 1 .// 10 .^ (5:-1:1) testTol = 0.2 +f = (u, p, t) -> sin(u) +prob_ode_nonlinear = ODEProblem( + ODEFunction(f; + analytic = (u0, p, t) -> 2 * acot(exp(-t) * + cot(0.5))), 1.0, + (0.0, 0.5)) + @testset "Explicit Solver Convergence Tests ($(["out-of-place", "in-place"][i]))" for i in 1:2 prob = (ODEProblemLibrary.prob_ode_linear, ODEProblemLibrary.prob_ode_2Dlinear)[i] @@ -46,6 +53,15 @@ testTol = 0.2 sim3 = test_convergence(dts, prob, RKM()) @test sim3.𝒪est[:l∞]≈4 atol=0.2 + sim_ps6 = test_convergence(dts2, prob_ode_nonlinear, PSRK4p7q6()) + @test sim_ps6.𝒪est[:l∞]≈4 atol=testTol + + sim_ps5 = test_convergence(dts2, prob_ode_nonlinear, PSRK3p6q5()) + @test sim_ps5.𝒪est[:l∞]≈3 atol=testTol + + sim_ps4 = test_convergence(dts2, prob_ode_nonlinear, PSRK3p5q4()) + @test sim_ps4.𝒪est[:l∞]≈3 atol=testTol + sim_ms5 = test_convergence(dts2, prob, MSRK5()) @test sim_ms5.𝒪est[:l∞]≈5 atol=testTol @@ -117,6 +133,10 @@ end reltol = 1e-2) @test sim113.𝒪est[:final]≈1 atol=testTol + sim114 = test_convergence(dts, prob, ImplicitEuler(nlsolve = NonlinearSolveAlg()), + reltol = 1e-2) + @test sim114.𝒪est[:final]≈1 atol=testTol + sim13 = test_convergence(dts, prob, ImplicitMidpoint()) @test sim13.𝒪est[:final]≈2 atol=testTol @@ -126,6 +146,9 @@ end sim134 = test_convergence(dts, prob, ImplicitMidpoint(nlsolve = NLAnderson())) @test sim134.𝒪est[:final]≈2 atol=testTol + sim136 = test_convergence(dts, prob, ImplicitMidpoint(nlsolve = NonlinearSolveAlg())) + @test sim136.𝒪est[:final]≈2 atol=testTol + sim13 = test_convergence(dts, prob, Trapezoid()) @test sim13.𝒪est[:final]≈2 atol=testTol @@ -135,6 +158,9 @@ end sim135 = test_convergence(dts, prob, Trapezoid(nlsolve = NLAnderson())) @test sim135.𝒪est[:final]≈2 atol=testTol + sim137 = test_convergence(dts, prob, Trapezoid(nlsolve = NonlinearSolveAlg())) + @test sim137.𝒪est[:final]≈2 atol=testTol + sim14 = test_convergence(dts, prob, TRBDF2()) @test sim14.𝒪est[:final]≈2 atol=testTol @@ -223,6 +249,10 @@ end sim23 = test_convergence(dts, prob, MEBDF2(nlsolve = NLAnderson()), reltol = 1e-2) @test sim23.𝒪est[:final]≈2 atol=testTol + sim24 = test_convergence( + dts, prob, MEBDF2(nlsolve = NonlinearSolveAlg()), reltol = 1e-2) + @test sim24.𝒪est[:final]≈2 atol=testTol + #FBDF @test_nowarn solve(prob, FBDF()) diff --git a/test/algconvergence/ode_rosenbrock_tests.jl b/test/algconvergence/ode_rosenbrock_tests.jl index 257d424af9..f4f82b7296 100644 --- a/test/algconvergence/ode_rosenbrock_tests.jl +++ b/test/algconvergence/ode_rosenbrock_tests.jl @@ -106,7 +106,7 @@ import LinearSolve sol = solve(prob, ROS2PR()) @test length(sol) < 60 - + ### ROS2PR prob = prob_ode_linear @@ -629,7 +629,7 @@ import LinearSolve sol = solve(prob, Rodas5P()) @test length(sol) < 20 - + println("Rodas5Pe") prob = prob_ode_linear diff --git a/test/algconvergence/partitioned_methods_tests.jl b/test/algconvergence/partitioned_methods_tests.jl index e078444410..764694b935 100644 --- a/test/algconvergence/partitioned_methods_tests.jl +++ b/test/algconvergence/partitioned_methods_tests.jl @@ -112,6 +112,9 @@ sol = solve(prob, Nystrom4(), dt = 1 / 1000) # Nyström method dts = 1 .// 2 .^ (9:-1:6) +sim = test_convergence(dts, prob, RKN4(), dense_errors = true) +@test sim.𝒪est[:l2]≈4 rtol=1e-1 +@test sim.𝒪est[:L2]≈4 rtol=1e-1 sim = test_convergence(dts, prob, Nystrom4(), dense_errors = true) @test sim.𝒪est[:l2]≈4 rtol=1e-1 @test sim.𝒪est[:L2]≈4 rtol=1e-1 @@ -294,6 +297,9 @@ sim = test_convergence(dts, prob, KahanLi8(), dense_errors = true) # Nyström method dts = 1 .// 2 .^ (9:-1:6) +sim = test_convergence(dts, prob, RKN4(), dense_errors = true) +@test sim.𝒪est[:l2]≈4 rtol=1e-1 +@test sim.𝒪est[:L2]≈4 rtol=1e-1 sim = test_convergence(dts, prob, Nystrom4(), dense_errors = true) @test sim.𝒪est[:l2]≈4 rtol=1e-1 @test sim.𝒪est[:L2]≈4 rtol=1e-1 @@ -379,7 +385,7 @@ sol = solve(prob, ERKN7(), reltol = 1e-8) @test length(sol.u) < 38 # Testing generalized Runge-Kutte-Nyström methods on velocity dependend ODEs with the damped oscillator -println("In Place") +println("Out of Place") # Damped oscillator prob = ODEProblem( @@ -411,12 +417,13 @@ sim = test_convergence(dts, prob, FineRKN5(), dense_errors = true) @test sim.𝒪est[:L2]≈4 rtol=1e-1 # Adaptive methods regression test + sol = solve(prob, FineRKN4()) @test length(sol.u) < 28 sol = solve(prob, FineRKN5()) @test length(sol.u) < 20 -println("Out of Place") +println("In Place") # Damped oscillator prob = ODEProblem( DynamicalODEFunction{true}((d_du, du, u, p, t) -> @.(d_du=-u - 0.5 * du), @@ -483,6 +490,20 @@ end @test abs(sol_i.destats.nf - 4 * sol_i.destats.naccept) < 4 end + @testset "RKN4" begin + alg = RKN4() + dt = 0.5 + # fixed time step + sol_i = solve(ode_i, alg, dt = dt) + sol_o = solve(ode_o, alg, dt = dt) + @test sol_i.t ≈ sol_o.t + @test sol_i.u ≈ sol_o.u + @test sol_i.destats.nf == sol_o.destats.nf + @test sol_i.destats.nf2 == sol_o.destats.nf2 + @test sol_i.destats.naccept == sol_o.destats.naccept + @test 19 <= sol_i.destats.naccept <= 21 + @test abs(sol_i.destats.nf - 2 * sol_i.destats.naccept) < 4 + end @testset "FineRKN4" begin alg = FineRKN4() dt = 0.5 diff --git a/test/gpu/Project.toml b/test/gpu/Project.toml index 39a8540125..b42a597fa8 100644 --- a/test/gpu/Project.toml +++ b/test/gpu/Project.toml @@ -1,6 +1,11 @@ [deps] +Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" [compat] CUDA = "5" diff --git a/test/gpu/hermite_test.jl b/test/gpu/hermite_test.jl new file mode 100644 index 0000000000..db7d233884 --- /dev/null +++ b/test/gpu/hermite_test.jl @@ -0,0 +1,16 @@ +using ComponentArrays, CUDA, Adapt, RecursiveArrayTools, FastBroadcast, FillArrays, + OrdinaryDiffEq, Test + +a = ComponentArray((a = rand(Float32, 5, 5), b = rand(Float32, 5, 5))) +a = adapt(CuArray, a) +pa = ArrayPartition(a) +pb = deepcopy(pa) +pc = deepcopy(pa) +pd = deepcopy(pa) +pe = deepcopy(pa) +k = [pd, pe] +t = FillArrays.Trues(length(pa)) + +OrdinaryDiffEq.hermite_interpolant!(pa, 0.1, 0.2, pb, pc, k, nothing, Val{0}, t) # if this doesnt error we're good + +@test pa.x[1] != pb.x[1] diff --git a/test/integrators/check_error.jl b/test/integrators/check_error.jl index 13edc73911..91615c8e1a 100644 --- a/test/integrators/check_error.jl +++ b/test/integrators/check_error.jl @@ -5,26 +5,26 @@ u0 = 0.0 # explosion time is 1.0 tspan = (0.0, 10.0) prob = ODEProblem(f_ec, u0, tspan) options = [:reltol => 1e-8, :abstol => 1e-8, :verbose => false] -desired_code = ReturnCode.MaxIters +desired_codes = (ReturnCode.MaxIters, ReturnCode.Unstable) # Test that sol.retcode is set to the correct value by various ways to # invoke integrator. sol = solve(prob, Tsit5(); options...) -@test sol.retcode == desired_code +@test sol.retcode in desired_codes integrator = init(prob, Tsit5(); options...) solve!(integrator) -@test integrator.sol.retcode == desired_code +@test integrator.sol.retcode in desired_codes integrator = init(prob, Tsit5(); options...) for _ in integrator end -@test integrator.sol.retcode == desired_code +@test integrator.sol.retcode in desired_codes integrator = init(prob, Tsit5(); options...) step!(integrator, 10.0) -@test integrator.sol.retcode == desired_code +@test integrator.sol.retcode in desired_codes # Test check_error integrator = init(prob, Tsit5(); options...) @@ -33,7 +33,7 @@ step!(integrator) ok = false for i in 1:(integrator.opts.maxiters) step!(integrator) - if check_error(integrator) == desired_code + if check_error(integrator) in desired_codes global ok = true # @show i break diff --git a/test/integrators/ode_cache_tests.jl b/test/integrators/ode_cache_tests.jl index a272868055..9625616287 100644 --- a/test/integrators/ode_cache_tests.jl +++ b/test/integrators/ode_cache_tests.jl @@ -4,13 +4,11 @@ using ElasticArrays, LinearSolve Random.seed!(213) CACHE_TEST_ALGS = [Euler(), Midpoint(), RK4(), SSPRK22(), SSPRK33(), SSPRK43(), SSPRK104(), CarpenterKennedy2N54(), SHLDDRK64(), ORK256(), DGLDDRK73_C(), - CFRLDDRK64(), TSLDDRK74(), - CKLLSRK43_2(), - ParsaniKetchesonDeconinck3S32(), + CFRLDDRK64(), TSLDDRK74(), CKLLSRK43_2(), ParsaniKetchesonDeconinck3S32(), BS3(), BS5(), DP5(), DP8(), Feagin10(), Feagin12(), Feagin14(), TanYam7(), Tsit5(), TsitPap8(), Vern6(), Vern7(), Vern8(), Vern9(), OwrenZen3(), OwrenZen4(), - OwrenZen5(), - AutoTsit5(Rosenbrock23()), TRBDF2(), KenCarp4(), ABDF2()] + OwrenZen5(), AutoTsit5(Rosenbrock23()), TRBDF2(), KenCarp4(), ABDF2(), + OrdinaryDiffEq.DefaultODEAlgorithm()] broken_CACHE_TEST_ALGS = [ QNDF(), ExtrapolationMidpointHairerWanner(), diff --git a/test/integrators/step_limiter_test.jl b/test/integrators/step_limiter_test.jl new file mode 100644 index 0000000000..566d5da527 --- /dev/null +++ b/test/integrators/step_limiter_test.jl @@ -0,0 +1,50 @@ +using OrdinaryDiffEq, Test + +# define the counting variable +const STEP_LIMITER_VAR = Ref(0) +# define the step_limiter! function which just counts the number of step_limiter calls +step_limiter!(u, integrator, p, t) = STEP_LIMITER_VAR[] += 1 + +# This function tests the step limiter functionality of an ODE solver. +function test_step_limiter(alg_type) + STEP_LIMITER_VAR[] = 0 # reset the counting variable + prob = ODEProblem((du, u, p, t) -> du .= u, [1.0], (0.0, 1.0)) + + sol = solve(prob, alg_type(; step_limiter!), dt = 0.1) + + n = sol.stats.naccept + sol.stats.nreject + @test n == STEP_LIMITER_VAR[] +end + +@testset "Step_limiter Test" begin + # it only catches the most basic errors, i.e. if the step_limiter! function is not called + # or called more then one time + + # test the step_limiter! function + alg_types = [ + QNDF1, QNDF2, QNDF, FBDF, ImplicitEuler, ImplicitMidpoint, Trapezoid, TRBDF2, + SDIRK2, SDIRK22, ABDF2, Feagin10, Feagin12, Feagin14, + KenCarp3, KenCarp4, KenCarp5, Kvaerno3, Kvaerno4, Kvaerno5, + Rosenbrock23, Rosenbrock32, ROS3P, Rodas3, Rodas23W, Rodas3P, Rodas4, Rodas42, + Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, + RadauIIA5, RadauIIA3, SIR54, Alshina2, Alshina3, Heun, Ralston, Midpoint, RK4, + OwrenZen3, OwrenZen4, OwrenZen5, + BS3, DP5, Tsit5, DP8, TanYam7, TsitPap8, FRK65, PFRK87, BS5, Vern6, Vern7, + Vern8, Vern9, QPRK98, SSPRKMSVS43, SSPRKMSVS32, SSPRK432, SSPRK43, + RDPK3SpFSAL35, RDPK3Sp35, NDBLSRK124, NDBLSRK134, DGLDDRK73_C, + DGLDDRK84_C, DGLDDRK84_F, SHLDDRK64, RDPK3Sp49, RDPK3SpFSAL49, RDPK3Sp510, RDPK3SpFSAL510, + Alshina6, RKM, MSRK5, MSRK6, Anas5, RKO65, RK46NL, ORK256, KYK2014DGSSPRK_3S2, + SSPRK22, SSPRK104, SSPRK54, SSPRK932, SSPRK83, SSPRK73, SSPRK63, SSPRK53_H, + SSPRK53_2N2, SSPRK53_2N1, SSPRK53, SSPRK33, SHLDDRK_2N, SHLDDRK52, KYKSSPRK42, + CarpenterKennedy2N54, CFRLDDRK64, TSLDDRK74, ParsaniKetchesonDeconinck3S32, + ParsaniKetchesonDeconinck3S82, + ParsaniKetchesonDeconinck3S53, ParsaniKetchesonDeconinck3S173, ParsaniKetchesonDeconinck3S94, + ParsaniKetchesonDeconinck3S184, ParsaniKetchesonDeconinck3S105, ParsaniKetchesonDeconinck3S205, + CKLLSRK43_2, CKLLSRK54_3C, CKLLSRK95_4S, CKLLSRK95_4C, CKLLSRK95_4M, CKLLSRK54_3C_3R, + CKLLSRK54_3M_3R, CKLLSRK54_3N_3R, CKLLSRK85_4C_3R, CKLLSRK85_4M_3R, CKLLSRK85_4P_3R, + CKLLSRK54_3N_4R, CKLLSRK54_3M_4R, CKLLSRK65_4M_4R, CKLLSRK85_4FM_4R, CKLLSRK75_4M_5R] #Stepanov5 + + for alg_type in alg_types + test_step_limiter(alg_type) + end +end diff --git a/test/interface/default_solver_tests.jl b/test/interface/default_solver_tests.jl new file mode 100644 index 0000000000..b409ab087c --- /dev/null +++ b/test/interface/default_solver_tests.jl @@ -0,0 +1,86 @@ +using OrdinaryDiffEq, Test, LinearSolve, LinearAlgebra, SparseArrays + +f_2dlinear = (du, u, p, t) -> (@. du = p * u) + +prob_ode_2Dlinear = ODEProblem(f_2dlinear, rand(4, 2), (0.0, 1.0), 1.01) +sol = @inferred solve(prob_ode_2Dlinear) + +tsitsol = solve(prob_ode_2Dlinear, Tsit5()) +# test that default isn't much worse than Tsit5 (we expect it to use Tsit5 for this). +@test sol.stats.naccept == tsitsol.stats.naccept +@test sol.stats.nf == tsitsol.stats.nf +@test all(isequal(1), sol.alg_choice) + +sol = solve(prob_ode_2Dlinear, reltol = 1e-10) +vernsol = solve(prob_ode_2Dlinear, Vern7(), reltol = 1e-10) +# test that default isn't much worse than Tsit5 (we expect it to use Tsit5 for this). +@test sol.stats.naccept == vernsol.stats.naccept +@test sol.stats.nf == vernsol.stats.nf +@test all(isequal(2), sol.alg_choice) + +prob_ode_linear_fast = ODEProblem( + ODEFunction(f_2dlinear, mass_matrix = 2 * I(2)), rand(2), (0.0, 1.0), 1.01) +sol = solve(prob_ode_linear_fast) +@test all(isequal(3), sol.alg_choice) +# for some reason the timestepping here is different from regular Rosenbrock23 (including the initial timestep) + +function rober(u, p, t) + y₁, y₂, y₃ = u + k₁, k₂, k₃ = p + [-k₁ * y₁ + k₃ * y₂ * y₃, + k₁ * y₁ - k₃ * y₂ * y₃ - k₂ * y₂^2, + k₂ * y₂^2] +end +prob_rober = ODEProblem(rober, [1.0, 0.0, 0.0], (0.0, 1e3), (0.04, 3e7, 1e4)) +sol = solve(prob_rober) +rosensol = solve(prob_rober, AutoTsit5(Rosenbrock23(autodiff = false))) +# test that default has the same performance as AutoTsit5(Rosenbrock23()) (which we expect it to use for this). +@test sol.stats.naccept == rosensol.stats.naccept +@test sol.stats.nf == rosensol.stats.nf +@test unique(sol.alg_choice) == [1, 3] +@test sol.alg_choice[1] == 1 +@test sol.alg_choice[end] == 3 + +sol = solve(prob_rober, reltol = 1e-7, abstol = 1e-7) +rosensol = solve( + prob_rober, AutoVern7(Rodas5P(autodiff = false)), reltol = 1e-7, abstol = 1e-7) +# test that default has the same performance as AutoTsit5(Rosenbrock23()) (which we expect it to use for this). +@test sol.stats.naccept == rosensol.stats.naccept +@test sol.stats.nf == rosensol.stats.nf +@test unique(sol.alg_choice) == [2, 4] +@test sol.alg_choice[1] == 2 +@test sol.alg_choice[end] == 4 + +function exrober(du, u, p, t) + y₁, y₂, y₃ = u + k₁, k₂, k₃ = p + du .= vcat( + [-k₁ * y₁ + k₃ * y₂ * y₃, + k₁ * y₁ - k₃ * y₂ * y₃ - k₂ * y₂^2, + k₂ * y₂^2], u[4:end]) +end + +for n in (100,) # 600 should be added but currently is broken for unknown reasons + stiffalg = n < 50 ? 4 : n < 500 ? 5 : 6 + linsolve = n < 500 ? nothing : KrylovJL_GMRES() + jac_prototype = sparse(I(n + 3)) + jac_prototype[1:3, 1:3] .= 1.0 + + prob_ex_rober = ODEProblem(ODEFunction(exrober; jac_prototype), + vcat([1.0, 0.0, 0.0], ones(n)), (0.0, 100.0), (0.04, 3e7, 1e4)) + sol = solve(prob_ex_rober) + fsol = solve(prob_ex_rober, AutoTsit5(FBDF(; autodiff = false, linsolve))) + # test that default has the same performance as AutoTsit5(Rosenbrock23()) (which we expect it to use for this). + @test sol.stats.naccept == fsol.stats.naccept + @test sol.stats.nf == fsol.stats.nf + @test unique(sol.alg_choice) == [1, stiffalg] +end + +function swaplinear(u, p, t) + [u[2], u[1]] .* p +end +swaplinearf = ODEFunction(swaplinear, mass_matrix = ones(2, 2) - I(2)) +prob_swaplinear = ODEProblem(swaplinearf, rand(2), (0.0, 1.0), 1.01) +sol = solve(prob_swaplinear, reltol = 1e-7) # reltol must be set to avoid running into a bug with Rosenbrock23 +@test all(isequal(4), sol.alg_choice) +# for some reason the timestepping here is different from regular Rodas5P (including the initial timestep) diff --git a/test/interface/inplace_interpolation.jl b/test/interface/inplace_interpolation.jl index 88cdd084c3..474ef15708 100644 --- a/test/interface/inplace_interpolation.jl +++ b/test/interface/inplace_interpolation.jl @@ -25,7 +25,7 @@ out_VMF = vecarrzero(ntt, size(prob_ode_2Dlinear.u0)) # Vector{Matrix{Float64} @test_throws MethodError sol_ODE(out_VF, tt; idxs = 1:1) @test sol_ODE(out_VF, tt) isa Vector{Float64} @test sol_ODE(out_VVF_1, tt) isa Vector{Vector{Float64}} - @test sol_ODE_interp.u == out_VF + @test sol_ODE_interp.u ≈ out_VF end @testset "2D" begin diff --git a/test/interface/interpolation_output_types.jl b/test/interface/interpolation_output_types.jl index a35c926e16..5a6767768f 100644 --- a/test/interface/interpolation_output_types.jl +++ b/test/interface/interpolation_output_types.jl @@ -17,10 +17,10 @@ res1 = solve(prob, Vern8(), dt = 1 / 10, saveat = 1 / 10) res3 = solve(prob, CalvoSanz4(), dt = 1 / 10, saveat = 1 / 10) sol = solve(prob, CalvoSanz4(), dt = 1 / 10) -@test sol(0.32) isa OrdinaryDiffEq.ArrayPartition -@test sol(0.32, Val{1}) isa OrdinaryDiffEq.ArrayPartition -@test sol(0.32, Val{2}) isa OrdinaryDiffEq.ArrayPartition -@test sol(0.32, Val{3}) isa OrdinaryDiffEq.ArrayPartition +@test sol(0.32) isa RecursiveArrayTools.ArrayPartition +@test sol(0.32, Val{1}) isa RecursiveArrayTools.ArrayPartition +@test sol(0.32, Val{2}) isa RecursiveArrayTools.ArrayPartition +@test sol(0.32, Val{3}) isa RecursiveArrayTools.ArrayPartition function f(du, u, p, t) du .= u @@ -40,3 +40,30 @@ sol(0:0.1:100; idxs = [1, 2]) @test sol(0:0.1:100) isa DiffEqArray @test length(sol(0:0.1:100)) == length(0:0.1:100) @test length(sol(0:0.1:100).u[1]) == 3 + +## Test DPRKN Interpolation + +#Parameters +ω = 1 + +#Initial Conditions +x₀ = [0.0] +dx₀ = [π / 2] +tspan = (0.0, 2π) + +ϕ = atan((dx₀[1] / ω) / x₀[1]) +A = √(x₀[1]^2 + dx₀[1]^2) + +function harmonicoscillator(ddu, du, u, ω, t) + ddu .= -ω^2 * u +end + +prob = SecondOrderODEProblem(harmonicoscillator, dx₀, x₀, tspan, ω) +sol = solve(prob, DPRKN6()) +@test sol(0.5) isa RecursiveArrayTools.ArrayPartition +@test sol(0.5; idxs = 1) isa Number +@test sol(0.5; idxs = [1]) isa Vector +@test sol(0.5; idxs = [1, 2]) isa Vector +@test Vector(sol(0.5)) == sol(0.5; idxs = [1, 2]) +@test reverse(Vector(sol(0.5))) == sol(0.5; idxs = [2, 1]) +@test Vector(sol(0.5)) == [sol(0.5; idxs = 1); sol(0.5; idxs = 2)] diff --git a/test/interface/ode_initdt_tests.jl b/test/interface/ode_initdt_tests.jl index 7f6f18e78d..3e8b7c85e9 100644 --- a/test/interface/ode_initdt_tests.jl +++ b/test/interface/ode_initdt_tests.jl @@ -21,7 +21,7 @@ dt₀ = sol3.t[2] T = Float32 u0 = T.([1.0; 0.0; 0.0]) -tspan = T.((0, 100)) +tspan = T.((0, 70)) prob = remake(prob, u0 = u0, tspan = tspan) @test_nowarn solve(prob, Euler(); dt = T(0.0001)) diff --git a/test/interface/ode_saveat_tests.jl b/test/interface/ode_saveat_tests.jl index beb6671c92..b945941149 100644 --- a/test/interface/ode_saveat_tests.jl +++ b/test/interface/ode_saveat_tests.jl @@ -39,37 +39,42 @@ end sol = solve(prob_forward, RK4(), dt = 1 / 2^(2), save_everystep = true, adaptive = false) sol2 = solve(prob_forward, RK4(), dt = 1 / 2^(2), save_everystep = true, adaptive = false, saveat = [0.125, 0.6, 0.61, 0.8]) - +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.125, 0.6, 0.61, 0.8] sol = solve(prob_forward, Rosenbrock32(), dt = 1 / 2^(2), save_everystep = true) sol2 = solve(prob_forward, Rosenbrock32(), dt = 1 / 2^(2), save_everystep = true, saveat = [0.125, 0.6, 0.61, 0.8]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.125, 0.6, 0.61, 0.8] sol = solve(prob_forward, Trapezoid(), dt = 1 / 2^(2), save_everystep = true) sol2 = solve(prob_forward, Trapezoid(), dt = 1 / 2^(2), save_everystep = true, saveat = [0.125, 0.6, 0.61, 0.8]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.125, 0.6, 0.61, 0.8] sol = solve(prob_reverse, RK4(), dt = 1 / 2^(2), save_everystep = true, adaptive = false) sol2 = solve(prob_reverse, RK4(), dt = 1 / 2^(2), save_everystep = true, adaptive = false, saveat = [0.8, 0.61, 0.6, 0.125]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.8, 0.61, 0.6, 0.125] sol = solve(prob_reverse, Rosenbrock32(), dt = 1 / 2^(2), save_everystep = true) sol2 = solve(prob_reverse, Rosenbrock32(), dt = 1 / 2^(2), save_everystep = true, saveat = [0.8, 0.61, 0.6, 0.125]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.8, 0.61, 0.6, 0.125] sol = solve(prob_reverse, Trapezoid(), dt = 1 / 2^(2), save_everystep = true) sol2 = solve(prob_reverse, Trapezoid(), dt = 1 / 2^(2), save_everystep = true, saveat = [0.8, 0.61, 0.6, 0.125]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.8, 0.61, 0.6, 0.125] prob = prob_ode_2Dlinear @@ -78,28 +83,33 @@ sol = solve(prob, DP5(), dt = 1 // 2^(2), save_everystep = true) sol2 = solve(prob, DP5(), dt = 1 // 2^(2), save_everystep = true, saveat = [0.0, 1 / 2, 1.0]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [1 / 2] sol = solve(prob, RK4(), dt = 1 / 2^(2), save_everystep = true, adaptive = false) sol2 = solve(prob, RK4(), dt = 1 / 2^(2), save_everystep = true, adaptive = false, saveat = [0.0, 0.125, 0.6, 0.61, 0.8, 1.0]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.125, 0.6, 0.61, 0.8] sol = solve(prob, Rosenbrock32(), dt = 1 / 2^(2), save_everystep = true) sol2 = solve(prob, Rosenbrock32(), dt = 1 / 2^(2), save_everystep = true, saveat = [0.125, 0.6, 0.61, 0.8]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test symdiff(sol.t, sol2.t) == [0.125, 0.6, 0.61, 0.8] sol = solve(prob, Trapezoid(), dt = 1 / 2^(2), save_everystep = false) sol2 = solve(prob, Trapezoid(), dt = 1 / 2^(2), saveat = [0.125, 0.6, 0.61, 0.8]) +@test sol.retcode == sol2.retcode == ReturnCode.Success @test sort!(symdiff(sol.t, sol2.t)) == [0.0, 0.125, 0.6, 0.61, 0.8, 1.0] sol = solve(prob, Trapezoid(), dt = 1 / 2^(2), save_everystep = true, dense = false, saveat = [0, 0.125, 0.6, 0.61, 0.8]) +@test sol.retcode == ReturnCode.Success @test !(sol.t[2] ≈ 0) # Test Iterators @@ -107,11 +117,13 @@ sol = solve(prob, Trapezoid(), dt = 1 / 2^(2), save_everystep = true, dense = fa sol2 = solve(prob, DP5(), dt = 1 // 2^(2), save_everystep = false, dense = false, saveat = 0:(1 // 100):1) +@test sol2.retcode == ReturnCode.Success @test sol2.t ≈ collect(0:(1 // 100):1) sol2 = solve(prob, DP5(), dt = 1 // 2^(2), save_everystep = false, dense = false, saveat = range(0, stop = 1, length = 100)) +@test sol2.retcode == ReturnCode.Success @test sol2.t ≈ range(0, stop = 1, length = 100) f = (du, u, p, t) -> prob.f(du, u, p, t) diff --git a/test/regression/iipvsoop_tests.jl b/test/regression/iipvsoop_tests.jl index df0fb77696..1a70809d84 100644 --- a/test/regression/iipvsoop_tests.jl +++ b/test/regression/iipvsoop_tests.jl @@ -118,8 +118,8 @@ working_rosenbrock_algs = [Rosenbrock23(), ROS3P(), Rodas3(), Ros4LStab(), Rodas4(), Rodas42(), Rodas4P(), Rodas5(), Rodas23W(), Rodas3P(), Rodas5Pe(), Rodas5P(), ROS2(), ROS2PR(), ROS2S(), ROS3(), ROS3PR(), Scholz4_7(), - ROS34PW1a(), ROS34PW1b(), ROS34PW2(), ROS34PW3(), - ROS34PRw(), ROS3PRL(), ROS3PRL2()] + ROS34PW1a(), ROS34PW1b(), ROS34PW2(), ROS34PW3(), + ROS34PRw(), ROS3PRL(), ROS3PRL2()] rosenbrock_algs = [Rosenbrock32() ] diff --git a/test/runtests.jl b/test/runtests.jl index dcfb6f2345..e476da28c3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -52,6 +52,7 @@ end @time @safetestset "Controller Tests" include("interface/controllers.jl") @time @safetestset "Inplace Interpolation Tests" include("interface/inplace_interpolation.jl") @time @safetestset "Algebraic Interpolation Tests" include("interface/algebraic_interpolation.jl") + @time @safetestset "Default Solver Tests" include("interface/default_solver_tests.jl") end if !is_APPVEYOR && (GROUP == "All" || GROUP == "InterfaceII" || GROUP == "Interface") @@ -104,6 +105,7 @@ end @time @safetestset "Error Check Tests" include("integrators/check_error.jl") @time @safetestset "Event Detection Tests" include("integrators/event_detection_tests.jl") @time @safetestset "Event Repetition Detection Tests" include("integrators/event_repeat_tests.jl") + @time @safetestset "Step Limiter Tests" include("integrators/step_limiter_test.jl") end if !is_APPVEYOR && @@ -191,5 +193,6 @@ end @time @safetestset "Autoswitch GPU" include("gpu/autoswitch.jl") @time @safetestset "Linear LSRK GPU" include("gpu/linear_lsrk.jl") @time @safetestset "Reaction-Diffusion Stiff Solver GPU" include("gpu/reaction_diffusion_stiff.jl") + @time @safetestset "Scalar indexing bug bypass" include("gpu/hermite_test.jl") end end # @time