Modelica® Language Specification version 3.7-dev

Chapter 11 Statements and Algorithm Sections

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.

11.1 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:

algorithm-section :
   [ initial ] algorithm { statement ";" }

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.

11.1.1 Initial Algorithm Sections

See section 8.6 for a description of both initial algorithm sections and initial equation sections.

11.1.2 An Algorithm in a Model

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).

  • A clocked variable v in a discrete-time sub-partition, section 16.8.1, is initialized with previous(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.

For a clocked variables it is important to skip this initialization when not needed, in order to avoid an excessive amount of clocked states, section 16.4.

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:

model Test // wrong Modelica model (has 4 equations for 2 unknowns)
  Real x[2](start = {-11, -22});
algorithm // conceptually: x = {1, -22}
  x[1] := 1;
algorithm // conceptually: x = {-11, 2}
  x[2] := 2;
end Test;

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.]

11.1.3 The Algorithm in a Function

11.2 Statements

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:

statement :
   ( component-reference ( ":=" expression | function-call-args )
     | "(" output-expression-list ")" ":="
       component-reference function-call-args
     | break
     | return
     | if-statement
     | for-statement
     | while-statement
     | when-statement
   )
   description

11.2.1 Simple Assignment Statements

The syntax of simple assignment statement is as follows:

component-reference ":=" expression

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.

11.2.1.1 Assignments from Called Functions with Multiple Results

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 n results needs mn receiving variables on the left-hand side, and the variables are assigned from left to right.

(out1, out2, out3) := function_name(in1, in2, in3, in4);

It is possible to omit receiving variables from this list:

(out1, , out3) := function_name(in1, in2, in3, in4);

[Example: The function f called below has three results and two inputs:

(a, b, c) := f(1.0, 2.0);
(x[1], x[2], x[1]) := f(3, 4);

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:

(, x[2], x[1]) := f(3,4);

]

The syntax of an assignment statement with a call to a function with multiple results is as follows:

"(" output-expression-list ")" ":=" component-reference function-call-args

[Also see section 8.3.1 regarding calling functions with multiple results within equations.]

11.2.1.2 Assigned Variables - Restrictions

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.

11.2.2 For-Statement

The syntax of a for-statement is as follows:

for for-indices loop
  { statement ";" }
end for

A for-statement may optionally use several iterators (for-indices), see section 11.2.2.3 for more information:

for-indices:
   for-index { "," for-index }
for-index:
   IDENT [ in  expression ]

The following is an example of a prefix of a for-statement:

for IDENT in expression loop

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:

for i in 1 : 10 loop // i takes the values 1, 2, 3, , 10
for r in 1.0 : 1.5 : 5.5 loop // r takes the values 1.0, 2.5, 4.0, 5.5
for i in {1, 3, 6, 7} loop // i takes the values 1, 3, 6, 7
for i in TwoEnums loop // i takes the values TwoEnums.one, TwoEnums.two
                       // for TwoEnums = enumeration(one, two)

The loop-variable may hide other variables as in the following example. Using another name for the loop-variable is, however, strongly recommended.

  constant Integer j = 4;
  Real x[j];
equation
  for j in 1:j loop // The loop-variable j takes the values 1, 2, 3, 4
    x[j] = j; // Uses the loop-variable j
  end for;

]

11.2.2.1 Implicit Iteration Ranges

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:

  Real x[4];
  Real xsquared[:] = {x[i] * x[i] for i};
  // Same as: {x[i] * x[i] for i in 1 : size(x, 1)}
  Real xsquared2[size(x, 1)];
  Real xsquared3[size(x, 1)];
equation
  for i loop // Same as: for i in 1 : size(x, 1) loop 
    xsquared2[i] = x[i]^2;
  end for;
algorithm
  for i loop // Same as: for i in 1 : size(x, 1) loop 
    xsquared3[i] := x[i]^2;
  end for;

]

[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:

type FourEnums = enumeration(one, two, three, four);
Real x[4];
Real xe[FourEnums] = x;
Real xsquared3[FourEnums] = {xe[i] * xe[i] for i in FourEnums};
Real xsquared4[FourEnums] = {xe[i] * xe[i] for i};
Real xsquared5[FourEnums] = {x[i] * x[i] for i};

]

11.2.2.2 Types as Iteration 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:

  type FourEnums = enumeration(one, two, three, four);
  Real xe[FourEnums];
  Real xsquared1[FourEnums];
  Real xsquared2[FourEnums] = {xe[i] * xe[i] for i in FourEnums};
equation
  for i in FourEnums loop
    xsquared1[i] = xe[i]^2;
  end for;

]

11.2.2.3 Nested For-Loops and Reduction Expressions with Multiple Iterators

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:

  Real x[4,3];
algorithm
  for j, i in 1:2 loop
    // The loop variable j takes the values 1, 2, 3, 4 (due to use)
    // The loop variable i takes the values 1, 2 (given range)
    x[j,i] := j+i;
  end for;

]

11.2.3 While-Statement

The while-statement has the following syntax:

while expression loop
  { statement ";" }
end while

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:

  1. 1.

    The expression of the while-statement is evaluated.

  2. 2.

    If the expression of the while-statement is false, the execution continues after the while-statement.

  3. 3.

    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.

11.2.4 Break-Statement

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:

break;

[Example: (Note that this could alternatively use return).

function findValue "Returns position of val or 0 if not found"
  input Integer x[:];
  input Integer val;
  output Integer index;
algorithm
  index := size(x, 1);
  while index >= 1 loop
    if x[index] == val then
      break;
    else
      index := index - 1;
    end if;
  end while;
end findValue;

]

11.2.5 Return-Statements

Can only be used inside functions, see section 12.1.2.

11.2.6 If-Statement

The if-statements have the following syntax:

if expression then
  { statement ";" }
{ elseif expression then
  { statement ";" }
}
[ else
  { statement ";" }
]
end if

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.

11.2.7 When-Statements

A when-statement has the following syntax:

when expression then
  { statement ";" }
{ elsewhen expression then
  { statement ";" }
}
end when

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:

when x > 2 then
  y1 := sin(x);
  y3 := 2*x + y1+y2;
end when;

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:

when {x > 2, sample(0, 2), x < 5} then
  y1 := sin(x);
  y3 := 2*x + y1+y2;
end when;

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.:

algorithm
  when x > 2 then
    y1 := sin(x);
  end when;
equation
  y2 = sin(y1);
algorithm
  when x > 2 then
    y3 := 2 * x + y1 + y2;
  end when;

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.]

11.2.7.1 Where a When-Statement May Occur

  • 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:

when x > 2 then
  when y1 > 3 then
    y2 := sin(x);
  end when;
end when;

]

11.2.7.2 Statements within When-Statements

[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.

]

11.2.7.3 Defining When-Statements by If-Statements

A when-statement:

algorithm
  when {x > 1, , y > p} then
    
  elsewhen x > y.start then
    
  end when;

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

  Boolean b1[N](start = {x.start > 1, , y.start > p});
  Boolean b2(start = x.start > y.start);
algorithm
  b1: = {x > 1, , y > p};
  b2: = x > y.start;
  if edge(b1[1]) or edge(b1[2]) or  or edge(b1[N]) then
    
  elseif edge(b2) then
    
  end if;

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.

11.2.8 Special 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.

11.2.8.1 Assert-Statement

See section 8.3.7. A failed assert stops the execution of the current algorithm.

11.2.8.2 Terminate-Statement

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.