The reason I think this is needed is that in some instances, there’s a need to interface with a complex component that can’t be modeled easily by a set of differential equations. For example, a PV module could be controlled by a complex MPPT.
Anyway, I’m stuck on the right interface.
Currently, one can define an event as follows:
ODESystem(eqs, t; continuous_events = [ x ~ 0 ] => [v ~ -v])
Now, for a generalized
affect! we can do something like:
ODESystem(eqs, t; continuous_events = [ x ~ 0 ] => affect!)
affect! is a function. However, note that in this case the user doesn’t pass the variables/parameters of interest.
Therefore, with such an interface, MTK will have to expose all variables/parameters belonging to the
ODESystem (note that if the
affect! is defined as part of a sub-system, in principle, it could access all states and parameters of the entire system. This would break modularity, so let’s not go there).
For example, we could have:
function affect!(t, sts, pars) sts.v = -sts.v end
However, MTK aggressively prunes unnecessary equations and variables. It can deduce (although it currently doesn’t) what variables that appear in affect equations should be “protected” from pruning. However, for the opaque
affect! above, this doesn’t seem possible.
Another issue is that of “context”: to be useful, the
affect! function should have access to some context/state it can interact with (e.g. the
The user could use closure to achieve this:
function make_affect(context) let context = context function (t,u,p) update!(context, u) p.C = new_c(context) end end end affect! = make_affect(MyContext())
However, this looks to me like an hack (and also a lot to expect from a library user).
So, an alternative interface could be for the user to pass not just the function, e.g.:
ODESystem(eqs, t; continuous_events = [ x ~ 0 ] => (affect!, context, (v = v, r = resistor.r), [C]))
This would allow MTK to pass the requested variables/parameters via
function affect!(t, ctx; v, r, C) v = -C*v update_context!(ctx, r) end
The main drawback I see in this solution is it’s cumbersome, but it’s the best I got.
What do you think?