Skip to content

Commit b154436

Browse files
committed
Support for Jump & Reaction systems.
1 parent 1d9a036 commit b154436

File tree

5 files changed

+79
-16
lines changed

5 files changed

+79
-16
lines changed

src/ModelingToolkit.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ include("systems/diffeqs/sdesystem.jl")
116116
include("systems/diffeqs/abstractodesystem.jl")
117117
include("systems/diffeqs/first_order_transform.jl")
118118
include("systems/diffeqs/modelingtoolkitize.jl")
119-
include("systems/diffeqs/validation.jl")
120119
include("systems/diffeqs/basic_transformations.jl")
121120

122121
include("systems/jumps/jumpsystem.jl")
@@ -130,10 +129,10 @@ include("systems/control/controlsystem.jl")
130129
include("systems/pde/pdesystem.jl")
131130

132131
include("systems/reaction/reactionsystem.jl")
133-
include("systems/dependency_graphs.jl")
134132

135133
include("systems/discrete_system/discrete_system.jl")
136-
134+
include("systems/validation.jl")
135+
include("systems/dependency_graphs.jl")
137136
include("systems/systemstructure.jl")
138137
using .SystemStructures
139138

src/systems/jumps/jumpsystem.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractSystem
5757
if checks
5858
check_variables(states, iv)
5959
check_parameters(ps, iv)
60+
check_units(ap,iv)
6061
end
6162
new{U}(ap, iv, states, ps, var_to_name, observed, name, systems, defaults, connection_type)
6263
end

src/systems/reaction/reactionsystem.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ struct ReactionSystem <: AbstractSystem
162162
ps′ = value.(ps)
163163
check_variables(states′, iv′)
164164
check_parameters(ps′, iv′)
165+
check_units(eqs)
165166
end
166167
new(collect(eqs), iv′, states′, ps′, observed, name, systems, defaults, connection_type)
167168
end

src/systems/diffeqs/validation.jl renamed to src/systems/validation.jl

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Base.:*(x::Union{Num,Symbolic},y::Unitful.AbstractQuantity) = x * y
22

33
"Find the units of a symbolic item."
4-
get_units(x) = 1
4+
get_units(x::Real) = 1
55
get_units(x::Unitful.Quantity) = 1 * Unitful.unit(x)
66
get_units(x::Num) = get_units(value(x))
77
function get_units(x::Symbolic)
@@ -53,7 +53,7 @@ function safe_get_units(term, info)
5353
side
5454
end
5555

