Functional Mock-Up Objects¶
SMOL implements functional mock-up objects (FMOs), encapsulations of functional mock-up units (FMUs) as defined by the FMI standard, currently version 2.0.2. An FMO is a wrapper that integrates FMUs into the language; it is a special object with the inputs and outputs of an FMU as properties/fields and special statements that initialize and advance the wrapped FMU. An FMO is not an instance of a SMOL class, but its inputs and outputs define an FMO-type on which a subtyping relation is given.
Syntax¶
Syntactically, FMOs are treated as special objects with distinct FMO-types and a distinct expression for their instantiation.
Types¶
The type of an FMO contains the list of all its inputs and all its outputs.
Syntactically, an FMO-type has the following form: The keyword FMO,
followed by a comma-separated list of inputs and outputs enclosed in square
brackets.
TYPE ::= ... | 'FMO' '[' (FmuParam (',' FmuParam)* )? ']'
FmuParam ::= ('in' | 'out') TYPE NAME
Each input of the underlying FMO that is to be written must be declared via
in TYPE NAME, and every output that is to be read must be declared via
out TYPE NAME. NAME must be the name of an input or output variable,
respectively, as declared by the underlying FMU in its
modelDescription.xml file.
Types of input and output variables must be given as SMOL types. The following table shows the type names used by the FMI standard and how they translate to SMOL type names:
FMI 2.0.2 |
SMOL |
|---|---|
Real |
Double |
Boolean |
Boolean |
String |
String |
Integer |
Int |
The type of an FMO wrapping an FMU without any inputs and outputs is
FMO[].
FMO-types are covariant:
An FMO-type T = FMO[in Ti1 i1,... , out To1 o1...] is a subtype of another FMO-type S = FMO[in Sj1 j1,... , out Sp1 p1...]
if
each input
iofTis also an inputiofS, such that the type ofiinTis a subtype of the type ofiinS, andeach output
iofTis also an outputiofS, such that the type ofiinTis a subtype of the type ofiinS.
Statements¶
The simulate statement takes a path to an FMU and a list of variable initializers, which initialize the FMO.
The doStep statement targets an expression with an FMO-type and takes a Double typed expression as a parameter.
Statement ::= ... | (Type? NAME '=')? 'simulate' '(' STRING (',' VarInits)?')'
| Expression '.' 'doStep' '(' Expression ')'
VarInits ::= NAME '=' LITERAL (',' VarInits)?
The variable initializers must target inputs or parameters of the FMU and respect typing. The string parameter must be a path to an FMU with a model description for co-simulation. If the path is relative, then it must be relative to the directory where the SMOL runtime is run.
The following shows how an FMO is loaded and passed as a parameter.
class C(FMO[ out Int i] fmo) end
main
FMO[in Int j, out Int i] cont = simulate("path/to/fmu", j=1, k=1);
C c = new C(cont);
end
Semantics¶
The fields and methods of an FMO are auto-generated: there is one field for every input and one field for every output.
Assigning to a field that is an output
triggers at a compile-time error.
Reading a field that is an input
triggers a compile-time warning. [1]
Each such operation results in a call to fmi2SetXXX, resp. fmi2GetXXX, an FMO does not buffer read or written values itself.
Addtionally, each FMO has a field role of String type and a field offset of integer type, which play a role in their semantic lifting and is explained below.
These fields can be read and written and are not connected to the encapsulated FMU.
The doStep statement advances the encapsulated FMU by t time units. It results
in a call to doStep of the encapsulated FMU.
The following shows how an FMO is loaded and manipulated.
main
FMO[in Int j, out Int i] cont = simulate("path/to/fmu", j=1, k=1);
cont.role = "Example FMO";
cont.doStep(0.1);
Int v = cont.i;
cont.j = v+1;
end
Semantic Lifting¶
Note
Semantical lifting of FMOs is under development. Currently, they are completely omitted from the generated knowledge graph.
Footnotes