@@ -42,13 +42,13 @@ Notes:
42
42
- The three-argument form assumes all reactant and product stoichiometric coefficients
43
43
are one.
44
44
"""
45
- struct Reaction{S <: Variable , T <: Number }
45
+ struct Reaction{S, T <: Number }
46
46
""" The rate function (excluding mass action terms)."""
47
47
rate
48
48
""" Reaction substrates."""
49
- substrates:: Vector{Operation}
49
+ substrates:: Vector
50
50
""" Reaction products."""
51
- products:: Vector{Operation}
51
+ products:: Vector
52
52
""" The stoichiometric coefficients of the reactants."""
53
53
substoich:: Vector{T}
54
54
""" The stoichiometric coefficients of the products."""
65
65
function Reaction (rate, subs, prods, substoich, prodstoich;
66
66
netstoich= nothing , only_use_rate= false , kwargs... )
67
67
68
- (isnothing (prods)&& isnothing (subs)) && error (" A reaction requires a non-nothing substrate or product vector." )
69
- (isnothing (prodstoich)&& isnothing (substoich)) && error (" Both substrate and product stochiometry inputs cannot be nothing." )
70
- if isnothing (subs)
71
- subs = Vector {Operation } ()
68
+ (isnothing (prods)&& isnothing (subs)) && error (" A reaction requires a non-nothing substrate or product vector." )
69
+ (isnothing (prodstoich)&& isnothing (substoich)) && error (" Both substrate and product stochiometry inputs cannot be nothing." )
70
+ if isnothing (subs)
71
+ subs = Vector {Term } ()
72
72
! isnothing (substoich) && error (" If substrates are nothing, substrate stiocihometries have to be so too." )
73
73
substoich = typeof (prodstoich)()
74
74
end
75
75
if isnothing (prods)
76
- prods = Vector {Operation } ()
76
+ prods = Vector {Term } ()
77
77
! isnothing (prodstoich) && error (" If products are nothing, product stiocihometries have to be so too." )
78
78
prodstoich = typeof (substoich)()
79
79
end
80
+ subs = value .(subs)
81
+ prods = value .(prods)
80
82
ns = isnothing (netstoich) ? get_netstoich (subs, prods, substoich, prodstoich) : netstoich
81
- Reaction (rate, subs, prods, substoich, prodstoich, ns, only_use_rate)
83
+ Reaction (value ( rate) , subs, prods, substoich, prodstoich, ns, only_use_rate)
82
84
end
83
85
84
86
93
95
# calculates the net stoichiometry of a reaction as a vector of pairs (sub,substoich)
94
96
function get_netstoich (subs, prods, sstoich, pstoich)
95
97
# stoichiometry as a Dictionary
96
- nsdict = Dict {Variable, eltype(sstoich)} (sub. op => - sstoich[i] for (i,sub) in enumerate (subs))
98
+ nsdict = Dict {Any, eltype(sstoich)} (sub => - sstoich[i] for (i,sub) in enumerate (subs))
97
99
for (i,p) in enumerate (prods)
98
100
coef = pstoich[i]
99
- prod = p. op
100
- @inbounds nsdict[prod] = haskey (nsdict, prod) ? nsdict[prod] + coef : coef
101
+ @inbounds nsdict[p] = haskey (nsdict, p) ? nsdict[p] + coef : coef
101
102
end
102
103
103
104
# stoichiometry as a vector
@@ -124,12 +125,12 @@ struct ReactionSystem <: AbstractSystem
124
125
""" The reactions defining the system."""
125
126
eqs:: Vector{Reaction}
126
127
""" Independent variable (usually time)."""
127
- iv:: Variable
128
+ iv:: Any
128
129
""" Dependent (state) variables representing amount of each species."""
129
- states:: Vector{Variable}
130
+ states:: Vector
130
131
""" Parameter variables."""
131
- ps:: Vector{Variable}
132
- pins:: Vector{Variable}
132
+ ps:: Vector
133
+ pins:: Vector
133
134
observed:: Vector{Equation}
134
135
""" The name of the system"""
135
136
name:: Symbol
@@ -138,15 +139,13 @@ struct ReactionSystem <: AbstractSystem
138
139
end
139
140
140
141
function ReactionSystem (eqs, iv, species, params;
141
- pins = Variable [],
142
- observed = Operation [],
142
+ pins = [],
143
+ observed = [],
143
144
systems = ReactionSystem[],
144
145
name = gensym (:ReactionSystem ))
145
146
146
147
isempty (species) && error (" ReactionSystems require at least one species." )
147
- paramvars = map (v -> convert (Variable,v), params)
148
- specvars = map (s -> convert (Variable,s), species)
149
- ReactionSystem (eqs, convert (Variable,iv), specvars, paramvars,
148
+ ReactionSystem (eqs, value (iv), value .(species), value .(params),
150
149
pins, observed, name, systems)
151
150
end
152
151
@@ -187,15 +186,15 @@ function oderatelaw(rx; combinatoric_ratelaw=true)
187
186
end
188
187
189
188
function assemble_drift (rs; combinatoric_ratelaws= true )
190
- D = Differential (rs. iv () )
191
- eqs = [D (x (rs . iv ()) ) ~ 0 for x in rs. states]
189
+ D = Differential (rs. iv)
190
+ eqs = [D (x) ~ 0 for x in rs. states]
192
191
species_to_idx = Dict ((x => i for (i,x) in enumerate (rs. states)))
193
192
194
193
for rx in rs. eqs
195
194
rl = oderatelaw (rx; combinatoric_ratelaw= combinatoric_ratelaws)
196
195
for (spec,stoich) in rx. netstoich
197
196
i = species_to_idx[spec]
198
- if iszero (eqs[i]. rhs)
197
+ if _iszero (eqs[i]. rhs)
199
198
signedrl = (stoich > zero (stoich)) ? rl : - rl
200
199
rhs = isone (abs (stoich)) ? signedrl : stoich * rl
201
200
else
@@ -209,7 +208,7 @@ function assemble_drift(rs; combinatoric_ratelaws=true)
209
208
end
210
209
211
210
function assemble_diffusion (rs, noise_scaling; combinatoric_ratelaws= true )
212
- eqs = Expression[ Constant ( 0 ) for x in rs. states, y in rs. eqs]
211
+ eqs = fill ( Num ( 0 ), length ( rs. states), length ( rs. eqs))
213
212
species_to_idx = Dict ((x => i for (i,x) in enumerate (rs. states)))
214
213
215
214
for (j,rx) in enumerate (rs. eqs)
281
280
"""
282
281
```julia
283
282
ismassaction(rx, rs; rxvars = get_variables(rx.rate),
284
- haveivdep = any(var -> isequal(rs.iv,convert(Variable, var) ), rxvars),
283
+ haveivdep = any(var -> isequal(rs.iv,var), rxvars),
285
284
stateset = Set(states(rs)))
286
285
```
287
286
@@ -297,7 +296,7 @@ explicitly on the independent variable (usually time).
297
296
- Optional: `stateset`, set of states which if the rxvars are within mean rx is non-mass action.
298
297
"""
299
298
function ismassaction (rx, rs; rxvars = get_variables (rx. rate),
300
- haveivdep = any (var -> isequal (rs. iv, convert (Variable,var) ), rxvars),
299
+ haveivdep = any (isequal (rs. iv), rxvars),
301
300
stateset = Set (states (rs)))
302
301
# if no dependencies must be zero order
303
302
(length (rxvars)== 0 ) && return true
311
310
@inline function makemajump (rx; combinatoric_ratelaw= true )
312
311
@unpack rate, substrates, substoich, netstoich = rx
313
312
zeroorder = (length (substoich) == 0 )
314
- reactant_stoch = Vector {Pair{Operation ,eltype(substoich)}} (undef, length (substoich))
313
+ reactant_stoch = Vector {Pair{Term ,eltype(substoich)}} (undef, length (substoich))
315
314
@inbounds for i = 1 : length (reactant_stoch)
316
315
reactant_stoch[i] = var2op (substrates[i]. op) => substoich[i]
317
316
end
@@ -321,27 +320,22 @@ end
321
320
# push!(rates, rate)
322
321
net_stoch = [Pair (var2op (p[1 ]),p[2 ]) for p in netstoich]
323
322
# push!(nstoich, net_stoch)
324
- MassActionJump (rate, reactant_stoch, net_stoch, scale_rates= false , useiszero= false )
323
+
324
+ # XXX : vv--- this sucks
325
+ MassActionJump (Num (rate), reactant_stoch, net_stoch, scale_rates= false , useiszero= false )
325
326
end
326
327
327
328
function assemble_jumps (rs; combinatoric_ratelaws= true )
328
329
meqs = MassActionJump[]; ceqs = ConstantRateJump[]; veqs = VariableRateJump[]
329
330
stateset = Set (states (rs))
330
331
# rates = []; rstoich = []; nstoich = []
331
- rxvars = Operation[]
332
- ivname = rs. iv. name
332
+ rxvars = []
333
333
334
334
isempty (equations (rs)) && error (" Must give at least one reaction before constructing a JumpSystem." )
335
335
for rx in equations (rs)
336
336
empty! (rxvars)
337
- (rx. rate isa Operation) && get_variables! (rxvars, rx. rate)
338
- haveivdep = false
339
- @inbounds for i = 1 : length (rxvars)
340
- if rxvars[i]. op. name == ivname
341
- haveivdep = true
342
- break
343
- end
344
- end
337
+ (rx. rate isa Term) && get_variables! (rxvars, rx. rate)
338
+ haveivdep = any (isequal (rs. iv), rxvars)
345
339
if ismassaction (rx, rs; rxvars= rxvars, haveivdep= haveivdep, stateset= stateset)
346
340
push! (meqs, makemajump (rx, combinatoric_ratelaw= combinatoric_ratelaws))
347
341
else
@@ -379,6 +373,9 @@ function Base.convert(::Type{<:ODESystem}, rs::ReactionSystem; combinatoric_rate
379
373
systems= convert .(ODESystem,rs. systems))
380
374
end
381
375
376
+ makeparam (s:: Sym ) = Sym {Parameter{Number}} (s. name)
377
+ makeparam (s:: Sym{<:Parameter} ) = s
378
+
382
379
"""
383
380
```julia
384
381
Base.convert(::Type{<:SDESystem},rs::ReactionSystem)
@@ -400,12 +397,30 @@ Finally, a `Vector{Operation}` can be provided (the length must be equal to the
400
397
Here the noise for each reaction is scaled by the corresponding parameter in the input vector.
401
398
This input may contain repeat parameters.
402
399
"""
403
- function Base. convert (:: Type{<:SDESystem} ,rs:: ReactionSystem , combinatoric_ratelaws= true ; noise_scaling= nothing :: Union{Vector{Operation},Operation,Nothing} )
404
- (typeof (noise_scaling) <: Vector{Operation} ) && (length (noise_scaling)!= length (rs. eqs)) && error (" The number of elements in 'noise_scaling' must be equal to the number of reactions in the reaction system." )
405
- (typeof (noise_scaling) <: Operation ) && (noise_scaling = fill (noise_scaling,length (rs. eqs)))
400
+ function Base. convert (:: Type{<:SDESystem} ,rs:: ReactionSystem , combinatoric_ratelaws= true ; noise_scaling= nothing )
401
+
402
+ if noise_scaling isa Vector
403
+ (length (noise_scaling)!= length (rs. eqs)) &&
404
+ error (" The number of elements in 'noise_scaling' must be equal " *
405
+ " to the number of reactions in the reaction system." )
406
+ noise_scaling = value .(noise_scaling)
407
+ elseif ! isnothing (noise_scaling)
408
+ noise_scaling = fill (value (noise_scaling),length (rs. eqs))
409
+ end
410
+
406
411
eqs = assemble_drift (rs; combinatoric_ratelaws= combinatoric_ratelaws)
407
- noiseeqs = assemble_diffusion (rs,noise_scaling; combinatoric_ratelaws= combinatoric_ratelaws)
408
- SDESystem (eqs,noiseeqs,rs. iv,rs. states,(noise_scaling=== nothing ) ? rs. ps : union (rs. ps,Variable {ModelingToolkit.Parameter{Number}} .(noise_scaling)),name= rs. name,systems= convert .(SDESystem,rs. systems))
412
+
413
+ noiseeqs = assemble_diffusion (rs,noise_scaling;
414
+ combinatoric_ratelaws= combinatoric_ratelaws)
415
+
416
+ SDESystem (eqs,
417
+ noiseeqs,
418
+ rs. iv,
419
+ rs. states,
420
+ (noise_scaling=== nothing ) ?
421
+ rs. ps :
422
+ union (rs. ps,makeparam .(noise_scaling)),
423
+ name= rs. name,systems= convert .(SDESystem,rs. systems))
409
424
end
410
425
411
426
"""
@@ -499,7 +514,7 @@ function DiffEqBase.SteadyStateProblem(rs::ReactionSystem, u0::Union{AbstractArr
499
514
end
500
515
501
516
# determine which species a reaction depends on
502
- function get_variables! (deps:: Set{Operation} , rx:: Reaction , variables)
517
+ function get_variables! (deps:: Set , rx:: Reaction , variables)
503
518
(rx. rate isa Operation) && get_variables! (deps, rx. rate, variables)
504
519
for s in rx. substrates
505
520
push! (deps, s)
0 commit comments