diff --git a/CHANGELOG.md b/CHANGELOG.md index c77518ac..e3881573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# main + +- Support StochasticDiffEq v6.96+, where the diffusion function is no longer reachable via `integrator.g`. The extension now reads it from the `SDEProblem` (`prob.g`), which is a stable SciMLBase accessor that works across both old and new StochasticDiffEq versions. +- Run the multiplicative and non-diagonal noise examples on the `CoupledSDEs` docs page so they actually integrate a trajectory. + # v3.15 - New function `named_variables(ds)` for getting the variable names of an MTK-generated dynamical system. diff --git a/Project.toml b/Project.toml index a65de88c..91add9c3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DynamicalSystemsBase" uuid = "6e36e845-645a-534a-86f2-f5d4aa5a06b4" repo = "https://github.com/JuliaDynamics/DynamicalSystemsBase.jl.git" -version = "3.15.6" +version = "3.16.0" [deps] ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" diff --git a/docs/src/CoupledSDEs.md b/docs/src/CoupledSDEs.md index add9f3ce..355f38b0 100644 --- a/docs/src/CoupledSDEs.md +++ b/docs/src/CoupledSDEs.md @@ -84,6 +84,8 @@ function g!(du, u, p, t) return nothing end sde = CoupledSDEs(f!, rand(2)./10; g=g!) +tr = trajectory(sde, 1.0) +plot_trajectory(tr...) ``` #### Non-diagonal noise @@ -105,6 +107,8 @@ function g!(du, u, p, t) end diffeq = (alg = RKMilCommute(), reltol = 1e-3, abstol = 1e-3, dt=0.1) sde = CoupledSDEs(f!, rand(2)./10; g=g!, noise_prototype = zeros(2, 2), diffeq = diffeq) +tr = trajectory(sde, 1.0) +plot_trajectory(tr...) ``` !!! warning diff --git a/ext/src/CoupledSDEs.jl b/ext/src/CoupledSDEs.jl index 1e4aca21..12a6fb33 100644 --- a/ext/src/CoupledSDEs.jl +++ b/ext/src/CoupledSDEs.jl @@ -85,6 +85,10 @@ function DynamicalSystemsBase.CoupledSDEs( end solver, remaining = _decompose_into_sde_solver_and_remaining(diffeq) + # The default `dtmin` from SciML scales with `tspan`. With our open-ended + # `tspan = (0, 1e11)` it becomes ~1e-5, which is too coarse for the SDE + # adaptive controller and causes spurious `DtLessThanMin` aborts. + remaining = haskey(remaining, :dtmin) ? remaining : merge((dtmin = 0.0,), remaining) integ = __init( prob, solver; diff --git a/ext/src/classification.jl b/ext/src/classification.jl index 252aa294..9b4d54b3 100644 --- a/ext/src/classification.jl +++ b/ext/src/classification.jl @@ -50,7 +50,8 @@ function diffusion_function(g, IIP, noise_prototype) end function diffusion_function(ds::CoupledSDEs{IIP}) where {IIP} - return diffusion_function(ds.integ.g, IIP, referrenced_sciml_prob(ds).noise_rate_prototype) + prob = referrenced_sciml_prob(ds) + return diffusion_function(prob.g, IIP, prob.noise_rate_prototype) end """ diff --git a/src/core_systems/continuous_time_ode.jl b/src/core_systems/continuous_time_ode.jl index be39a445..e216109e 100644 --- a/src/core_systems/continuous_time_ode.jl +++ b/src/core_systems/continuous_time_ode.jl @@ -52,7 +52,7 @@ to access the solvers. The default `diffeq` is: $(DynamicalSystemsBase.DEFAULT_DIFFEQ) `diffeq` keywords can also include `callback` for [event handling -](http://docs.juliadiffeq.org/latest/features/callback_functions.html). +](https://docs.sciml.ai/DiffEqDocs/stable/features/callback_functions/). The convenience constructors `CoupledODEs(prob::ODEProblem [, diffeq])` and `CoupledODEs(ds::CoupledODEs [, diffeq])` are also available. diff --git a/test/continuous.jl b/test/continuous.jl index 1249a0d2..846051d6 100644 --- a/test/continuous.jl +++ b/test/continuous.jl @@ -41,6 +41,7 @@ end prob = lorenz_oop.integ.sol.prob ds = CoupledODEs(prob, (alg = Vern9(), abstol = 0.0, reltol = 1.0e-6, verbose = false)) @test ds.integ.alg isa Vern9 - @test ds.integ.opts.verbose == false + # SciML moved from Bool verbose to a `DEVerbosity` struct of per-toggle verbosities. + @test nameof(typeof(ds.integ.opts.verbose.linear_verbosity)) == :None end diff --git a/test/jacobian.jl b/test/jacobian.jl index 831d6634..7daed445 100644 --- a/test/jacobian.jl +++ b/test/jacobian.jl @@ -48,23 +48,23 @@ end jac = jacobian(ds) @test jac isa GeneratedFunctionWrapper - @test jac([1.0, 1.0], [], 0.0) == [-3 0;0 3] + @test jac([1.0, 1.0], prob.p, 0.0) == [-3 0;0 3] @testset "CoupledSDEs" begin # just to check if MTK @brownian does not give any problems using StochasticDiffEq - @brownian β + @brownians β eqs = [ D(u[1]) ~ 3.0 * u[1] + β, D(u[2]) ~ -3.0 * u[2] + β, ] - @mtkbuild sys = System(eqs, t) + @mtkcompile sys = System(eqs, t) prob = SDEProblem(sys, [1.0, 1.0], (0.0, 1.0), jac = true) sde = CoupledSDEs(prob) jac = jacobian(sde) @test jac isa GeneratedFunctionWrapper - @test jac([1.0, 1.0], [], 0.0) == [-3 0; 0 3] + @test jac([1.0, 1.0], prob.p, 0.0) == [-3 0; 0 3] end end diff --git a/test/stochastic.jl b/test/stochastic.jl index b48172f6..00d966b0 100644 --- a/test/stochastic.jl +++ b/test/stochastic.jl @@ -73,7 +73,8 @@ end diffeq = (alg = SRA(), abstol = 1.0e-3, reltol = 1.0e-3, verbose = false) ) @test lorenz_SRA.integ.alg isa SRA - @test lorenz_SRA.integ.opts.verbose == false + # SciML moved from Bool verbose to a `DEVerbosity` struct of per-toggle verbosities. + @test nameof(typeof(lorenz_SRA.integ.opts.verbose.linear_verbosity)) == :None # also test SDEproblem creation prob = lorenz_SRA.integ.sol.prob @@ -81,7 +82,7 @@ end ds = CoupledSDEs(prob, (alg = SRA(), abstol = 0.0, reltol = 1.0e-3, verbose = false)) @test ds.integ.alg isa SRA - @test ds.integ.opts.verbose == false + @test nameof(typeof(ds.integ.opts.verbose.linear_verbosity)) == :None @test_throws ArgumentError CoupledSDEs(prob; diffeq = (alg = SRA(),)) @@ -104,7 +105,10 @@ end corr = CoupledSDEs(f, zeros(2); covariance = [1 0.3; 0.3 1]) corr_alt = CoupledSDEs(f, zeros(2); g = g, noise_prototype = zeros(2, 2)) @test corr.noise_type == corr_alt.noise_type - @test all(corr.integ.g(zeros(2), (), 0.0) .== corr_alt.integ.g(zeros(2), (), 0.0)) + @test all( + DynamicalSystemsBase.referrenced_sciml_prob(corr).g(zeros(2), (), 0.0) .== + DynamicalSystemsBase.referrenced_sciml_prob(corr_alt).g(zeros(2), (), 0.0) + ) end @testset "ArgumentError" begin