Modelica® Language Specification version 3.7-dev

Chapter 13 Packages

Packages in Modelica may contain definitions of constants and classes including all kinds of specialized classes, functions, and subpackages. By the term subpackage we mean that the package is declared inside another package, no inheritance relationship is implied. Parameters and variables cannot be declared in a package. The definitions in a package should typically be related in some way, which is the main reason they are placed in a particular package. Packages are useful for a number of reasons:

  • Definitions that are related to some particular topic are typically grouped into a package. This makes those definitions easier to find and the code more understandable.

  • Packages provide encapsulation and coarse-grained structuring that reduces the complexity of large systems. An important example is the use of packages for construction of (hierarchical) class libraries.

  • Name conflicts between definitions in different packages are eliminated since the package name is implicitly prefixed to names of definitions declared in a package.

  • Information hiding and encapsulation can be supported to some extent by declaring protected classes, types, and other definitions that are available only inside the package and therefore inaccessible to outside code.

  • Modelica defines a method for locating a package by providing a standard mapping of package names to storage places, typically file or directory locations in the file system.

13.1 Package as Specialized Class

The package concept is a specialized class (section 4.7), using the keyword package.

13.2 Importing Definitions from a Package

The import-clause makes public classes and other public definitions declared in some package available for use by shorter names in a class or a package. It is the only way of referring to definitions declared in some other package for use inside an encapsulated package or class.

[The import-clauses in a package or class fill the following two needs:

  • Making definitions from other packages available for use (by shorter names) in a package or class.

  • Explicit declaration of usage dependences on other packages.

]

An import-clause can occur in one of the following syntactic forms:

import 𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛𝑛𝑎𝑚𝑒; (qualified import of top-level definition)

import 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒.𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛𝑛𝑎𝑚𝑒; (qualified import)

import 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒.{𝑑𝑒𝑓1, 𝑑𝑒𝑓2, , 𝑑𝑒𝑓n}; (multiple definition import)

import 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒.*; (unqualified import)

import 𝑠ℎ𝑜𝑟𝑡𝑛𝑎𝑚𝑒 = 𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛𝑛𝑎𝑚𝑒; (renaming import of top-level definition)

import 𝑠ℎ𝑜𝑟𝑡𝑛𝑎𝑚𝑒 = 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒.𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛𝑛𝑎𝑚𝑒; (renaming import)

Here 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒 is the fully qualified name of the imported package including possible dot notation and 𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛𝑛𝑎𝑚𝑒 is the name of an element in a package. The multiple definition import is equivalent to multiple single definition imports with corresponding 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒 and definition names.

13.2.1 Lookup of Imported Names

This section only defines how the imported name is looked up in the import-clause. For lookup in general – including how import-clauses are used – see section 5.3.

Lookup of the name of an imported package or class deviates from the normal lexical lookup. For example, consider A.B.C in the import-clauses import A.B.C;, import D = A.B.C;, or import A.B.C.*;. Here, lookup starts with the lexical lookup of the first part of the name (A) at the top level.

Qualified import-clauses may only refer to packages or elements of packages, i.e., in import A.B.C; or import D = A.B.C;, A.B must be a package. Unqualified import-clauses may only import from packages, i.e., in import A.B.*;, A.B must be a package.

[In import A; the class A can be any class which is an element of the unnamed top-level package.]

[For example, if the package ComplexNumbers would have been declared as a subpackage inside the package Modelica.Math, its fully qualified name would be Modelica.Math.ComplexNumbers. 𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛𝑛𝑎𝑚𝑒 is the simple name without dot notation of a single definition that is imported. A 𝑠ℎ𝑜𝑟𝑡𝑛𝑎𝑚𝑒 is a simple name without dot notation that can be used to refer to the package after import instead of the presumably much longer 𝑝𝑎𝑐𝑘𝑎𝑔𝑒𝑛𝑎𝑚𝑒.

The forms of import are exemplified below assuming that we want to access the addition operation of the hypothetical package Modelica.Math.ComplexNumbers:

import Modelica.Math.ComplexNumbers;       // Accessed by ComplexNumbers.Add
import Modelica.Math.ComplexNumbers.Add;   // Accessed by Add
import Modelica.Math.ComplexNumbers.{Add,Sub}; // Accessed by Add and Sub
import Modelica.Math.ComplexNumbers.*;     // Accessed by Add
import Co = Modelica.Math.ComplexNumbers;  // Accessed by Co.Add

]

