Importing implementations must pass valid values into the following instantiation calls for all of their arguments:
-
FMI 3.0:
fmi3InstantiateModelExchange
,fmi3InstantiateCoSimulation
, andfmi3InstantiateScheduledExecution
-
FMI 2.0:
fmi2Instantiate
-
FMI 1.0:
fmiInstantiate
,fmiInstantiateSlave
Note especially that null pointers are not valid for any of the string arguments to these functions, unless explicitly allowed in the respective standard. Implementations must pass proper values especially for the following fields:
-
instanceName
must not be the null pointer, the empty string or a string only containing whitespace. -
instantiationToken
(3.0),fmuGUID
(2.0), andGUID
(1.0) must match the value of theinstantiationToken
(3.0) andguid
(2.0/1.0) attribute from the modelDescription.xml file, respectively. -
For FMI 3.0,
resourcePath
must be a valid native path to the FMU’sresources
directory. If an FMU has noresources
directory or if no such path can be provided due to implementation restrictions theresourcePath
argument must be a null pointer. -
For FMI 2.0/1.0
fmuResourceLocation
/fmuLocation/
must be a valid URI (per RFC 3986), and should be a URI with thefile
scheme, since that is currently the only scheme that is required to be supported by the FMU. Note that the description of this in the FMI 1.0 standards is very unclear and confusing, so that in practice, until a proper cleanup version of the 1.0 standard is released, as far as valid URIs are concerned the implementation should follow the spirit of the rules as laid out in the FMI 2.0 standard for the fmuResourceLocation argument, but pointing to the root of the unpacked FMU archive rather than the resources directory. Note also thatfile://C:/
and similar are not valid file URIs, but should rather be supplied as eitherfile:///C:/
(empty authority) or asfile:/C:/
(missing authority) to be valid URIs. Furthermore the validity of a URI is not influenced by the existence or non-existence of the file/directory pointed to, so that in the case of FMI 2.0, a URI pointing to the resources directory would still be a valid URI, even if the unpacked FMU archive did not contain a resources directory. -
mimeType
(FMI 1.0 only) must not be null and must be a valid MIME type; unless specific requirements indicate otherwise,application/x-fmu-sharedlibrary
is the proper string to pass here.
If an importer tries to create a second instance of an FMU where the capability flag canBeInstantiatedOnlyOncePerProcess
is true, the FMU should provide an error message and return NULL
.
Exporting implementations should guard (by safely handling these cases without crashing) against common errors in calls to the instantiation functions, including:
-
instanceName
,GUID
/fmuGUID
/instantiationToken
,fmuLocation
/fmuResourceLocation
andmimeType
might all be null pointers or empty strings, or otherwise invalid, -
GUID
/fmuGUID
/instantationToken
is possibly not theguid
/instantiationToken
attribute from the model description, but something else entirely (i.e. neither the guid attribute from this version of the FMU nor from a former version), -
Especially under FMI 1.0
fmuLocation
is very likely not pointing to the right location (either pointing to the resources directory, or the root directory of the unzipped FMU, to the zipped FMU, or to a different directory entirely), or is an invalid URI (e.g.file://C:/something
or the empty string) or of an unknown scheme. This of course makes resource-loading difficult. For Model Exchange FMUs (which are not passed anfmuLocation
argument in any case) and for Co-Simulation FMUs (which often get these kinds of illegal/unclear URIs) as a fallback mechanism, it is recommended to load resources from paths derived from the location of the SharedObject/DLL for platforms that support this: On Win32 for example this can be achieved through the use ofGetModuleFileName
with themodule_handle
of the DLL (as provided in aDllMain
argument), or viadladdr
on a known symbol in the FMU on OS X or Linux and similar ELF-based systems. Note that this kind of mechanism should only be used as a fallback, iffmuLocation
is not provided (ME FMUs) or is invalid in some way.
When performing initialization of variable values, including parameters and initial values for other variables, importers should not rely on default values being already set in the FMU (i.e. burned into the binary so to speak):
While the FMI standards specify that default values shall both be specified in the modelDescription.xml
file and are already set in the FMU upon instantiation, some implementations generate FMUs where this is not true, i.e. the default values of variables when not set do not match the values as specified in the modelDescription.xml
file.
Since there is little effort in actually setting default values through the FMI API at initialization time, the more conservative approach is to always set default values through the API based on the modelDescription.xml
file, or on the actual parameter/initial values as specified by the user, not relying on any burned-in default values.
Exporting implementations must ensure that any default values specified for variables in the modelDescription.xml
file are actually “burned-in”:
The values shall be set automatically as default values upon FMU instantiation, so that importing implementations can rely on the standard-mandated behavior that unset variables have their default values as specified in the modelDescription.xml
.
Note that for all start values, especially the mandatory start values for input and parameter variables, it is the responsibility of the FMU — and hence the exporter or the user of the exporter — to provide suitable start values: An importer should be able to rely on these start values, i.e. it is always at liberty to use them unchanged, if no better start values are available to the importer.
If an FMU provides start values that e.g. result in a division-by-zero or some other error inside the FMU if unchanged, these are obviously not suitable start values, and should not have been selected.
Importers should however be aware of the existence of such FMUs, which can easily result from negligence during creation of an FMU: Importers should, if more suitable start values are available, set them at the earliest permissible point in time, to avoid uneccesarily triggering such errors in the FMU. For FMI 2.0/3.0, for example, different start values for inputs and parameters can and should already be set after instantiation, prior to entering initialization mode.
Importers should respect the different order of necessary function calls between FMI 1.0 and FMI 2.0/3.0 when performing initialization (this phase has seen larger changes between FMI 1.0 and 2.0/3.0 due to the introduction of explicit phases/modes in the FMI API, whereas these phases where only implicit in FMI 1.0).
For FMI 1.0 Co-Simulation FMUs importing implementations should honor the canHandleEvents
capability of the FMU: If this capability flag is false, then the implementation cannot call the doStep
function with zero communicationStepSize
, even at time 0 (used e.g. for generating valid initial values).
In these cases the integration environment must start simulation with the first simulation step, without any event iteration.
With FMI 2.0 Co-Simulation FMUs do not support 0-size time steps in any case.
With FMI 3.0, Co-Simulation FMUs can support event handling explicitly via the hasEventMode
capability flag.
Importers can make use of this feature by passing fmi3True
for the eventModeUsed
argument of the fmi3InstantiateCoSimulation
call.
Importing implementations should support a wide variety of solver algorithms, in order to support Model-Exchange FMUs as fully as possible. Ideally this should include support for attaching external solvers through specified APIs, so that experienced users can extend the supported solver base for specific new domains where appropriate. Supporting the use of several different solvers in one model that integrates a number of FMUs, so that e.g. different Model Exchange FMUs can be solved through different solvers than other parts of the model – without resorting to Co-Simulation FMUs – can be beneficial in terms of performance and usability.
In any case the proper documentation of the employed solver algorithms and their configurable settings is very beneficial in understanding and handling differences between implementations.
Exporting implementations should offer all of their built-in solver algorithms (including solver settings like step-size, tolerance, etc.) for export when generating Co-Simulation FMUs, so that the same solvers can be used inside the environment as in exported FMUs. This should ideally also include the ability to export Co-Simulation FMUs using user-supplied solvers, where appropriate (e.g. where the environment supports the integration of external solvers for model evaluation).
Importing implementations should support mixing FMUs of different types (and different FMI versions) in one simulation model, ensuring proper semantics for connections between those FMUs and each other as well as the rest of the simulation model. This should also be checked in cross-checking with other implementations.
As a side issue, importing implementations should try to use as much of the fine-grained direct dependency information potentially present in FMI 1.0 (and even more so in FMI 2.0/3.0) as possible, in order to avoid algorithmic loops being detected where they are not really present.
Importing implementations should allow fine-grained selection of FMU logging output recording/display, either based on the new FMU-defined logging categories for FMI 2.0/3.0 or on the raw string category argument of the logging callback in FMI 1.0.
Note that since the logging callback type signature in FMI 1.0 and 2.0 uses a variable argument list, this can have implications for the calling convention of that function on platforms that have different calling conventions for C functions with variable argument lists than for functions with fixed argument lists.
Starting with FMI 3.0, the logging callback uses a fixed argument list.
Exporting implementations should support the fine-grained selection of logging categories in FMI 2.0/3.0 and should use fine-grained category names in the category argument for FMI 1.0 logging callback calls.
In FMI 1.0 they should try to not produce verbose logging output when the debug logging flag is fmiFalse
.
FMI 2.0/3.0 provide comprehensive information about the structure of a model encapsulated as an FMU, as defined in the element ModelStructure
of the modelDescription.xml
.
This element defines the dependencies between variables, both during initialization as well as at runtime, which may differ.
The following examples demonstrate in more detail how this information can be understood and used.
An FMU is defined by the following equations:
where \({u_{1}}\) is a continuous-time input (variability
= continuous
), \({u_{2}}\) is any type of input, \({u_{3}}\) is a floating-point discrete-time input (variability
= discrete
), and \({p}\) is a fixed parameter (variability
= fixed
).
The initialization is defined by:
and therefore, the initialization equations are:
The model structure for this equation system can be defined as:
<ModelVariables>
<Float64 name="p" valueReference= "1" causality="parameter" variability="fixed" start="0"/>
<Float64 name="u1" valueReference= "2" causality="input" start="0"/>
<Float64 name="u2" valueReference= "3" causality="input" start="0"/>
<Float64 name="u3" valueReference= "4" causality="input" variability="discrete" start="0"/>
<Float64 name="x1" valueReference= "5"/>
<Float64 name="x2" valueReference= "6"/>
<Float64 name="x3" valueReference= "7"/>
<Float64 name="der(x1)" valueReference= "8" derivative="5"/>
<Float64 name="der(x2)" valueReference= "9" derivative="6"/>
<Float64 name="der(x3)" valueReference="10" derivative="7"/>
<Float64 name="y" valueReference="11" causality="output"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="11" dependencies="6 7"/>
<ContinuousStateDerivative valueReference="8" dependencies="6"/>
<ContinuousStateDerivative valueReference="9" dependencies="2 4 5 6" dependenciesKind="constant constant dependent fixed"/>
<ContinuousStateDerivative valueReference="10" dependencies="2 3 4 5 6" />
<InitialUnknown valueReference="6" dependencies="2 4 5"/>
<InitialUnknown valueReference="7" dependencies="2 4 5 11"/>
<InitialUnknown valueReference="8"/>
<InitialUnknown valueReference="10"/>
<InitialUnknown valueReference="11"/>
</ModelStructure>
An FMU is defined by the following equation:
where \({u}\) is a continuous-time input with valueReference
= 1
and \({y}\) is a continuous-time output with valueReference
= 2
.
The definition of the model structure is then:
<ModelVariables>
<Float64 name="u" valueReference= "1" causality="input" start="1"/>
<Float64 name="y" valueReference= "2" causality="output"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="2" dependencies="1" dependenciesKind="discrete"/>
<InitialUnknown valueReference="2"/>
</ModelStructure>
Note that \({y = d \cdot u}\) where \({d}\) changes only during event mode (\({d = 2 \cdot u}\) or \({3 \cdot u\ }\) depending on relation \({u > 0}\) that changes only at event mode).
Therefore dependenciesKind
= discrete
.
An FMU is defined by the following equation:
where \({u}\) is a continuous-time input with valueReference
= 1
and \({y}\) is a continuous-time output with valueReference
= 2
.
The definition of the model structure is then:
<ModelVariables>
<Float64 name="u" valueReference= "1" causality="input" start="1"/>
<Float64 name="y" valueReference= "2" causality="output"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="2" dependencies="1" dependenciesKind="dependent"/>
<InitialUnknown valueReference="2"/>
</ModelStructure>
Note that \({y = c}\) where \({c}\) changes only during event mode (\({c = 2}\) or \({3\ }\) depending on relation \({u > 0}\) that changes only at event mode).
Therefore dependenciesKind
= dependent
because it is not a linear relationship on \({u}\).
An FMU is defined by the following equations:
where \({u}\) is a continuous-time input with valueReference
= 1
, \({y}\) is a continuous-time output with valueReference
= 2
and \({dxdt}\) is a continuous-time derivative with valueReference
= 4
.
The definition of the model structure is then:
<ModelVariables>
<Float64 name="u" valueReference= "1" causality="input" start="0"/>
<Float64 name="y" valueReference= "2" causality="output"/>
<Float64 name="x" valueReference= "3"/>
<Float64 name="dxdt" valueReference= "4"/>
</ModelVariables>
<ModelStructure>
<Output valueReference="2" dependencies="3" dependenciesKind="constant"/>
<ContinuousStateDerivative valueReference="4" dependencies="1" dependenciesKind="constant"/>
<InitialUnknown valueReference="2" dependencies="3"/>
</ModelStructure>