Skip to content

Commit f148311

Browse files
authored
Merge pull request #319 from isaacsas/allow-sys-names-and-more
Allow sys names and other API fixes
2 parents 890fa43 + c3c26ee commit f148311

File tree

7 files changed

+86
-37
lines changed

7 files changed

+86
-37
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Catalyst"
22
uuid = "479239e8-5488-4da2-87a7-35f2df7eef83"
3-
version = "6.9.1"
3+
version = "6.10.0"
44

55
[deps]
66
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
@@ -17,7 +17,7 @@ DataStructures = "0.18"
1717
DocStringExtensions = "0.8"
1818
Latexify = "0.14"
1919
MacroTools = "0.5.5"
20-
ModelingToolkit = "5.12.0"
20+
ModelingToolkit = "5.13.0"
2121
Parameters = "0.12"
2222
Reexport = "0.2, 1.0"
2323
Requires = "1.0"

docs/src/api/catalyst_api.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ be converted to other `ModelingToolkit.AbstractSystem`s, including a
1111
`ModelingToolkit.ODESystem`, `ModelingToolkit.SDESystem`, or
1212
`ModelingToolkit.JumpSystem`.
1313

14-
An empty network can be generated using [`@reaction_network`](@ref) with no arguments or
15-
the [`make_empty_network`](@ref) function. These can then be extended
14+
An empty network can be generated using [`@reaction_network`](@ref) with no
15+
arguments (or one argument to name the system), or the
16+
[`make_empty_network`](@ref) function. These can then be extended
1617
programmatically using [`addspecies!`](@ref), [`addparam!`](@ref), and
1718
[`addreaction!`](@ref).
1819

docs/src/tutorials/generated_systems.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Each `Reaction` within `reactions(rn)` has a number of subfields. For `rx` a
3333
non-filled arrows and should ignore mass action kinetics. `false` by default.
3434

3535
Empty `ReactionSystem`s can be generated via [`make_empty_network`](@ref) or
36-
[`@reaction_network`](@ref) with no arguments. `ReactionSystem`s can be
37-
programmatically extended using [`addspecies!`](@ref), [`addparam!`](@ref),
38-
[`addreaction!`](@ref), [`@add_reactions`](@ref), or composed using `merge` and
39-
`merge!`.
36+
[`@reaction_network`](@ref) with no arguments (giving one argument to the latter
37+
will specify a system name). `ReactionSystem`s can be programmatically extended
38+
using [`addspecies!`](@ref), [`addparam!`](@ref), [`addreaction!`](@ref),
39+
[`@add_reactions`](@ref), or composed using `merge` and `merge!`.

src/networkapi.jl

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Return the number of species within the given [`ReactionSystem`](@ref).
6969
function numspecies(network)
7070
ns = length(ModelingToolkit.ModelingToolkit.get_states(network))
7171
for sys in ModelingToolkit.get_systems(network)
72-
ns += numspecies(ns)
72+
ns += numspecies(sys)
7373
end
7474
ns
7575
end
@@ -95,7 +95,7 @@ Return the number of parameters within the given [`ReactionSystem`](@ref).
9595
function numparams(network)
9696
np = length(ModelingToolkit.get_ps(network))
9797
for sys in ModelingToolkit.get_systems(network)
98-
np += numparams(ns)
98+
np += numparams(sys)
9999
end
100100
np
101101
end
@@ -219,13 +219,14 @@ end
219219
######################## functions to extend a network ####################
220220

221221
"""
222-
make_empty_network(; iv=Sym{ModelingToolkit.Parameter{Real}}(:t))
222+
make_empty_network(; iv=Sym{ModelingToolkit.Parameter{Real}}(:t),
223+
name=gensym(:ReactionSystem))
223224
224225
Construct an empty [`ReactionSystem`](@ref). `iv` is the independent variable,
225-
usually time.
226+
usually time, and `name` is the name to give the `ReactionSystem`.
226227
"""
227-
function make_empty_network(; iv=Sym{ModelingToolkit.Parameter{Real}}(:t))
228-
ReactionSystem(Reaction[], iv, [], [], Equation[], gensym(:ReactionSystem), ReactionSystem[])
228+
function make_empty_network(; iv=Sym{ModelingToolkit.Parameter{Real}}(:t), name=gensym(:ReactionSystem))
229+
ReactionSystem(Reaction[], iv, [], [], Equation[], name, ReactionSystem[])
229230
end
230231