13.2.2 Rules for Import-Clauses

The following rules apply to import-clauses:

  • The import-clauses are not inherited.

  • The import-clauses are not named elements of a class or package. This means that import-clauses cannot be changed by modifiers or redeclarations.

  • The order of import-clauses does not matter.

  • One can only import from packages, not from other kinds of classes. Both packages and classes can be imported into, i.e., they may contain import-clauses.

  • An imported package or definition should always be referred to by its fully qualified name in the import-clause.

  • Multiple qualified import-clauses shall not have the same import name (see section 5.3.1).

13.3 The Modelica Library Path – MODELICAPATH

The top-level scope implicitly contains a number of classes stored externally. If a top-level name is not found at global scope, a Modelica translator shall look up additional classes in an ordered list of library roots, called MODELICAPATH.

[The implementation of MODELICAPATH is tool dependent. In order that a user can work in parallel with different Modelica tools, it is advisable to not have this list as environment variable, but as a setting in the respective tool. Since MODELICAPATH is tool dependent, it is not specified in which way the list of library roots is stored. Typically, on a Windows system MODELICAPATH is a string with path names separated by ‘;’ whereas on a Linux system it is a string with path names separated by a ‘:’.]

In addition a tool may define an internal list of libraries, since it is in general not advisable for a program installation to modify global environment variables. The version information for a library (as defined in section 18.8) may also be used during this search to search for a specific version of the library (e.g., if Modelica library version 2.2 is needed and the first directory in MODELICAPATH contain Modelica library version 2.1, whereas the second directory contains Modelica version 2.2, then Modelica library version 2.2 is loaded from the second directory.).

[The first part of the path A.B.C (i.e., A) is located by searching the ordered list of roots in MODELICAPATH. If no root contains A the lookup fails. If A has been found in one of the roots, the rest of the path is located in A; if that fails, the entire lookup fails without searching for A in any of the remaining roots in MODELICAPATH.]

If during lookup a top-level name is not found in the unnamed top-level scope, the search continues in the package hierarchies stored in these directories.

[Example: Figure 13.1 below shows an example MODELICAPATH = C:\library;C:\lib1;C:\lib2, with three directories containing the roots of the package hierarchies Modelica, MyLib, and ComplexNumbers. The first two are represented as the subdirectories C:\library\Modelica and C:\lib1\MyLib, whereas the third is stored as the file C:\lib2\ComplexNumbers.mo.

Roots of package hierarchies, e.g.,

Figure 13.1: Roots of package hierarchies, e.g., Modelica, MyLib, and ComplexNumbers in MODELICAPATH = C:\library;C:\lib1;C:\lib2.

Assume that we want to access the package MyLib.Pack2 in figure 13.1 above, e.g., through an import-clause import MyLib.Pack2;. During lookup we first try to find a package MyLib corresponding to the first part of the name in the import-statement. It is not found in the top-level scope since it has not previously been loaded into the environment.

Since the name was not found in the top-level scope the search continues in the directories in the MODELICAPATH in the specified order. For the search to succeed, there must be a subdirectory MyLib or a file MyLib.mo in one of the directories mentioned in the MODELICAPATH. If there is no such subdirectory or file, the lookup fails. If MyLib is found in one of the directories, the rest of the name, in this case Pack2, is located in MyLib. If that fails, the entire lookup fails without continuing the search in possibly remaining directories.

In this example the name matches the subdirectory named MyLib in the second directory C:\lib1 mentioned in the MODELICAPATH. This subdirectory must have a file package.mo containing a definition of the package MyLib, according to the Modelica rules on how to map a package hierarchy to the file system. The subpackage Pack2 is stored in its own subdirectory or file in the subdirectory MyLib. In this case the search succeeds and the package MyLib.Pack2 is loaded into the environment.]

13.4 File System Mapping of Package/Class

A package/class hierarchy may be represented in the hierarchical structure of the operating system (the file system). For classes with version information see also section 18.8.3. The nature of such an external entity falls into one of the following two groups:

  • Directory in the file system.

  • File in the file system.

