MTK SDDE ArgumentError when Connecting two Components

Hi,
I am trying to connect two MTK components and then solve the resulting SDDE system. However, I am getting an ArgumentsError that I don’t understand.

using ModelingToolkit
using DifferentialEquations
using ModelingToolkit: t_nounits as t, D_nounits as D
using StochasticDiffEq

@component function StochasticLV(;name)
    @variables x(t) = 0.9 y(t) = 0.9
    @parameters begin
        α = 2/3
        β = 4/3
        γ = 1
        δ = 1
    end
    @brownians η
    eqs = [
        D(x) ~ α * x - β * x * y + η
        D(y) ~ -γ * y + δ * x * y
    ]
    System(eqs, t; name)
end

@component function SomethingElse(;name, τ)
    @variables z(t) = 0 x(..)
    @parameters θ = 0.1 τ = τ
    @brownians ξ
    eqs = [
        D(z) ~ -θ * x(t - τ) + ξ
    ]
    System(eqs, t; name)
end

@named lv = StochasticLV()
@named sth = SomethingElse(τ = 3)

connection_eqs = [
    sth.x ~ lv.x
]

@named connected_model = System(connection_eqs, t, [], []; systems = [lv, sth])
connected = mtkcompile(connected_model)

prob = SDDEProblem(connected, [], (0.0, 1.0))
sol = solve(prob, ImplicitEM())

Stacktrace:

