SciML / ModelingToolkit.jl

An acausal modeling framework for automatically parallelized scientific machine learning (SciML) in Julia. A computer algebra system for integrated symbolics for physics-informed machine learning and automated transformations of differential equations
https://mtk.sciml.ai/dev/
Other
1.41k stars 204 forks source link

could the @structure_parameters of descendant models the main model calls be assigned simultaneously during @mtkbuild? Add the global variable feature? #2848

Open wang890 opened 2 months ago

wang890 commented 2 months ago

The MTK modeling process seems to be as follows: @structural_parameters determine the model structure. Only after the model structure is determined can a specific ODESystem be obtained, so structural parameters can not be assined by @parameters. The @parameter assignment of ODEsystem is very easy and can be done after @mtkbuild, but structural parameters should be assigned during @mtkbuild.

# for @parameter params, assignment is easy.
u0s = [sys.capacitor.v=>0.0, sys.resistor.i=>0.0]
params = [sys.resistor.alpha=>0.01]
tspan = (0, 20.0)
saveat = 0.1
prob = ODEProblem(sys, u0s, tspan, params)

Is your feature request related to a problem? Please describe.

For the case of a hierarchical ModelingToolkit.model, that is, model A calls B, B calls C, @structural_parameters assignent is a bit difficult. Take the RC system code of Issue #2758 as example, The current solution is as follows.

@mtkmodel Rc begin
    @structural_parameters begin        
        resistorUseHeatPort = false
    end
    @components begin                
        resistor = Resistor(; R=1.0, use_Heat_Port=resistorUseHeatPort)        
        ......(Ignored)
        if resistorUseHeatPort
            fixedTemperature = FixedTemperature(T=400.15)
        end
    end
    @equations begin
        connect.... (Ignored)
        if resistorUseHeatPort
             connect(resistor.conditionalHeatPort.heatPort, fixedTemperature.port)
        end  
    end
end
@mtkmodel Resistor begin   
    @structural_parameters begin        
        use_Heat_Port = false       
    end   
    @extend i,v,p,n = onePort = OnePort()

    # only the last @extend takes effect, so conditionalHeatPort was defined as @components
    @components begin        
         conditionalHeatPort = ConditionalHeatPort(; useHeatPort=use_Heat_Port)
    end
    ...... (Ignored) 
end
@mtkmodel ConditionalHeatPort begin
    @structural_parameters begin        
        useHeatPort = false  # = true, if heatPort is enabled
    end    
    ...... Ignore @parameters  @variables

    @components begin
        heatPort = HeatPort_a()
    end 
    @equations begin
        if useHeatPort     
            ......
        else ...... 
end
# when @mtkbuild using Rc
@mtkbuild sys = Rc(; resistorUseHeatPort=true)

resistorUseHeatPort, use_Heat_Port, useHeatPort are the structural parameter of model Rc, Resistor, ConditionalHeatPort, respectively. In fact, these three structural parameters mean the same thing. In the current MTK version, they cannot use the same variable name, so I need to think about how to name them using different strings.

For this hierarchical model Rc, I must pass the structural_parameters step by step, like Resistor(; use_Heat_Port=resistorUseHeatPort), and ConditionalHeatPort(; useHeatPort=use_Heat_Port) in Resistor again, and then I can bulid ODESystem using @mtkbuild sys = Rc(; resistorUseHeatPort=true)

Describe the solution you’d like

For the @mtkmodel style, not @component function style:

(1) Is there a better way to pass @structural_parameters in hierarchical models? When the main model is instantiated using @mtkbuild, could the structure parameters of its child, grandchild, descendant models it calls be assigned simultaneously? like @mtkbuild sys = Rc(; structural_param=..., child's_structural_param=..., grandchild's__structural_param=...), assigning all stucture parameters of the called descendant models at one time.

In current MTK version, it seems that: the @parameters of child model the main model calls could be assigned by double _ , like @mtkbuild sys = Rc(; resistor__R=100), but it doesn't work for grandchild models and structure parameters, that is, resistor__conditionalHeatPort__T=300 Error, resistor__use_Heat_Port=true Error.

(2) Is it possible to add global variable features? If the structure parameter could be declared as a global variable, resistorUseHeatPort, use_Heat_Port, useHeatPort could use the same name such as use_heat_port, and we don't need to pass the structural parameter step by step, we could do it as follows: @mtkbuild sys = Rc(; use_head_port=true), the use_heat_port value in Resistor() ConditionalHeatPort() is automatically that of use_heat_port in Rc, because use_heat_port is a global variable. ---- other related keywords: protected, private, public, ...

@structural_parameters is useful. Sometimes, we can use the Julia function ifelse(), but sometimes if... else... statement is necessary for the model construction by @mtkmodel.

Thanks a lot for you all @ChrisRackauckas

ChrisRackauckas commented 3 weeks ago

@AayushSabharwal or @ven-k just handled something of the sort?