In this page
fmi
Load and run FMI Functional Mock-up Units
(.fmu) from GCL, built on top of FMI4C.
The library loads an FMU, exposes its model description, and drives a Co-Simulation (instantiate → initialize → step → read/write variables → terminate). FMI 1.0, 2.0 and 3.0 are all supported through one version-agnostic API: the FMU’s FMI version is detected at load time and every call routes to the matching implementation internally.
@library("fmi", "0.0.0");
Quick start
var fmu = Fmu::load("model.fmu", "inst");
var sim = fmu.instantiate(false);
sim.setup(0.0, 10.0, 0.0); // startTime, stopTime, tolerance (0 => undefined)
sim.enterInitialization();
// set parameters / initial inputs here, e.g. sim.setReal(6, 0.7);
sim.exitInitialization();
var t = 0.0;
var dt = 0.01;
while (t < 10.0) {
sim.doStep(t, dt);
t = t + dt;
var height = sim.getReal(1); // read an output by its value reference
info("t=${t} h=${height}");
}
sim.terminate();
Loading and inspecting an FMU
Fmu::load(path, instanceName) unzips and parses the FMU. The unzip happens
in-process, so no external unzip tool is required. It throws a runtime error if
the file cannot be loaded.
var fmu = Fmu::load("model.fmu", "inst");
fmu.version(); // FmiVersion::fmi1 | fmi2 | fmi3
fmu.modelName(); // String
fmu.modelIdentifier(); // String (co-simulation binary base name)
fmu.guid(); // String (FMI3: the instantiation token)
fmu.variableCount(); // int
fmu.variables(); // Array<FmuVariable>
Each FmuVariable is a plain snapshot object of the model-description entry:
type FmuVariable {
name: String;
valueReference: int; // the handle used by get*/set* below
causality: FmiCausality; // input | output | parameter | ...
variability: FmiVariability; // constant | fixed | tunable | discrete | continuous
dataType: FmiDataType; // real | integer | boolean | string | ...
}
Variables are addressed by their integer value reference, which you read from
variables(). Use it with the get*/set* methods below.
Running a co-simulation
Fmu::instantiate(loggingOn) creates a Co-Simulation instance. Passing
loggingOn = true forwards the FMU’s own debug logging to the GreyCat logger
(visible with --log=trace). The instance keeps its parent Fmu alive, so the
Fmu may go out of scope while a FmuInstance is still in use.
Initialization is a three-phase sequence mirroring the FMI standard. Set
parameters and initial inputs between enterInitialization and
exitInitialization:
var sim = fmu.instantiate(false);
sim.setup(0.0, 10.0, 1e-6); // startTime, stopTime, tolerance
sim.enterInitialization();
sim.setReal(6, 0.7); // e.g. set a parameter
sim.exitInitialization();
setup(startTime, stopTime, tolerance)—tolerance <= 0means “tolerance undefined”;stopTime <= startTimemeans “stop time undefined”.doStep(currentTime, stepSize)— advance the simulation by one communication step. Returns anFmiStatus.terminate()— end the simulation.
Every stepping/IO method returns an FmiStatus (ok, warning, discard,
error, fatal, pending). A production loop should check it:
if (sim.doStep(t, dt) != FmiStatus::ok) {
// handle discard / error
}
Reading and writing variables
Scalar accessors take a value reference; the setters return an FmiStatus:
var h = sim.getReal(1); // float
sim.setReal(6, 0.7); // FmiStatus
sim.getInt(vr); sim.setInt(vr, 3);
sim.getBool(vr); sim.setBool(vr, true);
sim.getString(vr); sim.setString(vr, "text");
Batch accessors read or write several variables in one call. For reads the result has one entry per value reference, in order; for writes the two arrays must be the same length:
var vals = sim.getRealArray(Array<int> { 1, 3 }); // Array<float>
sim.setRealArray(Array<int> { 1, 3 }, Array<float> { 1.0, 0.0 });
sim.getIntArray(vrs); sim.setIntArray(vrs, values);
sim.getBoolArray(vrs); sim.setBoolArray(vrs, values);
sim.getStringArray(vrs); sim.setStringArray(vrs, values);
For FMI 3 FMUs, getReal/getInt (and their array forms) automatically dispatch
on each variable’s declared width — a getReal works whether the variable is
Float32 or Float64, and a getInt works for any of the Int8…Int64 /
UInt8…UInt64 types, widening the result to a GCL int. Note that a UInt64
value above int range is truncated.
Version differences handled for you
| concept | FMI 1 | FMI 2 | FMI 3 |
|---|---|---|---|
| initialize | initializeSlave on exit |
setupExperiment + enter/exit |
enter/exit initialization |
| step | fmi1_doStep |
fmi2_doStep |
fmi3_doStep |
| real type | Real |
Real |
Float64/Float32 |
| integer type | Integer |
Integer |
Int8…UInt64 |
The same GCL calls work across all three; the differences above are applied internally based on the loaded FMU’s version.
Scope
- Co-Simulation only. Model Exchange (bring-your-own solver) is not exposed.
- FMU state save/restore, derivatives, and event handling are not exposed.