I am trying to build a hierarchical model of groups of Lorenz oscillators. I am following the tutorial, but instead of solving the pair of coupled oscillators, I’d like to solve a set of many pairs of coupled oscillators, i.e. use the connected system as a component in the next level system.
I am having trouble figuring out how to assemble the pairs into an ODESystem.
# I am following the tutorial https://mtk.sciml.ai/stable/tutorials/ode_modeling/
using ModelingToolkit
@parameters t σ ρ β
@variables x(t) y(t) z(t)
@derivatives D'~t
eqs = [D(x) ~ σ*(y-x),
D(y) ~ x*(ρ-z)-y,
D(z) ~ x*y - β*z]
lorenz1 = ODESystem(eqs,name=:lorenz1)
lorenz2 = ODESystem(eqs,name=:lorenz2)
@variables a(t)
@parameters γ
connections = [0 ~ lorenz1.x + lorenz2.y + a*γ]
# Now deviate from tutorial by introducing a 2nd level of connected blocks
# Other issue: How does scoping work? Is it ok to re-use components named lorenz1 and lorenz2, or will the hierarchy be flattened eventually
# connected1 and 2 are pairs of Lorenz oscillators. I'd like to solve multiple pairs together.
connected1 = ODESystem(connections,t,[a],[γ],systems=[lorenz1,lorenz2], name=:connected1)
connected2 = ODESystem(connections,t,[a],[γ],systems=[lorenz1,lorenz2], name=:connected2)
connections2ndLevel = [] # Pairs are not connected
variables2ndLevel = [] # No extra variables
parameters2ndLevel = [] # No extra parameters
totalSystem = ODESystem(connections2ndLevel,t,variables2ndLevel, parameters2ndLevel, systems = [connected1, connected2], name=:totalSystem)
# This does not work:
ERROR: MethodError: no method matching ODESystem(::Array{Any,1}, ::Operation, ::Array{Any,1}, ::Array{Any,1}; systems=ODESystem[ODESystem(Equation[Equation(ModelingToolkit.Constant(0), (lorenz1₊x(t) + lorenz2₊y(t)) + a(t) * γ)], t, Variable[a], Variable[γ], Variable[], Equation[], Base.RefValue{Array{Expression,1}}(Expression[]), Base.RefValue{Any}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), :connected1, ODESystem[ODESystem(Equation[Equation(derivative(x(t), t), σ * (y(t) - x(t))), Equation(derivative(y(t), t), x(t) * (ρ - z(t)) - y(t)), Equation(derivative(z(t), t), x(t) * y(t) - β * z(t))], t, Variable[x, y, z], Variable[β, σ, ρ], Variable[], Equation[], Base.RefValue{Array{Expression,1}}(Expression[]), Base.RefValue{Any}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), :lorenz1, ODESystem[]), ODESystem(Equation[Equation(derivative(x(t), t), σ * (y(t) - x(t))), Equation(derivative(y(t), t), x(t) * (ρ - z(t)) - y(t)), Equation(derivative(z(t), t), x(t) * y(t) - β * z(t))], t, Variable[x, y, z], Variable[β, σ, ρ], Variable[], Equation[], Base.RefValue{Array{Expression,1}}(Expression[]), Base.RefValue{Any}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), :lorenz2, ODESystem[])]), ODESystem(Equation[Equation(ModelingToolkit.Constant(0), (lorenz1₊x(t) + lorenz2₊y(t)) + a(t) * γ)], t, Variable[a], Variable[γ], Variable[], Equation[], Base.RefValue{Array{Expression,1}}(Expression[]), Base.RefValue{Any}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), :connected2, ODESystem[ODESystem(Equation[Equation(derivative(x(t), t), σ * (y(t) - x(t))), Equation(derivative(y(t), t), x(t) * (ρ - z(t)) - y(t)), Equation(derivative(z(t), t), x(t) * y(t) - β * z(t))], t, Variable[x, y, z], Variable[β, σ, ρ], Variable[], Equation[], Base.RefValue{Array{Expression,1}}(Expression[]), Base.RefValue{Any}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), :lorenz1, ODESystem[]), ODESystem(Equation[Equation(derivative(x(t), t), σ * (y(t) - x(t))), Equation(derivative(y(t), t), x(t) * (ρ - z(t)) - y(t)), Equation(derivative(z(t), t), x(t) * y(t) - β * z(t))], t, Variable[x, y, z], Variable[β, σ, ρ], Variable[], Equation[], Base.RefValue{Array{Expression,1}}(Expression[]), Base.RefValue{Any}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), Base.RefValue{Array{Expression,2}}(Array{Expression}(undef,0,0)), :lorenz2, ODESystem[])])], name=:totalSystem)
...
How do I re-use the oscillator pairs as further components?
How does scoping work? Do all of the components eventually form a hierarchical namespace, or are all components flattened? In this case I would need to give each pair an individual name.
# I couldn't address individual components either:
connections2ndLevel = [0 ~ connected1.lorenz1.x + connected2.lorenz1.x]
ERROR: MethodError: no method matching ODESystem(::Array{Equation,1}, ::Variable{ModelingToolkit.Parameter{Number}}, ::Array{Variable,1}, ::Array{Variable,1}, ::Base.RefValue{Array{Expression,1}}, ::Base.RefValue{Any}, ::Base.RefValue{Array{Expression,2}}, ::Base.RefValue{Array{Expression,2}}, ::Symbol, ::Array{ODESystem,1})