组织内容

让我们先来简单地演示如何将内容组织成包。要做到这一点,我们将重温经典猎食者猎物系统模型。在我们前述的模型中,所有的变量类型均是Real。让我们来优化模型中一系列不同量的类型。

我们可以将这些类型组织成如下的包:

  package Types
    type Rabbits = Real(quantity="Rabbits", min=0);
    type Wolves = Real(quantity="Wolves", min=0);
    type RabbitReproduction = Real(quantity="Rabbit Reproduction", min=0);
    type RabbitFatalities = Real(quantity="Rabbit Fatalities", min=0);
    type WolfReproduction = Real(quantity="Wolf Reproduction", min=0);
    type WolfFatalities = Real(quantity="Wolf Fatalities", min=0);
  end Types;

对于这段Modelica代码,需要注意的第一件事情是,它使用了package关键字。定义package的语法与定义modelfunction的语法非常相似。而它们的主要区别在于package内仅包含定义或常量。package定义除了constant量外不能包含任何变量声明。在本例,我们看到这个package只包含type的定义。

现在,让我们把注意力转向Lotka-Volterra模型本身。假设此模型自身不需要定义类型,而去依赖于我们刚才定义的类型,模型可以被重构如下:

  model LotkaVolterra "Lotka-Volterra with types"
    parameter Types.RabbitReproduction alpha=0.1;
    parameter Types.RabbitFatalities beta=0.02;
    parameter Types.WolfReproduction gamma=0.4;
    parameter Types.WolfFatalities delta=0.02;
    parameter Types.Rabbits x0=10;
    parameter Types.Wolves y0=10;
    Types.Rabbits x(start=x0);
    Types.Wolves y(start=y0);
  equation
    der(x) = x*(alpha-beta*y);
    der(y) = -y*(gamma-delta*x);
  end LotkaVolterra;

请注意,现在所有的参数和变量如何得到一个特定类型(而不仅仅是普通的Real类型)。相反,我们能够将变量和附加信息相关联,而不局限于其为连续变量这一事实。例如,通过在类型定义加入min=0这一修饰符,我们可以规定变量非负。

仅通过观察Lotka-Volterra模型,我们很难发现模型在哪里找到上述的类型定义。Modelica编译器会使用一系列查找规则来查找上述定义。在后面我们将会介绍查找规则。就目前而言重要的一点是,我们有引用模型外数据的能力。

让我们稍稍离开目前的主题,去看看关于组织的一些额外细节。前述的Types包以及对其进行引用的LotkaVolterra模型均是一个称为NestedPackages的包的一部分。NestedPackages的定义如下:

within ModelicaByExample.PackageExamples;
package NestedPackages
  "An example of how packages can be used to organize things"
  package Types
    type Rabbits = Real(quantity="Rabbits", min=0);
    type Wolves = Real(quantity="Wolves", min=0);
    type RabbitReproduction = Real(quantity="Rabbit Reproduction", min=0);
    type RabbitFatalities = Real(quantity="Rabbit Fatalities", min=0);
    type WolfReproduction = Real(quantity="Wolf Reproduction", min=0);
    type WolfFatalities = Real(quantity="Wolf Fatalities", min=0);
  end Types;

  model LotkaVolterra "Lotka-Volterra with types"
    parameter Types.RabbitReproduction alpha=0.1;
    parameter Types.RabbitFatalities beta=0.02;
    parameter Types.WolfReproduction gamma=0.4;
    parameter Types.WolfFatalities delta=0.02;
    parameter Types.Rabbits x0=10;
    parameter Types.Wolves y0=10;
    Types.Rabbits x(start=x0);
    Types.Wolves y(start=y0);
  equation
    der(x) = x*(alpha-beta*y);
    der(y) = -y*(gamma-delta*x);
  end LotkaVolterra;
end NestedPackages;

需要注意,关于NestedPackages包一个非常重要的点是,它是包含在另一个名为PackageExamples的包内。而PackageExamples则又是一个名为ModelicaByExample的包的一部分。由顶部的within子句我们便可以发现这点:

within ModelicaByExample.PackageExamples;

在这本书至今模拟过的每一个模型均是包含在包内的。而在展示那些例子的源代码时,我们都将首行隐藏了起来。原因是当时我们还没有准备好讨论within子句的作用。但within子句在那些例子中均是存在的。

注意,Types包以及LotkaVolterra模型并没有任何的within子句。原因是由于它们均是直接定义在NestedPackages包内,因而我们知道它们具体在什么包内。那么,为什么这个子句会直接出现在NestedPackages的定义之前呢?这是因为NestedPackages是个独立的文件。换言之,Modelica定义映射到文件和目录时,我们需要明确指定定义之间的关系。我们将在后面讨论的文件、目录和包的定义之间的关系。暂时而言,重要的是了解within子句仅用于指定文件所从属的父包。