231232
"""
@@ -244,10 +245,10 @@ Notes:
244245
function addspecies!(network::ReactionSystem, s::Symbolic; disablechecks=false)
245246

246247
# we don't check subsystems since we will add it to the top-level system...
247-
curidx = disablechecks ? nothing : findfirst(S -> isequal(S, s), ModelingToolkit.ModelingToolkit.get_states(network))
248+
curidx = disablechecks ? nothing : findfirst(S -> isequal(S, s), ModelingToolkit.get_states(network))
248249
if curidx === nothing
249-
push!(ModelingToolkit.ModelingToolkit.get_states(network), s)
250-
return length(ModelingToolkit.ModelingToolkit.get_states(network))
250+
push!(ModelingToolkit.get_states(network), s)
251+
return length(ModelingToolkit.get_states(network))
251252
else
252253
return curidx
253254
end

src/reaction_network.jl

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ bwd_arrows = Set{Symbol}([:<, :←, :↢, :↤, :⇽, :⟵, :⟻, :⥚, :⥞, :
6565
double_arrows = Set{Symbol}([:, :, :, :, :, :, :, :])
6666
pure_rate_arrows = Set{Symbol}([:, :, :, :, :, :])
6767

68+
# unfortunately the following doesn't seem to work on 1.5, so supporting these
69+
# operators seems to require us to only support 1.6 and up...
70+
# @static if VERSION >= v"1.6.0"
71+
# push!(bwd_arrows, :<--)
72+
# push!(double_arrows, :<-->)
73+
# end
74+
75+
6876
# Declares symbols which may neither be used as parameters not varriables.
6977
forbidden_symbols = [:t, , :pi, :ℯ, :im, :nothing, :∅]
7078

@@ -78,26 +86,50 @@ network.
7886
7987
See the [Catalyst.jl for Reaction Models](@ref) documentation for details on
8088
parameters to the macro.
89+
90+
Examples:
91+
```julia
92+
# a basic SIR model, with name SIR
93+
sir_model = @reaction_network SIR begin
94+
c1, s + i --> 2i
95+
c2, i --> r
96+
end c1 c2
97+
98+
# a basic SIR model, with random generated name
99+
sir_model = @reaction_network begin
100+
c1, s + i --> 2i
101+
c2, i --> r
102+
end c1 c2
103+
104+
# an empty network with name empty
105+
emptyrn = @reaction_network empty
106+
107+
# an empty network with random generated name
108+
emptyrn = @reaction_network
109+
```
81110
"""
111+
macro reaction_network(name::Symbol, ex::Expr, parameters...)
112+
make_reaction_system(MacroTools.striplines(ex), parameters; name=name)
113+
end
114+
82115
macro reaction_network(ex::Expr, parameters...)
83116
make_reaction_system(MacroTools.striplines(ex), parameters)
84117
end
85118

