Skip to content

Commit 928ee8d

Browse files
feat: add is_dde flag for ODESystem and SDESystem
1 parent c0d1112 commit 928ee8d

File tree

6 files changed

+61
-7
lines changed

6 files changed

+61
-7
lines changed

src/systems/abstractsystem.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ for prop in [:eqs
971971
:solved_unknowns
972972
:split_idxs
973973
:parent
974+
:is_dde
974975
:index_cache
975976
:is_scalar_noise
976977
:isscheduled]

src/systems/diffeqs/abstractodesystem.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@ struct Schedule
33
dummy_sub::Any
44
end
55

6+
"""
7+
is_dde(sys::AbstractSystem)
8+
9+
Return a boolean indicating whether a system represents a set of delay
10+
differential equations.
11+
"""
12+
is_dde(sys::AbstractSystem) = has_is_dde(sys) && get_is_dde(sys)
13+
14+
function _check_if_dde(eqs, iv, subsystems)
15+
is_dde = any(ModelingToolkit.is_dde, subsystems)
16+
if !is_dde
17+
vs = Set()
18+
for eq in eqs
19+
vars!(vs, eq)
20+
is_dde = any(vs) do sym
21+
isdelay(unwrap(sym), iv)
22+
end
23+
is_dde && break
24+
end
25+
end
26+
return is_dde
27+
end
28+
629
function filter_kwargs(kwargs)
730
kwargs = Dict(kwargs)
831
for key in keys(kwargs)

src/systems/diffeqs/odesystem.jl

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ struct ODESystem <: AbstractODESystem
141141
"""
142142
gui_metadata::Union{Nothing, GUIMetadata}
143143
"""
144+
A boolean indicating if the given `ODESystem` represents a system of DDEs.
145+
"""
146+
is_dde::Bool
147+
"""
144148
Cache for intermediate tearing state.
145149
"""
146150
tearing_state::Any
@@ -178,7 +182,7 @@ struct ODESystem <: AbstractODESystem
178182
torn_matching, initializesystem, initialization_eqs, schedule,
179183
connector_type, preface, cevents,
180184
devents, parameter_dependencies,
181-
metadata = nothing, gui_metadata = nothing,
185+
metadata = nothing, gui_metadata = nothing, is_dde = false,
182186
tearing_state = nothing,
183187
substitutions = nothing, complete = false, index_cache = nothing,
184188
discrete_subsystems = nothing, solved_unknowns = nothing,
@@ -198,7 +202,7 @@ struct ODESystem <: AbstractODESystem
198202
ctrl_jac, Wfact, Wfact_t, name, systems, defaults, guesses, torn_matching,
199203
initializesystem, initialization_eqs, schedule, connector_type, preface,
200204
cevents, devents, parameter_dependencies, metadata,
201-
gui_metadata, tearing_state, substitutions, complete, index_cache,
205+
gui_metadata, is_dde, tearing_state, substitutions, complete, index_cache,
202206
discrete_subsystems, solved_unknowns, split_idxs, parent)
203207
end
204208
end
@@ -223,7 +227,8 @@ function ODESystem(deqs::AbstractVector{<:Equation}, iv, dvs, ps;
223227
parameter_dependencies = Equation[],
224228
checks = true,
225229
metadata = nothing,
226-
gui_metadata = nothing)
230+
gui_metadata = nothing,
231+
is_dde = nothing)
227232
name === nothing &&
228233
throw(ArgumentError("The `name` keyword must be provided. Please consider using the `@named` macro"))
229234
@assert all(control -> any(isequal.(control, ps)), controls) "All controls must also be parameters."
@@ -266,12 +271,15 @@ function ODESystem(deqs::AbstractVector{<:Equation}, iv, dvs, ps;
266271
disc_callbacks = SymbolicDiscreteCallbacks(discrete_events)
267272
parameter_dependencies, ps′ = process_parameter_dependencies(
268273
parameter_dependencies, ps′)
274+
if is_dde === nothing
275+
is_dde = _check_if_dde(deqs, iv′, systems)
276+
end
269277
ODESystem(Threads.atomic_add!(SYSTEM_COUNT, UInt(1)),
270278
deqs, iv′, dvs′, ps′, tspan, var_to_name, ctrl′, observed, tgrad, jac,
271279
ctrl_jac, Wfact, Wfact_t, name, systems, defaults, guesses, nothing, initializesystem,
272280
initialization_eqs, schedule, connector_type, preface, cont_callbacks,
273281
disc_callbacks, parameter_dependencies,
274-
metadata, gui_metadata, checks = checks)
282+
metadata, gui_metadata, is_dde, checks = checks)
275283
end
276284

277285
function ODESystem(eqs, iv; kwargs...)

src/systems/diffeqs/sdesystem.jl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ struct SDESystem <: AbstractODESystem
133133
be `true` when `noiseeqs isa Vector`.
134134
"""
135135
is_scalar_noise::Bool
136+
"""
137+
A boolean indicating if the given `ODESystem` represents a system of DDEs.
138+
"""
139+
is_dde::Bool
136140
isscheduled::Bool
137141