56-
function _validate(terms::Vector, labels::Vector; info::String = "")
56+
function _validate(terms::Vector, labels::Vector{String}; info::String = "")
5757
equnits = safe_get_units.(terms, info*", ".*labels)
5858
allthere = all(map(x -> x!==nothing, equnits))
5959
allmatching = true
@@ -86,20 +86,50 @@ function validate(eq::ModelingToolkit.Equation, noisevec::Vector; info::String =
8686
_validate(terms, labels, info = info)
8787
end
8888

89-
function validate(eqs::Vector{ModelingToolkit.Equation})
90-
all([validate(eqs[idx], info = "In eq. #$idx") for idx in 1:length(eqs)])
89+
function validate(eqs::Vector{ModelingToolkit.Equation}; info::String = "")
90+
all([validate(eqs[idx], info = info*"in eq. #$idx") for idx in 1:length(eqs)])
9191
end
9292

9393
function validate(eqs::Vector{ModelingToolkit.Equation}, noise::Vector)
94-
all([validate(eqs[idx], noise[idx], info = "In eq. #$idx") for idx in 1:length(eqs)])
94+
all([validate(eqs[idx], noise[idx], info = "in eq. #$idx") for idx in 1:length(eqs)])
9595
end
9696

9797
function validate(eqs::Vector{ModelingToolkit.Equation}, noise::Matrix)
98-
all([validate(eqs[idx], noise[idx, :], info = "In eq. #$idx") for idx in 1:length(eqs)])
98+
all([validate(eqs[idx], noise[idx, :], info = "in eq. #$idx") for idx in 1:length(eqs)])
9999
end
100100

101+
function validate(terms::Vector{<:SymbolicUtils.Symbolic})
102+
_validate(terms,["in term #$idx" for idx in 1:length(terms)],info = "")
103+
end
104+
105+
function validate(jump::Union{ModelingToolkit.VariableRateJump, ModelingToolkit.ConstantRateJump}, t::Symbolic; info::String = "")
106+
_validate([jump.rate, 1/t], ["rate", "1/t"], info = info) && # Assuming the rate is per time units
107+
validate(jump.affect!,info = info)
108+
end
109+
110+
function validate(jump::ModelingToolkit.MassActionJump, t::Symbolic; info::String = "")
111+
left_symbols = [x[1] for x in jump.reactant_stoch] #vector of pairs of symbol,int -> vector symbols
112+
net_symbols = [x[1] for x in jump.net_stoch]
113+
all_symbols = vcat(left_symbols,net_symbols)
114+
allgood = _validate(all_symbols, string.(all_symbols), info = info)
115+
n = sum(x->x[2],jump.reactant_stoch,init = 0)
116+
base_unitful = all_symbols[1] #all same, get first
117+
allgood && _validate([jump.scaled_rates, 1/(t*base_unitful^n)], ["scaled_rates", "1/(t*reactants^$n))"], info = info)
118+
end
119+
120+
function validate(jumps::Vector{<:JumpType}, t::Symbolic; info::String = "")
121+
all([validate(jumps[idx], t, info = info*"in jump #$idx") for idx in 1:length(jumps)])
122+
end
123+
124+
function validate(jumps::ArrayPartition{<:Union{Any, Vector{<:JumpType}}}, t::Symbolic)
125+
labels = ["in Mass Action Jumps, ", "in Constant Rate Jumps, ", "in Variable Rate Jumps, "]
126+
all([validate(jumps.x[idx], t, info = labels[idx]) for idx in 1:3])
127+
end
128+
129+
validate(eqs::Vector{<:ModelingToolkit.Reaction}) = validate(oderatelaw.(eqs))
130+
101131
"Returns true iff units of equations are valid."
102-
validate(eqs::Vector) = validate(convert.(ModelingToolkit.Equation, eqs))
132+
validate(eqs::Vector{Any}) = length(eqs) == 0
103133

104134
"Throws error if units of equations are invalid."
105135
check_units(eqs...) = validate(eqs...) || throw(ArgumentError("Some equations had invalid units. See warnings for details."))

test/units.jl

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using ModelingToolkit, Unitful, OrdinaryDiffEq
1+
using ModelingToolkit, Unitful, OrdinaryDiffEq, DiffEqJump
22
using Test
33
MT = ModelingToolkit
44
@parameters τ [unit = u"ms"]
@@ -130,11 +130,11 @@ eqs = [D(E) ~ P - E/τ
130130

131131
noiseeqs = [0.1u"MW",
132132
0.1u"MW"]
133-
sys = SDESystem(eqs,noiseeqs,t,[P,E],[τ,Q])
133+
sys = SDESystem(eqs, noiseeqs, t, [P, E], [τ, Q])
134134
# With noise matrix
135135
noiseeqs = [0.1u"MW" 0.1u"MW"
136136
0.1u"MW" 0.1u"MW"]
137-
sys = SDESystem(eqs,noiseeqs,t,[P,E],[τ,Q])
137+
sys = SDESystem(eqs,noiseeqs, t, [P, E], [τ, Q])
138138

139139
noiseeqs = [0.1u"MW" 0.1u"MW"
140140
0.1u"MW" 0.1u"s"]
@@ -158,10 +158,42 @@ sys_simple = structural_simplify(sys)
158158
@parameters v [unit = u"m/s"] r [unit =u"m"^3/u"s"] t [unit = u"s"]
159159
eqs = [V ~ r*t,
160160
V ~ L^3]
161-
sys = NonlinearSystem(eqs,[V,L],[t,r])
161+
sys = NonlinearSystem(eqs, [V, L], [t, r])
162162
sys_simple = structural_simplify(sys)
163163

164164
eqs = [L ~ v*t,
165165
V ~ L^3]
166-
sys = NonlinearSystem(eqs,[V,L],[t,r])
167-
sys_simple = structural_simplify(sys)
166+
sys = NonlinearSystem(eqs, [V,L], [t,r])
167+
sys_simple = structural_simplify(sys)
168+
169+
#Jump System
170+
@parameters β [unit = 1/(u"mol"^2*u"s")] γ [unit = 1/(u"mol"*u"s")] t [unit = u"s"]
171+
@variables S(t) [unit = u"mol"] I(t) [unit = u"mol"] R(t) [unit = u"mol"]
172+
rate₁ = β*S*I
173+
affect₁ = [S ~ S - 1u"mol", I ~ I + 1u"mol"]
174+
rate₂ = γ*I
175+
affect₂ = [I ~ I - 1u"mol", R ~ R + 1u"mol"]
176+
j₁ = ConstantRateJump(rate₁, affect₁)
177+
j₂ = VariableRateJump(rate₂, affect₂)
178+
js = JumpSystem([j₁, j₂], t, [S, I, R], [β, γ])
179+
180+
affect_wrong = [S ~ S - 1u"mol", I ~ I + 1]
181+
j_wrong = ConstantRateJump(rate₁, affect_wrong)
182+
@test_throws ArgumentError JumpSystem([j_wrong, j₂], t, [S, I, R], [β, γ])
183+
184+
rate_wrong = γ^2*I
185+
j_wrong = ConstantRateJump(rate_wrong, affect₂)
186+
@test_throws ArgumentError JumpSystem([j₁, j_wrong], t, [S, I, R], [β, γ])
187+
188+
# mass action jump tests for SIR model
189+
maj1 = MassActionJump(2*β/2, [S => 1, I => 1], [S => -1, I => 1])
190+
maj2 = MassActionJump(γ, [I => 1], [I => -1, R => 1])
191+
js3 = JumpSystem([maj1, maj2], t, [S,I,R], [β,γ])
192+
193+
#Test unusual jump system
194+
@parameters β γ t
195+
@variables S(t) I(t) R(t)
196+
197+
maj1 = MassActionJump(2.0, [0 => 1], [S => 1])
198+
maj2 = MassActionJump(γ, [S => 1], [S => -1])
199+
js4 = JumpSystem([maj1, maj2], t, [S], [β, γ])

0 commit comments

Comments
 (0)