|
| 1 | + |
| 2 | +""" |
| 3 | +$(TYPEDEF) |
| 4 | +
|
| 5 | +One chemical reaction. |
| 6 | +
|
| 7 | +# Fields |
| 8 | +$(FIELDS) |
| 9 | +
|
| 10 | +# Examples |
| 11 | +
|
| 12 | +``` |
| 13 | +using ModelingToolkit |
| 14 | +@parameters t k[1:20] |
| 15 | +@variables A(t) B(t) C(t) D(t) |
| 16 | +rxs = [Reaction(k[1], nothing, [A]), # 0 -> A |
| 17 | + Reaction(k[2], [B], nothing), # B -> 0 |
| 18 | + Reaction(k[3],[A],[C]), # A -> C |
| 19 | + Reaction(k[4], [C], [A,B]), # C -> A + B |
| 20 | + Reaction(k[5], [C], [A], [1], [2]), # C -> A + A |
| 21 | + Reaction(k[6], [A,B], [C]), # A + B -> C |
| 22 | + Reaction(k[7], [B], [A], [2], [1]), # 2B -> A |
| 23 | + Reaction(k[8], [A,B], [A,C]), # A + B -> A + C |
| 24 | + Reaction(k[9], [A,B], [C,D]), # A + B -> C + D |
| 25 | + Reaction(k[10], [A], [C,D], [2], [1,1]), # 2A -> C + D |
| 26 | + Reaction(k[11], [A], [A,B], [2], [1,1]), # 2A -> A + B |
| 27 | + Reaction(k[12], [A,B,C], [C,D], [1,3,4], [2, 3]), # A+3B+4C -> 2C + 3D |
| 28 | + Reaction(k[13], [A,B], nothing, [3,1], nothing), # 3A+B -> 0 |
| 29 | + Reaction(k[14], nothing, [A], nothing, [2]), # 0 -> 2A |
| 30 | + Reaction(k[15]*A/(2+A), [A], nothing; only_use_rate=true), # A -> 0 with custom rate |
| 31 | + Reaction(k[16], [A], [B]; only_use_rate=true), # A -> B with custom rate. |
| 32 | + Reaction(k[17]*A*exp(B), [C], [D], [2], [1]), # 2C -> D with non constant rate. |
| 33 | + Reaction(k[18]*B, nothing, [B], nothing, [2]), # 0 -> 2B with non constant rate. |
| 34 | + Reaction(k[19]*t, [A], [B]), # A -> B with non constant rate. |
| 35 | + Reaction(k[20]*t*A, [B,C], [D],[2,1],[2]) # 2A +B -> 2C with non constant rate. |
| 36 | + ] |
| 37 | +``` |
| 38 | +
|
| 39 | +Notes: |
| 40 | +- `nothing` can be used to indicate a reaction that has no reactants or no products. |
| 41 | + In this case the corresponding stoichiometry vector should also be set to `nothing`. |
| 42 | +- The three-argument form assumes all reactant and product stoichiometric coefficients |
| 43 | + are one. |
| 44 | +""" |
1 | 45 | struct Reaction{S <: Variable, T <: Number}
|
| 46 | + """The rate function (excluding mass action terms).""" |
2 | 47 | rate
|
| 48 | + """Reaction substrates.""" |
3 | 49 | substrates::Vector{Operation}
|
| 50 | + """Reaction products.""" |
4 | 51 | products::Vector{Operation}
|
| 52 | + """The stoichiometric coefficients of the reactants.""" |
5 | 53 | substoich::Vector{T}
|
| 54 | + """The stoichiometric coefficients of the products.""" |
6 | 55 | prodstoich::Vector{T}
|
| 56 | + """The net stoichiometric coefficients of all species changed by the reaction.""" |
7 | 57 | netstoich::Vector{Pair{S,T}}
|
| 58 | + """ |
| 59 | + `false` (default) if `rate` should be multiplied by mass action terms to give the rate law. |
| 60 | + `true` if `rate` represents the full reaction rate law. |
| 61 | + """ |
8 | 62 | only_use_rate::Bool
|
9 | 63 | end
|
10 | 64 |
|
@@ -52,12 +106,32 @@ function get_netstoich(subs, prods, sstoich, pstoich)
|
52 | 106 | ns
|
53 | 107 | end
|
54 | 108 |
|
| 109 | +""" |
| 110 | +$(TYPEDEF) |
| 111 | +
|
| 112 | +A system of chemical reactions. |
| 113 | +
|
| 114 | +# Fields |
| 115 | +$(FIELDS) |
| 116 | +
|
| 117 | +# Example |
| 118 | +Continuing from the example in the [`Reaction`](@ref) definition: |
| 119 | +``` |
| 120 | +rs = ReactionSystem(rxs, t, [A,B,C,D], k) |
| 121 | +``` |
| 122 | +""" |
55 | 123 | struct ReactionSystem <: AbstractSystem
|
| 124 | + """The reactions defining the system.""" |
56 | 125 | eqs::Vector{Reaction}
|
| 126 | + """Independent variable (usually time).""" |
57 | 127 | iv::Variable
|
| 128 | + """Dependent (state) variables representing amount of each species.""" |
58 | 129 | states::Vector{Variable}
|
| 130 | + """Parameter variables.""" |
59 | 131 | ps::Vector{Variable}
|
| 132 | + """The name of the system""" |
60 | 133 | name::Symbol
|
| 134 | + """systems: The internal systems""" |
61 | 135 | systems::Vector{ReactionSystem}
|
62 | 136 | end
|
63 | 137 |
|
@@ -141,6 +215,22 @@ function jumpratelaw(rx; rxvars=get_variables(rx.rate))
|
141 | 215 | end
|
142 | 216 |
|
143 | 217 | # if haveivdep=false then time dependent rates will still be classified as mass action
|
| 218 | +""" |
| 219 | +```julia |
| 220 | +ismassaction(rx, rs; rxvars = get_variables(rx.rate), |
| 221 | + haveivdep = any(var -> isequal(rs.iv,convert(Variable,var)), rxvars)) |
| 222 | +``` |
| 223 | +
|
| 224 | +True if a given reaction is of mass action form, i.e. `rx.rate` does not depend |
| 225 | +on any chemical species that correspond to states of the system, and does not depend |
| 226 | +explicitly on the independent variable (usually time). |
| 227 | +
|
| 228 | +# Arguments |
| 229 | +- `rx`, the [`Reaction`](@ref). |
| 230 | +- `rs`, a [`ReactionSystem`](@ref) containing the reaction. |
| 231 | +- Optional: `rxvars`, the `Variable`s the `rx` depends on. |
| 232 | +- Optional: `haveivdep`, `true` if the [`Reaction`](@ref) `rate` field explicitly depends on the independent variable. |
| 233 | +""" |
144 | 234 | function ismassaction(rx, rs; rxvars = get_variables(rx.rate),
|
145 | 235 | haveivdep = any(var -> isequal(rs.iv,convert(Variable,var)), rxvars))
|
146 | 236 | return !(haveivdep || rx.only_use_rate || any(convert(Variable,rxv) in states(rs) for rxv in rxvars))
|
@@ -172,19 +262,39 @@ function assemble_jumps(rs)
|
172 | 262 | eqs
|
173 | 263 | end
|
174 | 264 |
|
| 265 | +""" |
| 266 | +```julia |
| 267 | +Base.convert(::Type{<:ODESystem},rs::ReactionSystem) |
| 268 | +``` |
| 269 | +Convert a ReactionSystem to an ODESystem. |
| 270 | +""" |
175 | 271 | function Base.convert(::Type{<:ODESystem},rs::ReactionSystem)
|
176 | 272 | eqs = assemble_drift(rs)
|
177 | 273 | ODESystem(eqs,rs.iv,rs.states,rs.ps,name=rs.name,
|
178 | 274 | systems=convert.(ODESystem,rs.systems))
|
179 | 275 | end
|
180 | 276 |
|
| 277 | +""" |
| 278 | +```julia |
| 279 | +Base.convert(::Type{<:SDESystem},rs::ReactionSystem) |
| 280 | +``` |
| 281 | +
|
| 282 | +Convert a ReactionSystem to a SDESystem. |
| 283 | +""" |
181 | 284 | function Base.convert(::Type{<:SDESystem},rs::ReactionSystem)
|
182 | 285 | eqs = assemble_drift(rs)
|
183 | 286 | noiseeqs = assemble_diffusion(rs)
|
184 | 287 | SDESystem(eqs,noiseeqs,rs.iv,rs.states,rs.ps,
|
185 | 288 | name=rs.name,systems=convert.(SDESystem,rs.systems))
|
186 | 289 | end
|
187 | 290 |
|
| 291 | +""" |
| 292 | +```julia |
| 293 | +Base.convert(::Type{<:JumpSystem},rs::ReactionSystem) |
| 294 | +``` |
| 295 | +
|
| 296 | +Convert a ReactionSystem to a JumpSystem. |
| 297 | +""" |
188 | 298 | function Base.convert(::Type{<:JumpSystem},rs::ReactionSystem)
|
189 | 299 | eqs = assemble_jumps(rs)
|
190 | 300 | JumpSystem(eqs,rs.iv,rs.states,rs.ps,name=rs.name,
|
|
0 commit comments