FMI 3.0 & FMPy Cheatsheet

Functional Mock-up Interface · Co-Simulation · Model Exchange

FMI 3.0 FMPy (Python) Intermediate Level 🔗 Run the examples yourself

Learn more about FMI 3.0 and FMPy in the Learn Modelica & FMI newsletter on LinkedIn or visit the dedicated website.

1. FMI 3.0 Overview

The Functional Mock-up Interface (FMI) is an open standard for exchanging simulation models as Functional Mock-up Units (FMUs). An FMU is a zip file containing a model description (XML) and compiled binaries (or C source) that any FMI-compatible tool can import and simulate.

FMI 3.0 — What's New vs. 2.0

FeatureFMI 2.0FMI 3.0
Interface typesCo-Simulation, Model Exchange+ Scheduled Execution (limited tool support — see footnote*)
Data typesReal, Integer, Boolean, String, Enumeration+ NEW Float32, Int8/16/(32)/64, UInt8/16/32/64, Binary, Clock
Array variables❌ Not supported✅ First-class support for arrays
Clocks✅ Synchronous clocks for CS and ME (hybrid co-simulation)
Terminals & iconsBackported to FMI 2.0.x✅ Structured grouping of variables into bus-like terminals
Layered standardsBackported to FMI 2.0.x✅ Extensibility via layered standard concept
Build configuration Back ported to FMI 2.0.4✅ Source code FMUs with build instructions
Early return (CS)🟠 Limited support✅ FMU can return before communication step ends
Intermediate update (CS)✅ FMU can report intermediate values during a step
Event handling (CS)✅ Explicit event mode in CS (not just ME)
Adjoint derivatives❌ (only directional)NEW Adjoint derivatives for optimization / sensitivity analysis
Variable naming<ScalarVariable>Type-specific: <Float64>, <Int32>, <Binary>, etc.
Model descriptionfmiVersion="2.0"fmiVersion="3.0"

Three Interface Types

CS Co-Simulation

The FMU contains its own solver. A master algorithm just tells it "advance by Δt" and reads outputs. Simplest to use — ideal for coupling models from different tools.

ME Model Exchange

The FMU provides equations only (derivatives, event indicators). An external solver integrates the ODEs. More control, potentially more accurate — but the importing tool must provide a suitable solver.

🔍 Which One to Use?
  • CS — Default choice. Tool coupling. Black-box simulation. Also supports clocks & events in FMI 3.0 (hybrid co-simulation) — suitable for SiL, vECU, and most discrete-time use cases.
  • ME — Tight integration of an external model in a simulation tool. Custom solvers, stiff systems, or variable-step integration.
⚠️ *About Scheduled Execution (SE)

FMI 3.0 also defines a Scheduled Execution interface for clock-driven, real-time systems (HiL, RTOS). However, there is practically no tool support for SE at this time, including FMPy. For most use cases — including SiL, vECU testing, and multi-rate systems — CS FMUs with clocks (hybrid co-simulation) are the recommended approach. SE is therefore omitted from this cheatsheet.

Note: Clocks in CS/ME (synchronous clocks, similar to Modelica clocks) are different from the partition-based clocks in SE.

FMU Lifecycle — State Machine (Simplified)

Instantiated
Configuration
Mode
Initialization
Mode
Event Mode
Step Mode
(CS)
Terminated
ME also has: Event Mode ⇄ Continuous-Time Mode (where solver calls getDerivatives)
🔍 FMI 3.0 State Transitions

Key rule: You can only call certain FMI functions in certain states. For example, you can only set parameters in Configuration Mode or Initialization Mode, and you can only call fmi3DoStep in Step Mode (CS).

FMPy handles state transitions automatically when you use its high-level simulate_fmu() function.

2. FMU Anatomy & modelDescription.xml

FMU File Structure

An FMU is a zip file (renamed to .fmu) with a standardized internal layout:

myModel.fmu (zip archive)
├── modelDescription.xml  ← The "contract" — all variable info, capabilities, metadata
├── binaries/
│   ├── x86_64-windows/
│   │   └── myModel.dll  ← Compiled shared library (platform-specific)
│   ├── x86_64-linux/
│   │   └── myModel.so
│   └── aarch64-darwin/
│      └── myModel.dylib
├── sources/  ← Optional: C source code (for source-code FMUs)
│   ├── myModel.c
│   └── buildDescription.xml  ← FMI 3.0: build instructions
├── resources/  ← Data files, tables, maps needed by the model
│   └── data.csv
├── documentation/  ← Optional: HTML docs, images
│   └── index.html
└── terminalsAndIcons/  ← FMI 3.0: model icons (SVG/PNG)
    └── icon.svg
⚠️ Platform Binaries

FMI 3.0 uses consistent platform tuples: {arch}-{os} (e.g., x86_64-linux, aarch64-darwin). FMI 2.0 used different names (linux64, darwin64). An FMU only works on platforms for which it has binaries (or sources).

modelDescription.xml — Key Elements

Root Element

<fmiModelDescription
  fmiVersion="3.0"
  modelName="HeatExchanger"
  instantiationToken="{8c4e810f-...}"  <!-- was 'guid' in FMI 2.0 -->
  description="Counter-flow heat exchanger model"
  generationTool="MyTool 4.2">

  <CoSimulation modelIdentifier="HeatExchanger"
    canHandleVariableCommunicationStepSize="true"
    canReturnEarlyAfterIntermediateUpdate="true" />  <!-- capabilities -->

  <!-- and/or: <ModelExchange .../>, <ScheduledExecution .../> -->

Variable Declarations (FMI 3.0 — Typed Elements)

<ModelVariables>
  <Float64 name="T_inlet" valueReference="1"
    causality="input" start="293.15"
    description="Inlet temperature [K]" />

  <Float64 name="T_outlet" valueReference="2"
    causality="output"
    description="Outlet temperature [K]" />

  <Float64 name="k" valueReference="3"
    causality="parameter" variability="fixed"
    start="500.0" description="Heat transfer coeff [W/(m²K)]" />

  <!-- FMI 3.0: Array variable -->
  <Float64 name="T_profile" valueReference="10"
    causality="output">
    <Dimension start="20" />  <!-- array of 20 elements -->
  </Float64>

  <!-- FMI 3.0: Clock variable -->
  <Clock name="samplingClock" valueReference="100"
    causality="input" intervalVariability="fixed"
    intervalDecimal="0.01" />
</ModelVariables>

Causality × Variability

CausalityMeaningAllowed Variability
parameterSet before simulation, constant during runfixed, tunable
calculatedParameterComputed from parameters only during init for fixed and re-computed during simulation when tunablefixed, tunable
inputSet by the environment (master) during simulationdiscrete, continuous
outputComputed by the FMU, readable by the environmentconstant, discrete, continuous
localInternal variable, not for external useany
independentThe independent variable (usually time)continuous
structuralParameter3.0 Affects model structure (e.g., array sizes)fixed, tunable

Inspecting an FMU with FMPy

from fmpy import read_model_description, dump

# Quick summary of FMU contents
dump('HeatExchanger.fmu')

# Detailed programmatic access
md = read_model_description('HeatExchanger.fmu')
print(f"Model: {md.modelName}, FMI: {md.fmiVersion}")
print(f"GUID: {md.guid}")
print(f"CS: {md.coSimulation is not None}")
print(f"ME: {md.modelExchange is not None}")

# List all variables
for var in md.modelVariables:
    print(f"  {var.name:30s}  causality={var.causality:20s}  start={var.start}")

# Filter inputs and outputs
inputs  = [v for v in md.modelVariables if v.causality == 'input']
outputs = [v for v in md.modelVariables if v.causality == 'output']
params  = [v for v in md.modelVariables if v.causality == 'parameter']

3. Co-Simulation (CS) CS

How It Works

In Co-Simulation, the FMU contains its own ODE/DAE solver. The master algorithm:

  1. Sets inputs at the current communication point
  2. Tells the FMU to advance by stepSize
  3. Reads outputs at the new communication point
  4. Repeats until tEnd
