Modelica - 如何最好地调整从库到应用程序代码的导入
Modelica - how to best adapt import from library to application code
我对在可重用库部分和特定应用程序部分中构建 Modelica 代码有疑问。问题涉及介质和依赖于介质的设备,我受到 MSL 流体库中某些结构的启发,但我想制作更小的东西并适应我的需要,但我也可以与之一起成长。
问题是如何方便地使库适应应用程序代码中定义的新媒体。由于不同设备有多种模型,因此自然会有一个部分模型来定义设备应具有的连接器类型,然后只有在需要适配连接器时才对部分模型进行更改。
在我看来,我需要图书馆的三步适应过程,而不是我希望的一步。我在下面有一个详细的例子,可以更清楚地提出问题。
该示例是将液体从一个容器泵送到另一个容器的模型,即我们有一个进料罐、一个泵和一个收获罐。液体介质原本包含两种物质,现在在应用程序中我们要模拟七种物质。
在应用程序代码中,具有七种物质的新介质被声明为包 Medium7。泵、进料和收获罐的库模型的适配分以下三个步骤进行:
- 定义连接器 LiquidCon7 作为从库中导入标准连接器 LiquidCon 的扩展,并将介质重新声明为 Medium7
- 将部分模型 EquipmentMedium7 定义为标准部分模型 EquipmentMedium 的导入扩展,其中连接器重新声明为 LiquidCon 为 LiquidCon7
- 将包 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;
我对在可重用库部分和特定应用程序部分中构建 Modelica 代码有疑问。问题涉及介质和依赖于介质的设备,我受到 MSL 流体库中某些结构的启发,但我想制作更小的东西并适应我的需要,但我也可以与之一起成长。
问题是如何方便地使库适应应用程序代码中定义的新媒体。由于不同设备有多种模型,因此自然会有一个部分模型来定义设备应具有的连接器类型,然后只有在需要适配连接器时才对部分模型进行更改。 在我看来,我需要图书馆的三步适应过程,而不是我希望的一步。我在下面有一个详细的例子,可以更清楚地提出问题。
该示例是将液体从一个容器泵送到另一个容器的模型,即我们有一个进料罐、一个泵和一个收获罐。液体介质原本包含两种物质,现在在应用程序中我们要模拟七种物质。
在应用程序代码中,具有七种物质的新介质被声明为包 Medium7。泵、进料和收获罐的库模型的适配分以下三个步骤进行:
- 定义连接器 LiquidCon7 作为从库中导入标准连接器 LiquidCon 的扩展,并将介质重新声明为 Medium7
- 将部分模型 EquipmentMedium7 定义为标准部分模型 EquipmentMedium 的导入扩展,其中连接器重新声明为 LiquidCon 为 LiquidCon7
- 将包 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;