How to Create Global Parameters in ModelingToolkit.jl

Is it possible to create global parameters? For example, when modeling a gas or fluid, it would be convenient to define them globally, similar to how is done in SimScape with a domain definition.

I attempted to create an ODESystem with my fluid parameters and then pass this named system to other systems that rely on the fluid properties. This works, but my “fluid” ODESystem then becomes a subsystem of each component ODESystem, and now if I want to change density (i.e. fluid.rho_0), I need to set it in many places.

For example, if I look at the parameters of my system sys, then fluid is defined multiple times…

julia> parameters(sys)
12-element Vector{Any}:
 i4sim₊f₊vSA₊fluid₊rho_0
 i4sim₊f₊vSA₊fluid₊bulk
 i4sim₊f₊vBR₊fluid₊rho_0
 i4sim₊f₊vBR₊fluid₊bulk
 i4sim₊piston₊v1₊fluid₊rho_0
 i4sim₊piston₊v1₊fluid₊bulk
 i4sim₊piston₊v2₊fluid₊rho_0
 i4sim₊piston₊v2₊fluid₊bulk
 i4sim₊piston₊m₊g
 i4sim₊piston₊m₊m
 i4sim₊p_s₊p_source
 i4sim₊p_r₊p_source

Is there a way to define a global parameter that doesn’t need to be added as a sub-system or parameter to each ODESystem component?

2 Likes

Hello.

Have you tried to define rho as a variable in your subsytems and then define a connection between them to propagate the parameters ?

This would allow you to set rho_0 only in one source subsystem.
For example :

function SourceFluid(;name, rho_0 = 1.0)
    val = rho_0
    @named p = Pin()
    @parameters rho_0
    @variables rho 
    eqs = [
           0 ~ rho - rho_0
           0 ~ p.rho - rho
          ]
    ODESystem(eqs, t, [rho], [rho_0], systems=[p], defaults=Dict(rho_0 => val, rho => rho_0), name=name)
end

function vSA(;name)
    @named p = Pin()
    @named n = Pin()
    @variables rho bulk
    eqs = [
           0 ~ p.rho - rho
           0 ~ n.rho - rho
           0 ~ bulk - ...
          ]
    ODESystem(eqs, t, [rho, bulk], [], systems=[p, n], defaults=Dict(rho => rho), name=name)
end

It is an adaptation of the example in the doc

There’s also the GlobalScope feature that was recently added. No docs, yet, but see the discussion here.

3 Likes

Thanks for this tip. I gave GlobalScope() a try, and technically it works well, but I can see a duplication of the global parameter in parent components. For example, the following code produces comp with 2 parameters named rho

using ModelingToolkit

@variables t
@variables p(t)
@parameters rho
D = Differential(t)

rho = GlobalScope(rho)

fluid(;name) = ODESystem(Equation[], t, [p], [rho], defaults=[rho=>1000, p=>0], name=name)

@named A = fluid()
@named B = fluid()

eqs = [
    D(B.p) ~ A.p
    0 ~ (A.p) - (A.rho)
]

@named comp = ODESystem(eqs, t, [], [], systems=[A, B])

Here is the result for comp

julia> comp
Model comp with 2 equations
States (2):
  A₊p(t) [defaults to 0]
  B₊p(t) [defaults to 0]
Parameters (2):
  rho [defaults to 1000]
  rho [defaults to 1000]

The solution works well, if I run the model, it does seem to set rho globally

ps = [
    rho=>900
]
prob = ODEProblem(comp, [], (0,0.1), ps)
solve(prob, ImplicitEuler())

With result…

retcode: Success
Interpolation: 3rd order Hermite
t: 9-element Vector{Float64}:
 0.0
 1.0e-6
 1.2e-6
 3.2e-6
 2.3199999999999998e-5
 0.00022319999999999998
 0.0022231999999999994
 0.02222319999999999
 0.1
u: 9-element Vector{Vector{Float64}}:
 [900.0, 0.0]
 [900.0, 0.0009]
 [900.0, 0.00108]
 [900.0, 0.0028799999999999997]
 [900.0, 0.02088]
 [900.0, 0.20088]
 [900.0, 2.0008799999999995]
 [900.0, 20.00087999999999]
 [900.0, 90.0]

Open an issue.