Modelica - 如何最好地调整从库到应用程序代码的导入

Modelica - how to best adapt import from library to application code

我对在可重用库部分和特定应用程序部分中构建 Modelica 代码有疑问。问题涉及介质和依赖于介质的设备,我受到 MSL 流体库中某些结构的启发,但我想制作更小的东西并适应我的需要,但我也可以与之一起成长。

问题是如何方便地使库适应应用程序代码中定义的新媒体。由于不同设备有多种模型,因此自然会有一个部分模型来定义设备应具有的连接器类型,然后只有在需要适配连接器时才对部分模型进行更改。 在我看来,我需要图书馆的三步适应过程,而不是我希望的一步。我在下面有一个详细的例子,可以更清楚地提出问题。

该示例是将液体从一个容器泵送到另一个容器的模型,即我们有一个进料罐、一个泵和一个收获罐。液体介质原本包含两种物质,现在在应用程序中我们要模拟七种物质。

在应用程序代码中,具有七种物质的新介质被声明为包 Medium7。泵、进料和收获罐的库模型的适配分以下三个步骤进行:

  1. 定义连接器 LiquidCon7 作为从库中导入标准连接器 LiquidCon 的扩展,并将介质重新声明为 Medium7
  2. 将部分模型 EquipmentMedium7 定义为标准部分模型 EquipmentMedium 的导入扩展,其中连接器重新声明为 LiquidCon 为 LiquidCon7
  3. 将包 Equipment7 定义为标准包 Equipment 的导入扩展,其中部分模型从 EquipmentMedium 重新声明为 EquipmentMedium7。

首先,现在可以使用 Equipment7 中的设备在为 Medium7 定制的应用程序代码中定义一个系统。 — 我希望我能比上面描述的更直接地进行改编。如果我避免像这里那样在库和应用程序中划分代码,那么从 Medium2 切换到 Medium7 就容易得多,只需更改 LiquidConType 中使用的介质,然后该更改就会传播到整个系统。

当我阅读 Tiller 和 Fritzson 关于这个主题的教科书 material 时,或者当我试图理解 MSL 代码时,我发现了类似的结构,但仍然不是我这里的结构。我还认为,关于如何有效地使库适应新应用程序所要求的接口变化,我的问题不限于媒介,而是更广泛的代码范围。

只需阅读 2008 年的 Tillers 论文 "Patterns and anti-patterns in Modelica" 和第 2.3 节 "Medium Model Pattern" 这里有一个与我的问题相关的讨论,并想想第 649 页的最后几行。

我刚刚意识到我的模型结构破坏了 Modelica 定义,因为您不能从部分模型 EquipmentMedium 扩展 PumpType、FeedtankType 等,因为我需要 EquipmentMedium 是可替换的。请参阅 Modelica def 3.2 rev 2 第 6.2.1 节“传递不可替换”。

我将不胜感激对这个主题的一些评论,或许还有阅读建议。我的玩具问题的替代解决方案也很受欢迎!

谢谢,简·彼得

我不知道如何附加代码文件,但下面我展示了上述应用程序代码。库 DATA_v04 很简单。但请注意,我需要使用部分模型 EquipmentMedium 的扩展来定义模型 PumpType、FeedtankType 等...并且不允许。

    encapsulated package d4_app7 

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

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

        package Medium7
            constant String name = "Seven components"   "Medium name";
            constant Integer nc = 7                     "Number of substances; 
            type Concentration 
                 = Real[nc] (each min=0, each unit="kg/m3")  "Substance conc";
        end Medium7;

    //  ------------------------------------------------------------------------
    //     Adaptation of library DEMO to Medium7  
    //  ------------------------------------------------------------------------

        connector LiquidCon7
            import DEMO_v4.LiquidCon;
            extends LiquidCon(redeclare package medium=Medium7);
        end LiquidCon7;

        partial model EquipmentMedium7
            connector LiquidConType=LiquidCon7;
        end EquipmentMedium7;

        package Equipment7
            import DEMO_v4.Equipment;
            extends Equipment
               (redeclare partial model EquipmentMedium=EquipmentMedium7);           
        end Equipment7;

        import DEMO_v4.Control;

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

        model Test
            LiquidCon7.medium medium;
            Equipment7.PumpType pump;
            Equipment7.FeedtankType feedtank;
            Equipment7.HarvesttankType harvesttank;
            Control.FixValueType Fsp(val=0.2);
        equation
            connect(feedtank.outlet, pump.inlet);
            connect(pump.outlet, harvesttank.inlet);
            connect(Fsp.out, pump.Fsp);
        end Test;

    end d4_app7;

我从 JModelica 和 OpenModelica 支持中得到了一些关于这个问题的输入,以简化库代码对应用程序的适应,我在这里分享它。

原始问题中的代码在 JModelica 和 OpenModelica 中确实有效,但我发现它“笨拙”并且实际上还有一个核心缺陷,OpenModelica 社区的人们已经向我指出了这一点。我使用部分模型 EquipmentMedium 作为包 Equipment 的参数,并在包中从它扩展。从可替换模型扩展在这里提供了太多的灵活性,并在 OpenModelica 2.0-beta 错误中给出(但在早期版本的 OM 中没有)。

在下面库 DEMO_v11.mo 和应用程序代码 d11_app7.mo 的更新代码中,我简化了库的适配并避免从可替换模型扩展。毕竟需要适配的只是连接器LiquidCon,准确的说,只是连接器的中间部分需要适配。所以我使用Medium作为封装Equipment的形参,根据实际的Medium来定义封装内部的connector。然后不同的设备使用这个连接器。因此,这种从参数化连接器“扩展”包中模型的方式被认为是可以接受的,而从参数化模型扩展则不是。

在更新的代码中,我还在 Medium 包中引入了更多信息,并展示了如何将其扩展到新的 Medium - 来自我在这里的另一篇文章。

有关参数化包的灵活性的更多信息,请参阅 Hans Olsson 指出的 Modelica def 6.2.1 和 7.3.1。 Peter Fritzson 的书(2015 年第 2 版)中的第 4.15 节也对此进行了讨论。

图书馆代码DEMO_v11.mo:

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

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

        package Medium2
            replaceable constant String name = "Two components"    "Medium name";
            replaceable constant Integer nc = 2                    "Number of substances";
            replaceable type Concentration = Real[nc]              "Substance conc";
            replaceable constant Real[nc] mw = {10, 20}            "Substance weight";  
            constant Integer A = 1                                 "Substance index";
            constant Integer B = 2                                 "Substance index";   
        end Medium2;

        package Medium3 
            import M2 = DEMO_v11.Medium2;
            extends M2
                (name="Three components"                           "Medium name",
                 nc=3                                              "Number of substances",
                 mw = cat(1,M2.mw,{30})                            "Substance weight",
                 redeclare type Concentration = Real[nc]           "Substance conc");
            constant Integer C = 3                                 "Substance index";   
        end Medium3;

    //  ---------------------------------------------------------------------------------------------
    //     Equipment dependent on the medium  
    //  ---------------------------------------------------------------------------------------------

        package Equipment
            replaceable package Medium
            end Medium;

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

            model PumpType
                LiquidCon inlet, outlet;                                                     
                input RealInput Fsp;
            equation
                inlet.F = Fsp;                                         
                connect(outlet, inlet);                          
            end PumpType;

            model FeedtankType
                LiquidCon outlet;                                  
                constant Integer medium_nc = size(outlet.c,1);
                parameter Real[medium_nc] c_in (each unit="kg/m3") 
                                = {1.0*k for k in 1:medium_nc}     "Feed inlet conc";                        
                parameter Real V_0 (unit="m3") = 100               "Initial feed volume";
                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;
                der(V) = outlet.F;               
            end FeedtankType;

            model HarvesttankType
                LiquidCon inlet;                                   
                constant Integer medium_nc = size(inlet.c,1);
                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] c                                  "Substance conc";
                Real[medium_nc] m 
                      (start=m_0, each fixed=true)                 "Substance mass";
                Real V(start=V_0, fixed=true, unit="m3")           "Harvest liquid volume";
            equation
                for i in 1:medium_nc loop
                    der(m[i]) = inlet.c[i]*inlet.F;
                    c[i] = m[i]/V;
                end for;
                der(V) = inlet.F;               
            end HarvesttankType;
        end Equipment;

    //  ---------------------------------------------------------------------------------------------   
    //     Control 
    //  ---------------------------------------------------------------------------------------------

        package Control
            block FixValueType
                output RealOutput out;
                parameter Real val=0;
            equation
                out = val;
            end FixValueType;
        end Control;

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

    //  package Equipment3 = Equipment(redeclare package Medium=Medium3);   // Just shorter version

        package Equipment3
            import DEMO_v11.Equipment;
            extends Equipment(redeclare package Medium=Medium3);
        end Equipment3;

        model Test
            Equipment3.Medium medium;
            Equipment3.FeedtankType feedtank;
            Equipment3.HarvesttankType harvesttank;
            Equipment3.PumpType pump;
            Control.FixValueType Fsp(val=0.2);
        equation
            connect(feedtank.outlet, pump.inlet);
            connect(pump.outlet, harvesttank.inlet);
            connect(Fsp.out, pump.Fsp);
        end Test;

    end DEMO_v11;

和申请代码d11_app7.mo:

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

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

        package Medium7
            import M2 = DEMO_v11.Medium2;
            extends M2
                (name = "Seven components"                      "Medium name", 
                nc = 7                                          "Number of substances",
                mw = cat(1,M2.mw,{30,40,50,60,70})              "Substance weight",
                redeclare type Concentration = Real[nc]         "Substance conc");
            constant Integer C = 3                              "Substance index";
            constant Integer D = 4                              "Substance index";  
            constant Integer E = 5                              "Substance index";  
            constant Integer F = 6                              "Substance index";  
            constant Integer G = 7                              "Substance index";  
        end Medium7;

    //  ---------------------------------------------------------------------------------------------
    //     Adaptation of library DEMO_v11 to Medium7  
    //  ---------------------------------------------------------------------------------------------

        package Equipment7
            import DEMO_v11.Equipment;
            extends Equipment(redeclare package Medium=Medium7);
        end Equipment7;

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

        import DEMO_v11.Control;

        model Test
            Equipment7.Medium medium;                          // Instance not necessary but helpful for user interface
            Equipment7.PumpType pump;
            Equipment7.FeedtankType feedtank;
            Equipment7.HarvesttankType harvesttank;
            Control.FixValueType Fsp(val=0.2);
        equation
            connect(feedtank.outlet, pump.inlet);
            connect(pump.outlet, harvesttank.inlet);
            connect(Fsp.out, pump.Fsp);
        end Test;

    end d11_app7;