1- struct Reaction{T <: Number }
1+ struct Reaction{S <: Variable , T <: Number }
22 rate
33 substrates:: Vector{Operation}
44 products:: Vector{Operation}
55 substoich:: Vector{T}
6- prodstoich:: Vector{T}
6+ prodstoich:: Vector{T}
7+ netstoich:: Vector{Pair{S,T}}
8+ only_use_rate:: Bool
79end
810
11+ function Reaction (rate, subs, prods, substoich, prodstoich;
12+ netstoich= nothing , only_use_rate= false , kwargs... )
13+
14+ ns = isnothing (netstoich) ? get_netstoich (subs, prods, substoich, prodstoich) : netstoich
15+ Reaction (rate, subs, prods, substoich, prodstoich, ns, only_use_rate)
16+ end
17+
18+ # three argument constructor assumes stoichiometric coefs are one and integers
19+ Reaction (rate, subs, prods; kwargs... ) = Reaction (rate, subs, prods,
20+ ones (Int,length (subs)),
21+ ones (Int,length (prods));
22+ kwargs... )
23+
24+ # calculates the net stoichiometry of a reaction as a vector of pairs (sub,substoich)
25+ function get_netstoich (subs, prods, sstoich, pstoich)
26+ # stoichiometry as a Dictionary
27+ nsdict = Dict (sub. op => - sstoich[i] for (i,sub) in enumerate (subs))
28+ for (i,p) in enumerate (prods)
29+ coef = pstoich[i]
30+ prod = p. op
31+ @inbounds nsdict[prod] = haskey (nsdict, prod) ? nsdict[prod] + coef : coef
32+ end
33+
34+ # stoichiometry as a vector
35+ ns = [el for el in nsdict if el[2 ] != zero (el[2 ])]
36+
37+ ns
38+ end
39+
40+
941struct ReactionSystem <: AbstractSystem
1042 eqs:: Vector{Reaction}
1143 iv:: Variable
12- species :: Vector{Variable}
13- params :: Vector{Variable}
44+ states :: Vector{Variable}
45+ ps :: Vector{Variable}
1446 name:: Symbol
1547 systems:: Vector{ReactionSystem}
1648end
1749
18- function ReactionSystem (eqs, iv, species, params;
19- systems = ReactionSystem[],
20- name = gensym (:ReactionSystem ))
50+ function ReactionSystem (eqs, iv, species, params; systems = ReactionSystem[],
51+ name = gensym (:ReactionSystem ))
2152
22- ReactionSystem (eqs, iv, convert .(Variable,species),
23- convert .(Variable,params), name, systems)
53+ ReactionSystem (eqs, iv, convert .(Variable,species), convert .(Variable,params),
54+ name, systems)
2455end
2556
2657# Calculate the ODE rate law
@@ -37,61 +68,54 @@ function oderatelaw(rx)
3768 rl
3869end
3970
40- function essemble_drift (rs)
71+ function assemble_drift (rs)
4172 D = Differential (rs. iv ())
42- eqs = [D (x (rs. iv ())) ~ 0 for x in rs. species ]
43- species_to_idx = Dict (enumerate (rs. species ))
73+ eqs = [D (x (rs. iv ())) ~ 0 for x in rs. states ]
74+ species_to_idx = Dict ((x => i for (i,x) in enumerate (rs. states) ))
4475
45- # note, this should really use the net stoichiometry to avoid
46- # adding and substracting the same term for A + X -> B + X
4776 for rx in rs. eqs
48- rl = oderatelaw (rx. rate, rx. substrates, rx. substoich)
49- stoich = rx. substoich
50- for (sidx,substrate) in enumerate (rx. substrates)
51- i = species_to_idx[substrate. op]
52- eqs[i] = Equation (eqs[i]. lhs, eqs[i]. rhs - stoich[sidx]* rl)
53- end
54-
55- stoich = rx. prodstoich
56- for (pidx,product) in enumerate (rx. products)
57- i = species_to_idx[product. op]
58- eqs[i] = Equation (eqs[i]. lhs,eqs[i]. rhs + stoich[pidx]* rl)
77+ rl = oderatelaw (rx)
78+ for (spec,stoich) in rx. netstoich
79+ i = species_to_idx[spec]
80+ if iszero (eqs[i]. rhs)
81+ Δspec = (stoich == one (stoich)) ? rl : stoich * rl
82+ eqs[i] = Equation (eqs[i]. lhs, Δspec)
83+ else
84+ Δspec = (abs (stoich) == one (stoich)) ? rl : abs (stoich) * rl
85+ if stoich > zero (stoich)
86+ eqs[i] = Equation (eqs[i]. lhs, eqs[i]. rhs + Δspec)
87+ else
88+ eqs[i] = Equation (eqs[i]. lhs, eqs[i]. rhs - Δspec)
89+ end
90+ end
5991 end
6092 end
61-
6293 eqs
6394end
6495
65- function essemble_diffusion (rs)
66- eqs = Expression[Constant (0 ) for x in rs. species , y in rs. eqs]
67- species_to_idx = Dict (enumerate (rs. species ))
96+ function assemble_diffusion (rs)
97+ eqs = Expression[Constant (0 ) for x in rs. states , y in rs. eqs]
98+ species_to_idx = Dict ((x => i for (i,x) in enumerate (rs. states) ))
6899
69100 for (j,rx) in enumerate (rs. eqs)
70- rlsqrt = sqrt (oderatelaw (rx. rate, rx. substrates, rx. substoich))
71- stoich = rx. substoich
72- for (sidx,substrate) in enumerate (rx. substrates)
73- i = species_to_idx[substrate. op]
74- eqs[i,j] = - stoich[sidx] * rlsqrt
75- end
76-
77- for (pidx,product) in enumerate (rx. products)
78- i = species_to_idx[product. op]
79- Δp = stoich[pidx] * rlsqrt
80- eqs[i,j] = (eqs[i,j]== Constant (0 )) ? Δp : (eqs[i,j] + Δp)
101+ rlsqrt = sqrt (oderatelaw (rx))
102+ for (spec,stoich) in rx. netstoich
103+ i = species_to_idx[spec]
104+ eqs[i,j] = (stoich == one (stoich)) ? rlsqrt : stoich * rlsqrt
81105 end
82106 end
83107 eqs
84108end
85109
86110function Base. convert (:: Type{<:ODESystem} ,rs:: ReactionSystem )
87- eqs = essemble_drift (rs)
88- ODESystem (eqs,rs. iv,rs. species ,rs. params ,name= rs. name,
111+ eqs = assemble_drift (rs)
112+ ODESystem (eqs,rs. iv,rs. states ,rs. ps ,name= rs. name,
89113 systems= convert .(ODESystem,rs. systems))
90114end
91115
92116function Base. convert (:: Type{<:SDESystem} ,rs:: ReactionSystem )
93- eqs = essemble_drift (rs)
94- noiseeqs = essemble_diffusion (rs)
95- SDESystem (eqs,noiseeqs,rs. iv,rs. species ,rs. params ,
117+ eqs = assemble_drift (rs)
118+ noiseeqs = assemble_diffusion (rs)
119+ SDESystem (eqs,noiseeqs,rs. iv,rs. states ,rs. ps ,
96120 name= rs. name,systems= convert .(SDESystem,rs. systems))
97121end
0 commit comments