We’ve already discussed Annotations in general. Modelica includes a number of standard annotations that are specifically used in conjunction with functions. These meaning of these annotations is formally defined in the Modelica Specification. In this section, we’ll talk about the three general categories of annotations for functions and provide some discussion of why you need them and how to use them.
The first class of annotations are ones that provide additional
mathematical information about the function. Because functions are
algorithm sections, it is not generally possible to
derive equations for the behavior of the function and many symbolic
manipulations are therefore not possible. However, using the
annotations in this section allows us to augment the function
definition with such information.
As was saw in the ref:polynomial-evaluation example, there are
circumstances where we would like to inform the Modelica compiler how
to compute the derivative of a given function. This is done by adding
derivative annotation in the function.
The basic use of the
derivative annotation is to specify the name
of another Modelica function that computes the first derivative of the
function being annotated. For example:
function f input Real x; input Real y; output Real z; annotation algorithm z := // some expression involving x and y end f; function df input Real x; input Real y; input Real dx; input Real dy; output Real dz; algorithm dz := // some expression involving x, y, dx and dy end df;
Note that the first arguments to the derivative function,
this case, are the same as for the original function,
arguments are then followed by the differential versions of the input
arguments to the original function. Finally, the output(s) of the
derivative function are the differential versions of the output(s) of
the original function. It sounds complicated, but hopefully the same
code conveys how simple the construction really is.
Given such a Modelica function, the Modelica compiler can use such a function to compute various derivatives, e.g.,
Now consider a case where is zero. The derivative function will be passed this zero value or an array of zero values, if the argument was an array. That zero value will then be used in several calculations inside the derivative function. Most, if not all, of these will be multiplications and the results of those calculations will therefore be zeros. Those zeros will then be added to the final result, but will have no impact. In other words, there are many calculations that could be skipped because they won’t have any impact on the result.
In such cases, Modelica offers a way to avoid these calculations. If
the Modelica compiler knows a priori that one of the differentials
is zero, it can check (among the set of
if there are any functions that compute the derivative for that case.
These cases are specified using the
zeroDerivative argument to the
derivative annotation. So, in the case of our example function
f, we could add the following annotation:
function f input Real x; input Real y; output Real z; annotation algorithm z := // some expression involving x and y end f;
df_onlyx would then be defined as:
function df_onlyx input Real x; input Real y; input Real dx; output Real dz; algorithm dz := // some expression involving x, y, dx end df_onlyx;
Note that the
dy term is not included here. This function is
specifically for cases where
dy is zero. Because
appear in the arguments, this function includes only those
There are a few more variations worth covering here. The first is how
to specify what the second derivative of a function is. This is
done by adding an
order argument. Note that a function can have
derivative annotations, e.g.,
function f input Real x; input Real y; output Real z; annotation algorithm z := // some expression involving x and y end f; function df ... end df; function ddf input Real x; input Real y; input Real dx; input Real dy; input Real ddx; input Real ddy; output Real ddz; algorithm ddz := // some expression involving x, y, dx, dy, // ddx and ddz end ddf;
Hopefully there are no real surprises here. In order to compute the
second derivative, it is necessary to add an additional annotation
derivative annotation to the original function, i.e.,
This additional annotation has an additional argument
indicates which derivative that function computes.
There is one additional complication to discuss. What if the function has arguments that don’t represent real numbers, e.g.,
function g input Real x; input Integer y; output Real z; algorithm z := // some expression involving x and y end g;
Here, it makes no sense to take the derivative of this function with
respect to the
y argument, since it is an integer. Any non-real
argument can be ignored when formulating the derivative. So, if we
wished to compute the derivative of this function, we would do it as
function g input Real x; input Integer y; output Real z; annotation algorithm z := // some expression involving x and y end g; function dg input Real x; input Integer y; input Real dx; output Real dz; algorithm dz := // some expression involving x, y and dx end dg;
In other words, the differential arguments only apply to arguments that are real.
During our discussion on Non-Linearities, we showed how the
inverse annotation can be used to tell the Modelica compiler how
to compute the inverse of a function. The goal of an inverse function
is to solve explicitly for one of the current function’s input
arguments. As such, the
inverse annotation contains an explicit
equation involving the input and output variables of the current
function, but used in conjunction with another function to explicitly
compute one of the input arguments.
For example, for a Modelica function defined as follows:
function h input Real a; input Real b; output Real c; annotation algorithm c := // some calculation involving a and b end h;
we see that
b can be computed by passing
arguments to the function
h_inv_b which would be defined as
function h_inv_b input Real a; input Real c; output Real b; algorithm b := // some calculation involving a and c end h_inv_b;
The next class of annotations are related to how function definitions are translated into code for simulation. These annotations allow the model developer to provide hints to the Modelica compiler on how the code generation process should be done.
Inline annotation is a hint to the Modelica compiler that the
statements in the function should be “inlined”. The value of the
annotation is used to suggest whether inlining should be done. The
default value (if no
Inline annotation is present) is
The following is a function that uses the
function SimpleCalculation input Real x; input Real y; output Real z; annotation algorithm z := 2*x-y; end SimpleCalculation;
Here we see that the
Inline annotation suggests that the Modelica
compiler should inline the
SimpleCalculation function. The
function is inlined by replacing invocations of the function
with the statements in the function that compute the output result.
This is useful for functions that perform very simple calculations.
In those cases, the “cost” (in CPU time) of calling the function is on
the same order of magnitude as the cost of the work performed by the
function. By inlining the function, the cost of the function call can
be eliminated while still preserving the purpose of the function.
Inline function is merely a hint to the Modelica compiler.
The compiler is not obligated to inline the function. Also, the
compiler’s ability to inline the function will depend on the
complexity of the function. It is not necessary possible (or even
desirable) to inline a function in general.
Much like the Inline annotation, the
function tells the Modelica compiler that it would be more efficient
to inline the function. The
LateInline annotation is also
Boolean value to specify whether the function should be
inlined or not. The difference between the
LateInline annotations is that
LateInline indicates that
inlining should be performed after symbolic manipulation has been
performed. A full discussion of the potential interactions between
inlining and other symbolic manipulations is beyond the scope of this
It should be noted that the
LateInline annotation takes precedence
Inline annotation if they are both applied to a function,
The final class of annotations are related to functions that are
external. Such functions often depend on external
include files or libraries. These annotations inform the Modelica
compiler of these dependencies and where to locate them.
Include annotations is used whenever the code generated by a
Modelica compiler requires an include statement. Typically this is
required when external libraries are being referenced. The value of
Include annotation should be the string that should be
inserted into the generated code, e.g.,
The value of the
Include annotation is a string. If it
included embedded strings, they need to be escaped.
As already discussed, the Include annotation allows
include directives to be inserted into generated code. The
IncludeDirectory annotation specifies what directory should be
searched to find the content specified with the
The value of this annotation is a string. The string can represent a
directory or it can be a URL. For example, the default
value for the
IncludeDirectory annotation is:
We’ll explain the meaning of these modelica:// URLs shortly.
Library annotation is used to specify any compiled libraries
that a function might depend on. The value of library can be either a
simple string, representing the name of the library, or an array of
such strings, i.e.,
The Modelica compiler will then use this information during the “linking” of the generated code.
We have the same issue with
Library that we have with
Library annotation tells us what we need to add, but not where
to find it. In this way, the
LibraryDirectory annotation serves
the same role as the IncludeDirectory annotation. Like
IncludeDirectory annotation, it can also be a URL. It’s
default value is: