Modelica:无法使用连接器进行参数传播

Modelica: parameter propagation with connectors not possible

我正在研究用于模拟化学过程的 (Open)Modelica 库。使用商业工具,一种常见的方法是为进料流定义一次混合物配置(例如,有多少以及涉及哪些化学成分,如水、乙醇......),然后通过流将此信息传播到所有随后的单元操作。

遗憾的是,到目前为止我还没有设法使用强大的modelica语言来实现这个功能。理想情况是像这样对“流程”建模:

package StreamTest 
  connector Stream_Port
    parameter String componentlist[:];
    Real T, p;
  end Stream_Port;

  model Feed_model
    parameter String componentlist[:];
    Stream_Port Out(componentlist = componentlist);
    Real T, p;
  equation
    Out.T = T;
    Out.p = p;
  end Feed_model;

  model Tank_model
    parameter String componentlist[:];
    Real T,p;
    Stream_Port In(componentlist = componentlist);
  equation
    In.T = T;
    In.p = p;
  end Tank_model;

  model Process
    Feed_model Feed (componentlist = {"A", "B"});
    Tank_model Tank;
  equation
    connect(Feed.Out, Tank.In);
    Feed.Out.T = 200;
    Feed.Out.p = 1;
  end Process;
end StreamTest;

当然,这个例子被精简到最基本的部分,因为“componentlist”没有做任何事情。在下一步中,“componentlist”将用于计算每个模型中的物理属性,定义分子分数的数组大小等。

传播思路如下:

  1. “componentlist”只在Feed_model的实例中定义一次
  2. “组件列表”设置为等于连接器的“组件列表”Stream_Port。
  3. Feed 和 Tank 已连接,“组件列表”被传输到 Tank 的“In”端口。
  4. 现在是关键点:Tank 从端口“In”获取“componentlist”并将其传播到 Tank 的 componentlist。 componentlist 比在罐内用于物理特性和阵列大小,也可以通过罐的一些出口端口传播到下一个单元。

不幸的是,这不适用于 Openmodelica,尽管没有语法错误,而且我看不出这种方法不符合语言定义中的任何一点。错误信息是:

[StreamTest: 17:5-17:38]: Failed to deduce dimension 1 of componentlist due to missing binding equation.

当然,我可以为每个单元定义模型“过程”级别的“组件列表”:

model Process
  Feed_model Feed (componentlist = {"A", "B"});
  Tank_model Tank (componentlist = {"A", "B"});
equation
  connect(Feed.Out, Tank.In);
  Feed.Out.T = 200;
  Feed.Out.p = 1;
end Process;

但是我不得不为“流程”中的每个模型实例冗余地执行此操作——不像我想实现更大的流程模型那样优雅...

此行为的原因:参数传播仅在所有模型都被实例化的模型声明部分“向下”工作。当我们连接模型时,参数传播只能用于数组大小 inside 端口定义。它卡在那里:信息没有传输到下一个连接的单元。

知道如何解决这个问题吗?我错过了什么?虽然我对一些类似的商业工具很有经验,但我仍然在 modelica 的学习曲线上......

AFAIK,单独使用 (Open)Modelica 是不可能的,但是一些工具已经修改为具有自动化功能:

Automatic propagation of fluid models through the ports is not directly possible with the Modelica 3.4 specification, but might be supported by the Modelica tool. For example, in Dymola the option Advanced.MediaPropagation=1 can be set to apply automatic propagation of media models in a circuit.

(https://build.openmodelica.org/Documentation/Modelica.Fluid.UsersGuide.ComponentDefinition.FluidConnectors.html)

Dymola 视频对此进行了演示:https://www.modelon.com/propagating-replaceable-medium-automatically/

Modelica 规范问题,如果您希望在 language/reopen 讨论中看到它:https://github.com/modelica/ModelicaSpecification/issues/240

我认为问题是数组大小在编译时并没有在任何地方定义。假设您想要的是避免多次指定分量数 ,您还可以使用 inner/outer mechanism:

package StreamTest
  connector Stream_Port
    parameter String componentlist[:];
    Real T, p;
  end Stream_Port;

  model Feed_model
    outer parameter Integer n_components;
    parameter String componentlist[n_components];
    Stream_Port Out(componentlist = componentlist);
    Real T, p;
  equation
    Out.T = T;
    Out.p = p;
  end Feed_model;

  model Tank_model
    outer parameter Integer n_components;
    parameter String componentlist[n_components];
    Real T,p;
    Stream_Port In(componentlist = componentlist);
  equation
    In.T = T;
    In.p = p;
  end Tank_model;

  model Process
    inner parameter Integer n_components = 3; // only define it once 
    Feed_model Feed (componentlist = {"A", "B", "C"});
    Tank_model Tank;
  equation
    connect(Feed.Out, Tank.In);
    Feed.Out.T = 200;
    Feed.Out.p = 1;
  end Process;
end StreamTest;

在 Modelica 中,媒体模型不通过连接传播(我同意这很合乎逻辑)。相反,它们是通过自上而下的可替换包传播的。正如我所说,我知道通过连接器传播参数更直观。但是连接的语言语义只处理值,不处理类型,并且替换不同抽象媒体模型的能力非常重要,因为在大多数情况下不同的媒体模型不仅仅是参数化(值变化)而是拓扑变化(类型变化)。这就是为什么采用可替换包(类型)机制的原因。

我非常感兴趣地阅读了您的 post 和此处的讨论,我自己也曾为类似的问题而苦苦挣扎。区分 Modelica 中可以表达的内容与 Modelica 标准库的常见用法和风格很重要。

为了举例说明 Michael Tiller 所写的关于媒体模型如何通过可替换包传播的内容,我在下面附上了显示与您的示例有些相似的示例的代码。此处,具有浓度矢量 c 的液体流 F 从 FeedTank 流向 HarvestTank,通过具有驱动流动的压差的管道。还使用了流和流的概念。您可以在 阅读更多关于类似示例的信息。 (注DEMO_v46等同于DEMO_v40更新解决方案DEMO_v42)

我不想使用术语“传播”,而是说 EquipmentLib 使用可更换的媒体包进行了“改编”。 传播意味着一条路径,也许还有一系列变化,而这里整个 EquipmentLib 都在一条语句中进行了调整。

EquipmentLib 包含罐、管道、传感器、泵等组件,其中实际包装“介质”(包括物质数量)称为 EquipmentLib 的形式参数。通过更改库的“medium-parameter”,您可以使所有设备适应您选择的媒体。这就像我眼中的你在实践中的工作方式。例如,如果您需要建立一个处理强酸性溶液的工艺,那么您可以从一开始就选择指定用于处理该溶液的罐、管道、泵等。

 package DEMO_v46

 //  ---------------------------------------------------------------------------------------------
 //     Interfaces  
 //  ---------------------------------------------------------------------------------------------

     import Modelica.Blocks.Interfaces.RealInput;
     import Modelica.Blocks.Interfaces.RealOutput;

     partial package MediumBase
         constant String name                                   "Medium name";
         constant Integer nc = 1                                "Number of substances";
         replaceable type Concentration = Real[nc]              "Substance conc";       
     end MediumBase;

 //  ---------------------------------------------------------------------------------------------
 //     Medium3 specified  
 //  ---------------------------------------------------------------------------------------------

     package Medium3 
         extends MediumBase
             (name="Three component medium",
              nc=3);
         constant Real[nc] mw = {10, 20, 30}                    "Substance weight"; 
         constant Integer A = 1                                 "Substance index";
         constant Integer B = 2                                 "Substance index";
         constant Integer C = 3                                 "Substance index";
     end Medium3;

     record Medium_data
         constant String name = Medium3.name;
         constant Integer nc = Medium3.nc;
         constant Real[nc] mw = Medium3.mw;
         constant Integer A = Medium3.A;
         constant Integer B = Medium3.B;
         constant Integer C = Medium3.C;
     end Medium_data;

 //  ---------------------------------------------------------------------------------------------
 //     Equipment dependent on the medium but written in a general way 
 //  ---------------------------------------------------------------------------------------------

     package EquipmentLib
         replaceable package Medium = MediumBase         // formal parameter Medium for EquipmentLib
             constrainedby MediumBase;

         connector LiquidCon
             Real p                                              "Pressure"; 
             flow Real F (unit="m3/s")                           "Flow rate";
             stream Medium.Concentration c                       "Substance conc";
         end LiquidCon;

         model PipeType
             LiquidCon inlet, outlet; 
             parameter Real area = 1;
         equation
             inlet.F = -outlet.F;
             outlet.F = area^2*(outlet.p - inlet.p);            // Linearized Bernoulli equation
             for i in 1:Medium.nc loop
                 outlet.c[i] = inStream(inlet.c[i]);
                 inlet.c[i] = inStream(outlet.c[i]);
             end for;
         end PipeType;

        model FeedtankType
           LiquidCon outlet;                                  
             parameter Real p = 0.1                              "Pressure"; 
           parameter Real V_0 (unit="m3") = 100                "Initial feed volume";         
             parameter Real[Medium.nc] c_in (each unit="kg/m3") 
                            = {1.0*k for k in 1:Medium.nc}          "Feed inlet conc";                        
           Real V(start=V_0, fixed=true, unit="m3")            "Feed volume";
        equation    
             for i in 1:Medium.nc loop
                 outlet.c[i] = c_in[i];
             end for;
             outlet.p = p;
           der(V) = outlet.F;               
        end FeedtankType;

       model HarvesttankType
          LiquidCon inlet;
             parameter Real p = 0.0                             "Pressure";                     
           parameter Real V_0 (unit="m3") = 1.0               "Initial harvest liquid volume";
             parameter Real[Medium.nc] m_0 
                  (each unit="kg/m3") = zeros(Medium.nc)       "Initial substance mass";
             Real[Medium.nc] m 
                  (start=m_0, each fixed=true)                 "Substance mass";
             Real[Medium.nc] c                                  "Substance conc"; 
           Real V(start=V_0, fixed=true, unit="m3")           "Harvest liquid volume";
        equation
             inlet.p = p;
             inlet.c = c;
           der(V) = inlet.F;
             for i in 1:Medium.nc loop
                 der(m[i]) = actualStream(inlet.c[i])*inlet.F;
                 c[i] = m[i]/V;
             end for;               
        end HarvesttankType;
     end EquipmentLib;
  
 //  ---------------------------------------------------------------------------------------------
 //     Adaptation of package Equipment to Medium3 
 //  ---------------------------------------------------------------------------------------------

     package Equipment
         import DEMO_v46.EquipmentLib;
         extends EquipmentLib(redeclare package Medium=Medium3);
     end Equipment;

 //  ---------------------------------------------------------------------------------------------
 //     Examples of systems 
 //  ---------------------------------------------------------------------------------------------

     model Test
         Medium_data medium;
         Equipment.FeedtankType feedtank;
         Equipment.HarvesttankType harvesttank;
         Equipment.PipeType pipe;
     equation
         connect(feedtank.outlet, pipe.inlet);
         connect(pipe.outlet, harvesttank.inlet);
     end Test;

 end DEMO_v46;