ModelingToolkit: (Transport) delay? Example: Inflow to one water reservoir is a delayed outflow from another

Referring to @baggepinnen 's past response to the question about the possibility to model a delay using ModelingToolkit, I was just wondering if there has been any progress in this direction. Something along the line of delay(…) operator in Modelica.

Or what is the recommendation in the meantime? I am considering a cascade of water dams, wherein each dam is modelled (more or less as a plain hydraulic tank) using ModelingToolkit, but then a simple one-directional interaction between two neighbour dams is that the outflow from one constitutes an inflow to the other, surely with some (transport) delay.

DDEs are done via using the call at a different time:

using ModelingToolkit, DelayDiffEq
using ModelingToolkit: t_nounits as t, D_nounits as D

tau = 1;
@parameters p0=0.2 p1=0.2 q0=0.3 q1=0.3 v0=1 v1=1 d0=5 d1=1 d2=1 beta0=1 beta1=1
@variables x₀(t) x₁(t) x₂(..)
eqs = [D(x₀) ~ (v0 / (1 + beta0 * (x₂(t - tau)^2))) * (p0 - q0) * x₀ - d0 * x₀
       D(x₁) ~ (v0 / (1 + beta0 * (x₂(t - tau)^2))) * (1 - p0 + q0) * x₀ +
               (v1 / (1 + beta1 * (x₂(t - tau)^2))) * (p1 - q1) * x₁ - d1 * x₁
       D(x₂(t)) ~ (v1 / (1 + beta1 * (x₂(t - tau)^2))) * (1 - p1 + q1) * x₁ - d2 * x₂(t)]
@mtkbuild sys = System(eqs, t)

prob = DDEProblem(sys,
    [x₀ => 1.0, x₁ => 1.0, x₂(t) => 1.0],
    tspan,
    constant_lags = [tau])
4 Likes

I was wondering if it was somehow possible to use transport delay inside of a ModelingToolkit component. I tried modifing the example from @ChrisRackauckas to

using ModelingToolkit, DelayDiffEq
using ModelingToolkit: t_nounits as t, D_nounits as D

using Plots

# this does not work
tau = 1 
@mtkmodel FOL begin
    @parameters begin
        p0=0.2 
        p1=0.2 
        q0=0.3 
        q1=0.3 
        v0=1 
        v1=1 
        d0=5 
        d1=1 
        d2=1 
        beta0=1 
        beta1=1
    end
    @variables begin
        x₀(t) 
        x₁(t) 
        x₂(..)
    end
    @equations begin
        D(x₀) ~ (v0 / (1 + beta0 * (x₂(t - tau)^2))) * (p0 - q0) * x₀ - d0 * x₀
        D(x₁) ~ (v0 / (1 + beta0 * (x₂(t - tau)^2))) * (1 - p0 + q0) * x₀ +
               (v1 / (1 + beta1 * (x₂(t - tau)^2))) * (p1 - q1) * x₁ - d1 * x₁
        D(x₂(t)) ~ (v1 / (1 + beta1 * (x₂(t - tau)^2))) * (1 - p1 + q1) * x₁ - d2 * x₂(t)
    end
end

tspan = (0.0, 10.0)
@mtkbuild sys = FOL()

prob = DDEProblem(sys,
    [x₀ => 1.0, x₁ => 1.0, x₂(t) => 1.0],
    tspan,
    constant_lags = [tau])

alg = MethodOfSteps(Tsit5())
sol = solve(prob, alg)

plot(sol)

, but unfortunately, I had no luck running it. This is the error stacktrace:

ERROR: LoadError: AssertionError: Multiple independent variables are used in the model Symbol Symbol
Stacktrace:
  [1] assert_unique_independent_var(dict::Dict{Symbol, Any}, iv::Symbol)
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:485
  [2] assert_unique_independent_var(dict::Dict{Symbol, Any}, iv::Num)
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:478
  [3] generate_var!(dict::Dict{…}, a::Symbol, b::Symbol, varclass::Symbol, mod::Module; indices::Nothing, type::Type)
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:492
  [4] parse_variable_def!(dict::Dict{…}, mod::Module, arg::Expr, varclass::Symbol, kwargs::OrderedCollections.OrderedSet{…}, where_types::Vector{…}; def::Nothing, type::Type, meta::Dict{…})
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:279
  [5] parse_variable_def!
    @ ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:247 [inlined]
  [6] parse_variable_arg(dict::Dict{…}, mod::Module, arg::Expr, varclass::Symbol, kwargs::OrderedCollections.OrderedSet{…}, where_types::Vector{…})
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:878
  [7] parse_variable_arg!(exprs::Vector{…}, vs::Vector{…}, dict::Dict{…}, mod::Module, arg::Expr, varclass::Symbol, kwargs::OrderedCollections.OrderedSet{…}, where_types::Vector{…})
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:845
  [8] parse_variables!(exprs::Vector{…}, vs::Vector{…}, dict::Dict{…}, mod::Module, body::Expr, varclass::Symbol, kwargs::OrderedCollections.OrderedSet{…}, where_types::Vector{…})
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:1029
  [9] parse_model!(exprs::Vector{…}, comps::Vector{…}, ext::Base.RefValue{…}, eqs::Vector{…}, icon::Base.RefValue{…}, vs::Vector{…}, ps::Vector{…}, sps::Vector{…}, c_evts::Vector{…}, d_evts::Vector{…}, dict::Dict{…}, mod::Module, arg::Expr, kwargs::OrderedCollections.OrderedSet{…}, where_types::Vector{…})
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:606
 [10] _model_macro(mod::Module, name::Symbol, expr::Expr, isconnector::Bool)
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:71
 [11] var"@mtkmodel"(__source__::LineNumberNode, __module__::Module, name::Symbol, body::Any)
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/zfOUk/src/systems/model_parsing.jl:33
 [12] eval
    @ ./boot.jl:385 [inlined]
 [13] include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
    @ Base ./loading.jl:2076

Am I making any obvious mistake? Do you have any recommendation?

The change is just to the macro?

Yes, the only change is the macro. Sorry for the late response, I did not get notified.

I think we just don’t support it in the macro right now, but we should if we just lower to System instead of ODESystem. Can you open an issue?

Yes, I will open an issue later today. Thank you.

1 Like