Set Inputs
fmi3DoStep(Δt)
Get Outputs
Repeat

FMPy — Quick Simulation (High-Level API)

from fmpy import simulate_fmu
from fmpy.util import plot_result

# Simplest possible simulation
result = simulate_fmu(
    'HeatExchanger.fmu',
    stop_time=10.0,
    output_interval=0.01
)
plot_result(result)

# With parameters and input signals
result = simulate_fmu(
    'HeatExchanger.fmu',
    stop_time=100.0,
    step_size=0.1,            # communication step size
    output_interval=0.1,       # output recording interval
    start_values={
        'k': 750.0,              # parameter override
        'T_inlet': 350.0,        # initial input value
    },
    output=['T_outlet', 'Q_flow'],  # variables to record
)

# Access results (structured NumPy array)
time = result['time']
T_out = result['T_outlet']

Providing Input Signals

import numpy as np

# Option 1: NumPy structured array
dtype = np.dtype([('time', np.float64), ('T_inlet', np.float64)])
input_signals = np.array([
    (0.0,  293.15),
    (10.0, 293.15),
    (10.0, 350.00),   # step change at t=10
    (50.0, 350.00),
    (50.0, 320.00),   # step change at t=50
    (100.0, 320.00),
], dtype=dtype)

result = simulate_fmu(
    'HeatExchanger.fmu',
    stop_time=100.0,
    input=input_signals,       # FMPy interpolates between points
    output=['T_outlet'],
)

# Option 2: Read from CSV file
from fmpy.util import read_csv
input_signals = read_csv('inputs.csv')   # columns: time, T_inlet, ...

FMPy — Low-Level API (Full Control)

from fmpy import read_model_description, extract
from fmpy.fmi3 import FMU3Slave

md = read_model_description('HeatExchanger.fmu')
unzipdir = extract('HeatExchanger.fmu')

fmu = FMU3Slave(
    instanceName='instance1',
    unzipDirectory=unzipdir,
    modelIdentifier=md.coSimulation.modelIdentifier,
)

# Lifecycle: Instantiate → Configure → Initialize → Step → Terminate → Free
fmu.instantiate()
fmu.enterInitializationMode()
fmu.setFloat64([3], [750.0])   # set parameter k (valueReference=3)
fmu.exitInitializationMode()

# Simulation loop
time, step_size = 0.0, 0.1
while time < 10.0:
    fmu.setFloat64([1], [350.0])   # set input T_inlet
    fmu.doStep(
        currentCommunicationPoint=time,
        communicationStepSize=step_size
    )
    T_out = fmu.getFloat64([2])     # get output T_outlet
    print(f"t={time:.1f}  T_out={T_out[0]:.2f}")
    time += step_size

fmu.terminate()
fmu.freeInstance()

FMI 3.0 CS Additions

3.0 Early Return

The FMU can return from doStep before the full step is completed (e.g., because an event occurred). The master reads the actual time reached and adjusts.

Capability flag: canReturnEarlyAfterIntermediateUpdate

3.0 Intermediate Update

During doStep, the FMU can call back to the master to report intermediate values or request input updates. Enables tighter coupling without reducing the communication step.

Capability flag: providesIntermediateUpdate

3.0 Event Mode

In FMI 3.0, CS FMUs can enter Event Mode (via fmi3EnterEventMode) to handle discrete events during simulation — triggered by early return or when eventHandlingNeeded is set after doStep.

3.0 Clocks

FMI 3.0 introduces synchronous clocks for CS, enabling hybrid co-simulation with discrete-time and multi-rate behavior — without needing Scheduled Execution.

✅ CS Best Practices
  • Step size: Start with the output interval. If results are inaccurate, reduce step size (not output interval).
  • Variable step: If the FMU supports canHandleVariableCommunicationStepSize, adapt step size to dynamics.
  • Multiple FMUs: Use Gauss-Seidel ordering (set outputs of FMU1 as inputs to FMU2, then advance both).
  • Events: In FMI 3.0, check eventHandlingNeeded after doStep and enter Event Mode if true.
  • Co-simulation error: Compared to a monolithic simulation, co-simulation introduces a certain coupling error. The importer can influence/reduce this by choosing the right co-simulation algorithm — e.g., the order of get/set calls, inter-/extrapolation of values passed between FMUs, and iterating until reaching convergence.

