The fundamental structuring unit of modeling in Modelica is the class. Classes provide the structure for objects, also known as instances. Classes can contain equations which provide the basis for the executable code that is used for computation in Modelica. Conventional algorithmic code can also be part of classes. All data objects in Modelica are instantiated from classes, including the basic data types – Real, Integer, String, Boolean – and enumeration types, which are built-in classes or class schemata.
Declarations are the syntactic constructs needed to introduce classes and objects (i.e., components).
Members of a Modelica class can have two levels of visibility: public or protected. The default is public if nothing else is specified.
A protected element, P, in classes and components shall not be accessed via dot notation (e.g., A.P, a.P, a.P, a.b.P, .A.P; but there is no restriction on using P or P.x for a protected element P). They shall not be modified or redeclared except for modifiers applied to protected elements in a base class modification (not inside any component or class) and the modifier on the declaration of the protected element.
All elements defined under the heading protected are regarded as protected. All other elements (i.e., defined under the heading public, without headings or in a separate file) are public (i.e., not protected). Regarding inheritance of protected and public elements, see section 7.1.2.
The name of a declared element shall not have the same name as any other element in its partially flattened enclosing class. However, the internal flattening of a class can in some cases be interpreted as having two elements with the same name; these cases are described in section 5.5, and section 7.3.
Variables and classes can be used before they are declared.
[In fact, declaration order is only significant for:
Functions with more than one input variable called with positional arguments, section 12.4.1.
Functions with more than one output variable, section 12.4.3.
Records that are used as arguments to external functions, section 220.127.116.11.
Enumeration literal order within enumeration types, section 4.8.5.
Component declarations are described in this section.
A component declaration is an element of a class definition that generates a component. A component declaration specifies (1) a component name, i.e., an identifier, (2) the class to be flattened in order to generate the component, and (3) an optional Boolean parameter expression. Generation of the component is suppressed if this parameter expression evaluates to false. A component declaration may be overridden by an element-redeclaration.
A component or variable is an instance (object) generated by a component declaration. Special kinds of components are scalar, array, and attribute.
The formal syntax of a component declaration clause is given by the following syntactic rules:
[The declaration of a component states the type, access, variability, data flow, and other properties of the component. A component-clause, i.e., the whole declaration, contains type prefixes followed by a type-specifier with optional array-subscripts followed by a component-list.
There is no semantic difference between variables declared in a single declaration or in multiple declarations. For example, regard the following single declaration (component-clause) of two matrix variables:
That declaration has the same meaning as the following two declarations together:
The array dimension descriptors may instead be placed after the variable name, giving the two declarations below, with the same meaning as in the previous example:
The following declaration is different, meaning that the variable a is a scalar but B is a matrix as above:
If the type-specifier of the component declaration denotes a built-in type (RealType, IntegerType, etc.), the flattened or instantiated component has the same type.
A class defined with partial in the class-prefixes is called a partial class. Such a class is allowed to be incomplete, and cannot be instantiated in a simulation model; useful, e.g., as a base class.
If the type-specifier of the component does not denote a built-in type, the name of the type is looked up (section 5.3). The found type is flattened with a new environment and the partially flattened enclosing class of the component. It is an error if the type is partial in a simulation model, or if a simulation model itself is partial. The new environment is the result of merging
the modification of enclosing class element-modification with the same name as the component
the modification of the component declaration
in that order.
Array dimensions shall be scalar non-negative parameter expressions of type Integer, a reference to a type (which must an enumeration type or Boolean, see section 4.8.5), or the colon operator denoting that the array dimension is left unspecified (see section 10.1). All variants can also be part of short class definitions.
[Example: Variables with array dimensions:
The rules for components in functions are described in section 12.2.
Conditional declarations of components are described in section 4.4.5.
An environment that defines the value of a component of built-in type is said to define a declaration equation associated with the declared component. These are a subset of the binding equations, see section 8.1. The declaration equation is of the form x = expression defined by a component declaration, where expression must not have higher variability than the declared component x (see section 3.8). Unlike other equations, a declaration equation can be overridden (replaced or removed) by an element modification.
For declarations of vectors and matrices, declaration equations are associated with each element.
Only components of the specialized classes type, record, operator record, and connector, or components of classes inheriting from ExternalObject may have declaration equations. See also the corresponding rule for algorithms, section 18.104.22.168.
A prefix is property of an element of a class definition which can be present or not be present, e.g., final, public, flow.
Type prefixes (that is, flow, stream, discrete, parameter, constant, input, output) shall only be applied for type, record, operator record, and connector components – see also record specialized class, section 4.6. This is further restricted below; some of these combinations of type prefixes and specialized classes are not legal.
An exception is input for components whose type is of the special class function type (these can only be used for function formal parameters and has special semantics, see section 12.4.2), and the input prefix is not applied to the elements of the component and is allowed even if the elements have input or output prefix.
In addition, instances of classes extending from ExternalObject may have type prefixes parameter and constant, and in functions also type prefixes input and output, see section 12.9.7.
Variables declared with the stream type prefix shall be a subtype of Real. This is further restricted in section 15.1.
Variables declared with the input type prefix must not also have the prefix parameter or constant.
The type prefix flow of a component that is not a primitive element (see definition 9.1), is also applied to the elements of the component (this is done after verifying that the type prefixes occurring on elements of the component are correct). Primitive elements with the flow type prefix shall be a subtype of Real or an operator record defining an additive group, see section 9.2.
The type prefixes input and output of a structured component (except as described above) are also applied to the elements of the component (this is done after verifying that the type prefixes occurring on elements of the component are correct).
When any of the type prefixes flow, input and output are applied for a structured component, no element of the component may have any of these type prefixes, nor can they have stream prefix. The corresponding rules for the type prefixes discrete, parameter and constant are described in section 22.214.171.124 for structured components.
[The prefixes flow, stream, input and output could be treated more uniformly above, and instead rely on other rules forbidding combinations. The type prefix stream cannot be applied to structured components. The type prefix flow can be applied to structured components, see section 9.2. Note that there are no specific restrictions if an operator record component has the type prefix flow, since the members of an operator record cannot have any of the prefixes flow, stream, input or output.]
[Example: input can only be used, if none of the elements has a flow, stream, input or output type prefix.]
The prefixes input and output have a slightly different semantic meaning depending on the context where they are used:
In functions, these prefixes define the computational causality of the function body, i.e., given the variables declared as input, the variables declared as output are computed in the function body, see section 12.4.
In simulation models and blocks (i.e., on the top level of a model or block that shall be simulated), these prefixes define the interaction with the environment where the simulation model or block is used. Especially, the input prefix defines that values for such a variable have to be provided from the simulation environment and the output prefix defines that the values of the corresponding variable can be directly utilized in the simulation environment, see the notion of globally balanced in section 4.7.
In component models and blocks, the input prefix defines that a binding equation has to be provided for the corresponding variable when the component is utilized in order to guarantee a locally balanced model (i.e., the number of local equations is identical to the local number of unknowns), see section 4.7.
The output prefix does not have a particular effect in a model or block component and is ignored.
In connectors, prefixes input and output define that the corresponding connectors can only be connected according to block diagram semantics, see section 9.1 (e.g., a connector with an output variable can only be connected to a connector where the corresponding variable is declared as input). There is the restriction that connectors which have at least one variable declared as input must be externally connected, see section 4.7 (in order to get a locally balanced model, where the number of local unknowns is identical to the number of unknown equations). Together with the block diagram semantics rule this means, that such connectors must be connected exactly once externally.
In records, prefixes input and output are not allowed, since otherwise a record could not be, e.g., passed as input argument to a function.
The unexpanded binding equations for parameters and constants in the translated model must be acyclic after flattening; except that cycles are allowed if the cycles disappear when evaluating parameters having annotation Evaluate = true that are not part of the cycle. Thus it is not possible to introduce equations for parameters by cyclic dependencies.
[There is no exception for parameters with fixed = false, despite the fact that such parameters are generally allowed to be initialized from systems of dependent equations. However, a parameter with fixed = false can use an initial equation instead of a binding equation, allowing for cyclic dependencies.]
The prefixes discrete, parameter, constant of a component declaration are called variability prefixes and define in which situation the variable values of a component are initialized (see section 8.5 and section 8.6) and when they are changed during simulation:
A variable vc declared with constant prefix remains constant during simulation, with a value that is unaffected even by the initialization problem. This is called a constant, or constant variable.
A variable vc declared with the parameter prefix has a value determined at initialization, and keeps that value during the entire simulation. Thus it is known and non-changing during transient analysis. This is called a parameter, or parameter variable.
A discrete-time variable vd is a variable that is discrete-valued (that is, not of Real type) or assigned in a when-clause. The discrete prefix may be used to clarify that a variable is discrete-time. It has a vanishing time derivative between events. Note that this is not the same as saying that der(vd)=0 almost everywhere, as the derivative is not even defined at the events. It is not allowed to apply der to discrete-time variables. During transient analysis the variable can only change its value at event instants (see section 8.5).
A continuous-time variable is a Real variable without any prefix that is not assigned in a when-clause. A continuous-time variable vn may have a non-vanishing time derivative (provided der(vn) is allowed this can be expressed as der(vn) <> 0) and may also change its value discontinuously at any time during transient analysis (see section 8.5). It may also contain a combination of these effects. Regarding existence of der(vn), see operator 3.10.
Components declared as constant shall have an associated declaration equation with a constant expression, if the constant is directly in the simulation model, or used in the simulation model. The value of a constant can be modified after it has been given a value, unless the constant is declared final or modified with a final modifier. A constant without an associated declaration equation can be given one by using a modifier.
If a Real variable is declared with the prefix discrete it must in a simulation model be assigned in a when-clause, either by an assignment or an equation. The variable assigned in a when-clause shall not be defined in a sub-component of model or block specialized class. (This is to keep the property of balanced models.)
A Real variable assigned in a when-clause is a discrete-time variable, even though it was not declared with the prefix discrete. A Real variable not assigned in any when-clause and without any type prefix is a continuous-time variable.
The default variability for Integer, String, Boolean, or enumeration variables is discrete-time, and it is not possible to declare continuous-time Integer, String, Boolean, or enumeration variables.
[The restriction that discrete-valued variables (of type Boolean, etc) cannot be declared with continuous-time variability is one of the foundations of the expression variability rules that will ensure that any discrete-valued expression has at most discrete-time variability, see section 3.8.]
The variability of expressions and restrictions on variability for definition equations is given in section 3.8.
[Note that discrete-time expressions include parameter expressions, whereas discrete-time variables do not include parameter variables. The reason can intuitively be explained as follows
When discussing variables we also want to consider them as left-hand-side variables in assignments, and thus a lower variability would be a problem.
When discussing expressions we only consider them as right-hand-side expressions in those assignment, and thus a lower variability can automatically be included; and additionally we have sub-expressions where lower variability is not an issue.
For Real variables we can distinguish two subtly different categories: discrete-time and piecewise constant, where the discrete-time variables are a subset of all piecewise constant variables. The Real variables declared with the prefix discrete is a subset of the discrete-time Real variables. For a Real variable, being discrete-time is equivalent to being assigned in a when-clause. A variable used as argument to pre outside a when-clause must be discrete-time.
Tools may optimize code to only compute and store discrete-time variables at events. Tools may extend that optimization to piece-wise constant variables that only change at events (in the example above xc3). As shown above variables can be piecewise constant, but change at times that are not events (in the example above x4). It is not clear how a tool could detect and optimize the latter case.
A parameter variable is constant during simulation. This prefix gives the library designer the possibility to express that the physical equations in a library are only valid if some of the used components are constant during simulation. The same also holds for discrete-time and constant variables. Additionally, the parameter prefix allows a convenient graphical user interface in an experiment environment, to support quick changes of the most important constants of a compiled model. In combination with an if-equation, a parameter prefix allows removing parts of a model before the symbolic processing of a model takes place in order to avoid variable causalities in the model (similar to #ifdef in C). Class parameters can be sometimes used as an alternative.
A constant variable is similar to a parameter with the difference that constants cannot be changed after translation and usually not changed after they have been given a value. It can be used to represent mathematical constants, e.g.:
There are no continuous-time Boolean, Integer or String variables. In the rare cases they are needed they can be faked by using Real variables, e.g.:
Since off1 is a discrete-time variable, state events are generated such that off1 is only changed at event instants. Variable off2 may change its value during continuous integration. Therefore, u1 is guaranteed to be continuous during continuous integration whereas no such guarantee exists for u2.]
For elements of structured entities with variability prefixes the most restrictive of the variability prefix and the variability of the component wins (using the default variability for the component if there is no variability prefix on the component).
A component declaration can have a condition-attribute: if expression.
The expression must be a Boolean scalar expression, and must be a parameter expression.
[A parameter expression is required since it shall be evaluated at compile time.]
A redeclaration of a component shall not include a condition attribute; and the condition attribute is kept from the original declaration (see section 6.4).
If the Boolean expression is false the component (including its modifier) is removed from the flattened DAE, and connections to/from the component are removed. A component declared with a condition-attribute can only be modified and/or used in connections.
[Adding the component and then removing it ensures that the component is valid.
If a connect equation defines the connection of a non-conditional component c1 with a conditional component c2 and c2 is de-activated, then c1 must still be a declared element.
There are annotations to handle the case where the connector should be connected when activated, see section 18.7.]
Essentially everything in Modelica is a class, from the predefined classes Integer and Real, to large packages such as the Modelica standard library. The description consists of a class definition, a modification environment that modifies the class definition, an optional list of dimension expressions if the class is an array class, and a lexically enclosing class for all classes.
The object generated by a class is called an instance. An instance contains zero or more components (i.e., instances), equations, algorithms, and local classes. An instance has a type (section 6.3).
[Example: A rather typical structure of a Modelica class is shown below. A class with a name, containing a number of declarations followed by a number of equations in an equation section.
The following is the formal syntax of class definitions, including the special variants described in later sections.
An element is part of a class definition, and is one of: class definition, component declaration, or extends-clause. Component declarations and class definitions are called named elements. An element is either inherited from a base class or local.
A class definition of the form
is identical, except that type-specifier (the base-class) may be replaceable and for the lexical scope of modifiers, where the short class definition does not introduce an additional lexical scope for modifiers, to the longer form
An exception to the above is that if the short class definition is declared as encapsulated, then the type-specifier and modifiers follow the rules for encapsulated classes and cannot be looked up in the enclosing scope.
[Example: Demonstrating the difference in scopes:
The type-specifiers .Resistor rely on global name lookup (see 5.3.2), due to the encapsulated restriction.]
A short class definition of the form
where N represents arbitrary array dimensions, conceptually yields an array class
Such an array class has exactly one anonymous component (_); see also section 4.5.2. When a component of such an array class type is flattened, the resulting flattened component type is an array type with the same dimensions as _ and with the optional modifier applied.
[Example: The types of f1 and f2 are identical:
If a short class definition inherits from a partial class the new class definition will be partial, regardless of whether it is declared with the prefix partial or not.
If a short class definition does not specify any specialized class the new class definition will inherit the specialized class (this rule applies iteratively and also for redeclare).
A base-prefix applied in the short-class-definition does not influence its type, but is applied to components declared of this type or types derived from it; see also section 4.5.2.
It is not legal to combine equations, algorithms, components, base classes, or protected elements with an extends from an array class, a class with non-empty base-prefix, a simple type (Real, Boolean, Integer, String and enumeration types), or any class transitively extending from an array class, a class with non-empty base-prefix, or a simple type.
The local class should be statically flattenable with the partially flattened enclosing class of the local class apart from local class components that are partial or outer. The environment is the modification of any enclosing class element modification with the same name as the local class, or an empty environment.
The unflattened local class together with its environment becomes an element of the flattened enclosing class.
[Example: The following example demonstrates parameterization of a local class:
Flattening of class C2 yields a local class Voltage with nominal modifier 1000. The variables v1 and v2 are instances of this local class and thus have a nominal value of 1000.]
Specialized kinds of classes (earlier known as restricted classes) record, type, model, block, package, function and connector have the properties of a general class, apart from restrictions. Moreover, they have additional properties called enhancements. The definitions of the specialized classes are given below (additional restrictions on inheritance are in section 7.1.3):
record – Only public sections are allowed in the definition or in any of its components (i.e., equation, algorithm, initial equation, initial algorithm and protected sections are not allowed). The elements of a record shall not have prefixes input, output, inner, outer, stream, or flow. Enhanced with implicitly available record constructor function, see section 12.6. The components directly declared in a record may only be of specialized class record or type.
type – May only be predefined types, enumerations, array of type, or classes extending from type.
model – The normal modeling class in Modelica.
block – Same as model with the restriction that each public connector component of a block must have prefixes input and/or output for all connector variables.
[The purpose is to model input/output blocks of block diagrams. Due to the restrictions on input and output prefixes, connections between blocks are only possible according to block diagram semantic.]
function – See section 12.2 for restrictions and enhancements of functions. Enhanced to allow the function to contain an external function interface.
[Non-function specialized classes do not have this property.]
connector – Only public sections are allowed in the definition or in any of its components (i.e., equation, algorithm, initial equation, initial algorithm and protected sections are not allowed).
Enhanced to allow connect to components of connector classes. The elements of a connector shall not have prefixes inner, or outer. May only contain components of specialized class connector, record and type.
package – May only contain declarations of classes and constants. Enhanced to allow import of elements of packages. (See also chapter 13 on packages.)
operator record – Similar to record; but operator overloading is possible, and due to this the typing rules are different, see chapter 6. It is not legal to extend from an operator record (or connector inheriting from operator record), except if the new class is an operator record or connector that is declared as a short class definition, whose modifier is either empty or only modify the default attributes for the component elements directly inside the operator record. An operator record can only extend from an operator record. It is not legal to extend from any of its enclosing scopes. (See chapter 14).
operator – May only contain declarations of functions. May only be placed directly in an operator record. (See also chapter 14).
operator function – Shorthand for an operator with exactly one function; same restriction as function class and in addition may only be placed directly in an operator record.
Additionally only components which are of specialized classes record, type, operator record, and connector classes based on any of those can be used as component references in normal expressions and in the left hand side of assignments, subject to normal type compatibility rules. Additionally components of connectors may be arguments of connect-equations, and any component can be used as argument to the ndims and size-functions, or for accessing elements of that component (possibly in combination with array indexing).
[Example: Use of operator:
[In this section restrictions for model and block classes are present, in order that missing or too many equations can be detected and localized by a Modelica translator before using the respective model or block class. A non-trivial case is demonstrated in the following example:
In this case one can argue that both UseCorrelation (adding an acausal equation) and SpecialCorrelation (adding a default to an input) are correct. Still, when combined they lead to a model with too many equations, and it is not possible to determine which model is incorrect without strict rules – as the ones defined here.
In Modelica 2.2, model Broken will work with some models. However, by just redeclaring it to model SpecialCorrelation, an error will occur and it will be very difficult in a larger model to figure out the source of this error.
In Modelica 3.0, model UseCorrelation is no longer allowed and the translator will give an error. In fact, it is guaranteed that a redeclaration cannot lead to an unbalanced model any more.]
The restrictions below apply after flattening – i.e., inherited components are included – possibly modified. The corresponding restrictions on connectors and connections are in section 9.3.
The local number of unknowns of a model or block class is the sum based on the components:
For each declared component of specialized class type (Real, Integer, String, Boolean, enumeration and arrays of those, etc.) or record, or operator record not declared as outer, it is the number of unknown variables inside it (i.e., excluding parameters and constants and counting the elements after expanding all records, operator record, and arrays to a set of scalars of primitive types).
Each declared component of specialized class type or record declared as outer is ignored.
[I.e., all variables inside the component are treated as known.]
For each declared component of specialized class connector component, it is the number of unknown variables inside it (i.e., excluding parameters and constants and counting the elements after expanding all records and arrays to a set of scalars of primitive types).
For each declared component of specialized class block or model, it is the sum of the number of inputs and flow variables in the (top level) public connector components of these components (and counting the elements after expanding all records and arrays to a set of scalars of primitive types).
The local equation size of a model or block class is the sum of the following numbers:
The number of equations defined locally (i.e., not in any model or block component), including binding equations, and equations generated from connect-equations.
[This includes the proper count for when-clauses (see section 8.3.5), and algorithms (see section 11.1), and is also used for the flat Hybrid DAE formulation (see appendix B).]
The number of input and flow variables present in each (top-level) public connector component.
[This represents the number of connection equations that will be provided when the class is used, due to the balancing restrictions for connectors, see section 9.3.1.]
The number of (top-level) public input variables that neither are connectors nor have binding equations.
[I.e., top-level inputs are treated as known variables. This represents the number of binding equations that will be provided when the class is used.]
[To clarify top-level inputs without binding equation (for non-inherited inputs binding equation is identical to declaration equation, but binding equations also include the case where another model extends M and has a modifier on u giving the value):
Here u and u2 are top-level inputs and not connectors. The variable u2 has a binding equation, but u does not have a binding equation. In the equation count, it is assumed that an equation for u is supplied when using the model.]
A model or block class is locally balanced if the local number of unknowns is identical to the local equation size for all legal values of constants and parameters. ∎
[Here, legal values must respect final bindings and min/max-restrictions. A tool shall verify the locally balanced property for the actual values of parameters and constants in the simulation model. It is a quality of implementation for a tool to verify this property in general, due to arrays of (locally) undefined sizes, conditional declarations, for-loops etc.]
Similarly as locally balanced, but including all unknowns and equations from all components. The global number of unknowns is computed by expanding all unknowns (i.e., excluding parameters and constants) into a set of scalars of primitive types. This should match the global equation size defined as:
The number of equations defined (included in any model or block component), including equations generated from connect-equations.
The number of input and flow variables present in each (top-level) public connector component.
The number of (top-level) public input variables that neither are connectors nor have binding equations.
[I.e., top-level inputs are treated as known variables.]
The following restrictions hold:
In a non-partial model or block, all non-connector inputs of model or block components must have binding equations.
[E.g., if the model contains a component, firstOrder (of specialized class model) and firstOrder has input Real u then there must be a binding equation for firstOrder.u. Note that this also applies to components inherited from a partial base-class provided the current class is non-partial.]
A component declared with the inner or outer prefix shall not be of a class having top-level public connectors containing inputs.
In a declaration of a component of a record, connector, or simple type, modifiers can be applied to any element, and these are also considered for the equation count.
If use_support=true, there are two additional equations for support.phi and support.tau via the modifier.]
In a declarations of a component of a model or block class, modifiers shall only contain redeclarations of replaceable elements and binding equations. The binding equations in modifiers for components may in these cases only be for parameters, constants, inputs and variables having a default binding equation. For the latter case of variables having a default binding equation the modifier may not remove the binding equation using break, see section 7.2.7.
Modifiers of base-classes (on extends and short class definitions) shall only contain redeclarations of replaceable elements and binding equations. The binding equations follow the corresponding rules above, as if they were applied to the inherited component.
All non-partial model and block classes must be locally balanced.
[This means that the local number of unknowns equals the local equation size.]
Based on these restrictions, the following strong guarantee can be given:
All simulation models and blocks are globally balanced.
[Therefore the number of unknowns equal to the number of equations of a simulation model or block, provided that every used non-partial model or block class is locally balanced.]
[Example: Example 1:
Model Capacitor is a locally balanced model according to the following analysis:
Locally unknown variables: p.i, p.v, n.i, n.v, u
and 2 equations corresponding to the 2 flow variables p.i and n.i.
These are 5 equations in 5 unknowns (locally balanced model). A more detailed analysis would reveal that this is structurally non-singular, i.e., that the hybrid DAE will not contain a singularity independent of actual values.
If the equation u = p.v - n.v would be missing in the Capacitor model, there would be 4 equations in 5 unknowns and the model would be locally unbalanced and thus simulation models in which this model is used would be usually structurally singular and thus not solvable.
If the equation u = p.v - n.v would be replaced by the equation u = 0 and the equation C*der(u) = p.i would be replaced by the equation C*der(u) = 0, there would be 5 equations in 5 unknowns (locally balanced), but the equations would be singular, regardless of how the equations corresponding to the flow variables are constructed because the information that u is constant is given twice in a slightly different form.]
[Example: Example 2:
Since t is partial we cannot check whether this is a globally balanced model, but we can check that Circuit is locally balanced.
Counting on model Circuit results in the following balance sheet:
Locally unknown variables (8): p.i, p.v, n.i, n.v, and 2 flow variables for t (t.p.i, t.n.i), and 2 flow variables for c (c.p.i, c.n.i).
and 2 equation corresponding to the flow variables p.i, n.i.
In total we have 8 scalar unknowns and 8 scalar equations, i.e., a locally balanced model (and this feature holds for any models used for the replaceable component t).
Some more analysis reveals that this local set of equations and unknowns is structurally non-singular. However, this does not provide any guarantees for the global set of equations, and specific combinations of models that are locally non-singular may lead to a globally singular model.]
[Example: Example 3:
The use of connector here is a special design pattern. The variables p, h, Xi are marked as input to get correct equation count. Since they are connectors they should neither be given binding equations in derived classes nor when using the model. The design pattern is to give textual equations for them (as below); using connect-equations for these connectors would be possible (and would work) but is not part of the design.
This partial model defines that T, d, u can be computed from the medium model, provided p, h, Xi are given. Every medium with one or multiple substances and one or multiple phases, including incompressible media, has the property that T, d, u can be computed from p, h, Xi. A particular medium may have different “independent variables” from which all other intrinsic thermodynamic variables can be recursively computed. For example, a simple air model could be defined as:
The local number of unknowns in model SimpleAir (after flattening) is:
(T, d, u: variables defined in BaseProperties and inherited in SimpleAir), plus
(p, h, Xi: variables inside connectors defined in BaseProperties and inherited in SimpleAir)
resulting in unknowns. The local equation size is:
(equations defined in SimpleAir), plus
(input variables in the connectors inherited from BaseProperties)
Therefore, the model is locally balanced.
The generic medium model BaseProperties is used as a replaceable model in different components, like a dynamic volume or a fixed boundary condition:
The local number of unknowns of DynamicVolume is:
(inside the port connector), plus
(variables U, M and MXi), plus
(the input variables in the connectors of the medium model)
resulting in unknowns; the local equation size is
from the equation section, plus
flow variables in the port connector.
Therefore, DynamicVolume is a locally balanced model.
Note, when the DynamicVolume is used and the Medium model is redeclared to SimpleAir, then a tool will try to select p, T as states, since these variables have StateSelect.prefer in the SimpleAir model (this means that the default states U, M are derived quantities). If this state selection is performed, all intrinsic medium variables are computed from medium.p and medium.T, although p and h are the input arguments to the medium model. This demonstrates that in Modelica input/output does not define the computational causality. Instead, it defines that equations have to be provided here for p, h, Xi, in order that the equation count is correct. The actual computational causality can be different as it is demonstrated with the SimpleAir model.
The number of local variables in FixedBoundary_pTX is:
(inside the port connector), plus
(the input variables in the connectors of the medium model)
resulting in unknowns, while the local equation size is
from the equation section, plus
flow variables in the port connector.
Therefore, FixedBoundary_pTX is a locally balanced model. The predefined boundary variables p and Xi are provided via equations to the input arguments medium.p and medium.Xi, in addition there is an equation for T in the same way – even though T is not an input. Depending on the flow direction, either the specific enthalpy in the port (port.h) or h is used to compute the enthalpy flow rate H_flow. h is provided as binding equation to the medium. With the equation medium.T = T, the specific enthalpy h of the reservoir is indirectly computed via the medium equations. Again, this demonstrates, that an input just defines the number of equations have to be provided, but that it not necessarily defines the computational causality.]
The attributes of the predefined variable types (Real, Integer, Boolean, String) and enumeration types are described below with Modelica syntax although they are predefined. All attributes are predefined and attribute values can only be defined using a modification, such as in Real x(unit = "kg"). Attributes cannot be accessed using dot notation, and are not constrained by equations and algorithm sections.
The value in the definitions of the predefined types represents the value of an expresion of that type. Unlike attributes, the value of a component cannot be referred to by name; both access and modification of the value is made directly on the component.
[Example: Accessing and modifying a variable value, using Real as example of a predefined type:
Note that only the values of x and y are declared to be equal, but not their unit attributes, nor any other attribute of x and y]
It is not possible to combine extends from the predefined types, enumeration types, or this Clock type with other components.
The names Real, Integer, Boolean and String have restrictions similar to keywords, see section 2.3.3.
[Hence, it is possible to define a normal class called Clock in a package and extend from it.]
[It also follows that the only way to declare a subtype of, e.g., Real is to use the extends mechanism.]
The definitions use RealType, IntegerType, BooleanType, StringType, EnumType as mnemonics corresponding to machine representations. These are called the primitive types.
In situations where the start-attribute would apply if provided, but the attribute is not provided, the fallback value shall be used instead. Tools are recommended to give diagnostics when the fallback value is used. The fallback values for variables of the different predefined types are defined below. ∎
The following is the predefined Real type:
The unit and displayUnit attributes may be either the empty string or a string matching unit-expression in chapter 19. The meaning of the empty string depends on the context. For the input and output components of a function, the empty string allows different units to be used in different calls to the function. For a non-function component, the empty string allows the unit (or display unit) to be inferred by the tool.
The nominal attribute is meant to be used for scaling purposes and to define tolerances in relative terms, see section 4.8.6.
The fallback value is the closest value to consistent with the min and max bounds.
[For external functions in C89, RealType maps to double. In the mapping proposed in Annex F of the C99 standard, RealType/double matches the IEC 60559:1989 (ANSI/IEEE 754-1985) double format.]
The following is the predefined Integer type:
The minimal recommended number range for IntegerType is from -2147483648 to +2147483647, corresponding to a two’s-complement 32-bit integer implementation.
The fallback value is the closest value to consistent with the min and max bounds.
The following is the predefined Boolean type:
The fallback value is false.
The following is the predefined String type:
A StringType value (such as or other textual attributes of built-in types) may contain any Unicode data (and nothing else).
The fallback value is "".
A declaration of the form
defines an enumeration type E and the associated enumeration literals of the enum-list. The enumeration literals shall be distinct within the enumeration type. The names of the enumeration literals are defined inside the scope of E. Each enumeration literal in the enum-list has type E.
An optional comment string can be specified with each enumeration literal.
An enumeration type is a simple type and the attributes are defined in section 126.96.36.199. The Boolean type name or an enumeration type name can be used to specify the dimension range for a dimension in an array declaration and to specify the range in a for-loop range expression; see section 188.8.131.52. An element of an enumeration type can be accessed in an expression.
[Uses of elements of enumeration type in expressions include indexing into an array.]
Using enumeration types as expressions:
For each enumeration:
a new simple type is conceptually defined as
The fallback value is the min bound.
[Since the attributes and enumeration literals are on the same level, it is not possible to use the enumeration attribute names (quantity, min, max, start, fixed) as enumeration literals.]
The type conversion function Integer(expression of enumeration type) returns the ordinal number of the enumeration value E.enumvalue, to which the expression is evaluated, where , , for an enumeration type E = enumeration(e1, , en).
String(E.enumvalue) gives the String representation of the enumeration value.
[Example: String(E.Small) gives "Small".]
See also section 3.7.1.
Whenever an enumeration type is defined, a type conversion function with the same name and in the same scope as the enumeration type is implicitly defined. This function can be used in an expression to convert an integer value to the corresponding (as described in section 184.108.40.206) enumeration value.
For an enumeration type named EnumTypeName, the expression EnumTypeName(Integer expression) returns the enumeration value EnumTypeName.e such that Integer(EnumTypeName.e) is equal to the original integer expression.
Attempting to convert an integer argument that does not correspond to a value of the enumeration type is an error.
Converting from Integer to Colors:
An enumeration type defined using enumeration(:) is unspecified and can be used as a replaceable enumeration type that can be freely redeclared to any enumeration type. There can be no enumeration variables declared using enumeration(:) in a simulation model.
The attributes start and fixed define the initial conditions for a variable. fixed = false means an initial guess, i.e., value may be changed by static analyzer. fixed = true means a required value. The resulting consistent set of values for all model variables is used as initial values for the analysis to be performed.
The attribute nominal gives the nominal value for the variable. The user need not set it even though the standard does not define a default value. The lack of default allows the tool to propagate the nominal attribute based on equations, and if there is no value to propagate the tool should use a non-zero value, it may use additional information (e.g., min attribute) to find a suitable value, and as last resort use 1. If unbounded = true it indicates that the state may grow without bound, and the error in absolute terms shall be controlled.
[The nominal value can be used by an analysis tool to determine appropriate tolerances or epsilons, or may be used for scaling. For example, the tolerance for an integrator could be computed as tol * (abs(nominal) + (if x.unbounded then 0 else abs(x))). A default value is not provided in order that in cases such as a = b, where b has a nominal value but not a, the nominal value can be propagated to the other variable).]
The predefined StateSelect enumeration type is the type of the stateSelect attribute of the Real type. It is used to explicitly control state selection.
See section 12.9.7 for information about the predefined type ExternalObject.
The predefined AssertionLevel enumeration type is used together with assert, section 8.3.7.
The package Connections is used for over-constrained connection graphs, section 8.3.9.
A number of “predefined” record types and enumeration types for graphical annotations are described in chapter 18. These types are not predefined in the usual sense since they cannot be referenced in ordinary Modelica code, only within annotations.
See section 16.2.1 and section 16.3.