ERROR: ArgumentError: sth₊x(-sth₊τ + t) is present in the system but sth₊x(-sth₊τ + t) is not an unknown.
Stacktrace:
  [1] 
    @ ModelingToolkitTearing ~/.julia/packages/ModelingToolkitTearing/ZusxN/src/tearingstate.jl:298
  [2] TearingState
    @ ~/.julia/packages/ModelingToolkitTearing/ZusxN/src/tearingstate.jl:149 [inlined]
  [3] __mtkcompile(sys::System; inputs::OrderedCollections.OrderedSet{…}, outputs::OrderedCollections.OrderedSet{…}, disturbance_inputs::OrderedCollections.OrderedSet{…}, sort_eqs::Bool, kwargs::@Kwargs{…})
    @ ModelingToolkit ~/.julia/packages/ModelingToolkit/GtdTx/src/systems/systems.jl:34
  [4] __mtkcompile
    @ ~/.julia/packages/ModelingToolkit/GtdTx/src/systems/systems.jl:23 [inlined]
  [5] _mtkcompile(sys::System; kwargs::@Kwargs{…})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/systems.jl:155
  [6] _mtkcompile
    @ ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/systems.jl:128 [inlined]
  [7] mtkcompile(sys::System; additional_passes::Tuple{}, inputs::Vector{…}, outputs::Vector{…}, disturbance_inputs::Vector{…}, split::Bool, kwargs::@Kwargs{…})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/systems.jl:100
  [8] mtkcompile
    @ ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/systems.jl:84 [inlined]
  [9] InitializationProblem{…}(sys::System, t::Float64, op::ModelingToolkitBase.AtomicArrayDict{…}; fast_path::Bool, guesses::Dict{…}, check_length::Nothing, warn_initialize_determined::Bool, initialization_eqs::Vector{…}, fully_determined::Nothing, check_units::Bool, allow_incomplete::Bool, algebraic_only::Bool, time_dependent_init::Bool, initsys_mtkcompile_kwargs::@NamedTuple{}, is_steadystateprob::Bool, kwargs::@Kwargs{…})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/problems/initializationproblem.jl:97
 [10] InitializationProblem
    @ ~/.julia/packages/ModelingToolkitBase/gJDou/src/problems/initializationproblem.jl:25 [inlined]
 [11] #_#910
    @ ./none:0 [inlined]
 [12] maybe_build_initialization_problem(sys::System, iip::Bool, op::ModelingToolkitBase.AtomicArrayDict{…}, t::Float64, guesses::Dict{…}; time_dependent_init::Bool, u0_constructor::Function, p_constructor::Function, floatT::Type, initialization_eqs::Vector{…}, use_scc::Bool, eval_expression::Bool, eval_module::Module, missing_guess_value::ModelingToolkitBase.MissingGuessValue.var"typeof(MissingGuessValue)", implicit_dae::Bool, is_steadystateprob::Bool, expression::Type, kwargs::@Kwargs{…})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/problem_utils.jl:1610
 [13] __process_SciMLProblem(constructor::Type, sys::System, op::Dict{…}; floatT::Type, u0Type::Type, u0_eltype::Type, build_initializeprob::Bool, implicit_dae::Bool, t::Float64, guesses::Dict{…}, warn_initialize_determined::Bool, initialization_eqs::Vector{…}, eval_expression::Bool, eval_module::Module, fully_determined::Nothing, check_initialization_units::Bool, tofloat::Bool, u0_constructor::typeof(identity), p_constructor::typeof(identity), check_length::Bool, symbolic_u0::Bool, warn_cyclic_dependency::Bool, circular_dependency_max_cycle_length::Int64, circular_dependency_max_cycles::Int64, initsys_mtkcompile_kwargs::@NamedTuple{}, substitution_limit::Int64, use_scc::Bool, time_dependent_init::Bool, algebraic_only::Bool, missing_guess_value::ModelingToolkitBase.MissingGuessValue.var"typeof(MissingGuessValue)", allow_incomplete::Bool, is_initializeprob::Bool, is_steadystateprob::Bool, return_operating_point::Bool, compiler_options::CompilerOptions, init_compiler_options::CompilerOptions, kwargs::@Kwargs{…})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/problem_utils.jl:2016
 [14] process_SciMLProblem(constructor::Any, sys::System, op::Any; u0_eltype::Nothing, u0_constructor::Function, p_constructor::Function, symbolic_u0::Bool, kwargs::@Kwargs{…})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/systems/problem_utils.jl:1965
 [15] (SDDEProblem{…})(sys::System, op::Vector{…}, tspan::Tuple{…}; callback::Nothing, check_length::Bool, checkbounds::Bool, eval_expression::Bool, eval_module::Module, check_compatibility::Bool, u0_constructor::typeof(identity), sparse::Bool, sparsenoise::Bool, expression::Type, kwargs::@Kwargs{})
    @ ModelingToolkitBase ~/.julia/packages/ModelingToolkitBase/gJDou/src/problems/sddeproblem.jl:74
 [16] SDDEProblem
    @ ~/.julia/packages/ModelingToolkitBase/gJDou/src/problems/sddeproblem.jl:63 [inlined]
 [17] SDDEProblem
    @ ./none:0 [inlined]
 [18] SDDEProblem(sys::System, op::Vector{Any}, tspan::Tuple{Float64, Float64})
    @ ModelingToolkitBase ./none:0
 [19] top-level scope
    @ ~/Documents/SomeProject/src/models/test.jl:42
Some type information was truncated. Use `show(err)` to see complete types.

Calling mtkcompile() on the connected_model removes the sth₊x(t) unknown.

unknowns(connected_model)
4-element Vector{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}:
 lv₊x(t)
 lv₊y(t)
 sth₊z(t)
 sth₊x(t)
unknowns(connected)
3-element Vector{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}:
 sth₊z(t)
 lv₊y(t)
 lv₊x(t)

I’d appreciate any help regarding this issue. Thanks!

Open an issue for this.

Hi Chris, I created the issue. Thanks for the reply!

I’m hopeful that this document might help you work around the issue. It also details more about why it’s happening.

Thank you very much for the detailed reply! I read the document and am currently implementing the work around.

The solution works and I could make the example run. However, when translating the MRE to a more complex problem I observed slightly deviating solutions when setting tau = 0 (SDDE with t = 0 vs. SDE solution). I employ the same random seed and the deviations are marginal, however, is that something which is expected?

Yes: it’s expected, because seed doesn’t give you the same Brownian path across an SDE and an SDDE (they build their noise processes independently), so compare deterministically with the brownians dropped instead, where τ=0 matches the ODE to 1e-9.

Great. Thank you for your help!