Skip to content

Commit 8468313

Browse files
committed
update constraint eq tutorial
1 parent edc535a commit 8468313

File tree

1 file changed

+88
-22
lines changed

1 file changed

+88
-22
lines changed

docs/src/model_creation/constraint_equations.md

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ The easiest way to include ODEs and algebraic equations is to just include them
2121
when using the DSL to specify a model. Here we include an ODE for $V(t)$ along
2222
with degradation and production reactions for $P(t)$:
2323
```@example ceq1
24-
rn = @reaction_network dynamic_cell begin
24+
using Catalyst, OrdinaryDiffEqTsit5, Plots
25+
26+
rn = @reaction_network growing_cell begin
2527
# the growth rate
2628
@parameters λ = 1.0
2729
@@ -44,7 +46,7 @@ end
4446
We can now create an `ODEProblem` from our model and solve it to see how $V(t)$
4547
and $P(t)$ evolve in time:
4648
```@example ceq1
47-
oprob = ODEProblem(growing_cell, [], (0.0, 1.0))
49+
oprob = ODEProblem(rn, [], (0.0, 1.0))
4850
sol = solve(oprob, Tsit5())
4951
plot(sol)
5052
```
@@ -54,6 +56,7 @@ As an alternative to the previous approach, we could have also constructed our
5456
`ReactionSystem` all at once using the symbolic interface:
5557
```@example ceq2
5658
using Catalyst, OrdinaryDiffEqTsit5, Plots
59+
5760
t = default_t()
5861
D = default_time_deriv()
5962
@@ -84,8 +87,9 @@ equations), we must import the time differential operator from Catalyst. We do
8487
this through `D = default_time_deriv()`. Here, `D(V)` denotes the differential
8588
of the variable `V` with respect to time.
8689

87-
```@example ceq1
90+
```@example ceq2b
8891
using Catalyst, OrdinaryDiffEqTsit5, Plots
92+
8993
t = default_t()
9094
D = default_time_deriv()
9195
@@ -116,14 +120,14 @@ systems together Catalyst requires that the systems have not been marked as
116120

