# Media properties and component encapsulation in MTK

**URL:** <https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557>\
**Category:** Modelling & Simulations\
**Tags:** modelingtoolkit\
**Created:** [June 30, 2022, 8:59am UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557 "2022-06-30T08:59:44Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [June 30, 2022, 8:59am UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/1 "2022-06-30T08:59:45Z")

</div>

Hi,

Modelica has a `Media` library that captures the properties of various materials. It implements the equations given in IF97 (a version of was apparently implemented in [Julia](https://github.com/hzgzh/XSteam.jl)). It provides e.g. calculation of the Cp, Cv from temperature and pressure.

What’s the best practice to implement something similar in MTK (e.g. as part of a [ThermalFluid library](https://github.com/SciML/ModelingToolkitStandardLibrary.jl/issues/87))?

In particular:

- How do you define the “type” of a component? i.e. I’d like to have a `Medium` “`abstract type`” with properties `Cp`, `Cv`, ‘ρ’ etc. with “concrete” components such as Water and Oil implementing it (sure, I can _document_ what a “Medium” is required to provide, but I’d like MTK to enforce these interfaces)
- IF97 is rather complex, with dozens of parameters, which are of little interest to most using it. We _could_ implement IF97 fully as part of MTK, but using that model would import all those parameters and equations to the system using it. I think it makes sense for sub-systems to be (optionally) “black-boxes”, without all of their “internals” exposed.

DD

---

<div class="post-metadata">

**Author:** ![tred](https://avatars.discourse-cdn.com/v4/letter/t/48db29/32.png) [@tred](https://discourse.julialang.org/u/tred)\
**Post date:** [July 7, 2022, 8:46am UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/2 "2022-07-07T08:46:07Z")

</div>

Hi,

I use [CoolProp](https://github.com/CoolProp/CoolProp.jl) (low level interace) with MTK.  
It requires some interfacing and it has some limitations (it is not thread safe).  
I had to map functions with their derivatives and declare them to work with ForwardDiff.  
I hope that [Clapeyron](https://github.com/ypaul21/Clapeyron.jl) will be able to replace CoolProp sooner or later. I think it would require less interfacing.

The components of the fluid (and the thermodynamic model) are declared when the [MTK component](https://mtk.sciml.ai/dev/tutorials/spring_mass/) are instantiated.

About your second point, the macro `ModelingToolkit.@register` allows to keep functions as black-boxes in the equation system.

---

<div class="post-metadata">

**Author:** ![ehintz3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ehintz3/32/207755_2.png) [@ehintz3](https://discourse.julialang.org/u/ehintz3)\
**Post date:** [March 20, 2024, 12:52pm UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/3 "2024-03-20T12:52:46Z")

</div>

Hi, this is an old thread now, but do you have any more information or an example on how you did this? I now need to do the same thing.

---

<div class="post-metadata">

**Author:** ![Sushrut\_Deshpande](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sushrut_deshpande/32/52754_2.png) [@Sushrut\_Deshpande](https://discourse.julialang.org/u/Sushrut_Deshpande)\
**Post date:** [March 21, 2024, 12:39pm UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/4 "2024-03-21T12:39:58Z")

</div>

I have example with CoolProp. I can provide that if you want.

---

<div class="post-metadata">

**Author:** ![ehintz3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ehintz3/32/207755_2.png) [@ehintz3](https://discourse.julialang.org/u/ehintz3)\
**Post date:** [March 21, 2024, 2:23pm UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/5 "2024-03-21T14:23:46Z")

</div>

Please do! That would be very helpful for me.

---

<div class="post-metadata">

**Author:** ![Bumlebi](https://avatars.discourse-cdn.com/v4/letter/b/ce73a5/32.png) [@Bumlebi](https://discourse.julialang.org/u/Bumlebi)\
**Post date:** [June 23, 2024, 10:12pm UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/6 "2024-06-23T22:12:30Z")

</div>

Would be great if you could share in public. I’m also looking for a solution for this.

---

<div class="post-metadata">

**Author:** ![Sushrut\_Deshpande](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sushrut_deshpande/32/52754_2.png) [@Sushrut\_Deshpande](https://discourse.julialang.org/u/Sushrut_Deshpande)\
**Post date:** [June 24, 2024, 9:36am UTC](https://discourse.julialang.org/t/media-properties-and-component-encapsulation-in-mtk/83557/7 "2024-06-24T09:36:29Z")

</div>

Hello,  
Here is a simple Refrigeration cycle (vapour compression). It is using CoolProp.

```julia
using ModelingToolkit, DifferentialEquations, CoolProp

@variables t
D = Differential(t)
const fluid = "SO2"

PropsSI(out::AbstractString, name1::AbstractString, value1::Real, name2::AbstractString, value2::Real, fluid::AbstractString) = CoolProp.PropsSI(out, name1, value1, name2, value2, fluid)
@register_symbolic PropsSI(out::AbstractString, name1::AbstractString, value1::Real, name2::AbstractString, value2::Real, fluid::AbstractString)

@connector function CoolantPort(;name) 
vars = @variables begin 
    p(t), [input = true]
    h(t)
    mdot(t),[connect =Flow]
end
ODESystem(Equation[], t, vars, [];name=name)
end

function MassSource(;name,source_enthalpy,source_pressure,source_mdot) 
    @named port = CoolantPort()
    para = @parameters begin
        
    end
    vars = @variables begin

     end

    eqs = [
        port.mdot ~ source_mdot 
        port.p ~ source_pressure
        port.h ~ source_enthalpy
    ]
    compose(ODESystem(eqs, t, vars, para;name),port)
end

function compressor_h(πc, h_in, p_in)
    s = PropsSI("S", "H", h_in, "P", p_in, fluid)
    return PropsSI("H", "S", s, "P", πc * p_in, fluid)
end
    @register_symbolic compressor_h(πc, h_in, p_in)

function Compressor(;name,πc) 
    @named inport = CoolantPort()
    @named outport = CoolantPort()
    para = @parameters begin

    end
    vars = @variables begin

     end
   eqs = [ outport.p ~ πc * inport.p
            outport.h ~ compressor_h(πc, inport.h, inport.p)
            outport.mdot ~ inport.mdot
   ]    
   compose(ODESystem(eqs, t, vars, para;name), inport, outport)
end

function Condensor(;name)
    @named inport = CoolantPort()
    @named outport = CoolantPort()
    para = @parameters begin

    end
    vars = @variables begin

     end
   eqs = [ outport.p ~ inport.p
            outport.h ~ PropsSI("H","Q",0,"P",inport.p,fluid)
            outport.mdot ~ inport.mdot
   ]    
   compose(ODESystem(eqs, t, vars, para;name), inport, outport)
end

function ExpansionValve(;name,πc)
    @named inport = CoolantPort()
    @named outport = CoolantPort()
    para = @parameters begin

    end
    vars = @variables begin

     end
   eqs = [ outport.p ~ inport.p/πc
            outport.h ~ inport.h
            outport.mdot ~ inport.mdot
   ]    
   compose(ODESystem(eqs, t, vars, para;name), inport, outport)
end

function Evaporator(;name)
    @named inport = CoolantPort()
    @named outport = CoolantPort()
    para = @parameters begin

    end
    vars = @variables begin
     
     end
   eqs = [  
            outport.p ~ inport.p 
            outport.h ~ PropsSI("H","Q",1,"P",inport.p,fluid)
            outport.mdot ~ inport.mdot
   ]    
   compose(ODESystem(eqs, t, vars, para;name), inport, outport)
end

function MassSink(;name) 
    @named port = CoolantPort()
    para = @parameters begin
        
    end
    vars = @variables begin
        p(t) 
        mdot(t) 
        h(t) 
     end

   eqs = [
        mdot ~ port.mdot
        p ~ port.p
        h ~ port.h
   ]
   compose(ODESystem(eqs, t, vars, para;name),port)
end

start_T = 300
start_p = 101325
start_h = PropsSI("H","T",start_T,"P",start_p,fluid)
mdot = 10 

@named source = MassSource(source_enthalpy = start_h,source_pressure = start_p,source_mdot = mdot)
@named compressor = Compressor(πc = 10.0)
@named condensor = Condensor()
@named expvalve = ExpansionValve(πc = 10.0)
@named evap = Evaporator()
@named sink = MassSink()
#@unpack p,outport = oneport
eqs = [
    connect(source.port,compressor.inport)
    connect(compressor.outport,condensor.inport)
    connect(condensor.outport,expvalve.inport)
    connect(expvalve.outport,evap.inport)
    connect(evap.outport,sink.port)
]
@named model = ODESystem(eqs, t, systems=[source,compressor,condensor,expvalve,evap,sink])
u0 = []
tspan = (0.0, 1.0)
sys = structural_simplify(model)
prob = ODEProblem(sys,u0,tspan)
 sol = solve(prob,saveat = 1.0)

```
