@@ -72,6 +72,13 @@ function metadata_only_use_rate_check(metadata)
72
72
return Bool (metadata[only_use_rate_idx][2 ])
73
73
end
74
74
75
+ # Used to promote a vector to the appropriate type. Takes the `vec == Any[]` case into account by
76
+ # returning an empty vector of the appropriate type.
77
+ function promote_reaction_vector (vec, type)
78
+ isempty (vec) && (return type[])
79
+ type[value (v) for v in vec]
80
+ end
81
+
75
82
# calculates the net stoichiometry of a reaction as a vector of pairs (sub,substoich)
76
83
function get_netstoich (subs, prods, sstoich, pstoich)
77
84
# stoichiometry as a Dictionary
@@ -85,9 +92,6 @@ function get_netstoich(subs, prods, sstoich, pstoich)
85
92
[el for el in nsdict if ! _iszero (el[2 ])]
86
93
end
87
94
88
- # Get the net stoichiometries' type.
89
- netstoich_stoichtype (:: Vector{Pair{S, T}} ) where {S, T} = T
90
-
91
95
# ## Reaction Structure ###
92
96
93
97
"""
@@ -134,19 +138,19 @@ Notes:
134
138
- The three-argument form assumes all reactant and product stoichiometric coefficients
135
139
are one.
136
140
"""
137
- struct Reaction{S, T}
141
+ struct Reaction{T}
138
142
""" The rate function (excluding mass action terms)."""
139
143
rate:: Any
140
144
""" Reaction substrates."""
141
- substrates:: Vector
145
+ substrates:: Vector{BasicSymbolic{Real}}
142
146
""" Reaction products."""
143
- products:: Vector
147
+ products:: Vector{BasicSymbolic{Real}}
144
148
""" The stoichiometric coefficients of the reactants."""
145
149
substoich:: Vector{T}
146
150
""" The stoichiometric coefficients of the products."""
147
151
prodstoich:: Vector{T}
148
152
""" The net stoichiometric coefficients of all species changed by the reaction."""
149
- netstoich:: Vector{Pair{S , T}}
153
+ netstoich:: Vector{Pair{BasicSymbolic{Real} , T}}
150
154
"""
151
155
`false` (default) if `rate` should be multiplied by mass action terms to give the rate law.
152
156
`true` if `rate` represents the full reaction rate law.
@@ -160,83 +164,77 @@ struct Reaction{S, T}
160
164
end
161
165
162
166
# Five-argument constructor accepting rate, substrates, and products, and their stoichiometries.
163
- function Reaction (rate, subs, prods, substoich, prodstoich;
164
- netstoich = nothing , metadata = Pair{Symbol, Any}[],
165
- only_use_rate = metadata_only_use_rate_check (metadata), kwargs... )
166
- (isnothing (prods) && isnothing (subs)) &&
167
- throw (ArgumentError (" A reaction requires a non-nothing substrate or product vector." ))
168
- (isnothing (prodstoich) && isnothing (substoich)) &&
169
- throw (ArgumentError (" Both substrate and product stochiometry inputs cannot be nothing." ))
170
-
171
- if isnothing (subs)
172
- prodtype = typeof (value (first (prods)))
173
- subs = Vector {prodtype} ()
174
- ! isnothing (substoich) &&
175
- throw (ArgumentError (" If substrates are nothing, substrate stoichiometries have to be so too." ))
176
- substoich = typeof (prodstoich)()
177
- else
178
- subs = value .(subs)
179
- end
167
+ function Reaction (rate, subs:: Vector , prods:: Vector , substoich:: Vector{S} , prodstoich:: Vector{T} ;
168
+ netstoich = nothing , metadata = Pair{Symbol, Any}[],
169
+ only_use_rate = metadata_only_use_rate_check (metadata), kwargs... ) where {S,T}
170
+ # Error checks.
171
+ isempty (subs) && isempty (prods) &&
172
+ throw (ArgumentError (" A reaction requires either a non-empty substrate or product vector." ))
173
+ length (subs) != length (substoich) &&
174
+ throw (ArgumentError (" The substrate vector ($(subs) ) and the substrate stoichiometry vector ($(substoich) ) must have equal length." ))
175
+ length (prods) != length (prodstoich) &&
176
+ throw (ArgumentError (" The product vector ($(prods) ) and the product stoichiometry vector ($(prodstoich) ) must have equal length." ))
180
177
allunique (subs) ||
181
178
throw (ArgumentError (" Substrates can not be repeated in the list provided to `Reaction`, please modify the stoichiometry for any repeated substrates instead." ))
182
- S = eltype (substoich)
183
-
184
- if isnothing (prods)
185
- prods = Vector {eltype(subs)} ()
186
- ! isnothing (prodstoich) &&
187
- throw (ArgumentError (" If products are nothing, product stoichiometries have to be so too." ))
188
- prodstoich = typeof (substoich)()
189
- else
190
- prods = value .(prods)
191
- end
192
179
allunique (prods) ||
193
180
throw (ArgumentError (" Products can not be repeated in the list provided to `Reaction`, please modify the stoichiometry for any repeated products instead." ))
194
- T = eltype (prodstoich)
195
181
196
- # try to get a common type for stoichiometry, using Any if have Syms
182
+ # Ensures everything have uniform and correct types.
183
+ subs = promote_reaction_vector (subs, BasicSymbolic{Real})
184
+ prods = promote_reaction_vector (prods, BasicSymbolic{Real})
197
185
stoich_type = promote_type (S, T)
198
- if stoich_type <: Num
199
- stoich_type = Any
200
- substoich′ = Any[value (s) for s in substoich]
201
- prodstoich′ = Any[value (p) for p in prodstoich]
202
- else
203
- substoich′ = (S == stoich_type) ? substoich : convert .(stoich_type, substoich)
204
- prodstoich′ = (T == stoich_type) ? prodstoich : convert .(stoich_type, prodstoich)
205
- end
186
+ (stoich_type <: Num ) && (stoich_type = Any)
187
+ substoich = promote_reaction_vector (substoich, stoich_type)
188
+ prodstoich = promote_reaction_vector (prodstoich, stoich_type)
206
189
190
+ # Checks that all reactants are valid.
207
191
if ! (all (isvalidreactant, subs) && all (isvalidreactant, prods))
208
- badsts = union (filter (! isvalidreactant, subs), filter (! isvalidreactant, prods))
192
+ badsts = union (filter (isvalidreactant, subs), filter (isvalidreactant, prods))
209
193
throw (ArgumentError (""" To be a valid substrate or product, non-constant species must be declared via @species, while constant species must be parameters with the isconstantspecies metadata. The following reactants do not follow this convention:\n $badsts """ ))
210
194
end
211
-
212
- ns = if netstoich === nothing
213
- get_netstoich (subs, prods, substoich′, prodstoich′)
195
+
196
+ # Computes the net stoichiometries.
197
+ netstoich = if netstoich === nothing
198
+ get_netstoich (subs, prods, substoich, prodstoich)
214
199
else
215
- (netstoich_stoichtype (netstoich) != stoich_type) ?
216
- convert .(stoich_type, netstoich) : netstoich
200
+ if typeof (netstoich) != Vector{Pair{BasicSymbolic{Real}, stoich_type}}
201
+ netstoich = Pair{BasicSymbolic{Real}, stoich_type}[
202
+ value (ns[1 ]) => convert (stoich_type, ns[2 ]) for ns in netstoich]
203
+ end
204
+ netstoich
217
205
end
218
206
219
- # Check that all metadata entries are unique. (cannot use `in` since some entries may be symbolics).
207
+ # Handles metadata (check that all entries are unique, remove potential `only_use_rate`
208
+ # entries, and converts to the required type.
220
209
if ! allunique (entry[1 ] for entry in metadata)
221
210
error (" Repeated entries for the same metadata encountered in the following metadata set: $([entry[1 ] for entry in metadata]) ." )
222
211
end
223
-
224
- # Deletes potential `:only_use_rate => ` entries from the metadata.
225
212
if any (:only_use_rate == entry[1 ] for entry in metadata)
226
213
deleteat! (metadata, findfirst (:only_use_rate == entry[1 ] for entry in metadata))
227
214
end
228
-
229
- # Ensures metadata have the correct type.
230
215
metadata = convert (Vector{Pair{Symbol, Any}}, metadata)
231
216
232
- Reaction (value (rate), subs, prods, substoich′ , prodstoich′, ns , only_use_rate, metadata)
217
+ Reaction {stoich_type} (value (rate), subs, prods, substoich, prodstoich, netstoich , only_use_rate, metadata)
233
218
end
234
219
235
- # Three argument constructor assumes stoichiometric coefs are one and integers.
236
- function Reaction (rate, subs, prods; kwargs... )
237
- sstoich = isnothing (subs) ? nothing : ones (Int, length (subs))
238
- pstoich = isnothing (prods) ? nothing : ones (Int, length (prods))
239
- Reaction (rate, subs, prods, sstoich, pstoich; kwargs... )
220
+ # Three-argument constructor. Handles the case where no stoichiometries is given
221
+ # (by assuming that all stoichiometries are `1`).
222
+ function Reaction (rate, subs:: Vector , prods:: Vector ; kwargs... )
223
+ Reaction (rate, subs, prods, ones (Int, length (subs)), ones (Int, length (prods)); kwargs... )
224
+ end
225
+
226
+ # Handles cases where `nothing` is given (instead of an empty vector).
227
+ function Reaction (rate, subs:: Vector , prods:: Nothing , substoich:: Vector , prodstoich:: Nothing ; kwargs... )
228
+ Reaction (rate, subs, Int64[], substoich, Int64[]; kwargs... )
229
+ end
230
+ function Reaction (rate, subs:: Nothing , prods:: Vector , substoich:: Nothing , prodstoich:: Vector ; kwargs... )
231
+ Reaction (rate, Int64[], prods, Int64[], prodstoich; kwargs... )
232
+ end
233
+ function Reaction (rate, subs:: Vector , prods:: Nothing ; kwargs... )
234
+ Reaction (rate, subs, Int64[]; kwargs... )
235
+ end
236
+ function Reaction (rate, subs:: Nothing , prods:: Vector ; kwargs... )
237
+ Reaction (rate, Int64[], prods; kwargs... )
240
238
end
241
239
242
240
# Union type for `Reaction`s and `Equation`s.
0 commit comments