|
1 | | -struct Reaction |
| 1 | +struct Reaction{T <: Number} |
2 | 2 | rate |
3 | | - reactants::Vector{Operation} |
| 3 | + substrates::Vector{Operation} |
4 | 4 | products::Vector{Operation} |
| 5 | + substoich::Vector{T} |
| 6 | + prodstoich::Vector{T} |
5 | 7 | end |
6 | 8 |
|
7 | 9 | struct ReactionSystem <: AbstractSystem |
8 | 10 | eqs::Vector{Reaction} |
9 | 11 | iv::Variable |
10 | | - states::Vector{Variable} |
11 | | - ps::Vector{Variable} |
| 12 | + species::Vector{Variable} |
| 13 | + params::Vector{Variable} |
12 | 14 | name::Symbol |
13 | 15 | systems::Vector{ReactionSystem} |
14 | 16 | end |
15 | 17 |
|
16 | | -function ReactionSystem(eqs,iv,dvs,ps; |
| 18 | +function ReactionSystem(eqs, iv, species, params; |
17 | 19 | systems = ReactionSystem[], |
18 | | - name=gensym(:ReactionSystem)) |
19 | | - ReactionSystem(eqs,iv,convert.(Variable,dvs),convert.(Variable,ps),name,systems) |
| 20 | + name = gensym(:ReactionSystem)) |
| 21 | + |
| 22 | + ReactionSystem(eqs, iv, convert.(Variable,species), |
| 23 | + convert.(Variable,params), name, systems) |
20 | 24 | end |
21 | 25 |
|
22 | | -# TODO: Make it do the combinatorics stuff |
23 | | -reaction_expr(reactants) = *(reactants...) |
| 26 | +# Calculate the ODE rate law |
| 27 | +function oderatelaw(rx) |
| 28 | + @unpack rate, substrates, substoich = rx |
| 29 | + rl = rate |
| 30 | + coef = one(eltype(substoich)) |
| 31 | + for (i,stoich) in enumerate(substoich) |
| 32 | + coef *= factorial(stoich) |
| 33 | + rl *= (stoich != one(stoich)) ? substrates[i]^stoich : substrates[i] |
| 34 | + end |
| 35 | + (coef != one(coef)) && (rl /= coef) |
| 36 | + |
| 37 | + rl |
| 38 | +end |
24 | 39 |
|
25 | 40 | function essemble_drift(rs) |
26 | | - D = Differential(rs.iv()) |
27 | | - eqs = [D(x(rs.iv())) ~ 0 for x in rs.states] |
| 41 | + D = Differential(rs.iv()) |
| 42 | + eqs = [D(x(rs.iv())) ~ 0 for x in rs.species] |
| 43 | + species_to_idx = Dict(enumerate(rs.species)) |
28 | 44 |
|
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)) |
| 45 | + # note, this should really use the net stoichiometry to avoid |
| 46 | + # adding and substracting the same term for A + X -> B + X |
| 47 | + 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) |
33 | 53 | end |
34 | 54 |
|
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)) |
| 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) |
38 | 59 | end |
39 | 60 | end |
| 61 | + |
40 | 62 | eqs |
41 | 63 | end |
42 | 64 |
|
43 | 65 | function essemble_diffusion(rs) |
44 | | - eqs = Expression[Constant(0) for x in rs.states, y in rs.eqs] |
| 66 | + eqs = Expression[Constant(0) for x in rs.species, y in rs.eqs] |
| 67 | + species_to_idx = Dict(enumerate(rs.species)) |
45 | 68 |
|
46 | 69 | 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) |
| 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 |
50 | 75 | end |
51 | 76 |
|
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) |
| 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) |
55 | 81 | end |
56 | 82 | end |
57 | 83 | eqs |
58 | 84 | end |
59 | 85 |
|
60 | 86 | function Base.convert(::Type{<:ODESystem},rs::ReactionSystem) |
61 | 87 | eqs = essemble_drift(rs) |
62 | | - ODESystem(eqs,rs.iv,rs.states,rs.ps,name=rs.name, |
| 88 | + ODESystem(eqs,rs.iv,rs.species,rs.params,name=rs.name, |
63 | 89 | systems=convert.(ODESystem,rs.systems)) |
64 | 90 | end |
65 | 91 |
|
66 | 92 | function Base.convert(::Type{<:SDESystem},rs::ReactionSystem) |
67 | 93 | eqs = essemble_drift(rs) |
68 | 94 | noiseeqs = essemble_diffusion(rs) |
69 | | - SDESystem(eqs,noiseeqs,rs.iv,rs.states,rs.ps, |
| 95 | + SDESystem(eqs,noiseeqs,rs.iv,rs.species,rs.params, |
70 | 96 | name=rs.name,systems=convert.(SDESystem,rs.systems)) |
71 | 97 | end |
0 commit comments