Catalyst.jl icon indicating copy to clipboard operation
Catalyst.jl copied to clipboard

Trouble with interacting components

Open kaandocal opened this issue 3 months ago • 2 comments

Hi all! I'm trying to use Catalyst to model two interacting systems in E. coli: a nutrient sensor and a motor subsystem. The sensor measures nutrient concentrations L and outputs the target motor speed λ. The motor moves depending on λ and measures the nutrient concentration L based on the current position of the cell.

In my case λ is best described as an observable, so I tried

using Catalyst

t = default_t()
@variables L(t) λ(t)

rec = @network_component rec begin 
    @observables begin 
        $λ ~ E / (E + Ep)
    end 

    $(ParentScope(L)), E --> Ep
    1., Ep --> 0
end

mot = @network_component mot begin 
    @equations begin 
        D($(ParentScope(L))) ~ $(ParentScope(λ))
    end 
end 

rn = complete(ReactionSystem(t; name=:rn, systems=[rec, mot]))

u0 = [ rec.E => 0, rec.Ep => 10, L => 5 ]

tmax = 100.

prob = ODEProblem(rn, u0, (0, tmax); structural_simplify=true)

This yields

ERROR: ExtraVariablesSystemException: The system is unbalanced. There are 4 highest order derivative variables and 3 equations.
More variables than equations, here are the potential extra variable(s):
 rec₊E(t)
 rec₊Ep(t)
 L(t)
 λ(t)
Note that the process of determining extra variables is a best-effort heuristic. The true extra variables are dependent on the model and may not be in this list.

This is despite the system being well-defined (it can be written as an ODE in terms of E, Ep and L only. I am not sure how to eliminate λ. I'm not quite sure why structural_simplify is needed either, I guess this has to do with dependency resolution? Doing that manually (ouch) as follows:

mot = @network_component mot begin 
    @equations begin 
        D($L) ~ $(rec.E) / ($(rec.E) + $(rec.Ep))
    end 
end 

yields

ERROR: LoadError: MethodError: no method matching recursive_escape_functions!(::QuoteNode, ::Vector{Union{Expr, Symbol}})
The function `recursive_escape_functions!` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  recursive_escape_functions!(!Matched::Union{Bool, Float64, Int64, Expr, Symbol}, ::Any)
   @ Catalyst ~/.julia/packages/Catalyst/8qDWw/src/dsl.jl:983
  recursive_escape_functions!(!Matched::Union{Bool, Float64, Int64, Expr, Symbol})
   @ Catalyst ~/.julia/packages/Catalyst/8qDWw/src/dsl.jl:983

in expression starting at /home/user/code/mcpop/models/chemotaxis/testall.jl:15
Stacktrace:

(::Catalyst.var"#recursive_escape_functions!##0#recursive_escape_functions!##1"{Expr, Vector{Union{…}}})(i::Int64) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

foreach at [abstractarray.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

recursive_escape_functions!(expr::Expr, syms_skip::Vector{Union{Expr, Symbol}}) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

(::Catalyst.var"#recursive_escape_functions!##0#recursive_escape_functions!##1"{Expr, Vector{Union{…}}})(i::Int64) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

foreach at [abstractarray.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

recursive_escape_functions!(expr::Expr, syms_skip::Vector{Union{Expr, Symbol}}) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

(::Catalyst.var"#recursive_escape_functions!##0#recursive_escape_functions!##1"{Expr, Vector{Union{…}}})(i::Int64) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

foreach at [abstractarray.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

recursive_escape_functions!(expr::Expr, syms_skip::Vector{Union{Expr, Symbol}}) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

escape_equation!(eqexpr::Expr, all_syms::Vector{Union{Expr, Symbol}}) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

#get_rxexprs##2 at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

foreach(f::Catalyst.var"#get_rxexprs##2#get_rxexprs##3"{Vector{Union{Expr, Symbol}}, Expr}, itr::Vector{Expr}) at [abstractarray.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

get_rxexprs(reactions::Vector{Catalyst.DSLReaction}, equations::Vector{Expr}, all_syms::Vector{Union{Expr, Symbol}}) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

make_reaction_system(ex::Expr, name::QuoteNode) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

make_rs_expr(name::QuoteNode, network_expr::Expr; complete::Bool) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

kwcall(::@NamedTuple{complete::Bool}, ::typeof(Catalyst.make_rs_expr), name::QuoteNode, network_expr::Expr) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

var"@network_component"(__source__::LineNumberNode, __module__::Module, name::Symbol, network_expr::Expr) at [dsl.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

eval(m::Module, e::Any) at [boot.jl](vscode-file://vscode-app/opt/vscodium-bin/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

Adding ParentScope at random (I'm not sure how this works) doesn't fix anything. Any advice would be much appreciated!

kaandocal avatar Nov 09 '25 07:11 kaandocal

Thanks for the report. Haven't worked too much with the MTK's componnet-based stuff myself, but will try to look into this.

TorkelE avatar Nov 12 '25 10:11 TorkelE

This error has been mystifying. Depending on the flavour of the system, sometimes replacing @observables by @equation works - I need to look up the exact difference. More weirdly, at one point changing the variable name from lambda to something else fixed the issue. I do not have the exact system where that happened anymore, but I will post it if I find it!

kaandocal avatar Nov 12 '25 11:11 kaandocal