The Functional Mock-up Interface (FMI) is a free standard that defines a container and an interface to exchange dynamic models using a combination of XML files, binaries and C code, distributed as a ZIP file. It is supported by more than 100 tools and maintained as a Modelica Association Project. Releases and issues can be found on github.com/modelica.
Copyright © 2008-2011 MODELISAR Consortium and 2012-2020 The Modelica Association Project FMI.
This document is licensed under the Attribution-ShareAlike 4.0 International license. The code is released under the 2-Clause BSD License. The licenses text can be found in the LICENSE.txt file that accompanies this distribution.
1. Introduction
1.1. What is new in FMI 3.0
The FMI Design Community has improved the FMI standard to react to new requirements from the system simulation community.
Especially the ability to package control code into FMUs required some workarounds in FMI 2.0. With FMI 3.0, virtual electronic control units (vECUs) can be exported as FMU in a more natural way. Concrete features to support vECU export are:
-
introduction of more integer types and a 32-bit float type (see Section 2.4) to communicate native controller types to the outside,
-
introduction of two types of clocks to more exactly control timing of events and evaluation of model partitions across FMUs,
-
introduction of a binary type to support non-numeric data handling, such as complex sensor data interfaces,
-
extension of variables to arrays for more efficient and natural handling of non-scalar variables,
-
introduction of structural parameters that allow description and changing of array sizes, even during runtime to support advanced online calibration of control code, and
-
addition of the new interface type FMI for Scheduled Execution (see Section 5) that allows activation of individual model partitions (or tasks) from an external scheduler.
A second need of the simulation community was address by introducing the more advanced co-simulation interface FMI for Co-Simulation. New features, like
-
early return from a
fmi3DoStep
call, -
the intermediate update, or
allow implementation of more robust and efficient co-simulation algorithms to handle the growing system simulations the community is facing.
Parallel to the new standard features, the FMI Design Community has worked on improving the standard quality by:
-
modernizing the development methodology (e.g. moving to github) and a text-based source format,
-
publishing the FMI Standard now primarily as html to support easier navigation within the document and viewing on a wider range of devices,
-
supplying a large set of continuously validated Reference FMUs, and
-
integrating within the FMI Standard only validated C-code, XML and XSD snippets to reduce redundancy and ensure correctness.
While a number of desirable features had to be postponed, the resulting FMI 3.0 is certainly a significant step forward towards meeting the most important requirements of the system simulation community for the years to come.
1.2. Overview
The FMI (Functional Mock-up Interface) defines an interface to be implemented by an executable called an FMU (Functional Mock-up Unit).
The FMI functions are used (called) by a simulation environment to create one or more instances of the FMU and to simulate them, typically together with other models.
An FMU may either have its own solvers (FMI for Co-Simulation
), or require the simulation environment to perform numerical integration (FMI for Model Exchange, Section 3), or require the simulation environment to trigger model partition execution (FMI for Scheduled Execution , Section 5).
The goal of this interface is that the calling of an FMU in a simulation environment is reasonably simple.
This document does not describe how to generate an FMU from a modeling environment.
The FMI for Model Exchange interface defines an interface to the model of a dynamic system described by differential, algebraic and discrete-time equations. It provides an interface to evaluate these equations as needed in different simulation environments, as well as in embedded control systems, with explicit or implicit integrators, and fixed or variable step-size. The interface is designed to allow the description of large models.
The FMI for Co-Simulation interface are designed both for the coupling of simulation tools, and the coupling of subsystem models (which have been exported by their simulators together with its solvers as runnable code). The modular structure of these systems is exploited in all stages of the simulation process beginning with the separate model setup and pre-processing for the individual subsystems in different simulation tools. During time integration, the simulation is again performed independently for all subsystems restricting the data exchange between subsystems to discrete communication points. Finally, the visualization and post-processing of simulation data can be done individually for each subsystem in its own native simulation tool or by the simulation environment.
[TODO: add SE]
The interfaces have large parts in common, defined in Section 2. In particular:
-
FMI Application Programming Interface (C) — Section 2.2
All required equations or tool coupling computations are evaluated by calling standardized C functions. C is used because it is the most portable programming language today and is the only programming language that can be utilized in all embedded control systems. -
FMI Description Schema (XML) — Section 2.4
The schema defines the structure and content of an XML file generated by a modeling environment. This XML file contains the definition of all variables of the FMU in a standardized way. It is then possible to run the C code in an embedded system without the overhead of the variable definition (the alternative would be to store this information in the C code and access it via function calls, but this is neither practical for embedded systems nor for large models). Furthermore, the variable definition is a complex data structure and tools should be free to determine how to represent this data structure in their programs. The selected approach allows a tool to store and access the variable definitions (without any memory or efficiency overhead of standardized access functions) in the programming language of the simulation environment. -
FMU Distribution (ZIP) — Section 2.5
An FMU is distributed in one ZIP file. The ZIP file contains the FMI Description file (XML), the binaries and libraries required to execute the FMI functions (.dll or .so files), the sources of the FMI functions (optional), and other data used by the FMU (e.g., tables or maps). It is possible for an FMU to hide the source code to secure the contained know-how or to allow a fully automatic import of the FMU in another simulation environment. A schematic view of an FMU is shown in Figure 1.
Publications for FMI are available from https://fmi-standard.org/literature/, especially [BOA11] and [BOA12].
A growing set of tools supporting FMI can be found here https://www.fmi-standard.org/tools.
1.2.1. FMI for Model Exchange (ME)
The Model Exchange interface exposes an ODE to an external solver of an importing tool. Models are described by differential, algebraic and discrete equations with time-, state- and step-events. That integration algorithm of the importing tool, usually a DAE solver, is responsible for advancing time, setting states, handling events, etc. (See Section 3.)
1.2.2. FMI for Co-Simulation (CS)
The intention is to provide a standardized interface for coupling of simulation models or tools in a co-simulation environment. The data exchange between FMUs is largely restricted to discrete communication points. In the time between two communication points, the subsystems inside FMUs are solved independently by internal means. Co-simulation algorithms control the data exchange and the synchronization between FMUs (see Section 4).
Note that the co-simulation algorithm itself is not part of the FMI standard.
The FMI 3.0 Co-Simulation interface adds a number of features compared to FMI 2.0 primarily to allow for more sophisticated co-simulation algorithms that aim at more efficient and robust simulations. Such additional features are raising events between communication points using synchronous and asynchronous clocks or sharing values between communication points to allow for improved interpolation of data. The co-simulation algorithm is responsible for:
-
advancing the overall simulation time,
-
triggering of periodic and aperiodic clocks, and
-
handling events (e.g. clock ticks) signaled by the FMUs.
[TODO: is this the definition that a clock tick is an event]
For FMI for Co-Simulation the co-simulation algorithm is shielded from how the subsystem FMU advances time internally. For example, FMUs containing ODEs and exposing either of the co-simulation interfaces require to include an ODE solver inside the FMU to internally advance time between the communication points. As another example, for FMU that represent controller code, an internal scheduling algorithm will trigger tasks at the correct time and order while advancing time to the next communication point or event. (See Section 4.)
1.2.3. FMI for Scheduled Execution (SE)
The Scheduled Execution interface exposes individual model partitions (e.g. tasks of a control algorithm), to be called by a scheduler that acts as external scheduler. The scheduler is responsible for:
-
advancing the overall simulation time,
-
triggering of periodic and aperiodic clocks for all exposed model partitions of a set of FMUs, and
-
handling events (e.g. clock ticks) signaled by the FMUs.
In many ways, the Scheduled Execution interface is the equivalent of the Model Exchange interface: the first externalizes a scheduling algorithm usually found in a controller algorithm and the second interface externalizes the ODE solver. (See Section 5.)
1.2.4. Feature Overview of FMI Interface Types
Table 1 gives an overview of the features of the different interfaces.
Feature | Model Exchange | Co-Simulation | Scheduled Execution |
---|---|---|---|
Advancing Time |
Call |
Call |
|
Solver Included |
Not applicable |
||
Scheduler Included |
Not applicable |
||
Event Indicators |
|||
Includes similar or better mechanism |
|||
Includes similar or better mechanism |
Signal output clock ticks: |
||
Only Synchronous Clocks |
Only Synchronous Clocks |
||
Direct Feedthrough |
At events: |
1.3. Properties and Guiding Ideas
In this section, properties are listed and some principles are defined that guided the low-level design of the FMI. This shall increase self consistency of the FMI functions. The listed issues are sorted, starting from high-level properties to low-level implementation issues.
- Expressivity
-
The FMI provides the necessary features to package models of different domains, such as multibody and virtual ECUs, into an FMU.
- Stability
-
The FMI is expected to be supported by many simulation tools worldwide. Implementing such support is a major investment for tool vendors. Stability and backwards compatibility of the FMI has therefore high priority. To support this, the FMI defines "capability flags" that will be used by future versions of the FMI to extend and improve the FMI in a backwards compatible way, whenever feasible.
- Implementation
-
FMUs can be written manually or can be generated automatically from a modeling environment. Existing manually coded models can be transformed manually to a model according to the FMI standard.
- Processor independence
-
It is possible to distribute an FMU without knowing the target processor. This allows an FMU to run on a PC, a Hardware-in-the-Loop simulation platform or as part of the controller software of an ECU. Keeping the FMU independent of the target processor increases the usability of the FMU. To be processor independent, the FMU must include its C (or C++) sources.
- Simulator independence
-
It is possible to compile, link and distribute an FMU without knowing the environment in which the FMU will be loaded.
Reason: The standard would be much less attractive otherwise, unnecessarily restricting the later use of an FMU at compile time and forcing users to maintain simulator specific variants of an FMU. To be simulator independent, the FMU must export its implementation in self-contained binary form. This requires that the target operating system and processor be known. Once exported with binaries, the FMU can be executed by any simulator running on the target platform (provided the necessary licenses are available, if required from the model or from the used run-time libraries).
- Semantic versioning
-
The FMI standard uses semantic version numbers, as defined in [PW13], where the standard version consists of a triple of version numbers, consisting of major version, minor version, and patch version numbers, see Section 2.7.
- Version independence
-
FMUs with a specific major and minor version number are valid FMUs w.r.t. the same major version and any minor version because features of minor versions are optional and ignorable.
Reason: A tool can always export the greatest minor version it supports. Such an FMU can be imported into all tools supporting this major version and arbitrary minor versions. This achieves maximal longevity of FMUs protecting its value for users.
- Small run-time overhead
-
Communication between an FMU and an importer through the FMI does not introduce significant run-time overhead. This can be achieved by enabling caching of the FMU outputs and by exchanging multiple quantities with one call.
- Small footprint
-
A compiled FMU binary requires little memory.
Reason: An FMU may run on an ECU (Electronic Control Unit, for example, a microprocessor), and ECUs have strong memory limitations. This is achieved by storing variable attributes (
name
,unit
, etc.) and all other static information not needed for model evaluation in a separate text file (= Model Description File) that is not needed on the microprocessor where the executable might run. - Hide data structure
-
The FMI for Model Exchange does not prescribe a data structure (e.g., a C struct) to represent a model.
Reason: the FMI standard shall not unnecessarily restrict or prescribe a certain implementation of FMUs or simulators (whichever contains the model data) to ease implementation by different tool vendors.
- Support many and nested FMUs
-
A simulator may run many FMUs in a single simulation run and/or multiple instances of one FMU. The inputs and outputs of these FMUs can be connected with direct feedthrough. Moreover, an FMU may contain nested FMUs.
- Numerical Robustness
-
The FMI standard allows problems which are numerically critical (for example,
time
andstate events
, multiple sample rates, stiff problems) to be treated in a robust way. - Hide cache
-
A typical FMU will cache computed results for later reuse. To simplify usage and to reduce error possibilities by a simulator, the caching mechanism is hidden from the usage of the FMU.
Reason: First, the FMI should not force an FMU to implement a certain caching policy. Second, this helps to keep the FMI simple. To help implement this cache, the FMI provides explicit methods (called by the FMU environment) for setting properties that invalidate cached data. An FMU that chooses to implement a cache may maintain a set of "dirty" flags, hidden from the simulator. A get method, for example to a state, will then either trigger a computation, or return cached data, depending on the value of these flags.
- Support numerical solvers
-
A typical importer will use numerical solvers. These solvers require vectors for
states
,derivatives
and zero-crossing functions. The FMU directly fills the values of such vectors provided by the solvers.Reason: minimize execution time. The exposure of these vectors conflicts somewhat with the "hide data structure" requirement, but the efficiency gain justifies this.
- Explicit signature
-
The intended operations, arguments, and return types are made explicit in the signature. For example, an operator (such as
compute_derivatives
) is not passed as an int argument but a special function is called for this. Theconst
prefix is used for any pointer that should not be changed, includingconst char*
instead ofchar*
.Reason: the correct use of the FMI can be checked at compile time and allows calling of the C code in a C++ environment (which is much stricter on
const
than C is). This will help to develop FMUs that use the FMI in the intended way. - Few functions
-
The FMI consists of a few, "orthogonal" functions, avoiding redundant functions that could be defined in terms of others.
Reason: This leads to a compact, easy-to-use, and hence attractive API with a compact documentation.
- Error handling
-
All FMI methods use a common set of methods to communicate errors.
- Allocator must free
-
All memory (and other resources) allocated by the FMU are freed (released) by the FMU. Likewise, resources allocated by the importer are released by the importer.
Reason: this helps to prevent memory leaks and run-time errors due to incompatible run-time environments for different components.
- Immutable strings
-
All strings passed as arguments or returned are read-only and must not be modified by the receiver.
Reason: This eases the reuse of strings.
- Named list elements
-
All lists defined in the
fmi3ModelDescription.xsd
XML schema file have a string attributename
to a list element. This attribute must be unique with respect to all othername
attributes of the same list. - Use C
-
The FMI is encoded using C, not C++. Reasons: Avoid problems with compiler and linker dependent behavior, and run the FMU on embedded systems.
This version of the FMI standard does not have the following desirable properties. They might be added in a future version.
-
The FMI for Model Exchange is for ordinary differential equations (ODEs) in state space form. It is not for a general differential-algebraic equation system. However, algebraic equation systems inside the FMU are supported (for example, the FMU can report to the environment to re-run the current step with a smaller step size since a solution could not be found for an algebraic equation system).
-
Special features that might be useful for multibody system programs are not included.
-
The interface is for simulation and for embedded systems. Properties that might be additionally needed for trajectory optimization, for example, derivatives of the model with respect to parameters during continuous integration are not included.
-
No explicit definition of the variable hierarchy in the XML file.
1.4. Conventions Used in This Document
-
Non-normative text is given in square brackets in italic font: [Especially examples are defined in this style.]
-
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119.
-
{VariableType}
is used as a placeholder for all variable type names without thefmi3
prefix (e.g.fmi3Get{VariableType}
stands forfmi3GetUInt8
,fmi3GetBoolean
,fmi3GetFloat64
, etc.). -
State machine states be formatted in bold.
2. Common Concepts
The FMI defines the following interface types: FMI for Model Exchange, Co-Simulation, and Scheduled Execution. The concepts defined in this chapter are common to at least two of these interface types. The definitions that are specific to the particular cases are defined in Section 3, Section 4, and Section 5.
The term FMU (Functional Mock-up Unit) denotes an implementation (or any mix) of interface types.
In the following, we assume that the reader is familiar with the basics of the C programming language and the basics of numerical simulation. Please refer to Appendix A for the most commonly used terms.
2.1. Mathematical Definitions
This section introduces the mathematical notation used throughout this document. It is used to describe * ordinary differential equations in state-space representations with discontinuities (events), * algebraic equation systems, * discrete-time equations (sampled-data systems).
The independent
variable \(t \in \mathbb{T}\) [typically: time] is a tuple \(t = (t_R,t_I)\), where \(t_R \in \mathbb{R},\ t_{I} \in \mathbb{N} = \{0, 1, 2, \ldots\}\).
The real part \(t_R\) of this tuple is the independent
variable of the FMU for describing the continuous-time behavior of the model between events.
During continuous-time integration \(t_I = 0\).
The integer part \(t_I\) of this tuple is a counter to enumerate (and therefore distinguish) the events at the same continuous-time instant \(t_R\).
This time definition is also called "super-dense time" in literature, see, for example, [LZ07].
An ordering is defined on \(\mathbb{\text{T}}\) that leads to the notation in Table 2.
[The notation \(^{\bullet}t\) is from BCP10, adapted from non-standard analysis to super-dense time, in order to precisely define the value from the previous event iteration.]
Operation |
Mathematical meaning |
Description |
\(t_1 < t_2\) |
\((t_{\mathit{R1}},t_{\mathit{I1}}) < (t_{\mathit{R2}}, t_{\mathit{I2}})\ \Leftrightarrow \ t_{\mathit{R1}} < t_{\mathit{R2}}\ \textbf{or} \ t_{\mathit{R1}}= t_{\mathit{R2}} \ \textbf{and} \ t_{\mathit{I1}} < t_{\mathit{I2}}\) |
\(t_1\) is before \(t_2\) |
\(t_1 = t_2\) |
\((t_{\mathit{R1}},t_{\mathit{I1}}) = (t_{\mathit{R2}},t_{\mathit{I2}}) \ \Leftrightarrow t_{\mathit{R1}}= t_{\mathit{R2}}\ \textbf{and} \ t_{\mathit{I1}} = t_{\mathit{I2}}\) |
\(t_1\) is identical to \(t_2\) |
\(t^{+}\) |
\({{(t}_{R},t_{I})}^{+} \Leftrightarrow (\lim_{\mathit{\epsilon \rightarrow 0}}{\left(t_{R} + \varepsilon \right),t_{\mathit{Imax}})}\) |
right limit at \(t\). \(t_{\mathit{Imax}}\) is the largest occurring integer index of super-dense time |
\(^-t\) |
\(^{-}{{(t}_{R},t_{I})} \Leftrightarrow (\lim_{\mathit{\epsilon \rightarrow 0}}{\left( t_{R} - \varepsilon \right),0)}\) |
left limit at \(t\) |
\(^{\bullet}t\) |
\(^{\bullet}{\left( t_{R},t_{I} \right)\ } \Leftrightarrow \left\{ \begin{matrix} ^-t \ & \mathbf{if} \ t_I = 0 \\ (t_R, t_I - 1) \ & \mathbf{if} \ t_I > 0 \\ \end{matrix} \right.\) |
previous time instant (= either left limit or previous event instant). |
\(v^+(t)\) |
\(v(t^+)\) |
value at the right limit of \(t\) |
\(^{-}v(t)\) |
\(v(^-t)\) |
value at the left limit of \(t\) |
\(^{\bullet}v(t)\) |
\(v(^{\bullet}t)\) |
previous value (= either left limit or value from the previous event) |
[Assume that an FMU has an event at \(t_R=2.1s\) and here a variable changes discontinuously. If no event iteration occurs, the time instant when the event occurs is defined as (2.1, 0), and the time instant when the integration is restarted is defined as (2.1, 1).]
The hybrid differential equations exposed by FMI for Model Exchange or wrapped by FMI for Co-Simulation are described as piecewise continuous-time systems.
Discontinuities can occur at time instants \(t_0, t_1, \ldots, t_n\) where \(t_i < t_{i+1}\).
These time instants are called events
.
Events can be known before hand (= time event), or are defined implicitly (= state
and step events
), see below.
Between events, variables are either continuous
or do not change their value.
A variable is called discrete-time, if it changes its value only at an event instant.
Otherwise the variable is called continuous-time.
Only floating point variables can be continuous-time.
The following variable subscripts are used to describe the timing behavior of the corresponding variable (for example, \(v_d\) is a discrete-time variable):
A clock is a variable that communicates events across FMUs. Clock variables are special discrete and discrete-time variables that are active (are ticking) only at event time instants. Time-based clocks can only tick once per \(t_i\). Other clocks might tick multiple times during super-dense time instants of one \(t_i\).
Subscript |
Description |
|
A continuous-time variable is a floating-point variable representing a continuous function of time inside each interval \(t_i^+ < \ ^-t_{i+1}\). |
|
A discrete-time variable changes its value only at an event instant \(t = (t_i,n)\). Such a variable can change multiple times at the same continuous-time instant, but only at subsequent super-dense time instances \(n \in \mathbb{N} = \{0, 1, 2, \ldots\}\). |
|
A clocked variable is a discrete-time variable associated with a |
|
A set of continuous-time and discrete-time variables. |
|
A set of continuous-time variables accessible in Intermediate Update Mode. |
|
A set of variables which have an XML attribute-value combination as defined.
[Example: \(\mathbf{v}_{\mathit{initial=exact}}\) are variables defined with attribute |
At every event instant \(t_i\), continuous-time variables might change discontinuously (see Figure 2).
The mathematical description of an FMU uses the following variables:
Variable |
Description |
\(t\) |
For Co-Simulation and Scheduled Execution: |
\(\mathbf{v}\) |
A vector of all exposed variables (all variables defined in element |
\(\mathbf{p}\) |
Parameters.
The symbol without a subscript references [Example: Dependent |
\(\mathbf{u}\) |
Input variables.
The values of these variables are defined outside of the model.
Variables of this type are defined with attribute |
\(\mathbf{y}\) |
Output variables.
The values of these variables are computed in the FMU and they are designed to be used outside the FMU.
Variables of this type are defined with attribute |
\(\mathbf{w}\) |
Local variables of the FMU that must not be used for FMU connections.
Variables of this type are defined with attribute |
\(\mathbf{z}\) |
A vector of floating point continuous-time variables representing the event indicators used to define |
\(\mathbf{x}_c\) |
A vector of floating point continuous-time variables representing the continuous-time |
\(\mathbf{x}_d\) |
\(\mathbf{x}_d\) is a vector of (internal) discrete-time variables (of any type) representing the discrete-time states. |
\(T_{\mathit{next}}\) |
At initialization or at an event instant, an FMU can define the next time instant \(T_{\mathit{next}}\), at which the next time event occurs (see also the definition of events).
Every event removes automatically a previous definition of \(T_{\mathit{next}}\), and it must be explicitly defined again, even if a previously defined \(T_{\mathit{next}}\) was not yet reached (see |
\(\mathbf{r}\) |
A vector of Boolean variables representing relations: \(r_{j} := z_{j} > 0\). When entering Continuous-Time Mode all relations reported via the event indicators \(\mathbf{z}\) are fixed and during this mode these relations are replaced by \(^{\bullet}\mathbf{r}\). Only during Initialization Mode or Event Mode the domains \(z_{j} > 0\) can change. [For more details, see Remark 3 below.] |
2.2. General Mechanisms
This section contains the common interface definitions that allow a C program to invoke the FMU functions.
Note that the following general properties hold for an FMU:
-
FMI functions of one instance do not need to be thread-safe.
[For example, if the functions of one instance of an FMU are accessed from more than one thread; the multi-threaded simulation environment that uses the FMU must guarantee that there are no race conditions while invoking the FMI functions. The FMU itself does not implement any services to support this.] -
FMI functions must not change global settings which affect other processes/threads. An FMI function may change settings of the thread in which it is called (such as floating point control registers), provided these changes are restored before leaving the function or before a callback function is called.
[This property ensures that functions of different FMU instances can be called safely in any order. Additionally, they can be called in parallel provided the functions are called in different processes. If an FMI function changes for example the floating point control word of the CPU, it must restore the previous value before return of the function. For x86 CPUs, the floating point control word is set using thefldcw
instruction. This can be used to switch on additional exceptions such as floating point division by zero. An FMU might temporarily change the floating point control word and get notified on floating point exceptions internally, but has to restore the flag and clear the floating point status word before return of the respective FMI function.] -
In general, FMI function arguments are not allowed to be NULL, unless explicitly allowed by the standard document where NULL will be assigned a specific semantic.
[For an example of NULL being explicitly allowed seeresourceLocation
. Careful implementations should still guard against NULL pointers.] -
The FMI Standard does not provide a run-time platform or portability layer. Access to operating system resources and services, such as memory and file system, must be implemented with special care because the availability of such resources and services is not guaranteed. If some resource is required by the FMU but is not available, the FMU must log what resource failed and return with error.
2.2.1. Header Files and Naming of Functions
Three header files are provided that define the interface of an FMU.
In all header files the convention is used that all C function and type definitions start with the prefix fmi3
:
fmi3PlatformTypes.h
-
contains the type definitions of the input and output arguments of the functions as well as some C preprocessor macro definitions for constants. This header file must be used both by the FMU and by the importer. [Example of a definition in this header file:
typedef double fmi3Float64;
]
fmi3FunctionTypes.h
-
contains
typedef
definitions of all function prototypes of an FMU as well as enumerations for constants. This header file includesfmi3PlatformTypes.h
. When dynamically loading an FMU, these definitions can be used to type-cast the function pointers to the respective function definition. For simplicity, the function type for each function is composed of the function name itself with the suffixTYPE
.[Example of a definition in this header file:
typedef fmi3Status fmi3SetTimeTYPE(fmi3Instance, fmi3Float64);
]
fmi3Functions.h
-
contains the function prototypes of an FMU that can be accessed in simulation environments.
This header file includes
fmi3PlatformTypes.h
andfmi3FunctionTypes.h
. The header file version number for which the model was compiled, can be inquired by the importer withfmi3GetVersion
(see Section 2.2.4).[Example of a definition in this header file:
FMI3_Export fmi3SetTimeTYPE fmi3SetTime;
For Microsoft and Cygwin compilers
FMI3_Export
is defined as__declspec(dllexport)
and for Gnu-Compilers as__attribute__ ( ( visibility("default") ) )
in order to export the name for dynamic loading. Otherwise it is an empty definition.]
The goal is that both source code and binary representations of FMUs are supported and that several FMUs might be present at the same time in an executable (for example, FMU A may use an FMU B).
In order for this to be possible, the names of the functions in different FMUs must be different, or function pointers must be used.
To support the source code representation of FMUs, macros are provided in fmi3Functions.h
to build the actual function names by using a function prefix that depends on how the FMU is shipped.
[These macros can be defined differently in a target specific variant of fmi3Functions.h
to adjust them to the requirements of the supported compilers and platforms of the importing tool.]
An FMU C-file must include at the beginning a define
of FMI3_FUNCTION_PREFIX
with the same value as the value of the modelIdentifier
attribute defined in <fmiModelDescription><ModelExchange>
, <fmiModelDescription><CoSimulation>
or <fmiModelDescription><ScheduledExecution>
together with _
at the end (see Section 3.3, Section 4.3, Section 5.3).
This define
must be directly followed with an #include "fmi3Functions.h"
statement.
Typically, FMU functions are used as follows:
// FMU is shipped with C source code, or with static link library
#define FMI3_FUNCTION_PREFIX MyModel_
#include "fmi3Functions.h"
< usage of the FMU functions e.g. MyModel_fmi3SetTime >
// FMU is shipped with DLL/SharedObject
#include "fmi3FunctionTypes.h"
fmi3SetTimeTYPE *myname_setTime = < load symbol "fmi3SetTime" from DLL/SharedObject >;
< usage of the FMU function pointers, e.g. myname_setTime >
A function that is defined as fmi3GetFloat64
is changed by the macros to a function name as follows:
-
If the FMU is shipped with C source code or with static link library:
The constructed function name isMyModel_fmi3GetFloat64
. In other words the function name is prefixed with the model name and an_
. A simulation environment can therefore construct the relevant function names by generating code for the actual function call. In case of a static link library, the name of the library isMyModel.lib
on Windows andlibMyModel.a
on Linux; in other words themodelIdentifier
attribute is used to create the library name. -
If the FMU is shipped with DLL/SharedObject:
The constructed function name isfmi3GetFloat64
, in other words, it is not changed. [This can be realized in the case of a source code FMU with a target-specific version offmi3Functions.h
that does not use FMI3_FUNCTION_PREFIX to construct the function names.] A simulation environment will then dynamically load this library and will explicitly import the function symbols by providing the FMI function names as strings. The name of the library isMyModel.dll
on Windows orMyModel.so
on Linux; in other words themodelIdentifier
attribute is used as library name.
[An FMU can be optionally shipped so that it basically contains only the communication to another simulation tool (needsExecutionTool = true
, see Section 4).
This is particularly common for co-simulation tasks.
In this tool coupling case one DLL/Shared Object can be used for all models due to no function prefixing.]
Since modelIdentifier
is used as prefix of a C-function name it must fulfill the restrictions on C-function
names (only letters, digits and/or underscores are allowed).
[For example, if modelName = "A.B.C"
, then modelIdentifier
might be "A_B_C".]
Since modelIdentifier
is also used as name in a file system, it must also fulfill the restrictions of the targeted operating system.
Basically, this means that it should be short.
These restrictions apply to all interface types and for binary and source-code FMUs.
[For example, the Windows API only supports full path-names of a file up to 260 characters (see: http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx).]
2.2.2. Platform Dependent Definitions
To simplify porting, no C types are used in the function interfaces, but the alias types are defined in this section.
All definitions in this section are provided in the header file fmi3PlatformTypes.h
.
It is required to use this definition for all binary FMUs.
typedef void* fmi3Instance; /* Pointer to FMU instance */
This is a pointer to an FMU specific data structure that contains the information needed to process the model equations or to process the co-simulation of the model/subsystem represented by the FMU.
typedef void* fmi3InstanceEnvironment; /* Pointer to FMU environment */
This is a pointer to a data structure in the importer. Using this pointer, data can be transferred between the importer and callback functions it provides (see Section 2.3.1).
typedef void* fmi3FMUState; /* Pointer to internal FMU state */
This is a pointer to a data structure in the FMU that saves the internal FMU state of the actual or a previously saved time instant. This allows to restart a simulation from a saved FMU state (see [get-set-fmu-state]).
typedef unsigned int fmi3ValueReference; /* Handle to the value of a variable */
This is a handle to a (base type) variable value of the model.
A fmi3ValueReference
uniquely identifies the value and other properties of a variable, except for the variable name and the display unit that may differ for alias
variable definitions.
Structured entities, such as records, must be flattened into a set of values (scalars or arrays) of type fmi3Float64
, fmi3Int32
, etc.
Arrays may be flattened into a set of scalars or represented directly as array values.
An fmi3ValueReference
references one such value (scalar or array).
The coding of fmi3ValueReferences
is a "secret" of the environment that generated the FMU.
The interface to the equations only provides access to variable values via fmi3ValueReferences
.
Extracting concrete information about a variable can be done by reading the modelDescription.xml
in which the fmi3ValueReferences
are defined.
If a function in the following sections is called with a wrong fmi3ValueReference
value [for example, setting a constant with a call to fmi3SetFloat64
], then the function must return with an error ( fmi3Status == fmi3Error
, see Section 2.2.3).
Listing Base types shows the base types used in the interfaces of the C functions.
typedef float fmi3Float32; /* Single precision floating point (32-bit) */
typedef double fmi3Float64; /* Double precision floating point (64-bit) */
typedef int8_t fmi3Int8; /* 8-bit signed integer */
typedef uint8_t fmi3UInt8; /* 8-bit unsigned integer */
typedef int16_t fmi3Int16; /* 16-bit signed integer */
typedef uint16_t fmi3UInt16; /* 16-bit unsigned integer */
typedef int32_t fmi3Int32; /* 32-bit signed integer */
typedef uint32_t fmi3UInt32; /* 32-bit unsigned integer */
typedef int64_t fmi3Int64; /* 64-bit signed integer */
typedef uint64_t fmi3UInt64; /* 64-bit unsigned integer */
typedef char fmi3Boolean; /* Data type to be used with fmi3True and fmi3False */
typedef char fmi3Char; /* Data type for one character */
typedef const fmi3Char* fmi3String; /* Data type for character strings
('\0' terminated, UTF-8 encoded) */
typedef char fmi3Byte; /* Smallest addressable unit of the machine
(typically one byte) */
typedef const fmi3Byte* fmi3Binary; /* Data type for binary data
(out-of-band length terminated) */
typedef int fmi3Clock ; /* Data type to be used with fmi3ClockActive and
fmi3ClockInactive */
/* Values for fmi3Boolean */
#define fmi3True 1
#define fmi3False 0
/* Values for fmi3Clock */
#define fmi3ClockActive 1
#define fmi3ClockInactive 0
The data types fmi3Float32
, fmi3Float64
, fmi3Int8
, fmi3UInt8
, fmi3Int16
, fmi3UInt16
, fmi3Int32
, fmi3UInt32
, fmi3Int64
, fmi3UInt64
and fmi3Boolean
are called "numeric types" in the following.
If an fmi3String
or an fmi3Binary
variable is passed as input
argument to an FMI function and the FMU needs to use the string/binary later,
the FMI function must copy the string/binary before it returns and store it in the internal FMU memory,
because there is no guarantee for the lifetime of the string/binary after the function has returned.
If an fmi3String
or an fmi3Binary
variable is passed as output
argument from an FMI function and the string/binary shall be used in the target environment,
the target environment must copy the whole string/binary (not only the pointer).
The memory of this string/binary may be deallocated by the next call to any of the FMI functions (the string/binary memory might also be just a buffer, that is reused).
2.2.3. Status Returned by Functions
This section defines the status
flag (an enumeration of type fmi3Status
defined in file fmi3FunctionTypes.h
) that is returned by all functions to indicate the success of the function call:
typedef enum {
fmi3OK,
fmi3Warning,
fmi3Discard,
fmi3Error,
fmi3Fatal,
} fmi3Status;
The status has the following meaning:
fmi3OK
-
The call was successful. The output argument values are defined.
fmi3Warning
-
A non-critical problem was detected, but the computation can continue. The output argument values are defined. Function
logMessage
was called by the FMU and the user is expected to handle the problem. [In certain applications, e.g. in a prototyping environment, warnings may be acceptable. For production environments warnings should be treated like errors unless they can be safely ignored.]
fmi3Discard
-
The call was not successful and the FMU is in the same state as before the call. The output argument values are not defined, but the computation can continue. When debug logging is enabled (
loggingOn == fmi3True
) the functionlogMessage
was called by the FMU. Advanced simulation algorithms can try alternative approaches to drive the simulation by calling the function with different arguments or calling another function. Otherwise the simulation algorithm has to treat this return code likefmi3Error
and has to terminate the simulation.
fmi3Error
-
The call failed. The output argument values are undefined and the simulation cannot be continued. Function
logMessage
was called by the FMU and the FMU is in state Terminated. If a function returnsfmi3Error
, it is possible to restore a previously retrieved FMU state by callingfmi3SetFMUState
. Otherwisefmi3FreeInstance
orfmi3Reset
must be called. When detecting illegal arguments or a wrong function call at the current FMU state, the FMU must returnfmi3Error
. Other instances of this FMU are not affected by the error.
fmi3Fatal
-
The state of all instances of the model is irreparably corrupted. [For example, due to a run-time exception such as access violation or integer division by zero during the execution of an FMI function.] Function
logMessage
was called by the FMU. It is not allowed to call any other function for any instance of the FMU.
2.2.4. Inquire Version Number of Header Files
typedef const char* fmi3GetVersionTYPE(void);
This function returns fmi3Version
of the fmi3Functions.h
header file which was used to compile the functions of the FMU.
This function call is allowed always and in all interface types.
The standard header file as documented in this specification has version "3.0"
, so this function returns "3.0"
.
2.2.5. Variables of a Functional Mockup Unit
All variables of an FMU are identified with a handle called value reference.
The handle is defined in the modelDescription.xml
file as attribute valueReference
in variable elements.
Each variable must have a unique valueReference
.
A variable can be a scalar or an array.
2.2.5.1. Serialization of Array Variables
When getting or setting the values of array variables, the serialization of array variable values used in C-API function calls, as well as in the XML start
attributes, is defined as row major, i.e., dimension order from left to right for the C-API (e.g. array[dim1][dim2]…[dimN]
), and the document order in the XML attributes for the respective dimensions.
For this serialization of array variables the sparsity pattern of the array is not taken into account.
All elements of the array, including structural zeros, are serialized.
[Example: A 2D matrix
is serialized as follows:
A[0][0]=a11 |
memory address: A |
|
A[0][1]=a12 |
memory address: A+1 |
|
A[1][0]=a21 |
memory address: A+2 |
|
A[1][1]=a22 |
memory address: A+3 |
|
A[2][0]=a31 |
memory address: A+4 |
|
A[2][1]=a32 |
memory address: A+5 |
]
2.2.5.2. Getting and Setting Variable Values
The actual values of the variables that are defined in the modelDescription.xml
file can be inquired after calling fmi3EnterInitializationMode
with the following functions:
typedef fmi3Status fmi3GetFloat32TYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Float32 values[],
size_t nValues);
typedef fmi3Status fmi3GetFloat64TYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Float64 values[],
size_t nValues);
typedef fmi3Status fmi3GetInt8TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Int8 values[],
size_t nValues);
typedef fmi3Status fmi3GetUInt8TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3UInt8 values[],
size_t nValues);
typedef fmi3Status fmi3GetInt16TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Int16 values[],
size_t nValues);
typedef fmi3Status fmi3GetUInt16TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3UInt16 values[],
size_t nValues);
typedef fmi3Status fmi3GetInt32TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Int32 values[],
size_t nValues);
typedef fmi3Status fmi3GetUInt32TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3UInt32 values[],
size_t nValues);
typedef fmi3Status fmi3GetInt64TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Int64 values[],
size_t nValues);
typedef fmi3Status fmi3GetUInt64TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3UInt64 values[],
size_t nValues);
typedef fmi3Status fmi3GetBooleanTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Boolean values[],
size_t nValues);
typedef fmi3Status fmi3GetStringTYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3String values[],
size_t nValues);
typedef fmi3Status fmi3GetBinaryTYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
size_t sizes[],
fmi3Binary values[],
size_t nValues);
Get actual values of variables by providing their variable references.
[These functions are used to get the values of output variables if a model is connected with other models.
Since state derivatives are also variables, it is also possible to get the value of a state derivative.
Furthermore, the actual value of every variable defined in the modelDescription.xml
file can be determined at the actually defined time instant (see Section 2.4.8).]
-
valueReferences
is a vector ofnValueReferences
value handles that define the variables that shall be inquired. -
values
is a vector with the actual values of these variables. -
sizes
is a vector with the actual sizes of the values for binary variables. -
nValues
provides the number of values in thevalues
vector (andsizes
vector, where applicable) which is only equal tonValueReferences
if allvalueReference
s point to scalar variables.
The strings returned by fmi3GetString
, as well as the binary values returned by fmi3GetBinary
, must be copied in the target environment because the allocated memory for these strings might be deallocated or overwritten by the next call to any of the FMI functions.
For Model Exchange: fmi3Status == fmi3Discard
is possible for fmi3GetFloat32
and fmi3GetFloat64
only, but not for fmi3Get*Int*
, fmi3GetBoolean
, fmi3GetString
, fmi3GetBinary
, because these are discrete-time variables and their values can only change at an event instant where fmi3Discard
does not make sense.
It is also possible to set the values of certain variables at particular instants in time using the following functions:
typedef fmi3Status fmi3SetFloat32TYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Float32 values[],
size_t nValues);
typedef fmi3Status fmi3SetFloat64TYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Float64 values[],
size_t nValues);
typedef fmi3Status fmi3SetInt8TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Int8 values[],
size_t nValues);
typedef fmi3Status fmi3SetUInt8TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3UInt8 values[],
size_t nValues);
typedef fmi3Status fmi3SetInt16TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Int16 values[],
size_t nValues);
typedef fmi3Status fmi3SetUInt16TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3UInt16 values[],
size_t nValues);
typedef fmi3Status fmi3SetInt32TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Int32 values[],
size_t nValues);
typedef fmi3Status fmi3SetUInt32TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3UInt32 values[],
size_t nValues);
typedef fmi3Status fmi3SetInt64TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Int64 values[],
size_t nValues);
typedef fmi3Status fmi3SetUInt64TYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3UInt64 values[],
size_t nValues);
typedef fmi3Status fmi3SetBooleanTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Boolean values[],
size_t nValues);
typedef fmi3Status fmi3SetStringTYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3String values[],
size_t nValues);
typedef fmi3Status fmi3SetBinaryTYPE (fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const size_t sizes[],
const fmi3Binary values[],
size_t nValues);
Set parameters
, inputs
, and start
values, and re-initialize caching of variables that depend on these variables (see Section 2.4.8 for the exact rules on which type of variables fmi3Set{VariableType}
can be called, as well as Section 3.2.3 in case of Model Exchange, and Section 4.2.7 for Co-Simulation and Section 5.2.1 for Scheduled Execution).
-
valueReferences
is a vector ofnValueReferences
value handles that define the variables that shall be set. -
values
is a vector with the actual values of these variables. -
sizes
is a vector with the actual sizes of the values of binary variables. -
nValues
provides the number of values in thevalues
vector (andsizes
vector, where applicable) which is only equal tonValueReferences
if allvalueReference
s point to scalar variables.
All strings passed as arguments to fmi3SetString
, as well as all binary values passed as arguments to fmi3SetBinary
, must be copied inside these functions, because there is no guarantee of the lifetime of strings or binary values, when these functions return.
Note, fmi3Status == fmi3Discard
is possible for the fmi3Set{VariableType}
functions.
The value of a variable may only be accessed with the respective fmi3Get/Set{VariableType}
for its type.
2.2.6. Advancing Time
This section highlights the differences of the concept of time (in general the independent variable) for the three different FMI types, ME, CS and SE.
In Model Exchange, time is under the sole control of the importer and its integration algorithm.
The model itself receives the current time to be used in its computation with fmi3SetTime
.
In fact, time is not necessarily advancing linearly as solvers might need to find zero-crossing points or the importer uses the Model Exchange FMU to find points of optimal control.
In Co-Simulation, time advances in (possibly variable) steps negotiated between the co-simulation algorithm of the importer and the FMU.
The importer calls fmi3DoStep
with the currentCommunicationPoint
and a target communicationStepSize
(required to be larger than 0.0).
During this fmi3DoStep
, both importer and FMU might encounter events that will reduce the communicationStepSize
(potentially even down to 0.0).
The FMU may use earlyReturn
argument of the fmi3DoStep
function to tell the import that the FMU needs to return earlier, and the importer may use the callback fmi3CallbackIntermediateUpdate
to signal the FMU that the later should return earlier.
This way both can determine if such a step-size reduction is required.
The output argument lastSuccessfulTime
of fmi3DoStep
allows the FMU to signal the importer its current internal time.
In Scheduled Execution, time has a more discrete form.
The scheduler of the importer activates specific tasks according to the time of the importer.
The time itself is communicated to the FMU as activationTime
argument of fmi3ActivateModelPartition
.
Depending on the instantiated FMI type, the importer is restricted in what functions it is allowed to call in order to drive the simulation. The following chapters will focus on what mechanisms are relevant for the interface type at hand, without trying to constantly declare which functions not to use because they belong to the other interface type mechanisms.
2.2.7. Operation on Clocks
In the following section the operations on clocks
are described.
Clocks are defined for the exact timing of evaluations of clocked model partitions and exact timing of event handling across FMUs.
[In FMI 2.0 event detection in a system of FMUs was still done inside each of the FMUs individually with all the issues of floating point arithmetic.
Clocks offer a way to delegate event triggering to the importer to ensure that events meant to trigger at the exact same time will be synchronized across FMUs.]
Two types of clocks
are available, designed to address similar use cases with differences in details.
The clock
type "Synchronous Clocks"" complies with the limitations imposed by the synchronous clock theory, the other clock type "Communication Point Clocks" is a general purpose co-simulation clock for providing suitable communication points for the timed evaluation of model partitions.
The term clock
is used for both clock
types.
2.2.7.1. Synchronous Clocks
[The main use case of synchronous clocks is to facilitate the simulation of systems with:
-
different components whose behavior is triggered at different times by events, and
-
the components that trigger the events are different than the components handling those events.]
[Consider the system in Figure 3:
-
The controller samples the plant at some rate \(r\), and the plant is continuously affected by the actuator values between samples.
-
A supervisor adapts the controller behavior when some criteria on \(u\) is met.
-
When there is a new sample of \(x\), the equations in blue have to be executed synchronously (i.e., at the exact same time).
-
Similarly, when the supervisor decides to update the controller behavior, the equations in purple have to be executed synchronously.
-
\(previous(u_r)\) means the value of \(u_r\) computed at the previous sample by the controller.]
[Figure 4 illustrates a potential behavior of this example. Note that it is the supervisor that decides when to adapt the behavior of the controller, but the controller has to be executed when that happens. Also note that the change in controller behavior should only be reflected on its output when the next sample of the plant is done.]
[In order to understand the problem that synchronous clocks are trying to solve, it helps to try to implement the above system with FMI 2.0 Model Exchange FMUs. Such implementation is illustrated in Figure 5. In this implementation, time and state events can be used to mimic the behavior in Figure 4 with the Sensor FMU or Supervisor FMU driving the simulation into event mode when the events happen.]
[However, this approach poses a big problem: since both Ctrl and Sensor FMUs have time events to sample with frequency \(x\), it is unclear how the importer will guarantee that the two are going to executed in the same event mode. Due to floating point precision, it can happen that the importer takes both FMUs into event mode, but only one knows that it is entering event mode because it has to sample an input variable. It makes it unclear which equations should be executed.]
[This is the problem that synchronous clocks solve. Getting back to the example in Figure 5, by making Ctrl and Sensor share a clock, it will be clear which FMU is triggering the event, and it is easier for them to be executed at the same exact time.]
[Figure 6 illustrates one way to use clocks to realize the system introduced in Figure 3. The red lines denote clock connections. The Ctrl FMU declares an output clock \(r\), and the Sensor and Actuator FMUs declare input clocks, connected to \(r\). This way, the importer knows that when the Ctrl clock \(r\) ticks, then the Sensor and Actuator FMUs will be informed that the clock ticked and execute the corresponding equations.]
[In general:
-
The ticking of an output clock is determined by the FMU that declares it. So in Figure 6, the Supervisor FMU determines the ticking of \(s\) and Ctrl FMU determines the ticking of \(r\). The FMU Ctrl declared both an input clock and an outut clock, and the Sensor and Actuator FMUs both declare an input clock.
-
The ticking of an input clock is signaled by the importer, which in turn will find the source that determines the ticking of such clock.]
A clocked partition is a set of equations that are associated to a clock
and are executed when the corresponding clock
is active.
A clocked partition is mathematically defined as:
[TODO: shouldn’t this be: Claudio: rewrite this to make it clearer: the distinction between these two are just local vars and outputs. Claudio: Also relate to the previous example. Claudio: Also change the modelica sentence. Claudio: Make it clear that clocks are just a way to implement numerically sound event having across different FMUs. ]
Variables \(x_j\) are called states of a clocked partition
, or discrete-time states
and \(j\) is the \(j+1\)th tick of the associated clock
.
Variables \(u_j\) are the (external or local
) inputs
and \(y_j\) are the (external or local
) outputs
of a clocked partition.
A discrete-time state variable can be of any type (e.g. fmi3Float64
or fmi3Boolean
, but not of clock
type).
[TODO: (external or local) is here very confusing]
A clocked partition is not executed during Initialization Mode, but it is executed the first time at its first clock
tick.
The associated clock
of the model partition is synchronous to its discrete-time states.
Discrete-time states are listed in the <ModelStructure>
.
They can have initial values defined by XML attributes initial
and start
, or the initial values are computed internally as a function of the parameters.
There are two kinds of evaluation modes:
-
Regular evaluation for an active
clock
:state
andoutput
equations are evaluated. States get updated. Current input values are taken into account. -
Partial evaluation for a subactive
clock
:states
are left unmodified, only outputs are computed. Current input values are taken into account.[This mode can be used to compute partial derivatives \(\partial y_j / \partial x_{j-1}\) .]
2.2.7.2. Communication Point Clocks
Communication Point Clocks, introduced here, are used to define the communication points of model partitions (defined below).
These clocks
are not compatible with synchronous clock theory and must not be used together with Synchronous Clocks in one model.
A model partition is mathematically defined as:
[TODO: why do we need y_j here? it is not mentioned afterwards]
where:
-
\(x\) denotes the variables that are associated with the model partition. These are the variables that are computed when the model partition is evaluated. Each variable in \(x\) is associated with one, and only one, model partition. Multiple model partitions, when evaluated, may read the value of a single variable, but only one will change it.
-
\(u_j\) denotes the variables that are read, but not changed, when the model partition is evaluated.
-
\(t_j\) denotes the time at which the model partition is evaluated.
-
\(x_{\mathit{start}}\) denotes the start value of the variables that are associated with the model partition. This is the value that has been computed before
fmi3ExitInitializationMode
is called.
Communication Point Clocks can also be defined for continuous or piecewise continuous parts of the model.
Please refer to Section 5.2.3 for an FMU example of scheduled execution.
2.2.7.2.1. Clock Priority
The clocks
are ordered descending based on their priorities.
It is nevertheless possible to define multiple clocks
with the same priority.
No ordering is defined for clocks
of the same priority.
If a computational order information is needed, different priorities for clocks
have to be defined.
The priority of a clock
has to be defined in the modelDescription.xml
via the clock
variable integer attribute priority
- smaller values have a higher priority.
[For periodic
clocks
it is recommended to derive the priorities based on a rate monotonic scheduling scheme (smallest period leads to highest priority, that is, has the smallest priority value.]
[The clock priorities are local to an FMU. It is not possible for an FMU exporting tool to know in advance the priorities of other FMUs that will be connected to an FMU in a simulation setup. It is the task of the simulation algorithm to derive a computational order for the computation of two or more distinct FMUs based on the local FMU clock priorities and input-output relationships of connected FMUs.]
[For real-time computation use cases (e.g., in Scheduled Execution), the priority information is used also for task preemption configurations. It is therefore important to restrict the number of distinct priority levels for an FMU to available priority levels on the target platform and/or to avoid unnecessary computational overhead. A common number of different priority levels is, e.g., 100 (0 to 99), as defined in Linux based operating systems.]
2.2.7.3. Output Clocks
An outputClock
is a general clock
that ticks when a time-, state- or step-event occurs in the continuous-model partition of the FMU (for Communication Point Clocks these outputClock
activations can occur in all model partitions) and are identified based on their valueReference
.
The clock can be periodic
or aperiodic.
[Example: If \(b = x > 0\) , and a state event is defined when b changes from false
to true
, and b is defined as outputClock
, then this clock
is active whenever x changes from negative to positive values.]
Since output clocks
are ticking based on model internal information, it is required in case of FMI for Co-Simulation to signal the ticking of an outputClock
to the simulation environment during a fmi3DoStep
or fmi3ActivateModelPartition
computation.
In most cases [TODO: not all cases? which cases? if the time of the clock tick is a communication point already?] the signaling of an outputClock
tick requires creating a communication point for exchanging additional information (i.e. variable values) with the simulation environment.
Additional cases need to be handled if a clock
tick is not associated to an event that requires the creation of a communication point for the model partition that generated the event. [TODO: what?]
[Outside of the FMU it is not known in advance when this clock
ticks.
Instead, only when the clock
is activated by the FMU, then the environment is informed that the clock
ticks at this time instant.
It is the task of the environment to handle the messaged events appropriately based on the clockReference
information.
Example:
]
[TODO: local clocks should be introduced here too, they are just used afterwards. Issue 1172 will address the definition of local variables (including local clocks). Then we can introduce a section here on local clocks. ]
2.2.7.4. Input Clocks
An inputClock
is a periodic
or aperiodic clock
that is defined by a clock
outside of the FMU.
I.e., only when the clock
is activated by the environment of the FMU, then the FMU is informed that the clock
ticks at this time instant.
An input clocks must be independent to all other input clocks.
_[TODO: what does that mean?]
If dependent clocks exist, they can be exposed as local
or output
clocks.
[ TODO: Claudio: Explain why we have periodic clocks: because of the numerical problems. ]
2.2.7.5. Clock Unions
It is possible for an inputClock
to depend on an outputClock
of the same FMU using the triggeredBy
attribute of inputClock
variables.
An output clock
and the associated input clocks
define a clocks union to indicate that the outputClock
triggers the associated input clocks
at the same time instant.
It is only meaningful to combine an output clock
with an aperiodic inputClock
.
It is possible to define multiple unions of clocks
.
An input clock
may be contained in at most one clock union [naturally limited by the single triggeredBy
attribute].
An output clock
can be part of multiple clock unions.
Clock unions are needed to allow for an external scheduler to achieve an optimal control of model partitions and are applicable to both Synchronous Clocks and Communication Point Clocks and therefore apply to ME, CS and SE. [TODO: ??? model partitions only belong to Communication point clocks, how can this be true?? Claudio: - the FMU needs a mechanism to tell the importer that the FMU needs to go into event iteration when its own output clock ticks. It’s just a mechanism for the FMU to use its own output clocks as an input clock without having to rely on the master. - The importer need to trigger explicitly that input clock (refer to input clock section) after the output clock ticks. - Replace table by "Only aperiodic input clocks can be part of a union.". ] [TODO: Does the importer have to activate the corresponding input clocks???]
The following table lists which inputClock
variants can be combined with which outputClock
variants:
Input clock variant |
Output clock variant |
aperiodic |
aperiodic, periodic, strictly periodic |
periodic |
- |
strictly periodic |
- |

_[TODO: This example is given here out of context. Shouldn’t this be at SE? The text of of the figure should be normal text and. What is a Heider model? Claudio: remove it. ]
2.2.7.6. Dependent Output Clocks
If an outputClock
depends on an inputClock
, the attribute clockReference
is used to indicate that the outputClock
may (but does not have to) tick if and only if the referenced inputClock
ticks.
An outputClock
may depend on other unknowns, see the attribute dependencies
.
2.2.7.7. Periodic Clock Ticks
Either output
or input
, a periodic
clock
ticks at equidistant sample time points that are known a priori (defined in modelDescription.xml
) or are alternatively determined by the environment in case of input clocks
.
[TODO: A periodic
output
clock
ticks at a priori equidistant time points.
The ticks of a periodic
input
clock
are given by the importer.
FMI Design meeting: merge this sentence with the previous one.
Missing the relationship to strict clocks.]
Mathematically, the next clock
tick at time instant \(t_i\) is defined as:
where:
\(t_0\) |
The time instant in seconds at which the |
\(t_{i-1}\) |
The previous time instant in seconds, where the |
\(\Delta T > 0\) |
The constant time interval from the previous |
The interval \(\Delta T\) and \(t_{\mathit{offset}}\) must be defined for periodic
clocks
in the XML file.
In case of periodic
input clocks
these values are the start interval values if they are not given by the simulation algorithm.
[This information can be used for emulating periodic
input clocks
in FMI for Co-Simulation.].
[TODO: shouldn’t we use constant and fixed like for other variable variabilities (strictly periodic = constant periodic; periodic = fixed periodic; aperiodic = tunable periodic! TorstenBlochwitz will start an issue to collect use cases to clarify clock use.) Does the importer have to call fmi3SetInterval for aperiodic clocks at each clock tick if the clock should tick with the same interval? Or will there be only one clock tick per fmi3SetInterval call? FMI Design meeting: remark that set interval functions are informative to design model based controllers. The environment is the one that will tick. ]
A clock
is strictly periodic
if \(\Delta T\) is fixed for an FMU and cannot be changed.
The clock
is periodic, if \(\Delta T\) can be defined before calling fmi3EnterInitializationMode
via fmi3SetIntervalDecimal
or fmi3SetIntervalFraction
.
The clock
is aperiodic if \(\Delta T\) is not constant during a simulation run (fmi3SetIntervalDecimal
or fmi3SetIntervalFraction
can be called for that clock
during Event Mode).
2.2.7.8. Connecting Clocked FMUs
When connecting imported FMUs, input
and output
variables can readily be connected only when they are defined on a clock
with identical properties.
If this is not possible, an explicit cast of one clock
to another clock
is typically defined in the environment.
[TODO: What is a clock cast? If a clock cast can be done by the environment anyway, why mention which inputs/outputs can be connected? Remove the entire section: we do not want to say: don’t be stupid.]
The environment can evaluate required clock
casts for connections using the information on the clockReference
attribute of assigned variables [i.e. the variables that are assigned to a clock
based on modelDescription.xml
information].
[Example: Elementary blocks like a PI controller will have all variables on an inputClock
with identical properties.
Connecting such blocks together will therefore be possible without computationally expensive clock cast operations (and the environment can readily do the computation of assigned variables of the connected blocks based on the same clock
).]
2.2.7.9. Setting and Getting Clock Activation State
A clock
is activated by the environment for the current time instant by the function fmi3SetClock
, and the status of a clock
can be inquired with the function fmi3GetClock
:
typedef fmi3Status fmi3SetClockTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Clock values[],
const fmi3Boolean subactive[],
size_t nValues);
Sets clocks
activation status by providing the value references of the corresponding clock
variables and their values.
Note that clock
variables, like any other variables can be scalar or array variables.
(The serialization of variables is described in Section 2.2.5.1.)
-
valueReferences
is a vector ofnValueReferences
value handles that define the clock variables that shall be set. -
values
is a vector with the actual activation values of the clock variables,fmi3ClockActive
specifying that the clock is activated, otherwise it is deactivated. -
subactive
requires evaluation of a clocked partition in subactive mode (only output equations, no states change) if the argument subactive is not a null pointer andsubactive[i] = fmi3True
.subactive[i]
has no meaning for Communication Point Clocks and is ignored for suchclocks
. -
nValues
provides the number of values in thevalues
andsubactive
(if not null) vectors, which is only equal tonValueReferences
if allvalueReferences
point to scalar clock variables.
It is not allowed to call this function within the callback function intermediateUpdate
.
typedef fmi3Status fmi3GetClockTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Clock values[],
size_t nValues);
Inquires whether a set of clocks
is active by providing the value references of the corresponding clock
variables.
-
valueReferences
is a vector ofnValueReferences
value handles that define the clock variables that shall be inquired. -
values
will return the activation status at the current time instant of theclocks
referenced byvalueReferences[]
. Ifvalues[i] == fmi3ClockActive
theclock
is currently active, otherwise theclock
is not active. -
nValues
provides the number of values in thevalues
vector, which is only equal tonValueReferences
if allvalueReferences
point to scalar clock variables.
It is required for an FMU to directly internally set back the activation state
of an output clock[i] to fmi3ClockInactive
, if the function fmi3GetClock
is called for a clock[i]
and the interface is Scheduled Execution.
[This is required to allow preemption.]
[TODO: WHAT? Separate issue to discuss needs of preemption. Link to example. This is necessary but nor sufficient requirement for preemption. Pick better name for the Getting to show that the clock is auto-reset. ]
A clock
interval is set by the environment for the current time instant by the function fmi3SetIntervalDecimal
or fmi3SetIntervalFraction
, and it can be inquired with the function fmi3GetIntervalDecimal
or fmi3GetIntervalFraction
:
typedef fmi3Status fmi3SetIntervalDecimalTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Float64 interval[],
size_t nValues);
typedef fmi3Status fmi3SetIntervalFractionTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3UInt64 intervalCounter[],
const fmi3UInt64 resolution[],
size_t nValues);
typedef fmi3Status fmi3GetIntervalDecimalTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3Float64 interval[],
size_t nValues);
typedef fmi3Status fmi3GetIntervalFractionTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
fmi3UInt64 intervalCounter[],
fmi3UInt64 resolution[],
size_t nValues);
Both functions inquire the interval value for the provided clocks
(periodic
or aperiodic).
If the clocks
are aperiodic, the interval has to be inquired at every clock
tick, to define the follow-up clock
tick.
The following table summarizes the use of the API functions by the environment for different kinds of clocks
:
API function |
||
|
Call during Event Mode and only in SE in Intermediate Update Mode. |
Not allowed |
|
Not allowed |
Call after entering Event Mode. Repeated calls if recomputations of clock state are needed during Event Mode. |
|
Call during Event Mode and only in SE in Intermediate Update Mode. |
Not allowed |
|
Not allowed |
Call after first |
2.2.8. Getting Partial Derivatives
It is optionally possible to provide evaluation of partial derivatives for an FMU. For Model Exchange, this means computing the partial derivatives at any time instant, whereas for Co-Simulation, this means computing the partial derivatives at a communication point.
An FMU has different states and in every state an FMU might be described by different equations and different unknowns. The precise definitions are given in the mathematical descriptions of Model Exchange (Section 3.1) and Co-Simulation (Section 4.1). In every state, the general form of the FMU equations are:
where
-
\(\mathbf{v}_{\mathit{unknonwn}}\) is the vector of unknown floating point variables computed in the actual state:
-
Initialization Mode: The exposed unknowns listed as elements
<ModelStructure><InitialUnknown>
that have a floating point type. -
Continuous-Time Mode (Model Exchange): The continuous-time outputs and state derivatives (= the variables listed as elements
<ModelStructure><Output>
with a floating point type andvariability
=continuous
and the variables listed as elements<ModelStructure><Derivative>
). -
Event Mode (Model Exchange): The same variables as in the Continuous-Time Mode and additionally variables listed as elements
<ModelStructure><Output>
with a floating point type andvariability
=discrete
. -
Step Mode (Co-Simulation): The variables listed as elements
<ModelStructure><Output>
with a floating point type andvariability
=continuous
ordiscrete
. Each state derivative variable listed as elements<ModelStructure><Derivative>
, if present.
-
-
\(\mathbf{v}_{\mathit{known}}\) is the vector of known floating point
input
variables of function h that changes its value in the actual state. Details about which variables are in \(\mathbf{v}_{\mathit{known}}\) are given in the description of elementdependencies
in Section 2.4.9. -
\({\mathbf{v}_{\mathit{rest}}}\) is the set of
input
variables of function h that either changes its value in the actual state but are non-floating point variables, or do not change their values in this state, but change their values in other states [for example, discrete-timeinputs
in Continuous-Time Mode].
[The variable relationships are different in different states.
For example, during Continuous-Time Mode, a continuous-time output y does not depend on discrete-time inputs
(because they are held constant between events).
However, at Event Mode, y depends on discrete-time inputs
.
The function may compute the directional derivatives by numerical differentiation taking into account the sparseness of the equation system, or (preferred) by analytic derivatives.]
There are two access functions for partial derivatives:
-
fmi3GetDirectionalDerivative
to compute the directional derivatives \(\mathbf{v}_{\mathit{sensitivity}} = \mathbf{J} \cdot \mathbf{v}_{\mathit{seed}}\), and -
fmi3GetAdjointDerivative
to calculate the adjoint derivatives \(\mathbf{v}_{\mathit{sensitivity}}^T = \mathbf{v}_{\mathit{seed}}^T \cdot \mathbf{J}\)
with the Jacobian
where \(\mathbf{v}_{\mathit{known}}\) are the \(n\) knowns, and \(\mathbf{h}\) are the \(m\) functions to calculate the \(m\) unknwon variables \(\mathbf{v}_{\mathit{unknwon}}\) from the knowns.
Both functions can also be used to construct the partial derivative matrices.
The functions may only be called if their availability is indicated by the attributes providesDirectionalDerivatives
and providesAdjointDerivatives
respectively.
typedef fmi3Status fmi3GetDirectionalDerivativeTYPE(fmi3Instance instance,
const fmi3ValueReference unknowns[],
size_t nUnknowns,
const fmi3ValueReference knowns[],
size_t nKnowns,
const fmi3Float64 seed[],
size_t nSeed,
fmi3Float64 sensitivity[],
size_t nSensitivity);
typedef fmi3Status fmi3GetAdjointDerivativeTYPE(fmi3Instance instance,
const fmi3ValueReference unknowns[],
size_t nUnknowns,
const fmi3ValueReference knowns[],
size_t nKnowns,
const fmi3Float64 seed[],
size_t nSeed,
fmi3Float64 sensitivity[],
size_t nSensitivity);
Both functions have the same arguments:
-
unknowns
contains value references to the unknowns. -
nUnknowns
contains the length of argumentunknowns
. -
knowns
contains value references of the knowns. -
nKnowns
contains the length of argumentknowns
. -
seed
contains the components of the seed vector. -
nSeed
contains the length ofseed
. -
sensitivity
contains the components of the sensitivity vector. -
nSensitivity
contains the length ofsensitivity
.
[Note that array variables will be serialized, so nSeed
is only equal to nKnowns
in the case of directional derivatives (resp., equal to nUnknowns
in the case of adjoint derivatives) if all value references of knowns
(resp., unknowns
) point to scalar variables.
Likewise nSensitivity
is only equal to nUnknowns
(resp., nKnowns
) if all value references of unknowns
(resp., knowns
) point to scalar variables.]
2.2.8.1. Directional Derivatives
[Example:
Assume an FMU has the output equations
and this FMU is connected, so that \({y_1, u_1, u_3}\) appear in an algebraic loop.
Then the nonlinear solver needs a Jacobian and this Jacobian can be computed (without numerical differentiation) provided the partial derivative of \({y_1}\) with respect to \({u_1}\) and \({u_3}\) is available.
Depending on the environment where the FMUs are connected, these derivatives
can be provided:
(a) with one wrapper function around function fmi3GetDirectionalDerivative
to compute the directional derivatives with respect to these two variables (in other words, \({v_{\mathit{unknown}} = y_1}\), \({v_{\mathit{known}} = \left \{ u_1, u_3 \right \}}\)), and then the environment calls this wrapper function with \({v_{\mathit{seed}} = \left \{ 1, 0 \right \}}\) to compute the partial derivative with respect to \({u_1}\) and \({v_{\mathit{seed}} = \left \{ 0, 1 \right \}}\) to compute the partial derivative with respect to \({u_3}\), or
(b) with two direct function calls of fmi3GetDirectionalDerivative
(in other words, \({v_{\mathit{unknown}} = y_1, v_{\mathit{known}} = u_1, v_{\mathit{seed}} = 1}\); and \({v_{\mathit{unknown}} = y_1, v_{\mathit{known}} = u_3, v_{\mathit{seed}} = 1}\)).
Note that a direct implementation of this function with analytic derivatives:
(a) Provides the directional derivative for all input
variables; so in the above example: \({\Delta y_1 = \frac{\partial g_1}{\partial x} \cdot \Delta x + \frac{\partial g_1}{\partial u_1} \cdot \Delta u_1 + \frac{\partial g_1}{\partial u_3} \cdot \Delta u_3 + \frac{\partial g_1}{\partial u_4} \cdot \Delta u_4}\)
(b) Initializes all seed-values to zero; so in the above example: \({\Delta x = \Delta u_1 = \Delta u_3 = \Delta u_4 = 0}\)
(c) Computes the directional derivative with the seed-values provided in the function arguments; so in the above example: \({v_{\mathit{sensitivity}} = \Delta y_1 (\Delta x = 0, \Delta u_1 = 1, \Delta u_3 = 0, \Delta u_4 = 0)}\)] and \({v_{\mathit{sensitivity}} = \Delta y_1 (\Delta x = 0, \Delta u_1 = 0, \Delta u_3 = 1, \Delta u_4 = 0)}\)]
[Note, function fmi3GetDirectionalDerivative
can be utilized for the following purposes:
-
Numerical integrators of stiff methods need matrix \({\frac{\partial \mathbf{f}}{\partial \mathbf{x}}}\).
-
If the FMU is connected with other FMUs, the partial derivatives of the state derivatives and outputs with respect to the continuous states and the
inputs
are needed in order to compute the Jacobian for the system of the connected FMUs. -
If the FMU shall be linearized, the same
derivatives
as in the previous item are needed. -
If the FMU is used as the model for an extended Kalman filter, \({\frac{\partial \mathbf{f}}{\partial \mathbf{x}}}\) and \({\frac{\partial \mathbf{g}}{\partial \mathbf{x}}}\) are needed.
If a dense matrix shall be computed, the columns of the matrix can be easily constructed by successive calls of fmi3GetDirectionalDerivative
.
For example, constructing the system Jacobian \({\mathbf{A} = \frac{\partial \mathbf{f}}{\partial \mathbf{x}}}\) as dense matrix can be performed in the following way:
// c[] column vector
// set time, states and inputs
CHECK_STATUS(fmi3SetTime(m, time))
CHECK_STATUS(fmi3SetContinuousStates(m, x, nx))
// fmi3Set{VariableType}(m, ...)
// if required at this step, compute the Jacobian as a dense matrix
for (i = 0; i < nx; i++) {
// construct the Jacobian matrix column wise
CHECK_STATUS(fmi3GetDirectionalDerivative(m, vr_dx, nx, &vr_x[i], 1, &dk, 1, c, nx))
for (j = 0; j < nx; j++) {
J[j][i] = c[j];
}
}
If the sparsity of a matrix shall be taken into account, then the matrix can be constructed in the following way:
-
The incidence information of the matrix (whether an element is zero or not zero) is extracted from the XML file from element
<ModelStructure>
. -
A so called graph coloring algorithm is employed to determine the columns of the matrix that can be computed by one call of
fmi3GetDirectionalDerivative
. Efficient graph coloring algorithms are freely available, such as library ColPack written in C/C++ (LGPL), or the routines by [CGM84]. See e.g. http://www.netlib.org/toms/618. -
For the columns determined in (2), one call to
fmi3GetDirectionalDerivative
is made. After each such call, the elements of the resulting directional derivative vector are copied into their correct locations of the partial derivative matrix.
More details and implementational notes are available from [ABL12].
Example:
Directional derivatives for higher dimension variables are almost treated in the same way. Consider, for example, an FMU which calculates its output \({Y}\) by multiplying its 2x2 input \({U}\) with a 3x2 constant gain \({K}\), with
The output \({Y=K U}\) is a matrix of size 3x2. The directional derivative of an output element \({Y(i,j)}\) with respect to the input \({U}\) and the seed \({\Delta U}\) is:
To get the directional derivative of \({Y}\) with respect to \({U(2,1)}\) the command fmi3GetDirectionalDerivative(m, vr_Y, 1, vr_U, 1, {0.0, 0.0, 1.0, 0.0}, 4, dd, 6)
can be used where vr_Y
and vr_U
are references of the variable \({Y}\) and \({U}\), respectively.
Note that in order to get the directional derivative of \({Y}\) with respect to \({U(2,1)}\), the seed value {0, 0, 1.0, 0}
has been used.
The retrieved directional derivative dd
is stored in a matrix of size 3x2, so nSensitivity
is 6.
2.2.8.2. Adjoint Derivatives
[Adjoint derivatives are beneficial in several contexts:
-
in artificial intelligence (AI) frameworks the adjoint derivatives are called "vector gradient products" (VJPs). There adjoint derivatives are used in the backpropagation process to perform gradient-based optimization of parameters using reverse mode automatic differentiation (AD), see, e.g., [BPRS15].
-
in parameter estimation (see [BKF17])
Typically, reverse mode automatic differentiation (AD) is more efficient for these use cases than forward mode AD, as explained in the cited references.
If one would like to construct the full Jacobian matrix, one can use either fmi3GetDirectionalDerivative
(to column-wise construct it) or fmi3GetAdjointDerivative
(to row-wise construct it, possibly improved with coloring methods as mentioned above).
However in the applications motivating the adjoint derivatives, one does not need the full Jacobian matrix \(\mathbf{J}\), but vector \(\mathbf{v}^T\) multiplied from the left to the Jacobian, i.e. \(\mathbf{v}^T\mathbf{J}\).
For computing the full Jacobian matrix, the column-wise construct is generally more efficient.]
Example:
Assume an FMU has the output equations
and \(\left( w_1, w_2 \right)^T \cdot \mathbf{ \frac{\partial h}{\partial u} }\) for some vector \(\left( w_1, w_2 \right)^T\) is needed.
Then one can get this with one function call of fmi3GetAdjointDerivative
(with arguments \(\mathbf{v}_{\mathit{unknown}} = \text{valueReferences of} \left \{ y_1, y_2 \right \}, \mathbf{v}_{\mathit{known}} = \text{valueReferences of} \left \{ u_1, u_2 \right \}, \mathbf{v}_{\mathit{seed}} = \left( w_1, w_2 \right)^T\) ), while with fmi3GetDirectionalDerivative
at least two calls would be necessary to first construct the Jacobian column-wise and then multiplying from the right with \(\left( w_1, w_2 \right)^T\) .
If a dense matrix shall be computed, the rows of the matrix can be easily constructed by successive calls of fmi3GetAdjointDerivative
.
For example, constructing the system Jacobian \({\mathbf{A} = \frac{\partial \mathbf{f}}{\partial \mathbf{x}}}\) as a dense matrix can be performed in the following way:
for (i = 0; i < nx; i++) {
// construct the Jacobian matrix column wise
CHECK_STATUS(fmi3GetAdjointDerivative(m, &vr_dx[i], 1, vr_x, nx, &dk, 1, &J[i][0], nx))
}
]
2.2.9. Getting Number of Variable Dependencies and Variable Dependencies
The sparseness information within arrays is not given in the xml description.
The sparseness muss be retrieved during run-time using the C-API functions.
Zeros in the Jacobian are not necessarily due to the structure of the model.
Zero in the Jacobian might be due to the current operating point (current state
, current inputs
) and not due to a structural independence.
The variable dependency information in the XML description does not resolve to dependencies of individual array elements, nor does it take into account changing dependencies due to resizing of arrays via structural parameters
.
An FMU can indicate via the providesPerElementDependencies
capability flag that it is able to provide detailed dependency information at runtime through the following C-API.
Note that these functions are only defined if the capability flag providesPerElementDependencies = true
.
The number of dependencies of a given variable, which may change if structural parameters
are changed, can be retrieved by calling the following function:
typedef fmi3Status fmi3GetNumberOfVariableDependenciesTYPE(fmi3Instance instance,
fmi3ValueReference valueReference,
size_t* nDependencies);
This function returns the number of dependencies
for a given variable.
-
valueReference
specifies thevalueReference
of the variable for which the number ofdependencies
should be returned. -
nDependencies
points to thesize_t
variable that will receive the number ofdependencies
.
The actual dependencies
(of type fmi3DependencyKind
) can be retrieved by calling the function fmi3GetVariableDependencies
:
typedef enum {
/* fmi3Independent = 0, not needed but reserved for future use */
fmi3Constant = 1,
fmi3Fixed = 2,
fmi3Tunable = 3,
fmi3Discrete = 4,
fmi3Dependent = 5
} fmi3DependencyKind;
typedef fmi3Status fmi3GetVariableDependenciesTYPE(fmi3Instance instance,
fmi3ValueReference dependent,
size_t elementIndicesOfDependent[],
fmi3ValueReference independents[],
size_t elementIndicesOfIndependents[],
fmi3DependencyKind dependencyKinds[],
size_t nDependencies);
This function returns the dependency information for a single variable.
-
dependent
specifies thevalueReference
of the variable for which the dependencies should be returned. -
nDependencies
specifies the number of dependencies that the calling environment allocated space for in the result buffers, and should correspond to value obtained by callingfmi3GetNumberOfVariableDependencies
. -
elementIndicesOfDependent
must point to a buffer ofsize_t
values of sizenDependencies
allocated by the calling environment. It is filled in by this function with the element index of the dependent variable that dependency information is provided for. The element indices start with 1. Using the element index 0 means all elements of the variable. (Note: If an array has more than one dimension the indices are serialized in the same order as defined for values in Section 2.2.5.1.) -
independents
must point to a buffer offmi3ValueReference
values of sizenDependencies
allocated by the calling environment. It is filled in by this function with the value reference of theindependent
variable that this dependency entry is dependent upon. -
elementIndicesIndependents
must point to a buffer ofsize_t
values of sizenDependencies
allocated by the calling environment. It is filled in by this function with the element index of theindependent
variable that this dependency entry is dependent upon. The element indices start with 1. Using the element index 0 means all elements of the variable. (Note: If an array has more than one dimension the indices are serialized in the same order as defined for values in Section 2.2.5.1.) -
dependencyKinds
must point to a buffer offmi3DependencyKind
values of sizenDependencies
allocated by the calling environment. It is filled in by this function with the enumeration value describing the dependency of this dependency entry.
If this function is called before the fmi3ExitInitializationMode
call, it returns the initial dependencies.
If this function is called after the fmi3ExitInitializationMode
call, it returns the run-time dependencies.
The retrieved dependency information of one variable becomes invalid as soon as a structural parameter
linked to the variable or to any of its depending variables are set.
As a consequence, if you change structural parameters
affecting B or A, the dependency of B becomes invalid.
The dependency information must change only if structural parameters
are changed.
2.3. State Machine and Semantics
All FMI interface types share a number of states in their respective state machines. This chapter describes these common modes. FMI specific state-machine modes will be described in their respective chapters.
2.3.1. Super State: FMU State Setable
The description of the super state FMU State Setable generally describes functions that deal with instantiation, destruction and logging of FMUs.
This state is entered when any of the following functions is called: fmi3InstantiateModelExchange
, fmi3InstantiateCoSimulation
and fmi3InstantiateScheduledExecution
.
The state is left by either calling fmi3FreeInstance
or when any of the functions called during FMU State Setable returns fmi3Fatal
.
If any function called in super state FMU State Setable returns fmi3Error
, the FMU enters state Terminated.
- Allowed Function Calls
- Function
fmi3InstantiateModelExchange
-
FMU with initialization and events; between events, the simulation of continuous systems is performed with external integrators from the environment (see Section 3). The
modelDescription.xml
has to include a<ModelExchange>
element to allow callingfmi3InstantiateModelExchange
.
- Function
fmi3InstantiateCoSimulation
-
Black box interface for Co-Simulation (see Section 4). The
modelDescription.xml
has to include a<CoSimulation>
element to allow callingfmi3InstantiateCoSimulation
.
- Function
fmi3InstantiateScheduledExecution
-
Black box interface for Scheduled Execution (see Section 5). The
modelDescription.xml
has to include a<ScheduledExecution>
element to allow callingfmi3InstantiateScheduledExecution
.
typedef fmi3Instance fmi3InstantiateModelExchangeTYPE(
fmi3String instanceName,
fmi3String instantiationToken,
fmi3String resourceLocation,
fmi3Boolean visible,
fmi3Boolean loggingOn,
fmi3InstanceEnvironment instanceEnvironment,
fmi3CallbackLogMessage logMessage);
typedef fmi3Instance fmi3InstantiateCoSimulationTYPE(
fmi3String instanceName,
fmi3String instantiationToken,
fmi3String resourceLocation,
fmi3Boolean visible,
fmi3Boolean loggingOn,
fmi3Boolean eventModeUsed,
const fmi3ValueReference requiredIntermediateVariables[],
size_t nRequiredIntermediateVariables,
fmi3InstanceEnvironment instanceEnvironment,
fmi3CallbackLogMessage logMessage,
fmi3CallbackIntermediateUpdate intermediateUpdate);
typedef fmi3Instance fmi3InstantiateScheduledExecutionTYPE(
fmi3String instanceName,
fmi3String instantiationToken,
fmi3String resourceLocation,
fmi3Boolean visible,
fmi3Boolean loggingOn,
const fmi3ValueReference requiredIntermediateVariables[],
size_t nRequiredIntermediateVariables,
fmi3InstanceEnvironment instanceEnvironment,
fmi3CallbackLogMessage logMessage,
fmi3CallbackIntermediateUpdate intermediateUpdate,
fmi3CallbackLockPreemption lockPreemption,
fmi3CallbackUnlockPreemption unlockPreemption);
These functions return a new instance of an FMU with the respective interface type.
If a null pointer is returned, then instantiation failed.
In that case, logMessage
is called with detailed information about the reason.
An FMU can be instantiated many times (provided capability flag canBeInstantiatedOnlyOncePerProcess = false
).
The arguments of the instantiation functions are detailed as follows:
-
instanceName
is a unique identifier for the FMU instance. It is used to name the instance, for example, in error or information messages generated by one of thefmi3XXX
functions. The argumentinstanceName
must be a non empty string (in other words, must have at least one character that is not a white space). [If only one FMU is simulated, asinstanceName
attributemodelName
or<ModelExchange|CoSimulation|ScheduledExecution modelIdentifier="..">
from the XML schemafmi3ModelDescription
might be used.] -
instantiationToken
can be used by the FMU to check that themodelDescription.xml
file (see Section 2.5) is compatible with the implementation of the FMU. It is an opaque string generated by the FMU exporter that is stored in the xml file as mandatory attributeinstantiationToken
(see Section 2.4.1). It must be passed unchanged to the FMU. This argument must not be a null pointer.
-
resourceLocation
is a URI according to the IETF RFC3986 syntax to indicate the location to theresources
directory of the unzipped FMU archive. The following schemes must be understood by the FMU:-
Mandatory —
file
with absolute path (either including or omitting the authority component); -
Optional —
http
,https
,ftp
.
[Example: An FMU is unzipped in directory
C:\temp\MyFMU
, thenresourceLocation
=file:///C:/temp/MyFMU/resources
orfile:/C:/temp/MyFMU/resources
.
Thefmi3InstantiateXXX
functions are then able to read all needed resources from this directory, for example maps or tables used by the FMU.]
A NULL pointer is supplied forresourceLocation
, if no resource location can be provided to the FMU, which may occur-
if the FMU does not contain a resources folder, or
-
if the environment is not able to provide an URI to the resources folder [e.g., if the environment does not have a file system. If the FMU in such a case cannot be simulated, as it depends on the resources folder, it shall terminate with an error.]
-
-
visible == fmi3False
defines that the interaction with the user should be reduced to a minimum (no application window, no plotting, no animation, etc.). In other words, the FMU is executed in batch mode. Ifvisible == fmi3True
, the FMU is executed in interactive mode, and the FMU might require to explicitly acknowledge start of simulation / instantiation / initialization (acknowledgment is non-blocking). -
If
loggingOn == fmi3False
, then any logging is disabled and thelogMessage
callback function is not called by the FMU. IfloggingOn == fmi3True
, the FMU enables a vendor defined set of<LogCategories>
. This set should typically contain categories for messages that explain execution errors, likefmi3Discard
,fmi3Error
andfmi3Fatal
. The functionfmi3SetDebugLogging
gives more detailed control about required<LogCategories>
(see Section 2.4.5). -
If
eventModeUsed == fmi3True
the simulation algorithm can handle events, otherwisefmi3EnterEventMode
must not be called. The flag may only befmi3True
, ifhasEventMode == true
, otherwise the FMU must raise an error. For FMUs that have synchronous clocks,eventModeUsed == fmi3True
is required. -
instanceEnvironment
is a pointer that can be passed to thefmi3CallbackIntermediateUpdate
function in order that the simulation environment can provide an efficient way to identify the FMU that calledfmi3CallbackIntermediateUpdate
.
-
requiredIntermediateVariables
is an array of the value references of allinput
variables that the simulation algorithm intends to set and alloutput
variables it intends to get during intermediate updates. This set may be empty (nRequiredIntermediateVariables
== 0) when the simulation algorithm does not intend to use intermediate update. All variables referenced in this set must be marked with the attributeintermediateUpdate = "true"
in the model description. Only the variables inrequiredIntermediateVariables
may be accessed by the simulation algorithm usingfmi3Set{VariableType}
andfmi3Get{VariableType}
duringfmi3CallbackIntermediateUpdate
callbacks.
-
nRequiredIntermediateVariables
gives the number of entries inrequiredIntermediateVariables
. IfnRequiredIntermediateVariables
is zerorequiredIntermediateVariables
is not defined.
The arguments logMessage
, intermediateUpdate
, lockPreemption
, and unlockPreemption
, are function pointers provided by the simulation environment to be used by the FMU.
It is not allowed to change these functions between fmi3InstantiateXXX
and fmi3Terminate
calls.
Additionally, a pointer to the environment is provided (instanceEnvironment
) that needs to be passed to all of the callback functions, in order that those functions can utilize data from the environment, such as mapping a valueReference
to a string, or assigning memory to a certain FMU instance.
In the default fmi3FunctionTypes.h
file, typedefs for the function definitions are present to simplify the usage; this is non-normative.
These callback functions are defined below.
- Callback function
logMessage
typedef void (*fmi3CallbackLogMessage) (fmi3InstanceEnvironment instanceEnvironment,
fmi3String instanceName,
fmi3Status status,
fmi3String category,
fmi3String message);
Pointer to a function that is called in the FMU [usually if an fmi3XXX
function does not behave as desired].
-
instanceName
is the instance name of the model that calls this function. -
status
contains the severity of the message, seefmi3Status
. IflogMessage
is called withstatus == fmi3OK
, then the message is a pure information message. -
category
is the category of the message. The meaning ofcategory
is defined by the modeling environment that generated the FMU. Depending on this modeling environment, none, some, or all, allowed values ofcategory
for this FMU are defined in themodelDescription.xml
file via element<fmiModelDescription><LogCategories>
, see Section 2.4.5. Only messages are provided by functionlogMessage
that have a category according to a call tofmi3SetDebugLogging
. -
message
is a string that contains the message. [Typically, this function prints the message and stores it optionally in a log file.]
All string-valued arguments passed by the FMU to the logMessage
may be deallocated by the FMU directly after function logMessage
returns.
The simulation environment must therefore create copies of these strings if it needs to access these strings later.
The logMessage
function will append a line break to each message when writing messages after each other to a terminal or a file (the messages may also be shown in other ways, for example, as separate text-boxes in a GUI).
The caller may include line-breaks (using "\n") within the message, but should avoid trailing line breaks.
Variables can be referenced in a message with #<ValueReference>#
.
If the character #
shall be included in the message, it has to be prefixed with #
, so #
is an escape character.
[Example: The message #1365# must be larger than zero (used in IO channel ##4)
might be changed by the logMessage
function to body.m must be larger than zero (used in IO channel #4)
if body.m
is the name of the variable with value reference 1365.]
- Callback function
intermediateUpdate
-
See
fmi3CallbackIntermediateUpdate
for details. - Callback function
lockPreemption
andunlockPreemption
-
See Section 5.2.2 for details.
- Function
fmi3SetDebugLogging
typedef fmi3Status fmi3SetDebugLoggingTYPE(fmi3Instance instance,
fmi3Boolean loggingOn,
size_t nCategories,
const fmi3String categories[]);
The function controls debug logging that is output via the logMessage
callback function.
-
If
loggingOn == fmi3True
, debug logging is enabled, otherwise it is switched off. -
nCategories
defines the length of the next argumentcategories
IfloggingOn == fmi3True
andnCategories == 0
, then all debug messages shall be output. IfloggingOn == fmi3True
andnCategories > 0
, then only debug messages according to thecategories
argument shall be printed via thelogMessage
function. -
categories
is a vector withnCategories
elements. The allowed values ofcategories
are defined by the modeling environment that generated the FMU. Depending on the generating modeling environment, none, some or all allowed values forcategories
for this FMU are defined in themodelDescription.xml
file via element<fmiModelDescription><LogCategories>
, see Section 2.4.5.
- Function
fmi3Reset
typedef fmi3Status fmi3ResetTYPE(fmi3Instance instance);
Is called by the environment to reset the FMU after a simulation run.
The FMU goes into the same state as if fmi3InstantiateXXX
would have been called.
All variables have their default values.
Before starting a new run fmi3EnterInitializationMode
has to be called.
- Function
fmi3Terminate
typedef fmi3Status fmi3TerminateTYPE(fmi3Instance instance);
Changes state to Terminated.
After calling this function, the final values of all variables can be inquired with the fmi3Get{VariableType}
functions.
It is not allowed to call this function after one of the functions returned with a status flag of fmi3Error
or fmi3Fatal
.
- Function
fmi3FreeInstance
typedef void fmi3FreeInstanceTYPE(fmi3Instance instance);
Disposes the given instance, unloads the loaded model, and frees all the allocated memory and other resources that have been allocated by the functions of the FMU interface.
If a null pointer is provided for argument instance
, the function call is ignored (does not have an effect).
- Getting and Setting the Complete FMU State
The FMU has an internal state consisting of all values that are needed to continue a simulation.
This internal state consists especially of the values of the continuous-time states, iteration variables, parameter
values, input
values, delay buffers, file identifiers, and FMU internal status information.
With the functions of this section, the internal FMU state can be copied and the pointer to this copy is returned to the environment.
The FMU state copy can be set as actual FMU state, in order to continue the simulation from it.
[Examples for using this feature:
For variable step-size control of co-simulation algorithms (get the FMU state for every accepted communication step; if the follow-up step is not accepted, restart co-simulation from this FMU state).
For nonlinear Kalman filters (get the FMU state just before initialization; in every sample period, set new continuous states from the Kalman filter algorithm based on measured values; integrate to the next sample instant and inquire the predicted continuous states that are used in the Kalman filter algorithm as basis to set new continuous states).
For nonlinear model predictive control (get the FMU state just before initialization; in every sample period, set new continuous states from an observer, initialize and get the FMU state after initialization. From this state, perform many simulations that are restarted after the initialization with new input variables proposed by the optimizer).]
Furthermore, the FMU state can be serialized and copied in a byte vector. [This can be, for example, used to perform an expensive steady-state initialization, copy the received FMU state in a byte vector and store this vector on file. Whenever needed, the byte vector can be loaded from file and deserialized, and the simulation can be restarted from this FMU state, in other words, from the steady-state initialization.]
- Functions
fmi3GetFMUState
typedef fmi3Status fmi3GetFMUStateTYPE (fmi3Instance instance, fmi3FMUState* FMUState);
This function makes a copy of the internal FMU state and returns a pointer to this copy (FMUState
).
If on entry *FMUState == NULL
, a new allocation is required.
If *FMUState != NULL
, then *FMUState
points to a previously returned FMUState
that has not been modified since.
In particular, fmi3FreeFMUState
had not been called with this FMUState
as an argument.
[Function fmi3GetFMUState
typically reuses the memory of this FMUState
in this case and returns the same pointer to it, but with the actual FMUState
.]
- Function
fmi3SetFMUState
typedef fmi3Status fmi3SetFMUStateTYPE (fmi3Instance instance, fmi3FMUState FMUState);
This function copies the content of the previously copied FMUState
back and uses it as actual new FMU state.
The FMUState
copy still exists.
[The simulation is restarted at this state, when calling fmi3SetFMUState
with FMUState
.]
typedef fmi3Status fmi3FreeFMUStateTYPE(fmi3Instance instance, fmi3FMUState* FMUState);
This function frees all memory and other resources allocated with the fmi3GetFMUState
call for this FMUState
.
The argument to this function is the FMUState
to be freed.
If a null pointer is provided, the call is ignored.
The function returns a null pointer in argument FMUState
.
These functions can be called, if the optional capability flag canGetAndSetFMUState
is set to true
.
- Function
fmi3SerializedFMUStateSize
typedef fmi3Status fmi3SerializedFMUStateSizeTYPE(fmi3Instance instance,
fmi3FMUState FMUState,
size_t* size);
This function returns the size
of the byte vector, in order that FMUState
can be stored in it.
With this information, the environment has to allocate an fmi3Byte
vector of the required length size
.
- Function
fmi3SerializeFMUState
typedef fmi3Status fmi3SerializeFMUStateTYPE (fmi3Instance instance,
fmi3FMUState FMUState,
fmi3Byte serializedState[],
size_t size);
This function serializes the data which is referenced by pointer FMUState
and copies this data in to the byte vector serializedState
of length size
, that must be provided by the environment.
- Function
fmi3DeSerializeFMUState
typedef fmi3Status fmi3DeSerializeFMUStateTYPE (fmi3Instance instance,
const fmi3Byte serializedState[],
size_t size,
fmi3FMUState* FMUState);
This function deserializes the byte vector serializedState
of length size
, constructs a copy of the FMU state and returns FMUState
, the pointer to this copy.
- Functions
fmi3Get{VariableType}
-
See Section 2.2.5.2 for the general mechanism to get variable values. Getting variable might trigger computations. [If Terminated is entered because of an
fmi3Error
return value, retrieved values should only be used for debugging purposes.]
2.3.1.1. State: Instantiated
In this state the FMU can do one-time initializations and allocate memory.
This state is entered after fmi3InstantiateXXX
returned successfully.
- Mathematical Description
Equations in Instantiated |
FMI functions |
Set variables \(\mathbf{v}_{\mathit{initial=exact}}\) and \(\mathbf{v}_{\mathit{initial=approx}}\) |
|
- Allowed Function Calls
- Function
fmi3EnterConfigurationMode
typedef fmi3Status fmi3EnterConfigurationModeTYPE(fmi3Instance instance);
Changes state to Configuration Mode.
- Function
fmi3EnterInitializationMode
typedef fmi3Status fmi3EnterInitializationModeTYPE(fmi3Instance instance,
fmi3Boolean toleranceDefined,
fmi3Float64 tolerance,
fmi3Float64 startTime,
fmi3Boolean stopTimeDefined,
fmi3Float64 stopTime);
Changes state to Initialization Mode.
-
toleranceDefined
andtolerance
depend on the interface type:- Model Exchange
-
If
toleranceDefined == fmi3True
, then the model is called with a numerical integration scheme where the step size is controlled by usingtolerance
for error estimation (usually as relative tolerance). In such a case all numerical algorithms used inside the model (for example, to solve non-linear algebraic equations) should also operate with an error estimation of an appropriate smaller relative tolerance. - Co-Simulation
-
If
toleranceDefined == fmi3True
, then the communication step size of the FMU is controlled by error estimation. In case the FMU utilizes a numerical integrator with variable step size and error estimation, it is suggested to usetolerance
for the error estimation of the integrator (usually as relative tolerance).
An FMU for Co-Simulation might ignore this argument.
-
startTime
andstopTime
can be used to check whether the model is valid within the given boundaries, or to allocate the necessary memory for storing results.startTime
is thefixed
initial
value of theindependent
variable and inherits its unit.[It is defined with
causality
=independent
in themodelDescription.xml
. If theindependent
variable istime
,startTime
is the starting time of initialization.] -
If
stopTimeDefined == fmi3True
, thenstopTime
is the final value of theindependent
variable and inherits its unit. If the environment tries to compute paststopTime
, the FMU has to returnfmi3Status == fmi3Error
. IfstopTimeDefined == fmi3False
, then no final value of theindependent
variable is defined and argumentstopTime
is meaningless.
2.3.1.2. State: Initialization Mode
This mode is used by the simulation algorithm to compute consistent initial conditions for overall system.
Equations are active to determine the initial FMU state, as well as all outputs
(and optionally other variables exposed by the exporting tool).
Artificial or real algebraic loops over connected FMUs in Initialization Mode may be handled by using appropriate numerical algorithms.
- Allowed Function Calls
- Function
fmi3ExitInitializationMode
typedef fmi3Status fmi3ExitInitializationModeTYPE(fmi3Instance instance);
Changes the state to Event Mode (ME), Step Mode (CS) or Clock Activation Mode (SE). [This function switches off all initialization equations.]
- Function
fmi3GetDirectionalDerivative
- Function
fmi3Set{VariableType}
-
This function can be called for variables with
variability
\(\neq\)constant
and withinitial
=exact
. - Function
fmi3Get{VariableType}
-
The variables that can be retrieved by
fmi3Get{VariableType}
calls are defined in the XML file as elements<ModelStructure><InitialUnknown>
. For variables withcausality
=output
or continuous-timestates
or state derivatives.
2.3.1.3. State: Configuration Mode
In this state structural parameters
with variability
= fixed
or variability
= tunable
can be changed.
No other variables can be changed during Configuration Mode.
This state is entered from state Instantiated by calling fmi3EnterConfigurationMode
and left back to Instantiated by calling fmi3ExitConfigurationMode
.
fmi3EnterConfigurationMode
can only be called if the FMU contains at least one structural parameter
- Allowed Function Calls
- Function
fmi3ExitConfigurationMode
typedef fmi3Status fmi3ExitConfigurationModeTYPE(fmi3Instance instance);
Exits the Configuration Mode and returns to state Instantiated.
- Function
fmi3Set{VariableType}
-
Only for variables with
causality
=structuralParameter
andvariability
=fixed
orvariability
=tunable
.
2.3.1.4. State: Terminated
In this state, the solution at the final time of a simulation can be retrieved.
- Allowed Function Calls
- Function
fmi3GetDirectionalDerivative
-
No restrictions.
- Function
fmi3GetOutputDerivatives
-
No restrictions.
2.3.2. Super State: Initialized
This super state is entered by the FMU when fmi3ExitInitializationMode
is called.
If the function fmi3Terminate
is called, the FMU enters state Terminated from all states of this super state.
If any function returns fmi3Error
in Initialized, the FMU switches to state Terminated.
The states of this super state differ between the FMI types and will be described in detail in their respective chapters.
2.3.2.1. State: Event Mode
_[TODO: add Event Mode description after clocks/event clarification…]
The next event instant \(t_{i+1}\) is defined by the earliest occurrence of one of the following conditions:
-
The environment of the FMU triggers an event at the current time instant because at least one discrete-time
input
changes its value, a continuous-timeinput
has a discontinuous change, or atunable
parameter
changes its value. [Note that if an FMU A is connected to an FMU B, and an event is triggered for A, then potentially alloutputs
of A will be discontinuous at this time instant. It is therefore advisable to move B into Event Mode at this time instant too if anoutput
of A is connected to B. This means to callfmi3EnterEventMode
on B.]All the following events are internal events:
-
At a predefined time instant \(t_i=T_{\mathit{next}}(t_{i-1}, 0)\) that was defined at the previous event instant \(t_{i-1}\) by the FMU. Such an event is called time event.
-
At a time instant, where an event indicator \(z_j(t)\) changes its domain from \(z_j > 0\) to \(z_j \leq 0\) or from \(z_j \leq 0\) to \(z_j > 0\) (see Figure 8). More precisely: An event \(t = t_i\) occurs at the smallest time instant \(t\) with \(t>t_{i-1}\) where \((z_j(t)>0) \neq (z_j(t_{i-1}) >0)\). Such an event is called state event. [This definition is slightly different from the standard definition of
state events
: _ \(z_j(t) \cdot z_j(t_{i-1}) \leq 0\) _. This often used definition has the severe drawback that \(z_j(t_{i-1}) \neq 0\) is required in order to be well-defined and this condition cannot be guaranteed.]. All event indicators are piecewise continuous and are collected together in one vector of floating point numbers \(\mathbf{z(t)}\).
-
At every completed step of an integrator,
fmi3CompletedIntegratorStep
must be called (provided the capability flagcompletedIntegratorStepNotNeeded
of<fmiModelDescription>
isfalse
). An event occurs at this time instant, if indicated by the return argumententerEventMode == fmi3True
. Such an event is called step event. [Step events
are, for example, used to dynamically change the (continuous)states
of a model internally in the FMU, because the previous states are no longer suited numerically.]
In this mode all continuous-time and discrete-time equations are active and the unknowns at an event can be computed and retrieved. The event time of a state event may be determined if a domain change of at least one event indicator is detected at the end of a completed integrator step.
Event Mode is entered by calling fmi3EnterEventMode
, if an event is triggered in Continuous-Time Mode.
- Allowed Function Calls
- Function
fmi3UpdateDiscreteStates
-
In order to handle discrete events
fmi3UpdateDiscreteStates
is called. When the output argumentdiscreteStatesNeedUpdate == fmi3True
, the FMU should stay in Event Mode and another call tofmi3UpdateDiscreteStates
is required. - Function
fmi3EnterContinuousTimeMode
typedef fmi3Status fmi3EnterContinuousTimeModeTYPE(fmi3Instance instance);
TODO only in ME
The model enters Continuous-Time Mode and all discrete-time equations become inactive and all relations are "frozen".
This function has to be called when changing from Event Mode (after the global event iteration in Event Mode over all involved FMUs and other models has converged) into Continuous-Time Mode.
[This function might be used additionally for the following purposes: * If the FMU stores results internally on file, then the results after the initialization and/or the event has been processed can be stored. * If the FMU contains dynamically changing states, then a new state selection might be performed with this function.]
- Function
fmi3EnterStepMode
-
TODO only in CS
Once all events are handled and discreteStatesNeedUpdate == fmi3False
, the FMU should be pushed to Step Mode by calling fmi3EnterStepMode
, unless it requests to terminate the Co-Simulation by setting <<terminateSimulation,terminateSimulation
> to fmi3True
.
In this case, a new step can be started from the current communication point time.
fmi3GetClock
-
The status of
output clocks
andlocal clocks
can be inquired by this function during Event Mode and Intermediate Update Mode. fmi3SetClock
-
For
input clocks
,fmi3SetClock
is called after entering Event Mode to set the activation status ofclocks
. This function can be called several times, only if re-computations of clock state are needed during Event Mode. fmi3GetIntervalDecimal
&fmi3GetIntervalFraction
-
For
output clocks
andlocal clocks
it is allowed to call these functions during Event Mode and Intermediate Update Mode. These functions can be called only at the first activation ofperiodic
output clocks
. Foraperiodic
output clocks
, these functions must be called at every activation [to inquire when triggeredinput clocks
must tick]. fmi3SetIntervalDecimal
&fmi3SetIntervalFraction
-
These functions can be called only at the first activation of
periodic
input clocks
. These functions can be called for every activation ofaperiodic
input clocks
. - Function
fmi3GetDirectionalDerivative
2.3.2.2. State: Reconfiguration Mode
This state is entered from state Event Mode (ME), Step Mode (CS) or Clock Activation Mode (SE) by calling fmi3EnterConfigurationMode
.
fmi3EnterConfigurationMode
can only be called if the FMU contains at least one structural parameter
.
- Allowed Function Calls
- Function
fmi3ExitConfigurationMode
-
Returns back to Event Mode (ME), Step Mode (CS) or Clock Activation Mode (SE).
- Function
fmi3Set{VariableType}
-
Only for variables with
causality
=structuralParameter
andvariability
=tunable
. No other variables can be changed during Reconfiguration Mode.
2.3.3. State: Intermediate Update Mode
This state is only available in Co-Simulation and Scheduled Execution. The following use cases are enabled:
-
improve the input accuracy in CS between communication points, when the importer sets intermediate input values extracted with the same mechanism from another FMU as output values (see below for details and Section 4.2.3),
-
allow FMUs to inform the importer of an event, which occurs during an
fmi3DoStep
in case of CS orfmi3ActivateModelPartition
in case of SE (see Section 4.2, Section 4.2.3 and Section 5.2.1.3), -
allow the importer in CS to request an early return from FMUs calling
fmi3CallbackIntermediateUpdate
withcanReturnEarly == fmi3True
, because of any event between communication points (see Section 4.2.4 and Section 4.2.2). This also enables cooperative multitasking of FMUs in CS.
Note that the call to fmi3CallbackIntermediateUpdate
and thus entering the Intermediate Update Mode can only be triggered by the FMU itself.
The importer cannot actively trigger this and hence for some use cases (e.g. cooperative multitasking and setting of intermediate input values) it relies on the callbacks from the FMUs to be able to realize these use cases properly.
A Co-Simulation FMU can provide values for its output
variables at intermediate points between two consecutive communication points, and is able to accept new values for input
variables at these intermediate points.
This is typically required when the FMU uses a numerical solver to integrate the FMU’s internal state between communication points in fmi3DoStep
.
This numerical solver assumes that the inputs are continuous in the integration interval, dictated by fmi3DoStep
.
In FMI 2.0 Co-simulation, the intermediate inputs are provided by the use of extrapolations.
The intermediate update functions allow FMUs to receive inputs, and provide outputs, directly to the co-simulation algorithm, in those intermediate time points.
Due to the way numerical solvers estimate and correct the approximation error, these intermediate output
values may be tentative or may be final.
It is possible for the FMU to inform the co-simulation algorithm whether the internal solver is in a tentative state, meaning that the output values computed from that state are also tentative, or if the internal solver has successfully completed the integration step, meaning that the FMU’s internal state is final, and will never be changed in the current execution of fmi3DoStep
.
If the internal integration step has been successfully completed, the co-simulation algorithm can forward intermediate outputs to other FMUs, where they can be used, for e.g., for extrapolation, interpolation, filtering or asynchronous co-simulation.
[For tentative output values, the co-simulation algorithm must keep in mind that these values may change for the same time point.]
The FMU requests updated intermediate input
values for continuous variables every time they are required by the internal solver.
This can be either at tentative solver states or after successful integration steps.
Access to intermediate variables enables advanced Co-Simulation with interpolation/extrapolation techniques (such as polynomial extrapolation, TLM co-simulation, anti-alias filtering, smoothing of input among others)
Moreover, this enables the same input approximation that was possible in FMI 2.0 with fmi2SetInputDerivatives
, by evaluating the approximation polynomial and not within the FMU as in FMI 2.0.
Figure 9 summarizes the above description. It illustrates multiple intermediate internal solver steps, distinguishing between the final ones (with black-filled circles) and tentative ones (with white-filled circles). It distinguishes the level of trust that can be placed in the tentative outputs (with dashed arrows) and in final outputs (with solid arrows).
The FMU signals the support of Intermediate Update Mode via the capability flag providesIntermediateUpdate
.
The co-simulation algorithm signals the support for Intermediate Update Mode by providing a non-NULL callback-function pointer for intermediateUpdate
.
The FMU enters Intermediate Update Mode by calling fmi3CallbackIntermediateUpdate
within Step Mode (CS) or Clock Activation Mode (SE) and leaves the state towards Step Mode (CS) or Clock Activation Mode (SE) if the function returns fmi3OK
or fmi3Warning
.
If the function returns fmi3Error
the FMU enters state Terminated.
If the function returns fmi3Fatal
the FMU enters the terminal state.
typedef void (*fmi3CallbackIntermediateUpdate) (
fmi3InstanceEnvironment instanceEnvironment,
fmi3Float64 intermediateUpdateTime,
fmi3Boolean clocksTicked,
fmi3Boolean intermediateVariableSetRequested,
fmi3Boolean intermediateVariableGetAllowed,
fmi3Boolean intermediateStepFinished,
fmi3Boolean canReturnEarly,
fmi3Boolean *earlyReturnRequested,
fmi3Float64 *earlyReturnTime);
-
intermediateUpdateTime
is the internal value of theindependent
variable [typically simulation time] of the FMU at which the callback has been called. If an event happens or anoutputClock
ticks,intermediateUpdateTime
is the time of event oroutputClock
tick. If the FMU returns withearlyReturn == fmi3True
fromfmi3DoStep
thenintermediateUpdateTime
is the internal simulation time of the FMU of the lastfmi3CallbackIntermediateUpdate
call that signaledcanReturnEarly == fmi3True
.intermediateUpdateTime
is also the value of theindependent
variable of intermediate steps of the internal FMU solver. The FMU must not call the callback functionfmi3CallbackIntermediateUpdate
with anintermediateUpdateTime
that is smaller than theintermediateUpdateTime
given in a previous call offmi3CallbackIntermediateUpdate
withintermediateStepFinished == fmi3True
.
-
The
clocksTicked
parameter is only used in Scheduled Execution and is ignored in Co-Simulation. WhenclocksTicked == fmi3True
, it means thatfmi3GetClock
function must be called for gathering allclock
related information about tickingoutput clocks
atintermediateUpdateTime
and then activate the given model partitions accordingly.
-
If
intermediateVariableSetRequested == fmi3True
, the co-simulation algorithm should provide intermediateinput
variables by callingfmi3Set{VariableType}
for continuous variables withintermediateUpdate = true
. The set of variables for which the co-simulation algorithm can provide intermediate values is supplied through therequiredIntermediateVariables
argument tofmi3InstantiateXXX
. Note that if a co-simulation algorithm does not provide a new value for any of the variables contained in the set it registered, the last set value will be deemed to be the new value.
-
If
intermediateVariableGetAllowed == fmi3True
, the co-simulation algorithm may collect intermediate output variables by callingfmi3Get{VariableType}
for variables withintermediateUpdate = true
. The set of variables for which the co-simulation algorithm can get values is supplied through therequiredIntermediateVariables
argument tofmi3InstantiateXXX
.
-
If
intermediateStepFinished == fmi3False
, the intermediate outputs of the FMU that the co-simulation algorithm inquires withfmi3Get{VariableTypes}
resulting from tentative interval solver states and may still change for the sameintermediateUpdateTime
(e.g., if the solver deems the tentative state to cause a too high approximation error, it may go back in time and try to re-estimate the state using smaller internal time steps). [These outputs shall for example not be communicated to other connected FMUs. The use case for this is to let the co-simulation algorithm do some calculations for the FMU even for unfinished solver steps. This is beneficial for example for Transmission Line (TLM) co-simulation, where this helps to keep the interface cleaner. Instead of FMUs exchanging hard-to-understand variables such as "wave variable" and "characteristic impedance", they can exchange intuitive variables like "force" and "speed".] -
If
intermediateStepFinished == fmi3True
, intermediate outputs inquired by the co-simulation algorithm withfmi3Get{VariableTypes}
correspond to accepted internal solver steps and will not change (if the co-simulation algorithm does not rollback the FMU).
[So the co-simulation algorithm could for example-
use the values obtained with
fmi3Get{VariableTypes}
withintermediateStepFinished == fmi3True
to create an interpolation for the intermediate inputs of other FMUs. -
use this information for plotting.]
-
-
When
canReturnEarly == fmi3True
the co-simulation algorithm can request the FMU to return early at the currentintermediateUpdateTime
time instant by returning withearlyReturnRequested == fmi3True
from the callback functionfmi3CallbackIntermediateUpdate
. IfcanReturnEarly == fmi3False
the FMU will not do the early return, regardless of the co-simulation algorithm request.
-
earlyReturnRequested == fmi3True
requests the FMU to end thefmi3DoStep
at a Newtonian time instant and return early. This is only allowed ifcanReturnEarly == fmi3True
.
-
earlyReturnTime
is used to tell the FMU at what time to return early from the currentfmi3DoStep
(at the earliest), if the return value ofearlyReturnRequested
offmi3CallbackIntermediateUpdate
isfmi3True
. If theearlyReturnTime
is greater than the last signaledintermediateUpdateTime
, the FMU may integrate up to the time instantearlyReturnTime
.
When providing intermediate inputs to the FMU, it is important that the co-simulation algorithm provides the same input value for the same variable, at the same intermediateUpdateTime
.
In other words, it is required that the calculation of inputs to the FMU be deterministic.
This is assumed by the internal solver.
If an input value changes for the same intermediateUpdateTime
, the internal numerical solver may deem that re-estimate a state multiple times, without ever being able to decrease the approximation error.
Because the FMU intermediate outputs may be trusted when intermediateStepFinished == fmi3True
, the FMU is not allowed to call intermediateUpdate
for a simulation time point prior to or equal to a previous call whose argument intermediateStepFinished == fmi3True
.
If the early return is conducted successfully by the FMU it must return with earlyReturn == fmi3True
from fmi3DoStep
, indicating the current FMU time with lastSuccessfulTime
.
The co-simulation algorithm can decide if a rollback of the FMU to reach the earlyReturnTime
time is required or it may continue the simulation from lastSuccessfulTime
for that FMU.
Note that Event Mode is not supported in Scheduled Execution.
- Allowed Function Calls
- Function
fmi3Get{VariableType}
-
If
intermediateVariableGetAllowed == fmi3True
, the value of intermediate variables can be retrieved. Intermediate variables are variables that are marked with attributeintermediateUpdate = true
in themodelDescription.xml
and have been included in therequiredIntermediateVariables
argument tofmi3InstantiateXXX
. - Function
fmi3Set{VariableType}
-
If
intermediateVariableSetRequested == fmi3True
, the value of intermediate, continuous variables should be set. Intermediate variables are variables that are marked with attributeintermediateUpdate = true
in themodelDescription.xml
and have been included in therequiredIntermediateVariables
argument tofmi3InstantiateXXX
.
There is a defined order of calling these functions: first all fmi3Get{VariableType}
calls must be performed, then fmi3Set{VariableType}
may be called.
[This is analogous to the calling sequence of of fmi3Get{VariableType}
and fmi3Set{VariableType}
calls at communication points.]
Please refer to Section 5.2.1.3 for additional allowed functions in Intermediate Update Mode for SE.
The following code example shows an implementation of fmi3CallbackIntermediateUpdate
that uses intermediate update to record a set of variables at every internal solver step:
fmi3Status recordVariables(InstanceEnvironment *instanceEnvironment, fmi3Float64 time) {
fmi3ValueReference outputsVRs[2] = { vr_h, vr_v };
fmi3Float64 y[2];
fmi3Status status = fmi3GetFloat64(instanceEnvironment->instance, outputsVRs, 2, y, 2);
fprintf(instanceEnvironment->outputFile, "%g,%g,%g\n", time, y[0], y[1]);
return status;
}
void cb_intermediateUpdate(fmi3InstanceEnvironment instanceEnvironment,
fmi3Float64 intermediateUpdateTime,
fmi3Boolean eventOccurred,
fmi3Boolean clocksTicked,
fmi3Boolean intermediateVariableSetAllowed,
fmi3Boolean intermediateVariableGetAllowed,
fmi3Boolean intermediateStepFinished,
fmi3Boolean canReturnEarly,
fmi3Boolean *earlyReturnRequested,
fmi3Float64 *earlyReturnTime) {
if (!instanceEnvironment) {
return;
}
*earlyReturnRequested = fmi3False;
InstanceEnvironment* env = (InstanceEnvironment*)instanceEnvironment;
// remember the intermediateUpdateTime
env->intermediateUpdateTime = intermediateUpdateTime;
fmi3Status status = fmi3OK;
if (eventOccurred) {
return; // don't record events
}
// if getting intermediate output variables is allowed
if (intermediateVariableGetAllowed) {
// Get the output variables at time == intermediateUpdateTime
// fmi3Get{VariableType}();
status = recordVariables(env, intermediateUpdateTime);
// If integration step in FMU solver is finished
if (intermediateStepFinished) {
//Forward output variables to other FMUs or write to result files
}
}
// if setting intermediate output variables is allowed
if (intermediateVariableSetAllowed) {
// Compute intermediate input variables from output variables and
// variables from other FMUs. Use latest available output
// variables, possibly from get functions above.
// inputVariables = ...
// Set the input variables at time == intermediateUpdateTime
// fmi3Set{VariableType}();
}
// Internal execution in FMU will now continue
}
2.4. FMI Description Schema
All static information related to the core functionality of an FMU is stored in the text file modelDescription.xml
in XML format as specified by the XML schema file fmi3ModelDescription.xsd
.
Especially, the FMU variables and their attributes such as name
, unit
, default initial
value, etc. are stored in this file.
Additional optional information about the graphical representation and the grouping of FMU variables into terminals is stored in the optional text file icons/terminalsAndIcons.xml
in XML format as specified by the XML schema file fmi3TerminalsAndIcons.xsd
.
Build information for source code FMUs is provided together with a buildDescription.xml
file in the sources
directory that adheres to the fmi3BuildDescription.xsd
schema file.
It is not allowed to change the modelDescription.xml
file.
[Reason: The modelDescription.xml
file has to be consistent with the binary or source code implementations.
Specifically, changes to the start values are not allowed.]
The structure of the XML files is defined with the schema file fmi3ModelDescription.xsd
and the optional fmi3TerminalsAndIcons.xsd
and fmi3BuildDescription.xsd
files.
These schema files utilize several helper schema files.
In this section these schema files are discussed.
The normative definition are the above mentioned schema files.
In the graphical representation of the schema, optional elements are marked with a dashed box (e.g., see Figure 10).
The required data types (like: xs:normalizedString
) are defined in XML Schema Part 2: Datatypes Second Edition.
The types used in the FMI schema files are:
XML |
Description (http://www.w3.org/TR/xmlschema-2/) |
Mapping to C |
Mapping to FMI 3.0 |
|
IEEE 754 double-precision 64-bit floating point type [An IEEE 754 double-precision floating point value can have up to 17 significant digits in its decimal representation. In order to not loose precision, either an appropriate minimal printer algorithm should be used, or alternatively a number of this type should be stored in XML files with at least 17 significant digits.] |
|
|
|
IEEE 754 single-precision 32-bit floating point type [An IEEE 754 single-precision floating point value can have up to 9 significant digits in its decimal representation. In order to not loose precision, either an appropriate minimal printer algorithm should be used, or alternatively a number of this type should be stored in XML files with at least 9 significant digits.] |
|
|
|
Integer number with maximum value 127 and minimum value -128 (8 bit signed integer) |
|
|
|
Integer number with maximum value 255 and minimum value 0 (8 bit unsigned integer) |
|
|
|
Integer number with maximum value 32767 and minimum value -32768 (16 bit signed integer) |
|
|
|
Integer number with maximum value 65535 and minimum value 0 (16 bit unsigned integer) |
|
|
|
Integer number with maximum value 2147483647 and minimum value -2147483648 (32 bit signed integer) |
|
|
|
Integer number with maximum value 4294967295 and minimum value 0 (32 bit unsigned integer) |
|
|
|
Integer number with maximum value 9223372036854775807 and minimum value -9223372036854775808 (64 bit signed integer) |
|
|
|
Integer number with maximum value 18446744073709551615 and minimum value 0 (64 bit unsigned integer) |
|
|
|
Boolean number.
Legal literals: |
|
|
|
Any number of characters |
|
|
|
String without carriage return, line feed, and tab characters |
|
|
|
Arbitrary hex-encoded binary data |
|
|
|
Date, time and time zone (for details see XML Schema Part 2: Datatypes Second Edition).
Example: |
tool specific |
not defined |
The first line of an XML file, such as modelDescription.xml
, must contain the encoding scheme of the XML file.
It is required that the encoding scheme is always UTF-8:
<?xml version="1.0" encoding="UTF-8"?>
The FMI schema files (fmi3*.xsd
) are also stored in UTF-8.
[Note that the definition of an encoding scheme is a prerequisite in order for the XML file to contain letters outside of the 7 bit ANSI ASCII character set, such as German umlauts, or Asian characters.
Furthermore, note the FMI calling interface requires that strings are encoded in UTF-8.
Since the XML files are also required to be encoded in UTF-8, string variables need not to be transformed when reading from the XML files in to C string variables.].
[Note that child information items, such as elements in a sequence are ordered lists according to document order, whereas attribute information items are unordered sets (see http://www.w3.org/TR/XML-infoset/#infoitem.element).
The FMI schema is based on ordered lists in a sequence and therefore parsing must preserve this order.
For example, the information stored in <ModelVariables><Derivative>
is only correct if this property is fulfilled.]
All XML-based file formats defined in this standard allow optional Annotation
elements to be inserted in all XML elements that represent entities of the underlying data model.
This is achieved through the Annotations
element:

Each Annotation
element contains a required type
attribute, which contains the namespace for that annotation.
The content of the Annotation
element can be arbitrary XML data, and can make use of XML namespaces and XML schemas for combined validation where appropriate.
The namespace mechanism for the type
attribute is based on reverse domain notation:
The originator of a specification for additional data specifies a domain name under their control as the namespace for the additional data, in order to avoid conflicts due to name collisions.
The namespace is used in reverse domain notation.
All namespaces under both the org.modelica
and org.fmi-standard
domains are reserved for use in future layered standards.
[For example, extensions defined by the Modelica Association might make use of the org.modelica.fmi
namespace.
This could lead to annotations with a type
attribute of org.modelica.fmi.something
, and/or extra files under the extra/org.modelica.ssp.something
sub-directory.]
Annotations are intended to allow structured extensions of the FMI XML files, without creating conflicting extensions, or leaving ambiguities in interpretation. All annotations can safely be ignored by implementations that just implement the base FMI standard.
2.4.1. Definition of an FMU
This is the root-level schema file and is illustrated in Figure 11. The figure contains all elements in the schema file. Data is defined by attributes to these elements.

On the top level, the schema consists of the elements detailed in Table 9.
[If an optional element is present and defines a list (such as <UnitDefinitions>
), the list must have at least one element (such as <Unit>
).]
Element | Description |
---|---|
|
If present, the FMU is based on FMI for Model Exchange (Section 3) [(in other words, the FMU includes the model or the communication to a tool that provides the model, and the environment provides the simulation engine)]. |
|
If present, the FMU is based on FMI for Co-Simulation (Section 4). |
|
If present, the FMU is based on FMI for Scheduled Execution (Section 5). |
|
A global list of unit and display unit definitions [for example, used to convert display units into the units used in the model equations].
These definitions are used in the XML element |
|
A global list of type definitions that are utilized in |
|
A global list of log categories that can be set to define the log information that is supported from the FMU. |
|
Providing default settings for the integrator, such as stop time and relative tolerance. |
|
The central FMU data structure defining all variables of the FMU that are visible/accessible via the FMU functions. |
|
Defines the structure of the model.
Especially, the ordered lists of |
|
Optional annotations for the top-level element. |
At least one element of <ModelExchange>
, <CoSimulation>
or <ScheduledExecution>
must be present to identify the type of the FMU.
If multiple elements are defined, different types of models are included in the FMU.
The details of these elements are defined in Section 3, Section 4 or Section 5.
The XML attributes of <fmiModelDescription>
are:
Attribute | Description |
---|---|
|
Version of FMI that was used to generate the XML file.
The value for this version is [During development prototype FMU implementations can indicate compliance with a certain development version based on the tags available at https://github.com/modelica/fmi-standard/tags.
For example the value for the FMI 3.0 Alpha 2 release is |
|
The name of the model as used in the modeling environment that generated the XML file, such as |
|
The |
|
Optional string with a brief description of the model. |
|
Optional string with the name and organization of the model author. |
|
Optional version of the model [for example |
|
Optional information on the intellectual property copyright for this FMU [for example |
|
Optional information on the intellectual property licensing
for this FMU [for example |
|
Optional name of the tool that generated the XML file. |
|
Optional date and time when the XML file was generated.
The format is a subset of |
|
Defines whether the variable names in
|
2.4.2. Definition of Capability Flags
The elements <ModelExchange>
, <CoSimulation>
and <ScheduledExecution>
contain attributes representing capability flags describing which optional functionalities the FMU supports.
The following table contains capability flags common to all three interface types.
Attribute | Description |
---|---|
|
If |
|
This flag indicates cases (especially for embedded code), where only one instance per FMU is possible (multiple instantiation is default = |
If |
|
|
If |
|
If |
|
If |
|
The FMU is able to provide detailed dependency information at run time using |
|
The FMU is able to provide |
|
The FMU supports Intermediate Update Mode and will call |
A value of \(k\) with \(k>0\) signals to the co-simulation algorithm, that it is beneficial for the solver to receive intermediate inputs that are k-time continuously differentiable (\(C^k\)) on the current communication interval.
\(k=0\) means continuous (see Section 4.1.3). |
2.4.3. Definition of Units
In this section, the units of the variables are defined.
[Unit support is important for technical systems since otherwise it is very easy for errors to occur. Unit handling is a difficult topic, and there seems to be no method available that is really satisfactory for all applications, such as unit check, unit conversion, unit propagation or dimensional analysis. In FMI, a pragmatic approach is used that takes into account that every software system supporting units has potentially its own specific technique to describe and utilize units.]
Element <fmiModelDescription><UnitDefinitions>
is defined as:

It contains one or more Unit
definitions.
If no units are defined, element <UnitDefinitions>
must not be present.
The name
of a Unit
must be unique with respect to all other <Unit>
elements.
If a variable is associated with a Unit
, the value passed to fmi3Set{VariableType}
(resp. retrieved with fmi3Get{VariableType}
) has this unit.
[The purpose of the name is to uniquely identify a unit and, for example, use it to display the unit in menus or in plots.
Since there is no standard to represent units in strings, and there are different ways how this is performed in different tools, no specific format for the string representation of the unit is required.]
The Unit
definition consists of the exponents of the 7 SI base units kg
, m
, s
, A
, K
, mol
, cd
, the exponent of the SI derived unit rad
, and optionally a factor
and an offset
.
[The additional rad
base unit helps to handle the often occurring quantities in technical systems that depend on an angle.]

A value \(v_{unit}\) in Unit
is converted to the base unit \(v_{base}\) by the equation
where factor
and offset
are attributes of the <BaseUnit>
, and relativeQuantity
an attrinbute of the TypeDefinition
of a variable.
[For example, if \({p_{\mathit{bar}}}\) is a pressure value in unit bar
, and \({p_{\mathit{Pa}}}\) is the pressure value in <BaseUnit>
, then
and therefore, factor = 1.0e5
and offset = 0.0
.
In the following table several unit examples are given.
Note that if in column exponents
the definition \(\frac{kg \cdot m^2}{s^2}\) is present, then the attributes of <BaseUnit>
are kg=1, m=2, s=-2
.
Quantity |
Unit.name |
Unit.BaseUnit |
||
exponents |
factor |
offset |
||
Torque |
|
\({kg \cdot m^2 / s^2}\) |
|
|
Energy |
|
\({kg \cdot m^2 / s^2}\) |
|
|
Pressure |
|
\({\frac{kg}{m \cdot s^2}}\) |
|
|
Angle |
|
|
|
|
Angular velocity |
|
|
|
|
Angular velocity |
|
|
|
|
Frequency |
|
|
|
|
Temperature |
|
|
|
|
Per cent by length |
|
|
|
|
Parts per million |
|
|
|
|
Length |
|
|
|
|
Length |
|
|
|
|
Note that Hz
is typically used as Unit.name
for a frequency quantity, but it can also be used as <DisplayUnit>
for an angular velocity quantity (since revolution/s
).]
The <BaseUnit>
definitions can be utilized for different purposes (the following application examples are optional and a tool may also completely ignore the Unit
definitions):
- Unit check when connecting variables of different FMUs
-
When only one of
input
v2
andoutput
v1
, connected with equationv2 = v1
, defines a<BaseUnit>
element,fmi3Get{VariableType}
must be used to get the value ofv1
to then set it withfmi3Set{VariableType}
forv2
.When two variables v1 and v2 are connected and for both of them
<BaseUnit>
elements are defined, then they must have identical exponents of their<BaseUnit>
. Iffactor
andoffset
are also identical, again the connection equationv2 = v1
holds. Iffactor
andoffset
are not identical, the tool may either trigger an error or, if supported, perform a conversion; in other words, use the connection equation (in this case therelativeQuantity
of the<TypeDefinition>
, see below, has to be taken into account in order to determine whetheroffset
shall or shall not be utilized):factor(v1) * v1 + (if relativeQuantity(v1) then 0 else offset(v1)) = factor(v2) * v2 + (if relativeQuantity(v2) then 0 else offset(v2))
whererelativeQuantity(v1) = relativeQuantity(v2)
is required.As a result, wrong connections can be detected (for example, connecting a force with an angle-based variable would trigger an error) and conversions between, say, US and SI units can be either automatically performed or, if not supported, an error is triggered as well.
[Note that this approach is not satisfactory for variables belonging to different quantities that have, however, the same
<BaseUnit>
, such as quantitiesEnergy
andTorque
, orAngularVelocity
andFrequency
. To handle such cases, quantity definitions have to be taken into account (see<TypeDefinitions>
) and quantity names need to be standardized.]This approach allows a general treatment of units, without being forced to standardize the grammar and allowed values for units (for example, in FMI 1.0, a unit could be defined as
N.m
in one FMU and asN*m
in another FMU, and a tool would have to reject a connection, since the units are not identical. In FMI 2.0, the connection would be accepted, provided both elements have the same<BaseUnit>
definition). - Dimensional analysis of equations
-
In order to check the validity of equations in a modeling language, the defined units can be used for dimensional analysis, by using the
<BaseUnit>
definition of the respective unit. For this purpose, the<BaseUnit>
rad
has to be treated as1
. Example:\[\begin{align*} J \cdot \alpha = \tau \rightarrow [kg.m^2]*[rad/s^2] = [kg.m^2/s^2] & \quad \text{// o.k. ("rad" is treated as "1")} \\ J \cdot \alpha = f \rightarrow [kg.m^2]*[rad/s^2] = [kg.m/s^2] & \quad \text{// error, since dimensions do not agree} \end{align*}\] - Unit propagation
-
If unit definitions are missing for variables, they might be deduced from the equations where the variables are used. If no unit computation is needed,
rad
is propagated. If a unit computation is needed and one of the involved units hasrad
as a<BaseUnit>
, then unit propagation is not possible. Examples:-
a = b + c, and
Unit
of c is provided, but notUnit
of a and b:
The Unit definition ofc
(in other words,Unit.name
,<BaseUnit>
,<DisplayUnit>
) is also used fora
andb
. For example, if BaseUnit(c) =rad/s
, then BaseUnit(a) = BaseUnit(b) =rad/s
. -
a = b*c, and
Unit
of a and of c is provided, but notUnit
of b:
Ifrad
is either part of the<BaseUnit>
ofa
and/or ofc
, then the<BaseUnit>
ofb
cannot be deduced (otherwise it can be deduced). Example: IfBaseUnit(a) = kg.m/s2
andBaseUnit(c) = m/s2
, then theBaseUnit(b) can be deduced to be `kg
. In such a caseUnit.name
of b cannot be deduced from theUnit.name
ofa
andc
, and a tool would typically construct theUnit.name
ofb
from the deduced<BaseUnit>
.
-
]
A <Unit>
can contain any number of <DisplayUnit>
elements.

A <DisplayUnit>
is defined by name
, factor
, offset
, and inverse
.
The attribute name
must be unique with respect to all other names of the <DisplayUnit>
definitions of the same Unit
.
[Different Unit
elements may have the same <DisplayUnit>
names].
inverse == true
is only allowed if offset == 0
.
[Reason: no use case is known for the combination of inverse and offset, which would also be more complicated.]
A value \(v_{unit}\) in Unit
is converted to a value \(v_{display}\) in DisplayUnit
by the equation:
[offset
is needed for temperature units like F
(Fahrenheit), inverse
for inverse display units like mpg
(miles per gallon) or S
(Siemens).
For example, if \({T_K}\) is the temperature value of Unit.name
(in K
) and \({T_F}\) is the temperature value of <DisplayUnit>
(in °F
), then
and therefore, factor = 1.8 (=9/5)
and offset = -459.67 (= 32 - 273.15*9/5)
.
Both the DisplayUnit.name
definitions as well as the Unit.name
definitions are used in the variable elements.
Example of a definition:
<UnitDefinitions>
<Unit name="rad/s">
<BaseUnit s="-1" rad="1"/>
<DisplayUnit name="deg/s" factor="57.29577951308232"/>
<DisplayUnit name="rev/min" factor="9.549296585513721"/>
</Unit>
<Unit name="bar">
<BaseUnit kg="1" m="-1" s="-2" factor="1e5" offset="0"/>
</Unit>
<Unit name="L/100km">
<BaseUnit m="2" factor="1e-8"/>
<DisplayUnit name="mpg" inverse="true" factor="235.214583"/>
</Unit>
<Unit name="Re">
<BaseUnit/> <!-- unit="1" -->
<!-- (dimensionless, all exponents of BaseUnit are zero) -->
</Unit>
<Unit name="Euro/PersonYear"/> <!-- no mapping to BaseUnit defined -->
</UnitDefinitions>
]
2.4.4. Definition of Types
Element <fmiModelDescription><TypeDefinitions>
is defined as:

This element consists of a set of <TypeDefinition>
elements according to schema fmi3TypeDefinition
in file fmi3Type.xsd
.
Each <TypeDefinition>
has attributes name
and description
.
Attribute name
must be unique with respect to all other elements of the <TypeDefinitions>
list.
Furthermore, name
of a <TypeDefinition>
must be different to all name
attributes of variables [if the same names would be used, then this would nearly always give problems when importing the FMU in an environment such as Modelica, where a type name cannot be used as instance name].
Additionally, one variable type element must be present. Each variable type has its own attributes which can be consulted in the schema. Figure 16, Figure 17, Figure 18, Figure 19, and Figure 20, are representative examples.





The type elements are referred to in variable elements to declare their type.
[The alternative would be to define a type per variable.
However, this would lead to a situation where, e.g., the definition of a Torque
type would have to be repeated over and over.]
The attributes and elements have the following meaning:
Attribute or Elements | Description |
---|---|
|
Physical quantity of the variable.
[For example, |
|
Unit of the variable defined with attribute |
Default display unit.
The conversion to the |
|
|
Indicates the type of data passed as a binary.
Defaults to |
|
If this attribute is |
|
Minimum value of variable (variable value \(\geq\) |
|
Maximum value of variable (variable value \(\leq\) |
|
Nominal value of variable.
If not defined and no other information about the nominal value is available, then |
|
If |
|
|
[Attributes min
and max
can be set for variables of numeric type or <Enumeration>
.
The question is how fmi3Set{VariableType}
, fmi3Get{VariableType}
shall utilize this definition.
There are several conflicting requirements:
Avoiding forbidden regions (for example, if u
is an input
and "sqrt(u)" is computed in the FMU, min = 0
on u
shall guarantee that only values of u
in the allowed regions are provided).
Numerical algorithms (solvers or optimizers) do not guarantee constraints.
If a variable is outside of the bounds, the solver tries to bring it back into the bounds.
As a consequence, calling fmi3Get{VariableType}
during an iteration of such a solver might return values that are not in the defined min/max region.
After the iteration is finalized, it is only guaranteed that a value is within its bounds up to a certain numerical precision.
During system creation and prototyping, checks on min/max should be performed.
For maximum performance on production or real-time systems, these checks might not be performed.
The approach in FMI is therefore that min/max definitions are an information from the FMU to the environment defining the region in which the FMU is designed to operate.
In any case, it is expected that the FMU handles variables appropriately where the region definition is critical.
For example, dividing by an input
(so the input
should not be in a small range of zero) or taking the square root of an input
(so the input
should not be negative) may either result in fmi3Error
, or the FMU is able to handle this situation in other ways.
If the FMU is generated so that min/max shall be checked whenever meaningful (for example, for debug purposes), then the following strategy should be used:
If fmi3Set{VariableType}
is called violating the min/max attribute settings of the corresponding variable, the following actions are performed:
-
On a
fixed
ortunable
parameter
fmi3Status == fmi3Discard
is returned. -
On an
input
, the FMU decides what to return (If no computation is possible, it could returnfmi3Status == fmi3Discard
, in other situations it may returnfmi3Warning
orfmi3Error
, orfmi3OK
, if it is uncritical).
If an FMU defines min/max values for integer types and <Enumeration>
variables (local
and output
variables), then the expected behavior of the FMU is that fmi3Get{VariableType}
functions return values in the defined range.
If an FMU defines min/max values for numeric types, then the expected behavior of the FMU is that fmi3Get{VariableType}
returns values at the solution (accepted steps of the integrators) in the defined range with a certain uncertainty related to the tolerances of the numerical algorithms.]
2.4.4.1. Clock Type Definition
Clocks are integrated in the element <fmiModelDescription><ModelVariables>
as a variable element with the base type fmi3Clock
.
The variable sub type fmi3Clock
provides additional attributes for defining clocks
.
Attribute | Description |
---|---|
|
The type of
It is not allowed to include |
|
The optional attribute Only |
|
The [For
|
|
Clocks can be periodic or aperiodic.
If a
|
|
If a
|
|
The interval of
The initial tick of This results in the actual
The time `t = (shiftCounter + n * intervalCounter) / resolution. More information about clock intervals: Section 2.2.7.7. The attributes
|

2.4.5. Definition of Log Categories
Element <fmiModelDescription><LogCategories>
is defined as:

<LogCategories>
defines an unordered set of category strings that can be utilized to define the log output via function logMessage
, see Section 2.3.1.
A tool is free to use any normalizedString
for a category value.
The name
attribute of <Category>
must be unique with respect to all other elements of the <LogCategories>
list.
Table 15 shows the standardized names for <Category>
.
These names should be used if a tool supports the corresponding log category.
If a tool supports one of these log categories and wants to expose it, then an element <Category>
with this name should be added to <LogCategories>
.
[To be clear, only the <Category>
names listed under <LogCategories>
in the XML file are known to the importer of the FMU.]
Category | Description |
---|---|
|
Log all events (during initialization and simulation). |
|
Log the solution of linear systems of equations if the solution is singular (and the tool picked one solution of the infinitely many solutions). |
|
Log the solution of nonlinear systems of equations. |
|
Log the dynamic selection of |
|
Log messages when returning |
|
Log messages when returning |
|
Log messages when returning |
|
Log messages when returning |
|
Log all messages. |
The optional attribute description
shall contain a description of the respective log category.
[Typically, this string can be shown by a tool if more details for a log category are presented.]
[This approach to define <LogCategories>
has the following advantages:
-
A simulation environment can present the possible log categories in a menu and the user can select the desired one (in the FMI 1.0 approach, there was no easy way for a user to figure out from a given FMU what log categories could be provided).
Note that since element<LogCategories>
is optional, an FMU does not need to expose its log categories. -
The log output is drastically reduced, because via
fmi3SetDebugLogging
exactly the categories are set that shall be logged and therefore the FMU only has to print the messages with the corresponding categories to thelogMessage
function. In FMI 1.0, it was necessary to provide all log output of the FMU to thelogMessage
and then a filter in thelogMessage
could select what to show to the end-user. The approach introduced in FMI 2.0 is therefore much more efficient.]
2.4.6. Definition of a Default Experiment
Element <fmiModelDescription><DefaultExperiment>
is defined as:

<DefaultExperiment>
consists of the optional default start time, stop time, relative tolerance, and step size for the first simulation run.
A tool may ignore this information.
However, it is convenient for a user that startTime
, stopTime
, tolerance
and stepSize
have already a meaningful default value for the model at hand.
Furthermore, for Co-Simulation FMUs the stepSize
defines the preferred communicationStepSize
.
2.4.7. Definition of Terminals and Icons
This is the root element of the XML file icons/terminalsAndIcons.xml
, and is defined as:

On the top level, the schema consists of the following elements (see Figure 24).
Element | Description |
---|---|
|
If present, contains information for importers of FMUs to draw graphical representations of the FMU in a system view. |
|
If present, this allows combining input and output variables into logical groups to ease connections on a system level. |
2.4.7.1. Definition of a Graphical Representation
2.4.7.1.1. Overview
The graphical representation of the FMU and terminals are needed in order to more easily comprehend the meaning of connected FMUs and to help an importing tool to display the terminals and the FMU icon in the way the exporter intended.
The graphical representation is fully optional.
The graphical representation of terminals is separate from the terminal definitions in the <Terminals>
element.
There are two optional elements in the <GraphicalRepresentation>
:
-
The
<CoordinateSystem>
defines the extent of the whole icon (graphical items may exceed that rectangle). -
The
<Icon>
defines an image source for the FMU.

2.4.7.1.2. CoordinateSystem

The <CoordinateSystem>
element and its defined extent is used as reference for other graphical items.
It also provides a scaling factor to millimeter.
The coordinate system is defined by the coordinates of two points, the lower left (x1
, y1
) corner and the upper right (x2
, y2
) corner, where the coordinates of the first point shall be less than the coordinates of the second point [a first quadrant coordinate system].
The x-axis is directed to the right, the y-axis is directed upwards.
[The exporting tool should define how the coordinate system unit relates to mm display or print out size. However, an importing tool might choose to use the factor from the default coordinate system extent to the actual coordinate system extent to calculate a scaling factor, to match the default icon size in the importing tool.
The area defined by the coordinate system is suggested to be used as "clickable icon size" in other tools.
A <Terminal>
might be placed outside of this area, so the visible bounding box has to be determined by the importing tool.]
The coordinate system default is x1=-100, y1=-100, x2=100, y2=100
.
This extent is used if the <CoordinateSystem>
element is missing.
The default suggestedScalingFactorTo_mm
is 0.1.
So the default coordinate system display size should be 20 mm width and 20 mm height.
The FMU icon and all graphical representations provide the position and extent with the attributes x1
, y1
, x2
, y2
.
The values of these attributes directly relate to this coordinate system and are not normalized.
Flipping of the FMU icon or a terminal can be realized by setting its attributes x2 < x1
or y2 < y1
without changing the coordinate system.
2.4.7.1.3. Icon

The extent and position of the FMU icon are defined in the <Icon>
element.
The optional image file of the FMU icon is placed at the path icons/icon.png
in the ZIP archive of the FMU.
The terminals should not be visible in the image.
Optionally an SVG file can be provided if also the PNG file is present.
This enables high quality rendering and printing in importing tools.
This SVG file has to be placed at the path icons/icon.svg
in the ZIP archive.
The point (x1
, y1
) maps to the left lower corner of the PNG image or SVG viewport.
The point (x2
, y2
) maps to the right upper corner of the PNG image or SVG viewport.
2.4.7.1.4. Placement, Extent, and Painting Order of Graphical Items
The clickable icon size is defined by the <CoordinateSystem>
element.
The FMU icon itself may exceed this extent (or bounding box).
The bounding box of the terminals is given by the extent in the terminals element.
Their location is neither limited to the extent of the icon nor the extent of the coordinate system.
[An importing tool has to determine the outer bounding box enclosing all graphical items.]
Transparent SVG or PNG files are allowed and wanted.
The order of the elements in the XML file defines the order of painting.
The first element in the <TerminalGraphicalRepresentation>
is painted first and therefore behind the others, the last element is painted on top of the others and because of that in front of them.
[So the FMU icon should be placed first in the XML file, terminal below.]
2.4.7.2. Definition of Terminals
2.4.7.2.1. Overview
Terminals are fully optional and can be ignored by any importing tool.
Definition <Terminal>
: A terminal is…
-
a structured interface for connections to other models
-
intended to be used for signal flow between models, parameter propagation, and compatibility checks of the model configuration
-
a sequence of references to variables with connection meta data
Predefined rules for variable matching in a connection are given in Table 17. Predefined variable kinds are used to describe how the member variables have to be handled. Domain specific connection rules, terminals and their member variables can be provided by other standards.
[Co-simulation errors are not addressed by the terminals. The co-simulation algorithm has to be chosen and implemented by the importing tool. Features that might be required for specific co-simulation algorithms had to be implemented by the FMU exporting tool.
Algebraic loops in systems of connected Model Exchange FMUs are not addressed or resolved by the terminals.
It is not required that the causality
of the terminal member variables in connected terminals match.
The SSP standard refers to a connectorKind
.
This connectorKind
is not related to the terminalKind
or variableKind
described in Section 2.4.7.2.2 and Section 2.4.7.2.3.]
2.4.7.2.2. Terminals
Element <fmiTerminalsAndIcons><Terminals>
is defined as:

All instances of <Terminal>
have the type fmi3Terminal
and are listed in the <Terminals>
sequence.
The normalized string attribute name
of the <Terminal>
element is the instance name of the terminal.
The terminal name must be unique on each level.
The normalized string attribute matchingRule
describes the rules for variable matching in a connection.
As detailed in Table 17, there are three predefined matching rules: plug, bus, and sequence.
Other standards may define new matching rules.
In order to avoid ambiguities and conflicts, rule names must follow the reverse domain notation of a domain that is controlled by the entity defining the semantics and content of the additional entries.
The rule names beginning with org.modelica
and org.fmi-standard
are explicitly reserved for use by MAP FMI-defined layered standards.
There is a sequence of terminal member variables, terminal stream member variables, nested terminals, and an optional <TerminalGraphicalRepresentation>
element in the <Terminal>
element.
The member variables are the exchanged variables.
The type of the nested terminals is fmi3Terminal
, and they can be used to implement structured terminals.
The normalized string terminalKind
is an optional attribute.
Other standards may define terminal kinds.
It is intended that the terminalKind
is used to define domain specific member variable sequences, member names and order, or high level restrictions for connections.
[Other terminal kinds should refer to the predefined matchingRule
.
Vendor specific terminal kinds should start with _vendorName
or _toolName
to avoid namespace clashes.
Examples for terminalKind
: StandardXXX_Mechanical_Translational
, Modelica.Mechanics.Translational.Interfaces.Flange_a
, vendorNameA_customTypeA
, _vendorNameB_customLibrary_customTypeB
.
The structured naming convention of the <ModelVariables>
is independent from the terminal names and member variable names.
A tool may choose to connect terminals with a different or unknown terminalKind
, if the matchingRule
matches.]
2.4.7.2.3. Terminal Member Variable
The <TerminalMemberVariable>
is defined as:

The normalized string variableName
is used to identify the terminal member variable in the element <ModelVariables>
.
The information about minimum, maximum, and nominal values is available in there.
One variable can be part of several terminals.
If the matchingRule
plug
and bus
are used, then the normalized string memberName
is used for member variable matching.
So the memberName
attribute is required for plug
and bus
and it has to be unique for a terminal.
The memberName
is not required for matchingRule
sequence
.
The normalized string variableKind
is used to provide general information about the variable.
This information defines how the connection of this variable has to be implemented (e.g. Kirchhoff’s current law or common signal flow).
The predefined variableKind
are:
.Predefined kinds of variables.
variableKind |
Description |
---|---|
|
The values in connected terminals are intended to be equal.
Restricted to |
|
Variables which fulfill Kirchhoff’s current law.
Restricted to |
[The suggested variable naming scheme for the structured naming convention is <ModelVariable name> = <terminalName>.<memberName>.
Not all <ModelVariables>
which have the prefix "<terminalName>." are a member variable, and there may exist member variables which don’t have this prefix.
Example 1 (suggested scheme): <ModelVariable name> is portA.U
, <terminalName> is portA
, <memberName> is U
.
Example 2 (suggested scheme): <ModelVariable name> is hierarchConn.innerConn.U
, <outer terminal name> is hierarchConn
, <inner terminal name> is innerConn
, <memberName> is U
.
Example 3 (no prefix): <ModelVariable name> is u
, <terminalName> is portA
, <memberName> is u
.
Example 4 (prefix but not a member): <ModelVariable name> is portA.u
, there is a terminal with <terminalName> portA
, but this variable is not a terminal member.
The suggested variable naming scheme for the non-structured naming convention is: <ModelVariable name> = <memberName>
Matching is not restricted by variability
, causality
or variable type.
Example: A fixed
variable may be connected to a tunable
variable, a variable of type fmi3Float64
may be connected to a variable of type fmi3Int32
.
However, it is recommended that the variable types and variabilities are equal.
The matchingRule
refers to the <TerminalMemberVariable>
on the same level only.
Nested terminals can have different `matchingRule`s.
There is no special handling of derivatives
.
If a derivative
is a terminal member variable then it is considered as normal member variable.
However, if a derivative
of a terminal member variable is not terminal member, then this derivative
information may be used by an importing tool.]
2.4.7.2.4. Terminal Stream Member Variable
The <TerminalStreamMemberVariable>
is defined as:

This element is used for variables which fulfill the balance equation for transported quantities.
It is restricted to input
and output
, parameter
and calculatedParameter
.
The Stream concept is described in the appendix D.3 of the Modelica specification.
Only one terminal member variable with the variableKind
inflow
or outflow
per terminal is allowed, if a <TerminalStreamMemberVariable>
is present.
[More sophisticated structures can be implemented using hierarchical terminals.]
The attribute inStreamVariableName
and outStreamVariableName
are used to identify the <ModelVariables>
.
If the referenced model variables are arrays, then the size of the inStreamVariableName
and outStreamVariableName
has to be equal.
A terminal may have more than one <TerminalStreamMemberVariable>
.
The inStreamMemberName
and outStreamMemberName
describe the terminal member name for matching purposes, similar to the memberName
attribute in the <TerminalMemberVariable>
.
[An example of use for an array of stream variables is a gas mixture flow.
The gas composition could be implemented as a mass fraction vector.
The outStreamVariableName
refers to \(portA.q_\textit{outStream}\textit{[]}\) and the inStreamVariableName
refers to \(portA.q_\textit{inStream}\textit{[]}\) .
The inStreamMemberName
and outStreamMemberName
are " \(q_\textit{inStream}\textit{[]}\) " and " \(q_\textit{outStream}\textit{[]}\) ".
Balance equation for transported quantities:
\(0 = \sum{q_i\dot{m}_i}\)
\(0 = \sum{\dot{m}_i}\cdot \left\{\begin{array}{ll} q_{i, \mathit{outStream}} &\textit{if $\dot{m}$ is outflowing through terminal $i$}\\ q_{i, \mathit{inStream}} &\textit{if $\dot{m}$ is inflowing through terminal $i$} \end{array}\right.\)
The \(q_{i,\mathit{outStream}}\) is the convective quantity in case the matter flows out of the FMU.
\(q_{i,\mathit{inStream}}\) is the convective quantity in case the matter flows into the FMU.
Both variables are present in the terminal.
The outStream variable has the causality
output
or calculatedParameter
because this information has to be provided by each FMU.
The inStream variable has the causality
input
or parameter
.
To display the actual value in an importing tool, this actual value has to be selected depending on the sign of the terminal member variable with variableKind
inflow
or outflow
.
However, calculating the actual value is not necessary.
If only two terminals with a variable are connected and their causality
matches, then the values of the outStream variables can be forwarded to the corresponding inStream values.
In Modelica the inStream variable is not directly visible, the value can only be accessed using "inStream()", therefore an additional model variable has to be added during the export. It is suggested that Modelica tools exporting an FMU derive the member name for the inStream variable according to the scheme "<outStream name>_inStream". E.g. if the outStream name is "h_outflow" then the inStream name should be "h_outflow_inStream".]
2.4.7.2.5. Terminal Graphical Representation
The <TerminalGraphicalRepresentation>
is defined as:

The iconBaseName
attribute is mandatory.
This attribute defines the base name of the image file as a relative URI according to RFC 3986.
The base URI that this relative URI is resolved against is the URI of the icons/terminalsAndIcons.xml
file in the FMU ZIP archive.
Implementations are required to support relative URIs, excluding relative URIs that move beyond the baseURI (i.e. go "up" a level via ..).
Implementations are not required to support any absolute URIs and any specific URI schemes.
The PNG file with the extension '.png' has to be provided.
An additional SVG file with extension '.svg' is optional.
[Note that this specification is functionally equivalent to looking up image sources from the icons folder of the FMU ZIP archive after dot removal from the path as per section 5.2.4 of RFC 3986.]
The defaultConnectionStrokeSize
and defaultConnectionColor
can be provided to define the intended connection line layout in the importing tool.
The stroke size is given relative to the coordinate system extent.
The stroke color is given in RGB values from 0 to 255. E.g.: 255 255 0
.
[Nested terminals may have a <TerminalGraphicalRepresentation>
element.
However, if and how nested terminals are displayed, is up to the importing tool.]
[The order of painting of the <TerminalGraphicalRepresentation>
of terminals on each level is equal to the order of appearance in the <Terminal>
element.
So graphical representations appearing first, are painted first, are behind graphical representations which appear below.]
The Annotations
element can be used by vendors to store additional information for the graphical representation.
[It is suggested that Modelica tools store the Modelica annotation of the connector under the type
org.modelica.Modelica4Annotation
in the annotations of an element connector
.
The attribute name
of the connector element is equal to the name
attribute of the referenced fmi3Terminal
.]
2.4.7.2.6. General Remark on Signal
[The signal variableKind
can be applied for different use cases.
The first use case is a signal flow from an output
of one FMU to an input
of another FMU.
The output
value has to be forwarded to the input
.
The signal flow can cause algebraic loops.
If variables in connected terminals have the causality
output
, then an importing tool may iterate an undefined input
of an FMU to ensure that the connected output values are equal.
Another use case is the parameter propagation.
If a variable in both connected terminals has the causality
parameter
, then an importing tool could ask the user for the value of one of those parameters
only, and propagate this value to the other FMU.
If only one of the variables has causality
parameter
, and the other is a constant
output
or calculatedParameter
, then the importing tool could also propagate the parameter
value without presenting a parameter to the user.
One example of use would be the name of a substance flowing through a pipe.
If the fluid flows from one pipe FMU to another, the substance should be the same.
This substance name could be propagated over several FMUs.
Finally the variableKind
signal
can be applied to implement compatibility checks.
If for example the variability
of the variables in connected terminals are constant
, then the importing tool can implement an equality assertion.
This is also possible with calculated
parameters
.
One example of use would be the cross sectional flow area in pipes which is calculated from geometry parameters.
A change in the cross sectional flow area is relevant for the momentum equation, and therefore the connection has to be deemed incompatible if these variables are present and unequal.]
2.4.7.2.7. General Remark on Inflow and Outflow
[Flow variables have a direction and must fulfill a zero sum constraint i.e. the sum of all flow variables connected must be zero (Kirchhoff’s current law).
In addition because different tools might have different direction definitions both, inflow
and outflow
are available as variableKind
.
For variables with inflow
a positive value means that the flow is inwards, and for outflow
a positive value means that the flow is outwards.
For the sake of simplicity in the following \(\dot{m}_i\) denotes an inflowing quantity:
\(0 = \sum{\dot{m}_i}\)
[Connecting a single output
outflow
to a single input
inflow
, or vice versa automatically fulfills the flow constraint, while connecting two variables of the same flow type requires a negation of the variable value.
inflow
and outflow
is only used as a sign convention for scalar flow quantities which obey Kirchhoff’s current law (sum up to zero).
Other, nonscalar, quantities which also sum up to zero, like a mechanical force in 3D space according to D’Alembert’s principle, are not covered by this sign convention.
This is the case since Kirchhoff’s current law only holds for scalars where a sign convention is sufficient.
Other definitions are beyond the scope of this terminal specification and need clear definition in other specifications on top of this.]
2.4.8. Definition of Model Variables
The element of <fmiModelDescription><ModelVariables>
is the central part of the model description.
It provides the static information of all exposed variables and is defined as follows.

The <ModelVariables>
element consists of an ordered set of variable elements (see Figure 32).
Variable elements can uniformly represent variables of primitive (atomic) types, like single floating point or integer variables, or as well as arrays of an arbitrary (but fixed) number of dimensions.
The schema definition is present in a separate file fmi3Variable.xsd
.
Variable elements representing array variables must contain at least one <Dimension>
element.
Each <Dimension>
element specifies the size of one dimension of the array:
-
If the
start
attribute of the<Dimension>
element is present, it defines a constant unsigned 64-bit integer size for this dimension. Thevariability
of the dimension size isconstant
in this case. -
If the
valueReference
attribute of the<Dimension>
element is present, it defines the size of this dimension to be the value of the variable with the value reference given by thevalueReference
attribute. The referenced variable must be a variable of type<UInt64>
, and must either be a constant (i.e. withvariability
=constant
) or astructural parameter
(i.e. withcausality
=structuralParameter
). Thevariability
of the dimension size is in this case thevariability
of the referenced variable.
These two options are mutually exclusive, i.e., for each <Dimension>
element either a start
attribute or a valueReference
attribute can be supplied, but not both.
However different dimension sizes can be specified using different mechanisms and can have differing variability
attributes.
All initial dimension sizes (i.e. prior to any configuration or reconfiguration) must be positive integers (i.e. not zero), so that no dimension is initially vanished.
[This allows importing tools to ignore structural parameters
because that start
value reflects the internal default setting of that structural parameter
.
The rationale for requiring positive start values for structural parameters
is that this avoids importers having to deal with vanishing dimensions if they do not want to deal with them (or even with changing sizes at all).
If we allowed 0 dimension sizes for initial values, tools that do not even care about changing dimension sizes must be prepared to handle vanishing dimensions.]
Changes to dimension sizes are constrained by the min
/max
attributes of the referenced structural parameters
, which can be any non-negative integer, including zero.
Specifying a minimum size of zero on a structural parameter
allows any related dimension sizes to be changed to zero in Configuration Mode or Reconfiguration Mode, thus causing the respective array size to go to zero, which leaves the respective array variable without any active elements.
The actual dimension sizes of arrays are also constrained by the FMU platform, due to memory and addressing constraints:
Since the API functions to access variables and their values are constrained to size_t
individual elements, platforms with addresses of less than 64-bit width will not be able to access elements beyond their addressing limits, neither will they be able to allocate enough memory or address space to represent such arrays.
For these reasons implementations must take platform-specific constraints into account when changing dimension sizes, and must be prepared to handle the inability of the FMU to adjust to the desired sizes during Configuration Mode or Reconfiguration Mode.
Changing any dimension of a variable in Configuration Mode or Reconfiguration Mode invalidates the variable’s current value (including its start
value).
It should be noted that changing a structural parameter
might affect dimension sizes of several variables.
A variable can have any number of <Alias>
elements that define a variable alias.
Each variable alias has a required attribute name
whose value must be unique among all variables and variable aliases, and an optional attribute description
.
Variable aliases of floating point variables may additionally have a displayUnit
that follows the same rules as for variables.
[ Example:
<Float64 name="engine.torque" valueReference="1" unit="N.m">
<Alias name="engine.torqueLbfFt" description="Engine torque in pound-foot"
displayUnit="lbf.ft"/>
</Float64>
]
The attributes of variables are:

Attribute | Description |
---|---|
|
The full, unique name of the variable. Every variable is uniquely identified within an FMU instance by this name. |
|
A handle of the variable to efficiently identify the variable value in the model interface and for references within the |
|
An optional description string describing the meaning of the variable. |
|
Enumeration that defines the causality of the variable. Allowed values of this enumeration:
Setting of local variables:
[Continuous-time [TODO: add ClockedState elements to ModelStructure.] [TODO: rename Derivative to StateDerivative to differentiate between derivatives of states and general derivatives of any other variable.]
[ Example:
]
The default of [ |
|
Enumeration that defines the time dependency of the variable, in other words, it defines the time instants when a variable can change its value.
[The purpose of this attribute is to define when a result value needs to be inquired and to be stored.
For example,
The default is [Note that the information about continuous |
|
Enumeration that defines how the variable is initialized, i.e. if a For the variable with The attribute
If [The environment decides when to use the If If |
|
Only for variables with |
|
The optional attribute If the If the If |
|
The optional attribute |
|
If this boolean attribute is This attribute is only used for Co-Simulation.
The default value of this attribute is |
If initial
is not present, its value is defined by Table 19 based on the values of causality
and variability
(default underlined):
|
— |
— |
— |
— |
exact |
exact |
— |
|
|
exact |
exact |
calculated, approx |
— |
— |
calculated, approx |
— |
|
|
exact |
exact |
calculated, approx |
— |
— |
calculated, approx |
— |
|
|
— |
— |
— |
exact |
calculated, exact, approx |
calculated, exact, approx |
— |
|
|
— |
— |
— |
exact |
calculated, exact, approx |
calculated, exact, approx |
— |
|
— |
— |
— |
exact |
calculated |
calculated |
— |
[Note: For local and output variables and initial
= exact
, then the variable is explicitly set in Initialization Mode.
The value of the variable is either the start
value stored in a variable element <XXX start=YYY/>
or the value set with fmi3Set{VariableType}
during Initialization Mode.]
Table 20 shows the combinations of variability
/causality
settings that are allowed.
|
— (a) |
— (a) |
— (a) |
— (a) |
(7) |
(10) |
— (c) |
|
|
(16) |
(1) |
(3) |
— (d) |
— (e) |
(11) |
— (c) |
|
|
(17) |
(2) |
(4) |
— (d) |
— (e) |
(12) |
— (c) |
|
|
— (b) |
— (b) |
— (b) |
(5) |
(8) |
(13) |
— (c) |
|
|
— (b) |
— (b) |
— (b) |
(6) |
(9) |
(14) |
(15) |
|
— |
— |
— |
(18) |
(18) |
(19) |
— |
[Discussion of the combinations that are not allowed:
Explanation why this combination is not allowed | |
---|---|
(a) |
The combinations |
(b) |
The combinations |
(c) |
For an |
(d) |
A |
(e) |
A |
Discussion of the combinations that are allowed:
Setting | Example | |
---|---|---|
(1) |
||
(2) |
|
|
(3) |
Non- |
|
(4) |
|
|
(5) |
||
(6) |
|
|
(7) |
Variable where the value never changes and that can be used in another model. |
|
(8) |
|
|
(9) |
|
|
(10) |
Variable where the value never changes. Cannot be used in another model. |
|
(11) |
Local variable that depends on |
|
(12) |
Local variable that depends on |
|
(13) |
|
|
(14) |
|
|
(15) |
All variables are a function of the continuous-time variable marked as |
|
(16) |
|
|
(17) |
|
|
(18) |
Variable that defines a |
|
(19) |
Variable that defines a |
How to treat tunable
variables:
A parameter
p is a variable that does not change its value during simulation, in other words, dp/dt = 0.
If the parameter
p is changing, then Dirac impulses are introduced since dp/dt of a discontinuous constant
variable p
is a Dirac impulse.
Even if this Dirac impulse would be modeled correctly by the modeling environment, it would introduce unwanted vibrations
.
Furthermore, in many cases the model equations are derived under the assumption of a constant
value (like mass or capacity), and the model equations would be different if p
would be time varying.
FMI for Model Exchange:
Therefore, "tuning a (structural) parameter
" during simulation does not mean to "change the parameter online" during simulation.
Instead, this is a short hand notation for:
-
Stop the simulation at an event instant (usually, a step event, in other words, after a successful integration step).
-
Change the values of the
tunable
(structural)parameters
. Fortunable
structural parameters
, the Reconfiguration Mode must be entered before and left afterwards. -
Compute all
parameters
(and sizes of variables,states
,derivatives
, event indicators, …) that depend on thetunable
(structural)parameters
. -
Newly start the simulation using as initial values previously stored values and the new values of the
parameters
.
Basically this means that a new simulation run is started from the previous FMU state with changed parameter
values.
With this interpretation, changing parameters
online is "clean", as long as these changes appear at an event instant.
FMI for Co-Simulation:
Changing of tunable
parameters
is allowed before an fmi3DoStep
call (so, whenever an input
can be set with fmi3Set{VariableType}
) and before fmi3ExitInitializationMode
is called (that is before and during Initialization Mode).
The FMU internally carries out event handling if necessary.]
Type specific properties are defined in the required choice element, where exactly one of the numeric types or an <Enumeration>
must be present in the XML file:
Figure 34, Figure 35, Figure 36, Figure 37, and Figure 38, are representative examples.





The attributes are defined in Section 2.4.4 (<TypeDefinitions>
), except:
Attribute | Description |
---|---|
|
If present, name of type defined with |
|
Initial or guess value of variable.
This value is also stored in the C functions.
[Therefore, calling The The interpretation of [The standard approach is to set the If Variables with
|
|
If present, this variable is the derivative of variable with value reference The |
|
Only for Model Exchange (if only a Co-Simulation FMU, this attribute must not be present.
If both Model Exchange and a Co-Simulation FMU, this attribute is ignored for co-simulation): |
|
The optional attributes |
2.4.9. Definition of the Model Structure
The structure of the model is defined in element <fmiModelDescription><ModelStructure>
.
This structure is with respect to the underlying model equations, independently how these model equations are solved.
[For example, when exporting a model in more than one FMI format; then the model structure is identical in all cases.
E.g. a Co-Simulation FMU has either an integrator included that solves the model equations, or the discretization formula of the integrator and the model equations are solved together ("inline integration").
In all cases the model has the same continuous-time states
.
In the case of a Model-Exchange FMU, the internal implementation is a discrete-time system, but from the outside this is still a continuous-time model that is solved with an integration method.]
The required part defines an ordering of the outputs
, the (exposed) derivatives
, the event indicators, and the unknowns that are available during Initialization [Therefore, when linearizing an FMU, every tool will use the same ordering for the outputs
, states
, and derivatives
for the linearized model.
The ordering of the inputs
should be performed in this case according to the ordering in <ModelVariables>
.]
A Model Exchange FMU must expose all derivatives
of its continuous-time states
in elements <ModelStructure><Derivative>
and must expose all event indicators in elements <EventIndicator>
.
A Co-Simulation FMU does not need to expose these state derivatives and event indicators.
[If a Co-Simulation FMU exposes its state derivatives, they are usually not utilized for the co-simulation, but, for example, to linearize the FMU at a communication point.]
The optional part defines in which way derivatives
, outputs
, and initial unknowns, depend on inputs
, and continuous-time states
, at the current super-dense time instant (ME) or at the current communication point (CS and SE).
[The listed dependencies
declare the dependencies between whole (multi-dimensional-)variables and not individual elements of the variables.]
[A simulation environment can utilize this information to improve the efficiency, for example, when connecting FMUs together, or when computing the partial derivative of the derivatives
with respect to the states
in the simulation engine.]
Figure 39 shows the definition of <ModelStructure>
.

Note that attribute dependenciesKind
for element <InitialUnknown>
has less enumeration values as dependenciesKind
in the other lists, as detailed in Table 24.
<ModelStructure>
consists of the elements detailed in Table 24 (see also Figure 39; the symbols of the mathematical equations describing the dependency are defined in Section 3.1):
Element | Description |
---|---|
|
Ordered list of all outputs, in other words, a list of value references where every corresponding variable must have |
|
Ordered list of all state derivatives, in other words, a list of value references where every corresponding variable must be a state derivative.
[Note that only The corresponding continuous-time |
|
Ordered list of all exposed unknowns in Initialization Mode. This list consists of all variables with - - - all continuous-time The resulting list is not allowed to have duplicates (for example, if a \({\mathbf{v}_{\mathit{initialUnknowns}} := \mathbf{f}_{\mathit{init}}(\mathbf{u}_c, \mathbf{u}_d, t_0, \mathbf{v}_{\mathit{initial=exact}})}\) Since, [Example: Assume an FMU is defined in the following way: \({(\mathbf{y}_{c+d}, \dot{\mathbf{x}}_c) := \mathbf{f}_{\mathit{init}}(\mathbf{x}_c, \mathbf{u}_{c+d}, t_0, \mathbf{p})}\) \({(\mathbf{y}_{c+d}, \dot{\mathbf{x}}_c) := \mathbf{f}_{\mathit{sim}}(\mathbf{x}_c, \mathbf{u}_{c+d}, t_i, \mathbf{p})}\) Therefore, the initial state \({\mathbf{x}_c(t_0)}\) has |
|
Ordered list of all event indicators, in other words, a list of value references where every corresponding variable must be a event indicator.
[Note that only For Co-Simulation, elements |
Elements <Output>
, <Derivative>
and <InitialUnknown>
have the following attributes:
Attribute | Description |
---|---|
|
The value reference of the unknown \({v_{\mathit{unknown}}}\). |
|
Optional attribute defining the dependencies of the unknown \({v_{\mathit{unknown}}}\) (directly or indirectly via auxiliary variables) with respect to \({\mathbf{v}_{\mathit{known}}}\).
If not present, it must be assumed that the unknown depends on all knowns.
If present as empty list, the unknown depends on none of the knowns.
Otherwise the unknown depends on the knowns defined by the given value references. - inputs (variables with - continuous-time states - [
- inputs (variables with - variables with - For Co-Simulation, if the capability flag |
|
If
Only for floating point type unknowns \({v_{\mathit{unknown}}}\):
Only for floating point type unknowns \({v_{\mathit{unknown}}}\) in Event and Continuous-Time Mode (ME) and at communication points (CS and SE), and not for
|
[Example 1:
An FMU is defined by the following equations:
where \({u_{1}}\) is a continuous-time input
(variability
= continuous
), \({u_{2}}\) is any type of input
, \({u_{3}}\) is a floating point discrete-time input
(variability
= "discrete"`), and \({p}\) is a fixed
parameter
(variability
= fixed
).
The initialization is defined by:
and therefore, the initialization equations are:
This equation system can be defined as:
<ModelVariables>
<Float64 name="p" valueReference= "1"/>
<Float64 name="u1" valueReference= "2"/>
<Float64 name="u2" valueReference= "3"/>
<Float64 name="u3" valueReference= "4"/>
<Float64 name="x1" valueReference= "5"/>
<Float64 name="x2" valueReference= "6"/>
<Float64 name="x3" valueReference= "7"/>
<Float64 name="der(x1)" valueReference= "8" derivative="5"/>
<Float64 name="der(x2)" valueReference= "9" derivative="6"/>
<Float64 name="der(x3)" valueReference="10" derivative="7"/>
<Float64 name="y" valueReference="11" causality="output"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="11" dependencies="6 7"/>
<Derivative valueReference="8" dependencies="6"/>
<Derivative valueReference="9" dependencies="2 4 5 6" dependenciesKind="constant constant dependent fixed"/>
<Derivative valueReference="10" dependencies="2 3 4 5 6" />
<InitialUnknown valueReference="6" dependencies="2 4 5"/>
<InitialUnknown valueReference="7" dependencies="2 4 5 11"/>
<InitialUnknown valueReference="8"/>
<InitialUnknown valueReference="10"/>
<InitialUnknown valueReference="11"/>
</ModelStructure>
Example 2:
where \({u}\) is a continuous-time input
with valueReference
= 1
and \({y}\) is a continuous-time output
with valueReference
= 2
.
The definition of the model structure is then:
<ModelStructure>
<Output valueReference="2" dependencies="1" dependenciesKind="discrete"/>
<InitialUnknown valueReference="2"/>
</ModelStructure>
[Note that \({y = d \cdot u}\) where \({d}\) changes only during Event Mode ( \({d = 2 \cdot u}\) or \({3 \cdot u\ }\) depending on relation \({u > 0}\) that changes only at Event Mode).
Therefore dependenciesKind
= discrete
.]
Example 3:
where \({u}\) is a continuous-time input
with valueReference
= 1
and \({y}\) is a continuous-time output
with valueReference
= 2
.
The definition of the model structure is then:
<ModelStructure>
<Output valueReference="2" dependencies="1" dependenciesKind="dependent"/>
<InitialUnknown valueReference="2"/>
</ModelStructure>
[Note that \({y = c}\) where \({c}\) changes only during Event Mode ( \({c = 2}\) or \({3\ }\) depending on relation \({u > 0}\) that changes only at Event Mode).
Therefore dependenciesKind
= dependent
because it is not a linear relationship on \({u}\). ]
Example 4:
where u
is continuous-time input value reference 1
, y
is a continuous-time output with value reference 2
and dxdt
is a continuous-time derivative with value reference 4
.
The definition of the model structure is then:
<ModelVariables>
<Float64 name="u" valueReference= "1"/>
<Float64 name="y" valueReference= "2" causality="output"/>
<Float64 name="x" valueReference= "3"/>
<Float64 name="dxdt" valueReference= "4"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="2" dependencies="3" dependenciesKind="constant"/>
<Derivative valueReference="4" dependencies="1" dependenciesKind="constant"/>
<InitialUnknown valueReference="2" dependencies="3"/>
</ModelStructure>
Defining FMU features with the dependencies
list:
[Note that via the dependencies
list the supported features of the FMU can be defined.
Examples:
-
If a state derivative
der_x
is a function of aparameter
p (so of astart
value of a variable withcausality
=parameter
andvariability
=fixed
), and the FMU does not support an iteration overp
during Initialization Mode (for example, to iterate over p such that the state derivativeder_x
is zero), then thedependencies
list ofder_x
should not includep
. If an FMU is imported in an environment and such an iteration is set up, then the tool can figure out that the resulting algebraic system of equations is structurally singular and therefore can reject such a definition. -
For Co-Simulation FMUs, it is common that no algebraic loops over the
input
/output
variables nor overstart
values is supported. In such a case, alldependencies
lists foroutput
variables under the<InitialUnknown>
element should be defined as empty lists defining that the setting ofinputs
and/or ofstart
values does not influence theoutputs
. As a result, it is not possible to formulate algebraic loops of connected FMUs during Initialization Mode.]
2.4.10. Variable Naming Conventions
With attribute variableNamingConvention
in <fmiModelDescription>
, the convention is defined how the variable names have been constructed.
If this information is known, the environment may be able to represent the names in a better way (for example, as a tree and not as a linear list).
In the following definitions, the EBNF is used:
= production rule [ ] optional { } repeat zero or more times | or
The names must be unique, non-empty strings.
[It is recommended that the names are visually clearly different from each other; but it is not required.]
The following conventions for scalar names are defined:
variableNamingConvention = flat
name = Unicode-char { Unicode-char } // identical to xs:normalizedString Unicode-char = any Unicode character without carriage return (#xD), line feed (#xA) nor tab (#x9)
variableNamingConvention = structured
Structured names are hierarchical using "." as a separator between hierarchies.
A name consists of "_", letters and digits or may consist of any characters enclosed in single apostrophes.
A name may identify an array element on every hierarchical level using "[…]" to identify the respective array index.
If an array is a leaf node of the variable hierarchy then the array can also be represented as a single variable of type array.
A derivative
of a variable is defined with der(name)
for the first time derivative and der(name,N)
for the N-th derivative.
Examples:
vehicle.engine.speed resistor12.u v_min robot.axis.'motor #234' der(pipe[3,4].T[14],2) // second time derivative of pipe[3,4].T[14]
The precise syntax is:
name = identifier | "der(" identifier ["," unsignedInteger ] ")" identifier = B-name [ arrayIndices ] {"." B-name [ arrayIndices ] } B-name = nondigit { digit | nondigit } | Q-name nondigit = "pass:[_]" | letters "a" to "z" | letters "A" to "Z" digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Q-name = "'" ( Q-char | escape ) { Q-char | escape } "'" Q-char = nondigit | digit | "!" | "#" | "$" | "%" | "&" | "(" | ")" | "*" | "+" | "," | "-" | "." | "/" | ":" | ";" | "<" | ">" | "=" | "?" | "@" | "[" | "]" | "^" | "{" | "}" | "|" | "~" | " " escape = "\'" | "\"" | "\?" | "\\" | "\a" | "\b" | "\f" | "\n" | "\r" | "\t" | "\v" arrayIndices = "[" unsignedInteger {"," unsignedInteger} "]" unsignedInteger = digit { digit }
[This definition is identical to the syntax of an identifier in Modelica version 3.2.]
The tree of names is mapped to an ordered list of variable names in depth-first order. Example:
vehicle transmission ratio outputSpeed engine inputSpeed temperature
is mapped to the following list of variable names:
vehicle.transmission.ratio vehicle.transmission.outputSpeed vehicle.engine.inputSpeed vehicle.engine.temperature
All flattened array elements are given in a consecutive sequence of variables. Elements of multi-dimensional arrays are ordered according to "row major" order that is elements of the last index are given in sequence.
[For example, the vector centerOfMass
in body arm1
is mapped to the following variables:
robot.arm1.centerOfMass[1] robot.arm1.centerOfMass[2] robot.arm1.centerOfMass[3]
[For example, a controller might receive 3 rpm sensors mapped to the following variables:
transmission.rpms[0] transmission.rpms[1] transmission.rpms[2]
For example, a table T[4,3,2]
(first dimension 4 entries, second dimension 3 entries, third dimension 2 entries) is mapped to the following variables:
T[1,1,1] T[1,1,2] T[1,2,1] T[1,2,2] T[1,3,1] T[1,3,2] T[2,1,1] T[2,1,2] T[2,3,1] ...
]
It might be that not all elements of an array are present. If they are present, they are given in consecutive order in the XML file.
The variableNamingConvention
structured
does not define if arrays are 0-based or 1-based.
[FMI 3.0 introduces arrays of variables to improve handling of arrays.]
2.5. FMU Distribution
An FMU consists of several files, that are stored in a ZIP file with a pre-defined structure.
The implementation of the simulation model represented by the FMU may be distributed in source code and/or in binary format.
The FMU must be distributed with at least one implementation, in other words, either sources or one of the binaries for a particular machine.
It is also possible to provide the sources and binaries for different target machines together in one ZIP file.
The FMU must implement all common API functions according to Section 2.2 and the functions for at least one of the FMI interface types.
Especially it is required that all functions that are part of the specified FMI interface type are present, even if they are only needed for optional capabilities that the FMU does not support.
The behavior of those functions is unspecified, so while calling environments can rely on the functions being present, they cannot rely on any particular behavior for functions only needed for capabilities the FMU does not support.
The extension of the ZIP file must be .fmu
[, for example, HybridVehicle.fmu
].
The compression method used for the ZIP file must be deflate
[(most free tools, such as zlib, offer only the common compression method deflate
)].
[Note: especially section 4.4.17 of the ZIP format specification states that backslashes "\" are forbidden as path separator, only forward slashes "/" are allowed.
Non-ASCII directory names are not explicitly forbidden, but might pose a problem on different operating systems and are thus discouraged.]
Every FMU is distributed with its own ZIP file.
2.5.1. Structure of the ZIP file
// Structure of ZIP file of an FMU modelDescription.xml // description of FMU (required file) documentation // directory containing the documentation (optional) index.html // entry point of the documentation diagram.png // descriptive diagram view of the model (optional) diagram.svg // if existing the diagram.png is required (optional) <other documentation files> licenses // directory for licenses (optional) license.{txt|html} // Entry point for license information <license files> // For example BSD licenses icons // FMU and terminal icons (optional) terminalsAndIcons.xml // description of terminals and icons (optional) icon.png // image file of icon without terminals (optional) icon.svg // if existing the icon.png is required (optional) // all terminal and fmu icons referenced in the graphical representation sources // directory containing the C sources (optional) buildDescription.xml // All needed C sources and header files to compile and link the FMU // except fmi3PlatformTypes.h, fmi3FunctionTypes.h, and fmi3Functions.h. // The files to be compiled (but not the files included from these files) // have to be reported in the buildDescription.xml. binaries // directory containing the binaries (optional) x86_64-windows // binaries for Windows on Intel 64-bit <modelIdentifier>.dll // shared library of the FMI implementation <other DLLs> // the DLL can include other DLLs x86_64-windows-msvc140mt // static libraries for 64-bit Windows generated <modelIdentifier>.lib // with Visual Studio 2015 with /MT flag i686-linux // binaries for Linux on Intel 32-bit <modelIdentifier>.so // shared library of the FMI implementation aarch32-linux // binaries for Linux on ARM 32-bit <modelIdentifier>.so // shared library of the FMI implementation x86_64-darwin // binaries for macOS <modelIdentifier>.dylib // shared library of the FMI implementation // If an FMU is run through one of its binaries all items in that binary // folder are recommended to be unpacked at the same location as the binary // < modelIdentifier >.* is unpacked. If not it is likely that, if the FMU // has dependencies on those items, it will not be able to find them. resources // resources used by the FMU (optional) // data in FMU specific files which will be read during initialization; // also more folders can be added under resources (tool/model specific). // In order for the FMU to access these resource files, the resource directory // shall be available in unzipped form and the absolute path to this directory // should be reported via argument "resourceLocation" of fmi3InstantiateXXX. extra // Additional (meta-)data of the FMU (optional) // additional (meta-)data that is supposed to travel with the FMU; // see below for structure and content definition.
2.5.2. Documentation Directory
2.5.2.1. Licenses Subdirectory
This optional subdirectory can be used to bundle all license texts for the code, binaries or other material (documentation, content of resources folder) contained tin the FMU.
If it is present, it must contain either a license.txt
or license.html
file as entry point.
[It is strongly recommended to include all license and copyright related information in the licenses folder of an FMU (especially but not only for contained open source software) - the license.{txt|html}
file can serve as an entry point for describing the contained licenses.
This will help the users to comply with license conditions when passing source or binary code contained in an FMU to other persons or organizations.]
2.5.3. Sources Directory
#include
directive with "…"
should be used for header files distributed in the FMU instead of using <…>
.
In case information beyond <BuildConfiguration>
is required to compile the FMU for specific targets, the documentation
directory is the place to store further instructions.
[Note that the header files fmi3PlatformTypes.h
and fmi3FunctionTypes.h/fmi3Functions.h
are not included in the FMU due to the following reasons:
fmi3PlatformTypes.h
makes no sense in the sources
directory, because if sources are provided, then the importer defines this header file and not the FMU.
This header file is not included in the binaries
directory, because it is implicitly defined by the platform directory (for example, i686-windows
for a 32-bit machine or x86_64-linux
for a 64-bit machine).
fmi3FunctionTypes.h
/ fmi3Functions.h
are not needed in the sources
directory, because they are implicitly defined by attribute fmiVersion
in file modelDescription.xml
.
Furthermore, in order that the C compiler can check for consistent function arguments, the header file from the importer should be used when compiling the C sources.
It would therefore be counter-productive (unsafe) if this header file was present.
These header files are not included in the binaries
directory, since they are already utilized to build the executable of the simulation environment.
The version number of the header file used to construct the FMU can be deduced via attribute fmiVersion
in file modelDescription.xml
or via function call fmi3GetVersion
.]
2.5.4. Binaries Directory
2.5.4.1. Platform Tuple Definition
The names of the binary directories are standardized by the "platform tuple".
Further names can be introduced by vendors.
Dynamic link libraries must include all referenced resources that are not available on a standard target machine [for example, DLLs on Windows that are built with Visual Studio should be compiled with the /MT
option to include the required symbols from the Visual C runtime in the DLL, and not use the option /MD
where this is not the case].
When compiling a shared object on Linux, RPATH="$ORIGIN"
has to be set when generating the shared object in order that shared objects used from it, can be dynamically loaded.
The binaries must be placed in the respective <platformTuple> directory with the general format <arch>-<sys>{-<abi>{<abi_ver>}{<abi_sub>}}
.
- Architecture
<arch>
-
Name Description aarch32
ARM 32-bit Architecture
aarch64
ARM 64-bit Architecture
i386
Intel 3rd generation x86 32-bit
i586
Intel 5th generation x86 32-bit w/o SSE
i686
Intel 6th generation x86 32-bit with SSE2
x86_64
Intel/AMD x86 64-bit
- Operating system
<sys>
-
Name Description darwin
Darwin (macOS, iOS, watchOS, tvOS, audioOS)
linux
Linux
windows
Microsoft Windows
- Application Binary Interface (ABI)
<abi>
-
Name Description elf
ELF file format
gnu
GNU
android
Android
macho
Mach object file format
msvc
Microsoft Visual C
- ABI version
<abi_ver>
-
Name Description 80
Visual Studio 2005 (MSVC++ 8.0)
90
Visual Studio 2008 (MSVC++ 9.0)
100
Visual Studio 2010 (MSVC++ 10.0)
110
Visual Studio 2012 (MSVC++ 11.0)
120
Visual Studio 2013 (MSVC++ 12.0)
140
Visual Studio 2015 (MSVC++ 14.0)
141
Visual Studio 2017 (MSVC++ 15.0)
- Sub-ABI
<abi_sub>
-
Name Description md
Visual Studio with /MD
mt
Visual Studio with /MT
mdd
Visual Studio with /MDd
mtd
Visual Studio with /MTd
[Typical scenarios are to provide binaries only for one machine type (for example, on the machine where the importer is running and for which licenses of run-time libraries are available) or to provide only sources (for example, for translation and download for a particular micro-processor).]
2.5.4.2. External Libraries
If run-time libraries are needed by the FMU that have to be present on the target machine and cannot be shipped within the FMU (e.g., due to licensing issues), then automatic processing is likely impossible.
In such cases special handling is needed, for example, by providing the run-time libraries at appropriate places by the receiver.
The requirements and the expected processing should be documented in the documentation
directory in this case.
2.5.4.3. Dependency on Installed Tool
FMI provides the means for two kinds of implementation: needsExecutionTool = true
and needsExecutionTool = false
.
In the first case a tool specific wrapper DLL/SharedObject has to be provided as the binary, in the second a compiled or source code version of the model with its solver is stored (see Section 4 for details).
2.5.4.4. Multiple Interface Types
In an FMU multiple interface types might be present.
If in all cases the executable part is provided as a shared library, then one of up to four libraries can be provided.
The library names are defined in the modelIdentifier
attribute of elements <fmiModelDescription><ModelExchange|CoSimulation|ScheduledExecution>
:
[Example of different libraries: binaries x86_64-windows MyModel_ModelExchange.dll // modelIdentifier of <ModelExchange> = // "MyModel_ModelExchange" MyModel_CoSimulation.dll // modelIdentifier of <CoSimulation> = // "MyModel_CoSimulation" ]
[The usual distribution of an FMU will be with DLLs/SharedObjects because then further automatic processing (for example, importing into another tool) is possible.]
A source-based distribution might require manual interaction in order that it can be utilized.
The intention is to support platforms that are not known in advance (such as HIL platforms or microcontrollers).
All source file names that need to be defined in a compiler directive have to be defined in sources/buildDescription.xml
.
2.5.5. Resources Directory
In the optional directory resources
, additional data can be provided in FMU specific formats, typically for tables and maps used in the FMU.
This data must be read into the model at the latest during initialization (that is, before fmi3ExitInitializationMode
is called).
The actual file names in the ZIP file to access the data files can either be hard-coded in the generated FMU functions, or the file names can be provided as string arguments via the fmi3SetString
function.
[Note that an URI pointing to the resources directory is provided by the initialization functions.
If the environment is not able to do so, a NULL pointer will be provided instead, and the FMU can react with an error, if it requires access to the content of the resources folder.]
In the case of an FMU implementation of needsExecutionTool = true
type, the resources
directory can contain the model file in the tool specific file format.
2.5.6. Extra Directory
The ZIP archive may contain additional entries with the prefix extra/
that can be used to store additional data and meta-data.
In order to avoid ambiguities and conflicts, the extra files should be provided in subdirectories using a reverse domain notation of a domain that is controlled by the entity defining the semantics and content of the additional entries [(for example extra/com.example/SimTool/meta.xml
or extra/org.example.stdname/data.asd
)].
The use of subdirectories beginning with org.modelica
and org.fmi-standard
is explicitly reserved for use by MAP FMI-defined layered standards, i.e. other uses must not use subdirectory names beginning with these prefixes.
It is explicitly allowed for tools and users other than the original creator of an FMU to modify, add or delete entries in the extra/
directory without affecting the validity of the FMU in all other aspects.
Specifically all validation or digital signature schemes used to protect the content of the FMU should take the variability of extra file content into account [(for example by having separate checksums or signatures for FMU core content and extra content, or not having signatures at all for extra content)].
2.5.7. Supporting Multiple Interface Types in one FMU
Exporters are encouraged to support multiple FMI interface types in one FMU, so it can be used in differently capable simulation algorithms and for different use cases.
To indicate support for a specific interface type, the <fmiModelDescription>
must have the respective element present.
[That improves the reusability of FMUs.
A common application of this multiple mode support is the reuse of FMUs for real-time and non-real-time simulations.]
The described multi-mode support is based on wrapping functionality into the fmi3DoStep
function by emulating missing features of the Co-Simulation or Model Exchange interface types, the FMU has been specifically exported for.
[An FMU that supports Scheduled Execution will in most cases also support Co-Simulation.
Wrapping towards other the Co-Simulation interface can influence the simulation results.
Especially aperiodic input clocks
can not always be sufficiently emulated in modes that do not directly support clocks
.
Therefore it is recommended that the FMU provides logging information to the user about the influence of the current mode on simulation results, if non-optimal modes are used by the simulation environment.]
2.5.8. Import Examples
The following code examples demonstrate how to access the FMI functions of FMUs that are implemented as a shared library or static library / source code.
2.5.8.1. Accessing FMI Functions in Shared Libraries
/* This example demonstrates how to import an FMU implemented as a shared library */
#ifdef _WIN32
#include <Windows.h>
#else
#include <dlfcn.h>
#endif
#include <stdlib.h>
// FMI function types
#include "fmi3FunctionTypes.h"
#define INSTANTIATION_TOKEN "{8c4e810f-3da3-4a00-8276-176fa3c9f000}"
#ifdef _WIN32
#define RESOURCE_LOCATION "file:/C:/tmp/VanDerPol"
#else
#define RESOURCE_LOCATION "file:///var/tmp/VanDerPol"
#endif
static void cb_logMessage(fmi3InstanceEnvironment instanceEnvironment, fmi3String instanceName, fmi3Status status, fmi3String category, fmi3String message) {
// log message...
}
int main(int argc, char* argv[]) {
#if defined(_WIN32)
HMODULE libraryHandle = LoadLibrary("VanDerPol\\binaries\\x86_64-windows\\VanDerPol.dll");
#elif defined(__APPLE__)
void *libraryHandle = dlopen("VanDerPol/binaries/x86_64-darwin/VanDerPol.dylib", RTLD_LAZY);
#else
void *libraryHandle = dlopen("VanDerPol/binaries/x86_64-linux/VanDerPol.so", RTLD_LAZY);
#endif
if (!libraryHandle) {
return EXIT_FAILURE;
}
fmi3InstantiateModelExchangeTYPE *instantiateModelExchange =
#ifdef _WIN32
GetProcAddress(libraryHandle, "fmi3InstantiateModelExchange");
#else
dlsym(libraryHandle, "fmi3InstantiateModelExchange");
#endif
fmi3FreeInstanceTYPE *freeInstance =
#ifdef _WIN32
GetProcAddress(libraryHandle, "fmi3FreeInstance");
#else
dlsym(libraryHandle, "fmi3FreeInstance");
#endif
// load remaining FMI functions...
if (!instantiateModelExchange || !freeInstance) {
return EXIT_FAILURE;
}
fmi3Instance m = instantiateModelExchange(
"instance1", // instance name
INSTANTIATION_TOKEN, // instantiation token (from XML)
RESOURCE_LOCATION, // resource location (extracted FMU)
fmi3False, // visible
fmi3False, // debug logging disabled
NULL, // instance environment
cb_logMessage); // logger callback
if (!m) {
return EXIT_FAILURE;
}
// simulation...
freeInstance(m);
// unload shared library
#ifdef _WIN32
FreeLibrary(libraryHandle);
#else
dlclose(libraryHandle);
#endif
return EXIT_SUCCESS;
}
2.5.8.2. Accessing FMI Functions in Static Libraries and Source Code
/* This example demonstrates how to import an FMU implemented as a static library or source code*/
// FMI function prefix (from XML)
#define FMI3_FUNCTION_PREFIX VanDerPol_
#include "fmi3Functions.h"
#undef FMI3_FUNCTION_PREFIX
#define INSTANTIATION_TOKEN "{8c4e810f-3da3-4a00-8276-176fa3c9f000}"
static void cb_logMessage(fmi3InstanceEnvironment instanceEnvironment, fmi3String instanceName, fmi3Status status, fmi3String category, fmi3String message) {
// log message
}
int main(int argc, char* argv[]) {
fmi3Instance m = VanDerPol_fmi3InstantiateModelExchange(
"instance1", // instance name
INSTANTIATION_TOKEN, // instantiation token (from XML)
"file:///tmp/VanDerPol", // resource location (extracted FMU)
fmi3False, // visible
fmi3False, // debug logging disabled
NULL, // instance environment
cb_logMessage); // logger callback
// simulation ...
VanDerPol_fmi3FreeInstance(m);
return m ? EXIT_SUCCESS : EXIT_FAILURE;
}
2.6. Definition of Source Code
A source code FMU contains the sources of the model in the sources
directory together with a buildDescription.xml
that contains at least one <BuildConfiguration>
element for the supported platforms.
Each <BuildConfiguration>
provides the necessary information to compile and link the sources of the model into a dynamic library or as part of an executable.
An FMU importing tool may not regard more than one <BuildConfiguration>
when building the FMU for a specific <platform>
.
The importer chooses the matching <BuildConfiguration>
based on the <platform>
and <modelIdentifier>
attributes.
Attribute | Description |
---|---|
|
The attribute |
|
Platform tuple of the platform the |
|
Description of the build configuration |
2.6.1. SourceFileSet
The <SourceFileSet>
element groups source files that can be compiled with the same compiler and compiler options.
Every build configuration must contain at least one <SourceFileSet>
.
An importer of the FMU has to regard every <SourceFileSet>
of the matching <BuildConfiguration>
.
Attribute | Description |
---|---|
|
Name of the |
|
Language of the source files (e.g. |
|
The compiler to compile the sources (e.g. |
|
The compiler flags that have to be used when compiling the sources (e.g. |
2.6.1.1. SourceFile
Attribute | Description |
---|---|
|
Path of the source file relative to the |
2.6.1.2. PreprocessorDefinition
The <PreprocessorDefinition>
element defines a preprocessor definition that needs to be passed to the compiler when compiling the source files in the <SourceFileSet>
.
Attribute | Description |
---|---|
|
Name of the preprocessor definition |
|
Value of the preprocessor definition |
|
Determines wether the definition is optional (default is |
|
Description of the preprocessor definition |
2.6.1.3. PreprocessorDefinition/Option
The <Option>
element defines a possible value for the <PreprocessorDefinition>
.
If a <PreprocessorDefinition>
contains <Option>
elements, its default value must be contained in the options.
Attribute | Description |
---|---|
|
Value of the preprocessor definition option |
|
Description of the preprocessor definition option |
2.6.1.4. IncludeDirectory
The <IncludeDirectory>
element defines the include directories that need to be passed to the compiler when compiling the source files in the <SourceFileSet>
.
Attribute | Description |
---|---|
|
Path of the include directory relative to the |
2.6.2. Library
The <Library>
element defines a static library required to link the model binary.
An importer of the FMU has to link every library of the matching <BuildConfiguration>
.
Attribute | Description |
---|---|
|
Name of the library |
|
Version specifier of the library as defined in PEP 440.
The characters |
|
Boolean attribute that determines wether the library is contained in the |
|
Description of the library definition option |
2.6.3. Examples
<?xml version="1.0" encoding="UTF-8"?>
<fmiBuildDescription fmiVersion="3.0-alpha.5">
<BuildConfiguration modelIdentifier="PIDContoller">
<SourceFileSet>
<SourceFile name="all.c"/>
</SourceFileSet>
</BuildConfiguration>
</fmiBuildDescription>
<?xml version="1.0" encoding="UTF-8"?>
<fmiBuildDescription fmiVersion="3.0-alpha.5">
<BuildConfiguration modelIdentifier="PlantModel" description="Build configuration for desktop platforms">
<SourceFileSet language="C99">
<SourceFile name="fmi3Functions.c"/>
<SourceFile name="solver.c"/>
</SourceFileSet>
<SourceFileSet language="C++11">
<SourceFile name="model.c"/>
<SourceFile name="logging/src/logger.c"/>
<PreprocessorDefinition name="FMI_VERSION" value="3"/>
<PreprocessorDefinition name="LOG_TO_FILE" optional="true"/>
<PreprocessorDefinition name="LOG_LEVEL" value="0" optional="true">
<Option value="0" description="Log infos, warnings and errors"/>
<Option value="1" description="Log warnings and errors"/>
<Option value="2" description="Log only errors"/>
</PreprocessorDefinition>
<IncludeDirectory name="logging/include"/>
</SourceFileSet>
<Library name="hdf5" version=">=1.8,!=1.8.17,<1.10" external="true" description="HDF5"/>
</BuildConfiguration>
<BuildConfiguration modelIdentifier="PlantModel" platform="aarch64-linux">
<SourceFileSet language="C99">
<SourceFile name="fmi3Functions.c"/>
</SourceFileSet>
<SourceFileSet language="C++11" compiler="clang++" compilerOptions="-fno-rtti">
<SourceFile name="model.c"/>
<PreprocessorDefinition name="NO_FILE_SYSTEM"/>
</SourceFileSet>
<Library name="libm.a" description="OpenLibm math library"/>
</BuildConfiguration>
</fmiBuildDescription>
2.7. Versioning and Layered Standards
The FMI standard uses semantic version numbers, as defined in [PW13], where the standard version consists of a triple of version numbers, consisting of major version, minor version, and patch version numbers [e.g. 1.2.3 for major version 1, minor version 2 and patch version 3].
-
Major versions will introduce changes that are neither backward nor forward-compatible, including changes to the XML schemas to include new non-ignorable content.
-
Minor versions will only contain clarifications and include new layered standards, which may add new ignorable XML content, as defined below, into the core standard document, indicating that the standard needs to be supported by all conforming implementations.
-
Patch versions will only change explanatory text of the standard, make formerly defined content clearer, without any other changes to the XML schemas or other content definitions. For this reason, the version number attribute of all FMI files will only contain major and minor version numbers and not the patch version number: It should never be necessary for an importing tool to know the patch version number of the standard that the generating tool implemented.
In order to enable the backward-compatible extension of the FMI standard in minor releases and between minor releases, the FMI project intends the use of the layered standard mechanism to introduce new features in a fully backward-compatible and optional way.
A layered standard defines extensions to the base FMI standard by specifying either standardized annotations, standardized extra files in the FMU, and/or support for additional MIME types/file formats, defined in Section 2.4.4.
A layered standard can include a single or combined set of extension mechanisms from this set.
The layered standard is thus considered to be layered on top of the definitions and extensions mechanisms provided by this base standard.
Layered standards can fall into three categories:
-
Layered standards defined by third parties, without any representations by the FMI project for their suitability or content, or even knowledge by the FMI project about their existence.
-
Layered standards defined by third parties that are endorsed by the FMI project and listed on the FMI project website.
-
Layered standards can be defined/adopted and published by the FMI project itself, making them FMI project layered standards.
Layered standards that have achieved enough adoption or importance to be included into the base standard set could be incorporated into a new minor or major release version of the base standard as an optional or mandatory appendix, making support for this layered standard optional or required for conformance with the newly published minor release version of the base standard.
3. FMI for Model Exchange
This chapter contains the interface description to access the equations of a dynamic system from a C program. A schematic view of a model in FMI for Model Exchange format is shown in Figure 40:
Blue arrows: Information provided by the FMU.
Red arrows : Information provided to the FMU.
\(\mathbf{v}_{\mathit{start}}\), \(\mathbf{u}\), \(\mathbf{y}\), and \(\mathbf{w}\), are of a numeric type or string;
\(\mathbf{t}\), \(\mathbf{x}_c\), \(\mathbf{z}\) are of floating point type.
The goal of the Model Exchange interface is to numerically solve a system of differential, algebraic and discrete-time equations. In this version of the interface, ordinary differential equations in state-space representation with events are handled (abbreviated as "hybrid ODE"). Algebraic equation systems might be contained inside the FMU. Also, the FMU might consist of discrete-time equations only, for example, describing a sampled-data controller.
3.1. Mathematical Description
3.1.1. Computation Modes
Computing the solution of an FMI model means to split the solution process in different phases, and in every phase different equations and solution methods are utilized. The phases can be categorized according to the following modes:
3.1.1.1. Initialization Mode
This mode is used to compute at the start time \(t_0\) initial values for continuous-time states
\(\mathbf{x}_c(t_0)\), and for the previous (internal) discrete-time states \(\mathbf{x}_d(t_0)\), by utilizing extra equations not present in the other modes (for example, equations to define the start
value for a state
or for the derivative of a state
).
3.1.1.2. Continuous-Time Mode
This mode is used to compute the values of all floating point continuous-time variables between events by numerically solving ordinary differential and algebraic equations. All discrete-time variables are fixed during this phase and the corresponding discrete-time equations are not evaluated.
3.1.1.3. Event Mode
This mode is used to compute new values for all continuous-time variables, as well as for all discrete-time variables that are activated at the current event instant \(t\), given the values of the variables from the previous instant \({}^{\bullet}t\). This is performed by solving algebraic equations consisting of all continuous-time and all active discrete-time equations.
3.1.2. Model Evaluations, Dependencies, and Call Sequence
When connecting FMUs together, loop structures can occur that lead to particular difficulties because linear or non-linear algebraic systems of equations in floating point variables but also in Boolean or Integer variables might be present.
In order to solve such systems of equations over FMUs efficiently, the dependency information is needed stating, for example, which outputs
depend directly on inputs
.
This data is optionally provided in the XML file under element <ModelStructure>
.
If this data is not provided, the worst case must be assumed, that is, all output
variables depend algebraically on all input
variables.
[Example: In Figure 41 two different types of connected FMUs are shown (the "dotted lines" characterize the dependency information):
In the left diagram, FMU1 and FMU2 are connected in such a way that by an appropriate sequence of fmi3Set{VariableType}
and fmi3Get{VariableType}
calls, the FMU variables can be computed with the following call sequence:
fmi3Instance FMI1, FMI2;
fmi3ValueReference vr_FMU1_u, vr_FMU1_y, vr_FMU2_u1, vr_FMU2_u2, vr_FMU2_y1, vr_FMU2_y2;
fmi3Float64 s=0.1, FMU2_y1, FMU1_y, FMU2_y2;
...
fmi3SetFloat64(FMU2, &vr_FMU2_u1, 1, &s, 1);
fmi3GetFloat64(FMU2, &vr_FMU2_y1, 1, &FMU2_y1, 1);
fmi3SetFloat64(FMU1, &vr_FMU1_u, 1, &FMU2_y1, 1);
fmi3GetFloat64(FMU1, &vr_FMU1_y, 1, &FMU1_y, 1);
fmi3SetFloat64(FMU2, &vr_FMU2_u2, 1, &FMU1_y, 1);
fmi3GetFloat64(FMU2, &vr_FMU2_y1, 1, &FMU2_y2, 1);
...
In the right diagram, FMU3 and FMU4 are connected in such a way that a real algebraic loop is present.
This loop might be solved iteratively with a Newton method.
In every iteration the iteration variable \(u_4\) is provided by the solver, and via the shown sequence of fmi3Set{VariableType}
and fmi3Get{VariableType}
calls, the residual is computed and is provided back to the solver.
Based on the residual a new value of \(u_4\) is provided.
The iteration is terminated when the residual is close to zero.
fmi3Instance FMI1, FMI2;
fmi3ValueReference vr_FMU3_u, vr_FMU3_y, vr_FMU4_u, vr_FMU4_y;
fmi3Float64 s, FMU3_y, FMU4_y, residual;
bool converged;
// Newton iteration
while (!converged)
{
// input s[0] calculated by the solver
...
fmi3SetFloat64(FMU2, &vr_FMU4_u, 1, &s, 1);
fmi3GetFloat64(FMU2, &vr_FMU4_y, 1, &FMU4_y, 1);
fmi3SetFloat64(FMU1, &vr_FMU3_u, 1, &FMU4_y, 1);
fmi3GetFloat64(FMU1, &vr_FMU3_y, 1, &FMU3_y, 1);
residual=s-FMU3_y; // provided to the solver
}
These types of artificial or real algebraic loops can occur in all the different modes, such as Initialization Mode, Event Mode, and Continuous-Time Mode. Since different variables are computed in every mode and the causality of variable computation can be different in Initialization Mode as with respect to the other two modes, it might be necessary to solve different kinds of loops in the different modes.]
In Table 33 the equations are defined that can be evaluated in the respective mode. The following color coding is used in the table:
-
grey: If a variable in an argument list is marked in grey, then this variable is not changing in this mode and just the last calculated value from the previous mode is internally used. For an input argument, it is not allowed to call
fmi3Set{VariableType}
. For an output argument, callingfmi3Get{VariableType}
on such a variable returns always the same value in this mode. -
green: Functions marked in green are special functions to enter or leave a mode.
-
blue: Equations and functions marked in blue define the actual computations to be performed in the respective mode.
[In Table 33, the setting of the super-dense time, (\(t_R\), \(t_I\)), is precisely described. Tools will usually not have such a representation of time. However, super-dense time defines precisely when a new "model evaluation" starts and therefore which variable values belong to the same "model evaluation" at the same (super-dense) time instant and should be stored together.]
Equations |
FMI functions |
Equations before Initialization Mode |
|
Set variables \(\mathbf{v}_{\mathit{initial=exact}}\) and \(\mathbf{v}_{\mathit{initial=approx}}\) that have a |
|
Equations during Initialization Mode |
|
Enter Initialization Mode at \(t=t_0\) (activate initialization, discrete-time and continuous-time equations).
Set |
|
Set variables \(\mathbf{v}_{\mathit{initial=exact}}\) that have a |
|
Set continuous-time and discrete-time |
|
\(\mathbf{v}_{\mathit{initialUnknowns}}:=f_{\mathit{init}}(\mathbf{u_c}, \mathbf{u_d}, \color{grey}t_{\color{grey} 0}, \mathbf{v}_{\mathit{initial=exact}}\)) |
|
Exit Initialization Mode (de-activate initialization equations) |
|
Equations during Event Mode |
|
Enter Event Mode at \(t = t_{i}\) with \({t_{i}\ : = (t}_{R},t_{I} + 1)\) if externalEvent or nextMode \(\equiv\) EventMode or \(t_i=(T_{\mathit{next}}(t_{i-1}), 0)\) or \(\min_{t>t_{i-1}} t:\left\lbrack z_{j}\left( t \right) > 0\ \neq \ z_{j}\left( t_{i-1} \right) > 0 \right\rbrack\) |
|
Set |
|
Set continuous-time and discrete-time |
|
Set continuous-time |
|
\((\mathbf{y}_{c+d}, \mathbf{\dot{x}}_c, \mathbf{w}_{c+d}, \mathbf{z}, \mathbf{x}_{c,\mathit{reinit}})=\mathbf{f}_{\mathit{sim}}(\mathbf{x_c}, \mathbf{u_{c+d}}, \color{grey}t_{\color{grey} i}, \mathbf{p}_{\mathit{tune}}, \color{grey}{\mathbf{p}_{\mathit{other}})}\) |
|
Increment super-dense time and define with
|
|
Equations during Continuous-Time Mode |
|
Enter Continuous-Time Mode: |
|
Set |
|
Set continuous-time |
|
Set continuous-time |
|
\((\mathbf{y}_{c}\mathbf{,} \color{grey}{\mathbf{y}_{d}}\mathbf{,\ }{\dot{\mathbf{x}}}_{c}\mathbf{,}_{}\mathbf{w}_{c}\mathbf{,}\color{grey}{\mathbf{w}_{d}}\mathbf{,z,}\color{grey}{\mathbf{x}_{c,\mathit{reinit}}}):=\mathbf{f}_{\mathit{sim}}(\mathbf{x}_{c},\ \mathbf{u}_{c}\mathbf{,} \color{grey}{\mathbf{\ u}_{d}}, t,\color{grey}{\mathbf{p}_{\mathit{tune}},\mathbf{p}_{\mathit{other}}})\) |
|
Complete integrator step and return |
|
Data types |
|
\(t \in \mathbb{R}, \mathbf{p} \in \mathbb{P}^{np}, \mathbf{u}(t) \in \mathbb{P}^{nu},\mathbf{y}(t) \in \mathbb{P}^{ny}, \mathbf{x}_c(t) \in \mathbb{R}^{nxc}, \mathbf{x}_d(t) \in \mathbb{P}^{nxd}, \mathbf{w}(t) \in \mathbb{P}^{nw}, \mathbf{z}(t) \in \mathbb{R}^{nz}\) |
[Remark 1 - Calling Sequences:
In Table 33, for notational convenience in every mode one function call is defined to compute all output arguments from all inputs arguments.
In reality, every scalar output argument can be computed by one fmi3Get{VariableType}
function call.
Additionally, the output argument need not be a function of all input arguments, but of only a subset from it, as defined in the XML file under <ModelStructure>
.
This is essential when FMUs are connected in a loop, as shown in Figure 41.
For example, since \(y_{\mathit{2a}}\) depends only on \(u_{\mathit{1a}}\) , but not on \(u_{\mathit{1b}}\), it is possible to call fmi3Set{VariableType}
to set \(u_{\mathit{1a}}\) , and then inquire \(y_{\mathit{2a}}\) with fmi3Get{VariableType}
without setting \(u_{\mathit{1b}}\) beforehand.
It is non-trivial to provide code for fmi3Set{VariableType}
, fmi3Get{VariableType}
, if the environment can call fmi3Set{VariableType}
on the inputs
in quite different orders.
A simple remedy is to provide the dependency information, not according to the real functional dependency, but according to the sorted equations in the generated code.
Example:
Assume an FMU is described by the following equations (u1
, u2
are inputs
, y1
, y2
are outputs
,w1
, w2
are internal variables):
w1 = w2 + u1 w2 = u2 y1 = w1 y2 = w2
Sorting of the equations might result in (this ordering is not unique):
w2 := u2 y2 := w2 w1 := w2 + u1 y1 := w1
With this ordering, the dependency should be defined as y2 = f(u2), y1 = f(u1,u2)
.
When y2
is called first with fmi3Get{VariableType}
, then only u2
must be set first (since y2 = f(u2)
), and the first two equations are evaluated.
If later y1
is inquired as well, then the first two equations are not evaluated again and only the last two equations are evaluated.
On the other hand, if y1
is inquired first, then u1
and u2
must be set first (since y1 = f(u1,u2)
) and then all equations are computed.
When y2
is inquired afterwards, the cached value is returned.
If sorting of the equations in this example would instead result in the following code:
w2 := u2 w1 := w2 + u1 y1 := w1 y2 := w2
then the dependency should be defined as y2 = f(u1,u2)
, y1 = f(u1,u2)
, because u1
and u2
must be first set, before y2
can be inquired with fmi3Get{VariableType}
when executing this code.
Remark 2 - Mathematical Model of Discrete-Time FMUs:
There are many different ways discrete-time systems are described. For FMI, the following basic mathematical model for discrete-time systems is used (other description forms must be mapped, as sketched below):

At an event instant, the discrete system is described by algebraic equations as function of the previous (internal) discrete-time states>> \(_{}^{\bullet}\mathbf{x}_{d}\) and the discrete-time inputs
\(\mathbf{u}_{d}\).
If FMUs are connected in a loop, these algebraic equations are called iteratively, until the solution is found.
If the current discrete-time states \(\mathbf{x}_{d}\) and the previous discrete-time states \(_{}^{\bullet}\mathbf{x}_{d}\) are not identical, the discrete-time states are updated, the integer part of the time is incremented and a new event iteration is performed.
Other discrete-time models must be mapped to this description form.
Examples:
However, just like in FMI 2.0, it could in principle also be implemented by activating the model equations only at the first event iteration and returning always discreteStatesNeedUpdate == fmi3False
from fmi3UpdateDiscreteStates
.
Furthermore, the discrete-time states are not updated by fmi3UpdateDiscreteStates
, but as first action before the discrete-time equations are evaluated, in order that \(^{\bullet}\mathbf{x}_d\) (= value at the previous Lucid Synchrone/Modelica 3.3 clock tick) and \(\mathbf{x}_d\) (value at the latest Lucid Synchrone/Modelica 3.3 clock tick) have reasonable values between Lucid Synchrone/Modelica 3.3 clock ticks.
- State machines with one memory location for a state
-
In such a system there is only one memory location for a discrete-time state and not two, and therefore a discrete-time state is updated in the statement where it is assigned (and not in
fmi3UpdateDiscreteStates
). As a result,fmi3UpdateDiscreteStates
is basically just used to start a new (super-dense) time instant. This is unproblematic, as long as no algebraic loops occur. FMUs of this type can therefore not be used in real algebraic loops if the involved variables depend on a discrete-time state. This restriction is communicated to the environment of the FMU by theScalarVariable
definition of the correspondinginput
with flagcanHandleMultipleSetPerTimeInstant
= false
(so aninput
with this flag is not allowed to be called in an algebraic loop).
Remark 3 - Event Indicators / Frozen Relations:
In Table 33, vector \(\mathbf{r}\) is used to collect all relations together that are utilized in the event indicators \(\mathbf{z}\) . In Continuous-Time Mode all these relations are "frozen" and do not change during the evaluations in the respective mode. This is indicated in Table 33 by computing \(\mathbf{r}\) when entering the Continuous-Time Mode and providing \(\mathbf{r}\) as (internal) input argument to the evaluation functions. Example:
An equation of the form
y = if x1 > x2 or x1 < x3 then +1 else -1;
can be implemented in the FMU as:
z1 := x1 - x2; z2 := x3 - x1; if *Initialization Mode* or *Event Mode* then r1 := z1 > 0; r2 := z2 > 0; end if; y = if r1 or r2 then +1 else -1
Therefore, the original if-clause is evaluated in this form only during Initialization Mode and Event Mode. In Continuous-Time Mode this equation is evaluated as:
z1 = x1 - x2; z2 = x3 - x1 y = if r1 or r2 then +1 else -1;
and when entering Continuous-Time Mode r1 and r2 are computed as
r1 = z1 > 0 r2 = z2 > 0
When z1 changes from z1 > 0 to z1 ⇐ 0 or vice versa, or z2 correspondingly, the integration is halted, and the environment must call fmi3EnterEventMode
.
An actual implementation will pack the code into a function with side effects, say Greater(…), resulting in:
y = if Greater(x1-x2,...) or Greater(x3-x1,...) then +1 else -1;
Furthermore, a hysteresis should be added for the event indicators.]
An FMU is initialized in Initialization Mode with \(\mathbf{f}_{\mathit{init}}(\ldots)\).
The input arguments to this function consist of the input
variables (= variables with causality
= input
), of the independent
variable (= variable with causality
= independent
[typically: time]), and of all variables that have a start
value with initial
= exact
in order to compute the continuous-time states
and the output variables at the initial time \(t_0\).
In Table 33, the variables with initial
= exact
are collected together in variable \(\mathbf{v}_{\mathit{initial=exact}}\).
For example, initialization might be defined by providing initial start
values for the states
, \(\mathbf{x}_{\mathit{c0}}\), or by stating that the state derivatives are zero (\(\dot{\mathbf{x}}_{c} = \mathbf{0}\)).
Initialization is a difficult topic by itself, and it is required that an FMU solves a well-defined initialization problem inside the FMU in Initialization Mode.
After calling fmi3ExitInitializationMode
, the FMU is implicitly in Event Mode, and all discrete-time and continuous-time variables at the initial time instant \((t_R, 0)\) can be calculated.
If these variables are present in an algebraic loop, iteration can be used to compute them.
Once finalized, fmi3UpdateDiscreteStates
must be called, and depending on the value of the return argument, the FMU either continues the event iteration at the initial time instant or switches to Continuous-Time Mode.
After switching to Continuous-Time Mode, the integration is started.
Basically, during Continuous-Time Mode, the derivatives
of the continuous states
are computed.
If FMUs and/or submodels are connected, then the inputs
of these models are the outputs
of other models, and therefore, the corresponding FMU outputs must be computed.
Whenever result values shall be stored, usually at output points defined before the start of the simulation, the fmi3Get{VariableType}
function with respect to the desired variables must be called.
Continuous integration is stopped at an event instant.
An event instant is determined by a time
, state
or step event, or by the environment (e.g. to change a continuous
variable discretely).
In order to determine a state event, the event indicators z have to be inquired at every completed integrator step.
Once the event indicators signal a change of their domain, an iteration over time is performed between the previous and the actual completed integrator step, in order to determine the time instant of the domain change up to a certain precision.
After an event is triggered, the FMU needs to be switched to Event Mode.
In this mode, systems of equations over connected FMUs might be solved (similarly as in Continuous-Time Mode).
Once convergence is reached, fmi3UpdateDiscreteStates
must be called to increment super-dense time (and conceptually update the discrete-time states defined internally in the FMU by \(^{\bullet}\mathbf{x}_d := \mathbf{x}_d\)).
Depending on the discrete-time model, a new event iteration might be needed.
[For example, an FMU implements a state machine that forces an internal state transitions to occur, when new input
values are available.]
The function calls in Table 33 describe precisely which input arguments are needed to compute the desired output argument(s).
There is no 1:1 mapping of these mathematical functions to C functions.
Instead, all input arguments are set with fmi3Set{VariableType}
C function calls, and then the result argument(s) can be determined with the C functions defined in the right column of Table 33.
This technique is discussed in detail in Section 3.2.1.
[In short: For efficiency reasons, all equations from Table 33 will usually be available in one (internal) C function.
With the C functions described in the next sections, input arguments are copied into the internal model data structure only when their value has changed in the environment.
With the C functions in the right column of Table 33, the internal function is called in such a way that only the minimum needed equations are evaluated.
Hereby, variable values calculated from previous calls can be reused.
This technique is called "caching" and can significantly enhance the simulation efficiency of real-world models.]
3.2. Application Programming Interface
This section contains the interface description to evaluate different model parts from a C program.
3.2.1. Providing Independent Variables and Re-initialization of Caching
Depending on the situation, different variables need to be computed.
In order to be efficient, it is important that the interface requires only the computation of variables that are needed in the present context.
For example, during the iteration of an integrator step, only the state derivatives need to be computed, provided the output
of a model is not connected.
It might be that at the same time instant other variables are needed.
For example, if an integrator step is completed, the event indicator functions need to be computed as well.
If the state derivatives have already been computed at the present time instant, then it is important for efficiency that they are not newly computed in the call to compute the event indicator functions.
This means, the state derivatives shall be reused from the previous call.
This feature is called "caching of variables" in the sequel.
Caching requires that the model evaluation can detect when the input arguments, like time or states, have changed.
This is achieved by setting them explicitly with a function call, since every such function call signals precisely a change of the corresponding variables.
For this reason, this section contains functions to set the input arguments of the equation evaluation functions.
This is unproblematic for time and states, but is more involved for parameters
and inputs
, since the latter may have different data types.
typedef fmi3Status fmi3SetTimeTYPE(fmi3Instance instance, fmi3Float64 time);
Set a new value for the independent variable (typically a time instant) and re-initialize caching of variables that depend on time, provided the newly provided time value is different to the previously set time value (variables that depend solely on constants
or parameters
need not to be newly computed in the sequel, but the previously computed values can be reused).
typedef fmi3Status fmi3SetContinuousStatesTYPE(fmi3Instance instance,
const fmi3Float64 continuousStates[],
size_t nContinuousStates);
Set a new (continuous) state vector and re-initialize caching of variables that depend on the states
.
-
Argument
nContinuousStates
is the length of -
argument
continuousStates
and is provided for checking purposes (variables that depend solely onconstants
, parameters
, time, and inputs
do not need to be newly computed in the sequel, but the previously computed values can be reused).
Note that the continuous states
might also be changed in Event Mode.
Note that fmi3Status == fmi3Discard
is possible.
fmi3Status fmi3Set{VariableType}(..);
Set new values for parameters
, start
values and inputs
and re-initialize caching of variables that depend on these variables.
The details of these functions are defined in Section 2.2.5.2.
[The functions above have the slight drawback that values must always be copied.
For example, a call to fmi3SetContinuousStates
will provide the actual states in a vector, and this function has to copy the values in to the internal model data structure so that subsequent evaluation calls can utilize these values.
If this turns out to be an efficiency issue, a future release of FMI might provide additional functions to provide the address of a memory area where the variable values are present.]
3.2.2. Evaluation of Model Equations
This section contains the core functions to evaluate the model equations. Before one of these functions can be called, the appropriate functions from the previous section have to be used, to set the input arguments to the current model evaluation.
typedef fmi3Status fmi3EnterEventModeTYPE(fmi3Instance instance,
fmi3Boolean stepEvent,
const fmi3Int32 rootsFound[],
size_t nEventIndicators,
fmi3Boolean timeEvent);
The model enters Event Mode from the Continuous-Time Mode and discrete-time equations may become active (and relations are not "frozen").
The followings function arguments have to be given to inform the FMU why Event Mode was entered.
[These arguments are not mutually exclusive.]
-
stepEvent
signals withfmi3True
that a step event occurred. -
rootsFound
is an array of lengthnEventIndicators
that signals if a state event occurred. Fori = 1, …, nEventIndicators, rootsFound[i-1] != 0
if the event indicator \(z_i\) has a root, androotsFound[i-1] == 0
if not. For the components \(z_i\) for which a root was found, the sign ofrootsFound[i-1]
indicates the direction of the zero-crossing. A value of+1
indicates that \(z_i\) is increasing, while a value of-1
indicates a decreasing \(z_i\). IfnEventIndicators == 0
the value ofrootsFound
is not defined. -
nEventIndicators
contains the number of event indicators (length ofrootsFound
) or0
if the caller cannot provide this information. -
timeEvent
signals withfmi3True
that a time event occurred.
[An input event can be detected by the FMU by keeping track of the calls of fmi3Set{VariableType}
in Event Mode.]
typedef fmi3Status fmi3UpdateDiscreteStatesTYPE(fmi3Instance instance,
fmi3Boolean *discreteStatesNeedUpdate,
fmi3Boolean *terminateSimulation,
fmi3Boolean *nominalsOfContinuousStatesChanged,
fmi3Boolean *valuesOfContinuousStatesChanged,
fmi3Boolean *nextEventTimeDefined,
fmi3Float64 *nextEventTime);
The FMU is in Event Mode.
If the super-dense time before a call to fmi3UpdateDiscreteStates
was \((t_R,t_I)\), then the time instant after the call is \((t_R,t_{I + 1})\).
-
If output argument
discreteStatesNeedUpdate == fmi3True
, the FMU should stay in Event Mode, and the FMU requires to set new inputs to the FMU (fmi3Set{VariableType}
oninputs
) to compute and get theoutputs
(fmi3Get{VariableType}
onoutputs
) and to callfmi3UpdateDiscreteStates
again.
-
If output argument
terminateSimulation == fmi3True
, the FMU signals it needs to terminate the simulation. -
If argument
nominalsOfContinuousStatesChanged == fmi3True
, then the nominal values of thestates
have changed due to the function call and can be inquired withfmi3GetNominalsOfContinuousStates
. -
If argument
valuesOfContinuousStatesChanged == fmi3True
, then at least one element of the continuous state vector has changed its value due to the function call.
The new values of the states
can be inquired with fmi3GetContinuousStates
or individually for each state for which reinit = true
by calling fmi3GetFloat*
.
If no element of the continuous state vector has changed its value, valuesOfContinuousStatesChanged
must return fmi3False
.
[If fmi3True
would be returned in this case, an infinite event loop may occur.]
-
If argument
nextEventTimeDefined == fmi3True
, then the simulation shall integrate at most untiltime
reaches value of
-
argument
nextEventTime
, and shall callfmi3EnterEventMode
at this time instant. If a (e.g. state event) event happens beforenextEventTime
, the definition ofnextEventTime
becomes obsolete.
With multiple connected FMUs, the environment shall
-
call
fmi3Terminate
, ifterminateSimulation == fmi3True
is returned by at least one FMU, -
call
fmi3EnterContinuousTimeMode
if all FMUs returndiscreteStatesNeedUpdate == fmi3False
, and -
stay in Event Mode otherwise.
When the FMU is terminated, it is assumed that an appropriate message is printed by the logMessage
function (see Section 2.3.1) to explain the reason for the termination.
typedef fmi3Status fmi3CompletedIntegratorStepTYPE(fmi3Instance instance,
fmi3Boolean noSetFMUStatePriorToCurrentPoint,
fmi3Boolean* enterEventMode,
fmi3Boolean* terminateSimulation);
This function must be called by the environment after every completed step of the integrator provided the capability flag completedIntegratorStepNotNeeded = false
.
Argument noSetFMUStatePriorToCurrentPoint == fmi3True
if fmi3SetFMUState
will no longer be called for time instants prior to current time in this simulation run [the FMU can use this flag to flush a result buffer].
The function returns enterEventMode
to signal to the environment that the environment shall call fmi3EnterEventMode
, and it returns terminateSimulation
to signal if the simulation shall be terminated.
If enterEventMode == fmi3False
and terminateSimulation == fmi3False
the FMU stays in Continuous-Time Mode without the environment having to call fmi3EnterContinuousTimeMode
again.
When the integrator step is completed and the states
are modified by the integrator afterwards (for example, correction by a BDF method),
then fmi3SetContinuousStates
has to be called with the updated states before fmi3CompletedIntegratorStep
is called.
When the integrator step is completed and one or more event indicators change sign (with respect to the previously completed integrator step), then the integrator or the environment has to determine the time instant of the sign change that is closest to the previous completed step up to a certain precision (usually a small multiple of the machine epsilon).
This is usually performed by an iteration where time is varied and state
variables needed during the iteration are determined by interpolation.
Function fmi3CompletedIntegratorStep
must be called after this state event location procedure and not after the successful computation of the time step by the integration algorithm.
The intended purpose of the function call is to indicate to the FMU that at this stage all inputs
and state
variables have valid (accepted) values.
After fmi3CompletedIntegratorStep
is called, it is still allowed to go back in time (calling fmi3SetTime
) and inquire values of variables at previous time instants with fmi3Get{VariableType}
[for example, to determine values of non-state variables at output points].
However, it is not allowed to go back in time over the previous fmi3CompletedIntegratorStep
or the previous fmi3EnterEventMode
call.
[This function might be used, for example, for the following purposes:
Delays:
All variables that are used in a "delay(..)" operator are stored in an appropriate buffer and the function returns with enterEventMode == fmi3False
, and terminateSimulation == fmi3False
.
-
Dynamic state selection:
It is checked whether the dynamically selected states are still numerically appropriate. If yes, the function returns withenterEventMode == fmi3False
otherwise withenterEventMode == fmi3True
. In the latter case,fmi3EnterEventMode
has to be called and the states are dynamically changed by a subsequentfmi3UpdateDiscreteStates
.
Note that this function is not used to detect time or state events
, for example, by comparing event indicators of the previous with the current call of fmi3CompletedIntegratorStep
.
These types of events are detected in the environment, and the environment has to call fmi3EnterEventMode
independently in these cases, whether the return argument enterEventMode
of fmi3CompletedIntegratorStep
is fmi3True
or fmi3False
.]
typedef fmi3Status fmi3GetDerivativesTYPE(fmi3Instance instance,
fmi3Float64 derivatives[],
size_t nContinuousStates);
typedef fmi3Status fmi3GetEventIndicatorsTYPE(fmi3Instance instance,
fmi3Float64 eventIndicators[],
size_t nEventIndicators);
Compute state derivatives (that is derivatives w.r.t. to the independent
variable also taking into account its unit) and event indicators at the current instant of the independent
variable [typically: time] and for the current states
.
Note that fmi3Status == fmi3Discard
is possible for both functions.
The derivatives
are returned as a vector with nContinuousStates
elements.
The ordering of the elements of the derivatives
vector must be identical to the ordering of the continuousStates
vector (for example, derivatives[2]
is the derivative
of continuousStates[2]
).
The order of the continuousStates
and derivatives
vector must be the same as the ordered list of elements <ModelStructure><Derivative>
.
[Array variables are serialized as defined in Section 2.2.5.1.]
The event indicators are returned as a vector with nEventIndicators
elements.
The order of the eventIndicators
vector must be the same as the ordered list of elements <ModelStructure><EventIndicator>
.
[Array variables are serialized as defined in Section 2.2.5.1.]
A state event is triggered when the domain of an event indicator changes from \(z_j > 0\) to \(z_j \leq 0\) or vice versa.
The FMU must guarantee that at an event restart \(z_j \neq 0\), for example, by shifting \(z_j\) with a small value.
Furthermore, \(z_j\) should be scaled in the FMU with its nominal value (so all elements of the returned vector eventIndicators
should be in the order of "one").
typedef fmi3Status fmi3GetContinuousStatesTYPE(fmi3Instance instance,
fmi3Float64 continuousStates[],
size_t nContinuousStates);
Return the new continuous state vector continuousStates
.
The order of the states is also the same as the ordered list of elements <ModelStructure><Derivative>
.
_[Array variables are serialized as defined in Section 2.2.5.1.]
typedef fmi3Status fmi3GetNominalsOfContinuousStatesTYPE(fmi3Instance instance,
fmi3Float64 nominals[],
size_t nContinuousStates);
Return the nominal values of the continuous states
with the some convention for the order as above.
This function should always be called after calling function fmi3UpdateDiscreteStates
, if nominalsOfContinuousStatesChanged == fmi3True
, since then the nominal values of the continuous states
have changed [for example, because the association of the continuous states
to variables has changed due to internal dynamic state selection].
If the FMU does not have information about the nominal value of a continuous state
i, a nominal value nominals[i] == 1.0
should be returned.
Note that it is required that nominals[i] > 0.0
.
[Typically, the nominal values of the continuous states
are used to compute the absolute tolerance required by the integrator.
Example:
absoluteTolerance[i] = 0.01 * tolerance * nominals[i];
]
Note that simulation backward in time is only allowed over continuous time intervals.
As soon as an event occurs (fmi3EnterEventMode
was called), going back in time is forbidden, because fmi3EnterEventMode
/ fmi3UpdateDiscreteStates
can only compute the next discrete state, not the previous one.
Note that during Initialization, Event Mode, and Continuous-Time Mode, input
variables can be set with fmi3Set{VariableType}
and output variables can be retrieved with fmi3Get{VariableType}
interchangeably according to the model structure defined under element <ModelStructure>
in the XML file.
[For example, if one output
y1
depends on two inputs
u1
, u2
, then these two inputs
must be set, before y1
can be retrieved.
If additionally an output
y2
depends on an input
u3
, then u3
can be set and y2
can be retrieved afterwards.
As a result, artificial or real
algebraic loops over connected FMUs in any of these three modes can be handled by using appropriate numerical algorithms.]
3.2.3. State Machine for Model Exchange
Every implementation of the FMI must support calling sequences of the functions according to the state machine in Figure 42.
The objective of the state machine is to define the allowed calling sequences for functions of the FMI: Calling sequences not accepted by the state machine are not supported by the FMI.
The behavior of an FMU is undefined for such a calling sequence.
The state machine is given here as UML 2.0 state machine.
If a transition is labelled with one or more function names (for example, fmi3EnterEventMode
, fmi3EnterContinuousTimeMode
), this means that the transition is taken if any of these functions is successfully called.
Note that the FMU can always determine in which state it is since every state is entered by a particular function call (such as fmi3EnterEventMode
), or a particular return value (such as fmi3Fatal
).
The transition conditions time event, and state event are defined in Section 3.1.
Each state of the state machine corresponds to a certain phase of a simulation. Common states are defined in Section 2.3, such as super states FMU State Setable and Initialized, states Instantiated, Configuration Mode, Reconfiguration Mode, Initialization Mode, and Terminated.
3.2.3.1. State: Continuous-Time Mode
In this state, the continuous-time model equations are active and integrator steps are performed.
Continuous-Time Mode is entered from Event Mode with calling fmi3EnterContinuousTimeMode
.
- Allowed Function Calls
- Function
fmi3EnterEventMode
-
When an event is detected, the importer must call this function to move the FMU into Event Mode.
- Function
fmi3EnterConfigurationMode
-
If the environment wants to change
structural parameters
, it must move the FMU into Reconfiguration Mode usingfmi3EnterConfigurationMode
. - Function
fmi3GetDirectionalDerivative
3.2.4. Code Example
In the following example, the usage of the fmi3XXX
functions is sketched in order to clarify the typical calling sequence of the functions in a simulation environment.
Furthermore, it is assumed that one FMU is directly integrated in a simulation environment.
If the FMU would be used inside another model, additional code is needed, especially initialization and event iteration has to be adapted.
m = M_fmi3InstantiateModelExchange("m", INSTANTIATION_TOKEN, NULL, fmi3False, fmi3False, NULL, cb_logMessage);
// "m" is the instance name
// "M_" is the MODEL_IDENTIFIER
if (m == NULL) {
status = fmi3Error;
goto TERMINATE;
}
// set the start time
time = tStart;
// set all variable start values (of "ScalarVariable / <type> / start") and
// set the start values at time = Tstart
// M_fmi3SetReal/Integer/Boolean/String(m, ...)
// initialize
// determine continuous and discrete states
CHECK_STATUS(M_fmi3EnterInitializationMode(m, fmi3False, 0.0, tStart, fmi3True, tEnd));
CHECK_STATUS(M_fmi3ExitInitializationMode(m));
initialEventMode = fmi3True;
enterEventMode = fmi3False;
timeEvent = fmi3False;
stateEvent = fmi3False;
// initialize previous event indicators
CHECK_STATUS(M_fmi3GetEventIndicators(m, previous_z, NZ));
initialEventMode = fmi3False;
CHECK_STATUS(M_fmi3EnterContinuousTimeMode(m));
// retrieve initial state x and
// nominal values of x (if absolute tolerance is needed)
CHECK_STATUS(M_fmi3GetContinuousStates(m, x, NX));
CHECK_STATUS(M_fmi3GetNominalsOfContinuousStates(m, x_nominal, NX));
// retrieve solution at t=Tstart, for example, for outputs
// M_fmi3SetFloat*/Int*/UInt*/Boolean/String/Binary(m, ...)
while (!terminateSimulation) {
tNext = time + h;
// handle events
if (enterEventMode || stateEvent || timeEvent) {
if (!initialEventMode) {
CHECK_STATUS(M_fmi3EnterEventMode(m, fmi3False, rootsFound, NZ, timeEvent));
}
// event iteration
fmi3Boolean newDiscreteStatesNeeded = fmi3True;
fmi3Boolean terminateSimulation = fmi3False;
fmi3Boolean nominalsOfContinuousStatesChanged = fmi3False;
fmi3Boolean valuesOfContinuousStatesChanged = fmi3False;
fmi3Boolean nextEventTimeDefined = fmi3False;
fmi3Float64 nextEventTime = 0;
while (newDiscreteStatesNeeded) {
// set inputs at super dense time point
// M_fmi3SetFloat*/Int*/UInt*/Boolean/String/Binary(m, ...)
fmi3Boolean nominalsChanged = fmi3False;
fmi3Boolean statesChanged = fmi3False;
// update discrete states
CHECK_STATUS(M_fmi3NewDiscreteStates(m, &newDiscreteStatesNeeded, &terminateSimulation, &nominalsChanged, &statesChanged, &nextEventTimeDefined, &nextEventTime));
// getOutput at super dense time point
// M_fmi3GetFloat*/Int*/UInt*/Boolean/String/Binary(m, ...)
nominalsOfContinuousStatesChanged |= nominalsChanged;
valuesOfContinuousStatesChanged |= statesChanged;
if (terminateSimulation) goto TERMINATE;
}
// enter Continuous-Time Mode
CHECK_STATUS(M_fmi3EnterContinuousTimeMode(m));
// retrieve solution at simulation (re)start
CHECK_STATUS(recordVariables(outputFile, m, time));
if (initialEventMode || valuesOfContinuousStatesChanged) {
// the model signals a value change of states, retrieve them
CHECK_STATUS(M_fmi3GetContinuousStates(m, x, NX));
}
if (initialEventMode || nominalsOfContinuousStatesChanged) {
// the meaning of states has changed; retrieve new nominal values
CHECK_STATUS(M_fmi3GetNominalsOfContinuousStates(m, x_nominal, NX));
}
if (nextEventTimeDefined) {
tNext = min(nextEventTime, tEnd);
} else {
tNext = tEnd;
}
initialEventMode = fmi3False;
}
if (time >= tEnd) {
goto TERMINATE;
}
// compute derivatives
CHECK_STATUS(M_fmi3GetDerivatives(m, der_x, NX));
// advance time
h = min(fixedStep, tNext - time);
time += h;
CHECK_STATUS(M_fmi3SetTime(m, time));
// set continuous inputs at t = time
// M_fmi3SetFloat*(m, ...)
// set states at t = time and perform one step
for (size_t i = 0; i < NX; i++) {
x[i] += h * der_x[i]; // forward Euler method
}
CHECK_STATUS(M_fmi3SetContinuousStates(m, x, NX));
// get event indicators at t = time
CHECK_STATUS(M_fmi3GetEventIndicators(m, z, NZ));
stateEvent = fmi3False;
for (size_t i = 0; i < NZ; i++) {
// check for zero crossings
if (previous_z[i] < 0 && z[i] >= 0) {
rootsFound[i] = 1; // -\+
} else if (previous_z[i] > 0 && z[i] <= 0) {
rootsFound[i] = -1; // +/-
} else {
rootsFound[i] = 0; // no zero crossing
}
stateEvent |= rootsFound[i];
previous_z[i] = z[i]; // remember the current value
}
// inform the model about an accepted step
CHECK_STATUS(M_fmi3CompletedIntegratorStep(m, fmi3True, &enterEventMode, &terminateSimulation));
// get continuous output
// M_fmi3GetFloat*(m, ...)
CHECK_STATUS(recordVariables(outputFile, m, time));
}
TERMINATE:
if (m && status != fmi3Error && status != fmi3Fatal) {
// retrieve final values and terminate simulation
CHECK_STATUS(recordVariables(outputFile, m, time));
fmi3Status s = M_fmi3Terminate(m);
status = max(status, s);
}
if (m && status != fmi3Fatal) {
// clean up
M_fmi3FreeInstance(m);
}
In the code above errors are handled by the following definition:
#define CHECK_STATUS(S) status = S; if (status != fmi3OK) goto TERMINATE;
3.2.5. Event Handling
This concerns the following API calls: fmi3SetClock
, fmi3GetClock
, fmi3SetIntervalDecimal
, fmi3SetIntervalFraction
, fmi3GetIntervalDecimal
, fmi3GetIntervalFraction
A clock
event is handled by the environment in the following way:
[TODO: Move this section into Common and there the Event Mode description.]
- Enter event mode
-
The Event Mode is entered after initialization (call to function
fmi3ExitInitializationMode
) or during simulation with a call to the functionfmi3EnterEventMode
. The FMU activatesoutput clocks
. - Synchronize clock activation and intervals with the environment
-
[TODO: remove usage of clock tick and use clock activation instead (Note to self: search also for "`clock` tick").]
The clock
activation status can be inquired with the function fmi3GetClock
.
The environment calls the function fmi3SetClock
for periodic
clocks
and input clocks
.
Moreover the current clock
intervals may be inquired with the function fmi3GetIntervalDecimal
or fmi3GetIntervalFraction
and set with the function fmi3SetIntervalDecimal
fmi3SetIntervalFraction
.
[In the Modelica language this is the value returned by the interval() operator.
The initialization of intervals is needed for output
and input
sample times if a clock
ticks the first time.
The FMU determines the interval itself at subsequent clock
ticks.]
[TODO: This should not be in Event Handling, merge into the other section for clock intervals with the table.]
[TODO: Write here a few sentences about how clocks interact with the event iteration.]
- Leave event mode
-
The function
fmi3UpdateDiscreteStates
evaluates the discrete-time equations, provided the correspondingclock
is active and the discrete-time equations have not already been evaluated with calls tofmi3Get{VariableType}
functions. Clocks are automatically deactivated byfmi3UpdateDiscreteStates
and byfmi3Reset
. [This handling of discrete-time states and `time events is forward compatible with FMI 2.0 for any model that could be treated with FMI 2.0 and is exported again using the new features. The environment may ignore the new functionsfmi3SetClock
,fmi3GetClock
,fmi3SetIntervalDecimal
,fmi3SetIntervalFraction
,fmi3GetIntervalDecimal
andfmi3GetIntervalFraction
. The new functions are needed for FMUs with input sample times and to set discrete-time states in model-based control applications or if algebraic loops are present among discrete-time equations of multiple connected FMUs.]
3.2.6. Getting Number of Event Indicators
The number of event indicators can change during simulation if it depends on one or more tunable
structural parameters
and can be retrieved after instantiating the FMU by calling:
typedef fmi3Status fmi3GetNumberOfEventIndicatorsTYPE(fmi3Instance instance,
size_t* nEventIndicators);
This function returns the number of event indicators.
The dependency of the number of event indicators on structural parameters
is implicitly given in the modelDescription.xml
file.
[All event indicator variables are listed as elements <EventIndicator>
in <ModelStructure>
.
If the event indicator variable is an array variable and the <Dimension>
element maps to a dependent variable, then this dependent variable is a dependency for the number of event indicators.]
If all structural parameters
are unchanged then this dependency information can be used to calculate the initial number of states just using information given in the XML file without the need to call this C-API function.
-
Argument
nEventIndicators
points to thesize_t
variable that will receive the number of event indicators.
3.2.7. Getting Number of States
The number of states
can change during simulation if it depends on one or more tunable
structural parameters
and can be retrieved after instantiating the FMU by calling:
typedef fmi3Status fmi3GetNumberOfContinuousStatesTYPE(fmi3Instance instance,
size_t* nContinuousStates);
This function returns the number of continuous states
.
The dependency of the number of states on structural parameters
is implicitly given in the modelDescription.xml
file.
[All state derivative variables are listed as elements <Derivative>
in <ModelStructure>
.
Each state derivative variable maps to the corresponding state variable by the derivative
attribute.
If the state variable is an array variable and the <Dimension>
element maps to a dependent variable, then this dependent variable is a dependency for the number of states.]
If all structural parameters
are unchanged then this dependency information can be used to calculate the initial number of states just using information given in the XML file without the need to call this C-API function.
-
Argument
nContinuousStates
points to thesize_t
variable that will receive the number ofstates
.
3.3. Description Schema
The common XML elements and attributes are defined in Section 2.4.
Additional elements and attributes are defined subsequently.
If the FMU implements the Model Exchange interface type, the element <ModelExchange>
must be present.
It is defined as:

The attributes in the following table are defined on top of the common attributes and have the following meaning (all attributes are optional with exception of modelIdentifier
):
Attribute | Description |
---|---|
|
Short class name according to C syntax, for example, |
|
If |
3.3.1. Example XML Description File
When generating an FMU from the hypothetical model MyLibrary.SpringMassDamper
, the XML file may have the following content:
<?xml version="1.0" encoding="UTF-8"?>
<fmiModelDescription
fmiVersion="3.0-alpha.5"
modelName="MyLibrary.SpringMassDamper"
instantiationToken="{8c4e810f-3df3-4a00-8276-176fa3c9f9e0}"
description="Rotational Spring Mass Damper System"
version="1.0"
generationDateAndTime="2011-09-23T16:57:33Z"
variableNamingConvention="structured">
<ModelExchange modelIdentifier="MyLibrary_SpringMassDamper"/>
<UnitDefinitions>
<Unit name="rad">
<BaseUnit rad="1"/>
<DisplayUnit name="deg" factor="57.2957795130823"/>
</Unit>
<Unit name="rad/s">
<BaseUnit s="-1" rad="1"/>
</Unit>
<Unit name="kg.m2">
<BaseUnit kg="1" m="2"/>
</Unit>
<Unit name="N.m">
<BaseUnit kg="1" m="2" s="-2"/>
</Unit>
</UnitDefinitions>
<TypeDefinitions>
<Float64Type name="Modelica.Units.SI.Inertia" quantity="MomentOfInertia" unit="kg.m2" min="0.0"/>
<Float64Type name="Modelica.Units.SI.Torque" quantity="Torque" unit="N.m"/>
<Float64Type name="Modelica.Units.SI.AngularVelocity" quantity="AngularVelocity" unit="rad/s"/>
<Float64Type name="Modelica.Units.SI.Angle" quantity="Angle" unit="rad"/>
</TypeDefinitions>
<DefaultExperiment startTime="0.0" stopTime="3.0" tolerance="0.0001"/>
<ModelVariables>
<Float64 name="inertia1.J" valueReference="1073741824"
description="Moment of load inertia" causality="parameter" variability="fixed"
declaredType="Modelica.Units.SI.Inertia" start="1"/>
<Float64 name="torque.tau" valueReference="536870912"
description="Accelerating torque acting at flange (= -flange.tau)" causality="input"
declaredType="Modelica.Units.SI.Torque" start="0"/>
<Float64 name="inertia1.phi" valueReference="805306368"
description="Absolute rotation angle of component" causality="output"
declaredType="Modelica.Units.SI.Angle"/>
<Float64 name="inertia1.w" valueReference="805306369"
description="Absolute angular velocity of component (= der(phi))" causality="output"
declaredType="Modelica.Units.SI.AngularVelocity"/>
<Float64 name="x[1]" valueReference="0" initial="exact" start="0"/>
<Float64 name="x[2]" valueReference="1" initial="exact" start="0"/>
<Float64 name="der(x[1])" valueReference="2" derivative="0"/>
<Float64 name="der(x[2])" valueReference="3" derivative="1"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="805306368"/>
<Output valueReference="805306369"/>
<Derivative valueReference="2"/>
<Derivative valueReference="3"/>
<InitialUnknown valueReference="805306368"/>
<InitialUnknown valueReference="805306369"/>
<InitialUnknown valueReference="2" dependencies="0 536870912"/>
<InitialUnknown valueReference="3" dependencies="0 1"/>
</ModelStructure>
</fmiModelDescription>
4. FMI for Co-Simulation
This chapter defines the Functional Mock-up Interface (FMI) for the coupling of two or more simulation models in a co-simulation environment (FMI for Co-Simulation). It is designed both for coupling with subsystem models, which have been exported by their simulator together with its solver as runnable code, and for coupling of simulation tools on a single machine or as part of a distributed co-simulation.
Co-simulation exploits the modular structure of coupled problems in all stages of the simulation process beginning with the separate model setup and preprocessing for the individual subsystems in different simulation tools (which can be powerful simulators as well as simple C programs). During time integration, the simulation is again performed independently for all subsystems restricting the data exchange between subsystems to discrete communication points \(t_i\). For simulator coupling, also the visualization and post-processing of simulation data is done individually for each subsystem in its own native simulation tool. We use the following terms: the communication points \(t_i\), the communication steps \(t_i \rightarrow t_{i+1}\) and the communication step sizes \(h_i := t_{i+1} - t_i\). The term "communication point" in FMI for Co-Simulation refers to the communication between subsystems in a co-simulation environment and should not be mixed with the output points for saving simulation results to file.
FMI for Co-Simulation provides an interface standard for the solution of time-dependent coupled systems consisting of subsystems that are continuous in time (model components that are described by non-stationary differential equations) or time-discrete (model components that are described by difference equations such as discrete controllers).
In a block representation of the coupled system, the subsystems are represented by blocks with (internal) state
variables \(x(t)\) that are connected to other subsystems (blocks) of the coupled problem by subsystem inputs
\(u(t)\) and subsystem outputs
\(y(t)\).
In this framework, the physical connections between subsystems are represented by mathematical coupling conditions between the inputs \(u(t)\) and the outputs
\(y(t)\) of all subsystems, [KS00].
For co-simulation, two basic groups of functions have to be implemented:
-
functions for the data exchange between subsystems
-
functions to synchronize the simulation of all subsystems and to proceed in communication steps \(t_i \rightarrow t_{i+1}\) from initial time \(t_0 := t_{\mathit{start}}\) to end time \(t_N := t_{\mathit{stop}}\)
In FMI for Co-Simulation, both groups of functions are implemented in one software component, the co-simulation algorithm. The data exchange between the FMUs is handled via the co-simulation algorithm only. There is no direct communication between the FMUs. The co-simulation functionality can be implemented by a special software tool (a separate simulation backplane) or by one of the involved simulation tools. In its most general form, the coupled system may be simulated in nested co-simulation environments and FMI for Co-Simulation applies to each level of the hierarchy.
FMI for Co-Simulation defines interface routines for the communication between the importer and all FMUs in a co-simulation environment. The most common co-simulation algorithms stop at each communication point \(t_i\) the simulation (time integration) of all FMUs, collects the outputs \(y(t_i)\) from all FMUs, determines the FMU inputs \(u(t_i)\), distributes these FMU inputs and continues the (co-)simulation with the next communication step \(t_i \rightarrow t_{i+1} = t_i + h\) with fixed communication step size \(h\). In each FMU, an appropriate solver is used to integrate its subsystem for a given communication step \(t_i \rightarrow t_{i+1}\). The simplest co-simulation algorithms approximate the (unknown) FMU inputs \(u(t), (t > t_i))\) by constant data \(u(t_i)\) for \(t_i \leq t < t_{i+1}\). FMI for Co-Simulation supports this classical brute force approach as well as more sophisticated simulation algorithms. FMI for Co-Simulation is designed to support a very general class of simulation algorithms but it does not define simulation algorithms itself.
The ability of FMUs to support more sophisticated simulation algorithms is characterized by a set of capability flags inside the XML description of the FMU (see Section 4). Typical examples are:
-
the ability to handle variable communication step sizes \(h_i\),
-
the ability to repeat a rejected communication step \(t_i \rightarrow t_{i+1}\) with reduced communication step size,
-
the ability to provide
derivatives
ofoutputs
w.r.t. time, to allow input approximation (Section 4.2.1), -
or the ability to provide Jacobians.
FMI for Co-Simulation is restricted to FMUs with the following properties:
-
All calculated values are time-dependent functions within an a priori defined time interval \(t_{\mathit{start}} \leq t \leq t_{\mathit{stop}}\) (provided
stopTimeDefined == fmi3True
when callingfmi3EnterInitializationMode
). -
All simulations are carried out with increasing time in general. The current time \(t\) is running step by step from \(t_{\mathit{start}}\) to \(t_{\mathit{stop}}\). The algorithm of the FMU may have the property to be able to repeat the simulation of parts of \([t_{\mathit{start}}, t_{\mathit{stop}}\)] or the whole time interval \([t_{\mathit{start}}, t_{\mathit{stop}}\)].
-
The FMU can be given a time value \(t_i, t_{\mathit{start}} \leq t_i \leq t_{\mathit{stop}}\).
-
The FMU is able to interrupt the simulation when \(t_i\) is reached.
-
During the interrupted simulation, the FMU (and its individual solver) can receive values for
inputs
\(u(t_i)\) and send values of outputs \(y(t_i)\). -
Whenever the simulation in an FMU is interrupted, a new time value \(t_{i+1}, t_i \leq t_{i+1} \leq t_{\mathit{stop}}\), can be given to simulate the time subinterval \(t_i < t \leq t_{i+1}\).
-
The subinterval length \(h_i\) is the communication step size of the \(i^{th}\) communication step, \(h_i = t_{i+1} - t_i\). Note that the communication step size initiated by the co-simulation algorithm has to be greater than zero.
FMI for Co-Simulation allows a co-simulation flow which starts with instantiation and initialization (all FMUs are prepared for computation, the communication links are established), followed by simulation (the FMUs are forced to simulate a communication step), and finishes with shutdown. The details of the flow are given in the state machine of the calling sequences from co-simulation algorithm to FMU, for each co-simulation interface (see Section 4.2.7, and Section 5.2.1).
The asynchronous mode for FMUs known from FMI 2.0 has been removed since this mode was not supported by tools and it can be suitably replaced by Co-Simulation implementations that control the asynchronous computation of FMUs via separate tasks/threads created for each FMU.
The Co-Simulation interface provides functionalities to control and observe the ticking of clocks. For FMI for Co-Simulation, the ticking of a clock is interpreted as an activity of the associated model partition. During simulation, the co-simulation algorithm updates and manages values of inputs and outputs of FMUs and further models at communication points for each model partition. The number of communication points created for a model partition per time unit can be seen as a model rate. In that sense multiple model partitions of a model define multiple model rates in a model.
The notion of clock
in FMI for Model Exchange has been extended to the FMI for Co-Simulation.
Both output clocks
and input clocks
are supported in Co-Simulation with clocks
.
In order to handle input
and output clocks
in Co-Simulation, a new Event Mode has been introduced.
The concept and the way input
and output clocks
are handled are very similar in Model Exchange and Co-Simulation.
In order to handle input clocks
, the co-simulation algorithm schedules input clocks
and adjusts the communication steps in such a way that inputClock
ticks become communication points.
At these communication points, the FMU is pushed to the Event Mode and input clocks
are handled.
Output clocks
, on the other hand, communicate events detected by the FMU.
The FMU detects an outputClock
and informs the co-simulation algorithm by invoking a callback in which the event time and the event type is communicated.
Then FMU stops the current Co-Simulation step and returns back from fmi3DoStep
.
Then the FMU is pushed to the Event Mode and the event is handled.
Note that, since output events time instants are not known in advance, at output event time instants, new communication points are created.
4.1. Mathematical Description
This section contains a formal mathematical model of Co-Simulation FMUs.
[The following fundamental assumptions are made:
The FMUs are seen by the co-simulation algorithm as purely sampled-data systems, with the exception, that the simulation algorithm can provide input data of a defined level of smoothness (with the flag recommendedIntermediateInputSmoothness
) within a communication interval via the intermediate update mechanism (see Section 2.3.3).
Such a sampled-data system consists typically of a hybrid ODE that is integrated between communication points (known as "sampled access to time continuous systems") where internal events may occur and be handled, but events are not visible from the outside of the FMU.
Co-Simulation FMUs can also be used for real sampled-data systems (so a sampled discrete controller; the inputs
and outputs
could be of type <Float{32|64}>
, <[U]Int{8|16|32|64}>
, <Boolean>
, <String>
, <Clock>
or <Enumeration>
with variability
= discrete
.)
However, in FMI 3.0, Co-Simulation (CS) and Scheduled Execution (SE) may likely be more suitable for this use-case.
And - at least without using intermediate update (see Section 2.3.3), which is untypical for sampled data systems - with Co-Simulation there will always be a communication step delay for information going "through the FMU", so there cannot be an immediate reaction as in Co-Simulation (see Section 4).
]
The communication between the importer and a FMU takes place at
-
a discrete set of time instants, called communication points, where input variables may change in non-smooth or even non-continuous way.
-
intermediate time instances, where the simulation algorithm may get and set variables using Section 2.3.3.
When the transient simulation of the coupled system through Co-Simulation is completed, the sequence of evaluations is the following (here \(\mathbf{x} = {\lbrack \mathbf{x}_c; \mathbf{x}_d \rbrack}^T\) is the combined vector of continuous-time and discrete-time states, and \(\mathbf{y} = {\lbrack \mathbf{y}_c; \mathbf{y}_d \rbrack}^T\)) is the combined vector of continuous-time and discrete-time outputs
):
where \(\mathbf{\Phi}_i\) and \(\mathbf{\Gamma}_i\) define the system behavior for the time interval \(t_i < t \leq t_{i+1}\), with \(t_i = t_0 + \sum_{k=0}^{i-1}h_k\).
[For the part of the Co-Simulation FMU that is based on an ODE, a differential equation is solved between communication points:
If the simulation algorithm implements an extrapolation method of order \(m_{extra}\) , it can provide intermediate inputs of the form:
where \(\mathbf{C}_{i, j}\) are coefficients that can be equal to output derivatives of a connected FMU to realize a Taylor polynomial.
The function \(\mathbf{\varphi}\) shall approximate the numerical integration of the underlying differential equation.
For example, for a stiff differential equation one could use a linear implicit Euler method (neglecting intermediate variable information):
]
Definition Sequence of Co-Simulation evaluations is consistent with the definition of co-simulation by [KS00].
-
At the communication points, the simulation algorithm provides generalized inputs to the FMU:
-
The current
input
variables \(\mathbf{u}_i\) of the FMU (in other words, theinput
variables of the model represented by the FMU, in the sense of system-level simulation). -
Varying
parameters
\(\mathbf{p}_{\mathit{tune},i}\), also known astunable
parameters
.
-
-
The FMU provides generalized outputs to the simulation algorithm, which are:
-
The current output variables \(\mathbf{y}_{i+1}^{(0)}\) of the FMU (same remark as above), along with some of their successive
derivatives
\(\left\{ \mathbf{y}_{i+1}^{(j)} \right\}_{j=1,\cdots,m_{odo}}\) (in case of continuous-time variables). -
Observation variables and
calculated
varyingparameters
\(\mathbf{w}_{i+1}\), along with directional derivatives estimated at \(t = t_{i+1}\) (in case of continuous-time variables).
-
-
At intermediate times \(t\in (t_i, t_{i+1})\) the simulation algorithm and the FMU exchange values for \(\mathbf{u}_u(t)\) and \(\mathbf{y}_u(t)\).
-
Initialization: The FMU being a sampled-data system, its internal states (which can be either continuous-time or discrete-time) need to be initialized at \(t = t_0\). This is performed through an auxiliary function [this relationship is defined in the XML file under elements
<ModelStructure><InitialUnknown>
]:
Computing the solution of an FMI Co-Simulation model means to split the solution process in two phases and in every phase different equations and solution methods are utilized. The phases can be categorized according to the following modes:
4.1.1. Initialization Mode
This mode is used to compute at the start time \(t_0\) initial values for all variables of the Co-Simulation FMU, especially for continuous-time states
\(\mathbf{x}_c(t_0)\), discrete-time states \(\mathbf{x}_d(t_0)\), and for the previous discrete-time states \(^{\bullet}\mathbf{x}_d(t_0)\) by utilizing extra equations only present in Initialization Mode [for example, equations to set all derivatives
to zero, that is, to initialize in steady-state].
If the FMU is connected in loops with other models, iterations over the FMU equations are possible. Algebraic equations are solved in this mode.
4.1.2. Step Mode
This mode is used to compute the values of all continuous-time and discrete-time variables at communication points by numerically solving ordinary differential, algebraic and discrete equations. If the FMU is connected in loops with other models, no iterations over the FMU equations are possible for a given communication point.
[Note that for a Co-Simulation FMU, no super-dense time description is used at communication points.]
The equations are defined in Table 36 can be evaluated in the respective mode. The following color coding is used in the table:
grey |
If a variable in an argument list is marked in grey, then this variable is not changing in this mode and just the last calculated value from the previous mode is internally used.
For an input argument it is not allowed to call |
green |
Functions marked in green are special functions to enter or leave a mode. |
blue |
Equations and functions marked in blue define the actual computations to be performed in the respective mode. |
Equations | FMI functions |
---|---|
Equations before Initialization Mode in state machine |
|
Set variables and that have a start value ( |
|
Equations during Initialization Mode in state machine |
|
Enter Initialization Mode at (activate initialization, discrete-time and continuous-time equations). Set and set |
fmi3EnterInitializationMode |
Set variables \(v_{\mathit{initial=exact}}\) and \(v_{\mathit{initial=approx}}\) that have a |
|
Set continuous-time and discrete-time |
|
\(\mathbf{v}_{\mathit{InitialUnknowns}} := \mathbf{f}_{\mathit{init}}(\mathbf{u}_c, \mathbf{u}_d, t_0, \mathbf{v}_{\mathit{initial=exact}})\) |
|
Exit Initialization Mode (de-activate initialization equations) |
fmi3ExitInitializationMode |
Equations during Step Mode in state machine |
|
Set |
|
Set continuous-time and discrete-time |
|
\(\begin{matrix} t_{i+1} := t_i + h_i \\ (\mathbf{y}_{c+d}, \mathbf{y}_c^{(j)}, \mathbf{w}_{c+d}) := \mathbf{f}_{\mathit{doStep}}(\mathbf{u}_{c+d}, \mathbf{u}_u, t_i, h_i, \mathbf{p}_{\mathit{tune}}, \mathbf{p}_{\mathit{other}})_{t_i} \\ t_i := t_{i+1} \end{matrix}\) |
|
Equations during Intermediate Update Mode in state machine |
|
Set continuous-time |
|
\(\mathbf{y}_u(t):= \mathbf{f}_{\mathit{Intermediate}}(\mathbf{u}_{i, c+d}, \mathbf{u}_u (t \in [t_i, t_{i+1}) ), t, h_i, \mathbf{p}_{\mathit{tune}}, \mathbf{p}_{\mathit{other}})\) |
|
Data types |
|
\(t, t_i, h_i \in \mathbb{R}, \mathbf{p} \in \mathbb{P}^{np}, \mathbf{u}(t) \in \mathbb{P}^{nu}, \mathbf{y}(t) \in \mathbb{P}^{ny}, \mathbf{x}_c(t) \in \mathbb{R}^{nxc}, \mathbf{x}_d(t) \in \mathbb{P}^{nxd}, \mathbf{w}(t) \in \mathbb{P}^{nw}\) |
[Remark - Calling Sequences:
In Table 36, for notational convenience in Initialization Mode one function call is defined to compute all output arguments from all inputs arguments.
In reality, every variable output argument is computed by one fmi3Get{VariableType}
function call.
In Step Mode the input arguments to \(\mathbf{f}_{\mathit{doStep}}\) are defined by calls to fmi3Set{VariableType}
functions.
The variables computed by \(\mathbf{f}_{\mathit{doStep}}\) can be inquired by fmi3Get{VariableType}
function calls.]
4.1.3. Smoothness, Continuity and Discontinuity
Since inputs will be set at specific communication points by the importing tool, the FMU must make assumptions about the values between these communication points, including points of intermediate updates.
Between communication points, even when intermediate updates are called, all changes must be assumed to be continuous.
Changes to continuous
variables are only considered discrete in Event Mode.
Continuous inputs may change between communication points in case of intermediateVariableSetRequested == true
.
These intermediate values are provided by the co-simulation algorithm for example by an extrapolation polynomial build with the output derivatives of connected FMUs (see recommendedIntermediateInputSmoothness
).
FMUs can signal with the optional flag recommendedIntermediateInputSmoothness
of value \(k\) to the co-simulation algorithm that best convergence rates can be achieved if the functions are of smoothness \(C^{k}([t_i, t_{i+1}])\), that is k-time continuously differentiable, with \(C^{0}\) meaning continuous.
It is therefore recommended that the function defined by the continuation of \(\mathbf{u}_{i, u}\) with \(\mathbf{u}_{i+1, u}\) is of smoothness \(C^{k}([t_i, t_{i+2}])\) with the optional flag recommendedIntermediateInputSmoothness
of value \(k\).
[This can increase simulation speed for higher order multi-step solvers that in this case do not have to reset at communication points.]
For continuous
input variables, the importer must ensure that the input approximation function \(\mathbf{u}_u\) is consistent with the values of the input variable (\(\mathbf{u}_u(t_{i+1})= \mathbf{u}(t_{i+1})\)).
If a continuous
input changes discontinuously
(e.g. the actual input value deviates too much from the extrapolation polynomial), the co-simulation algorithm must raise an event (if supported) to indicate to the FMU a discontinuous change at an input.
[In the case of Co-Simulation without events, detecting discrete changes to continuous input variables (for instance to reset the integration algorithm) requires heuristics.]
Discrete
inputs keep their values between communication points.
Furthermore, changing discrete
variables at communication points will likely require special handling within the FMU.
Since the FMU itself can detect such changes, the co-simulation algorithm does not need to raise explicit events in such a case.
4.2. Application Programming Interface
This section contains the interface description to access the input/output data and status information of a Co-Simulation FMU from a C program.
4.2.1. Getting and Setting Variable Values
Input
, output
and other variables are accessed via the fmi3Get{VariableType}
and fmi3Set{VariableType}
functions, defined in Section 2.2.5.2.
- Function
fmi3GetOutputDerivatives
The n-th derivatives
with respect to time of continuous outputs
can be retrieved with fmi3GetOutputDerivatives
to allow interpolation/extrapolation of connected input variables between communication points by the co-simulation algorithm using fmi3CallbackIntermediateUpdate
.
[This enables the same functionality as fmi2SetInputDerivatives
did in FMI1.0 and FMI2.0.]
Whether the FMU is able to provide the derivatives
of outputs
is given by the unsigned integer capability flag maxOutputDerivativeOrder
that represents the maximum order of the output
derivatives
.
If the actual order is lower (because the order of integration algorithm is low), the retrieved value is 0.
Restrictions on calling the function are the same as for the fmi3Get{VariableType}
function for continuous
outputs
.
The returned values correspond to the current time of the FMU.
For example, after a successful call to fmi3DoStep
, the returned values are related to the end of the communication step.
typedef fmi3Status fmi3GetOutputDerivativesTYPE(fmi3Instance instance,
const fmi3ValueReference valueReferences[],
size_t nValueReferences,
const fmi3Int32 orders[],
fmi3Float64 values[],
size_t nValues);
-
valueReferences
is a vector of value references that define the variables whosederivatives
shall be retrieved. If multiple derivatives of a variable shall be retrieved, list the value reference multiple times. -
nValueReferences
is the dimension of the argumentsvalueReferences
andorders
. -
orders
contains the orders of the respectivederivative
(1 means the firstderivative
, 2 means the secondderivative
, …, 0 is not allowed). If multiple derivatives of a variable shall be retrieved, provide a list of them in theorders
array, corresponding to a multiply occurring value reference in thevalueReferences
array. -
values
is a vector with the values of thederivatives
. The order of thevalues
elements is derived from a twofold serialization: the outer level corresponds to the combination of a value reference (e.g.,valueReferences[k]
) and order (e.g.,orders[k]
), and the inner level to the serialization of variables as defined in Section 2.2.5.1. The inner level does not exist for scalar variables. -
nValues
is the size of the argumentvalues
.nValues
only equalsnValueReferences
if all corresponding output variables are scalar variables.
[ Example:
Assuming an FMU has outputs \(y_1\)[2*3] with value reference 1, \(y_2\) with value reference 2, \( y_3\)[2] value reference 3, \(y_4\) with value reference 4 and maxOutputDerivativeOrder
=2.
With valueReferences
= [1, 1, 3, 3, 4, 4], and orders
= [1, 2, 1, 2, 1, 2], fmi3GetOutputDerivatives
will provide first and second time derivatives of the outputs y1, y3, y4, which in values
are serialized in the following way:
((array serialization of \(\dot y_1\)), (array serialization of \(\ddot y_1\)), (array serialization of \(\dot y_3\)), (array serialization of \(\ddot y_3\)), \(\dot y_4\), \(\ddot y_4\))
If the internal polynomial is of order 1 and the co-simulation algorithm inquires the second derivative
of an output
, the FMU will return zero.]
4.2.2. Computation in Co-Simulation
The importer requests the computation of the next time step with the following function:
typedef fmi3Status fmi3DoStepTYPE(fmi3Instance instance,
fmi3Float64 currentCommunicationPoint,
fmi3Float64 communicationStepSize,
fmi3Boolean noSetFMUStatePriorToCurrentPoint,
fmi3Boolean* eventEncountered,
fmi3Boolean* clocksAboutToTick,
fmi3Boolean* terminate,
fmi3Boolean* earlyReturn,
fmi3Float64* lastSuccessfulTime);
-
currentCommunicationPoint
is the current communication point of the co-simulation algorithm (\(t_i\)) with the unit of theindependent
variable and
-
communicationStepSize
is the communication step size (\(h_i\)) with the unit of theindependent
variable.communicationStepSize
must be \(> 0.0\).
-
noSetFMUStatePriorToCurrentPoint == fmi3True
iffmi3SetFMUState
will no longer be called for time instants prior tocurrentCommunicationPoint
in this simulation run. [The FMU can use this flag to flush a result buffer.]
-
eventEncountered == fmi3True
indicates that an event was encountered atlastSuccessfulTime
and the co-simulation algorithm has to callfmi3UpdateDiscreteStates
to gather related information about the event.
-
clocksAboutToTick == fmi3True
indicates that one or more clocks will tick atlastSuccessfulTime
and, after callingfmi3UpdateDiscreteStates
,fmi3GetClock
should be called to gather all information related tooutput clocks
that have the valuefmi3ClockActive
. -
terminate
signals to the co-simulation algorithm that the FMU requests the end of the simulation for internal reasons. This is not due to an error, but a natural limit to the simulation time has been reached inside the FMU.
-
earlyReturn
signals to the co-simulation algorithm that the FMU returns early from thefmi3DoStep
at the time specified inlastSuccessfulTime
.
-
lastSuccessfulTime
represents the internal time of the FMU whenfmi3DoStep
returns.
The FMU is expected to compute until time \(t_{i+1} = t_i + h_i\), or lastSuccessfulTime
=
currentCommunicationPoint
+
communicationStepSize
.
This is especially interesting, if fmi3DoStep
returns with earlyReturn == fmi3True
.
In this case, the step did not compute until \(t_{i+1}\), but stopped computation error free until lastSuccessfulTime
.
However, even when the FMU returns from fmi3DoStep
with fmi3OK
, it is allowed that lastSuccessfulTime
deviates from the expected currentCommunicationPoint
+
communicationStepSize
.
[An example is a fixed-step integrator inside the FMU that cannot possibly stop at exactly the requested time.
Advanced co-simulation algorithms might be able to take this information into account.
It is even possible that the lastSuccessfulTime
is still equal to currentCommunicationPoint
when earlyReturn == fmi3True
is returned (contrary to the possibly expected fmi3Discard
) to indicate a changed internal state of the FMU, e.g. steps in super-dense time.]
[The calling environment defines the communication points and fmi3DoStep
must synchronize to these points by always integrating exactly to \(t_i + h_i\).
It is up to fmi3DoStep
how to achieve this.]
At the first call to fmi3DoStep
after fmi3ExitInitializationMode
was called currentCommunicationPoint
must be equal to startTime
as set with fmi3EnterInitializationMode
.
[Formally, argument currentCommunicationPoint
is not needed.
It is present in order to handle a mismatch between the co-simulation algorithm and the state of the FMU: The currentCommunicationPoint
and the state of the FMU defined by former fmi3DoStep
or fmi3SetFMUState
calls have to be consistent with respect to each other.
For example, if the FMU does not use the update formula for the independent
variable as required above, \(t_{i+1} = t_i + h_i\) (using argument \(t_i\) = currentCommunicationPoint
of fmi3DoStep
) but uses internally an own update formula, such as \(t_{s,i+1} = t_{s,i} + h_{s,i}\) then the FMU could use as time increment \(\text{h}_{s,i} := (t_i - t_{s,i}) + h_i\) (instead of \(\text{h}_{s,i} := h_i\) ) to avoid a mismatch between the co-simulation algorithm time \(t_{i+1}\) and the FMU internal time \(t_{s,i+1}\) for large i.]
It depends on the capabilities of the FMU which argument constellations and calling sequences are allowed (see Section 4).
Only fmi3DoStep
can change the time of a Co-Simulation FMU from the outside (time advances internally during a communication interval).
4.2.3. Communication of Event Time and Input and Output Values
The fmi3CallbackIntermediateUpdate
callback described in Section 2.3.3 is also used in order to communicate the input
and output
and, in particular, the event and clock
time from the FMU to the co-simulation algorithm.
The fmi3CallbackIntermediateUpdate
callback allows internal events (e.g. associated to outputClock
ticks) to be signaled from an FMU to the co-simulation algorithm.
For the interface type Co-Simulation, the fmi3CallbackIntermediateUpdate
callback must be defined in the instantiate function, i.e. NULL is not allowed.
The arguments of fmi3CallbackIntermediateUpdate
are used to signal outputClock
ticks and internal events to the co-simulation algorithm.
See Section 2.3.3 for details of the function parameters.
typedef void (*fmi3CallbackIntermediateUpdate) (
fmi3InstanceEnvironment instanceEnvironment,
fmi3Float64 intermediateUpdateTime,
fmi3Boolean clocksTicked,
fmi3Boolean intermediateVariableSetRequested,
fmi3Boolean intermediateVariableGetAllowed,
fmi3Boolean intermediateStepFinished,
fmi3Boolean canReturnEarly,
fmi3Boolean *earlyReturnRequested,
fmi3Float64 *earlyReturnTime);
Only the first discontinuity event at a Newtonian time instant shall be signaled using this function. There may be an event iteration in Event Mode at a Newtonian time instant causing super-dense time instants.
Based on the information provided by fmi3CallbackIntermediateUpdate
, additional information about the discontinuity at that time instant can be obtained by the co-simulation algorithm from the FMU by calling fmi3UpdateDiscreteStates
and fmi3GetClock
.
4.2.4. Early Return
[In the particular context of multi-FMU architectures, significant co-simulation speed-up may be obtained if the co-simulation algorithm can avoid waiting until the end of the slowest FMU step integration. If an FMU prematurely stops its current step integration computation due to an unpredictable internal event before the normal end of the step calculation, all other concurrently running FMUs may be stopped as soon as possible in order to minimize the time needed for the co-simulation algorithm to resynchronize all the FMUs at the same event time.
In this context based on parallel multi-FMU calculations, Figure 45 illustrates different possibilities to synchronize FMUs at the same event time.
Each FMU starts integration from communication point \(t_{i}\) to reach the next communication point \(t_{i+1}\) . Assuming an unexpected internal event is detected at \(t^{'}_{i+1}< t_{i+1}\) inside FMU1 , the FMU immediately informs the co-simulation algorithm and asks for an early return. Since all FMUs should be resynchronized at the event time which will be the next new communication point, the co-simulation algorithm would like to avoid other FMUs exceed the event time.
-
In the case of FMU1, the FMU waits to get pushed into the event mode to handle the event at \(t^{'}_{i+1}\) .
-
FMU2 can not be interrupted before it reaches \(t_{i+1}\) , which requires a complete rollback and a new co-simulation from \(t_{i}\) to \(t^{'}_{i+1}\) .
-
FMU3 triggers the callback function to the co-simulation algorithm after passing \(t^{'}{i+1}\) , which leads to a request by the co-simulation algorithm to immediately do an early return. The FMU interrupts its computation and a partial rollback and a new co-simulation from \(t_{i}\) to \(t^{'}_{i+1}\) is necessary.
-
In the case of FMU4, the FMU triggered the callback function before reaching \(t^{'}_{i+1}\) . The co-simulation algorithm requests FMU4 to do an early return at \(t^{'}{i+1}\) and the FMU will interrupt its current integration step at \(t^{'}{i+1}\) . No rollback is necessary for FMU4.
Each ongoing FMU stops its integration either exactly at the interrupt time given by the co-simulation algorithm or immediately after its current intermediate step, if this time is already out-of-date. Afterwards, a new step integration done on the FMU returns and signals the premature stop (early-return) to the co-simulation algorithm.
Due to the early-return mechanism, the overall execution time of the simulation can be reduced.]
A Co-Simulation FMU is allowed to stop the execution of fmi3DoStep
and return without reaching the predefined communication time, i.e. currentCommunicationPoint
+
communicationStepSize
.
This mechanism is called "early return".
The Boolean capability flag canReturnEarlyAfterIntermediateUpdate
in the modelDescription.xml
file indicates whether the FMU supports the early-return feature.
The default value of this capability flag is false
.
Each time an internal discontinuity or an event happens inside an FMU with capability flag canReturnEarlyAfterIntermediateUpdate = true
, the callback function fmi3CallbackIntermediateUpdate
is called by the FMU.
The co-simulation algorithm can only use this early return functionality, if it provides the fmi3CallbackIntermediateUpdate
callback function pointer in the instantiate function.
With the early return feature, an FMU can signal outputClock
events or internal state changes, i.e., discontinuity events to the co-simulation algorithm at any time (not only at the end of fmi3DoStep
function calls).
When an internal event occurs inside the FMU at a time instant, it informs the co-simulation algorithm that a new communication point for the Co-Simulation can be created.
Note that an event signal is not seen in the narrow sense of solver induced discontinuity events but in the general sense of a simulation event that has to be handled by the co-simulation algorithm (e.g. state changes that require extended handling).
A second use of the early-return mechanism is the following:
In particular in multi-node architectures, significant co-simulation speed-up may be obtained if the co-simulation algorithm can avoid waiting until the end of the slowest fmi3DoStep
, when many FMUs are integrating in parallel and an event occurs.
To exploit such efficiency gains, the co-simulation algorithm can command the FMUs to return early from the current communication step, if it gets triggered in the callback function by the FMUs.
[In this use case, early return is a simple form of cooperative multitasking.]
Early return is even helpful if the FMU or the co-simulation algorithm do not support the advanced handling of events based on the Co-Simulation functionalities.
Multiple event types and also outputClock
ticks or interrupts can be supported based on the early-return functionality and additional functionalities provided by Co-Simulation.
4.2.5. Handling Early Return and Events
If the FMU is successful in conducting an early return, fmi3DoStep
returns with earlyReturn == fmi3True
.
If the FMU returns from fmi3DoStep
with earlyReturn == fmi3True
, the co-simulation algorithm has to call fmi3EnterEventMode
for that FMU.
typedef fmi3Status fmi3EnterEventModeTYPE(fmi3Instance instance,
fmi3Boolean stepEvent,
const fmi3Int32 rootsFound[],
size_t nEventIndicators,
fmi3Boolean timeEvent);
The co-simulation algorithm can also call fmi3EnterEventMode
at communication instants to handle input events, as will be discussed in following sections.
If an FMU provides the early-return capability that includes the handling of events in Event Mode,
the FMU signals this via canReturnEarlyAfterIntermediateUpdate
in the modelDescription.xml
.
The FMU stops computation at the first encountered internal event (if any) and the event time is provided through the output argument lastSuccessfulTime
, along with the reason eventEncountered == fmi3True
.
The co-simulation algorithm will start event handling by calling fmi3EnterEventMode
for that FMU to push the FMU into Event Mode.
In this mode the co-simulation algorithm is supposed to catch all events through the fmi3UpdateDiscreteStates
function.
If an early-return request of the co-simulation algorithm is ignored by the FMU, then fmi3DoStep
returns with earlyReturn == fmi3False
.
The co-simulation algorithm can start a resynchronization of FMUs at an event time, if the currentCommunicationPoint
has passed the event time, the co-simulation algorithm can roll-back the FMU and repeat the step with a suitable communicationStepSize
(if the FMU supports the roll-back).
typedef fmi3Status fmi3UpdateDiscreteStatesTYPE(fmi3Instance instance,
fmi3Boolean *discreteStatesNeedUpdate,
fmi3Boolean *terminateSimulation,
fmi3Boolean *nominalsOfContinuousStatesChanged,
fmi3Boolean *valuesOfContinuousStatesChanged,
fmi3Boolean *nextEventTimeDefined,
fmi3Float64 *nextEventTime);
In Event Mode and only after fmi3DoStep
returned with earlyReturn == fmi3True
, and fmi3EnterEventMode
was called, the function fmi3UpdateDiscreteStates
may be called.
Only the following output arguments are defined by the FMU:
-
When
discreteStatesNeedUpdate = true
, the co-simulation algorithm should stay in Event Mode and another call tofmi3UpdateDiscreteStates
is required. -
When
nextEventTimeDefined == fmi3True
, an event time is available and the value is given bynextEventTime
. This is the case when the model can report in advance the accurate time of the next predictable time event. -
When
terminateSimulation == fmi3True
, the model requested to stop integration and the co-simulation algorithm should callfmi3Terminate
.
All other output arguments of fmi3UpdateDiscreteStates
are undefined and have no meaning in Co-Simulation.
In Event Mode it is allowed to call fmi3Get{VariableType}
after fmi3UpdateDiscreteStates
has been called and it is allowed to call fmi3Set{VariableType}
before calling fmi3UpdateDiscreteStates
.
The FMU leaves Event Mode when the co-simulation algorithm calls fmi3EnterStepMode
.
4.2.6. Co-Simulation with Clock Support
In this section, signaling and retrieving clock
ticks as well as the interface for supporting clocks
in FMI for Co-Simulation will be discussed.
If an FMU for Co-Simulation declares clocks
and clocked variables in the modelDescription.xml
file, it supports clocks
.
Note, even if no clock
is defined by an FMU in modelDescription.xml
, the co-simulation algorithm can instantiate a Co-Simulation FMU to be able to use early return with event handling in Event Mode.
If an FMU provides clocks
and the co-simulation algorithm is using the interface type Co-Simulation, the co-simulation algorithm must handle these clocks
and early return requests by the FMU.
If the co-simulation algorithm does not support or does not want to support early-return or clocks
, it must set the interface type to Co-Simulation if supported by the FMU.
If the FMU provides the Co-Simulation interface and is instantiated with it, the FMU must internally handle all events during fmi3DoStep
.
typedef fmi3Status fmi3EnterStepModeTYPE(fmi3Instance instance);
4.2.6.1. Transfer of Input and Output Values and Parameters
If the co-simulation algorithm supports clocks
, all input clocks
of the model should be handled and inputClock
events should be scheduled by the co-simulation algorithm.
If an outputClock
will tick, the FMU returns from fmi3DoStep
with clocksAboutToTick == fmi3True
.
After calling fmi3UpdateDiscreteStates
, the activation status of output clocks
can be retrieved with fmi3GetClock
.
Then fmi3SetClock
(and fmi3SetIntervalDecimal
or fmi3SetIntervalFraction
if necessary) should be invoked to enable the ticked input clocks
.
Each clock
, that ticks outside of the FMU (i.e. inputClock
), is activated for an FMU based on its clockReference
and an associated fmi3SetClock
in Event Mode.
fmi3SetClock
can activate multiple clocks
with each call.
An event iteration is possible.
Once all clock
events are handled for this time instant, the FMU should be pushed into Step Mode by calling fmi3EnterStepMode
.
In Step Mode, the co-simulation algorithm can call fmi3DoStep
for the time interval from the current event time instant until the next input event instant.
Note that fmi3DoStep
may not reach the next input event instant because an early return may occur.
The co-simulation algorithm sets and gets clock
variable values similar to the FMI for Model Exchange, as defined in Section 2.2.7.9.
4.2.6.2. Computation in Co-Simulation
Similar to FMI for Model Exchange, in order to activate input clocks
of an FMU, it is required to push the FMU into Event Mode by calling fmi3EnterEventMode
.
If fmi3DoStep
returns with eventEncountered == fmi3True
or clocksAboutToTick == fmi3True
, the FMU must be pushed into Event Mode and fmi3UpdateDiscreteStates
must be called.
In order to retrieve the status of output clocks
, fmi3GetClock
and fmi3GetIntervalDecimal
or fmi3GetIntervalFraction
need to be called in the Event Mode.
If the fmi3DoStep
return value is fmi3OK
, the calling of fmi3GetClock
, fmi3GetIntervalDecimal
, fmi3GetIntervalFraction
, fmi3UpdateDiscreteStates
is only meaningful after fmi3SetClock
in the case of super-dense time iterations are desired.
Similar to the Model Exchange case, the allowed call order is fmi3GetClock
, fmi3GetIntervalDecimal
, fmi3GetIntervalFraction
, fmi3Get{VariableType}
, fmi3Set{VariableType}
.
Function calls of this call order can be omitted.
The handling of return values of function calls is identical to Co-Simulation.
If terminateSimulation
becomes fmi3True
after calling fmi3UpdateDiscreteStates
then the co-simulation should be terminated by calling fmi3Terminate
.
Once handling of the clock
events finished, the co-simulation algorithm calls fmi3EnterStepMode
for that FMU to push it into Step Mode.
Note that it is not allowed to call fmi3EnterEventMode
or fmi3EnterStepMode
in Scheduled Execution.
[Usually the co-simulation algorithm should be able to derive (but is not forced to do so) the correct communication point times for input clocks
in advance and thus it should be able to set the proper communicationStepSize
for fmi3DoStep
.
This might not be possible if an aperiodic inputClock
of an FMU depends on the ticking of an aperiodic outputClock
of another FMU or other aperiodic tick sources.]
4.2.7. State Machine for Co-Simulation
The state machine in Figure 46 defines the supported calling sequences.
Each state of the state machine corresponds to a certain phase of a simulation. Common states are defined in Section 2.3, such as super states FMU State Setable and Initialized, states Instantiated, Configuration Mode, Reconfiguration Mode, Initialization Mode, Terminated and Intermediate Update Mode.
4.2.7.1. State: Step Mode
This state is used by the co-simulation algorithm to progress simulation time.
- Allowed Function Calls
- Function
fmi3EnterConfigurationMode
-
Changes state to Reconfiguration Mode. This function must not be called if the FMU contains no
tunable
structural parameters
(i.e. withcausality
=structuralParameter
andvariability
=tunable
). - Function
fmi3EnterEventMode
-
Changes state to Event Mode. This function must not be called, if
fmi3InstantiateCoSimulation
signaledeventModeUsed = fmi3False
, which implies that the capability flaghasEventMode = true
. - Function
fmi3DoStep
-
Within
fmi3DoStep
the FMU may callfmi3CallbackIntermediateUpdate
-
If the function returns with
fmi3OK
orfmi3Warning
the FMU stays in this state. -
The co-simulation algorithm must call
fmi3DoStep
withcommunicationStepSize > 0.0
. -
If the function returns with
earlyReturn == fmi3True
the FMU will change to states depending on the flags offmi3CallbackIntermediateUpdate
. -
The FMU may return immediately from
fmi3DoStep
withlastSuccessfulTime == currentCommunicationPoint
if an event was detected immediately at thecurrentCommunicationPoint
. Such an event might be caused by the change of an input during the communication point, or may be pending after the initialization.
-
- Function
fmi3Set{VariableType}
-
For variables with:
It is not allowed to call fmi3Get{VariableType}
functions after fmi3Set{VariableType}
functions without an fmi3DoStep
call in between.
[The reason is to avoid different interpretations of the caching, since contrary to FMI for Model Exchange, fmi3DoStep
will perform the actual calculation instead of fmi3Get{VariableType}
, and therefore, dummy algebraic loops at communication points cannot be handled by an appropriate sequence of fmi3Get{VariableType}
and fmi3Set{VariableType}
calls as for Model Exchange.
Examples:
Correct calling sequence | Wrong calling sequence |
---|---|
fmi3Set{VariableType} on inputs |
fmi3Set{VariableType} on inputs |
]
4.2.8. Code Example for Co-Simulation
In the following example, the usage of the FMI functions is sketched in order to clarify the typical calling sequence of the functions in a simulation environment.
We consider two FMUs, where both have one continuous
floating point input
and one continuous
floating point output
which are connected in the following way:
We assume no algebraic dependency between input and output
of each FMU.
The code demonstrates the simplest co-simulation algorithm as shown in Section 4.1:
-
Constant communication step size.
-
No repeating of communication steps.
-
The error handling is implemented in a very rudimentary way.
////////////////////////////
// Initialization sub-phase
// instantiate both FMUs
s1 = s1_fmi3InstantiateCoSimulation("instance1", // instanceName
guid, // instantiationToken
NULL, // resourceLocation
fmi3False, // visible
fmi3False, // loggingOn
fmi3False, // eventModeRequired
NULL, // requiredIntermediateVariables
0, // nRequiredIntermediateVariables
NULL, // instanceEnvironment
cb_logMessage, // logMessage
NULL); // intermediateUpdate
s2 = s2_fmi3InstantiateCoSimulation("instance1", // instanceName
guid, // instantiationToken
NULL, // resourceLocation
fmi3False, // visible
fmi3False, // loggingOn
fmi3False, // eventModeRequired
NULL, // requiredIntermediateVariables
0, // nRequiredIntermediateVariables
NULL, // instanceEnvironment
cb_logMessage, // logMessage
NULL); // intermediateUpdate
if (s1 == NULL || s2 == NULL)
return EXIT_FAILURE;
// start and stop time
startTime = 0;
stopTime = 10;
// communication step size
h = 0.01;
// set all variable start values (of "ScalarVariable / <type> / start")
// s1_fmi3SetReal/Integer/Boolean/String(s1, ...);
// s2_fmi3SetReal/Integer/Boolean/String(s2, ...);
// initialize the FMUs
s1_fmi3EnterInitializationMode(s1, fmi3False, 0.0, startTime, fmi3True, stopTime);
s2_fmi3EnterInitializationMode(s2, fmi3False, 0.0, startTime, fmi3True, stopTime);
// set the input values at time = startTime
// fmi3SetReal/Integer/Boolean/String(s1, ...);
// fmi3SetReal/Integer/Boolean/String(s2, ...);
s1_fmi3ExitInitializationMode(s1);
s2_fmi3ExitInitializationMode(s2);
////////////////////////
// Simulation sub-phase
tc = startTime; // current time
while ((tc < stopTime) && (status == fmi3OK)) {
// retrieve outputs
// fmi3GetReal(s1, ..., 1, &y1);
// fmi3GetReal(s2, ..., 1, &y2);
// set inputs
// fmi3SetReal(s1, ..., 1, &y2);
// fmi3SetReal(s2, ..., 1, &y1);
// call instance s1 and check status
fmi3Boolean terminate, earlyReturn;
fmi3Float64 lastSuccessfulTime;
status = s1_fmi3DoStep(s1, tc, h, fmi3True, &terminate, &earlyReturn, &lastSuccessfulTime);
if (terminate) {
printf("Instance s1 requested to terminate simulation.");
break;
}
// call instance s2 and check status as above
status = s2_fmi3DoStep(s2, tc, h, fmi3True, &terminate, &earlyReturn, &lastSuccessfulTime);
// ...
// increment current time
tc += h;
}
//////////////////////////
// Shutdown sub-phase
if (status != fmi3Error && status != fmi3Fatal) {
s1_fmi3Terminate(s1);
s2_fmi3Terminate(s2);
}
if (status != fmi3Fatal) {
s1_fmi3FreeInstance(s1);
s2_fmi3FreeInstance(s2);
}
4.2.9. Code Example for Clocks
In the following example, the usage of the FMI functions is sketched in order to clarify the typical calling sequence of the functions in a simulation environment. We consider …
The error handling is implemented in a very rudimentary way.
//include::examples/c-code/co_simulation_clocked.c[tags=CoSimulation]
4.3. Description Schema
The common XML elements and attributes are defined in Section 2.4.
Additional elements and attributes are defined subsequently.
If the FMU implements the Co-Simulation interface type, the element <CoSimulation>
must be present.
It is defined as:

The attributes in the following table are defined on top of the common attributes and have the following meaning (all attributes are optional with exception of modelIdentifier
):
Attribute | Description |
---|---|
|
Short class name according to C syntax, for example, |
The FMU can handle variable communication step size.
The communication step size (argument |
|
If |
|
|
The fixed internal step size of the FMU (optional).
[This information can be used by the co-simulation algorithm to synchronize the communication interval with the internal step size of the FMU.
The co-simulation algorithm should calculate the communication points by multiplying ( |
|
If |
Note that if needsExecutionTool = true
, then it is required that the original tool is available to be executed during co-simulation.
If needsExecutionTool = false
, the FMU is completely contained inside the FMU in source code or binary format (DLL/SharedObject).
4.3.1. Clocks in Co-Simulation
The co-simulation algorithm collects the information about the number and properties of clocks
supported by the FMU by analyzing the modelDescription.xml
, see Section 2.4.4.1.
The definition of clocks
is optional.
Each inputClock
that ticks outside of the FMU, is activated for an FMU based on their valueReference
.
Output clocks
inside of an FMU signal their activation based on their valueReference
.
[If dependencies
(fmi3Unknown
) are defined in the <ModelStructure>
section of the modelDescription.xml
, it is recommended to define such dependencies
only within a model partition of a model (i.e. between variables that are assigned to the same clock
).]
If dependencies
are defined for variables across model partitions, such variables can not be assigned to a clock
via clockReference
.
For FMI for Co-Simulation, variables that are assigned to a model partition of the model based on clockReference
are not necessarily clocked
.
Such variables can be continuous-time or discrete-time variables if the clock
is of clockType = communicationPoint
.
4.3.2. Example XML Description File
4.3.2.1. Example XML Description File with Early Return
The Example fmiModelDescription below is the same as shown in Section 3.3.1 for a Model Exchange FMU.
The only differences are the replacement of the element <ModelExchange>
with the element <CoSimulation>
(with additional attributes), and the removal of local
variables, which are associated with continuous states
and their derivatives
and presence of the capability flags canHandleVariableCommunicationStepSize
and canReturnEarlyAfterIntermediateUpdate
with value true
.
<?xml version="1.0" encoding="utf-8"?>
<fmiModelDescription
fmiVersion="3.0-alpha.5"
modelName="MyLibrary.SpringMassDamper_Early_Return_example"
instantiationToken="{8c4e810f-3df3-4a00-8276-176fa3c9f9e0}"
description="Rotational Spring Mass Damper System"
version="1.0"
generationDateAndTime="2011-09-23T16:57:33Z"
variableNamingConvention="structured">
<CoSimulation
modelIdentifier="MyLibrary_SpringMassDamper"
canHandleVariableCommunicationStepSize="true"
canReturnEarlyAfterIntermediateUpdate="true"
hasEventMode="true"/>
<UnitDefinitions>
<Unit name="rad">
<BaseUnit rad="1"/>
<DisplayUnit name="deg" factor="57.2957795130823"/>
</Unit>
<Unit name="rad/s">
<BaseUnit s="-1" rad="1"/>
</Unit>
<Unit name="kg.m2">
<BaseUnit kg="1" m="2"/>
</Unit>
<Unit name="N.m">
<BaseUnit kg="1" m="2" s="-2"/>
</Unit>
</UnitDefinitions>
<TypeDefinitions>
<Float64Type name="Modelica.Units.SI.Inertia" quantity="MomentOfInertia" unit="kg.m2" min="0.0"/>
<Float64Type name="Modelica.Units.SI.Torque" quantity="Torque" unit="N.m"/>
<Float64Type name="Modelica.Units.SI.AngularVelocity" quantity="AngularVelocity" unit="rad/s"/>
<Float64Type name="Modelica.Units.SI.Angle" quantity="Angle" unit="rad"/>
</TypeDefinitions>
<DefaultExperiment startTime="0.0" stopTime="3.0" tolerance="0.0001"/>
<ModelVariables>
<Float64 name="inertia1.J" valueReference="1073741824"
description="Moment of load inertia" causality="parameter" variability="fixed"
declaredType="Modelica.Units.SI.Inertia" start="1"/>
<Float64 name="torque.tau" valueReference="536870912"
description="Accelerating torque acting at flange (= -flange.tau)" causality="input"
declaredType="Modelica.Units.SI.Torque" start="0"/>
<Float64 name="inertia1.phi" valueReference="805306368"
description="Absolute rotation angle of component" causality="output"
declaredType="Modelica.Units.SI.Angle"/>
<Float64 name="inertia1.w" valueReference="805306369"
description="Absolute angular velocity of component (= der(phi))" causality="output"
declaredType="Modelica.Units.SI.AngularVelocity"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="805306368"/>
<Output valueReference="805306369"/>
<InitialUnknown valueReference="805306368"/>
<InitialUnknown valueReference="805306369"/>
</ModelStructure>
</fmiModelDescription>
4.3.2.2. Example XML Description File with Clocks
The example below is the same one as shown in Section 4.3.2.1 for a Co-Simulation FMU.
The only differences are, that the element <fmiModelDescription><CoSimulation>
is present and clocks
are defined in the modelDescription.xml
.
The XML file may have the following content:
//include::examples/co_simulation_clocked_cosimulation.xml[]
5. FMI for Scheduled Execution
The Co-Simulation interface provides an indirect control over the computation of model partitions. With Scheduled Execution a simulation algorithm can directly control the time of computation (i.e. scheduling) for such model partitions.
The Scheduled Execution interface addresses simulation use cases with the following requirements:
-
At any time (even for unpredictable events), an event can be signaled to an FMU;
-
If multiple FMUs share resources (e.g. control tasks), the time requirements (e.g. execution time, communication deadlines) of all model partitions have to be observed and respected;
-
Time requirements may exist due to communication constraints (that are not apparent at FMU simulation level) which have to be fulfilled by the simulation algorithm;
-
That requires a global evaluation order and preemption policy for all model partitions of the multiple FMUs
-
Priority information provided by the FMUs has to be evaluated and merged to an overall priority for available model partitions
-
-
Data shall move between the different FMU model partitions for the same or next activation time.
-
Get/set operations must also be possible for the same activation time for different model partitions between the computation of these model partitions.
-
-
The Co-Simulation interface provides support for concurrent computation of model partitions (i.e. a support of multiple rates) on a single computational resource (e.g. CPU-core) of an FMU. For that a preemptive multitasking regime is intended (cooperative multitasking is not covered by this description).
[A parallel computation of model partitions is not part of the FMI 3.0 API. An FMU may still internally use parallel computation on multiple cores, but handling this is (currently) not part of the FMI standard. Such an internal parallel computation is not visible to the simulation algorithm. It is a tool vendor specific solution that has ties to the used OS and the co-simulation environment.]
5.1. Mathematical Description
The Scheduled Execution interface has a different timing concept compared to FMI for Co-Simulation.
This is required to cover clock
ticks for aperiodic input clocks
which may tick at time instances that are not predictable in advance for the simulation algorithm.
Typically, hardware I/O or virtual ECU software events belong to this category.
A simulation algorithm’s call for computing a model partition will compute the results of the model partition defined by an inputClock
for the current clock
tick time \(t_i\).
The result values will be computed for the current clock
tick time (activation time) \(t_i\) from the assigned inputClock
(which is known to the simulation algorithm).
Refer to the clock
time progress definition (Section 2.2.7.2) for periodic
clocks
.
If required, the FMU can internally derive the clock
interval \(\Delta T_i\) based on the last clock
tick time \(t_{i-1}\) i.e. last activation time for this model partition.
A model partition can only be activated once per activation time point \(t_i\).
Model partitions that are associated to output clocks
will accordingly provide the result values of the model partition’s variables for the current outputClock
tick time \(t_i\) of the active outputClock
.
The activation of such an outputClock
is not controlled by the simulation algorithm but internally by the FMU.
More details can be found in Section 2.2.7, specifically Section 2.2.7.2.
5.2. Application Programming Interface
This section contains the description of the Scheduled Execution interface for a C program.
The direct scheduling of model partitions based on clock
ticks requires an additional handling mode for FMUs.
The FMU signals its support for direct model partition scheduling in the modelDescription.xml
via the element <fmiModelDescription><ScheduledExecution>
.
The simulation algorithm signals to the FMU that it supports and has recognized the clock
and model partition scheduling capabilities of the FMU by instantiating it as Scheduled Execution.
Error, reset or terminate information is a global state of the FMU.
If e.g. an function returns fmi3Discard
or fmi3Error
this is also assumed for all active or preempted model partitions.
In case of fmi3Discard
or fmi3Error
no repetition of the step is possible, the only possible way to go forward is to enter the Terminated state and to end or to reset the simulation or - if supported - to set the FMU back to a former state.
5.2.1. State Machine for Scheduled Execution
This section summarizes the available states and the allowed function calls in the respective states.
If the simulation algorithm intends to enter the state Terminated it must ensure that all tasks related to model partitions of the FMU have ended.
Hence if in states Clock Activation Mode, Intermediate Update Mode, or Reconfiguration Mode a function returns fmi3Fatal
the simulation algorithm may prematurely end all tasks related to the computation of model partitions of this FMU.
If in these states a function returns fmi3Discard
or fmi3Error
the simulation algorithm may wait until all other tasks of the model partitions of this FMU have ended, but new tasks must not be started.
Each state of the state machine corresponds to a certain phase of a simulation. Common states are defined in Section 2.3, such as super states FMU State Setable and Initialized, states Instantiated, Configuration Mode, Reconfiguration Mode, Initialization Mode, Terminated and Intermediate Update Mode.
5.2.1.1. Super State: Initialized
Special to Scheduled Execution, the following additional constrains apply to the state Initialized (see Section 2.3.2).
The FMU enters state Terminated only after all other tasks related to the computation of model partitions of this FMU have ended.
After fmi3Terminate
has been called no new tasks can be started (e.g. related to outputClock
ticks) and all other function calls for this FMU must return fmi3Error
until the state Terminated is reached.
5.2.1.2. State: Clock Activation Mode
The FMU enters this state when the simulation algorithm calls fmi3ExitInitializationMode
in state Initialization Mode or fmi3ExitConfigurationMode
in state Reconfiguration Mode.
In this state the simulation algorithm can create multiple concurrent tasks related to an FMU and in each task the simulation algorithm can activate one or multiple input clocks
of an FMU based on the defined clock
properties via a fmi3ActivateModelPartition
call for each clock
.
- Allowed Function Calls
fmi3ActivateModelPartition
-
Each
fmi3ActivateModelPartition
call is now associated to the computation of a (publicly disclosed, externally controlled) model partition of the model and therefore to a single definedinputClock
.
typedef fmi3Status fmi3ActivateModelPartitionTYPE(fmi3Instance instance,
fmi3ValueReference clockReference,
size_t clockElementIndex,
fmi3Float64 activationTime);
The fmi3ActivateModelPartition
function has the following arguments:
-
fmi3Instance instance
: same meaning as for otherfmi3*
functions -
fmi3ValueReference
clockReference
:valueReference
of aninputClock
variable defined in themodelDescription.xml
which shall be activated -
size_t
clockElementIndex
:: The element index of theinputClock
variable which shall be activated. For a scalarclock
variable this must be 0; for arrayclock
variables, the element clock to activate is specified using the 1-based element index. Using the element index 0 means all elements of theclock
variable. (Note: If an array has more than one dimension the indices are serialized in the same order as defined for values in Section 2.2.5.1).
-
fmi3Float64 activationTime
: value of theindependent
variable of the assignedinputClock
tick time \(t_i\) [typically: simulation (i.e. virtual) time] (which is known to the simulation algorithm).
Scheduling of fmi3ActivateModelPartition
calls for each FMU is done by the simulation algorithm.
Calls are based on ticks of periodic
or aperiodic input clocks
.
These input clock
ticks can be based on clock
ticks from FMU external sources (e.g. output clocks
of other FMUs).
The inputClock
ticks can also be based on output clock
ticks of the same FMU.
Refer to Section 5.1 and Section 2.2.7.2.
The fmi3ActivateModelPartition
function is not called for output clocks
of an FMU.
Note that this is a different timing concept compared to fmi3DoStep
calls for Co-Simulation FMUs or the fmi3SetTime
for Model Exchange FMUs.
A fmi3ActivateModelPartition
call will compute the results of the model partition defined by clockReference
and clockElementIndex
(i.e. valueReference
of the variable that defines a clock
and an element index into that for arrays) for the current clock
tick \(t_i\).
If required, the FMU can internally derive the clock
interval \(\Delta T_i\) based on the last clock
tick time \(t_{i-1}\) i.e. last activationTime
for this clockReference
and clockElementIndex
(based on last fmi3ActivateModelPartition
call).
Consecutive calls to fmi3ActivateModelPartition
for a clockReference
and clockElementIndex
(i.e. valueReference
of clock
variable and element index into that for arrays) must have strictly monotonically increasing activationTime
\(t_i\).
- Function
fmi3Set{VariableType}
-
This function can be called before scheduling a model partition for variables assigned to that model partition via its associated
clock
and all variables not associated to aclock
(global variables). - Function
fmi3Get{VariableType}
,fmi3GetOutputDerivatives
,fmi3GetDirectionalDerivative
-
These functions can be called after the computation of a model partition for variables assigned to that model partition via its associated
clock
and all variables not associated to aclock
(global variables).
Set/get operations must be atomic for a single variable.
[Because of real-time constraints, the computational effort has to be predictable for all operations in Scheduled Execution.
Therefore, all computationally expensive operations to compute a model partition have to be contained within the fmi3ActivateModelPartition
function.
The simulation algorithm can assume that fmi3Get{VariableType}
and fmi3Set{VariableType}
operations are not computationally expensive.
It is recommended, to call fmi3Set{VariableType}
and fmi3Get{VariableType}
in the same task as fmi3ActivateModelPartition
.]
The restrictions related to variable causality
and variability
defined for Step Mode in Co-Simulation
apply.
It is not allowed to call fmi3Get{VariableType}
functions after fmi3Set{VariableType}
functions without an fmi3ActivateModelPartition
call in between.
[The reason is to avoid different interpretations of the caching, since contrary to FMI for Model Exchange
, fmi3ActivateModelPartition
will perform the actual calculation instead of fmi3Get{VariableType}
, and therefore, dummy algebraic loops at communication points cannot be handled by an appropriate sequence of fmi3Get{VariableType}
and fmi3Set{VariableType}
calls as for Model Exchange.
Example:
Correct calling sequence for a model partition | Illegal calling sequence |
---|---|
fmi3Set{VariableType} on inputs |
fmi3Set{VariableType} on inputs |
]
- Function
fmi3CallbackIntermediateUpdate
-
Only in this state the FMU is allowed to call the callback
fmi3CallbackIntermediateUpdate
. The callback may be called from concurrent tasks withinfmi3ActivateModelPartition
. The function must not returnfmi3Discard
. - Functions
fmi3GetFMUState
,fmi3SetFMUState
,fmi3FreeFMUState
,fmi3SerializedFMUStateSize
,fmi3SerializeFMUState
,fmi3DeSerializeFMUState
-
These functions must not be called if any model partition is currently active or preempted. [This is because these functions apply to the whole FMU and not only to a specific model partition.]
5.2.1.3. State: Intermediate Update Mode
Here only special remarks w.r.t. Intermediate Update Mode in Scheduled Execution are made.
For the general mechanism see Section 2.3.3.
The arguments canReturnEarly
, earlyReturnRequested
, earlyReturnTime
are ignored by FMU and importer.
A model partition of an SE FMU calls fmi3CallbackIntermediateUpdate
to signal clock activations with clocksTicked == fmi3True
.
The scheduling algorithm then uses fmi3GetClock
to determine which clock ticked.
If an output clock
with an attribute triggeredBy
ticked, the scheduling algorithm schedules the model partition associated with the corresponding input clock
.
- Allowed Function Calls
-
Additionally to the functions listed in Section 2.3.3, SE allows calling the following functions (in ME and CS, the following functions can be called in Event Mode):
fmi3GetClock
-
For an
outputClock
only the first call offmi3GetClock
for a specific activation of thisclock
signalsfmi3ClockActive
. The FMU sets the reported activation state immediately back tofmi3ClockInactive
for the followingfmi3GetClock
calls for thatclock
(in the same or other model partitions of the FMU) until thisoutputClock
is internally activated again. The simulation algorithm can callfmi3Set{VariableType}
andfmi3Get{VariableType}
during the callback for variables associated to anoutputClock
that is active during this callback. fmi3GetIntervalDecimal
&fmi3GetIntervalFraction
-
For
output clocks
andlocal clocks
it is allowed to call these functions during Intermediate Update Mode. These functions can be called only at the first activation ofperiodic
output clocks
. Foraperiodic
output clocks
, these functions must be called at every activation [to inquire when triggeredinput clocks
must tick].
[Based on the FMI standard it cannot be determined which part of the code of an FMU has called the callback function fmi3CallbackIntermediateUpdate
.
This is especially the case for Scheduled Execution where multiple model partitions can be active at the same time.
This causes no issues since all function call prerequisites are connected to the activation state of clocks
, modelDescription.xml
information and additionally available information from fmi3CallbackIntermediateUpdate
]
5.2.2. Preemption Support
For real-time applications the simulation time equals the real wall clock
time, thus each fmi3ActivateModelPartition
computation step has to be finished in real-time within its current period time length (computation time is not only defined by the runtime of fmi3ActivateModelPartition
but also by the time for setting and getting variables and related operations).
Usually a preemptive scheduling of the fmi3ActivateModelPartition
, fmi3Get{VariableType}
, fmi3Set{VariableType}
calls is required for respecting this constraint.
The FMU’s code has to be prepared for being able to correctly handle preemptive calls of fmi3ActivateModelPartition
, fmi3Get{VariableType}
, fmi3Set{VariableType}
.
That requires a secured internal and external access to global states and variable values.
Thus in Scheduled Execution a support for a correct handling of the preemption of model partition computations is required.
That also requires that the FMU reports the active state of a outputClock
only with the first call of fmi3GetClock
for a specific activation of this clock
and sets the reported activation state immediately back to false
for the following fmi3GetClock
calls for that clock
until this outputClock
is internally activated again.
If a preemptive multitasking regime is intended an individual task (or thread — task and thread are used synonymously here) for each model partition (associated to an inputClock
) has to be created.
The task for computing each fmi3ActivateModelPartition
is created and controlled by the simulation algorithm, not by the FMU.
So the FMU exporting tool does not need to take care for that (except for preparing its code to support preemption).
[If only one single model partition (inputClock
) is available via the interface of an FMU, preemptive calls of the related fmi3ActivateModelPartition
function are possible by default since there are no external cross dependencies within one model partition between communication points.]
Based on the inputClock
settings defined in the XML the simulation algorithm calls fmi3Set{VariableType}
, fmi3ActivateModelPartition
, fmi3Get{VariableType}
calls.
Set/get calls for each task are only allowed for variables that are associated to the inputClock
associated to that task or - here preemption issues become important - to variables that are associated to no clocks
(global variables), based on the XML information (see Section 2.4.4.1).
[The recommendation is to avoid global variable associations as much as possible in the XML. It is also recommended to reduce dependencies (defined in XML model structure) between variables located in different model partitions of one FMU, since this also requires in most cases that the related variables have to be global variables.]
The simulation algorithm has no knowledge about the FMU internal communication between the model partitions of a single FMU and does not handle it.
The simulation algorithm schedules the fmi3ActivateModelPartition
(as well as related fmi3Get{VariableType}
and fmi3Set{VariableType}
) calls based on given priorities for input clocks
defined in the modelDescription.xml
.
Priority (see Section 2.4.4.1):
-
Same priority: Model partitions (e.g. tasks) cannot preempt each other. Arbitrary evaluation order is possible for model partitions of the same priority.
-
Different priorities: Model partitions of a higher priority preempt partitions of a lower priority as soon as the higher priority partition needs to be computed.
[If multiple tasks are needed to be scheduled for computation at a certain time instant a simulation algorithm must schedule a task of a higher priority always before a task of a lower priority]
Input
clock
ticks (see Section 2.2.7.4):
-
(
strict
)periodic
(period can be predefined by FMU or be defined by simulation algorithm, depending on XML information) -
aperiodic (based on external possibly unpredictable events or on an
outputClock
of the same FMU)
Based on the period and priority definitions the exporting tool can restrict the code evaluation order.
It nevertheless has to secure its code against concurrent evaluation [not against parallel evaluation, as this is not supported for model partitions of an FMU in the interface description of this mode] along the defined priority restrictions.
Mostly this is required for internal inter-model-partition communication and in general for the joint use of global variables within the FMU.
The exporting tool has to consider the effect of input
aperiodic clocks
and the influences of computing speed, so the exact preemption occurrence points cannot be foreseen (within the given priority and period restrictions).
To guard certain code parts against preemption they must be enclosed with the callback functions lockPreemption
and unlockPreemption
.
[Such locks should be used with care and only for securing very short code parts that cannot be secured otherwise.]
typedef void (*fmi3CallbackLockPreemption) ();
typedef void (*fmi3CallbackUnlockPreemption) ();
Even if the scheduler does not support preemption, at least an empty implementation of these callback functions must be provided to allow the reuse of code for different modes together with an efficient preemption. [This avoids checks for null function pointers. A function call to a void-void function with an immediate return is hardly any overhead.]
Example for the use of fmi3CallbackLockPreemption
and fmi3CallbackUnlockPreemption
callback functions in the FMU code:
Int16 DataBuffer[3]; // global buffer
void Task1(void) //low priority
{
...
// write data to DataBuffer
fmi3CallbackLockPreemption();
DataBuffer[0] = internal_out_RootSys1_1;
DataBuffer[1] = internal_out_RootSys1_2;
DataBuffer[2] = internal_out_RootSys1_3;
fmi3CallbackUnlockPreemption();
...
}
...
void Task2(void) //high priority
{
...
// read data from DataBuffer
fmi3CallbackLockPreemption();
internal_in_RootSys2_1 = DataBuffer[0];
internal_in_RootSys2_2 = DataBuffer[1];
internal_in_RootSys2_3 = DataBuffer[2];
fmi3CallbackUnlockPreemption();
...
}
5.2.3. Example for Scheduled Execution
The FMU ThreeInputClocks sketches the usage of the FMI functions.
The example is given in a mix of pseudo-code and C, in order to keep it small and understandable.
We consider one FMU with three model partitions.
Two model partitions associated to two periodic
input clocks
10msClock and 50msClock (clock
periods 10 ms and 50 ms) and one aperiodic inputClock
AperiodicClock.
During the execution of the model partition of input clock
10msClock the output clock
OutClock may tick and invoke the execution of model partition of aperiodic inputClock
AperiodicClock.
The function calls fmi3ActivateModelPartition
are executed in the context of preemptable tasks whose priorities are derived from the respective inputClock
configurations of the FMU.
In this example the execution of the task of inputClock
AperiodicClock is waiting for the task of inputClock
10msClock to finish.
Likewise the task of AperiodicClock is suspended when the task of higher priority is scheduled again.
The example also depicts how a task associated to an even lower prior inputClock
50msClock is delayed several times by tasks of higher priority.
Note that the point of time when the task was scheduled is the activationTime
of fmi3ActivateModelPartition
(…Activate…(input clock
, activationTime
)).

5.2.3.1. Description Schema
The simulation algorithm collects the information about the number and properties of clocks
supported by the FMU via analyzing the modelDescription.xml
as defined in Section 2.4.
For every input clock
the simulation algorithm defines a task.
The properties period
and priority
are defined based on the input clocks'
period
and priority
defined in the modelDescription.xml
.
The simulation algorithm can read from the modelDescription.xml
that output clock
OutClock may tick triggered by inputClock
10msClock and that inputClock
AperiodicClock is triggered by OutClock.
<?xml version="1.0" encoding="UTF-8"?>
<fmiModelDescription fmiVersion="3.0" modelName="ThreeInputClocks">
<ScheduledExecution modelIdentifier="ThreeInputClocks" canBeInstantiatedOnlyOncePerProcess="true"/>
<LogCategories>
<Category name="logStatusError" description="Log error messages"/>
</LogCategories>
<DefaultExperiment startTime="0" stopTime="6" stepSize="0.001"/>
<ModelVariables>
<!-- Variables related to input clock 10msClock -->
<Float64 name="AIn1" valueReference="0" causality="input" clockReference="5" start="0"/>
<Float64 name="AIn2" valueReference="1" causality="input" clockReference="5" start="0"/>
<Float64 name="AOut" valueReference="2" causality="output" clockReference="5"/>
<!-- Variables related to input clock AperiodicClock -->
<Float64 name="BIn" valueReference="3" causality="input" clockReference="6" start="0"/>
<Float64 name="BOut" valueReference="4" causality="output" clockReference="6"/>
<!-- Clock variables -->
<!-- Periodic input clock -->
<Clock name="10msClock" valueReference="5" causality="input" clockType="communicationPoint"
priority="1" periodic="true" strict="true" intervalCounter="10" resolution="1000"/>
<!-- Input clock that must be triggered by OutClock -->
<Clock name="AperiodicClock" valueReference="6" causality="input" clockType="communicationPoint"
priority="2" triggeredBy="7" />
<!-- Output clock activated in model partition associated to 10msClock -->
<Clock name="OutClock" valueReference="7" causality="output" clockType="communicationPoint"
priority="2" clockReference="5" />
<!-- Periodic input clock -->
<Clock name="50msClock" valueReference="8" causality="input" clockType="communicationPoint"
priority="3" periodic="true" strict="true" intervalCounter="50" resolution="1000"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="2"/>
<Output valueReference="4"/>
</ModelStructure>
</fmiModelDescription>
5.2.3.2. Simulation Algorithm Implementation
To enable the computation of a Scheduled Execution FMU a simulation algorithm has to provide a task scheduler.
Depending on the particular configuration the simulation algorithm sets up tasks for every input clock
.
When executed each task calls fmi3ActivateModelPartition
for its respective input clock
.
The activationTime
is provided by the simulation algorithm.
Periodic tasks can be scheduled on initialization of the simulation application.
Aperiodic tasks are scheduled explicitly during the execution.
Task10ms.Execute()
{
// Set inputs with valueReference 0 and 1 associated to clockIndex 5
fmi3SetFloat64(s, {0,1}, &AIn);
// call for 10msClock tick (clockIndex 5)
fmi3ActivateModelPartition(s, 5, 0, Task10ms.ActivationTime);
// Get output with valueReference 2 associated to clockIndex 0
fmi3GetFloat64(s, {2}, &AOut);
};
As specified in the XML file, input clock
AperiodicClock is triggered by output clock
OutClock thus the simulation algorithm ensures the task associated to AperiodicClock is scheduled when fmi3CallbackIntermediateUpdate
is called by the FMU and OutClock has ticked.
void CallbackIntermediateUpdate(..., fmi3Boolean clocksTicked, ...)
{
fmi3ValueReference outputClockReferences = {7};
fmi3Boolean[] clocksActivationState = {fmi3ClockInactive};
if (clocksTicked)
{
// ask FMU if output clock has ticked
fmi3GetClocks(... outputClockReferences, &clocksActivationState, ...);
}
if (clocksActivationState[0])
{
// schedule task for AperiodicClock
Scheduler->ScheduleTask(TaskAperiodic);
}
}
5.2.3.3. FMU Implementation
The FMU implements fmi3ActivateModelPartition
dispatching for every input clock
so the code might look like this:
fmi3Status fmi3ActivateModelPartition(fmi3Instance *instance,
fmi3ValueReference clockReference, fmi3Float64 activationTime)
{
switch (clockReference)
{
case 5:
// Input clock 10msClock
activateModelPartition10ms(instance, activationTime);
case 6:
// Input clock AperiodicClock
activateModelPartitionAperiodic(instance, activationTime);
case 8:
// Input clock AperiodicClock
activateModelPartition50ms(instance, activationTime);
...
}
}
In the context of the task being executed every 10 ms, the FMU lets output clock
OutClock tick and calls fmi3CallbackIntermediateUpdate
.
void activateModelPartition10ms(fmi3Instance *instance, ...)
{
...
if (...)
{
// outputClock ticks
fmi3SetClock({7});
// inform simulation algorithm that output clock has ticked
fmi3Boolean clocksTicked = fmi3True;
instance->fmi3CallbackIntermediateUpdate(..., clocksTicked, ...);
}
...
}
If fmi3GetClock
is called for a certain output clock
the output clock
is reset.
fmi3Status fmi3GetClock(..., fmi3ValueReference outputClockReferences,
fmi3Clock *clocksActivationState, ...)
{
if (outputClockReferences[0] == 7)
{
clocksActivationState[0] = outClockActivationState;
outClockActivationState = fmi3ClockInactive;
}
}
5.3. Description Schema
The common XML elements and attributes are defined in Section 2.4.
Additional elements and attributes are defined subsequently.
If the FMU implements the Scheduled Execution interface type, the element <ScheduledExecution>
must be present.
It is defined as:

The attribute in the following table is defined on top of the common attributes and have the following meaning (all attributes are optional with exception of modelIdentifier
):
Attribute | Description |
---|---|
|
Short class name according to C syntax, for example, |
References
-
[ABL12] Åkesson J., Braun W., Lindholm P., and Bachmann B. (2012): Generation of Sparse Jacobians for the Functional Mockup Interface 2.0. 9th International Modelica Conference, Munich, 2012. http://www.ep.liu.se/ecp/076/018/ecp12076018.pdf
-
[BPRS15] Atilim Gunes Baydin, Barak A. Pearlmutter, Alexey Andreyevich Radul, Jeffrey Mark Siskind (2015): Automatic differentiation in machine learning: a survey. https://arxiv.org/abs/1502.05767
-
[BCP10] Benveniste A., Caillaud B., Pouzet M. (2010): The Fundamentals of Hybrid Systems Modelers. In 49th IEEE International Conference on Decision and Control (CDC), Atlanta, Georgia, USA, December 15-17. http://www.di.ens.fr/~pouzet/bib/cdc10.pdf
-
[BOA11] Blochwitz T., Otter M., Arnold M., Bausch C., Clauß C., Elmqvist H., Junghanns A., Mauss J., Monteiro M., Neidhold T., Neumerkel D., Olsson H., Peetz J.-V., Wolf S. (2011): The Functional Mockup Interface for Tool independent Exchange of Simulation Models. 8th International Modelica Conference, Dresden 2011. http://www.ep.liu.se/ecp/063/013/ecp11063013.pdf
-
[BKF17] Braun W., Kulshreshtha K., Franke R., Walther A., Bachmann B., Towards Adjoint and Directional Derivatives in FMI utilizing ADOL-C within OpenModelica, 12th International Modelica Conference, Prague, 2017. https://2017.international.conference.modelica.org/proceedings/html/submissions/ecp17132363_BraunKulshreshthaFrankeBachmannWalther.pdf
-
[BOA12] Blochwitz T., Otter M., Åkesson J., Arnold M., Clauß C., Elmqvist H., Friedrich M., Junghanns A., Mauss J., Neumerkel D., Olsson H., Viel A. (2012): Functional Mockup Interface 2.0: The Standard for Tool independent Exchange of Simulation Models. 9th International Modelica Conference, Munich, 2012. http://www.ep.liu.se/ecp/076/017/ecp12076017.pdf
-
[KS00] Kübler R., Schiehlen W. (2000): Two methods of simulator coupling. Mathematical and Computer Modeling of Dynamical Systems 6 pp. 93-113.
-
[LZ07] Lee E.A., Zheng H. (2007): Leveraging Synchronous Language Principles for Heterogeneous Modeling and Design of Embedded Systems. EMSOFT'07, September 30-October 3, Salzburg, Austria. https://ptolemy.berkeley.edu/publications/papers/07/unifying/LeeZheng_SRUnifying.pdf
-
[MLS12] Modelica (2012): Modelica, A Unified Object-Oriented Language for Systems Modeling. Language Specification, Version 3.3, May 9, 2012. https://www.modelica.org/documents/ModelicaSpec33.pdf
-
[MG09] MODELISAR Glossary (2009): MODELISAR WP2 Glossary and Abbreviations. Version 1.0, June 9, 2009.
-
[PZ06] Pouzet M. (2006): Lucid Synchrone. Version 3.0, Tutorial and Reference Manual. http://www.di.ens.fr/~pouzet/lucid-synchrone/
-
[CGM84] Coleman, Garbow, Moré (1984): Software for estimating sparse Jacobian matrices, ACM Transactions on Mathematical Software. TOMS , vol. 10, no. 3, pp. 346-347
-
[PW13] Preston-Werner, T. (2013): Semantic Versioning 2.0.0. https://semver.org/spec/v2.0.0.html
Appendix A: Glossary
This glossary is a subset of (MODELISAR Glossary, 2009) with some extensions.
Term |
Description |
argument |
Refers to a function parameter. Not to be confused with parameter. |
capability flag |
Capability flags are used to indicate to the importer what optional functionality the FMU supports. |
clock |
A variable to report events or trigger events or model partitions. |
clock tick |
When the |
communication points |
Time grid for data exchange between importer and FMU(s) in a (co-)simulation environment. |
communication step size |
Distance between two subsequent communication points. |
co-simulation |
Coupling of several simulation programs in order to compute the global behavior of a system that consists of several subsystems. The subsystems are coupled in the sense that the behavior of each subsystem depends on the behavior of the remaining subsystems, so that the co-simulation must be computed in a step-by-step fashion. Each simulation program is responsible for computing the behavior of a subsystem, using the outputs produced by the other simulation programs. Synonyms: dynamic mutual-exchange, simulator coupling, and coupled simulation. |
direct feedthrough |
Direct feedthrough describes that values of output variables depend directly on values of input variables. |
ECU |
Electronic Control Unit (Microprocessor that is used to control a technical system). |
event |
Something that occurs instantaneously at a specific time or when a specific condition occurs. At an event, numerical integration is suspended and variables may change their values discontinuously. Internal events occur inside the FMU and should be signaled to the environment without any delay and can cause event handling and/or the activation of an output clock. Input clocks are activated by the environment to inform the FMU about the exact moment an event across FMUs has to be handled. See state event, step event and time event. |
event indicator |
A variable that changes sign exactly at an event. |
exporter |
A program that creates an FMU. |
external scheduler |
See scheduler. |
feedthrough |
See direct feedthrough. |
FMI |
Functional Mock-up Interface: |
FMI functions |
The function of the FMI C-API. |
FMI for co-simulation |
Functional Mock-up Interface for Co-Simulation: |
FMI for model exchange |
Functional Mock-up Interface for Model Exchange: |
FMU |
Functional Mock-up Unit: |
FMU clock |
See |
importer |
The tool that imports or loads one or more FMUs. Also called simulation environment, environment, calling environment, (co-)simulation algorithm, target platform, target environment, integrator (in ME). |
independent variable |
All variables are a function of this |
An input event occurs when a discrete input variable changes or a continuous input variable has a discontinuity. |
|
integration algorithm |
The numerical algorithm to solve differential equations. |
integrator |
A software component, which implements an integration algorithm. |
interface |
An abstraction of a software component that describes its behavior without dealing with the internal implementation. Software components communicate with each other via interfaces. |
interrupt |
Event connected to the tick of an |
machine epsilon |
Smallest floating point value. |
mock-up |
A full-sized structural, but not necessarily functional model built accurately to scale, used chiefly for study, testing, or display. In the context of computer aided design (CAD), a digital mock-up (DMU) means a computer-based representation of the product geometry with its parts, usually in 3-D, for all kinds of geometrical and mechanical analyses. |
model |
A model is a mathematical or logical representation of a system of entities, phenomena, or processes.
Basically a model is a simplified abstract view of the complex reality. |
model description file |
The model description file is an XML file, which supplies a description of all properties of a model (for example, |
model description interface |
An interface description to write or retrieve information from the model description file. |
Model Description Schema |
An XML schema that defines how all relevant, non-executable, information about a "model class" (FMU) is stored in a text file in XML format. Most important, data for every variable is defined (variable name, handle, data type, variability, unit, etc.), see Section 2.4. |
model rate |
Inverse of time interval between two communication points associated to an exposed model partition within the FMU (i.e. |
model partition |
Model partitions can be associated to a discrete or (piecewise) continuous part of the FMU.
The computation of model partitions can be externally controlled based on Not all FMU internal model partitions have to be exposed in the Co-Simulation interface as As stated above, continuous parts of the FMU are also associated to model partitions that define the communication points for the |
Newtonian time instant |
TODO |
ODE |
see Ordinary Differential Equation |
Ordinary Differential Equation |
Differential equation containing one or more functions of one independent variable (typically time) and the derivatives of those functions. |
output points |
Tool internal time grid for saving output data to file (in some tools also known as "communication points" - but this term is used in a different way in FMI for Co-Simulation, see above). |
output step size |
Distance between two subsequent output points. |
parameter |
A quantity within a model, which remains constant during simulation ( |
run-time environment |
See co-simulation environment |
scheduled execution |
FMI type that externalizes the scheduler to run model partitions, potentially synchronized between more than one FMU and exchanging input and output variables accordingly. |
simulation |
Compute the behavior of one or several models under specified conditions. |
simulation model |
see model |
simulation program |
Software to develop and/or solve simulation models.
The software includes a solver, may include a user interface and methods for post processing (see also: simulation tool, simulation environment). |
simulation tool |
see simulation program |
simulator |
A simulator can include one or more simulation programs, which solve a common simulation task. |
simulator coupling |
See tool coupling. |
solver |
Software component, which includes algorithms to solve models, for example, integration algorithms and event handling methods. |
state |
The continuous |
Event that is defined by the time instant where the domain \(z > 0\) of an event indicator variable |
|
Event that might occur at a completed integrator step. Since this event type is not defined by a precise time or condition, it is usually not defined by a user. A program may use it, for example, to dynamically switch between different states. A step event is handled much more efficiently than a state event, because the event is just triggered after performing a check at a completed integrator step, whereas a search procedure is needed for a state event. |
|
structural parameter |
A parameter influencing the size and/or dimensionality of an array variable of an FMU. |
synchronous clock theory |
TODO |
super-dense time |
A precise definition of time taking into account iterations at an event.
For an FMU, the |
task |
Special kind of model partition that is used in control code. |
Event that is defined by a predefined time instant. Since the time instant is known in advance, the integrator can select its step size so that the event point is directly reached. Therefore, this event can be handled efficiently. |
|
tick relationshipt |
Event that is defined by a predefined time instant. Since the time instant is known in advance, the integrator can select its step size so that the event point is directly reached. Therefore, this event can be handled efficiently. |
TLM |
see Transmission Line Method |
Transmission Line Method |
A mathematical method which uses physically motivated time delays to decouple an equation system into independent parts during a specified time frame without compromising numerical stability. Also known as the bi-lateral delay line method. |
user interface |
The part of the simulation program that gives the user control over the simulation and allows watching results. |
XML |
eXtensible Markup Language (www.w3.org/XML, en.wikipedia.org/wiki/XML) - An open standard to store information in text files in a structured form. |
Appendix B: Acknowledgements
Until Dec. 2011, this work was carried out within the ITEA2 MODELISAR project (project number: ITEA2-07006, https://itea3.org/project/modelisar.html).
Daimler AG, DLR, ITI GmbH, Martin Luther University Halle-Wittenberg, QTronic GmbH and SIMPACK AG thank BMBF for partial funding of this work within MODELISAR (BMBF Förderkennzeichen: 01lS0800x).
Dassault Systèmes (Sweden) thanks the Swedish funding agency VINNOVA (2008-02291) for partial funding of this work within MODELISAR.
LMS Imagine and IFPEN thank DGCIS for partial funding of this work within MODELISAR.
Since Sept. 2012 until Nov. 2015, this work is partially carried out within the ITEA2 MODRIO project (project number: ITEA 2-11004, https://itea3.org/project/modrio.html).
-
DLR, ITI GmbH, QTronic GmbH and SIMPACK AG thank BMBF for partial funding of this work within MODRIO (BMBF Förderkennzeichen: 01IS12022E).
-
Dassault Systèmes (Sweden), Linköping University and Modelon AB thank the Swedish funding agency VINNOVA (2012—01157) for partial funding of this work within MODRIO.
-
Siemens PLM Software (France) and IFPEN thank DGCIS for partial funding of this work within MODRIO.