包的定义

基本语法

正如我们在本章所了解的一样,package是一种允许我们对定义进行组织(包含其它包的定义)的Modelica实体。package的语法定义与其它Modelica定义有很多共同点。定义包的一般语法是:

package PackageName "Description of package"
  // A package can contain other definitions or variables with the
  // constant qualifier.
end PackageName;

包定义可用encapsulated限定词作为前缀。我们将在考察的Modelica的查找规则时进行进一步讨论。

如果必要包也可以进行嵌套例如:

package OuterPackage "A package that wraps a nested package"
  // Anything contained in OuterPackage
  package NestedPackage "A nested package"
    // Things defined inside NestedPackage
  end NestedPackage;
end OuterPackage;

实际上,包嵌套十分常见。这使我们能够表达复杂的分类。

文件夹储存

虽然我们将整个Modelica定义库存作为一系列嵌套的包储存在单一的文件内,但至少有两个原因令这种做法不可取。首先,由于文件长度和缩进层次,所得到的文件将相当没有可读性。然后,从版本控制的角度来看,将库分成更小的文件可以帮助避免合并冲突。

储存在单一文件内

Modelica语言源代码可以用数种方法映射到文件系统中。最简单的方法将所有信息存储为一个文件。此类文件会带有.mo后缀。这个文件可能只包含一个模型定义,也可能包含一个内有深层嵌套的包或任何两者之间的内容。

储存为文件夹

正如上述讨论,将一切存储在单个文件内通常不是一个好主意。另一种方法是Modelica语言定义映射到一个目录结构里。要将包储存为一个文件夹,可以通过创建一个与这个包名称相同的的文件夹以达成目的。然后,该目录内必须有一个名为package.mo的文件存储此包内的定义,不过不包括任何嵌套定义 。嵌套定义可以存储为(如上文所述的)单个文件,或者(如在本段中描述般)作为目录形式 。下图试图以可视化形式描述一个文件夹布局的例子:

/RootPackage               # Top-level package stored as a directory
  package.mo               # Indicates this directory is a package
  NestedPackageAsFile.mo   # Definitions stored in one file
  /NestedPackageAsDir      # Nested package stored as a directory
    package.mo             # Indicates this directory is a package

与名为RootPackage的包关联的package.mo文件将有类似如下的形式:

within;
package RootPackage
  // only annotations can be stored in a package.mo
end RootPackage;

这里要注意两点。首先,这里没有本应存在的within子句。这表明该包不在任何其它的包内。再者,NestedPackageAsFileNestedPackageAsDir的定义并没有(也不能)出现。两者必须存储在package.mo文件之外。

同样,与名为NestedPackageAsDir的包关联的package.mo文件如下:

within RootPackage;
package NestedPackageAsDir
  // only annotations can be stored in a package.mo
end NestedPackageAsDir;

再一次,此包没有包含任何定义,只有标注。within子句则略有不同,以反映NestedPackageAsDir属于RootPackage包这一事实。

最后,NestedPackageAsFile.mo文件看起来会是这样的:

within RootPackage;
package NestedPackageAsFile
  // The following can be stored here including:
  //  * constants
  //  * nested definitions
  //  * annotations
end NestedPackageAsFile;

这里的within子句和NestedPackageAsDir的包内的一致。不过,由于我们将本包存为单独的文件,常量、模型、包、函数等的嵌套定义均是允许的。

文件夹内的排序

若所有定义被存储在单个文件内,那么定义出现在文件中出现的顺序就是其在可视化环境(例如包浏览器)内的顺序。但是,若定义被存储在文件系统中,上述隐含的顺序便不存在。出于这个原因,开发者可以在package.mo旁边加入一个可选的package.order文件以指定定义的顺序。该文件不过是包内嵌套的实体名称一行一个地组成的列表。因此,例如我们要为示例包结构加上顺序,那么文件系统将有如下内容:

/RootPackage               # Top-level package stored as a directory
  package.mo               # Indicates this directory is a package
  package.order            # Specifies an ordering for this package
  NestedPackageAsFile.mo   # Definitions stored in one file
  /NestedPackageAsDir      # Nested package stored as a directory
    package.mo             # Indicates this directory is a package
    package.order          # Specifies an ordering for this package

若没有package.order文件,Modelica语言工具很可能会简单地按字母顺序对包的内容进行排序。但如果我们想将RootPackage的内容按字母顺序逆向排序,那么RootPackage文件夹内的package.order文件将如下所示:

NestedPackageAsFile
NestedPackageAsDir

这将告诉Modelica工具NestedPackageAsFile应该排在NestedPackageAsDir之前。

版本

MODELICAPATH

多数Modelica工具允许用户通过指定文件的完整路径,或通过使用文件选择对话框打开文件。但每次查找打开大量文件并不十分有趣。出于这个原因,Modelica规范定义了名为MODELICAPATH的特殊环境变量。用户可以用此变量来帮助工具自动地定位源代码的位置。

MODELICAPATH环境变量包含了应搜索目录的列表。在Windows中,该列表的分隔符为;,而在Unix中则为:。当Modelica编译器遇到一个尚未读取的包时,编译器会从MODELICAPATH环境变量的给定目录里搜索寻找匹配的文件或文件夹。例如,若MODELICAPATH定义如下(假设我们使用Unix惯例):

/home/mtiller/Dir1:/home/mtiller/Dir2

而编译器在寻找一个名为MyLib的包。那么编译器会首先在/home/mtiller/Dir1内寻找名为MyLib.mo的(作为单个文件存储的)包,或者一个名为MyLib且内含package.mo文件的文件夹。如果两者都没有出现,那么编译器会继而在/home/mtiller/Dir1内(对相同的内容)进行查找。

modelica:// URL地址

在许多情况下,我们需要在Modelica包内包含非Modelica文件。这些非Modelica的文件可能包括数据、脚本、图像等。我们将这些非Modelica的文件称为“资源(resource)”。现在,我们已经介绍了Modelica定义是如何映射到文件系统中的。因此,我们可以讨论Modelica的一个非常有用的功能,即利用URL地址来指代资源的位置。

例如,当我们讨论外部函数时,我们引入了数个标注来指定资源的位置。具体而言,IncludeDirectoryLibraryDirectory标注分别指定了Modelica编译器寻找文件和库文件的位置。正如之前简要地提到的一样,上述标注的默认值以modelica:://LibraryName/Resources开始。这样的URL地址允许我们相对于一个给定Modelica定义所在文件系统上的位置 定义资源的位置。让我们重新考虑前述的目录结构,不过这次我们增加了一些资源文件:

/RootPackage               # Top-level package stored as a directory
  package.mo               # Indicates this directory is a package
  package.order            # Specifies an ordering for this package
  NestedPackageAsFile.mo   # Definitions stored in one file
  /NestedPackageAsDir      # Nested package stored as a directory
    package.mo             # Indicates this directory is a package
    package.order          # Specifies an ordering for this package
    datafile.mat           # Data specific to this package
  /Resources               # Resources are stored here by convention
    logo.jpg               # An image file

如果我们有模型需要包含在NestedPackageAsDir内的数据文件,我们可以使用下面的URL来引用这个文件:

modelica://RootPackage/NestedPackageAsDir/datafile.mat

这样的URL地址以modelica://开始。这表示我们所引用的资源相对于一个Modelica模型所在的位置。请不要将其错误理解为,例如说,一个通过网络获取的文件。在//后面接着是Modelica定义的完全限定名,唯一的不同只是组件之间是由一个.分隔开的,而是用/。Modelica编译器会将其解释为包含该定义的文件夹名称。最后,URL的最末元素确定要使用文件的名称。

在另一个例子里,如果要引用Resources包中的logo.jpg文件,我们会使用如下URL:

modelica://RootPackage/Resources/logo.jpg

对于模型库的相关文件,常用惯例是将其存储在名为Resources的子包内(因此IncludeDirectoryLibraryDirectory有上述默认值)。