/
fmusim.c
180 lines (156 loc) · 6.78 KB
/
fmusim.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include "fmusim.h"
#include "fmuio.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef _MSC_VER
#define TRUE 1
#define FALSE 0
#define min(a,b) (a>b ? b : a)
#endif
#define RESULT_FILE "result.csv"
// simulate the given FMU using the forward euler method.
// time events are processed by reducing step size to exactly hit tNext.
// state events are checked and fired only at the end of an Euler step.
// the simulator may therefore miss state events and fires state events typically too late.
int fmuSimulate(FMU* fmu, double tEnd, double h, fmiBoolean loggingOn, char separator) {
int i, n;
double dt, tPre;
fmiBoolean timeEvent, stateEvent, stepEvent;
double time;
int nx; // number of state variables
int nz; // number of state event indicators
double *x; // continuous states
double *xdot; // the crresponding derivatives in same order
double *z = NULL; // state event indicators
double *prez = NULL; // previous values of state event indicators
fmiEventInfo eventInfo; // updated by calls to initialize and eventUpdate
ModelDescription* md; // handle to the parsed XML file
const char* guid; // global unique id of the fmu
fmiCallbackFunctions callbacks; // called by the model during simulation
fmiComponent c; // instance of the fmu
fmiStatus fmiFlag; // return code of the fmu functions
fmiReal t0 = 0; // start time
fmiBoolean toleranceControlled = fmiFalse;
int nSteps = 0;
int nTimeEvents = 0;
int nStepEvents = 0;
int nStateEvents = 0;
FILE* file;
// instantiate the fmu
md = fmu->modelDescription;
guid = getString(md, att_guid);
callbacks.logger = fmuLogger;
callbacks.allocateMemory = calloc;
callbacks.freeMemory = free;
c = fmu->instantiateModel(getModelIdentifier(md), guid, callbacks, loggingOn);
if (!c) return fmuError("could not instantiate model");
// allocate memory
nx = getNumberOfStates(md);
nz = getNumberOfEventIndicators(md);
x = (double *) calloc(nx, sizeof(double));
xdot = (double *) calloc(nx, sizeof(double));
if (nz>0) {
z = (double *) calloc(nz, sizeof(double));
prez = (double *) calloc(nz, sizeof(double));
}
if (!x || !xdot || nz>0 && (!z || !prez)) return fmuError("out of memory");
// open result file
if (!(file=fopen(RESULT_FILE, "w"))) {
printf("could not write %s\n", RESULT_FILE);
return 0; // failure
}
// set the start time and initialize
time = t0;
fmiFlag = fmu->setTime(c, t0);
if (fmiFlag > fmiWarning) return fmuError("could not set time");
fmiFlag = fmu->initialize(c, toleranceControlled, t0, &eventInfo);
if (fmiFlag > fmiWarning) fmuError("could not initialize model");
if (eventInfo.terminateSimulation) {
printf("model requested termination at init");
tEnd = time;
}
// output solution for time t0
outputRow(fmu, c, t0, file, separator, TRUE); // output column names
outputRow(fmu, c, t0, file, separator, FALSE); // output values
// enter the simulation loop
while (time < tEnd) {
// get current state and derivatives
fmiFlag = fmu->getContinuousStates(c, x, nx);
if (fmiFlag > fmiWarning) return fmuError("could not retrieve states");
fmiFlag = fmu->getDerivatives(c, xdot, nx);
if (fmiFlag > fmiWarning) return fmuError("could not retrieve derivatives");
// advance time
tPre = time;
time = min(time+h, tEnd);
timeEvent = eventInfo.upcomingTimeEvent && eventInfo.nextEventTime < time;
if (timeEvent) time = eventInfo.nextEventTime;
dt = time - tPre;
fmiFlag = fmu->setTime(c, time);
if (fmiFlag > fmiWarning) fmuError("could not set time");
// perform one step
for (i=0; i<nx; i++) x[i] += dt*xdot[i]; // forward Euler method
fmiFlag = fmu->setContinuousStates(c, x, nx);
if (fmiFlag > fmiWarning) return fmuError("could not set states");
if (loggingOn) printf("Step %d to t=%.16g\n", nSteps, time);
// Check for step event, e.g. dynamic state selection
fmiFlag = fmu->completedIntegratorStep(c, &stepEvent);
if (fmiFlag > fmiWarning) return fmuError("could not complete intgrator step");
// Check for state event
for (i=0; i<nz; i++) prez[i] = z[i];
fmiFlag = fmu->getEventIndicators(c, z, nz);
if (fmiFlag > fmiWarning) return fmuError("could not retrieve event indicators");
stateEvent = FALSE;
for (i=0; i<nz; i++)
stateEvent = stateEvent || (prez[i] * z[i] < 0);
// handle events
if (timeEvent || stateEvent || stepEvent) {
if (timeEvent) {
nTimeEvents++;
if (loggingOn) printf("time event at t=%.16g\n", time);
}
if (stateEvent) {
nStateEvents++;
if (loggingOn) for (i=0; i<nz; i++)
printf("state event %s z[%d] at t=%.16g\n",
(prez[i]>0 && z[i]<0) ? "-\\-" : "-/-", i, time);
}
if (stepEvent) {
nStepEvents++;
if (loggingOn) printf("step event at t=%.16g\n", time);
}
// event iteration in one step, ignoring intermediate results
fmiFlag = fmu->eventUpdate(c, fmiFalse, &eventInfo);
if (fmiFlag > fmiWarning) return fmuError("could not perform event update");
// terminate simulation, if requested by the model
if (eventInfo.terminateSimulation) {
printf("model requested termination at t=%.16g\n", time);
break; // success
}
// check for change of value of states
if (eventInfo.stateValuesChanged && loggingOn) {
printf("state values changed at t=%.16g\n", time);
}
// check for selection of new state variables
if (eventInfo.stateValueReferencesChanged && loggingOn) {
printf("new state variables selected at t=%.16g\n", time);
}
} // if event
outputRow(fmu, c, time, file, separator, FALSE); // output values for this step
nSteps++;
} // while
// cleanup
fclose(file);
if (x!=NULL) free(x);
if (xdot!= NULL) free(xdot);
if (z!= NULL) free(z);
if (prez!= NULL) free(prez);
// print simulation summary
printf("Simulation from %g to %g terminated successful\n", t0, tEnd);
printf(" steps ............ %d\n", nSteps);
printf(" fixed step size .. %g\n", h);
printf(" time events ...... %d\n", nTimeEvents);
printf(" state events ..... %d\n", nStateEvents);
printf(" step events ...... %d\n", nStepEvents);
printf("CSV file '%s' written.\n", RESULT_FILE);
return 1; // success
}