Whereas equations are very well suited for physical modeling, there are situations where computations are more conveniently expressed as algorithms, i.e., sequences of statements. In this chapter we describe the algorithmic constructs that are available in Modelica.
Statements are imperative constructs allowed in algorithm sections.
An algorithm section is a part of a class definition comprised of the keyword algorithm followed by a sequence of statements. The formal syntax is as follows:
Like an equation, an algorithm section relates variables, i.e., constrains the values that these variables can take simultaneously. In contrast to an equation section, an algorithm section distinguishes inputs from outputs: An algorithm section specifies how to compute output variables as a function of given input variables. A Modelica tool may actually invert an algorithm section, i.e., compute inputs from given outputs, e.g., by search (generate and test), or by deriving an inverse algorithm symbolically.
Equation equality = or any other kind of equation (see chapter 8) shall not be used in an algorithm section.
See section 8.6 for a description of both initial algorithm sections and initial equation sections.
An algorithm section is conceptually a code fragment that remains together and the statements of an algorithm section are executed in the order of appearance. Whenever an algorithm section is invoked, all variables appearing on the left hand side of the assignment operator := are initialized (at least conceptually):
A continuous-time variable is initialized with the value of its start-attribute.
A discrete-time variable v is initialized with pre(v).
If at least one element of an array appears on the left hand side of the assignment operator, then the complete array is initialized in this algorithm section.
A parameter assigned in an initial algorithm, section 8.6, is initialized with the value of its start-attribute.
[Initialization is performed, in order that an algorithm section cannot introduce a “memory” (except in the case of discrete-time variables assigned in the algorithm), which could invalidate the assumptions of a numerical integration algorithm. Note, a Modelica tool may change the evaluation of an algorithm section, provided the result is identical to the case, as if the above conceptual processing is performed.
An algorithm section is treated as an atomic vector-equation, which is sorted together with all other equations. For the sorting process (BLT), every algorithm section with N different left-hand side variables, is treated as an atomic N-dimensional vector-equation containing all variables appearing in the algorithm section. This guarantees that all N equations end up in an algebraic loop and the statements of the algorithm section remain together.
Example:
The conceptual part indicate that if the variable is assigned unconditionally in the algorithm before it is used the initialization can be omitted. This is usually the case, except for algorithms with when-statements, and especially for initial algorithms.]
See section 12.4.4.
Statements are imperative constructs allowed in algorithm sections. A flattened statement is identical to the corresponding nonflattened statement.
Names in statements are found as follows:
If the name occurs inside an expression: it is first found among the lexically enclosing reduction functions (see section 10.3.4) in order starting from the inner-most, and if not found it proceeds as if it were outside an expression:
Names in a statement are first found among the lexically enclosing for-statements in order starting from the inner-most, and if not found:
Names in a statement shall be found by looking up in the partially flattened enclosing class of the algorithm section.
The syntax of statements is as follows:
The syntax of simple assignment statement is as follows:
The expression is evaluated. The resulting value is stored into the variable denoted by component-reference.
The expression must not have higher variability than the assigned component, see section 3.8.
Assignment to array variables with subscripts is described in section 10.5.
There is a special form of assignment statement that is used only when the right-hand side contains a call to a function with multiple results. The left-hand side contains a parenthesized, comma-separated list of variables receiving the results from the function call. A function with results needs receiving variables on the left-hand side, and the variables are assigned from left to right.
It is possible to omit receiving variables from this list:
[Example: The function f called below has three results and two inputs:
In the second example above x[1] is assigned twice: first with the first output, and then with the third output. For that case the following will give the same result:
]
The syntax of an assignment statement with a call to a function with multiple results is as follows:
[Also see section 8.3.1 regarding calling functions with multiple results within equations.]
Only components of the specialized classes type, record, operator record, and connector may appear as left-hand-side in algorithms. This applies both to simple assignment statements, and the parenthesized, comma-separated list of variables for functions with multiple results.
The syntax of a for-statement is as follows:
A for-statement may optionally use several iterators (for-indices), see section 11.2.2.3 for more information:
The following is an example of a prefix of a for-statement:
The rules for for-statements are the same as for for-expressions in section 8.3.2.1 – except that the expression of a for-statement is not restricted to a parameter-expression.
If the for-statement contains event-generating expressions, any expression in for-index shall be evaluable.
[In general, the same event-generating expression requires distinct crossing functions for different iterations of the for-loop, and the restriction ensures that the number of crossing functions is known during translation time.]
[Example:
The loop-variable may hide other variables as in the following example. Using another name for the loop-variable is, however, strongly recommended.
]
An iterator IDENT in range-expr without the in range-expr requires that the IDENT appears as the subscript of one or several subscripted expressions, where the expressions are not part of an array in a component of an expandable connector. The dimension size of the array expression in the indexed position is used to deduce the range-expr as 1:size(array-expression,indexpos) if the indices are a subtype of Integer, or as E.e1:E.en if the indices are of an enumeration type E = enumeration(e1, , en), or as false:true if the indices are of type Boolean. If it is used to subscript several expressions, their ranges must be identical. There may not be assignments to the entire arrays that are subscripted with IDENT inside the loop, but there may be assignments to individual elements or ranges of elements.
[The size of an array – the iteration range – can be evaluated on entry to the for-loop, since the array size cannot change during the execution of the for-loop.]
The IDENT may also, inside a reduction expression, array constructor expression, for-statement, or for-equation, occur freely outside of subscript positions, but only as a reference to the variable IDENT, and not for deducing ranges. The IDENT may also be used as a subscript for an array in a component of an expandable connector but it is only seen as a reference to the variable IDENT and cannot be used for deducing ranges.
[Example: Implicit iterator ranges for an Integer subscript:
]
[Example: An array dimension’s type of subscript does not matter for array compatibility, only the size of the array dimension matters. This is true also for array constructor expressions with implicit iterator ranges:
]
The iteration range can be specified as Boolean or as an enumeration type. This means iteration over the type from min to max, i.e., for Boolean it is the same as false:true and for an enumeration E it is the same as E.min:E.max. This can be used for for-loops and reduction expressions.
[Example:
]
The notation with several iterators is a shorthand notation for nested for-statements or for-equations (or reduction expressions). For for-statements or for-equations it can be expanded into the usual form by replacing each ‘,’ by “loop for” and adding extra “end for”. For reduction expressions it can be expanded into the usual form by replacing each ‘,’ by “) for” and prepending the reduction expression with “functionName(”.
[Example:
]
The while-statement has the following syntax:
The expression of a while-statement shall be a scalar Boolean expression.
The while-statement corresponds to while-statements in other programming languages, and is formally defined as follows:
The expression of the while-statement is evaluated.
If the expression of the while-statement is false, the execution continues after the while-statement.
If the expression of the while-statement is true, the entire body of the while-statement is executed (except if a break-statement, see section 11.2.4, or a return-statement, see section 11.2.5, is executed), and then execution proceeds at step 1.
Event-generating expressions are neither allowed in the expression nor in the loop body statements. A deprecated feature is that all expressions in a while-statement are implicitly inside noEvent.
The break-statement breaks the execution of the innermost while- or for-loop enclosing the break-statement and continues execution after the while- or for-loop. It can only be used in a while- or for-loop in an algorithm section. It has the following syntax:
[Example: (Note that this could alternatively use return).
]
Can only be used inside functions, see section 12.1.2.
The if-statements have the following syntax:
The expression of an if- or elseif-clause must be scalar Boolean expression. One if-clause, and zero or more elseif-clauses, and an optional else-clause together form a list of branches. One or zero of the bodies of these if-, elseif- and else-clauses is selected, by evaluating the conditions of the if- and elseif-clauses sequentially until a condition that evaluates to true is found. If none of the conditions evaluate to true the body of the else-clause is selected (if an else-clause exists, otherwise no body is selected). In an algorithm section, the selected body is then executed. The bodies that are not selected have no effect on that model evaluation.
A when-statement has the following syntax:
The expression of a when-statement shall be a discrete-time Boolean scalar or vector expression. The statements within a when-statement are activated only at the instant when the scalar or any one of the elements of the vector expression becomes true.
[Example: Algorithms are activated when x becomes > 2:
The statements inside the when-statement are activated on the positive edge of any of the expressions x > 2, sample(0, 2), or x < 5:
For when-statements in algorithm sections the order is significant and it is advisable to have only one assignment within the when-statement and instead use several algorithm sections having when-statements with identical conditions, e.g.:
Merging the when-statements can lead to less efficient code and different models with different behavior depending on the order of the assignment to y1 and y3 in the algorithm.]
A when-statement shall not be used within a function.
A when-statement shall not occur inside an initial algorithm.
A when-statement cannot be nested inside another when-statement.
when-statements shall not occur inside while-loops, for-loops, or if-statements in algorithms.
[Example: The following nested when-statement is invalid:
]
[In contrast to when-equations, section 8.3.5.3, there are no additional restrictions within when-statements:
In algorithms, all assignment statements are already restricted to left-hand-side variables.
If at least one element of an array appears on the left-hand-side of the assignment operator inside a when-statement, it is as if the entire array appears in the left-hand-side according to section 11.1.2. Thus, there is no need to restrict the indices to parameter-expressions.
The for-loops and if-statements are not problematic inside when-statements in algorithms, since all left-hand-side variables inside when-statements are assigned to their pre-values before the start of the algorithm, according to section 11.1.2.
]
A when-statement:
is similar to the following special if-statement, where Boolean b1[N]; and Boolean b2; are necessary because edge can only be applied to variables
with edge(A) = A and not pre(A) and the additional guarantee, that the statements within this special if-statement are only evaluated at event instants. The difference compared to the when-statements is that, e.g., pre may only be used on continuous-time real variables inside the body of a when-clause and not inside these if-statements.
These special statements have the same form and semantics as the corresponding equations, apart from the general difference in semantics between equations and statements.
See section 8.3.7. A failed assert stops the execution of the current algorithm.
See section 8.3.8. The terminate-statement shall not be used in functions. In an algorithm outside a function it does not stop the execution of the current algorithm.