Hi everyone,

I am running into an issues using discrete events and irreducible variables in ModelingToolkit.jl. I hope the following example is sufficent as an MWE. It is a composite model of two tanks in sequence which are connected with valves. In the future, I want to set the valve position `S`

from a soft-controller in a discrete event. For now, I just use a sine function. Furthermore, a level sensor should send back the level in the tank `L`

to the soft-controller, which is “simulated” by `println()`

within the Callback.

```
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
using DifferentialEquations
using Plots
# Create a simple Tank model with reading and writing events
function affect!(integ,vars,pars,_)
integ.ps[pars.S] = 0.5 + 0.5*sin(2*3.14*integ.ps[pars.freq]*integ.t)
println("$(integ.u[vars.L])") # Read L using the passed identifier
end
@mtkmodel Tank begin
@constants begin
g::Float64 = 9.81, [description = "Gravitational acceleration."]
end
@parameters begin
S(t)::Float64 = 0.0
k_V::Float64 = 10.0
rho::Float64 = 1000.0
A::Float64 = 1.0
freq::Float64 = 0.1
end
@variables begin
F_in(t)::Float64, [guess = 0.0]
F_out(t)::Float64, [guess = 0.0]
L(t)::Float64, [guess = 0.0, irreducible = true] # Making L irreducible
V(t)::Float64 = 1.0
Dp(t)::Float64, [guess = 0.0]
end
@equations begin
D(V) ~ F_in - F_out
V ~ A*L
Dp ~ rho*g*L
F_out ~ S*k_V*sign(Dp)*sqrt(abs(Dp)/100000*1000/rho)
end
@discrete_events begin
1.0 => (affect!,[L],[freq,S],[S],nothing) # Pass indentfier for L to affect! function
end
end
# Create composite model
@mtkmodel SimulateTankSystem begin
@components begin
tank1 = Tank(;A=1.0)
tank2 = Tank(;A=2.0,freq=0.2)
end
@equations begin
tank1.F_in ~ 2.0
tank2.F_in ~ tank1.F_out
end
end
# Main function
function main()
@mtkbuild sys = SimulateTankSystem()
prob = ODEProblem(sys, [], (0.0, 10.0);tstops=0:0.1:10.0)
sol = solve(prob,QNDF()) # A DAE solver is needed here, as the equation for L remains the same!
# Plotting
plot(sol;idxs=sys.tank1.S)
plot!(sol;idxs=sys.tank2.S)
plot(sol;idxs=sys.tank1.L)
plot!(sol;idxs=sys.tank2.L)
end
main()
```

Now the issue is, that `structural_simplify()`

in `mtkbuild()`

does eliminate `L`

, if you do not apply a workarround. I studied multiple issues on this topic, e.g. #1646, #1797. They are still open but have been arround for quite a while already. They suggest to use `irreducible = true`

to avoid that the required variables are eliminated from the system.

**Now my problem:** If I use the code above the volumes `V`

and the levels `L`

are set back to the consistent initial conditions each time the callback is called. Is this intentional? What am I doing wrong here?

**Furthermore:** Have other solutions to this problem perhaps been worked out in the meantime?

- I saw one suggest like reconstructing observables
**without**using`irreducible`

. I could hardcode this in the callback using`integ.sol[integ.f.sys.tank1.L][end]`

, but I am not sure what this does to performance of the simulation for a growing number of timesteps saved within`sol`

. I have the impression that the whole time history is calculated each time I call`integ.sol`

. Furthermore, I would like to construct more complex systems in future and am not sure yet, how to get the path to the specific tank in a generic form into the callback. - Or are
**discrete-time variables**(SampledData) the way to go?

Thank you for your help !