1- struct Reaction
1+ struct Reaction{S <: Variable , T <: Number }
22 rate
3- reactants :: Vector{Operation}
3+ substrates :: Vector{Operation}
44 products:: Vector{Operation}
5+ substoich:: Vector{T}
6+ prodstoich:: Vector{T}
7+ netstoich:: Vector{Pair{S,T}}
8+ only_use_rate:: Bool
59end
610
11+ function Reaction (rate, subs, prods, substoich, prodstoich;
12+ netstoich= nothing , only_use_rate= false , kwargs... )
13+
14+ subsv = isnothing (subs) ? Vector {Operation} () : subs
15+ prodsv = isnothing (prods) ? Vector {Operation} () : prods
16+ ns = isnothing (netstoich) ? get_netstoich (subsv, prodsv, substoich, prodstoich) : netstoich
17+ Reaction (rate, subsv, prodsv, substoich, prodstoich, ns, only_use_rate)
18+ end
19+
20+ # three argument constructor assumes stoichiometric coefs are one and integers
21+ function Reaction (rate, subs, prods; kwargs... )
22+
23+ sstoich = isnothing (subs) ? Int[] : ones (Int,length (subs))
24+ pstoich = isnothing (prods) ? Int[] : ones (Int,length (prods))
25+ Reaction (rate, subs, prods, sstoich, pstoich; kwargs... )
26+ end
27+
28+ # calculates the net stoichiometry of a reaction as a vector of pairs (sub,substoich)
29+ function get_netstoich (subs, prods, sstoich, pstoich)
30+ # stoichiometry as a Dictionary
31+ nsdict = Dict {Variable,eltype(sstoich)} (sub. op => - sstoich[i] for (i,sub) in enumerate (subs))
32+ for (i,p) in enumerate (prods)
33+ coef = pstoich[i]
34+ prod = p. op
35+ @inbounds nsdict[prod] = haskey (nsdict, prod) ? nsdict[prod] + coef : coef
36+ end
37+
38+ # stoichiometry as a vector
39+ ns = [el for el in nsdict if el[2 ] != zero (el[2 ])]
40+
41+ ns
42+ end
43+
44+
745struct ReactionSystem <: AbstractSystem
846 eqs:: Vector{Reaction}
947 iv:: Variable
@@ -13,59 +51,74 @@ struct ReactionSystem <: AbstractSystem
1351 systems:: Vector{ReactionSystem}
1452end
1553
16- function ReactionSystem (eqs,iv,dvs,ps;
17- systems = ReactionSystem[],
18- name= gensym (:ReactionSystem ))
19- ReactionSystem (eqs,iv,convert .(Variable,dvs),convert .(Variable,ps),name,systems)
54+ function ReactionSystem (eqs, iv, species, params; systems = ReactionSystem[],
55+ name = gensym (:ReactionSystem ))
56+
57+ ReactionSystem (eqs, iv, convert .(Variable,species), convert .(Variable,params),
58+ name, systems)
2059end
2160
22- # TODO : Make it do the combinatorics stuff
23- reaction_expr (reactants) = * (reactants... )
61+ # Calculate the ODE rate law
62+ function oderatelaw (rx)
63+ @unpack rate, substrates, substoich, only_use_rate = rx
64+ rl = rate
65+ if ! only_use_rate
66+ coef = one (eltype (substoich))
67+ for (i,stoich) in enumerate (substoich)
68+ coef *= factorial (stoich)
69+ rl *= isone (stoich) ? substrates[i] : substrates[i]^ stoich
70+ end
71+ (! isone (coef)) && (rl /= coef)
72+ end
73+ rl
74+ end
2475
25- function essemble_drift (rs)
26- D = Differential (rs. iv ())
76+ function assemble_drift (rs)
77+ D = Differential (rs. iv ())
2778 eqs = [D (x (rs. iv ())) ~ 0 for x in rs. states]
79+ species_to_idx = Dict ((x => i for (i,x) in enumerate (rs. states)))
2880
29- for rx in rs. eqs
30- for reactant in rx. reactants
31- i = findfirst (x-> x == reactant. op,rs. states)
32- eqs[i] = Equation (eqs[i]. lhs,eqs[i]. rhs - rx. rate * reaction_expr (rx. reactants))
33- end
34-
35- for product in rx. products
36- i = findfirst (x-> x == product. op,rs. states)
37- eqs[i] = Equation (eqs[i]. lhs,eqs[i]. rhs + rx. rate * reaction_expr (rx. reactants))
81+ for rx in rs. eqs
82+ rl = oderatelaw (rx)
83+ for (spec,stoich) in rx. netstoich
84+ i = species_to_idx[spec]
85+ if iszero (eqs[i]. rhs)
86+ signedrl = (stoich > zero (stoich)) ? rl : - rl
87+ rhs = isone (abs (stoich)) ? signedrl : stoich * rl
88+ else
89+ Δspec = isone (abs (stoich)) ? rl : abs (stoich) * rl
90+ rhs = (stoich > zero (stoich)) ? (eqs[i]. rhs + Δspec) : (eqs[i]. rhs - Δspec)
91+ end
92+ eqs[i] = Equation (eqs[i]. lhs, rhs)
3893 end
3994 end
4095 eqs
4196end
4297
43- function essemble_diffusion (rs)
98+ function assemble_diffusion (rs)
4499 eqs = Expression[Constant (0 ) for x in rs. states, y in rs. eqs]
100+ species_to_idx = Dict ((x => i for (i,x) in enumerate (rs. states)))
45101
46102 for (j,rx) in enumerate (rs. eqs)
47- for reactant in rx. reactants
48- i = findfirst (x-> x == reactant. op,rs. states)
49- eqs[i,j] = - sqrt (rx. rate) * reaction_expr (rx. reactants)
50- end
51-
52- for product in rx. products
53- i = findfirst (x-> x == product. op,rs. states)
54- eqs[i,j] = sqrt (rx. rate) * reaction_expr (rx. reactants)
103+ rlsqrt = sqrt (oderatelaw (rx))
104+ for (spec,stoich) in rx. netstoich
105+ i = species_to_idx[spec]
106+ signedrlsqrt = (stoich > zero (stoich)) ? rlsqrt : - rlsqrt
107+ eqs[i,j] = isone (abs (stoich)) ? signedrlsqrt : stoich * rlsqrt
55108 end
56109 end
57110 eqs
58111end
59112
60113function Base. convert (:: Type{<:ODESystem} ,rs:: ReactionSystem )
61- eqs = essemble_drift (rs)
114+ eqs = assemble_drift (rs)
62115 ODESystem (eqs,rs. iv,rs. states,rs. ps,name= rs. name,
63116 systems= convert .(ODESystem,rs. systems))
64117end
65118
66119function Base. convert (:: Type{<:SDESystem} ,rs:: ReactionSystem )
67- eqs = essemble_drift (rs)
68- noiseeqs = essemble_diffusion (rs)
120+ eqs = assemble_drift (rs)
121+ noiseeqs = assemble_diffusion (rs)
69122 SDESystem (eqs,noiseeqs,rs. iv,rs. states,rs. ps,
70123 name= rs. name,systems= convert .(SDESystem,rs. systems))
71124end
0 commit comments