138142
function SDESystem(tag, deqs, neqs, iv, dvs, ps, tspan, var_to_name, ctrls, observed,
@@ -141,6 +145,7 @@ struct SDESystem <: AbstractODESystem
141145
ctrl_jac, Wfact, Wfact_t, name, systems, defaults, connector_type,
142146
cevents, devents, parameter_dependencies, metadata = nothing, gui_metadata = nothing,
143147
complete = false, index_cache = nothing, parent = nothing, is_scalar_noise = false,
148+
is_dde = false,
144149
isscheduled = false;
145150
checks::Union{Bool, Int} = true)
146151
if checks == true || (checks & CheckComponents) > 0
@@ -165,7 +170,7 @@ struct SDESystem <: AbstractODESystem
165170
ctrl_jac,
166171
Wfact, Wfact_t, name, systems, defaults, connector_type, cevents, devents,
167172
parameter_dependencies, metadata, gui_metadata, complete, index_cache, parent, is_scalar_noise,
168-
isscheduled)
173+
is_dde, isscheduled)
169174
end
170175
end
171176

@@ -188,7 +193,8 @@ function SDESystem(deqs::AbstractVector{<:Equation}, neqs::AbstractArray, iv, dv
188193
complete = false,
189194
index_cache = nothing,
190195
parent = nothing,
191-
is_scalar_noise = false)
196+
is_scalar_noise = false,
197+
is_dde = nothing)
192198
name === nothing &&
193199
throw(ArgumentError("The `name` keyword must be provided. Please consider using the `@named` macro"))
194200
iv′ = value(iv)
@@ -223,11 +229,14 @@ function SDESystem(deqs::AbstractVector{<:Equation}, neqs::AbstractArray, iv, dv
223229
disc_callbacks = SymbolicDiscreteCallbacks(discrete_events)
224230
parameter_dependencies, ps′ = process_parameter_dependencies(
225231
parameter_dependencies, ps′)
232+
if is_dde === nothing
233+
is_dde = _check_if_dde(deqs, iv′, systems)
234+
end
226235
SDESystem(Threads.atomic_add!(SYSTEM_COUNT, UInt(1)),
227236
deqs, neqs, iv′, dvs′, ps′, tspan, var_to_name, ctrl′, observed, tgrad, jac,
228237
ctrl_jac, Wfact, Wfact_t, name, systems, defaults, connector_type,
229238
cont_callbacks, disc_callbacks, parameter_dependencies, metadata, gui_metadata,
230-
complete, index_cache, parent, is_scalar_noise; checks = checks)
239+
complete, index_cache, parent, is_scalar_noise, is_dde; checks = checks)
231240
end
232241

233242
function SDESystem(sys::ODESystem, neqs; kwargs...)

test/dde.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ eqs = [D(x₀) ~ (v0 / (1 + beta0 * (x₂(t - tau)^2))) * (p0 - q0) * x₀ - d0
3838
(v1 / (1 + beta1 * (x₂(t - tau)^2))) * (p1 - q1) * x₁ - d1 * x₁
3939
D(x₂(t)) ~ (v1 / (1 + beta1 * (x₂(t - tau)^2))) * (1 - p1 + q1) * x₁ - d2 * x₂(t)]
4040
@mtkbuild sys = System(eqs, t)
41+
@test ModelingToolkit.is_dde(sys)
4142
prob = DDEProblem(sys,
4243
[x₀ => 1.0, x₁ => 1.0, x₂(t) => 1.0],
4344
tspan,
@@ -77,6 +78,7 @@ sol = solve(prob, RKMil())
7778
τ = 1.0
7879
eqs = [D(x(t)) ~ a * x(t) + b * x(t - τ) + c +* x(t) + γ) * η]
7980
@mtkbuild sys = System(eqs, t)
81+
@test ModelingToolkit.is_dde(sys)
8082
@test equations(sys) == [D(x(t)) ~ a * x(t) + b * x(t - τ) + c]
8183
@test isequal(ModelingToolkit.get_noiseeqs(sys), [α * x(t) + γ])
8284
prob_mtk = SDDEProblem(sys, [x(t) => 1.0 + t], tspan; constant_lags = (τ,));
@@ -100,8 +102,11 @@ end
100102
eqs = [osc1.jcn ~ osc2.delx,
101103
osc2.jcn ~ osc1.delx]
102104
@named coupledOsc = System(eqs, t)
105+
@test ModelingToolkit.is_dde(coupledOsc)
103106
@named coupledOsc = compose(coupledOsc, systems)
107+
@test ModelingToolkit.is_dde(coupledOsc)
104108
@named coupledOsc2 = System(eqs, t; systems)
109+
@test ModelingToolkit.is_dde(coupledOsc2)
105110
for coupledOsc in [coupledOsc, coupledOsc2]
106111
local sys = structural_simplify(coupledOsc)
107112
@test length(equations(sys)) == 4

test/odesystem.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,3 +1394,11 @@ end
13941394
prob = @test_nowarn ODEProblem(sys, nothing, (0.0, 1.0))
13951395
@test_nowarn solve(prob)
13961396
end
1397+
1398+
@testset "ODEs are not DDEs" begin
1399+
@variables x(t)
1400+
@named sys = ODESystem(D(x) ~ x, t)
1401+
@test !ModelingToolkit.is_dde(sys)
1402+
@named sys2 = ODESystem(Equation[], t; systems = [sys])
1403+
@test !ModelingToolkit.is_dde(sys)
1404+
end

0 commit comments

Comments
 (0)