Skip to content

Commit a45a1bc

Browse files
authored
Merge pull request #838 from SciML/src_restructure
Source folder restructure
2 parents 1cfa932 + a9d11c9 commit a45a1bc

15 files changed

+3474
-3607
lines changed

src/Catalyst.jl

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -69,41 +69,72 @@ function __init__()
6969
end
7070
end
7171

72-
# base system type and features
73-
include("reactionsystem.jl")
74-
export isspecies
75-
export Reaction, ReactionSystem, ismassaction, oderatelaw, jumpratelaw, isspatial
76-
export ODEProblem,
77-
SDEProblem, JumpProblem, NonlinearProblem, DiscreteProblem,
78-
SteadyStateProblem
72+
### Package Constants ###
7973

80-
# reaction_network macro
74+
# Union type of types that can occur in expressions.
8175
const ExprValues = Union{Expr, Symbol, Float64, Int, Bool}
82-
include("expression_utils.jl")
83-
include("reaction_network.jl")
84-
export @reaction_network, @network_component, @reaction, @species
8576

86-
# registers CRN specific functions using Symbolics.jl
87-
include("registered_functions.jl")
88-
export mm, mmr, hill, hillr, hillar
77+
# The symbol used for conserved quantities in conservation law eliminations.
78+
const CONSERVED_CONSTANT_SYMBOL =
79+
80+
# Declares symbols which may neither be used as parameters nor unknowns.
81+
const forbidden_symbols_skip = Set([:ℯ, :pi, , :t, :∅])
82+
const forbidden_symbols_error = union(Set([:im, :nothing, CONSERVED_CONSTANT_SYMBOL]),
83+
forbidden_symbols_skip)
84+
const forbidden_variables_error = let
85+
fvars = copy(forbidden_symbols_error)
86+
delete!(fvars, :t)
87+
fvars
88+
end
8989

90-
# functions to query network properties
91-
include("networkapi.jl")
90+
### Package Main ###
91+
92+
# The `Reaction` structure and its functions.
93+
include("reaction.jl")
94+
export isspecies
95+
export Reaction
96+
export get_noise_scaling, has_noise_scaling
97+
98+
# The `ReactionSystem` structure and its functions.
99+
include("reactionsystem.jl")
100+
export ReactionSystem, isspatial
92101
export species, nonspecies, reactionparams, reactions, speciesmap, paramsmap
93-
export numspecies, numreactions, numreactionparams, setdefaults!, symmap_to_varmap
102+
export numspecies, numreactions, numreactionparams, setdefaults!
94103
export make_empty_network, reactionparamsmap
95104
export dependants, dependents, substoichmat, prodstoichmat, netstoichmat
96-
export conservationlaws, conservedquantities, conservedequations, conservationlaw_constants
105+
export reactionrates
97106
export isequivalent
98-
export set_default_noise_scaling, get_noise_scaling, has_noise_scaling
107+
export set_default_noise_scaling
99108

100109
# depreciated functions to remove in future releases
101110
export params, numparams
102111

103-
# network analysis functions
104-
export reactioncomplexmap, reactioncomplexes, incidencemat, reactionrates, complexstoichmat
112+
# Conversions of the `ReactionSystem` structure.
113+
include("reactionsystem_conversions.jl")
114+
export ODEProblem,
115+
SDEProblem, JumpProblem, NonlinearProblem, DiscreteProblem,
116+
SteadyStateProblem
117+
export ismassaction, oderatelaw, jumpratelaw
118+
export symmap_to_varmap
119+
120+
# reaction_network macro
121+
include("expression_utils.jl")
122+
include("dsl.jl")
123+
export @reaction_network, @network_component, @reaction, @species
124+
125+
# Network analysis functionality.
126+
include("network_analysis.jl")
127+
export reactioncomplexmap, reactioncomplexes, incidencemat
128+
export complexstoichmat
105129
export complexoutgoingmat, incidencematgraph, linkageclasses, deficiency, subnetworks
106130
export linkagedeficiencies, isreversible, isweaklyreversible
131+
export conservationlaws, conservedquantities, conservedequations, conservationlaw_constants
132+
133+
# registers CRN specific functions using Symbolics.jl
134+
include("registered_functions.jl")
135+
export mm, mmr, hill, hillr, hillar
136+
137+
# functions to query network properties
107138

108139
# for Latex printing of ReactionSystems
109140
include("latexify_recipes.jl")

src/chemistry_functionality.jl

Lines changed: 127 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,49 @@ Symbolics.option_to_metadata_type(::Val{:iscompound}) = CompoundSpecies
77
Symbolics.option_to_metadata_type(::Val{:components}) = CompoundComponents
88
Symbolics.option_to_metadata_type(::Val{:coefficients}) = CompoundCoefficients
99

