@@ -25,12 +25,13 @@ functional affect](@id func_affects) representation is also allowed as described
25
25
below.
26
26
27
27
## Continuous Events
28
- The basic purely symbolic continuous event interface is
28
+ The basic purely symbolic continuous event interface to encode * one* continuous
29
+ event is
29
30
``` julia
30
31
AbstractSystem (eqs, ... ; continuous_events:: Vector{Equation} )
31
32
AbstractSystem (eqs, ... ; continuous_events:: Pair{Vector{Equation}, Vector{Equation}} )
32
33
```
33
- In the former equations that evaluate to 0 will represent conditions that should
34
+ In the former, equations that evaluate to 0 will represent conditions that should
34
35
be detected by the integrator, for example to force stepping to times of
35
36
discontinuities. The latter allow modeling of events that have an effect on the
36
37
state, where the first entry in the ` Pair ` is a vector of equations describing
@@ -135,17 +136,17 @@ hline!([0], l=(:black, 5), primary=false)
135
136
136
137
### [ Generalized functional affect support] (@id func_affects)
137
138
In some instances, a more flexible response to events is needed, which cannot be
138
- encapsulated by a symbolic equations. For example, a component may implement
139
+ encapsulated by symbolic equations. For example, a component may implement
139
140
complex behavior that is inconvenient or impossible to represent symbolically.
140
141
ModelingToolkit therefore supports regular Julia functions as affects: instead
141
142
of one or more equations, an affect is defined as a ` tuple ` :
142
143
``` julia
143
144
[x ~ 0 ] => (affect!, [v, x], [p, q], ctx)
144
145
```
145
146
where, ` affect! ` is a Julia function with the signature: `affect!(integ, u, p,
146
- ctx)` ; ` [ u,v] ` and ` [ p,q] ` are the states (variables) and parameters that are
147
- accessed by ` affect! ` , respectively; and ` ctx ` is a context that is passed to
148
- ` affect! ` as the ` ctx ` argument.
147
+ ctx)` ; ` [ u,v] ` and ` [ p,q] ` are the symbolic states (variables) and parameters
148
+ that are accessed by ` affect! ` , respectively; and ` ctx ` is a context that is
149
+ passed to ` affect! ` as the ` ctx ` argument.
149
150
150
151
` affect! ` receives a [ DifferentialEquations.jl
151
152
integrator] ( https://docs.sciml.ai/stable/modules/DiffEqDocs/basics/integrator/ )
@@ -173,39 +174,42 @@ parameter `q` has been renamed `p2`.
173
174
As an example, here is the bouncing ball example from above using the functional
174
175
affect interface:
175
176
``` @example events
176
- sts = @variables y (t), v(t)
177
+ sts = @variables x (t), v(t)
177
178
par = @parameters g = 9.8
178
- bb_eqs = [D(y ) ~ v
179
+ bb_eqs = [D(x ) ~ v
179
180
D(v) ~ -g]
180
181
181
182
function bb_affect!(integ, u, p, ctx)
182
183
integ.u[u.v] = -integ.u[u.v]
183
184
end
184
185
186
+ reflect = [x ~ 0] => (bb_affect!, [v], [], nothing)
187
+
185
188
@named bb_model = ODESystem(bb_eqs, t, sts, par,
186
- continuous_events = [[y ~ 0] => (bb_affect!, [v], [], nothing)] )
189
+ continuous_events = reflect )
187
190
188
191
bb_sys = structural_simplify(bb_model)
189
- u0 = [v => 0.0, y => 50 .0]
192
+ u0 = [v => 0.0, x => 1 .0]
190
193
191
- bb_prob = ODEProblem(bb_sys, u0, (0, 15 .0))
194
+ bb_prob = ODEProblem(bb_sys, u0, (0, 5 .0))
192
195
bb_sol = solve(bb_prob, Tsit5())
193
196
194
197
plot(bb_sol)
195
198
```
196
199
197
200
## Discrete events support
198
201
In addition to continuous events, discrete events are also supported. The
199
- general interface to represent one discrete event is
202
+ general interface to represent a collection of discrete events is
200
203
``` julia
201
- AbstractSystem (eqs, ... ; discrete_events: : [condition1 => affect1, condition2 => affect2])
204
+ AbstractSystem (eqs, ... ; discrete_events = [condition1 => affect1, condition2 => affect2])
202
205
```
203
- where conditions are symbolic expressions that should evaluate to ` true ` when
204
- the affect should be executed. Here ` affect1 ` and ` affect2 ` are each either a
205
- vector of one or more symbolic equations, or a functional affect, just as for
206
- continuous events. As before for any * one* event the symbolic affect equations
207
- can either all change states (i.e. variables) or all change parameters, but one
208
- can not currently mix state and parameter changes within one individual event.
206
+ where conditions are symbolic expressions that should evaluate to ` true ` when an
207
+ individual affect should be executed. Here ` affect1 ` and ` affect2 ` are each
208
+ either a vector of one or more symbolic equations, or a functional affect, just
209
+ as for continuous events. As before for any * one* event the symbolic affect
210
+ equations can either all change states (i.e. variables) or all change
211
+ parameters, but one can not currently mix state and parameter changes within one
212
+ individual event.
209
213
210
214
### Example: Injecting cells into a population
211
215
Suppose we have a population of ` N(t) ` cells that can grow and die, and at time
@@ -234,8 +238,9 @@ the integrator stops at that time. In the next section we show how one can
234
238
bypass this needed by using a preset-time callback.
235
239
236
240
Note that more general logical expressions can be built, for example, suppose we
237
- want the event to occur at that time only if the solution is smaller than 50% of its
238
- steady-state value(which is 100), we can encode this by modifying the event to
241
+ want the event to occur at that time only if the solution is smaller than 50% of
242
+ its steady-state value (which is 100). We can encode this by modifying the event
243
+ to
239
244
``` @example events
240
245
injection = ((t == tinject) & (N < 50)) => [N ~ N + M]
241
246
@@ -244,14 +249,15 @@ oprob = ODEProblem(osys, u0, tspan, p)
244
249
sol = solve(oprob, Tsit5(); tstops = 10.0)
245
250
plot(sol)
246
251
```
247
- Since the solution is not smaller than half its steady-state value at the event
248
- time, the event condition now returns false.
252
+ Since the solution is * not* smaller than half its steady-state value at the
253
+ event time, the event condition now returns false.
249
254
250
255
Let's now also add a drug at time ` tkill ` that turns off production of new
251
256
cells, modeled by setting ` α = 0.0 `
252
257
``` @example events
253
258
@parameters tkill
254
259
260
+ # we reset the first event to just occur at tinject
255
261
injection = (t == tinject) => [N ~ N + M]
256
262
257
263
# at time tkill we turn off production of cells
@@ -273,12 +279,11 @@ events.
273
279
A preset-time event is triggered at specific set times, which can be
274
280
passed in a vector like
275
281
``` julia
276
- discrete_events= [[1.0 , 4.0 ] => [v ~ - v]]
282
+ discrete_events = [[1.0 , 4.0 ] => [v ~ - v]]
277
283
```
278
284
This will change the sign of ` v ` * only* at ` t = 1.0 ` and ` t = 4.0 ` .
279
285
280
- For example, our last example with treatment and killing could instead be
281
- modeled by
286
+ As such, our last example with treatment and killing could instead be modeled by
282
287
``` @example events
283
288
injection = [10.0] => [N ~ N + M]
284
289
killing = [20.0] => [α ~ 0.0]
@@ -301,9 +306,8 @@ discrete_events=[1.0 => [v ~ -v]]
301
306
```
302
307
will change the sign of ` v ` at ` t = 1.0 ` , ` 2.0 ` , ...
303
308
304
-
305
309
Finally, we note that to specify an event at precisely one time, say 2.0 below,
306
310
one must still use a vector
307
311
``` julia
308
- discrete_events= [[2.0 ] => [v ~ - v]]
312
+ discrete_events = [[2.0 ] => [v ~ - v]]
309
313
```
0 commit comments