# Generalized affects in MTK - what's a good interface?

**URL:** <https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390>\
**Category:** Modelling & Simulations\
**Tags:** modelingtoolkit\
**Created:** [June 27, 2022, 9:35am UTC](https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390 "2022-06-27T09:35:00Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [June 27, 2022, 9:35am UTC](https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390/1 "2022-06-27T09:35:00Z")

</div>

Hi,

I’ve recently started a [pull request](https://github.com/SciML/ModelingToolkit.jl/pull/1649) in an attempt to add more generalized `affect!` support to MTK (and also to support `discrete_events`, which is taken on by [others](https://github.com/SciML/ModelingToolkit.jl/pull/1663))

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:

```julia
ODESystem(eqs, t; continuous_events = [x ~ 0] => [v ~ -v])

```

Now, for a generalized `affect!` we can do something like:

```julia
ODESystem(eqs, t; continuous_events = [x ~ 0] => affect!)

```

where `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:

```julia
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 `MPPT` component).

The user _could_ use closure to achieve this:

```julia
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.:

```julia
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 `kwargs`:

```julia
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?

DD

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 28, 2022, 10:37am UTC](https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390/2 "2022-06-28T10:37:12Z")

</div>

This is probably a better discussion for the MTK issues. You won’t catch Yingbo on here often.

Though I wonder if it should just be

```julia
ODESystem(eqs, t; continuous_events = [x ~ 0] => affect!(:integrator,x,y))

```

which generates a function:

```julia
affect!(integrator,x,y)

```

where `x` is the integer for the index of `x`. That way you do `integrator.u[x]`.

But honestly, that’s then getting very close to just writing it yourself with `varmap_to_vars`. It might be simpler to just add symbolic indexing support to `AbstractVectorOfArray` and then `integrator.u[x]` would just work on the symbolic `x`, or just make `integrator[x]` work on the symbolic `x`. Then writing a the callback by hand is not much harder than this other interface.

---

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [June 28, 2022, 4:37pm UTC](https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390/3 "2022-06-28T16:37:44Z")

</div>

> [@ChrisRackauckas](#):
>
> Though I wonder if it should just be
> 
> ```julia
> ODESystem(eqs, t; continuous_events = [x ~ 0] => affect!(:integrator,x,y))
> 
> ```
> 
> which generates a function:
> 
> ```julia
> affect!(integrator,x,y)
> 
> ```
> 
> where `x` is the integer for the index of `x`. That way you do `integrator.u[x]`.

Encapsulating the affect construction as a function call could work.

However, I don’t like the idea of exposing `integrator` this way: this breaks modularity.  
I don’t want code simulating a bolt having access to parameters of the jet it is part of.

I think that:

```julia
function affect!(;x,y)
   x = x*y
end

```

is better than:

```julia
function affect!(integ; x, y)
   integ[x] = integ[x]*integ[y]
end

```

I _think_ this can be done at zero-cost.  
An alternative (which I don’t like) would be:

```julia
function affect!(t, sts, pars)
   sts.x = sts.x * sts.y
end

```

This is actually not far from passing the `integrator` - or rather a **view** of the integrator with only the variables requested in the call to `affect!` exposed (which now I think about it, is probably what you meant).

DD

---

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [June 28, 2022, 5:35pm UTC](https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390/4 "2022-06-28T17:35:58Z")

</div>

Hmm…

the syntax I’ve suggested won’t work:

```julia
   x = x*y

```

will _replace_ `x`. I’m pretty sure I can’t overload `=`.  
Of course, I could use a similar syntax to `Symbolics`:

```julia
   x ~ x*y

```

But this will only confuse the users.

Maybe `sts.x = sts.x * sts.y` or `sts[:x] = sts[:x] * sts[:y]` is not that bad…

---

<div class="post-metadata">

**Author:** ![YingboMa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yingboma/32/2181_2.png) [@YingboMa](https://discourse.julialang.org/u/YingboMa)\
**Post date:** [June 29, 2022, 4:57pm UTC](https://discourse.julialang.org/t/generalized-affects-in-mtk-whats-a-good-interface/83390/5 "2022-06-29T16:57:08Z")

</div>

What about

```julia
ODESystem(eqs, t; continuous_events = [x ~ 0] => (affect!, (v = v, r = resistor.r), [C]))

```

with

```julia
function affect!(integrator; v, r, C)
    integrator.u[v] = -integrator.p[C] * integrator.u[v] - integrator.u[r]
end

```

?

> But honestly, that’s then getting very close to just writing it yourself with `varmap_to_vars`. It might be simpler to just add symbolic indexing support to `AbstractVectorOfArray` and then `integrator.u[x]` would just work on the symbolic `x`, or just make `integrator[x]` work on the symbolic `x`. Then writing a the callback by hand is not much harder than this other interface.

Working with `Symbol` would put strain on the Julia compiler and also ambiguous. For instance, what if `x` is a symbolic array? If `x` is namespaced deep in a component, the user has to write `\_+` as well. It also kind of defeats the point of a-causal modeling as one needs to rewrite `affect!` when the model structure changes.
