Functional Mock-up Interface - FMI
==================================

The `Functional Mock-up Interface (FMI) <http://www.fmi-standard.org>`_ Standard
for model exchange and co-simulation allows export, exchange and import of pre-compiled
models between different tools.
The FMI standard is Modelica independent, so import and export works both between
different Modelica or non-Modelica tools.

See also :ref:`OMSimulator documentation<omsimulator-documentation>`.

FMI Standards
-------------

.. list-table:: FMI standard versions
   :header-rows: 1
   :widths: 30 70

   * - Version
     - Support in OpenModelica
   * - `1.0.1 <https://fmi-standard.org/assets/releases/FMI_for_ModelExchange_v1.0.1.pdf>`_
     - Deprecated
   * - `2.0.5 <https://github.com/modelica/fmi-standard/releases/download/v2.0.5/FMI-Specification-2.0.5.pdf>`_
     - Supported
   * - `3.0.2 <https://fmi-standard.org/docs/3.0.2/>`_
     - Experimental

Layered Standards
~~~~~~~~~~~~~~~~~~

Layered standards extend FMI 3.0 with optional, separately versioned
specifications.

.. list-table:: FMI 3.0 layered standards
   :header-rows: 1
   :widths: 40 60

   * - Layered standard
     - Support in OpenModelica
   * - `FMI-LS-BUS <https://github.com/modelica/fmi-ls-bus>`_
     - Not planned
   * - `FMI-LS-XCP <https://github.com/modelica/fmi-ls-xcp>`_
     - Not planned
   * - `FMI-LS-STRUCT <https://github.com/modelica/fmi-ls-struct>`_
     - Planned
   * - `FMI-LS-REF <https://github.com/modelica/fmi-ls-ref>`_
     - Planned
   * - `FMI-LS-DAE <https://github.com/modelica/fmi-ls-dae>`_
     - Planned (demonstrator in progress)

Supported Capability Flags
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The optional capabilities advertised in the ``modelDescription.xml`` of an
exported FMU, per FMI version and interface type (Model Exchange, Co-Simulation
and, for FMI 3.0, Scheduled Execution).

.. list-table:: Exported capability flags
   :header-rows: 1
   :widths: 32 11 11 11 11 13

   * - Capability
     - 2.0 ME
     - 2.0 CS
     - 3.0 ME
     - 3.0 CS
     - 3.0 SE
   * - Get and set FMU state
     - yes
     - yes
     - yes
     - yes
     - yes
   * - Serialize FMU state
     - no
     - no
     - yes
     - yes
     - yes
   * - Directional derivatives
     - cond
     - exp
     - cond
     - cond
     - cond
   * - Adjoint derivatives
     - —
     - —
     - wip
     - wip
     - wip
   * - Per-element dependencies
     - —
     - —
     - no
     - no
     - no
   * - Variable communication step size
     - —
     - yes
     - —
     - yes
     - —
   * - Interpolate inputs
     - —
     - yes
     - —
     - —
     - —
   * - Max output derivative order
     - —
     - 1
     - —
     - 1
     - —
   * - Event mode
     - —
     - —
     - —
     - yes
     - —
   * - Intermediate update
     - —
     - —
     - —
     - no
     - —

Legend:

- ``yes`` / ``no`` — the capability flag is exported as ``true`` / ``false``.
- ``cond`` — exported as ``true`` only when a symbolic directional-derivative
  Jacobian is available, i.e. not disabled via
  :ref:`-d=disableDirectionalDerivatives<omcflag-debug-disableDirectionalDerivatives>`.
- ``exp`` — only enabled with the experimental flag ``-d=fmuExperimental``
  (``false`` by default). In FMI 3.0 these state features are always enabled.
- ``wip`` — in active development; currently exported as ``false``.
- ``—`` — not applicable to this interface type or FMI version.

FMI Export
----------

To export a FMU use the OpenModelica command :ref:`buildModelFMU()<buildModelFMU>` from
the command line interface, OMShell, OMNotebook or MDT.
The FMU export command is also integrated in OMEdit.
Select `File > Export > FMU`. Or alternatively, right click a model to obtain the export
command.
The FMU package is generated in the current working directory of OMC or the directory set
in `OMEdit > Options > FMI > Move FMU`.
You can use the :ref:`cd()<cd>` command to see the current location.
The location of the generated FMU is printed in the Messages Browser of OMEdit or on the
command line.

You can set which version of FMI to export through OMEdit settings, see section
:ref:`omedit-options-fmi`.

.. figure :: media/fmiExport.png

  FMI Export.

To export the bouncing ball example to an FMU, use the following commands:

.. omc-mos ::
  :erroratend:

  loadFile(getInstallationDirectoryPath() + "/share/doc/omc/testmodels/BouncingBall.mo")
  buildModelFMU(BouncingBall)

After the command execution is complete you will see that a file BouncingBall.fmu has been
created. Its contents varies depending on the target platform.
On the machine generating this documentation the contents in
:numref:`BouncingBall-FMU-contents` are generated (along with the C source code).

.. omc-mos ::
  :hidden:

  system("unzip -l BouncingBall.fmu | egrep -v 'sources|files' | tail -n+3 | grep -o '[A-Za-z._0-9/]*$' > BB.log")

.. literalinclude :: ../tmp/BB.log
  :name: BouncingBall-FMU-contents
  :caption: BouncingBall FMU contents

A log file for FMU creation is also generated named ModelName\_FMU.log.
If there are some errors while creating the FMU, they will be shown in the command line
window and logged in this log file as well.

By default an FMU that can be used for both Model Exchange and Co-Simulation is generated.
We support FMI 1.0 (deprecated) and FMI 2.0 for Model Exchange and Co-Simulation FMUs,
with experimental support for FMI 3.0 (see the version table above).

For the Co-Simulation FMU two integrator methods are available:

* Forward Euler [default]
* SUNDIALS CVODE (see [#f1]_)

Forward Euler uses root finding, which does an Euler step of ``communicationStepSize``
in ``fmi2DoStep``. Events are checked for before and after the call to
``fmi2GetDerivatives``.

If CVODE is chosen as integrator the FMU should also include runtime dependencies
(:ref:`--fmuRuntimeDepends=modelica<omcflag-fmuRuntimeDepends>`) to copy all used dynamic
libraries into the generated FMU to make it exchangeable.

To export a Co-Simulation FMU with CVODE for the bouncing ball example use the
following commands:

.. omc-mos ::
  :erroratend:

  loadFile(getInstallationDirectoryPath() + "/share/doc/omc/testmodels/BouncingBall.mo")
  setCommandLineOptions("--fmiFlags=s:cvode")
  buildModelFMU(BouncingBall, version = "2.0", fmuType="cs")


The FMU BouncingBall.fmu will have a new file BouncingBall_flags.json in its resources
directory. By manually changing its content users can change the solver method without
recompiling the FMU.

The BouncingBall_flags.json for this example is displayed in
:numref:`BouncingBall-FMI-flags`.

.. omc-mos ::
  :hidden:

  system("unzip -cqq BouncingBall.fmu resources/BouncingBall_flags.json > BouncingBall_flags.json")

.. literalinclude :: ../tmp/BouncingBall_flags.json
  :name: BouncingBall-FMI-flags
  :caption: BouncingBall FMI flags


Compilation Process
~~~~~~~~~~~~~~~~~~~

OpenModelica can export FMUs that are compiled with CMake (default) or Makefiles. CMake
version v3.21 or newer is recommended, minimum CMake version is v3.5.

The Makefile FMU export will be removed in a future version of OpenModelica.
Set compiler flag :ref:`--fmuCMakeBuild=false<omcflag-fmuCMakeBuild>` to use the
Makefiles export.

The FMU contains a CMakeLists.txt file in the sources directory that can be used to
re-compile the FMU for a different host and is also used to cross compile for different
platforms.

The CMake compilation accepts the following settings:

* ``BUILD_SHARED_LIBS``:
  Boolean value to switch between dynamic and statically linked binaries.

  * ``ON`` (default): Compile DLL/Shared Object binary object.

  * ``OFF``: Compile static binary object.

* ``FMI_INTERFACE_HEADER_FILES_DIRECTORY``:
  String value specifying path to FMI header files containing ``fmi2Functions.h``,
  ``fmi2FunctionTypes.h`` and ``fmi2TypesPlatforms.h``.

  * Defaults to a location inside the OpenModelica installation directory, which was used
    to create the FMU. They need to be version 2.0.4 from the FMI Standard.

* ``RUNTIME_DEPENDENCIES_LEVEL``:
  String value to specify runtime dependencies set.

  * ``none``: Adds no runtime dependencies to FMU. The FMU can't be used on a system if it
    doesn't provided all needed dependencies.

  * ``modelica`` (default): Add Modelica runtime dependencies to FMU, e.g. a external C
    library used from a Modelica function. Needs CMake version v3.21 or newer.

  * ``all``: Add system and Modelica runtime dependencies. Needs CMake version v3.21 or
    newer.

  CMake install TARGETS RUNTIME_DEPENDENCIES is not supported when cross compiling.
  When cross compiling the FMU CMake project therefore falls back to installing the
  external libraries it linked against directly, which covers the Modelica libraries
  a model depends on but not the system libraries of the target platform.

* ``NEED_CVODE``:
  Boolean value to integrate CVODE integrator into CoSimulation FMU.

  * ``ON``: Link to SUNDIALS CVODE. If CVODE is not in a default location
    ``CVODE_DIRECTORY`` needs to be set.
    Its also recommended to use ``RUNTIME_DEPENDENCIES_LEVEL=modelica`` or higher to add
    SUNDIALS runtime dependencies into the FMU.

  * ``OFF`` (default): Don't link to SUNDIALS CVODE.

* ``CVODE_DIRECTORY``:
  String value with location of libraries ``sundials_cvode`` and ``sundials_nvecserial``
  with SUNDIALS version 5.4.0.

  * Defaults to a location inside the OpenModelica installation directory, which was
    used to create the FMU.


Then use CMake to configure, build and install the FMU.
To repack the FMU after installation use custom target ``create_fmu``.

For example to re-compile the FMU with cmake and runtime dependencies use:

.. code-block:: bash

    $ unzip BouncingBall.fmu -d BouncingBall_FMU
    $ cd BouncingBall_FMU/sources
    $ cmake -S . -B build_cmake \
      -D RUNTIME_DEPENDENCIES_LEVEL=modelica \
      -D CMAKE_C_COMPILER=clang -D CMAKE_CXX_COMPILER=clang++
    $ cmake --build build_cmake --target create_fmu --parallel

.. _fmitlm-export-options :

Platforms
~~~~~~~~~

The ``platforms`` setting specifies for what target system the FMU is compiled:

* Empty: Create a Source-Code-only FMU.

* ``native``:  Create a FMU compiled for the exporting system.

* ``<cpu>-<vendor>-<os>`` host triple: OpenModelica searches for programs in PATH matching
  pattern ``<cpu>-<vendor>-<os>cc`` to compile.
  E.g. ``x86_64-linux-gnu`` for a 64 bit Linux OS or ``i686-w64-mingw32`` for a 32 bit
  Windows OS using MINGW.

* ``<cpu>-<vendor>-<os> docker run ghcr.io/openmodelica/crossbuild:v1.27.0``
  Host triple with Docker image provided by OpenModelica:
  OpenModelica will use Docker image
  `ghcr.io/openmodelica/crossbuild:v1.27.0 <https://github.com/OpenModelica/openmodelica-crossbuild>`_
  to cross compile. The image provides compiler toolchain files to
  cross compile with CMake for the following host triples:

    * ``i686-linux-gnu``
    * ``x86_64-linux-gnu``
    * ``aarch64-linux-gnu``
    * ``arm-linux-gnueabi``
    * ``arm-linux-gnueabihf``
    * ``i686-w64-mingw32``
    * ``x86_64-w64-mingw32``

  OpenModelica will add a matching ``CMAKE_TOOLCHAIN_FILE`` to the compilation
  process.

  If your model depends on external C libraries the library has to be available
  for the target platform, e.g. in ``Resources/Library/win64`` when compiling for
  ``x86_64-w64-mingw32``. OpenModelica searches the ``Resources/Library`` sub
  directory matching the target platform and copies the library into the FMU next
  to the model binary. If no binary for the target platform is shipped with the
  Modelica library, providing a pre-compiled static library can be necessary.

* ``<cpu>-<vendor>-<os> docker run <image>`` Host triple with Docker image:
  OpenModelica will use the specified Docker image to cross compile for given host triple.
  Because privilege escalation is very easy to achieve with Docker OMEdit adds
  ``--pull=never`` to the Docker calls for the ``multiarch/crossbuild`` images. Only use
  this option if you understand the security risks associated with Docker images from
  unknown sources.
  E.g. ``x86_64-linux-gnu docker run --pull=never multiarch/crossbuild`` to cross compile
  for a 64 bit Linux OS.
  Because system libraries can be different for different versions of the same operating
  system, it is advised to use :ref:`--fmuRuntimeDepends=all<omcflag-fmuRuntimeDepends>`.

Cross Compilation
~~~~~~~~~~~~~~~~~

Cross compilation can be done by using platform
``<cpu>-<vendor>-<os> docker run ghcr.io/openmodelica/crossbuild:v1.27.0``
or done manually. Both can be difficult at times.

To `cross compile with CMake <https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html>`_
provide a toolchain file specifying the target system and where to find the
compiler toolchain for the target system.

For example the Docker image
`ghcr.io/openmodelica/crossbuild:v1.27.0 <https://github.com/OpenModelica/openmodelica-crossbuild>`_
provided by OpenModelica is based on Linux (Ubuntu 24.04 at the time of writing)
and has toolchains installed to cross compile together with matching
`toolchain files <https://github.com/OpenModelica/openmodelica-crossbuild/tree/main/toolchain>`_.

Manual Cross Compilation
""""""""""""""""""""""""

Let's have a look at example model ``BouncingBall``:

First generate C sources for the FMU:

.. omc-mos ::
  :parsed:

  loadFile(getInstallationDirectoryPath() + "/share/doc/omc/testmodels/BouncingBall.mo")
  buildModelFMU(BouncingBall, platforms = {""})

OpenModelica won't zip the FMU in this case.
If you already have an existing FMU unzip it into some directory
``<Model>.fmutmp``. Optionally delete existing binaries like
``<Model>.fmutmp/binaries/linux64/``.

Then cross compile the sources with a suitable toolchain file.

.. code-block:: bash
  # Optional: Work inside interactive Docker container
  docker run --rm -it \
    -v $PWD:/fmu \
    -v /home/andreas/workdir/OM/OpenModelica/build_cmake/install_cmake/include/omc/FMI2:/fmiInclude \
    -w/fmu \
    ghcr.io/openmodelica/crossbuild:v1.27.0 bash

  cd <Model>.fmutmp/sources
  cmake -S . -B build \
    -DCMAKE_TOOLCHAIN_FILE=/opt/cmake/toolchain/x86_64-w64-mingw32.cmake \
    -DRUNTIME_DEPENDENCIES_LEVEL=none \
    -DFMI_INTERFACE_HEADER_FILES_DIRECTORY=/fmiInclude \
    -G "Unix Makefiles"
  cmake --build build --parallel --target install

Now the FMU should contain ``binaries/win64/BouncingBall.dll``.
Compile additional binaries in the same way and when done zip the FMU by running

.. code-block:: bash
  cmake --build build --parallel --target create_fmu

Now there should be a FMU with ``win64`` binaries ``BouncingBall-fmu``.

.. _fmi-import :

FMI Import - SSP
----------------

If you want to simulate a single, stand-alone FMU, or possibly a connection
of several FMUs, the recommended tool to do that is OMSimulator, see the
:ref:`OMSimulator documentation<omsimulator-documentation>` and
:ref:`omedit-graphical-modelling` for further information.

FMI Import - Non-Standard Modelica Model
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FMI Import allows to use an FMU, generated according to the FMI for Model
Exchange 2.0 standard, as a component in a Modelica model. This can be
useful if the FMU describes the behavior of a component or sub-system in a
structured Modelica model, which is not easily turned into a pure FMI-based
model that can be handled by OMSimulator.

FMI is a computational description of a dynamic model, while a Modelica model is
a declarative description; this means that not all conceivable FMUs can be successfully
imported as Modelica models. Also, the current implementation of FMU import in
OpenModelica is still somewhat experimental and not guaranteed to work in all
cases. However, if the FMU-ME you want to import was exported from a Modelica model
and only represents continuous time dynamic behavior, it should work without problems
when imported as a Modelica block.

Please also note that the current implementation of FMI Import in OpenModelica
is based on a built-in wrapper that uses a `reinit()` statement in an algorithm
section. This is not allowed by the Modelica Language Specification, so it is
necessary to set the compiler to accept this non-standard construct by setting
the :ref:`--allowNonStandardModelica=reinitInAlgorithms<omcflag-allowNonStandardModelica>`
compiler flag.
In OMEdit, you can set this option by activating the *Enable FMU Import* checkbox in the
*Tools | Options | Simulation | Translation Flags* tab. This will generate a warning during
compilation, as there is no guarantee that the imported model using this feature
can be ported to other Modelica tools; if you want to use a model that contains
imported FMUs in another Modelica tool, you should rely on the other tool's import
feature to generate the Modelica blocks corresponding to the FMUs.

After setting the :ref:`--allowNonStandardModelica<omcflag-allowNonStandardModelica>`
flag, to import the FMU package use the OpenModelica command importFMU,

.. omc-mos ::
  :parsed:

  list(OpenModelica.Scripting.importFMU, interfaceOnly=true);

The command could be used from command line interface, OMShell,
OMNotebook or MDT. The importFMU command is also integrated with OMEdit
through the `File > Import > FMU` dialog: the FMU package is extracted in the directory
specified by workdir, or in the current directory of omc if not specified, see
`Tools > Open Working Directory`.

The imported FMU is then loaded in the Libraries Browser and can be used as any
other regular Modelica block.

.. rubric:: Footnotes
.. [#f1] `Sundials Webpage <http://computation.llnl.gov/projects/sundials-suite-nonlinear-differential-algebraic-equation-solvers>`__
