如何在 Dymola 中找到哪个组件正在使用外部组件?

How to find which component is using outer components in Dymola?

在Modelica模型中,我们经常使用外部组件,比如系统设置和其他公共变量,但是如果我正在阅读一个新模型,有没有什么简单的方法可以让我找到哪个组件正在使用外部组件?
例如,下面的屏幕截图是 Modelica.Fluid.Examples.HeatingSystem,我怎么知道哪个组件正在使用“系统”作为外部组件?
我可以逐行阅读代码,但是有更简单的方法吗?

Dymola 在图形用户界面中不提供此类功能。但是使用 ModelManagement 库可以获得这样的信息。该库可通过标准 Dymola 许可证获得并已预安装。

下面是函数 SO.printComponents(),它使用 ModelManagement 库获取 class 中符合给定条件的所有组件。

对于您的模型,打印输出为:

Components in Modelica.Fluid.Examples.HeatingSystem using Modelica.Fluid.System as outer:
  tank<Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel>.heatTransfer<Modelica.Fluid.Interfaces.PartialHeatTransfer>.system
  tank<Modelica.Fluid.Interfaces.PartialLumpedVolume>.system
  pump<Modelica.Fluid.Machines.BaseClasses.PartialPump>.heatTransfer<Modelica.Fluid.Interfaces.PartialHeatTransfer>.system
  ...
  valve<Modelica.Fluid.Interfaces.PartialTwoPort>.system
  ...

您会看到 Modelica.Fluid.Examples.HeatingSystem 中的所有组件,其中包含 Modelica.Fluid.System 的实例,前缀为 outer。

如果组件通过 extends 从基础 class 继承了系统实例,则基础 class 以 <base-class>.[= 形式在尖括号之间给出。 31=]

例如,输出中的第一个组件意味着,tank 组件正在扩展 PartialLumpedVessel class,其中包含一个组件 heatTransfer,它扩展了 PartialHeatTransfer 其中包含我们要查找的系统实例。

请注意,对于多级继承,只给出了最终基 class,而不是它的完整路径。这是例如与阀门相关,它通过 PartialValvePartialTwoPortTransport.

PartialTwoPort 继承系统实例

背景资料

ModelManagement 库在包 ModelManagement.Structure 中提供了一些有趣的函数,这些函数允许获取有关 Modelica classes 的信息。

函数分为两种不同的类型:

  • ModelManagement.Structure.AST:对于这些函数,只考虑所选 class 的 Modelica 代码。继承的一切都不考虑。
  • ModelManagement.Structure.Instantiated: 这个包中的所有函数都在翻译后的模型上运行

乍一看,ModelManagement.Structure.Instantiated.UsedModels 似乎是个不错的起点。但它的文档说:

Optionally disabled components, base-classes, and called functions are not included.

由于 Fluid 包大量使用了继承,如果不考虑继承,我们很容易错过一个组件。

幸运的是,测试库包含一个函数,returns 所有继承的基础 classes Testing.Utilities.Class.getExtendedClasses。此外 ModelManagement.Structure.AST.ComponentsInClassAttributes 允许我们检索给定 class 的所有组件(但不是继承的组件)。

利用这两个函数,我们可以构建一个新函数:

  • 检索 class 的所有组件,包括从基础 classes
  • 继承的组件
  • 检查组件是否符合我们的搜索条件(在您的情况下它应该是 Modelica.Fluid.System 的外部实例)
  • 递归检查所有组件的子组件,因为系统的使用可能发生在层次结构的更下方

这是代码。此外还包括一个小打印功能,可以将找到的组件很好地打印到终端。

package SO

  function getComponentsUsingClass "Get all components in class c1 which use class c2 as local component"
    import ModelManagement.Structure.AST;
    import Testing.Utilities.Class.getExtendedClasses;
    import Testing.Utilities.Vectors.catStrings;

    input String c1 "Full path of class of which components are retrieved";
    input String c2 "Full path of class which must be used in the components";
    input Boolean isOuter=false "Return only components where c2 is used as an outer instance";
    output String cmp[:] "All components in c1 using c2";
  protected 
    String sub[:] "Sub-components";
    Boolean baseClass "True if current class is a baseClass of c1 (c1 extends it)";
    String prefix "Used to give base classe";
  algorithm 

    cmp :=fill("", 0);

    // loop over class c1 and all its base classes
    for c in cat(1,{c1}, getExtendedClasses(c1)) loop

      baseClass :=c <> c1;
      prefix :=if baseClass then "<" + c + ">." else ".";

      // loop over all components in the current class
      for cmpa in AST.ComponentsInClassAttributes(c) loop

        if cmpa.fullTypeName==c2 and cmpa.isOuter==isOuter then
          cmp :=cat(1, cmp, {prefix+cmpa.name});
        end if;

        // if the current component is a Modelica class, obtain all sub-components using c2
        // (Mon-Modelica classes would e.g. be the attributes min, max, stateSelect etc. of built in classes)
        if cmpa.fullTypeName<>"" then
          sub := getComponentsUsingClass(cmpa.fullTypeName, c2, isOuter);
          sub :=catStrings(fill(prefix+cmpa.name, size(sub, 1)), sub);
          cmp :=cat(1, cmp, sub);
        end if;
      end for;
    end for;
  end getComponentsUsingClass;

  function printComponents
    import Modelica.Utilities.Streams.print;
    import DymolaModels.Utilities.Strings.stripLeft;
    input String c1="Modelica.Fluid.Examples.HeatingSystem" "Full path of class of which components are retrieved";
    input String c2="Modelica.Fluid.System" "Full path of class which must be used in the components";
    input Boolean isOuter=true "Return only components where c2 is used as an outer instance";
  algorithm 

    print("Components in " + c1 + " using " + c2 + (if isOuter then " as outer" else "") + ":");

    for c in getComponentsUsingClass(c1, c2,isOuter) loop
      print("  " + stripLeft(c, "."));
    end for;
  end printComponents;

  annotation (uses(
      Modelica(version="4.0.0"),
      Testing(version="1.3.1"),
      ModelManagement(version="1.2.0"),
      DymolaModels(version="1.2")));
end SO;