Skip to content

Commit 4cc3dc7

Browse files
DiscreteSystem (#986)
* DiscreteSystem added * Update test/test_epidemiological_compartmental.jl Co-authored-by: Christopher Rackauckas <[email protected]> * Update test/test_epidemiological_compartmental.jl Co-authored-by: Christopher Rackauckas <[email protected]> * Update test/test_epidemiological_compartmental.jl Co-authored-by: Christopher Rackauckas <[email protected]> * Update test/test_epidemiological_compartmental.jl Co-authored-by: Christopher Rackauckas <[email protected]> * DiscreteSystem doesn't need two files * Rename test_epidemiological_compartmental.jl to discretesystem.jl * Update runtests.jl * Update discretesystem.jl * Update discrete_system.jl * Update discretesystem.jl * Update discretesystem.jl * Update discretesystem.jl Co-authored-by: Christopher Rackauckas <[email protected]>
1 parent f253b51 commit 4cc3dc7

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed

src/ModelingToolkit.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ include("systems/pde/pdesystem.jl")
130130
include("systems/reaction/reactionsystem.jl")
131131
include("systems/dependency_graphs.jl")
132132

133+
include("systems/discrete_system/discrete_system.jl")
134+
133135
include("systems/systemstructure.jl")
134136
using .SystemStructures
135137

@@ -162,6 +164,7 @@ export Term, Sym
162164
export SymScope, LocalScope, ParentScope, GlobalScope
163165
export independent_variable, states, parameters, equations, controls, observed, structure
164166
export structural_simplify
167+
export DiscreteSystem, DiscreteProblem
165168

166169
export calculate_jacobian, generate_jacobian, generate_function
167170
export calculate_tgrad, generate_tgrad
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
$(TYPEDEF)
3+
4+
A system of difference equations.
5+
6+
# Fields
7+
$(FIELDS)
8+
9+
# Example
10+
11+
```
12+
using ModelingToolkit
13+
14+
@parameters t σ ρ β
15+
@variables x(t) y(t) z(t) next_x(t) next_y(t) next_z(t)
16+
17+
eqs = [next_x ~ σ*(y-x),
18+
next_y ~ x*(ρ-z)-y,
19+
next_z ~ x*y - β*z]
20+
21+
de = DiscreteSystem(eqs,t,[x,y,z],[σ,ρ,β])
22+
```
23+
"""
24+
struct DiscreteSystem <: AbstractSystem
25+
"""The differential equations defining the discrete system."""
26+
eqs::Vector{Equation}
27+
"""Independent variable."""
28+
iv::Sym
29+
"""Dependent (state) variables."""
30+
states::Vector
31+
"""Parameter variables."""
32+
ps::Vector
33+
observed::Vector{Equation}
34+
"""
35+
Name: the name of the system
36+
"""
37+
name::Symbol
38+
"""
39+
systems: The internal systems. These are required to have unique names.
40+
"""
41+
systems::Vector{DiscreteSystem}
42+
"""
43+
default_u0: The default initial conditions to use when initial conditions
44+
are not supplied in `DiscreteSystem`.
45+
"""
46+
default_u0::Dict
47+
"""
48+
default_p: The default parameters to use when parameters are not supplied
49+
in `DiscreteSystem`.
50+
"""
51+
default_p::Dict
52+
end
53+
54+
"""
55+
$(TYPEDSIGNATURES)
56+
57+
Constructs a DiscreteSystem.
58+
"""
59+
function DiscreteSystem(
60+
discreteEqs::AbstractVector{<:Equation}, iv, dvs, ps;
61+
observed = Num[],
62+
systems = DiscreteSystem[],
63+
name=gensym(:DiscreteSystem),
64+
default_u0=Dict(),
65+
default_p=Dict(),
66+
)
67+
iv′ = value(iv)
68+
dvs′ = value.(dvs)
69+
ps′ = value.(ps)
70+
71+
default_u0 isa Dict || (default_u0 = Dict(default_u0))
72+
default_p isa Dict || (default_p = Dict(default_p))
73+
default_u0 = Dict(value(k) => value(default_u0[k]) for k in keys(default_u0))
74+
default_p = Dict(value(k) => value(default_p[k]) for k in keys(default_p))
75+
76+
sysnames = nameof.(systems)
77+
if length(unique(sysnames)) != length(sysnames)
78+
throw(ArgumentError("System names must be unique."))
79+
end
80+
DiscreteSystem(discreteEqs, iv′, dvs′, ps′, observed, name, systems, default_u0, default_p)
81+
end
82+
83+
"""
84+
$(TYPEDSIGNATURES)
85+
86+
Generates an DiscreteProblem from an DiscreteSystem.
87+
"""
88+
function DiffEqBase.DiscreteProblem(sys::DiscreteSystem,u0map,tspan,
89+
parammap=DiffEqBase.NullParameters();
90+
eval_module = @__MODULE__,
91+
eval_expression = true,
92+
kwargs...)
93+
dvs = states(sys)
94+
ps = parameters(sys)
95+
eqs = equations(sys)
96+
# defs = defaults(sys)
97+
t = get_iv(sys)
98+
u0 = varmap_to_vars(u0map,dvs)
99+
rhss = [eq.rhs for eq in eqs]
100+
u = dvs
101+
p = varmap_to_vars(parammap,ps)
102+
103+
f_gen = build_function(rhss, dvs, ps, t; expression=Val{eval_expression}, expression_module=eval_module)
104+
f_oop,f_iip = (@RuntimeGeneratedFunction(eval_module, ex) for ex in f_gen)
105+
f(u,p,t) = f_oop(u,p,t)
106+
DiscreteProblem(f,u0,tspan,p;kwargs...)
107+
end

test/discretesystem.jl

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Example: Compartmental models in epidemiology
2+
#=
3+
- https://github.com/epirecipes/sir-julia/blob/master/markdown/function_map/function_map.md
4+
- https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#Deterministic_versus_stochastic_epidemic_models
5+
=#
6+
using ModelingToolkit
7+
8+
@inline function rate_to_proportion(r,t)
9+
1-exp(-r*t)
10+
end;
11+
12+
# Independent and dependent variables and parameters
13+
@parameters t c nsteps δt β γ
14+
@variables S(t) I(t) R(t) next_S(t) next_I(t) next_R(t)
15+
16+
infection = rate_to_proportion*c*I/(S+I+R),δt)*S
17+
recovery = rate_to_proportion(γ,δt)*I
18+
19+
# Equations
20+
eqs = [next_S ~ S-infection,
21+
next_I ~ I+infection-recovery,
22+
next_R ~ R+recovery]
23+
24+
# System
25+
sys = DiscreteSystem(eqs,t,[S,I,R],[c,nsteps,δt,β,γ])
26+
27+
# Problem
28+
u0 = [S => 990.0, I => 10.0, R => 0.0]
29+
p ==> 0.05, c => 10.0, γ => 0.25, δt => 0.1, nsteps => 400]
30+
tspan = (0.0,ModelingToolkit.value(substitute(nsteps,p))) # value function (from Symbolics) is used to convert a Num to Float64
31+
prob_map = DiscreteProblem(sys,u0,tspan,p)
32+
33+
# Solution
34+
using OrdinaryDiffEq
35+
sol_map = solve(prob_map,FunctionMap());
36+
37+
# Direct Implementation
38+
39+
function sir_map!(du,u,p,t)
40+
(S,I,R) = u
41+
(β,c,γ,δt) = p
42+
N = S+I+R
43+
infection = rate_to_proportion*c*I/N,δt)*S
44+
recovery = rate_to_proportion(γ,δt)*I
45+
@inbounds begin
46+
du[1] = S-infection
47+
du[2] = I+infection-recovery
48+
du[3] = R+recovery
49+
end
50+
nothing
51+
end;
52+
u0 = [990.0,10.0,0.0];
53+
p = [0.05,10.0,0.25,0.1];
54+
prob_map = DiscreteProblem(sir_map!,u0,tspan,p);
55+
sol_map2 = solve(prob_map,FunctionMap());
56+
57+
@test Array(sol_map) Array(sol_map2)

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ using SafeTestsets, Test
66
@safetestset "Simplify Test" begin include("simplify.jl") end
77
@safetestset "Direct Usage Test" begin include("direct.jl") end
88
@safetestset "System Linearity Test" begin include("linearity.jl") end
9+
@safetestset "DiscreteSystem Test" begin include("discretesystem.jl") end
910
@safetestset "ODESystem Test" begin include("odesystem.jl") end
1011
@safetestset "LabelledArrays Test" begin include("labelledarrays.jl") end
1112
@safetestset "Mass Matrix Test" begin include("mass_matrix.jl") end

0 commit comments

Comments
 (0)