@@ -337,3 +337,84 @@ plot(sol(tv)[y], sol(tv)[x], line_z=tv)
337
337
vline!([-1.5, 1.5], l=(:black, 5), primary=false)
338
338
hline!([0], l=(:black, 5), primary=false)
339
339
```
340
+
341
+ ### Generalized affect support
342
+ In some instances, a more flexible response to events is needed, which cannot be encapsulated by
343
+ an equation. For example, a component may implement complex behavior that it is inconvenient or
344
+ impossible to capture in equations.
345
+
346
+ ModelingToolkit therefore supports Julia functions as affects: instead of an equation, an affect is
347
+ defined as a ` tuple ` :
348
+ ```
349
+ [x ~ 0] => (affect!, [v, x], [p, q], ctx)
350
+ ```
351
+
352
+ where, ` affect! ` is a Julia function with the signature: ` affect!(integ, u, p, ctx) ` ; ` [u,v] ` and ` [p,q] `
353
+ are the states (variables) and parameters that are accessed by ` affect! ` , respectively; and ` ctx ` is a
354
+ context that is passed to ` affect! ` as the ` ctx ` argument.
355
+
356
+ ` affect! ` receives the ` DiffEqs ` integrator as its first argument, which can then be used to access states
357
+ and parameters that are provided in the ` u ` and ` p ` arguments (implemented as ` NamedTuple ` s):
358
+
359
+ ```
360
+ function affect!(integ, u, v, ctx)
361
+ # integ.t is the current time
362
+ # integ.u[u.v] is the value of the state `v` above
363
+ # integ.p[p.q] is the value of the parameter `q` above
364
+ end
365
+ ```
366
+
367
+ When accessing variables of a sub-system, it could be useful to rename them (alternatively, an affect function
368
+ may be reused in different contexts):
369
+ ```
370
+ [x ~ 0] => (affect!, [resistor₊v => :v, x], [p, q => :p2], ctx)
371
+ ```
372
+
373
+ Here, ` resistor₊v ` is passed as ` v ` while ` q ` has been renamed ` p2 ` .
374
+
375
+ As an example, here is the bouncing ball example from ` DiffEqs ` using ModelingToolkit:
376
+
377
+ ``` @example events
378
+ sts = @variables y(t), v(t)
379
+ par = @parameters g = 9.8
380
+ bb_eqs = [D(y) ~ v
381
+ D(v) ~ -g]
382
+
383
+ function bb_affect!(integ, u, p, ctx)
384
+ integ.u[u.v] = -integ.u[u.v]
385
+ end
386
+
387
+ @named bb_model = ODESystem(bb_eqs, t, sts, par,
388
+ continuous_events = [[y ~ 0] => (bb_affect!, [v], [], nothing)])
389
+
390
+ bb_sys = structural_simplify(bb_model)
391
+ u0 = [v => 0.0, y => 50.0]
392
+
393
+ bb_prob = ODEProblem(bb_sys, u0, (0, 15.0))
394
+ bb_sol = solve(bb_prob, Tsit5())
395
+
396
+ plot(bb_sol)
397
+ ```
398
+
399
+ ### Discrete events support
400
+ In addition to continuous events, discrete events are also supported.
401
+
402
+ TBD
403
+
404
+ Two important sub-classes of discrete events are periodic and set-time events. A periodic event is triggered at
405
+ fixed intervals (e.g. every Δt seconds). To specify a periodic interval, pass the interval as the condition for
406
+ the event:
407
+
408
+ ```
409
+ discrete_events=[1.0 => [v ~ -v]]
410
+ ```
411
+
412
+ will change the sign of ` v ` at t=1.0, 2.0, ...
413
+
414
+ Alternatively, the event may be triggered at specific set times:
415
+ ```
416
+ discrete_events=[[1.0, 4.0] => [v ~ -v]]
417
+ ```
418
+
419
+ will change the sign of ` v ` * only* at t=1.0, 4.0.
420
+
0 commit comments