⚠️ Currently in development!
Liaison is an open-source tool designed to simplify the sharing of Functional Mock-up Units (FMUs) both within and between organizations. It addresses two specific challenges:
-
Platform and environment compatibility — when an FMU cannot be easily packaged to run across different operating systems (e.g. Linux, Windows) or when the target environment lacks required dependencies (e.g., MATLAB runtime).
-
Intellectual property protection — when there is resistance to sharing models directly due to concerns about revealing proprietary information.
To address these challenges, Liaison uses a client-server architecture with a two-step workflow:
- First, Liaison is used to generate a client FMU, called the LiaisonFMU, based on the original FMU. This LiaisonFMU is configured to communicate with a server via a Zenoh network at a predefined endpoint. It represents the original FMU but does not contain any of the original software or files besides the model description file.
- Second, Liaison is used to serve the original FMU at the predefined endpoint on a Zenoh network using a computer with the appropriate operating system and/or dependencies.
Zenoh acts as the communication layer, enabling seamless data exchange within and across networks, depending on its configuration. This approach allows FMUs to be used remotely without needing to share the original files, preserving intellectual property while enabling interoperability.
Liaison is inspired on FMU-proxy. The main difference between both softwares is that Liaison relies on Zenoh as the communication layer. Thanks to Zenoh’s peer-to-peer capabilities, the client FMU does not need to know the exact location of the FMU server — routing is handled automatically by the network. Another difference is that Liaison currently supports FMI 3.0.
To get started with Liaison, follow these steps:
Prerequesites
- Download the latest release.
- Install FMPy in your Python environment.
Note: FMPy is not a required dependency for Liaison; it is only used for testing. - Get an FMU according to FMI 3.0. You can use one of the reference FMUs provided by Modelica. We recommend
BouncingBall
.
Step 1: Create a "Liaison FMU"
Use the following command to create a Liaison FMU.
./liaison --make-fmu ./BouncingBall.fmu fmus/bouncingball
The result will be an FMU named BouncingBallLiaison.fmu
. Unlike the original FMU, this Liaison FMU does not include the original logic but retains the model description. It acts as a client, making all FMI function calls to the FMU being served at fmus/bouncingball
.
Step 2: Serve the original FMU
Start serving the original FMU at fmus/bouncingball
with the command:
./liaison --serve ../tests/BouncingBall.fmu fmus/bouncingball
Step 3: Use the "Liaison FMU" in a simulation
Use the Liaison FMU in a simulation with FMPy:
fmpy simulate BouncingBallLiaison.fmu --show-plot
With this setup, FMPy will simulate the FMU as if it were the original, but the underlying logic is now served by the original FMU, which can be hosted on another computer within the same local network (LAN) or in another network using a Zenoh router (see "Zenoh configuration" below.)
The flag --zenoh-config
can be used to provide a Zenoh configuration JSON file so that the Liasion FMU and the Liasion server connects to a Zenoh router.
./liaison --make-fmu ../BouncingBall.fmu fmus/bouncingball --zenoh-config ../config.json
./liaison --serve ../BouncingBall.fmu fmus/bouncingball --zenoh-config ../config.json
The following is an example of Zenoh configuration JSON file using TLS. Liaison will look for the certificates (i.e *.pem
files) in the locations specified in the configuration file.
{
"mode": "client",
"connect": {
"endpoints": ["tls/zenoh.foobar.com:443"]
},
"listen": {
"endpoints": ["tls/[::]:7447"]
},
"transport": {
"link": {
"tls": {
"root_ca_certificate": "./minica.pem",
"enable_mtls": true,
"connect_private_key": "./key.pem",
"connect_certificate": "./cert.pem"
}
}
}
}
The flag --debug
can be used so that the output is extra verbose to facilitate debbuging.
./liaison --serve ./tests/BouncingBall.fmu fmus/bouncingball --debug
If the FMU requires a Python environment, the Python environment (e.g. Conda or venv) needs to be declared by using the flag --python-env
. This is the case for FMUs built with PythonFMU3.
Examples
Conda
conda create -n bb
./liaison --serve <Python-based FMU> <responderId> --python-env /home/user/miniconda3/envs/bb
venv
python -m venv bb
./liaison --serve <Python-based FMU> <responderId> --python-env ./bb
This repository contains the necessary files for developing Liaison smoothly in VSCode. To do so, you must have the VSCode extension "DevContainers".
- Clone the repository.
- Open it in VSCode.
- Reopen the repository in a DevContainer.
- Build the targets.
FMI 3.0 functions stated below without any remarks are implemented.
Common Functions
fmi3GetVersion
fmi3SetDebugLogging
fmi3InstantiateModelExchange
fmi3InstantiateCoSimulation (partially implemented)
fmi3InstantiateScheduledExecution (partially implemented)
fmi3FreeInstance
fmi3EnterInitializationMode
fmi3ExitInitializationMode
fmi3EnterEventMode
fmi3Terminate
fmi3Reset
Get/Set Variable Values
fmi3GetFloat32, fmi3SetFloat32
fmi3GetFloat64, fmi3SetFloat64
fmi3GetInt8, fmi3SetInt8
fmi3GetUInt8, fmi3SetUInt8
fmi3GetInt16, fmi3SetInt16
fmi3GetUInt16, fmi3SetUInt16
fmi3GetInt32, fmi3SetInt32
fmi3GetUInt32, fmi3SetUInt32
fmi3GetInt64, fmi3SetInt64
fmi3GetUInt64, fmi3SetUInt64
fmi3GetBoolean, fmi3SetBoolean
fmi3GetString
fmi3SetString
fmi3GetBinary
fmi3SetBinary
fmi3GetClock
fmi3SetClock
Variable Dependency and FMU State
fmi3GetNumberOfVariableDependencies (NOT implemented)
fmi3GetVariableDependencies (NOT implemented)
fmi3GetFMUState (NOT implemented)
fmi3SetFMUState (NOT implemented)
fmi3FreeFMUState (NOT implemented)
fmi3SerializedFMUStateSize (NOT implemented)
fmi3SerializeFMUState (NOT implemented)
fmi3DeserializeFMUState (NOT implemented)
PGetting Partial Derivatives
fmi3GetDirectionalDerivative (NOT implemented)
fmi3GetAdjointDerivative (NOT implemented)
Configuration Mode
fmi3EnterConfigurationMode (NOT implemented)
fmi3ExitConfigurationMode (NOT implemented)
Clock Interval / Shift
fmi3GetIntervalDecimal (NOT implemented)
fmi3GetIntervalFraction (NOT implemented)
fmi3GetShiftDecimal (NOT implemented)
fmi3GetShiftFraction (NOT implemented)
fmi3SetIntervalDecimal (NOT implemented)
fmi3SetIntervalFraction (NOT implemented)
fmi3SetShiftDecimal (NOT implemented)
fmi3SetShiftFraction (NOT implemented)
Discrete States
fmi3EvaluateDiscreteStates (NOT implemented)
fmi3UpdateDiscreteStates (NOT implemented)
Model Exchange
fmi3EnterContinuousTimeMode (NOT implemented)
fmi3CompletedIntegratorStep (NOT implemented)
fmi3SetTime (NOT implemented)
fmi3SetContinuousStates (NOT implemented)
fmi3GetContinuousStateDerivatives (NOT implemented)
fmi3GetEventIndicators (NOT implemented)
fmi3GetContinuousStates (NOT implemented)
fmi3GetNominalsOfContinuousStates (NOT implemented)
fmi3GetNumberOfEventIndicators (NOT implemented)
fmi3GetNumberOfContinuousStates (NOT implemented)
Co-Simulation
fmi3DoStep
fmi3EnterStepMode (NOT implemented)
fmi3GetOutputDerivatives (NOT implemented)
Scheduled Execution
fmi3ActivateModelPartition (NOT implemented)