86-
### Macros used for manipulating, and successively builing up, reaction systems. ###
87-
88-
#Returns a empty network (with, or without, parameters declared)
89-
macro reaction_network(parameters...)
90-
!isempty(intersect(forbidden_symbols,parameters)) && error("The following symbol(s) are used as parameters: "*((map(s -> "'"*string(s)*"', ",intersect(forbidden_symbols,parameters))...))*"this is not permited.")
91-
return Expr(:block,:(@parameters $((:t,parameters...)...)),
119+
#Returns a empty network (with, or without, a declared name)
120+
macro reaction_network(name::Symbol=gensym(:ReactionSystem))
121+
return Expr(:block,:(@parameters t),
92122
:(ReactionSystem(Reaction[],
93123
t,
94124
[],
95-
[$(parameters...)],
125+
[],
96126
Equation[],
97-
gensym(:ReactionSystem),
127+
$(QuoteNode(name)),
98128
ReactionSystem[])))
99129
end
100130

131+
### Macros used for manipulating, and successively builing up, reaction systems. ###
132+
101133
"""
102134
@add_reactions
103135
@@ -139,16 +171,15 @@ end
139171
### Functions that process the input and rephrase it as a reaction system ###
140172

141173
# Takes the reactions, and rephrases it as a "ReactionSystem" call, as designated by the ModelingToolkit IR.
142-
function make_reaction_system(ex::Expr, parameters)
174+
function make_reaction_system(ex::Expr, parameters; name=gensym(:ReactionSystem))
143175
reactions = get_reactions(ex)
144176
reactants = get_reactants(reactions)
145-
!isempty(intersect(forbidden_symbols,union(reactants,parameters))) && error("The following symbol(s) are used as reactants or parameters: "*((map(s -> "'"*string(s)*"', ",intersect(forbidden_symbols,union(reactants,parameters)))...))*"this is not permited.")
146-
147-
network_code = Expr(:block,:(@parameters t),:(@variables), :(ReactionSystem([],t,[],[])))
177+
!isempty(intersect(forbidden_symbols,union(reactants,parameters))) && error("The following symbol(s) are used as reactants or parameters: "*((map(s -> "'"*string(s)*"', ",intersect(forbidden_symbols,union(reactants,parameters)))...))*"this is not permited.")
178+
network_code = Expr(:block,:(@parameters t),:(@variables), :(ReactionSystem([],t,[],[]; name=$(QuoteNode(name)))))
148179
foreach(parameter-> push!(network_code.args[1].args, parameter), parameters)
149180
foreach(reactant -> push!(network_code.args[2].args, Expr(:call,reactant,:t)), reactants)
150-
foreach(parameter-> push!(network_code.args[3].args[5].args, parameter), parameters)
151-
foreach(reactant -> push!(network_code.args[3].args[4].args, reactant), reactants)
181+
foreach(parameter-> push!(network_code.args[3].args[6].args, parameter), parameters)
182+
foreach(reactant -> push!(network_code.args[3].args[5].args, reactant), reactants)
152183
for reaction in reactions
153184
subs_init = isempty(reaction.substrates) ? nothing : :([]); subs_stoich_init = deepcopy(subs_init)
154185
prod_init = isempty(reaction.products) ? nothing : :([]); prod_stoich_init = deepcopy(prod_init)
@@ -161,7 +192,7 @@ function make_reaction_system(ex::Expr, parameters)
161192
push!(reaction_func.args[4].args, prod.reactant)
162193
push!(reaction_func.args[6].args, prod.stoichiometry)
163194
end
164-
push!(network_code.args[3].args[2].args,reaction_func)
195+
push!(network_code.args[3].args[3].args,reaction_func)
165196
end
166197
return network_code
167198
end

test/make_model.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ rng = StableRNG(12345)
88
include("test_networks.jl")
99

1010

11-
### Debugg functions ###
12-
11+
### Debug functions ###
1312
opname(x) = istree(x) ? nameof(operation(x)) : nameof(x)
14-
1513
alleq(xs,ys) = all(isequal(x,y) for (x, y) in zip(xs, ys))
1614

1715
# Gets all the reactants in a set of equations.
@@ -405,3 +403,13 @@ rn = @reaction_network begin
405403
k2, I --> R
406404
end k1 k2
407405
@test isequal(opname(species(rn)[2]),:I)
406+
407+
408+
# test names work
409+
rn = @reaction_network SIR1 begin
410+
k1, S + I --> 2I
411+
k2, I --> R
412+
end k1 k2
413+
@test nameof(rn) == :SIR1
414+
415+

test/model_modification.jl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ empty_network_1 = @reaction_network
1313
@test length(empty_network_1.states) == 0
1414
@test length(ps) == 0
1515

16-
empty_network_2 = @reaction_network p1 p2 p3 p4 p5
16+
empty_network_2 = @reaction_network
17+
@variables p1 p2 p3 p4 p5
18+
addparam!(empty_network_2, p1)
19+
addparam!(empty_network_2, p2)
20+
addparam!(empty_network_2, p3)
21+
addparam!(empty_network_2, p4)
22+
addparam!(empty_network_2, p5)
1723
@unpack eqs,iv,ps,name,systems = empty_network_2
1824
@test length(eqs) == 0
1925
@test iv.name == :t
@@ -129,7 +135,9 @@ end k1
129135
end k4 m J4
130136
push!(identical_networks, reaction_networks_real[3] => step_by_step_network_7)
131137

132-
step_by_step_network_8 = @reaction_network k1
138+
step_by_step_network_8 = @reaction_network
139+
@parameters k1
140+
addparam!(step_by_step_network_8,k1)
133141
@add_reactions step_by_step_network_8 begin
134142
k1, X1 X2
135143
0, X2 X3

0 commit comments

Comments
 (0)