Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,598 @@
#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
}
}

View File

@@ -0,0 +1,887 @@
#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;
}
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;
}