Skip to content

Commit 55dce8b

Browse files
committed
change internals, handle events
1 parent ce7f9f7 commit 55dce8b

File tree

2 files changed

+95
-10
lines changed

2 files changed

+95
-10
lines changed

src/registered_functions.jl

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,23 @@ expand_registered_functions(expr)
116116
117117
Takes an expression, and expands registered function expressions. E.g. `mm(X,v,K)` is replaced with v*X/(X+K). Currently supported functions: `mm`, `mmr`, `hill`, `hillr`, and `hill`.
118118
"""
119-
function expand_registered_functions!(expr)
120-
iscall(expr) || return expr
119+
function expand_registered_functions(expr)
120+
if hasnode(is_catalyst_function, expr)
121+
expr = replacenode(expr, expand_catalyst_function)
122+
end
123+
return expr
124+
end
125+
126+
# Checks whether an expression corresponds to a catalyst function call (e.g. `mm(X,v,K)`).
127+
function is_catalyst_function(expr)
128+
iscall(expr) || (return false)
129+
return operation(expr) in [Catalyst.mm, Catalyst.mmr, Catalyst.hill, Catalyst.hillr, Catalyst.hillar]
130+
end
131+
132+
# If the input expression corresponds to a catalyst function call (e.g. `mm(X,v,K)`), returns
133+
# it in its expanded form. If not, returns the input expression.
134+
function expand_catalyst_function(expr)
135+
is_catalyst_function(expr) || (return expr)
121136
args = arguments(expr)
122137
if operation(expr) == Catalyst.mm
123138
return args[2] * args[1] / (args[1] + args[3])
@@ -131,23 +146,55 @@ function expand_registered_functions!(expr)
131146
return args[3] * (args[1]^args[5]) /
132147
((args[1])^args[5] + (args[2])^args[5] + (args[4])^args[5])
133148
end
134-
for i in 1:length(args)
135-
args[i] = expand_registered_functions!(args[i])
136-
end
137-
return expr
138149
end
150+
139151
# If applied to a Reaction, return a reaction with its rate modified.
140152
function expand_registered_functions(rx::Reaction)
141-
Reaction(expand_registered_functions!(deepcopy(rx.rate)), rx.substrates, rx.products,
153+
Reaction(expand_registered_functions(rx.rate), rx.substrates, rx.products,
142154
rx.substoich, rx.prodstoich, rx.netstoich, rx.only_use_rate, rx.metadata)
143155
end
156+
144157
# If applied to a Equation, returns it with it applied to lhs and rhs
145158
function expand_registered_functions(eq::Equation)
146-
return expand_registered_functions!(deepcopy(eq.lhs)) ~ expand_registered_functions!(deepcopy(eq.rhs))
159+
return expand_registered_functions(eq.lhs) ~ expand_registered_functions(eq.rhs)
147160
end
161+
162+
# If applied to a continuous event, returns it applied to eqs and affect.
163+
function expand_registered_functions(ce::ModelingToolkit.SymbolicContinuousCallback)
164+
eqs = expand_registered_functions(ce.eqs)
165+
affect = expand_registered_functions(ce.affect)
166+
return ModelingToolkit.SymbolicContinuousCallback(eqs, affect)
167+
end
168+
169+
# If applied to a discrete event, returns it applied to condition and affects.
170+
function expand_registered_functions(de::ModelingToolkit.SymbolicDiscreteCallback)
171+
condition = expand_registered_functions(de.condition)
172+
affects = expand_registered_functions(de.affects)
173+
return ModelingToolkit.SymbolicDiscreteCallback(condition, affects)
174+
end
175+
176+
# If applied to a vector, applies it to every element in the vector
177+
function expand_registered_functions(vec::Vector)
178+
return [Catalyst.expand_registered_functions(element) for element in vec]
179+
end
180+
148181
# If applied to a ReactionSystem, applied function to all Reactions and other Equations, and return updated system.
182+
# Currently, `ModelingToolkit.has_X_events` returns `true` even if event vector is empty (hence
183+
# this function cannot be used).
149184
function expand_registered_functions(rs::ReactionSystem)
150-
@set! rs.eqs = [Catalyst.expand_registered_functions(eq) for eq in get_eqs(rs)]
151-
@set! rs.rxs = [Catalyst.expand_registered_functions(rx) for rx in get_rxs(rs)]
185+
if isdefined(Main, :Infiltrator)
186+
Main.infiltrate(@__MODULE__, Base.@locals, @__FILE__, @__LINE__)
187+
end
188+
189+
@set! rs.eqs = Catalyst.expand_registered_functions(get_eqs(rs))
190+
@set! rs.rxs = Catalyst.expand_registered_functions(get_rxs(rs))
191+
if !isempty(ModelingToolkit.get_continuous_events(rs))
192+
@set! rs.continuous_events =
193+
Catalyst.expand_registered_functions(ModelingToolkit.get_continuous_events(rs))
194+
end
195+
if !isempty(ModelingToolkit.get_discrete_events(rs))
196+
@set! rs.discrete_events =
197+
Catalyst.expand_registered_functions(ModelingToolkit.get_discrete_events(rs))
198+
end
152199
return rs
153200
end

test/reactionsystem_core/custom_crn_functions.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Fetch packages.
44
using Catalyst, Test
5+
using ModelingToolkit: get_continuous_events, get_discrete_events
56
using Symbolics: derivative
67

78
# Sets stable rng number.
@@ -174,4 +175,41 @@ let
174175
@test isequal(only(Catalyst.get_rxs(rs_expanded_funcs)).rate, v*X/(X + K))
175176
@test isequal(last(Catalyst.get_eqs(rs)).lhs, Catalyst.mm(V,v,K))
176177
@test isequal(last(Catalyst.get_eqs(rs_expanded_funcs)).lhs, v*V/(V + K))
178+
end
179+
180+
# Tests on model with events.
181+
let
182+
# Creates a model, saves it, and creates an expanded version.
183+
rs = @reaction_network begin
184+
@continuous_events begin
185+
[mm(X,v,K) ~ 1.0] => [X ~ X]
186+
end
187+
@discrete_events begin
188+
[1.0] => [X ~ mmr(X,v,K) + Y*(v + K)]
189+
1.0 => [X ~ X]
190+
(hill(X,v,K,n) > 1000.0) => [X ~ hillr(X,v,K,n) + 2]
191+
end
192+
v0 + hillar(X,Y,v,K,n), X --> Y
193+
end
194+
rs_saved = deepcopy(rs)
195+
rs_expanded = Catalyst.expand_registered_functions(rs)
196+
197+
# Checks that the original model is unchanged (equality currently does not consider events).
198+
@test rs == rs_saved
199+
@test get_continuous_events(rs) == get_continuous_events(rs_saved)
200+
@test get_discrete_events(rs) == get_discrete_events(rs_saved)
201+
202+
# Checks that the new system is expanded.
203+
@unpack v0, X, Y, v, K, n = rs
204+
continuous_events = [
205+
[v*X/(X + K) ~ 1.0] => [X ~ X]
206+
]
207+
discrete_events = [
208+
[1.0] => [X ~ v*K/(X + K) + Y*(v + K)]
209+
1.0 => [X ~ X]
210+
(v * (X^n) / (X^n + K^n) > 1000.0) => [X ~ v * (K^n) / (X^n + K^n) + 2]
211+
]
212+
@test isequal(only(Catalyst.get_rxs(rs_expanded)).rate, v0 + v * (X^n) / (X^n + Y^n + K^n))
213+
@test isequal(get_continuous_events(rs_expanded).eqs, [v*X/(K + X) ~ 1.0])
214+
@test isequal(get_continuous_events(rs_expanded).eqs, [v*X/(K + X) ~ 1.0])
177215
end

0 commit comments

Comments
 (0)