4. Model Exchange (ME) ME

How It Works

The FMU provides the model equations — derivatives, algebraic outputs, event indicators. An external ODE solver (provided by the master / tool) drives the integration.

Set Inputs
& States
Get
Derivatives
ODE Solver
Step
Set New
States
Repeat

ME vs CS — When to Use Which

AspectCS Co-SimulationME Model Exchange
SolverSuitable solver bundled with modelYou provide it (or FMPy provides one)
Interface complexity⭐ Much simpler API⭐⭐⭐ More complex (states, events, derivatives)
Step size controlCommunication points onlyFull control (variable-step)
AccuracyLimited by communication stepSolver-controlled (error-based)
Coupled simulationEasy (each FMU is self-contained)Requires combined state vector
Stiff systemsFMU's internal solver handles itYou must use an implicit solver
Ease of use⭐⭐⭐ Simple⭐⭐ More complex
Best forTool coupling, black-box modelsCustom integration, accuracy-critical

FMPy — Model Exchange Simulation

from fmpy import simulate_fmu

# FMPy automatically uses CVode solver for ME
result = simulate_fmu(
    'HeatExchanger.fmu',
    fmi_type='ModelExchange',     # default is 'CoSimulation'
    stop_time=10.0,
    output_interval=0.01,
    solver='CVode',                # CVode (default), Euler
    start_values={'k': 750.0},
    output=['T_outlet'],
)

Low-Level ME API (Manual Solver Loop)

from fmpy.fmi3 import FMU3ModelExchange

# ... (instantiate, extract as before)
fmu = FMU3ModelExchange(...)
fmu.instantiate()
fmu.enterInitializationMode()
fmu.exitInitializationMode()
fmu.enterContinuousTimeMode()

# Get initial states
n_states = md.numberOfContinuousStates
n_events = md.numberOfEventIndicators
x = fmu.getContinuousStates()

# Simple forward Euler (for illustration — use CVode in practice!)
time, dt = 0.0, 1e-3
while time < 10.0:
    fmu.setTime(time)
    fmu.setContinuousStates(x)

    # Check for events
    event_indicators = fmu.getEventIndicators()

    # Get derivatives: dx/dt = f(x, u, t)
    dx = fmu.getDerivatives()

    # Euler step
    x = [x[i] + dt * dx[i] for i in range(n_states)]
    time += dt

fmu.terminate()
fmu.freeInstance()
⚠️ ME Event Handling

In Model Exchange, you must handle state events (zero-crossings of event indicators) and time events (reported by getNextEventTime). When an event occurs:

  1. Enter Event Mode: fmu.enterEventMode()
  2. Call fmu.updateDiscreteStates() until newDiscreteStatesNeeded = false
  3. Re-enter Continuous-Time Mode: fmu.enterContinuousTimeMode()
  4. Get new states: x = fmu.getContinuousStates()

FMPy's simulate_fmu() handles all of this automatically.

5. FMPy Practical Reference FMPy

Installation

# Install FMPy as tool
uv tool install fmpy[complete]

# In virtual environment
# Minimal dependencies install of FMPy
uv add fmpy

# With optional dependencies (plotting, GUI)
uv add fmpy[complete]

# Verify installation
python -c "import fmpy; print(fmpy.__version__)"

# Command-line tools
fmpy --help
fmpy info HeatExchanger.fmu      # dump model description
fmpy validate HeatExchanger.fmu  # check FMU compliance
fmpy simulate HeatExchanger.fmu  # run from command line
fmpy gui                         # launch graphical interface

Key Functions

FunctionPurposeReturns
fmpy.dump(fmu_path)Print FMU summary to consoleNone (prints)
fmpy.read_model_description(fmu_path)Parse modelDescription.xmlModelDescription object
fmpy.simulate_fmu(fmu_path, ...)High-level simulation (CS or ME)NumPy structured array
fmpy.extract(fmu_path)Extract FMU zip to temp dirPath to extracted directory
fmpy.instantiate_fmu(unzipdir, md, fmi_type)Create FMU instance for low-level APIFMU instance object
fmpy.util.plot_result(result)Plot simulation resultsPlotly figure
fmpy.util.read_csv(path)Read input signal CSVNumPy structured array
fmpy.util.write_csv(path, result)Write results to CSVNone
fmpy.validation.validate_fmu(fmu_path)Validate FMU complianceList of issues

simulate_fmu() — Full Parameter Reference

result = simulate_fmu(
    filename,                     # path to .fmu file
    fmi_type='CoSimulation',      # 'CoSimulation' or 'ModelExchange'
    start_time=0.0,              # simulation start time
    stop_time=1.0,               # simulation end time
    step_size=None,              # CS communication step (None = auto)
    output_interval=None,        # recording interval (None = step_size)
    solver='CVode',              # ME solver: 'CVode' or 'Euler'
    relative_tolerance=None,     # solver tolerance (ME)
    start_values={},             # dict: variable_name → value
    input=None,                  # input signals (NumPy array or CSV path)
    output=None,                 # list of variable names to record (None = all)
    timeout=None,                # max simulation time in seconds
    fmu_instance=None,           # re-use existing FMU instance
    validate=True,               # validate FMU before simulation
    debug_logging=False,         # enable FMU debug output
    set_input_derivatives=False, # enable input interpolation (CS)
)

Batch Simulation / Parameter Sweeps

import numpy as np
import matplotlib.pyplot as plt
from fmpy import simulate_fmu

# Parameter sweep over heat transfer coefficient
k_values = [100, 500, 1000, 2000, 5000]
results = {}

for k in k_values:
    results[k] = simulate_fmu(
        'HeatExchanger.fmu',
        stop_time=60.0,
        start_values={'k': k},
        output=['T_outlet'],
    )

# Plot comparison
fig, ax = plt.subplots()
for k, r in results.items():
    ax.plot(r['time'], r['T_outlet'], label=f'k={k}')
ax.legend(); ax.set_xlabel('Time [s]'); ax.set_ylabel('T_outlet [K]')
plt.show()

Saving & Loading Results

from fmpy.util import write_csv, read_csv
import pandas as pd

# Save to CSV
write_csv('results.csv', result)

# Or convert to pandas DataFrame for analysis
df = pd.DataFrame(result)
df.to_csv('results.csv', index=False)

# Load back
df = pd.read_csv('results.csv')

FMPy GUI

🔍 FMPy Graphical Interface

FMPy includes a Qt-based GUI for interactive FMU exploration:

You can inspect variables, configure a run, and view the resulting plot in one place.

  • fmpy gui — launch empty GUI, open FMU via File menu
  • fmpy gui HeatExchanger.fmu — open specific FMU directly
  • Features: variable browser, parameter editing, simulation, result plotting
  • Requires: pip install fmpy[complete] (installs PyQt)
  • Limitation: only supports one FMU at a time
FMPy GUI showing model information, variables, and simulation settings
Open an FMU, browse variables, and configure the simulation.
FMPy GUI showing a simulation result plot
Select a variable to plot and inspect the result directly in the GUI.

Containers — Nested / Composite FMUs

📦 FMPy Containers (Nested FMUs)

FMPy supports containers — packaging multiple FMUs into a single composite FMU. This allows you to:

  • Combine several FMUs into one redistributable .fmu file
  • Define internal connections between sub-FMUs
  • Expose selected inputs/outputs to the outside
  • Simplify deployment — ship one FMU instead of many

Create a container FMU via the FMPy GUI or programmatically. See fmpy.container module and FMPy documentation for details.

6. Troubleshooting & Best Practices

Debugging Decision Tree

