|
1 | 1 | using ModelingToolkit, JumpProcesses, LinearAlgebra, NonlinearSolve, Optimization, |
2 | 2 | OptimizationOptimJL, OrdinaryDiffEq, RecursiveArrayTools, SciMLBase, |
3 | | - SteadyStateDiffEq, StochasticDiffEq, SymbolicIndexingInterface, |
| 3 | + SteadyStateDiffEq, StochasticDiffEq, DelayDiffEq, SymbolicIndexingInterface, |
4 | 4 | DiffEqCallbacks, Test, Plots |
5 | 5 | using ModelingToolkit: t_nounits as t, D_nounits as D |
6 | 6 |
|
|
922 | 922 | @test_throws ErrorException sol(-0.1; idxs = sys.c) |
923 | 923 | @test_throws ErrorException sol(-0.1; idxs = [sys.x, sys.x + sys.c]) |
924 | 924 | end |
| 925 | + |
| 926 | +@testset "DDEs" begin |
| 927 | + function oscillator(; name, k = 1.0, τ = 0.01) |
| 928 | + @parameters k=k τ=τ |
| 929 | + @variables x(..)=0.1 y(t)=0.1 jcn(t)=0.0 delx(t) |
| 930 | + eqs = [D(x(t)) ~ y, |
| 931 | + D(y) ~ -k * x(t - τ) + jcn, |
| 932 | + delx ~ x(t - τ)] |
| 933 | + return System(eqs, t; name = name) |
| 934 | + end |
| 935 | + systems = @named begin |
| 936 | + osc1 = oscillator(k = 1.0, τ = 0.01) |
| 937 | + osc2 = oscillator(k = 2.0, τ = 0.04) |
| 938 | + end |
| 939 | + eqs = [osc1.jcn ~ osc2.delx, |
| 940 | + osc2.jcn ~ osc1.delx] |
| 941 | + @named coupledOsc = System(eqs, t) |
| 942 | + @named coupledOsc = compose(coupledOsc, systems) |
| 943 | + sys = structural_simplify(coupledOsc) |
| 944 | + prob = DDEProblem(sys, [], (0.0, 10.0); constant_lags = [sys.osc1.τ, sys.osc2.τ]) |
| 945 | + # TODO: Remove this hack once MTK can generate appropriate observed functions |
| 946 | + fn = prob.f |
| 947 | + function fake_observed(_) |
| 948 | + return function obsfn(u, h, p, t) |
| 949 | + return u + h(p, t - 0.1) |
| 950 | + end |
| 951 | + end |
| 952 | + |
| 953 | + struct NonMarkovianWrapper{S} |
| 954 | + sys::S |
| 955 | + end |
| 956 | + SymbolicIndexingInterface.symbolic_container(x::NonMarkovianWrapper) = x.sys |
| 957 | + SymbolicIndexingInterface.is_markovian(::NonMarkovianWrapper) = false |
| 958 | + fn = DDEFunction(fn.f; observed = fake_observed, sys = NonMarkovianWrapper(fn.sys)) |
| 959 | + function fake_hist(p, t) |
| 960 | + return ones(length(prob.u0)) .* t |
| 961 | + end |
| 962 | + prob = DDEProblem( |
| 963 | + fn, prob.u0, fake_hist, prob.tspan, prob.p; constant_lags = prob.constant_lags) |
| 964 | + sym = sys.osc1.delx |
| 965 | + @test prob[sym] ≈ prob.u0 .+ (prob.tspan[1] - 0.1) |
| 966 | + integ = init(prob, MethodOfSteps(Tsit5())) |
| 967 | + step!(integ, 10.0, true) |
| 968 | + # DelayDiffEq wraps `integ.f` and that doesn't contain `.observed` |
| 969 | + # so the hack above doesn't work. `@reset` also doesn't work. |
| 970 | + @test_broken integ[sym] ≈ integ.u + SciMLBase.get_sol(integ)(9.9) |
| 971 | + sol = solve(prob, MethodOfSteps(Tsit5())) |
| 972 | + @test sol[sym] ≈ sol.u .+ sol(sol.t .- 0.1).u |
| 973 | +end |
0 commit comments