117121
We can now merge the two systems into one complete `ReactionSystem` model using
118122
[`ModelingToolkit.extend`](@ref):
119-
```@example ceq1
123+
```@example ceq2b
120124
@named growing_cell = extend(osys, rn)
121125
growing_cell = complete(growing_cell)
122126
```
123127

124128
We see that the combined model now has both the reactions and ODEs as its
125129
equations. To solve and plot the model we proceed like normal
126-
```@example ceq1
130+
```@example ceq2b
127131
oprob = ODEProblem(growing_cell, [], (0.0, 1.0))
128132
sol = solve(oprob, Tsit5())
129133
plot(sol)
@@ -143,7 +147,82 @@ details on the types of events that can be represented symbolically. A
143147
lower-level approach for creating events via the DifferentialEquations.jl
144148
callback interface is illustrated [here](https://docs.sciml.ai/DiffEqDocs/stable/features/callback_functions/) tutorial.
145149

146-
Let's first create our equations and unknowns/species again
150+
```@example ceq3a
151+
using Catalyst, OrdinaryDiffEqTsit5, Plots
152+
153+
rn = @reaction_network growing_cell begin
154+
# the growth rate
155+
@parameters λ = 1.0
156+
157+
# assume there is no protein initially
158+
@species P(t) = 0.0
159+
160+
# set the initial volume to 1.0
161+
@variables V(t) = 1.0
162+
163+
# the reactions
164+
V, 0 --> P
165+
1.0, P --> 0
166+
167+
# the coupled ODE for V(t)
168+
@equations begin
169+
D(V) ~ λ * V
170+
end
171+
172+
# every 1.0 time unit we half the volume of the cell and the number of proteins
173+
@continuous_events begin
174+
[V ~ 2.0] => [V ~ V/2, P ~ P/2]
175+
end
176+
end
177+
```
178+
We can now create and simulate our model
179+
```@example ceq3a
180+
oprob = ODEProblem(rn, [], (0.0, 10.0))
181+
sol = solve(oprob, Tsit5())
182+
plot(sol)
183+
Catalyst.PNG(plot(sol; fmt = :png, dpi = 200)) # hide
184+
```
185+
We can also model discrete events. Here at a time `switch_time` we will set the parameter `k_on` to be
186+
zero:
187+
```@example ceq3a
188+
rn = @reaction_network param_off_ex begin
189+
@parameters switch_time
190+
k_on, A --> B
191+
k_off, B --> A
192+
193+
@discrete_events begin
194+
(t == switch_time) => [k_on ~ 0.0]
195+
end
196+
end
197+
198+
u0 = [:A => 10.0, :B => 0.0]
199+
tspan = (0.0, 4.0)
200+
p = [:k_on => 100.0, :switch_time => 2.0, :k_off => 10.0]
201+
oprob = ODEProblem(rn, u0, tspan, p)
202+
sol = solve(oprob, Tsit5(); tstops = 2.0)
203+
plot(sol)
204+
```
205+
Note that for discrete events we need to set a stop time via `tstops` so that
206+
the ODE solver can step exactly to the specific time of our event. In the
207+
previous example we just manually set the numeric value of the parameter in the
208+
`tstops` kwarg to `solve`, however, it can often be convenient to instead get
209+
the value of the parameter from `oprob` and pass this numeric value. This helps
210+
ensure consistency between the value passed via `p` and/or symbolic defaults and
211+
what we pass as a `tstop` to `solve`. We can do this as
212+
```@example ceq3a
213+
oprob = ODEProblem(rn, u0, tspan, p)
214+
switch_time_val = oprob.ps[:switch_time]
215+
sol = solve(oprob, Tsit5(); tstops = switch_time_val)
216+
plot(sol)
217+
```
218+
For a detailed discussion on how to directly use the lower-level but more
219+
flexible DifferentialEquations.jl event/callback interface, see the
220+
[tutorial](https://docs.sciml.ai/Catalyst/stable/catalyst_applications/advanced_simulations/#Event-handling-using-callbacks)
221+
on event handling using callbacks.
222+
223+
## [Adding events via the symbolic interface](@id constraint_equations_events_symbolic)
224+
Let's repeat the previous two models using the symbolic interface. We first
225+
create our equations and unknowns/species again
147226
```@example ceq3
148227
using Catalyst, OrdinaryDiffEqTsit5, Plots
149228
t = default_t()
@@ -171,7 +250,9 @@ sol = solve(oprob, Tsit5())
171250
plot(sol)
172251
Catalyst.PNG(plot(sol; fmt = :png, dpi = 200)) # hide
173252
```
174-
We can also model discrete events. Similar to our example with continuous events, we start by creating reaction equations, parameters, variables, and unknowns.
253+
We can again also model discrete events. Similar to our example with continuous
254+
events, we start by creating reaction equations, parameters, variables, and
255+
unknowns.
175256
```@example ceq3
176257
t = default_t()
177258
@parameters k_on switch_time k_off
@@ -193,22 +274,7 @@ Simulating our model,
193274
rs2 = complete(rs2)
194275
195276
oprob = ODEProblem(rs2, u0, tspan, p)
196-
sol = solve(oprob, Tsit5(); tstops = 2.0)
197-
plot(sol)
198-
```
199-
Note that for discrete events we need to set a stop time via `tstops` so that
200-
the ODE solver can step exactly to the specific time of our event. In the
201-
previous example we just manually set the numeric value of the parameter in the
202-
`tstops` kwarg to `solve`, however, it can often be convenient to instead get
203-
the value of the parameter from `oprob` and pass this numeric value. This helps
204-
ensure consistency between the value passed via `p` and/or symbolic defaults and
205-
what we pass as a `tstop` to `solve`. We can do this as
206-
```julia
207277
switch_time_val = oprob.ps[:switch_time]
208278
sol = solve(oprob, Tsit5(); tstops = switch_time_val)
209279
plot(sol)
210280
```
211-
For a detailed discussion on how to directly use the lower-level but more
212-
flexible DifferentialEquations.jl event/callback interface, see the
213-
[tutorial](https://docs.sciml.ai/Catalyst/stable/catalyst_applications/advanced_simulations/#Event-handling-using-callbacks)
214-
on event handling using callbacks.

0 commit comments

Comments
 (0)