Each Modelica file in the file-system is stored in UTF-8 format (defined by The Unicode Consortium; https://unicode.org). A deprecated feature is that the file may start with the UTF-8 encoded BOM (byte order mark; 0xef 0xbb 0xbf); this is treated as white-space in the grammar. Since the use of BOM is deprecated, tools can ignore any BOM when reading, and it is recommended to never write it.

[Tools may also store classes in data-base systems, but that is not standardized.]

13.4.1 Directory Hierarchy Mapping

A directory shall contain a node, the file package.mo. The node shall contain a stored-definition that defines a class A with a name matching the name of the structured entity.

[The node typically contains documentation and graphical information for a package, but may also contain additional elements of the class A.]

A directory may also contain one or more sub-entities (directories or files). The sub-entities are mapped as elements of the class defined by their enclosing structured entity. Two sub-entities shall not define classes with identical names

[Example: If directory A contains the three files package.mo, B.mo and C.mo, the classes defined are A, A.B, and A.C.]

[Example: A directory shall not contain both the sub-directory A and the file A.mo.]

In order to preserve the order of sub-entities it is advisable to create a file package.order where each line contains the name of one class or constant (using its Modelica IDENT form). If a package.order is present when reading a structured entity the classes and constants are added in this order; if the contents does not exactly match the classes and constants in the package, the resulting order is tool specific and a warning may be given. Classes and constants that are stored in package.mo are also present in package.order but their relative order should be identical to the one in package.mo (this ensures that the relative order between classes and constants stored in different ways is preserved).

13.4.2 Single File Mapping

When mapping a package or class-hierarchy to a file (e.g., the file A.mo), that file shall only define a single class A with a name matching the name of the nonstructured entity. In a file hierarchy the files shall have the extension .mo.

A .mo file defining more than one class cannot be part of the mapping to file-structure and it is an error if it is loaded from the MODELICAPATH.

13.4.3 The within Clause

A within-clause has the following syntax:

  within [ packageprefixname ] ";"

A non-top-level entity shall begin with a within-clause which for the class defined in the entity specifies the location in the Modelica class hierarchy. A top-level class may contain a within-clause with no name. For a sub-entity of an enclosing structured entity, the within-clause shall designate the class of the enclosing entity; and this class must exist and must not have been defined using a short class definition.

[Example: The subpackage Rotational declared within Modelica.Mechanics has the fully qualified name Modelica.Mechanics.Rotational, which is formed by concatenating the packageprefixname with the short name of the package. The declaration of Rotational could be given as below:

within Modelica.Mechanics;
package Rotational // Modelica.Mechanics.Rotational
  

]

13.5 External Resources

In order to reference external resources from documentation (such as links and images in html-text) and/or to reference images in the Bitmap annotation (see section 18.6.5.6). Absolute URIs should be used, for example file:/// and the URI scheme modelica:/ which can be used to retrieve resources associated with a package. According to the URI specification scheme names are case-insensitive, but the lower-case form should be used, that is Modelica:/ is allowed but modelica:/ is the recommended form.

The Modelica-scheme has the ability to reference a hierarchical structure of resources associated with packages. The same structure is used for all kind of resource references, independent of use (external file, image in documentation, bitmap in icon layer, and link to external file in the documentation), and regardless of the storage mechanism.

Any Modelica-scheme URI containing a slash after the package-name is interpreted as a reference to a resource. The first segment of the path of the URI is interpreted as a fully qualified package name and the rest of the path of the URI is interpreted as the path (relative to the package) of the resource. Each storage scheme can define its own interpretation of the path (but care should be taken when converting from one storage scheme or when restructuring packages that resource references resolve to the same resource). Any storage scheme should be constrained such that a resource with a given path should be unique for any package name that precedes it. The second segment of the path shall not be the name of a class in the package given by the first segment.

As a deprecated feature the URI may start with modelica:// and use the host-part of the authority as the fully qualified package name. That feature is widely used, but deprecated since host-names are generally case-insensitive.

[Examples of deprecated URIs would be modelica://Modelica/Resources/C.jpg (referring to a resource) and modelica://Modelica.Blocks (referring to a package). These should be rewritten as modelica:/Modelica/Resources/C.jpg and modelica:/Modelica.Blocks.]

When Modelica packages are stored hierarchically in a file-system (i.e., package A in a directory A containing package.mo) the resource modelica:/A/Resources/C.jpg should be stored in the file A/Resources/C.jpg, it is not recommend to use modelica:/A.B/C.jpg for referencing resources; it could be stored in the file A/B/C.jpg – which is counter-intuitive if A.B is stored together with A. When Modelica packages are stored in other formats a similar mapping should be defined, such that a resource with a given path should be unique for any package name that precedes it. The second segment of the path shall not be the name of a class in the package given by the first segment. As above for Modelica 3.2.1/package.mo, i.e., resources starting from Modelica 3.2.1, and modelica:/Modelica.Mechanics/C.jpg is Modelica 3.2.1/Mechanics/C.jpg – regardless of whether Modelica.Mechanics is stored in Modelica 3.2.1/package.mo, Modelica 3.2.1/Mechanics.mo, or Modelica 3.2.1/Mechanics/package.mo.

When mapping a Modelica URI to a file-system path, the file-system path shall end in a directory separator if and only if the URI path ends in the segment separator ‘/’. For example, if modelica:/A/Resources maps to A/Resources, then modelica:/A/Resources/ maps to A/Resources/, and vice versa.

[The use of a trailing segment separator is recommended when the resource is a directory and the file-system path will be prepended to relative file paths within the directory. If possible, use URIs for specific files or specific sub-directories instead of appending relative paths to a generic URI such as modelica:/A/Resources/ as the latter creates a dependency on the entire directory.]

For a Modelica-package stored as a single file, A.mo, the resource modelica:/A/C.jpg refers to a file C.jpg stored in the same directory as A.mo, but using resources in this variant is not recommended since multiple packages will share resources.

In case the name of the class contains quoted identifiers, the single-quote ‘`’ and any reserved characters (‘:’, ‘/’, ‘?’, ‘#’, ‘[’, ‘]’, ‘@’, ‘!’, ‘$’, ‘&’, ‘(’, ‘)’, ‘*’, ‘+’, ‘,’, ‘;’, ‘=’) should be percent-encoded as normal in URIs.

[Example: Consider a top-level package Modelica and a class Mechanics inside it, a reference such as modelica:/Modelica.Mechanics/C.jpg is legal, while modelica:/Modelica/Mechanics/C.jpg is illegal. The references modelica:/Modelica.Mechanics/C.jpg and modelica:/Modelica/C.jpg must also refer to two distinct resources.]

13.6 Multilingual Descriptions

[Descriptive texts in a model or library are usually formulated in English. This section describes how a tool can present the library in another language. Translated Modelica text is provided by external files, so that no modification of the original Modelica text is required.]

The texts in following Modelica constructs should be translated:

  • description strings of component declarations and classes

  • strings in the following annotations:

    • Text.string, Text.textString

    • missingInnerMessage, obsolete, unassignedMessage

    • Dialog.group, Dialog.tab

    • Dialog.loadSelector.caption, Dialog.loadSelector.filter, Dialog.saveSelector.caption, Dialog.saveSelector.filter

    • Documentation.info, Documentation.revisions

    • Figure.title, Figure.caption, Figure.group, Plot.title, Axis.label, Curve.legend

    • mustBeConnected

[None of the translatable constructs can have any impact on simulation results.]

Comments (delimited as well as rest-of-line) are not translated. Only constructs given entirely by one or more concatenated string literals are translated, using nothing but the operator + for concatenation. In order to have parameter values as part of the texts the special substitution syntax is preferable (see section 18.6.5.5 and section 18.2.2.4), and translators need to be aware of these substrings in order to make good translations.

[Example: Consider:

annotation(, Text(string = "1st Frequency: %f1"),
               Text(string = "2nd Frequency: " + String(w2 / (2 * pi))), );

In this example only "1st Frequency: %f1" can be translated; the second Text.string doesn’t consist entirely of concatenated string literals, and is hence completely excluded from translation.]

The files to support translation must be provided along with the library. They must be stored in the resources directory modelica://𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒/Resources/Language/.

Two kind of files in Drepper et al. (2020) format have to be provided:

  1. 1.

    Template file 𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒.pot (Portable Object Template), one file per library which is stored as the resource modelica://𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒/Resources/Language/𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒.pot. It describes all translatable strings in the library, but does not contain any translations. The pattern 𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒 denotes the toplevel class name of the library.

  2. 2.

    One file for each supported language with the name 𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒.𝑙𝑎𝑛𝑔𝑢𝑎𝑔𝑒.po (Portable Object), as the resource modelica://𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒/Resources/Language/𝐿𝑖𝑏𝑟𝑎𝑟𝑦𝑁𝑎𝑚𝑒.𝑙𝑎𝑛𝑔𝑢𝑎𝑔𝑒.po. This file is a copy of the associated template file, but extended with the translations in the specified language. The pattern 𝑙𝑎𝑛𝑔𝑢𝑎𝑔𝑒 stands for the ISO 639-1 language code, e.g., de or sv.

The detailed format of these files is described in Drepper et al. (2020). Use of translation files in other formats (including the binary MO file format) is not standardized in Modelica. For Modelica translations, only the keywords msgctxt, msgid and msgstr are used, meaning that a translation entry looks like this:

#: 𝑓𝑖𝑙𝑒𝑛𝑎𝑚𝑒:𝑙𝑖𝑛𝑒𝑁𝑢𝑚𝑏𝑒𝑟
#, no-c-format
msgctxt 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝐶𝑜𝑛𝑡𝑒𝑥𝑡
msgid 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝐼𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑒𝑟
msgstr 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝑇𝑟𝑎𝑛𝑠𝑙𝑎𝑡𝑖𝑜𝑛

The restriction to a few keywords makes it easier for tools to support the format without relying on the implementation from Drepper et al. (2020).

The use of no-c-format ensures that translation tools will not parse "%class" as the format specifier %c followed by lass.

[In the remainder of this section, several facts about the gettext specification are interleaved non-normatively for easy access to some of the gettext basics. Always refer to the external gettext specification for full detail or in case of doubt.

All text strings are in double quotes and encoded with UTF-8 characters. Comments start with an # and are continued until the end of line. Spaces outside strings are ignored and used as separators.

The files consist of a header and a body. The header is marked with an empty msgid and looks like this:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-15 10:52+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"'

All general terms in the header should be replaced by specific information.

Following the header, there is one translation entry for each string to be translated. It can start with an optional comment describing the location (file name and line number) of the text to translate. Multiple occurences of the same string can be listed here, separated by space.]

The 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝐶𝑜𝑛𝑡𝑒𝑥𝑡 following the keyword msgctxt shall be the full name of the Modelica class (e.g., "Modelica.Blocks.Math.Sin") where the text appears. Short class definitions do not appear here. Texts in such classes belong to the enclosing full class definition.

The text string which shall be translated is used as 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝐼𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑒𝑟 (following the msgid keyword), and shall contain the original string from the Modelica code. Note that if a msgid string is given more than once in the same context, all occurrences are translated with the same (last) translation!

[The 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝑇𝑟𝑎𝑛𝑠𝑙𝑎𝑡𝑖𝑜𝑛 (following the keyword msgstr) is the translation of 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝐼𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑒𝑟 and is typically edited using special tools for translators. In the template file this string is empty by definition. If this is empty in a language specific file the 𝑚𝑒𝑠𝑠𝑎𝑔𝑒𝐼𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑒𝑟 may be used instead.]

[Since in Modelica control sequences also start with a backslash and another backslash is used to use sequences literally or to hide double quotes, no change is required here. But Modelica allows strings to go over more than one line, gettext does not. Therefore, line breaks in Modelica must be encoded with "\n" for gettext.

In order to avoid long lines in the translated strings (following msgid or msgstr), strings may be split into smaller parts given on consecutive lines. E.g., the Modelica description

"A
B\"C" + "D\nE"

evaluates to:

A

B”CD

E

which in the translation entry looks like:

msgid ""
"A\n"
"B\"CD\n"
"E"

]

[Example: Consider a simple sine-source:

within MyPackage.Sources;
model Sine "Sine"
  parameter Frequency f=2 "Frequency";
  RealOutput y=sin(2*pi*f*time); // Relying on imported types
  /* Could add details. Note that this is not translated */
  annotation(Icon(graphics={Text(extent={{0,0},{40,40}},
                        textString="Frequency: %f")}));
end Sine;

The entries for translating this model into Swedish could look like this:

#: MyPackage/Sources/package.mo:10126
#, no-c-format
msgctxt "MyPackage.Sources.Sine"
msgid "Sine"
msgstr "Sinus"
#: MyPackage/Sources/package.mo:10127
#, no-c-format
msgctxt "MyPackage.Sources.Sine"
msgid "Frequency"
msgstr "Frekvens"
#: MyPackage/Sources/package.mo:10131
#, no-c-format
msgctxt "MyPackage.Sources.Sine"
msgid "Frequency: %f"
msgstr "Frekvens: %f"

]

[To support the translation of these strings a number of free and commercial tools exist in context of GNU gettext.]