📋 What kind of FMU problem do you have?
A FMU won't load / import
→ Check platform: does the FMU contain binaries for your OS+arch? (unzip and check binaries/)
→ Validate: fmpy validate model.fmu — reports structural issues
→ Check FMI version: are you using FMI 2.0 API for a 3.0 FMU or vice versa?
→ Missing dependencies: the FMU's DLL/SO may need external libraries (check with ldd / otool -L / Dependency Walker)
B Initialization fails
→ Set all required start values via start_values={...}
→ Check that input variables have values before initialization
→ Enable debug logging: simulate_fmu(..., debug_logging=True)
→ Check parameter ranges — values outside the model's valid domain cause init failure
C Simulation crashes or gives wrong results
→ Reduce step size: step_size=1e-4 (CS) or tighten relative_tolerance (ME)
→ Check input signal timing: are step changes aligned with communication points?
→ Enable input derivatives: set_input_derivatives=True for smoother interpolation
→ Try ME instead of CS (or vice versa) to isolate solver vs. model issues
D Performance is poor
→ Increase step size (CS): largest step that gives acceptable accuracy
→ Reduce output variables: output=['var1', 'var2'] instead of recording everything
→ Increase output interval: output_interval=0.1 (less disk I/O)
→ For batch runs: reuse FMU instance with fmu_instance= parameter
E Cross-platform issues
→ Check that the FMU has binaries for your target: x86_64-linux, x86_64-windows, aarch64-darwin (Apple Silicon)
→ For source-code FMUs: compile locally with fmpy compile model.fmu
→ Watch for path separators: FMU resource paths should use /, not \

Common Error Messages

ErrorCauseFix
"No binary for platform..." FMU lacks binary for your OS/architecture Request FMU with correct platform; or use source-code FMU and compile
"fmi3EnterInitializationMode failed" Missing required start values or invalid parameter ranges Set all inputs/parameters via start_values; check valid ranges
"fmi3DoStep returned Error" Internal solver failure during step Reduce step size; check input continuity; enable debug logging
"fmi3DoStep returned Discard" FMU rejected the step (e.g., step too large) Reduce step size; handle early return; retry with smaller step
"Illegal call sequence" API function called in wrong state (e.g., doStep before init) Follow correct lifecycle: instantiate → configure → init → step → terminate
"Cannot set variable in this mode" Trying to set a parameter after initialization Set parameters before exitInitializationMode(); tunable params only in Event Mode
"Unsupported FMI version" Tool/library doesn't support the FMU's FMI version Update FMPy (pip install --upgrade fmpy); check FMI version compatibility
ImportError: DLL load failed Missing C runtime or dependency DLLs Install Visual C++ Redistributable (Windows); check ldd output (Linux)

Best Practices

✅ Do
  • Always validate FMUs before first use: fmpy validate
  • Set explicit start_values for all parameters — don't rely on defaults
  • Use dump() to understand an unfamiliar FMU before simulating
  • Start with large step sizes, then refine until results converge
  • Save results to CSV for post-processing with pandas/Excel
  • Test with a short simulation before running long sweeps
  • Pin FMPy version in requirements.txt for reproducibility
❌ Don't
  • Don't assume FMI 2.0 and 3.0 FMUs are interchangeable (different API)
  • Don't use explicit Euler for stiff ME models (use CVode)
  • Don't set inputs/parameters in the wrong lifecycle state
  • Don't ignore Discard return status from doStep — it means the step failed
  • Don't hard-code valueReference numbers — look them up from model description
  • Don't forget to call terminate() and freeInstance() in low-level API
  • Don't extract FMUs to shared temp dirs — use unique directories per instance

7. Quick-Reference Tables

FMI 3.0 API Functions Overview

