@@ -72,13 +72,6 @@ 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
-
82
75
# calculates the net stoichiometry of a reaction as a vector of pairs (sub,substoich)
83
76
function get_netstoich (subs, prods, sstoich, pstoich)
84
77
# stoichiometry as a Dictionary
@@ -92,6 +85,9 @@ function get_netstoich(subs, prods, sstoich, pstoich)
92
85
[el for el in nsdict if ! _iszero (el[2 ])]
93
86
end
94
87
88
+ # Get the net stoichiometries' type.
89
+ netstoich_stoichtype (:: Vector{Pair{S, T}} ) where {S, T} = T
90
+
95
91
# ## Reaction Structure ###
96
92
97
93
"""
@@ -138,19 +134,19 @@ Notes:
138
134
- The three-argument form assumes all reactant and product stoichiometric coefficients
139
135
are one.
140
136
"""
141
- struct Reaction{T}
137
+ struct Reaction{S, T}
142
138
""" The rate function (excluding mass action terms)."""
143
139
rate:: Any
144
140
""" Reaction substrates."""
145
- substrates:: Vector{Any}
141
+ substrates:: Vector
146
142
""" Reaction products."""
147
- products:: Vector{Any}
143
+ products:: Vector
148
144
""" The stoichiometric coefficients of the reactants."""
149
- substoich:: Vector
145
+ substoich:: Vector{T}
150
146
""" The stoichiometric coefficients of the products."""
151
- prodstoich:: Vector
147
+ prodstoich:: Vector{T}
152
148
""" The net stoichiometric coefficients of all species changed by the reaction."""
153
- netstoich:: Vector{Pair{Any , T}}
149
+ netstoich:: Vector{Pair{S , T}}
154
150
"""
155
151
`false` (default) if `rate` should be multiplied by mass action terms to give the rate law.
156
152
`true` if `rate` represents the full reaction rate law.
@@ -164,74 +160,83 @@ struct Reaction{T}
164
160
end
165
161
166
162
# Five-argument constructor accepting rate, substrates, and products, and their stoichiometries.
167
- function Reaction (rate, subs:: Vector , prods:: Vector , substoich:: Vector{S} , prodstoich:: Vector{T} ;
168
- netstoich = [], 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." ))
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
177
180
allunique (subs) ||
178
181
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
179
192
allunique (prods) ||
180
193
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)
181
195
182
- # Ensures everything have uniform and correct types.
183
- subs = promote_reaction_vector (subs, BasicSymbolic{Real})
184
- prods = promote_reaction_vector (prods, BasicSymbolic{Real})
196
+ # try to get a common type for stoichiometry, using Any if have Syms
185
197
stoich_type = promote_type (S, T)
186
- (stoich_type <: Num ) && (stoich_type = Any)
187
- substoich = promote_reaction_vector (substoich, stoich_type)
188
- prodstoich = promote_reaction_vector (prodstoich, stoich_type)
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
189
206
190
- # Checks that all reactants are valid.
191
207
if ! (all (isvalidreactant, subs) && all (isvalidreactant, prods))
192
208
badsts = union (filter (! isvalidreactant, subs), filter (! isvalidreactant, prods))
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 " ))
209
+ 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 "" " ))
194
210
end
195
-
196
- # Computes the net stoichiometries.
197
- if isempty (netstoich)
198
- netstoich = get_netstoich (subs, prods, substoich, prodstoich)
199
- elseif typeof (netstoich) != Vector{Pair{BasicSymbolic{Real}, stoich_type}}
200
- netstoich = Pair{BasicSymbolic{Real}, stoich_type}[
201
- value (ns[1 ]) => convert (stoich_type, ns[2 ]) for ns in netstoich]
211
+
212
+ ns = if netstoich === nothing
213
+ get_netstoich (subs, prods, substoich′, prodstoich′)
214
+ else
215
+ (netstoich_stoichtype (netstoich) != stoich_type) ?
216
+ convert .(stoich_type, netstoich) : netstoich
202
217
end
203
218
204
- # Handles metadata (check that all entries are unique, remove potential `only_use_rate`
205
- # entries, and converts to the required type.
219
+ # Check that all metadata entries are unique. (cannot use `in` since some entries may be symbolics).
206
220
if ! allunique (entry[1 ] for entry in metadata)
207
221
error (" Repeated entries for the same metadata encountered in the following metadata set: $([entry[1 ] for entry in metadata]) ." )
208
222
end
223
+
224
+ # Deletes potential `:only_use_rate => ` entries from the metadata.
209
225
if any (:only_use_rate == entry[1 ] for entry in metadata)
210
226
deleteat! (metadata, findfirst (:only_use_rate == entry[1 ] for entry in metadata))
211
227
end
212
- metadata = convert (Vector{Pair{Symbol, Any}}, metadata)
213
228
214
- Reaction {stoich_type} ( value (rate), subs, prods, substoich, prodstoich, netstoich, only_use_rate, metadata)
215
- end
229
+ # Ensures metadata have the correct type.
230
+ metadata = convert (Vector{Pair{Symbol, Any}}, metadata)
216
231
217
- # Three-argument constructor. Handles the case where no stoichiometries is given
218
- # (by assuming that all stoichiometries are `1`).
219
- function Reaction (rate, subs:: Vector , prods:: Vector ; kwargs... )
220
- Reaction (rate, subs, prods, ones (Int, length (subs)), ones (Int, length (prods)); kwargs... )
232
+ Reaction (value (rate), subs, prods, substoich′, prodstoich′, ns, only_use_rate, metadata)
221
233
end
222
234
223
- # Handles cases where `nothing` is given (instead of an empty vector).
224
- function Reaction (rate, subs:: Vector , prods:: Nothing , substoich:: Vector , prodstoich:: Nothing ; kwargs... )
225
- Reaction (rate, subs, Int64[], substoich, Int64[]; kwargs... )
226
- end
227
- function Reaction (rate, subs:: Nothing , prods:: Vector , substoich:: Nothing , prodstoich:: Vector ; kwargs... )
228
- Reaction (rate, Int64[], prods, Int64[], prodstoich; kwargs... )
229
- end
230
- function Reaction (rate, subs:: Vector , prods:: Nothing ; kwargs... )
231
- Reaction (rate, subs, Int64[]; kwargs... )
232
- end
233
- function Reaction (rate, subs:: Nothing , prods:: Vector ; kwargs... )
234
- Reaction (rate, Int64[], prods; kwargs... )
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... )
235
240
end
236
241
237
242
# Union type for `Reaction`s and `Equation`s.
0 commit comments