diff --git a/Project.toml b/Project.toml index 21acf70f4d..04fa1d69e7 100644 --- a/Project.toml +++ b/Project.toml @@ -23,7 +23,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] DataStructures = ">= 0.15.0" -DiffEqBase = ">= 5.10.0" +DiffEqBase = ">= 5.17.0" DiffEqDiffTools = ">= 0.14.0" DiffEqOperators = ">= 3.2.0" ExponentialUtilities = ">= 1.2.0" @@ -51,6 +51,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" [targets] -test = ["Calculus", "DiffEqCallbacks", "DiffEqDevTools", "DiffEqProblemLibrary", "DiffEqSensitivity", "InteractiveUtils", "ParameterizedFunctions", "Random", "SafeTestsets", "SparseArrays", "Statistics", "Test", "Unitful"] +test = ["Calculus", "DiffEqCallbacks", "DiffEqDevTools", "DiffEqProblemLibrary", "DiffEqSensitivity", "InteractiveUtils", "ParameterizedFunctions", "Random", "SafeTestsets", "SparseArrays", "Statistics", "Test", "Unitful", "ModelingToolkit"] diff --git a/src/derivative_utils.jl b/src/derivative_utils.jl index c66b8c4646..f52d5ca7de 100644 --- a/src/derivative_utils.jl +++ b/src/derivative_utils.jl @@ -349,6 +349,19 @@ function calc_W!(integrator, cache::OrdinaryDiffEqMutableCache, dtgamma, repeat_ is_compos = integrator.alg isa CompositeAlgorithm isnewton = alg isa NewtonAlgorithm + if W_transform && DiffEqBase.has_Wfact_t(f) + f.Wfact_t(W, u, p, dtgamma, t) + is_compos && (integrator.eigen_est = opnorm(LowerTriangular(W), Inf) + inv(dtgamma)) # TODO: better estimate + return nothing + elseif !W_transform && DiffEqBase.has_Wfact(f) + f.Wfact(W, u, p, dtgamma, t) + if is_compos + opn = opnorm(LowerTriangular(W), Inf) + integrator.eigen_est = (opn + one(opn)) / dtgamma # TODO: better estimate + end + return nothing + end + # fast pass # we only want to factorize the linear operator once new_jac = true @@ -362,7 +375,7 @@ function calc_W!(integrator, cache::OrdinaryDiffEqMutableCache, dtgamma, repeat_ W_dt = isnewton ? cache.nlsolver.cache.W_dt : dt # TODO: RosW new_jac = isnewton ? do_newJ(integrator, alg, cache, repeat_step) : true new_W = isnewton ? do_newW(integrator, cache.nlsolver, new_jac, W_dt) : true - + # calculate W if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing isnewton || DiffEqBase.update_coefficients!(W,uprev,p,t) # we will call `update_coefficients!` in NLNewton @@ -387,6 +400,19 @@ function calc_W!(nlsolver, integrator, cache::OrdinaryDiffEqMutableCache, dtgamm is_compos = integrator.alg isa CompositeAlgorithm isnewton = alg isa NewtonAlgorithm + if W_transform && DiffEqBase.has_Wfact_t(f) + f.Wfact_t(W, u, p, dtgamma, t) + is_compos && (integrator.eigen_est = opnorm(LowerTriangular(W), Inf) + inv(dtgamma)) # TODO: better estimate + return nothing + elseif !W_transform && DiffEqBase.has_Wfact(f) + f.Wfact(W, u, p, dtgamma, t) + if is_compos + opn = opnorm(LowerTriangular(W), Inf) + integrator.eigen_est = (opn + one(opn)) / dtgamma # TODO: better estimate + end + return nothing + end + # fast pass # we only want to factorize the linear operator once new_jac = true @@ -400,7 +426,7 @@ function calc_W!(nlsolver, integrator, cache::OrdinaryDiffEqMutableCache, dtgamm W_dt = isnewton ? nlsolver.cache.W_dt : dt # TODO: RosW new_jac = isnewton ? do_newJ(integrator, alg, cache, repeat_step) : true new_W = isnewton ? do_newW(integrator, nlsolver, new_jac, W_dt) : true - + # calculate W if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing isnewton || DiffEqBase.update_coefficients!(W,uprev,p,t) # we will call `update_coefficients!` in NLNewton diff --git a/test/interface/jacobian_tests.jl b/test/interface/jacobian_tests.jl index e1664597fd..0f74df3b1a 100644 --- a/test/interface/jacobian_tests.jl +++ b/test/interface/jacobian_tests.jl @@ -35,3 +35,21 @@ sol = solve(prob,KenCarp3(),abstol=1e-10,reltol=1e-10) @test sol.errors[:l2] < 8e-4 sol = solve(prob,KenCarp4(),abstol=1e-10,reltol=1e-10) @test sol.errors[:l2] < 1e-7 + +using ModelingToolkit +function lotka(du,u,p,t) + x = u[1] + y = u[2] + du[1] = p[1]*x - p[2]*x*y + du[2] = -p[3]*y + p[4]*x*y +end + +prob = ODEProblem(lotka,[1.0,1.0],(0.0,1.0),[1.5,1.0,3.0,1.0]) +de = ModelingToolkit.modelingtoolkitize(prob) +prob2 = remake(prob, f=ODEFunction(de..., Val(false), Wfact=true)) + +sol = solve(prob, TRBDF2()) + +for Alg in [Rodas5, Rosenbrock23, TRBDF2, KenCarp4] + @test Array( solve(prob2, Alg(), tstops=sol.t, adaptive=false) ) ≈ Array( solve(prob, Alg(), tstops=sol.t, adaptive=false) ) +end diff --git a/test/interface/stiffness_detection_test.jl b/test/interface/stiffness_detection_test.jl index bfa69129db..fa45c7e3fc 100644 --- a/test/interface/stiffness_detection_test.jl +++ b/test/interface/stiffness_detection_test.jl @@ -21,7 +21,7 @@ for (i, prob) in enumerate(probArr) sol = solve(prob, alg) @test length(sol.t) < 280 @test typeof(alg.algs[sol.alg_choice[1]]) <: Rodas5 - @test is_switching_fb(sol) + i == 1 || @test is_switching_fb(sol) # fails due to eigenvalue estimate of J sol = solve(prob, AutoDP5(Rodas5(); maxstiffstep=2, maxnonstiffstep=2, stifftol=11//10, nonstifftol=9//10), reltol=1e-5, abstol=1e-5)