Domains with callable parameters

Hi folks,
I am currently trying to define Domains with property data functions for the purpose of process simulation in ModelingToolkit.jl. To get started, I took the hydraulic example from the Domains doc page and modified it a bit. Unfortunately, the substance data function for the density does not seem to be passed on. Am I doing something wrong or is this feature simply not supported yet?
Thank you for your insides! :slight_smile:

Here is my code

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

@register_symbolic density_fun(p::Float64, T::Float64, x::Vector{Float64})
density_fun(p, T) = (1 + p / 2.09e9)

@connector function HydraulicPort(; p_int, name)
    pars = @parameters begin
        ρ(p::Float64, T::Float64)::Float64
        β::Float64
        μ::Float64
    end

    vars = @variables begin
        p(t)::Float64 = p_int
        dm(t)::Float64, [connect = Flow]
    end

    ODESystem(Equation[], t, vars, pars; name, defaults = [dm => 0])
end

@connector function HydraulicFluid(;
    density = 997.0,
    bulk_modulus = 2.09e9,
    viscosity = 0.0010016,
    name)

    pars = @parameters begin
        ρ(p::Float64, T::Float64)::Float64 = density_fun
        β::Float64 = bulk_modulus
        μ::Float64 = viscosity
    end

    vars = @variables begin
        dm(t)::Float64, [connect = Flow]
    end

    eqs = [
        dm ~ 0
    ]

    ODESystem(eqs, t, vars, pars; name, defaults = [dm => 0])
end

@component function FixedPressure(; p, name)
    pars = @parameters p = p
    systems = @named begin
        port = HydraulicPort(; p_int = p)
    end

    eqs = [port.p ~ p]

    ODESystem(eqs, t, [], pars; name, systems)
end

@component function FixedVolume(; vol, p_int, name)
    pars = @parameters begin
        p_int = p_int
        vol = vol
    end

    systems = @named begin
        port = HydraulicPort(; p_int)
    end

    vars = @variables begin
        rho(t) = port.ρ(101325.0, 298.15)
        drho(t) = 0
    end

    # let
    dm = port.dm
    p = port.p

    eqs = [D(rho) ~ drho
           rho ~ port.ρ(p, 298.15)
           dm ~ drho * vol]

    ODESystem(eqs, t, vars, pars; name, systems)
end

@component function System(; name)
    systems = @named begin
        src = FixedPressure(; p = 200e5)
        vol = FixedVolume(; vol = 0.1, p_int = 200e5)

        fluid = HydraulicFluid(; density = 876)
    end

    eqs = [connect(fluid, src.port)
           connect(src.port, vol.port)]

    ODESystem(eqs, t, [], []; systems, name)
end

@named odesys = System()

sys = structural_simplify(odesys)

using OrdinaryDiffEq
prob = ODEProblem(sys, [], (0,10))

Here is the error message

ERROR: Some parameters are missing from the variable map.
Please provide a value or default for the following variables:

Any[vol₊port₊ρ⋆, src₊port₊ρ⋆]

Stacktrace: ...

I don’t think it can pass on functions. That can be a feature down the line but right now it cannot do that. If it did, it would have to FunctionWrap it and lots of other tricks, so it’s not trivial. Worth an issue though.

Hi @ChrisRackauckas,
thank you very much for your (as always very fast) response. I just opened an issue.

One more question in this context: How complicated would it be to support forwarding a struct of different functions

struct PropertyPackage
  components::Vector{String}
  density::Function
  enthalpy::Function
  ...
end

by connecting a domain? Actually, I think this would be even more convenient for passing property functions in process simulation than using this special connector type as described in Domains. The fundamental issue is that you will most likely need a new domain for each process simulation model, because the material system is different from case to case. The equipment models including their ports are not dependent on these change though… So, it would be very convenient to just pass the property package.