10+
## Compound Getters ###
11+
12+
"""
13+
iscompound(s)
14+
15+
Returns `true` if the input is a compound species (else false).
16+
"""
17+
iscompound(s::Num) = iscompound(MT.value(s))
18+
function iscompound(s)
19+
MT.getmetadata(s, CompoundSpecies, false)
20+
end
21+
22+
"""
23+
components(s)
24+
25+
Returns a vector with a list of all the components of a compound species (created using e.g. the @compound macro).
26+
"""
27+
components(s::Num) = components(MT.value(s))
28+
function components(s)
29+
MT.getmetadata(s, CompoundComponents)
30+
end
31+
32+
"""
33+
coefficients(s)
34+
35+
Returns a vector with a list of all the stoichiometric coefficients of the components of a compound species (created using e.g. the @compound macro).
36+
"""
37+
coefficients(s::Num) = coefficients(MT.value(s))
38+
function coefficients(s)
39+
MT.getmetadata(s, CompoundCoefficients)
40+
end
41+
42+
"""
43+
component_coefficients(s)
44+
45+
Returns a Vector{Pari{Symbol,Int64}}, listing a compounds species (created using e.g. the @compound macro) all the coefficients and their stoichiometric coefficients.
46+
"""
47+
component_coefficients(s::Num) = component_coefficients(MT.value(s))
48+
function component_coefficients(s)
49+
return [c => co for (c, co) in zip(components(s), coefficients(s))]
50+
end
51+
52+
1053
### Create @compound Macro(s) ###
1154