FunctionCSMEPurpose
fmi3InstantiateCoSimulationCreate CS instance
fmi3InstantiateModelExchangeCreate ME instance
fmi3EnterInitializationModeEnter init mode (set params/inputs)
fmi3ExitInitializationModeExit init mode → ready to simulate
fmi3EnterEventModeHandle events
fmi3EnterContinuousTimeModeResume continuous integration (ME)
fmi3EnterStepModeResume stepping (CS, after event)
fmi3SetFloat64 / getFloat64Set/get variable values
fmi3DoStepAdvance CS simulation by Δt
fmi3SetTimeSet current time (ME)
fmi3SetContinuousStatesSet state vector (ME)
fmi3GetContinuousStatesGet state vector (ME)
fmi3GetDerivativesGet dx/dt (ME)
fmi3GetEventIndicatorsGet zero-crossing functions (ME)
fmi3UpdateDiscreteStatesProcess events, update discrete vars
fmi3GetClock / fmi3SetClockGet/set clock states (hybrid co-sim)
fmi3TerminateEnd simulation
fmi3FreeInstanceRelease memory
fmi3GetFMUState / fmi3SetFMUStateSave/restore FMU state (checkpoint)
fmi3SerializeFMUStateSerialize state to byte array
fmi3GetDirectionalDerivativePartial derivatives (Jacobian elements)
fmi3GetAdjointDerivative3.0 Adjoint derivatives (for optimization)

FMI 3.0 Data Types

XML ElementC TypePython (NumPy)Notes
<Float64>fmi3Float64np.float64Main numeric type (was Real in FMI 2.0)
<Float32>fmi3Float32np.float323.0 Single precision
<Int64>fmi3Int64np.int643.0
<Int32>fmi3Int32np.int32Was Integer in FMI 2.0
<Int16> / <Int8>fmi3Int16 / fmi3Int8np.int16 / np.int83.0
<UInt64> ... <UInt8>fmi3UInt*np.uint*3.0 Unsigned variants
<Boolean>fmi3Booleannp.bool_
<String>fmi3Stringstr
<Binary>fmi3Binarybytes3.0 Raw byte data
<Enumeration>fmi3Int64np.int64Maps to integer values
<Clock>fmi3Clocknp.bool_3.0 Synchronous clocks

FMI 3.0 Status Codes

StatusValueMeaningAction
fmi3OK0SuccessContinue normally
fmi3Warning1Success, but something is not idealContinue; check log for details
fmi3Discard2Operation not fully completed (CS: step rejected)Reduce step size; retry; check lastSuccessfulTime
fmi3Error3Recoverable errorCan try to recover (e.g., reset); check log
fmi3Fatal4Unrecoverable error — FMU is in invalid stateMust call freeInstance(); cannot continue

Variable Causality × Variability (Valid Combinations)

constant fixed tunable discrete continuous
parameter
calculatedParameter
input
output
local
independent
structuralParameter 3.0

FMPy Command-Line Reference

CommandPurposeExample
fmpy info <fmu>Display model description summaryfmpy info Boiler.fmu
fmpy validate <fmu>Validate FMU compliancefmpy validate Boiler.fmu
fmpy simulate <fmu>Simulate and plot resultsfmpy simulate Boiler.fmu --stop-time 10
fmpy gui [fmu]Launch graphical interfacefmpy gui Boiler.fmu
fmpy compile <fmu>Compile source-code FMU for current platformfmpy compile Boiler.fmu
fmpy create-cmake-project <fmu>Generate CMake project from source FMUfmpy create-cmake-project Boiler.fmu
fmpy create-jupyter-notebook <fmu>Generate Jupyter notebook for FMUfmpy create-jupyter-notebook Boiler.fmu

Useful Links

ResourceURL
FMI Standard (official)https://fmi-standard.org
FMI 3.0 Specificationhttps://fmi-standard.org/docs/3.0/
FMPy Documentationhttps://fmpy.readthedocs.io
FMPy GitHubhttps://github.com/CATIA-Systems/FMPy
FMU validation helperhttps://fmi-standard.org/validation/
Reference FMUs (test models)https://github.com/modelica/Reference-FMUs

Dr. Clément Coïc
FMI 3.0 & FMPy Cheatsheet · Version 1.0 · April 2026
Covers: Co-Simulation · Model Exchange · FMPy Python API
Standard: FMI 3.0 · Tool: FMPy · Intermediate level
Scheduled Execution (SE) omitted — no practical tool support yet; use CS with clocks instead.
Print tip: Use Ctrl+P / Cmd+P → Save as PDF for offline reference