Files
openvehicle-api/sdv_executables/sdv_dbc_util/fmu_fmi_templates.h
tompzf 6ed4b1534e Precommit (#1)
* first commit

* cleanup
2025-11-04 13:28:06 +01:00

2513 lines
88 KiB
C

/**
* @brief CoSimulation header template. File 'cosimulation.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szCosimulationHeaderTemplate[] = R"code(#pragma once
#include "model.h"
#define EPSILON (FIXED_SOLVER_STEP * 1e-6)
void doFixedStep(ModelInstance *comp, bool* stateEvent, bool* timeEvent);
)code";
/**
* @brief Part one of FMI2 function header template. Due to the size split into 2 strings.
* File 'fmi2Functions.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFMI2FunctionsHeaderTemplate1[] = R"code(#ifndef fmi2Functions_h
#define fmi2Functions_h
/* This header file must be utilized when compiling a FMU.
It defines all functions of the
FMI 2.0.1 Model Exchange and Co-Simulation Interface.
In order to have unique function names even if several FMUs
are compiled together (e.g. for embedded systems), every "real" function name
is constructed by prepending the function name by "FMI2_FUNCTION_PREFIX".
Therefore, the typical usage is:
#define FMI2_FUNCTION_PREFIX MyModel_
#include "fmi2Functions.h"
As a result, a function that is defined as "fmi2GetDerivatives" in this header file,
is actually getting the name "MyModel_fmi2GetDerivatives".
This only holds if the FMU is shipped in C source code, or is compiled in a
static link library. For FMUs compiled in a DLL/sharedObject, the "actual" function
names are used and "FMI2_FUNCTION_PREFIX" must not be defined.
Revisions:
- Sep. 29, 2019: License changed to 2-clause BSD License (without extensions)
- Apr. 9, 2014: All prefixes "fmi" renamed to "fmi2" (decision from April 8)
- Mar. 26, 2014: FMI_Export set to empty value if FMI_Export and FMI_FUNCTION_PREFIX
are not defined (#173)
- Oct. 11, 2013: Functions of ModelExchange and CoSimulation merged:
fmiInstantiateModel , fmiInstantiateSlave -> fmiInstantiate
fmiFreeModelInstance, fmiFreeSlaveInstance -> fmiFreeInstance
fmiEnterModelInitializationMode, fmiEnterSlaveInitializationMode -> fmiEnterInitializationMode
fmiExitModelInitializationMode , fmiExitSlaveInitializationMode -> fmiExitInitializationMode
fmiTerminateModel, fmiTerminateSlave -> fmiTerminate
fmiResetSlave -> fmiReset (now also for ModelExchange and not only for CoSimulation)
Functions renamed:
fmiUpdateDiscreteStates -> fmiNewDiscreteStates
- June 13, 2013: Functions removed:
fmiInitializeModel
fmiEventUpdate
fmiCompletedEventIteration
fmiInitializeSlave
Functions added:
fmiEnterModelInitializationMode
fmiExitModelInitializationMode
fmiEnterEventMode
fmiUpdateDiscreteStates
fmiEnterContinuousTimeMode
fmiEnterSlaveInitializationMode;
fmiExitSlaveInitializationMode;
- Feb. 17, 2013: Portability improvements:
o DllExport changed to FMI_Export
o FUNCTION_PREFIX changed to FMI_FUNCTION_PREFIX
o Allow undefined FMI_FUNCTION_PREFIX (meaning no prefix is used)
Changed function name "fmiTerminate" to "fmiTerminateModel" (due to #113)
Changed function name "fmiGetNominalContinuousState" to
"fmiGetNominalsOfContinuousStates"
Removed fmiGetStateValueReferences.
- Nov. 14, 2011: Adapted to FMI 2.0:
o Split into two files (fmiFunctions.h, fmiTypes.h) in order
that code that dynamically loads an FMU can directly
utilize the header files).
o Added C++ encapsulation of C-part, in order that the header
file can be directly utilized in C++ code.
o fmiCallbackFunctions is passed as pointer to fmiInstantiateXXX
o stepFinished within fmiCallbackFunctions has as first
argument "fmiComponentEnvironment" and not "fmiComponent".
o New functions to get and set the complete FMU state
and to compute partial derivatives.
- Nov. 4, 2010: Adapted to specification text:
o fmiGetModelTypesPlatform renamed to fmiGetTypesPlatform
o fmiInstantiateSlave: Argument GUID replaced by fmuGUID
Argument mimetype replaced by mimeType
o tabs replaced by spaces
- Oct. 16, 2010: Functions for FMI for Co-simulation added
- Jan. 20, 2010: stateValueReferencesChanged added to struct fmiEventInfo (ticket #27)
(by M. Otter, DLR)
Added WIN32 pragma to define the struct layout (ticket #34)
(by J. Mauss, QTronic)
- Jan. 4, 2010: Removed argument intermediateResults from fmiInitialize
Renamed macro fmiGetModelFunctionsVersion to fmiGetVersion
Renamed macro fmiModelFunctionsVersion to fmiVersion
Replaced fmiModel by fmiComponent in decl of fmiInstantiateModel
(by J. Mauss, QTronic)
- Dec. 17, 2009: Changed extension "me" to "fmi" (by Martin Otter, DLR).
- Dez. 14, 2009: Added eventInfo to meInitialize and added
meGetNominalContinuousStates (by Martin Otter, DLR)
- Sept. 9, 2009: Added DllExport (according to Peter Nilsson's suggestion)
(by A. Junghanns, QTronic)
- Sept. 9, 2009: Changes according to FMI-meeting on July 21:
meInquireModelTypesVersion -> meGetModelTypesPlatform
meInquireModelFunctionsVersion -> meGetModelFunctionsVersion
meSetStates -> meSetContinuousStates
meGetStates -> meGetContinuousStates
removal of meInitializeModelClass
removal of meGetTime
change of arguments of meInstantiateModel
change of arguments of meCompletedIntegratorStep
(by Martin Otter, DLR):
- July 19, 2009: Added "me" as prefix to file names (by Martin Otter, DLR).
- March 2, 2009: Changed function definitions according to the last design
meeting with additional improvements (by Martin Otter, DLR).
- Dec. 3 , 2008: First version by Martin Otter (DLR) and Hans Olsson (Dynasim).
Copyright (C) 2008-2011 MODELISAR consortium,
2012-2019 Modelica Association Project "FMI"
All rights reserved.
This file is licensed by the copyright holders under the 2-Clause BSD License
(https://opensource.org/licenses/BSD-2-Clause):
----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "fmi2TypesPlatform.h"
#include "fmi2FunctionTypes.h"
#include <stdlib.h>
/*
Export FMI2 API functions on Windows and under GCC.
If custom linking is desired then the FMI2_Export must be
defined before including this file. For instance,
it may be set to __declspec(dllimport).
*/
#if !defined(FMI2_Export)
#if !defined(FMI2_FUNCTION_PREFIX)
#if defined _WIN32 || defined __CYGWIN__
/* Note: both gcc & MSVC on Windows support this syntax. */
#define FMI2_Export __declspec(dllexport)
#else
#if __GNUC__ >= 4
#define FMI2_Export __attribute__ ((visibility ("default")))
#else
#define FMI2_Export
#endif
#endif
#else
#define FMI2_Export
#endif
#endif
/* Macros to construct the real function name
(prepend function name by FMI2_FUNCTION_PREFIX) */
#if defined(FMI2_FUNCTION_PREFIX)
#define fmi2Paste(a,b) a ## b
#define fmi2PasteB(a,b) fmi2Paste(a,b)
#define fmi2FullName(name) fmi2PasteB(FMI2_FUNCTION_PREFIX, name)
#else
#define fmi2FullName(name) name
#endif
)code";
/**
* @brief Part two of FMI2 function header template. Due to the size split into 2 strings.
* File 'fmi2Functions.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFMI2FunctionsHeaderTemplate2[] = R"code(
/***************************************************
Common Functions
****************************************************/
#define fmi2GetTypesPlatform fmi2FullName(fmi2GetTypesPlatform)
#define fmi2GetVersion fmi2FullName(fmi2GetVersion)
#define fmi2SetDebugLogging fmi2FullName(fmi2SetDebugLogging)
#define fmi2Instantiate fmi2FullName(fmi2Instantiate)
#define fmi2FreeInstance fmi2FullName(fmi2FreeInstance)
#define fmi2SetupExperiment fmi2FullName(fmi2SetupExperiment)
#define fmi2EnterInitializationMode fmi2FullName(fmi2EnterInitializationMode)
#define fmi2ExitInitializationMode fmi2FullName(fmi2ExitInitializationMode)
#define fmi2Terminate fmi2FullName(fmi2Terminate)
#define fmi2Reset fmi2FullName(fmi2Reset)
#define fmi2GetReal fmi2FullName(fmi2GetReal)
#define fmi2GetInteger fmi2FullName(fmi2GetInteger)
#define fmi2GetBoolean fmi2FullName(fmi2GetBoolean)
#define fmi2GetString fmi2FullName(fmi2GetString)
#define fmi2SetReal fmi2FullName(fmi2SetReal)
#define fmi2SetInteger fmi2FullName(fmi2SetInteger)
#define fmi2SetBoolean fmi2FullName(fmi2SetBoolean)
#define fmi2SetString fmi2FullName(fmi2SetString)
#define fmi2GetFMUstate fmi2FullName(fmi2GetFMUstate)
#define fmi2SetFMUstate fmi2FullName(fmi2SetFMUstate)
#define fmi2FreeFMUstate fmi2FullName(fmi2FreeFMUstate)
#define fmi2SerializedFMUstateSize fmi2FullName(fmi2SerializedFMUstateSize)
#define fmi2SerializeFMUstate fmi2FullName(fmi2SerializeFMUstate)
#define fmi2DeSerializeFMUstate fmi2FullName(fmi2DeSerializeFMUstate)
#define fmi2GetDirectionalDerivative fmi2FullName(fmi2GetDirectionalDerivative)
/***************************************************
Functions for FMI2 for Model Exchange
****************************************************/
#define fmi2EnterEventMode fmi2FullName(fmi2EnterEventMode)
#define fmi2NewDiscreteStates fmi2FullName(fmi2NewDiscreteStates)
#define fmi2EnterContinuousTimeMode fmi2FullName(fmi2EnterContinuousTimeMode)
#define fmi2CompletedIntegratorStep fmi2FullName(fmi2CompletedIntegratorStep)
#define fmi2SetTime fmi2FullName(fmi2SetTime)
#define fmi2SetContinuousStates fmi2FullName(fmi2SetContinuousStates)
#define fmi2GetDerivatives fmi2FullName(fmi2GetDerivatives)
#define fmi2GetEventIndicators fmi2FullName(fmi2GetEventIndicators)
#define fmi2GetContinuousStates fmi2FullName(fmi2GetContinuousStates)
#define fmi2GetNominalsOfContinuousStates fmi2FullName(fmi2GetNominalsOfContinuousStates)
/***************************************************
Functions for FMI2 for Co-Simulation
****************************************************/
#define fmi2SetRealInputDerivatives fmi2FullName(fmi2SetRealInputDerivatives)
#define fmi2GetRealOutputDerivatives fmi2FullName(fmi2GetRealOutputDerivatives)
#define fmi2DoStep fmi2FullName(fmi2DoStep)
#define fmi2CancelStep fmi2FullName(fmi2CancelStep)
#define fmi2GetStatus fmi2FullName(fmi2GetStatus)
#define fmi2GetRealStatus fmi2FullName(fmi2GetRealStatus)
#define fmi2GetIntegerStatus fmi2FullName(fmi2GetIntegerStatus)
#define fmi2GetBooleanStatus fmi2FullName(fmi2GetBooleanStatus)
#define fmi2GetStringStatus fmi2FullName(fmi2GetStringStatus)
/* Version number */
#define fmi2Version "2.0"
/***************************************************
Common Functions
****************************************************/
/* Inquire version numbers of header files */
FMI2_Export fmi2GetTypesPlatformTYPE fmi2GetTypesPlatform;
FMI2_Export fmi2GetVersionTYPE fmi2GetVersion;
FMI2_Export fmi2SetDebugLoggingTYPE fmi2SetDebugLogging;
/* Creation and destruction of FMU instances */
FMI2_Export fmi2InstantiateTYPE fmi2Instantiate;
FMI2_Export fmi2FreeInstanceTYPE fmi2FreeInstance;
/* Enter and exit initialization mode, terminate and reset */
FMI2_Export fmi2SetupExperimentTYPE fmi2SetupExperiment;
FMI2_Export fmi2EnterInitializationModeTYPE fmi2EnterInitializationMode;
FMI2_Export fmi2ExitInitializationModeTYPE fmi2ExitInitializationMode;
FMI2_Export fmi2TerminateTYPE fmi2Terminate;
FMI2_Export fmi2ResetTYPE fmi2Reset;
/* Getting and setting variables values */
FMI2_Export fmi2GetRealTYPE fmi2GetReal;
FMI2_Export fmi2GetIntegerTYPE fmi2GetInteger;
FMI2_Export fmi2GetBooleanTYPE fmi2GetBoolean;
FMI2_Export fmi2GetStringTYPE fmi2GetString;
FMI2_Export fmi2SetRealTYPE fmi2SetReal;
FMI2_Export fmi2SetIntegerTYPE fmi2SetInteger;
FMI2_Export fmi2SetBooleanTYPE fmi2SetBoolean;
FMI2_Export fmi2SetStringTYPE fmi2SetString;
/* Getting and setting the internal FMU state */
FMI2_Export fmi2GetFMUstateTYPE fmi2GetFMUstate;
FMI2_Export fmi2SetFMUstateTYPE fmi2SetFMUstate;
FMI2_Export fmi2FreeFMUstateTYPE fmi2FreeFMUstate;
FMI2_Export fmi2SerializedFMUstateSizeTYPE fmi2SerializedFMUstateSize;
FMI2_Export fmi2SerializeFMUstateTYPE fmi2SerializeFMUstate;
FMI2_Export fmi2DeSerializeFMUstateTYPE fmi2DeSerializeFMUstate;
/* Getting partial derivatives */
FMI2_Export fmi2GetDirectionalDerivativeTYPE fmi2GetDirectionalDerivative;
/***************************************************
Functions for FMI2 for Model Exchange
****************************************************/
/* Enter and exit the different modes */
FMI2_Export fmi2EnterEventModeTYPE fmi2EnterEventMode;
FMI2_Export fmi2NewDiscreteStatesTYPE fmi2NewDiscreteStates;
FMI2_Export fmi2EnterContinuousTimeModeTYPE fmi2EnterContinuousTimeMode;
FMI2_Export fmi2CompletedIntegratorStepTYPE fmi2CompletedIntegratorStep;
/* Providing independent variables and re-initialization of caching */
FMI2_Export fmi2SetTimeTYPE fmi2SetTime;
FMI2_Export fmi2SetContinuousStatesTYPE fmi2SetContinuousStates;
/* Evaluation of the model equations */
FMI2_Export fmi2GetDerivativesTYPE fmi2GetDerivatives;
FMI2_Export fmi2GetEventIndicatorsTYPE fmi2GetEventIndicators;
FMI2_Export fmi2GetContinuousStatesTYPE fmi2GetContinuousStates;
FMI2_Export fmi2GetNominalsOfContinuousStatesTYPE fmi2GetNominalsOfContinuousStates;
/***************************************************
Functions for FMI2 for Co-Simulation
****************************************************/
/* Simulating the slave */
FMI2_Export fmi2SetRealInputDerivativesTYPE fmi2SetRealInputDerivatives;
FMI2_Export fmi2GetRealOutputDerivativesTYPE fmi2GetRealOutputDerivatives;
FMI2_Export fmi2DoStepTYPE fmi2DoStep;
FMI2_Export fmi2CancelStepTYPE fmi2CancelStep;
/* Inquire slave status */
FMI2_Export fmi2GetStatusTYPE fmi2GetStatus;
FMI2_Export fmi2GetRealStatusTYPE fmi2GetRealStatus;
FMI2_Export fmi2GetIntegerStatusTYPE fmi2GetIntegerStatus;
FMI2_Export fmi2GetBooleanStatusTYPE fmi2GetBooleanStatus;
FMI2_Export fmi2GetStringStatusTYPE fmi2GetStringStatus;
#ifdef __cplusplus
} /* end of extern "C" { */
#endif
#endif /* fmi2Functions_h */
)code";
/**
* @brief FMI2 Function Type header template. File 'fmi2FunctionTypes.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFMI2FunctionTypesHeaderTemplate[] = R"code(#ifndef fmi2FunctionTypes_h
#define fmi2FunctionTypes_h
#include "fmi2TypesPlatform.h"
/* This header file must be utilized when compiling an FMU or an FMI master.
It declares data and function types for FMI 2.0.1
Revisions:
- Sep. 30, 2019: License changed to 2-clause BSD License (without extensions)
- Jul. 5, 2019: Remove const modifier from fields of fmi2CallbackFunctions (#216)
- Sep. 6, 2018: Parameter names added to function prototypes
- Apr. 9, 2014: all prefixes "fmi" renamed to "fmi2" (decision from April 8)
- Apr. 3, 2014: Added #include <stddef.h> for size_t definition
- Mar. 27, 2014: Added #include "fmiTypesPlatform.h" (#179)
- Mar. 26, 2014: Introduced function argument "void" for the functions (#171)
fmiGetTypesPlatformTYPE and fmiGetVersionTYPE
- Oct. 11, 2013: Functions of ModelExchange and CoSimulation merged:
fmiInstantiateModelTYPE , fmiInstantiateSlaveTYPE -> fmiInstantiateTYPE
fmiFreeModelInstanceTYPE, fmiFreeSlaveInstanceTYPE -> fmiFreeInstanceTYPE
fmiEnterModelInitializationModeTYPE, fmiEnterSlaveInitializationModeTYPE -> fmiEnterInitializationModeTYPE
fmiExitModelInitializationModeTYPE , fmiExitSlaveInitializationModeTYPE -> fmiExitInitializationModeTYPE
fmiTerminateModelTYPE , fmiTerminateSlaveTYPE -> fmiTerminate
fmiResetSlave -> fmiReset (now also for ModelExchange and not only for CoSimulation)
Functions renamed
fmiUpdateDiscreteStatesTYPE -> fmiNewDiscreteStatesTYPE
Renamed elements of the enumeration fmiEventInfo
upcomingTimeEvent -> nextEventTimeDefined // due to generic naming scheme: varDefined + var
newUpdateDiscreteStatesNeeded -> newDiscreteStatesNeeded;
- June 13, 2013: Changed type fmiEventInfo
Functions removed:
fmiInitializeModelTYPE
fmiEventUpdateTYPE
fmiCompletedEventIterationTYPE
fmiInitializeSlaveTYPE
Functions added:
fmiEnterModelInitializationModeTYPE
fmiExitModelInitializationModeTYPE
fmiEnterEventModeTYPE
fmiUpdateDiscreteStatesTYPE
fmiEnterContinuousTimeModeTYPE
fmiEnterSlaveInitializationModeTYPE;
fmiExitSlaveInitializationModeTYPE;
- Feb. 17, 2013: Added third argument to fmiCompletedIntegratorStepTYPE
Changed function name "fmiTerminateType" to "fmiTerminateModelType" (due to #113)
Changed function name "fmiGetNominalContinuousStateTYPE" to
"fmiGetNominalsOfContinuousStatesTYPE"
Removed fmiGetStateValueReferencesTYPE.
- Nov. 14, 2011: First public Version
Copyright (C) 2008-2011 MODELISAR consortium,
2012-2019 Modelica Association Project "FMI"
All rights reserved.
This file is licensed by the copyright holders under the 2-Clause BSD License
(https://opensource.org/licenses/BSD-2-Clause):
----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
*/
#ifdef __cplusplus
extern "C" {
#endif
/* make sure all compiler use the same alignment policies for structures */
#if defined _MSC_VER || defined __GNUC__
#pragma pack(push,8)
#endif
/* Include stddef.h, in order that size_t etc. is defined */
#include <stddef.h>
/* Type definitions */
typedef enum {
fmi2OK,
fmi2Warning,
fmi2Discard,
fmi2Error,
fmi2Fatal,
fmi2Pending
} fmi2Status;
typedef enum {
fmi2ModelExchange,
fmi2CoSimulation
} fmi2Type;
typedef enum {
fmi2DoStepStatus,
fmi2PendingStatus,
fmi2LastSuccessfulTime,
fmi2Terminated
} fmi2StatusKind;
typedef void (*fmi2CallbackLogger) (fmi2ComponentEnvironment componentEnvironment,
fmi2String instanceName,
fmi2Status status,
fmi2String category,
fmi2String message,
...);
typedef void* (*fmi2CallbackAllocateMemory)(size_t nobj, size_t size);
typedef void (*fmi2CallbackFreeMemory) (void* obj);
typedef void (*fmi2StepFinished) (fmi2ComponentEnvironment componentEnvironment,
fmi2Status status);
typedef struct {
fmi2CallbackLogger logger;
fmi2CallbackAllocateMemory allocateMemory;
fmi2CallbackFreeMemory freeMemory;
fmi2StepFinished stepFinished;
fmi2ComponentEnvironment componentEnvironment;
} fmi2CallbackFunctions;
typedef struct {
fmi2Boolean newDiscreteStatesNeeded;
fmi2Boolean terminateSimulation;
fmi2Boolean nominalsOfContinuousStatesChanged;
fmi2Boolean valuesOfContinuousStatesChanged;
fmi2Boolean nextEventTimeDefined;
fmi2Real nextEventTime;
} fmi2EventInfo;
/* reset alignment policy to the one set before reading this file */
#if defined _MSC_VER || defined __GNUC__
#pragma pack(pop)
#endif
/* Define fmi2 function pointer types to simplify dynamic loading */
/***************************************************
Types for Common Functions
****************************************************/
/* Inquire version numbers of header files and setting logging status */
typedef const char* fmi2GetTypesPlatformTYPE(void);
typedef const char* fmi2GetVersionTYPE(void);
typedef fmi2Status fmi2SetDebugLoggingTYPE(fmi2Component c,
fmi2Boolean loggingOn,
size_t nCategories,
const fmi2String categories[]);
/* Creation and destruction of FMU instances and setting debug status */
typedef fmi2Component fmi2InstantiateTYPE(fmi2String instanceName,
fmi2Type fmuType,
fmi2String fmuGUID,
fmi2String fmuResourceLocation,
const fmi2CallbackFunctions* functions,
fmi2Boolean visible,
fmi2Boolean loggingOn);
typedef void fmi2FreeInstanceTYPE(fmi2Component c);
/* Enter and exit initialization mode, terminate and reset */
typedef fmi2Status fmi2SetupExperimentTYPE (fmi2Component c,
fmi2Boolean toleranceDefined,
fmi2Real tolerance,
fmi2Real startTime,
fmi2Boolean stopTimeDefined,
fmi2Real stopTime);
typedef fmi2Status fmi2EnterInitializationModeTYPE(fmi2Component c);
typedef fmi2Status fmi2ExitInitializationModeTYPE (fmi2Component c);
typedef fmi2Status fmi2TerminateTYPE (fmi2Component c);
typedef fmi2Status fmi2ResetTYPE (fmi2Component c);
/* Getting and setting variable values */
typedef fmi2Status fmi2GetRealTYPE (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]);
typedef fmi2Status fmi2GetIntegerTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]);
typedef fmi2Status fmi2GetBooleanTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]);
typedef fmi2Status fmi2GetStringTYPE (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]);
typedef fmi2Status fmi2SetRealTYPE (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]);
typedef fmi2Status fmi2SetIntegerTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]);
typedef fmi2Status fmi2SetBooleanTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]);
typedef fmi2Status fmi2SetStringTYPE (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]);
/* Getting and setting the internal FMU state */
typedef fmi2Status fmi2GetFMUstateTYPE (fmi2Component c, fmi2FMUstate* FMUstate);
typedef fmi2Status fmi2SetFMUstateTYPE (fmi2Component c, fmi2FMUstate FMUstate);
typedef fmi2Status fmi2FreeFMUstateTYPE (fmi2Component c, fmi2FMUstate* FMUstate);
typedef fmi2Status fmi2SerializedFMUstateSizeTYPE(fmi2Component c, fmi2FMUstate FMUstate, size_t* size);
typedef fmi2Status fmi2SerializeFMUstateTYPE (fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte[], size_t size);
typedef fmi2Status fmi2DeSerializeFMUstateTYPE (fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate* FMUstate);
/* Getting partial derivatives */
typedef fmi2Status fmi2GetDirectionalDerivativeTYPE(fmi2Component c,
const fmi2ValueReference vUnknown_ref[], size_t nUnknown,
const fmi2ValueReference vKnown_ref[], size_t nKnown,
const fmi2Real dvKnown[],
fmi2Real dvUnknown[]);
/***************************************************
Types for Functions for FMI2 for Model Exchange
****************************************************/
/* Enter and exit the different modes */
typedef fmi2Status fmi2EnterEventModeTYPE (fmi2Component c);
typedef fmi2Status fmi2NewDiscreteStatesTYPE (fmi2Component c, fmi2EventInfo* fmi2eventInfo);
typedef fmi2Status fmi2EnterContinuousTimeModeTYPE(fmi2Component c);
typedef fmi2Status fmi2CompletedIntegratorStepTYPE(fmi2Component c,
fmi2Boolean noSetFMUStatePriorToCurrentPoint,
fmi2Boolean* enterEventMode,
fmi2Boolean* terminateSimulation);
/* Providing independent variables and re-initialization of caching */
typedef fmi2Status fmi2SetTimeTYPE (fmi2Component c, fmi2Real time);
typedef fmi2Status fmi2SetContinuousStatesTYPE(fmi2Component c, const fmi2Real x[], size_t nx);
/* Evaluation of the model equations */
typedef fmi2Status fmi2GetDerivativesTYPE (fmi2Component c, fmi2Real derivatives[], size_t nx);
typedef fmi2Status fmi2GetEventIndicatorsTYPE (fmi2Component c, fmi2Real eventIndicators[], size_t ni);
typedef fmi2Status fmi2GetContinuousStatesTYPE (fmi2Component c, fmi2Real x[], size_t nx);
typedef fmi2Status fmi2GetNominalsOfContinuousStatesTYPE(fmi2Component c, fmi2Real x_nominal[], size_t nx);
/***************************************************
Types for Functions for FMI2 for Co-Simulation
****************************************************/
/* Simulating the slave */
typedef fmi2Status fmi2SetRealInputDerivativesTYPE (fmi2Component c,
const fmi2ValueReference vr[], size_t nvr,
const fmi2Integer order[],
const fmi2Real value[]);
typedef fmi2Status fmi2GetRealOutputDerivativesTYPE(fmi2Component c,
const fmi2ValueReference vr[], size_t nvr,
const fmi2Integer order[],
fmi2Real value[]);
typedef fmi2Status fmi2DoStepTYPE (fmi2Component c,
fmi2Real currentCommunicationPoint,
fmi2Real communicationStepSize,
fmi2Boolean noSetFMUStatePriorToCurrentPoint);
typedef fmi2Status fmi2CancelStepTYPE(fmi2Component c);
/* Inquire slave status */
typedef fmi2Status fmi2GetStatusTYPE (fmi2Component c, const fmi2StatusKind s, fmi2Status* value);
typedef fmi2Status fmi2GetRealStatusTYPE (fmi2Component c, const fmi2StatusKind s, fmi2Real* value);
typedef fmi2Status fmi2GetIntegerStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2Integer* value);
typedef fmi2Status fmi2GetBooleanStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2Boolean* value);
typedef fmi2Status fmi2GetStringStatusTYPE (fmi2Component c, const fmi2StatusKind s, fmi2String* value);
#ifdef __cplusplus
} /* end of extern "C" { */
#endif
#endif /* fmi2FunctionTypes_h */
)code";
/**
* @brief FMI2 Types platform header template. File 'fmi2TypesPlatform.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFMI2TypesPlatformHeaderTemplate[] = R"code(#ifndef fmi2TypesPlatform_h
#define fmi2TypesPlatform_h
/* Standard header file to define the argument types of the
functions of the Functional Mock-up Interface 2.0.1
This header file must be utilized both by the model and
by the simulation engine.
Revisions:
- Sep. 29, 2019: License changed to 2-clause BSD License (without extensions)
- Apr. 9, 2014: All prefixes "fmi" renamed to "fmi2" (decision from April 8)
- Mar 31, 2014: New datatype fmiChar introduced.
- Feb. 17, 2013: Changed fmiTypesPlatform from "standard32" to "default".
Removed fmiUndefinedValueReference since no longer needed
(because every state is defined in ScalarVariables).
- March 20, 2012: Renamed from fmiPlatformTypes.h to fmiTypesPlatform.h
- Nov. 14, 2011: Use the header file "fmiPlatformTypes.h" for FMI 2.0
both for "FMI for model exchange" and for "FMI for co-simulation"
New types "fmiComponentEnvironment", "fmiState", and "fmiByte".
The implementation of "fmiBoolean" is change from "char" to "int".
The #define "fmiPlatform" changed to "fmiTypesPlatform"
(in order that #define and function call are consistent)
- Oct. 4, 2010: Renamed header file from "fmiModelTypes.h" to fmiPlatformTypes.h"
for the co-simulation interface
- Jan. 4, 2010: Renamed meModelTypes_h to fmiModelTypes_h (by Mauss, QTronic)
- Dec. 21, 2009: Changed "me" to "fmi" and "meModel" to "fmiComponent"
according to meeting on Dec. 18 (by Martin Otter, DLR)
- Dec. 6, 2009: Added meUndefinedValueReference (by Martin Otter, DLR)
- Sept. 9, 2009: Changes according to FMI-meeting on July 21:
Changed "version" to "platform", "standard" to "standard32",
Added a precise definition of "standard32" as comment
(by Martin Otter, DLR)
- July 19, 2009: Added "me" as prefix to file names, added meTrue/meFalse,
and changed meValueReferenced from int to unsigned int
(by Martin Otter, DLR).
- March 2, 2009: Moved enums and function pointer definitions to
ModelFunctions.h (by Martin Otter, DLR).
- Dec. 3, 2008 : First version by Martin Otter (DLR) and
Hans Olsson (Dynasim).
Copyright (C) 2008-2011 MODELISAR consortium,
2012-2019 Modelica Association Project "FMI"
All rights reserved.
This file is licensed by the copyright holders under the 2-Clause BSD License
(https://opensource.org/licenses/BSD-2-Clause):
----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
*/
/* Platform (unique identification of this header file) */
#define fmi2TypesPlatform "default"
/* Type definitions of variables passed as arguments
Version "default" means:
fmi2Component : an opaque object pointer
fmi2ComponentEnvironment: an opaque object pointer
fmi2FMUstate : an opaque object pointer
fmi2ValueReference : handle to the value of a variable
fmi2Real : double precision floating-point data type
fmi2Integer : basic signed integer data type
fmi2Boolean : basic signed integer data type
fmi2Char : character data type
fmi2String : a pointer to a vector of fmi2Char characters
('\0' terminated, UTF8 encoded)
fmi2Byte : smallest addressable unit of the machine, typically one byte.
*/
typedef void* fmi2Component; /* Pointer to FMU instance */
typedef void* fmi2ComponentEnvironment; /* Pointer to FMU environment */
typedef void* fmi2FMUstate; /* Pointer to internal FMU state */
typedef unsigned int fmi2ValueReference;
typedef double fmi2Real ;
typedef int fmi2Integer;
typedef int fmi2Boolean;
typedef char fmi2Char;
typedef const fmi2Char* fmi2String;
typedef char fmi2Byte;
/* Values for fmi2Boolean */
#define fmi2True 1
#define fmi2False 0
#endif /* fmi2TypesPlatform_h */
)code";
/**
* @brief Model header template. File 'model.h'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szModelHeaderTemplate[] = R"code(#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#if FMI_VERSION != 1 && FMI_VERSION != 2 && FMI_VERSION != 3
#error FMI_VERSION must be one of 1, 2 or 3
#endif
#define UNUSED(x) (void)(x)
#include <stddef.h> // for size_t
#include <stdbool.h> // for bool
#include <stdint.h>
#include "config.h"
#if FMI_VERSION == 1
#define not_modelError (Instantiated| Initialized | Terminated)
typedef enum {
Instantiated = 1 << 0,
Initialized = 1 << 1,
Terminated = 1 << 2,
modelError = 1 << 3
} ModelState;
#elif FMI_VERSION == 2
typedef enum {
StartAndEnd = 1 << 0,
Instantiated = 1 << 1,
InitializationMode = 1 << 2,
// ME states
EventMode = 1 << 3,
ContinuousTimeMode = 1 << 4,
// CS states
StepComplete = 1 << 5,
StepInProgress = 1 << 6,
StepFailed = 1 << 7,
StepCanceled = 1 << 8,
Terminated = 1 << 9,
modelError = 1 << 10,
modelFatal = 1 << 11,
} ModelState;
#else
typedef enum {
StartAndEnd = 1 << 0,
ConfigurationMode = 1 << 1,
Instantiated = 1 << 2,
InitializationMode = 1 << 3,
EventMode = 1 << 4,
ContinuousTimeMode = 1 << 5,
StepMode = 1 << 6,
ClockActivationMode = 1 << 7,
StepDiscarded = 1 << 8,
ReconfigurationMode = 1 << 9,
IntermediateUpdateMode = 1 << 10,
Terminated = 1 << 11,
modelError = 1 << 12,
modelFatal = 1 << 13,
} ModelState;
#endif
typedef enum {
ModelExchange,
CoSimulation,
ScheduledExecution,
} InterfaceType;
typedef enum {
OK,
Warning,
Discard,
Error,
Fatal,
Pending
} Status;
#if FMI_VERSION < 3
typedef void (*loggerType) (void* componentEnvironment, const char* instanceName, int status, const char* category, const char* message, ...);
#else
typedef void (*loggerType) (void* componentEnvironment, int status, const char* category, const char* message);
#endif
typedef void (*lockPreemptionType) (void);
typedef void (*unlockPreemptionType) (void);
typedef void (*intermediateUpdateType) (void* instanceEnvironment,
double intermediateUpdateTime,
bool intermediateVariableSetRequested,
bool intermediateVariableGetAllowed,
bool intermediateStepFinished,
bool canReturnEarly,
bool* earlyReturnRequested,
double* earlyReturnTime);
typedef void(*clockUpdateType) (void* instanceEnvironment);
typedef struct {
double startTime;
double stopTime;
double time;
const char* instanceName;
InterfaceType type;
const char* resourceLocation;
Status status;
// callback functions
loggerType logger;
intermediateUpdateType intermediateUpdate;
clockUpdateType clockUpdate;
lockPreemptionType lockPreemtion;
unlockPreemptionType unlockPreemtion;
bool logEvents;
bool logErrors;
void* componentEnvironment;
ModelState state;
// event info
bool newDiscreteStatesNeeded;
bool terminateSimulation;
bool nominalsOfContinuousStatesChanged;
bool valuesOfContinuousStatesChanged;
bool nextEventTimeDefined;
double nextEventTime;
bool clocksTicked;
bool isDirtyValues;
ModelData modelData;
#if NZ > 0
// event indicators
double z[NZ];
#endif
// internal solver steps
uint64_t nSteps;
// Co-Simulation
bool earlyReturnAllowed;
bool eventModeUsed;
} ModelInstance;
ModelInstance* createModelInstance(
loggerType logger,
intermediateUpdateType intermediateUpdate,
void* componentEnvironment,
const char* instanceName,
const char* instantiationToken,
const char* resourceLocation,
bool loggingOn,
InterfaceType interfaceType);
void freeModelInstance(ModelInstance* comp);
void reset(ModelInstance* comp);
bool setStartValues(ModelInstance* comp);
Status calculateValues(ModelInstance* comp);
Status getFloat32(ModelInstance* comp, ValueReference vr, float values[], size_t nValues, size_t* index);
Status getFloat64(ModelInstance* comp, ValueReference vr, double values[], size_t nValues, size_t* index);
Status getInt8(ModelInstance* comp, ValueReference vr, int8_t values[], size_t nValues, size_t* index);
Status getUInt8(ModelInstance* comp, ValueReference vr, uint8_t values[], size_t nValues, size_t* index);
Status getInt16(ModelInstance* comp, ValueReference vr, int16_t values[], size_t nValues, size_t* index);
Status getUInt16(ModelInstance* comp, ValueReference vr, uint16_t values[], size_t nValues, size_t* index);
Status getInt32(ModelInstance* comp, ValueReference vr, int32_t values[], size_t nValues, size_t* index);
Status getUInt32(ModelInstance* comp, ValueReference vr, uint32_t values[], size_t nValues, size_t* index);
Status getInt64(ModelInstance* comp, ValueReference vr, int64_t values[], size_t nValues, size_t* index);
Status getUInt64(ModelInstance* comp, ValueReference vr, uint64_t values[], size_t nValues, size_t* index);
Status getBoolean(ModelInstance* comp, ValueReference vr, bool values[], size_t nValues, size_t* index);
Status getString(ModelInstance* comp, ValueReference vr, const char* values[], size_t nValues, size_t* index);
Status getBinary(ModelInstance* comp, ValueReference vr, size_t sizes[], const char* values[], size_t nValues, size_t* index);
Status setFloat32(ModelInstance* comp, ValueReference vr, const float values[], size_t nValues, size_t* index);
Status setFloat64(ModelInstance* comp, ValueReference vr, const double values[], size_t nValues, size_t* index);
Status setInt8(ModelInstance* comp, ValueReference vr, const int8_t values[], size_t nValues, size_t* index);
Status setUInt8(ModelInstance* comp, ValueReference vr, const uint8_t values[], size_t nValues, size_t* index);
Status setInt16(ModelInstance* comp, ValueReference vr, const int16_t values[], size_t nValues, size_t* index);
Status setUInt16(ModelInstance* comp, ValueReference vr, const uint16_t values[], size_t nValues, size_t* index);
Status setInt32(ModelInstance* comp, ValueReference vr, const int32_t values[], size_t nValues, size_t* index);
Status setUInt32(ModelInstance* comp, ValueReference vr, const uint32_t values[], size_t nValues, size_t* index);
Status setInt64(ModelInstance* comp, ValueReference vr, const int64_t values[], size_t nValues, size_t* index);
Status setUInt64(ModelInstance* comp, ValueReference vr, const uint64_t values[], size_t nValues, size_t* index);
Status setBoolean(ModelInstance* comp, ValueReference vr, const bool values[], size_t nValues, size_t* index);
Status setString(ModelInstance* comp, ValueReference vr, const char* const values[], size_t nValues, size_t* index);
Status setBinary(ModelInstance* comp, ValueReference vr, const size_t sizes[], const char* const values[], size_t nValues, size_t* index);
Status activateClock(ModelInstance* comp, ValueReference vr);
Status getClock(ModelInstance* comp, ValueReference vr, bool* value);
Status setClock(ModelInstance* comp, ValueReference vr, const bool* value);
Status getInterval(ModelInstance* comp, ValueReference vr, double* interval, int* qualifier);
Status activateModelPartition(ModelInstance* comp, ValueReference vr, double activationTime);
void getContinuousStates(ModelInstance* comp, double x[], size_t nx);
void setContinuousStates(ModelInstance* comp, const double x[], size_t nx);
void getDerivatives(ModelInstance* comp, double dx[], size_t nx);
Status getOutputDerivative(ModelInstance* comp, ValueReference valueReference, int order, double* value);
Status getPartialDerivative(ModelInstance* comp, ValueReference unknown, ValueReference known, double* partialDerivative);
void getEventIndicators(ModelInstance* comp, double z[], size_t nz);
void eventUpdate(ModelInstance* comp);
//void updateEventTime(ModelInstance *comp);
bool invalidNumber(ModelInstance* comp, const char* f, const char* arg, size_t actual, size_t expected);
bool invalidState(ModelInstance* comp, const char* f, int statesExpected);
bool nullPointer(ModelInstance* comp, const char* f, const char* arg, const void* p);
void logError(ModelInstance* comp, const char* message, ...);
Status setDebugLogging(ModelInstance* comp, bool loggingOn, size_t nCategories, const char* const categories[]);
void logEvent(ModelInstance* comp, const char* message, ...);
void logError(ModelInstance* comp, const char* message, ...);
void* getFMUState(ModelInstance* comp);
void setFMUState(ModelInstance* comp, void* FMUState);
// shorthand to access the variables
#define M(v) (comp->modelData.v)
// "stringification" macros
#define xstr(s) str(s)
#define str(s) #s
// assert size of nValues for scalar variables
#define ASSERT_NVALUES(N) do { \
if (*index + (N) > nValues) { \
logError(comp, "Expected nValues > %zu but was %zu.", *index, nValues); \
return Error; \
} \
} while (0)
#ifdef __cplusplus
} // end of extern "C"
#endif
)code";
/**
* @brief CoSimulation template. File 'cosimulation.c'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szCosimulationSrcFileTemplate[] = R"code(#include <stdlib.h> // for calloc(), free()
#include <float.h> // for DBL_EPSILON
#include <math.h> // for fabs()
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "config.h"
#include "cosimulation.h"
#if FMI_VERSION == 3
#include "fmi3Functions.h"
#endif
#ifdef _MSC_VER
#define strdup _strdup
#endif
ModelInstance *createModelInstance(
loggerType cbLogger,
intermediateUpdateType intermediateUpdate,
void *componentEnvironment,
const char *instanceName,
const char *instantiationToken,
const char *resourceLocation,
bool loggingOn,
InterfaceType interfaceType) {
ModelInstance *comp = NULL;
if (!instanceName || strlen(instanceName) == 0) {
if (cbLogger) {
#if FMI_VERSION < 3
cbLogger(componentEnvironment, "?", Error, "error", "Missing instance name.");
#else
cbLogger(componentEnvironment, Error, "error", "Missing instance name.");
#endif
}
return NULL;
}
if (!instantiationToken || strlen(instantiationToken) == 0) {
if (cbLogger) {
#if FMI_VERSION < 3
cbLogger(componentEnvironment, instanceName, Error, "error", "Missing GUID.");
#else
cbLogger(componentEnvironment, Error, "error", "Missing instantiationToken.");
#endif
}
return NULL;
}
if (strcmp(instantiationToken, INSTANTIATION_TOKEN)) {
if (cbLogger) {
#if FMI_VERSION < 3
cbLogger(componentEnvironment, instanceName, Error, "error", "Wrong GUID.");
#else
cbLogger(componentEnvironment, Error, "error", "Wrong instantiationToken.");
#endif
}
return NULL;
}
comp = (ModelInstance *)calloc(1, sizeof(ModelInstance));
if (comp) {
comp->componentEnvironment = componentEnvironment;
comp->logger = cbLogger;
comp->intermediateUpdate = intermediateUpdate;
comp->lockPreemtion = NULL;
comp->unlockPreemtion = NULL;
comp->instanceName = strdup(instanceName);
comp->resourceLocation = resourceLocation ? strdup(resourceLocation) : NULL;
comp->status = OK;
comp->logEvents = loggingOn;
comp->logErrors = true; // always log errors
comp->nSteps = 0;
comp->earlyReturnAllowed = false;
comp->eventModeUsed = false;
}
if (!comp || !comp->instanceName) {
logError(comp, "Out of memory.");
return NULL;
}
comp->time = 0.0; // overwrite in fmi*SetupExperiment, fmi*SetTime
comp->type = interfaceType;
comp->state = Instantiated;
comp->newDiscreteStatesNeeded = false;
comp->terminateSimulation = false;
comp->nominalsOfContinuousStatesChanged = false;
comp->valuesOfContinuousStatesChanged = false;
comp->nextEventTimeDefined = false;
comp->nextEventTime = 0;
if (!setStartValues(comp))
{
cbLogger(componentEnvironment, instanceName, Error, "error", "VAPI initialization failed.");
}
comp->isDirtyValues = true;
return comp;
}
void freeModelInstance(ModelInstance *comp) {
free((void *)comp->instanceName);
free(comp);
}
void reset(ModelInstance* comp) {
comp->state = Instantiated;
comp->startTime = 0.0;
comp->time = 0.0;
comp->nSteps = 0;
comp->status = OK;
setStartValues(comp);
comp->isDirtyValues = true;
}
bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, size_t actual, size_t expected) {
if (actual != expected) {
comp->state = modelError;
logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, actual, expected);
return true;
}
return false;
}
bool invalidState(ModelInstance *comp, const char *f, int statesExpected) {
UNUSED(f);
UNUSED(statesExpected);
if (!comp) {
return true;
}
// TODO: add missing states and check state
return false;
// if (!(comp->state & statesExpected)) {
// comp->state = modelError;
// logError(comp, "%s: Illegal call sequence.", f);
// return true;
// }
//
// return false;
}
bool nullPointer(ModelInstance* comp, const char *f, const char *arg, const void *p) {
if (!p) {
comp->state = modelError;
logError(comp, "%s: Invalid argument %s = NULL.", f, arg);
return true;
}
return false;
}
Status setDebugLogging(ModelInstance *comp, bool loggingOn, size_t nCategories, const char * const categories[]) {
if (nCategories > 0) {
if (categories == NULL) {
logError(comp, "Argument categories must not be NULL.");
return Error;
}
for (size_t i = 0; i < nCategories; i++) {
if (categories[i] == NULL) {
logError(comp, "Argument categories[%zu] must not be NULL.", i);
return Error;
} else if (strcmp(categories[i], "logEvents") == 0) {
comp->logEvents = loggingOn;
} else if (strcmp(categories[i], "logStatusError") == 0) {
comp->logErrors = loggingOn;
} else {
logError(comp, "Log categories[%zu] must be one of \"logEvents\" or \"logStatusError\" but was \"%s\".", i, categories[i]);
return Error;
}
}
} else {
comp->logEvents = loggingOn;
comp->logErrors = loggingOn;
}
return OK;
}
static void logMessage(ModelInstance *comp, int status, const char *category, const char *message, va_list args) {
if (!comp->logger) {
return;
}
va_list args1;
int len = 0;
char *buf = "";
va_copy(args1, args);
len = vsnprintf(buf, len, message, args1);
va_end(args1);
if (len < 0) {
return;
}
va_copy(args1, args);
buf = (char *)calloc(len + 1, sizeof(char));
len = vsnprintf(buf, len + 1, message, args);
va_end(args1);
if (len >= 0) {
// no need to distinguish between FMI versions since we're not using variadic arguments
#if FMI_VERSION < 3
comp->logger(comp->componentEnvironment, comp->instanceName, status, category, buf);
#else
comp->logger(comp->componentEnvironment, status, category, buf);
#endif
}
free(buf);
}
void logEvent(ModelInstance *comp, const char *message, ...) {
if (!comp || !comp->logEvents) return;
va_list args;
va_start(args, message);
logMessage(comp, OK, "logEvents", message, args);
va_end(args);
}
void logError(ModelInstance *comp, const char *message, ...) {
if (!comp || !comp->logErrors) return;
va_list args;
va_start(args, message);
logMessage(comp, Error, "logStatusError", message, args);
va_end(args);
}
// default implementations
#if NZ < 1
void getEventIndicators(ModelInstance *comp, double z[], size_t nz) {
UNUSED(comp);
UNUSED(z);
UNUSED(nz);
// do nothing
}
#endif
#define GET_NOT_ALLOWED(t) do { \
UNUSED(vr); \
UNUSED(values); \
UNUSED(nValues); \
UNUSED(index); \
logError(comp, "Getting " t " is not allowed.");\
return Error; \
} while (false)
#ifndef GET_FLOAT32
Status getFloat32(ModelInstance* comp, ValueReference vr, float values[], size_t nValues, size_t* index) {
GET_NOT_ALLOWED("Float32");
}
#endif
#ifndef GET_INT8
Status getInt8(ModelInstance* comp, ValueReference vr, int8_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("Int8");
}
#endif
#ifndef GET_UINT8
Status getUInt8(ModelInstance* comp, ValueReference vr, uint8_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("UInt8");
}
#endif
#ifndef GET_INT16
Status getInt16(ModelInstance* comp, ValueReference vr, int16_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("Int16");
}
#endif
#ifndef GET_UINT16
Status getUInt16(ModelInstance* comp, ValueReference vr, uint16_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("UInt16");
}
#endif
#ifndef GET_INT32
Status getInt32(ModelInstance* comp, ValueReference vr, int32_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("Int32");
}
#endif
#ifndef GET_UINT32
Status getUInt32(ModelInstance* comp, ValueReference vr, uint32_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("UInt32");
}
#endif
#ifndef GET_INT64
Status getInt64(ModelInstance* comp, ValueReference vr, int64_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("Int64");
}
#endif
#ifndef GET_UINT64
Status getUInt64(ModelInstance* comp, ValueReference vr, uint64_t values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("UInt64");
}
#endif
#ifndef GET_BOOLEAN
Status getBoolean(ModelInstance* comp, ValueReference vr, bool values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("Boolean");
}
#endif
#ifndef GET_STRING
Status getString(ModelInstance* comp, ValueReference vr, const char* values[], size_t nValues, size_t *index) {
GET_NOT_ALLOWED("String");
}
#endif
#ifndef GET_BINARY
Status getBinary(ModelInstance* comp, ValueReference vr, size_t sizes[], const char* values[], size_t nValues, size_t *index) {
UNUSED(sizes);
GET_NOT_ALLOWED("Binary");
}
#endif
#define SET_NOT_ALLOWED(t) do { \
UNUSED(vr); \
UNUSED(values); \
UNUSED(nValues); \
UNUSED(index); \
logError(comp, "Setting " t " is not allowed.");\
return Error; \
} while (false)
#ifndef SET_FLOAT32
Status setFloat32(ModelInstance* comp, ValueReference vr, const float values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Float32");
}
#endif
#ifndef SET_FLOAT64
Status setFloat64(ModelInstance* comp, ValueReference vr, const double values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Float64");
}
#endif
#ifndef SET_INT8
Status setInt8(ModelInstance* comp, ValueReference vr, const int8_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Int8");
}
#endif
#ifndef SET_UINT8
Status setUInt8(ModelInstance* comp, ValueReference vr, const uint8_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("UInt8");
}
#endif
#ifndef SET_INT16
Status setInt16(ModelInstance* comp, ValueReference vr, const int16_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Int16");
}
#endif
#ifndef SET_UINT16
Status setUInt16(ModelInstance* comp, ValueReference vr, const uint16_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("UInt16");
}
#endif
#ifndef SET_INT32
Status setInt32(ModelInstance* comp, ValueReference vr, const int32_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Int32");
}
#endif
#ifndef SET_UINT32
Status setUInt32(ModelInstance* comp, ValueReference vr, const uint32_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("UInt32");
}
#endif
#ifndef SET_INT64
Status setInt64(ModelInstance* comp, ValueReference vr, const int64_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Int64");
}
#endif
#ifndef SET_UINT64
Status setUInt64(ModelInstance* comp, ValueReference vr, const uint64_t values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("UInt64");
}
#endif
#ifndef SET_BOOLEAN
Status setBoolean(ModelInstance* comp, ValueReference vr, const bool values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("Boolean");
}
#endif
#ifndef SET_STRING
Status setString(ModelInstance* comp, ValueReference vr, const char *const values[], size_t nValues, size_t* index) {
SET_NOT_ALLOWED("String");
}
#endif
#ifndef SET_BINARY
Status setBinary(ModelInstance* comp, ValueReference vr, const size_t size[], const char *const values[], size_t nValues, size_t* index) {
UNUSED(size);
SET_NOT_ALLOWED("Binary");
}
#endif
#ifndef ACTIVATE_CLOCK
Status activateClock(ModelInstance* comp, ValueReference vr) {
UNUSED(comp);
UNUSED(vr);
return Error;
}
#endif
#ifndef GET_CLOCK
Status getClock(ModelInstance* comp, ValueReference vr, bool* value) {
UNUSED(comp);
UNUSED(vr);
UNUSED(value);
return Error;
}
#endif
#ifndef GET_INTERVAL
Status getInterval(ModelInstance* comp, ValueReference vr, double* interval, int* qualifier) {
UNUSED(comp);
UNUSED(vr);
UNUSED(interval);
UNUSED(qualifier);
return Error;
}
#endif
#ifndef ACTIVATE_MODEL_PARTITION
Status activateModelPartition(ModelInstance* comp, ValueReference vr, double activationTime) {
UNUSED(comp);
UNUSED(vr);
UNUSED(activationTime);
return Error;
}
#endif
#if NX < 1
void getContinuousStates(ModelInstance *comp, double x[], size_t nx) {
UNUSED(comp);
UNUSED(x);
UNUSED(nx);
}
void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) {
UNUSED(comp);
UNUSED(x);
UNUSED(nx);
}
void getDerivatives(ModelInstance *comp, double dx[], size_t nx) {
UNUSED(comp);
UNUSED(dx);
UNUSED(nx);
}
#endif
#ifndef GET_PARTIAL_DERIVATIVE
Status getPartialDerivative(ModelInstance *comp, ValueReference unknown, ValueReference known, double *partialDerivative) {
UNUSED(comp);
UNUSED(unknown);
UNUSED(known);
UNUSED(partialDerivative);
logError(comp, "Directional derivatives are not supported.");
return Error;
}
#endif
void* getFMUState(ModelInstance* comp) {
ModelInstance* fmuState = (ModelInstance*)calloc(1, sizeof(ModelInstance));
if (fmuState) {
memcpy(fmuState, comp, sizeof(ModelInstance));
}
return fmuState;
}
void setFMUState(ModelInstance* comp, void* FMUState) {
ModelInstance* s = (ModelInstance*)FMUState;
comp->startTime = s->startTime;
comp->stopTime = s->stopTime;
comp->time = s->time;
comp->status = s->status;
comp->state = s->state;
comp->newDiscreteStatesNeeded = s->newDiscreteStatesNeeded;
comp->terminateSimulation = s->terminateSimulation;
comp->nominalsOfContinuousStatesChanged = s->nominalsOfContinuousStatesChanged;
comp->valuesOfContinuousStatesChanged = s->valuesOfContinuousStatesChanged;
comp->nextEventTimeDefined = s->nextEventTimeDefined;
comp->nextEventTime = s->nextEventTime;
comp->clocksTicked = s->clocksTicked;
comp->isDirtyValues = s->isDirtyValues;
comp->modelData = s->modelData;
#if NZ > 0
memcpy(comp->z, s->z, NZ * sizeof(double));
#endif
comp->nSteps = s->nSteps;
}
void doFixedStep(ModelInstance *comp, bool* stateEvent, bool* timeEvent) {
#if NX > 0
double x[NX] = { 0 };
double dx[NX] = { 0 };
getContinuousStates(comp, x, NX);
getDerivatives(comp, dx, NX);
// forward Euler step
for (int i = 0; i < NX; i++) {
x[i] += FIXED_SOLVER_STEP * dx[i];
}
setContinuousStates(comp, x, NX);
#endif
comp->nSteps++;
comp->time = comp->startTime + comp->nSteps * FIXED_SOLVER_STEP;
// state event
*stateEvent = false;
#if NZ > 0
double z[NZ] = { 0.0 };
getEventIndicators(comp, z, NZ);
// check for zero-crossings
for (int i = 0; i < NZ; i++) {
*stateEvent |= (comp->z[i] <= 0 && z[i] > 0) || (comp->z[i] > 0 && z[i] <= 0);
}
// remember the current event indicators
memcpy(comp->z, z, sizeof(double) * NZ);
#endif
// time event
*timeEvent = comp->nextEventTimeDefined && comp->time >= comp->nextEventTime;
bool earlyReturnRequested;
double earlyReturnTime;
// intermediate update
if (comp->intermediateUpdate) {
comp->intermediateUpdate(
comp->componentEnvironment, // instanceEnvironment
comp->time, // intermediateUpdateTime
false, // intermediateVariableSetRequested
true, // intermediateVariableGetAllowed
true, // intermediateStepFinished
false, // canReturnEarly
&earlyReturnRequested, // earlyReturnRequested
&earlyReturnTime); // earlyReturnTime
}
}
)code";
/**
* @brief Part one of FMI2 function template. Due to the size split into 2 strings.
* File 'fmi2Functions.c'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFmi2FunctionsSrcFileTemplate1[] = R"code(#if FMI_VERSION != 2
#error FMI_VERSION must be 2
#endif
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <math.h>
#include "config.h"
#include "model.h"
#include "cosimulation.h"
// C-code FMUs have functions names prefixed with MODEL_IDENTIFIER_.
// Define DISABLE_PREFIX to build a binary FMU.
#ifndef DISABLE_PREFIX
#define pasteA(a,b) a ## b
#define pasteB(a,b) pasteA(a,b)
#define FMI2_FUNCTION_PREFIX pasteB(MODEL_IDENTIFIER, _)
#endif
#include "fmi2Functions.h"
#define ASSERT_NOT_NULL(p) \
do { \
if (!p) { \
logError(S, "Argument %s must not be NULL.", xstr(p)); \
S->state = modelError; \
return (fmi2Status)Error; \
} \
} while (0)
#define GET_VARIABLES(T) \
do { \
Status status = OK; \
if (nvr == 0) return (fmi2Status)status; \
ASSERT_NOT_NULL(vr); \
ASSERT_NOT_NULL(value); \
size_t index = 0; \
if (S->isDirtyValues) { \
Status s = calculateValues(S); \
status = max(status, s); \
if (status > Warning) return (fmi2Status)status; \
S->isDirtyValues = false; \
} \
for (size_t i = 0; i < nvr; i++) { \
Status s = get ## T(S, vr[i], value, nvr, &index); \
status = max(status, s); \
if (status > Warning) return (fmi2Status)status; \
} \
return (fmi2Status)status; \
} while (0)
#define SET_VARIABLES(T) \
do { \
Status status = OK; \
if (nvr == 0) return (fmi2Status)status; \
ASSERT_NOT_NULL(vr); \
ASSERT_NOT_NULL(value); \
size_t index = 0; \
for (size_t i = 0; i < nvr; i++) { \
Status s = set ## T(S, vr[i], value, nvr, &index); \
status = max(status, s); \
if (status > Warning) return (fmi2Status)status; \
} \
if (nvr > 0) S->isDirtyValues = true; \
return (fmi2Status)status; \
} while (0)
#define GET_BOOLEAN_VARIABLES \
do { \
Status status = OK; \
for (size_t i = 0; i < nvr; i++) { \
bool v = false; \
size_t index = 0; \
Status s = getBoolean(S, vr[i], &v, nvr, &index); \
value[i] = v; \
status = max(status, s); \
if (status > Warning) return (fmi2Status)status; \
} \
return (fmi2Status)status; \
} while (0)
#define SET_BOOLEAN_VARIABLES \
do { \
Status status = OK; \
for (size_t i = 0; i < nvr; i++) { \
bool v = value[i]; \
size_t index = 0; \
Status s = setBoolean(S, vr[i], &v, nvr, &index); \
status = max(status, s); \
if (status > Warning) return (fmi2Status)status; \
} \
return (fmi2Status)status; \
} while (0)
#ifndef max
#define max(a,b) ((a)>(b) ? (a) : (b))
#endif
#ifndef DT_EVENT_DETECT
#define DT_EVENT_DETECT 1e-10
#endif
// ---------------------------------------------------------------------------
// Function calls allowed state masks for both Model-exchange and Co-simulation
// ---------------------------------------------------------------------------
#define MASK_fmi2GetTypesPlatform (StartAndEnd | Instantiated | InitializationMode \
| EventMode | ContinuousTimeMode \
| StepComplete | StepInProgress | StepFailed | StepCanceled \
| Terminated | modelError)
#define MASK_fmi2GetVersion MASK_fmi2GetTypesPlatform
#define MASK_fmi2SetDebugLogging (Instantiated | InitializationMode \
| EventMode | ContinuousTimeMode \
| StepComplete | StepInProgress | StepFailed | StepCanceled \
| Terminated | modelError)
#define MASK_fmi2Instantiate (StartAndEnd)
#define MASK_fmi2FreeInstance (Instantiated | InitializationMode \
| EventMode | ContinuousTimeMode \
| StepComplete | StepFailed | StepCanceled \
| Terminated | modelError)
#define MASK_fmi2SetupExperiment Instantiated
#define MASK_fmi2EnterInitializationMode Instantiated
#define MASK_fmi2ExitInitializationMode InitializationMode
#define MASK_fmi2Terminate (EventMode | ContinuousTimeMode \
| StepComplete | StepFailed)
#define MASK_fmi2Reset MASK_fmi2FreeInstance
#define MASK_fmi2GetReal (InitializationMode \
| EventMode | ContinuousTimeMode \
| StepComplete | StepFailed | StepCanceled \
| Terminated | modelError)
#define MASK_fmi2GetInteger MASK_fmi2GetReal
#define MASK_fmi2GetBoolean MASK_fmi2GetReal
#define MASK_fmi2GetString MASK_fmi2GetReal
#define MASK_fmi2SetReal (Instantiated | InitializationMode \
| EventMode | ContinuousTimeMode \
| StepComplete)
#define MASK_fmi2SetInteger (Instantiated | InitializationMode \
| EventMode \
| StepComplete)
#define MASK_fmi2SetBoolean MASK_fmi2SetInteger
#define MASK_fmi2SetString MASK_fmi2SetInteger
#define MASK_fmi2GetFMUstate MASK_fmi2FreeInstance
#define MASK_fmi2SetFMUstate MASK_fmi2FreeInstance
#define MASK_fmi2FreeFMUstate MASK_fmi2FreeInstance
#define MASK_fmi2SerializedFMUstateSize MASK_fmi2FreeInstance
#define MASK_fmi2SerializeFMUstate MASK_fmi2FreeInstance
#define MASK_fmi2DeSerializeFMUstate MASK_fmi2FreeInstance
#define MASK_fmi2GetDirectionalDerivative (InitializationMode \
| EventMode | ContinuousTimeMode \
| StepComplete | StepFailed | StepCanceled \
| Terminated | modelError)
// ---------------------------------------------------------------------------
// Function calls allowed state masks for Model-exchange
// ---------------------------------------------------------------------------
#define MASK_fmi2EnterEventMode (EventMode | ContinuousTimeMode)
#define MASK_fmi2NewDiscreteStates EventMode
#define MASK_fmi2EnterContinuousTimeMode EventMode
#define MASK_fmi2CompletedIntegratorStep ContinuousTimeMode
#define MASK_fmi2SetTime (EventMode | ContinuousTimeMode)
#define MASK_fmi2SetContinuousStates ContinuousTimeMode
#define MASK_fmi2GetEventIndicators (InitializationMode \
| EventMode | ContinuousTimeMode \
| Terminated | modelError)
#define MASK_fmi2GetContinuousStates MASK_fmi2GetEventIndicators
#define MASK_fmi2GetDerivatives (EventMode | ContinuousTimeMode \
| Terminated | modelError)
#define MASK_fmi2GetNominalsOfContinuousStates ( Instantiated \
| EventMode | ContinuousTimeMode \
| Terminated | modelError)
// ---------------------------------------------------------------------------
// Function calls allowed state masks for Co-simulation
// ---------------------------------------------------------------------------
#define MASK_fmi2SetRealInputDerivatives (Instantiated | InitializationMode \
| StepComplete)
#define MASK_fmi2GetRealOutputDerivatives (StepComplete | StepFailed | StepCanceled \
| Terminated | Error)
#define MASK_fmi2DoStep StepComplete
#define MASK_fmi2CancelStep StepInProgress
#define MASK_fmi2GetStatus (StepComplete | StepInProgress | StepFailed \
| Terminated)
#define MASK_fmi2GetRealStatus MASK_fmi2GetStatus
#define MASK_fmi2GetIntegerStatus MASK_fmi2GetStatus
#define MASK_fmi2GetBooleanStatus MASK_fmi2GetStatus
#define MASK_fmi2GetStringStatus MASK_fmi2GetStatus
// shorthand to access the instance
#define S ((ModelInstance *)c)
#define ASSERT_STATE(S) \
if (!allowedState(c, MASK_fmi2##S, #S)) \
return fmi2Error;
static bool allowedState(ModelInstance *instance, int statesExpected, char *name) {
if (!instance) {
return false;
}
if (!(instance->state & statesExpected)) {
logError(instance, "fmi2%s: Illegal call sequence.", name);
return false;
}
return true;
}
// ---------------------------------------------------------------------------
// FMI functions
// ---------------------------------------------------------------------------
fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID,
fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions,
fmi2Boolean visible, fmi2Boolean loggingOn) {
UNUSED(visible);
if (!functions || !functions->logger) {
return NULL;
}
return createModelInstance(
(loggerType)functions->logger,
NULL,
functions->componentEnvironment,
instanceName,
fmuGUID,
fmuResourceLocation,
loggingOn,
(InterfaceType)fmuType);
}
fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance,
fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime) {
UNUSED(toleranceDefined);
UNUSED(tolerance);
ASSERT_STATE(SetupExperiment)
S->startTime = startTime;
S->stopTime = stopTimeDefined ? stopTime : INFINITY;
S->time = startTime;
return fmi2OK;
}
fmi2Status fmi2EnterInitializationMode(fmi2Component c) {
ASSERT_STATE(EnterInitializationMode)
S->state = InitializationMode;
return fmi2OK;
}
fmi2Status fmi2ExitInitializationMode(fmi2Component c) {
ASSERT_STATE(ExitInitializationMode);
fmi2Status status = fmi2OK;
// if values were set and no fmi2GetXXX triggered update before,
// ensure calculated values are updated now
if (S->isDirtyValues) {
status = (fmi2Status)calculateValues(S);
S->isDirtyValues = false;
}
if (S->type == ModelExchange) {
S->state = EventMode;
} else {
S->state = StepComplete;
}
return status;
}
fmi2Status fmi2Terminate(fmi2Component c) {
ASSERT_STATE(Terminate)
S->state = Terminated;
return fmi2OK;
}
fmi2Status fmi2Reset(fmi2Component c) {
ASSERT_STATE(Reset);
reset(S);
return fmi2OK;
}
void fmi2FreeInstance(fmi2Component c) {
if (S) {
freeModelInstance(S);
}
}
// ---------------------------------------------------------------------------
// FMI functions: class methods not depending of a specific model instance
// ---------------------------------------------------------------------------
const char* fmi2GetVersion(void) {
return fmi2Version;
}
const char* fmi2GetTypesPlatform(void) {
return fmi2TypesPlatform;
}
// ---------------------------------------------------------------------------
// FMI functions: logging control, setters and getters for Real, Integer,
// Boolean, String
// ---------------------------------------------------------------------------
fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) {
ASSERT_STATE(SetDebugLogging)
return (fmi2Status)setDebugLogging(S, loggingOn, nCategories, categories);
}
fmi2Status fmi2GetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) {
ASSERT_STATE(GetReal)
if (nvr > 0 && nullPointer(S, "fmi2GetReal", "vr[]", vr))
return fmi2Error;
if (nvr > 0 && nullPointer(S, "fmi2GetReal", "value[]", value))
return fmi2Error;
if (nvr > 0 && S->isDirtyValues) {
calculateValues(S);
S->isDirtyValues = false;
}
GET_VARIABLES(Float64);
}
fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) {
ASSERT_STATE(GetInteger)
if (nvr > 0 && nullPointer(S, "fmi2GetInteger", "vr[]", vr))
return fmi2Error;
if (nvr > 0 && nullPointer(S, "fmi2GetInteger", "value[]", value))
return fmi2Error;
if (nvr > 0 && S->isDirtyValues) {
calculateValues(S);
S->isDirtyValues = false;
}
GET_VARIABLES(Int32);
}
fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) {
ASSERT_STATE(GetBoolean)
if (nvr > 0 && nullPointer(S, "fmi2GetBoolean", "vr[]", vr))
return fmi2Error;
if (nvr > 0 && nullPointer(S, "fmi2GetBoolean", "value[]", value))
return fmi2Error;
if (nvr > 0 && S->isDirtyValues) {
calculateValues(S);
S->isDirtyValues = false;
}
GET_BOOLEAN_VARIABLES;
}
fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) {
ASSERT_STATE(GetString)
if (nvr>0 && nullPointer(S, "fmi2GetString", "vr[]", vr))
return fmi2Error;
if (nvr>0 && nullPointer(S, "fmi2GetString", "value[]", value))
return fmi2Error;
if (nvr > 0 && S->isDirtyValues) {
calculateValues(S);
S->isDirtyValues = false;
}
GET_VARIABLES(String);
}
fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) {
ASSERT_STATE(SetReal)
if (nvr > 0 && nullPointer(S, "fmi2SetReal", "vr[]", vr))
return fmi2Error;
if (nvr > 0 && nullPointer(S, "fmi2SetReal", "value[]", value))
return fmi2Error;
SET_VARIABLES(Float64);
}
fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) {
ASSERT_STATE(SetInteger)
if (nvr > 0 && nullPointer(S, "fmi2SetInteger", "vr[]", vr))
return fmi2Error;
if (nvr > 0 && nullPointer(S, "fmi2SetInteger", "value[]", value))
return fmi2Error;
SET_VARIABLES(Int32);
}
fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) {
ASSERT_STATE(SetBoolean)
if (nvr>0 && nullPointer(S, "fmi2SetBoolean", "vr[]", vr))
return fmi2Error;
if (nvr>0 && nullPointer(S, "fmi2SetBoolean", "value[]", value))
return fmi2Error;
SET_BOOLEAN_VARIABLES;
}
fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) {
ASSERT_STATE(SetString);
if (nvr>0 && nullPointer(S, "fmi2SetString", "vr[]", vr))
return fmi2Error;
if (nvr>0 && nullPointer(S, "fmi2SetString", "value[]", value))
return fmi2Error;
SET_VARIABLES(String);
}
fmi2Status fmi2GetFMUstate (fmi2Component c, fmi2FMUstate* FMUstate) {
ASSERT_STATE(GetFMUstate);
*FMUstate = getFMUState(S);
return fmi2OK;
}
)code";
/**
* @brief Part two of FMI2 function template. Due to the size split into 2 strings.
* File 'fmi2Functions.c'. Code chunks are inserted at the keywords surrounded by %%.
*/
const char szFmi2FunctionsSrcFileTemplate2[] = R"code(
fmi2Status fmi2SetFMUstate(fmi2Component c, fmi2FMUstate FMUstate) {
ASSERT_STATE(SetFMUstate);
if (nullPointer(S, "fmi2SetFMUstate", "FMUstate", FMUstate)) {
return fmi2Error;
}
setFMUState(S, FMUstate);
return fmi2OK;
}
fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate* FMUstate) {
ASSERT_STATE(FreeFMUstate);
free(*FMUstate);
*FMUstate = NULL;
return fmi2OK;
}
fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate FMUstate, size_t *size) {
UNUSED(c);
UNUSED(FMUstate);
ASSERT_STATE(SerializedFMUstateSize);
*size = sizeof(ModelInstance);
return fmi2OK;
}
fmi2Status fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte serializedState[], size_t size) {
ASSERT_STATE(SerializeFMUstate);
if (nullPointer(S, "fmi2SerializeFMUstate", "FMUstate", FMUstate)) {
return fmi2Error;
}
if (invalidNumber(S, "fmi2SerializeFMUstate", "size", size, sizeof(ModelInstance))) {
return fmi2Error;
}
memcpy(serializedState, FMUstate, sizeof(ModelInstance));
return fmi2OK;
}
fmi2Status fmi2DeSerializeFMUstate (fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate* FMUstate) {
ASSERT_STATE(DeSerializeFMUstate);
if (invalidNumber(S, "fmi2DeSerializeFMUstate", "size", size, sizeof(ModelInstance))) {
return fmi2Error;
}
if (*FMUstate == NULL) {
*FMUstate = calloc(1, sizeof(ModelInstance));
}
memcpy(*FMUstate, serializedState, sizeof(ModelInstance));
return fmi2OK;
}
fmi2Status fmi2GetDirectionalDerivative(fmi2Component c, const fmi2ValueReference vUnknown_ref[], size_t nUnknown,
const fmi2ValueReference vKnown_ref[] , size_t nKnown,
const fmi2Real dvKnown[], fmi2Real dvUnknown[]) {
ASSERT_STATE(GetDirectionalDerivative);
// TODO: check value references
// TODO: assert nUnknowns == nDeltaOfUnknowns
// TODO: assert nKnowns == nDeltaKnowns
Status status = OK;
for (size_t i = 0; i < nUnknown; i++) {
dvUnknown[i] = 0;
for (size_t j = 0; j < nKnown; j++) {
double partialDerivative = 0;
Status s = getPartialDerivative(S, vUnknown_ref[i], vKnown_ref[j], &partialDerivative);
status = max(status, s);
if (status > Warning) {
return (fmi2Status)status;
}
dvUnknown[i] += partialDerivative * dvKnown[j];
}
}
return fmi2OK;
}
// ---------------------------------------------------------------------------
// Functions for FMI for Co-Simulation
// ---------------------------------------------------------------------------
/* Simulating the slave */
fmi2Status fmi2SetRealInputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr,
const fmi2Integer order[], const fmi2Real value[]) {
UNUSED(vr);
UNUSED(nvr);
UNUSED(order);
UNUSED(value);
ASSERT_STATE(SetRealInputDerivatives);
logError(S, "fmi2SetRealInputDerivatives: ignoring function call."
" This model cannot interpolate inputs: canInterpolateInputs=\"fmi2False\"");
return fmi2Error;
}
fmi2Status fmi2GetRealOutputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr,
const fmi2Integer order[], fmi2Real value[]) {
ASSERT_STATE(GetRealOutputDerivatives);
#ifdef GET_OUTPUT_DERIVATIVE
Status status = OK;
for (size_t i = 0; i < nvr; i++) {
const Status s = getOutputDerivative(S, vr[i], order[i], &value[i]);
status = max(status, s);
if (status > Warning) {
return (fmi2Status)status;
}
}
return (fmi2Status)status;
#else
UNUSED(vr);
UNUSED(nvr);
UNUSED(order);
UNUSED(value);
logError(S, "fmi2GetRealOutputDerivatives: ignoring function call."
" This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\"");
return fmi2Error;
#endif
}
fmi2Status fmi2CancelStep(fmi2Component c) {
ASSERT_STATE(CancelStep);
logError(S, "fmi2CancelStep: Can be called when fmi2DoStep returned fmi2Pending."
" This is not the case.");
return fmi2Error;
}
fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint,
fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) {
UNUSED(noSetFMUStatePriorToCurrentPoint);
ASSERT_STATE(DoStep);
if (communicationStepSize <= 0) {
logError(S, "Communication step size must be > 0 but was %g.", communicationStepSize);
S->state = modelError;
return fmi2Error;
}
if (currentCommunicationPoint + communicationStepSize > S->stopTime + EPSILON) {
logError(S, "At communication point %.16g a step size of %.16g was requested but stop time is %.16g.",
currentCommunicationPoint, communicationStepSize, S->stopTime);
S->state = modelError;
return fmi2Error;
}
const fmi2Real nextCommunicationPoint = currentCommunicationPoint + communicationStepSize + EPSILON;
while (true) {
if (S->time + FIXED_SOLVER_STEP > nextCommunicationPoint) {
break; // next communication point reached
}
bool stateEvent, timeEvent;
doFixedStep(S, &stateEvent, &timeEvent);
#ifdef EVENT_UPDATE
if (stateEvent || timeEvent) {
eventUpdate(S);
}
#endif
}
return S->terminateSimulation ? fmi2Discard : fmi2OK;
}
/* Inquire slave status */
static fmi2Status getStatus(char* fname, fmi2Component c, const fmi2StatusKind s) {
switch(s) {
case fmi2DoStepStatus: logError(S,
"%s: Can be called with fmi2DoStepStatus when fmi2DoStep returned fmi2Pending."
" This is not the case.", fname);
break;
case fmi2PendingStatus: logError(S,
"%s: Can be called with fmi2PendingStatus when fmi2DoStep returned fmi2Pending."
" This is not the case.", fname);
break;
case fmi2LastSuccessfulTime: logError(S,
"%s: Can be called with fmi2LastSuccessfulTime when fmi2DoStep returned fmi2Discard."
" This is not the case.", fname);
break;
case fmi2Terminated: logError(S,
"%s: Can be called with fmi2Terminated when fmi2DoStep returned fmi2Discard."
" This is not the case.", fname);
break;
}
return fmi2Discard;
}
fmi2Status fmi2GetStatus(fmi2Component c, const fmi2StatusKind s, fmi2Status *value) {
UNUSED(value);
ASSERT_STATE(GetStatus);
return getStatus("fmi2GetStatus", c, s);
}
fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real *value) {
ASSERT_STATE(GetRealStatus);
if (s == fmi2LastSuccessfulTime) {
*value = S->time;
return fmi2OK;
}
return getStatus("fmi2GetRealStatus", c, s);
}
fmi2Status fmi2GetIntegerStatus(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value) {
UNUSED(value);
ASSERT_STATE(GetIntegerStatus);
return getStatus("fmi2GetIntegerStatus", c, s);
}
fmi2Status fmi2GetBooleanStatus(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value) {
ASSERT_STATE(GetBooleanStatus);
if (s == fmi2Terminated) {
*value = S->terminateSimulation;
return fmi2OK;
}
return getStatus("fmi2GetBooleanStatus", c, s);
}
fmi2Status fmi2GetStringStatus(fmi2Component c, const fmi2StatusKind s, fmi2String *value) {
UNUSED(value);
ASSERT_STATE(GetStringStatus);
return getStatus("fmi2GetStringStatus", c, s);
}
// ---------------------------------------------------------------------------
// Functions for FMI2 for Model Exchange
// ---------------------------------------------------------------------------
/* Enter and exit the different modes */
fmi2Status fmi2EnterEventMode(fmi2Component c) {
ASSERT_STATE(EnterEventMode);
S->state = EventMode;
return fmi2OK;
}
fmi2Status fmi2NewDiscreteStates(fmi2Component c, fmi2EventInfo *eventInfo) {
ASSERT_STATE(NewDiscreteStates);
#ifdef EVENT_UPDATE
eventUpdate(S);
#endif
eventInfo->newDiscreteStatesNeeded = S->newDiscreteStatesNeeded;
eventInfo->terminateSimulation = S->terminateSimulation;
eventInfo->nominalsOfContinuousStatesChanged = S->nominalsOfContinuousStatesChanged;
eventInfo->valuesOfContinuousStatesChanged = S->valuesOfContinuousStatesChanged;
eventInfo->nextEventTimeDefined = S->nextEventTimeDefined;
eventInfo->nextEventTime = S->nextEventTime;
return fmi2OK;
}
fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c) {
ASSERT_STATE(EnterContinuousTimeMode);
S->state = ContinuousTimeMode;
return fmi2OK;
}
fmi2Status fmi2CompletedIntegratorStep(fmi2Component c, fmi2Boolean noSetFMUStatePriorToCurrentPoint,
fmi2Boolean *enterEventMode, fmi2Boolean *terminateSimulation) {
UNUSED(noSetFMUStatePriorToCurrentPoint);
ASSERT_STATE(CompletedIntegratorStep);
if (nullPointer(S, "fmi2CompletedIntegratorStep", "enterEventMode", enterEventMode))
return fmi2Error;
if (nullPointer(S, "fmi2CompletedIntegratorStep", "terminateSimulation", terminateSimulation))
return fmi2Error;
*enterEventMode = fmi2False;
*terminateSimulation = fmi2False;
return fmi2OK;
}
/* Providing independent variables and re-initialization of caching */
fmi2Status fmi2SetTime(fmi2Component c, fmi2Real time) {
ASSERT_STATE(SetTime);
S->time = time;
return fmi2OK;
}
fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t nx){
ASSERT_STATE(SetContinuousStates);
if (invalidNumber(S, "fmi2SetContinuousStates", "nx", nx, NX))
return fmi2Error;
if (nullPointer(S, "fmi2SetContinuousStates", "x[]", x))
return fmi2Error;
setContinuousStates(S, x, nx);
return fmi2OK;
}
/* Evaluation of the model equations */
fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx) {
ASSERT_STATE(GetDerivatives);
if (invalidNumber(S, "fmi2GetDerivatives", "nx", nx, NX))
return fmi2Error;
if (nullPointer(S, "fmi2GetDerivatives", "derivatives[]", derivatives))
return fmi2Error;
getDerivatives(S, derivatives, nx);
return fmi2OK;
}
fmi2Status fmi2GetEventIndicators(fmi2Component c, fmi2Real eventIndicators[], size_t ni) {
ASSERT_STATE(GetEventIndicators);
#if NZ > 0
if (invalidNumber(S, "fmi2GetEventIndicators", "ni", ni, NZ))
return fmi2Error;
getEventIndicators(S, eventIndicators, ni);
#else
UNUSED(c);
UNUSED(eventIndicators);
if (ni > 0) return fmi2Error;
#endif
return fmi2OK;
}
fmi2Status fmi2GetContinuousStates(fmi2Component c, fmi2Real states[], size_t nx) {
ASSERT_STATE(GetContinuousStates);
if (invalidNumber(S, "fmi2GetContinuousStates", "nx", nx, NX))
return fmi2Error;
if (nullPointer(S, "fmi2GetContinuousStates", "states[]", states))
return fmi2Error;
getContinuousStates(S, states, nx);
return fmi2OK;
}
fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c, fmi2Real x_nominal[], size_t nx) {
ASSERT_STATE(GetNominalsOfContinuousStates);
if (invalidNumber(S, "fmi2GetNominalContinuousStates", "nx", nx, NX))
return fmi2Error;
if (nullPointer(S, "fmi2GetNominalContinuousStates", "x_nominal[]", x_nominal))
return fmi2Error;
for (size_t i = 0; i < nx; i++)
x_nominal[i] = 1;
return fmi2OK;
}
)code";