1255
"""
@@ -146,135 +189,9 @@ function make_compounds(expr)
146189
return compound_declarations
147190
end
148191

149-
## Compound Getters ###
150-
151-
"""
152-
iscompound(s)
153-
154-
Returns `true` if the input is a compound species (else false).
155-
"""
156-
iscompound(s::Num) = iscompound(MT.value(s))
157-
function iscompound(s)
158-
MT.getmetadata(s, CompoundSpecies, false)
159-
end
160-
161-
"""
162-
components(s)
163-
164-
Returns a vector with a list of all the components of a compound species (created using e.g. the @compound macro).
165-
"""
166-
components(s::Num) = components(MT.value(s))
167-
function components(s)
168-
MT.getmetadata(s, CompoundComponents)
169-
end
170-
171-
"""
172-
coefficients(s)
173-
174-
Returns a vector with a list of all the stoichiometric coefficients of the components of a compound species (created using e.g. the @compound macro).
175-
"""
176-
coefficients(s::Num) = coefficients(MT.value(s))
177-
function coefficients(s)
178-
MT.getmetadata(s, CompoundCoefficients)
179-
end
180-
181-
"""
182-
component_coefficients(s)
183-
184-
Returns a Vector{Pari{Symbol,Int64}}, listing a compounds species (created using e.g. the @compound macro) all the coefficients and their stoichiometric coefficients.
185-
"""
186-
component_coefficients(s::Num) = component_coefficients(MT.value(s))
187-
function component_coefficients(s)
188-
return [c => co for (c, co) in zip(components(s), coefficients(s))]
189-
end
190-
191192

192193
### Reaction Balancing Functionality ###
193194

194-
# Reaction balancing error.
195-
const COMPOUND_OF_COMPOUND_ERROR = ErrorException("Reaction balancing does not currently work for reactions involving compounds of compounds.")
196-
197-
# Note this does not correctly handle compounds of compounds currently.
198-
# Internal function used by "balance_reaction" (via "get_balanced_stoich").
199-
function create_matrix(reaction::Catalyst.Reaction)
200-
@unpack substrates, products = reaction
201-
unique_atoms = [] # Array to store unique atoms
202-
n_atoms = 0
203-
ncompounds = length(substrates) + length(products)
204-
A = zeros(Int, 0, ncompounds)
205-
206-
coeffsign = 1
207-
jbase = 0
208-
for compounds in (substrates, products)
209-
for (j2, compound) in enumerate(compounds)
210-
j = jbase + j2
211-
212-
if iscompound(compound)
213-
atoms = components(compound)
214-
any(iscompound, atoms) && throw(COMPOUND_OF_COMPOUND_ERROR)
215-
coeffs = coefficients(compound)
216-
(atoms == nothing || coeffs == nothing) && continue
217-
else
218-
# If not a compound, assume coefficient of 1
219-
atoms = [compound]
220-
coeffs = [1]
221-
end
222-
223-
for (atom,coeff) in zip(atoms, coeffs)
224-
# Extract atom and coefficient from the pair
225-
i = findfirst(x -> isequal(x, atom), unique_atoms)
226-
if i === nothing
227-
# Add the atom to the atoms array if it's not already present
228-
push!(unique_atoms, atom)
229-
n_atoms += 1
230-
A = [A; zeros(Int, 1, ncompounds)]
231-
i = n_atoms
232-
end
233-
234-
# Adjust coefficient based on whether the compound is a product or substrate
235-
coeff *= coeffsign
236-
237-
A[i, j] = coeff
238-
end
239-
end
240-
241-
# update for iterating through products
242-
coeffsign = -1
243-
jbase = length(substrates)
244-
end
245-
246-
return A
247-
end
248-
249-
# Internal function used by "balance_reaction".
250-
function get_balanced_stoich(reaction::Reaction)
251-
# Create the reaction matrix A that is m atoms by n compounds
252-
A = create_matrix(reaction)
253-
254-
# get an integer nullspace basis
255-
X = ModelingToolkit.nullspace(A)
256-
nullity = size(X, 2)
257-
258-
stoichvecs = Vector{Vector{Int64}}()
259-
for (j, col) in enumerate(eachcol(X))
260-
signs = unique(col)
261-
262-
# If there is only one basis vector and the signs are not all the same this means
263-
# we have a solution that would require moving at least one substrate to be a
264-
# product (or vice-versa). We therefore do not return anything in this case.
265-
# If there are multiple basis vectors we don't currently determine if we can
266-
# construct a linear combination giving a solution, so we just return them.
267-
if (nullity > 1) || (all(>=(0), signs) || all(<=(0), signs))
268-
coefs = abs.(col)
269-
common_divisor = reduce(gcd, coefs)
270-
coefs .= div.(coefs, common_divisor)
271-
push!(stoichvecs, coefs)
272-
end
273-
end
274-
275-
return stoichvecs
276-
end
277-
278195
"""
279196
balance_reaction(reaction::Reaction)
280197
@@ -345,3 +262,87 @@ function balance_reaction(reaction::Reaction)
345262
(length(balancedrxs) > 1) && (@warn "Infinite balanced reactions from ($reaction) are possible, returning a basis for them. Note that we do not check if they preserve the set of substrates and products from the original reaction.")
346263
return balancedrxs
347264
end
265+
266+
# Internal function used by "balance_reaction".
267+
function get_balanced_stoich(reaction::Reaction)
268+
# Create the reaction matrix A that is m atoms by n compounds
269+
A = create_matrix(reaction)
270+
271+
# get an integer nullspace basis
272+
X = ModelingToolkit.nullspace(A)
273+
nullity = size(X, 2)
274+
275+
stoichvecs = Vector{Vector{Int64}}()
276+
for (j, col) in enumerate(eachcol(X))
277+
signs = unique(col)
278+
279+
# If there is only one basis vector and the signs are not all the same this means
280+
# we have a solution that would require moving at least one substrate to be a
281+
# product (or vice-versa). We therefore do not return anything in this case.
282+
# If there are multiple basis vectors we don't currently determine if we can
283+
# construct a linear combination giving a solution, so we just return them.
284+
if (nullity > 1) || (all(>=(0), signs) || all(<=(0), signs))
285+
coefs = abs.(col)
286+
common_divisor = reduce(gcd, coefs)
287+
coefs .= div.(coefs, common_divisor)
288+
push!(stoichvecs, coefs)
289+
end
290+
end
291+
292+
return stoichvecs
293+
end
294+
295+
# Reaction balancing error.
296+
const COMPOUND_OF_COMPOUND_ERROR = ErrorException("Reaction balancing does not currently work for reactions involving compounds of compounds.")
297+
298+
# Note this does not correctly handle compounds of compounds currently.
299+
# Internal function used by "balance_reaction" (via "get_balanced_stoich").
300+
function create_matrix(reaction::Catalyst.Reaction)
301+
@unpack substrates, products = reaction
302+
unique_atoms = [] # Array to store unique atoms
303+
n_atoms = 0
304+
ncompounds = length(substrates) + length(products)
305+
A = zeros(Int, 0, ncompounds)
306+
307+
coeffsign = 1
308+
jbase = 0
309+
for compounds in (substrates, products)
310+
for (j2, compound) in enumerate(compounds)
311+
j = jbase + j2
312+
313+
if iscompound(compound)
314+
atoms = components(compound)
315+
any(iscompound, atoms) && throw(COMPOUND_OF_COMPOUND_ERROR)
316+
coeffs = coefficients(compound)
317+
(atoms == nothing || coeffs == nothing) && continue
318+
else
319+
# If not a compound, assume coefficient of 1
320+
atoms = [compound]
321+
coeffs = [1]
322+
end
323+
324+
for (atom,coeff) in zip(atoms, coeffs)
325+
# Extract atom and coefficient from the pair
326+
i = findfirst(x -> isequal(x, atom), unique_atoms)
327+
if i === nothing
328+
# Add the atom to the atoms array if it's not already present
329+
push!(unique_atoms, atom)
330+
n_atoms += 1
331+
A = [A; zeros(Int, 1, ncompounds)]
332+
i = n_atoms
333+
end
334+
335+
# Adjust coefficient based on whether the compound is a product or substrate
336+
coeff *= coeffsign
337+
338+
A[i, j] = coeff
339+
end
340+
end
341+
342+
# update for iterating through products
343+
coeffsign = -1
344+
jbase = length(substrates)
345+
end
346+
347+
return A
348+
end

0 commit comments

Comments
 (0)