Modelica技术问询:如何传递基于record接口的记录至函数
在Modelica函数中接收基于partial record的派生记录实例
问题重现
你定义了如下的CrossSections包,其中CrossSection是partial record,派生出Circle和Rectangle两个具体记录:
package CrossSections partial record CrossSection constant String name="Generic"; parameter SI.Area area "cross sectional area"; end CrossSection; record Circle extends CrossSection(name="Circle", final area = (d/2)^2*Modelica.Constants.pi); parameter Modelica.Units.SI.Diameter d "Diameter of the cross section"; end Circle; record Rectangle parameter SI.Length a,b; extends CrossSection(name="Rectangle", final area = a*b); end Rectangle; end CrossSections
尝试编写函数foo接收CrossSection类型输入并根据实例类型分支计算时,出现报错Component 'cs' has partial type 'CrossSection':
function foo input CrossSections.CrossSection cs; output Real o1; algorithm if Modelica.Utilities.Strings.isEqual("Circle", cs.name) then o1 := cs.area*3; elseif Modelica.Utilities.Strings.isEqual("Rectangle", cs.name) then o1 := cs.area*2; else o1 := cs.area*5; end if; return; end foo;
解决方案
Modelica中不能直接将partial record作为函数输入类型,需要通过replaceable input配合constrainedby关键字实现多态记录的传递,以下是两种可行实现方式:
方式1:基于name字段分支(兼容所有Modelica工具)
修改函数输入定义,使用replaceable和constrainedby限定输入为CrossSection的派生具体记录:
function foo replaceable input CrossSections.CrossSection cs constrainedby CrossSections.CrossSection; output Real o1; algorithm if Modelica.Utilities.Strings.isEqual("Circle", cs.name) then o1 := cs.area*3; elseif Modelica.Utilities.Strings.isEqual("Rectangle", cs.name) then o1 := cs.area*2; else o1 := cs.area*5; end if; end foo;
方式2:基于类型判断(更安全,部分工具支持如Dymola)
使用Modelica.Utilities.Types.isInstanceOf函数直接判断实例类型,避免依赖name字段的硬编码:
function foo replaceable input CrossSections.CrossSection cs constrainedby CrossSections.CrossSection; output Real o1; algorithm if Modelica.Utilities.Types.isInstanceOf(cs, CrossSections.Circle) then o1 := cs.area*3; elseif Modelica.Utilities.Types.isInstanceOf(cs, CrossSections.Rectangle) then o1 := cs.area*2; else o1 := cs.area*5; end if; end foo;
调用示例
可以在模型中直接传入派生记录实例调用函数:
model TestFoo CrossSections.Circle circle(d=0.1); CrossSections.Rectangle rect(a=0.2, b=0.3); Real res1, res2; equation res1 = foo(circle); res2 = foo(rect); end TestFoo;
内容的提问来源于stack exchange,提问作者Fabian Bachl
相关产品推荐
相关产品推荐

