casadi_fmu.hpp
1 //
2 // MIT No Attribution
3 //
4 // Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl, KU Leuven.
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy of this
7 // software and associated documentation files (the "Software"), to deal in the Software
8 // without restriction, including without limitation the rights to use, copy, modify,
9 // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
16 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 //
19 
20 typedef struct {
21  // Name of instance
22  const char* instance_name;
23  // Value for all variables
24  double v[SZ_MEM];
25  // Value for derivatives
26  double d[SZ_MEM];
27  // Has any variable been set since last call
29  // Buffers for evaluation generated code
30  double t;
31  double p[N_P];
32  double x[N_X];
33  double xdot[N_X];
34  double u[N_U];
35  double y[N_Y];
36  // Buffers for derivative calculations
37  double dp[N_P];
38  double dx[N_X];
39  double dxdot[N_X];
40  double du[N_U];
41  double dy[N_Y];
42  // Work vectors for evaluation
43  const double* arg[SZ_ARG];
44  double* res[SZ_RES];
45  casadi_int iw[SZ_IW];
46  double w[SZ_W];
48 
49 int evaluate(casadi_fmi_memory* m) {
50  // Local variables
51  size_t i;
52  int mem, flag;
53  // Copy states, inputs and parameters to input buffers
54  for (i = 0; i < N_X; ++i) m->x[i] = m->v[x_vr[i]];
55  for (i = 0; i < N_P; ++i) m->p[i] = m->v[p_vr[i]];
56  for (i = 0; i < N_U; ++i) m->u[i] = m->v[u_vr[i]];
57 
58  // Map inputs to evaluation buffer
59  i = 0;
60  m->arg[i++] = &m->t;
61  m->arg[i++] = m->x;
62  m->arg[i++] = m->p;
63  m->arg[i++] = m->u;
64 
65  // Map outputs to evaluation buffer
66  i = 0;
67  m->res[i++] = m->xdot;
68  m->res[i++] = m->y;
69 
70  // Evaluate
71  mem = MODELNAME_checkout();
72  flag = MODELNAME(m->arg, m->res, m->iw, m->w, mem);
73  MODELNAME_release(mem);
74 
75  // Copy from output buffers
76  for (i = 0; i < N_X; ++i) m->v[xdot_vr[i]] = m->xdot[i];
77  for (i = 0; i < N_Y; ++i) m->v[y_vr[i]] = m->y[i];
78 
79  return flag;
80 }
81 
82 int evaluate_forward(casadi_fmi_memory* m) {
83  // Local variables
84  size_t i;
85  int mem, flag;
86  // Copy seeds for states, inputs and parameters to input buffers
87  for (i = 0; i < N_X; ++i) m->dx[i] = m->d[x_vr[i]];
88  for (i = 0; i < N_P; ++i) m->dp[i] = m->d[p_vr[i]];
89  for (i = 0; i < N_U; ++i) m->du[i] = m->d[u_vr[i]];
90 
91  // Map nondifferentiated inputs to evaluation buffer
92  i = 0;
93  m->arg[i++] = 0; // t
94  m->arg[i++] = m->x;
95  m->arg[i++] = m->p;
96  m->arg[i++] = m->u;
97 
98  // Map nondifferentiated outputs to evaluation buffer
99  m->arg[i++] = m->xdot;
100  m->arg[i++] = m->y;
101 
102  // Map forward seeds
103  m->arg[i++] = 0;
104  m->arg[i++] = m->dx;
105  m->arg[i++] = m->dp;
106  m->arg[i++] = m->du;
107 
108  // Map forward sensitivities
109  i = 0;
110  m->res[i++] = m->dxdot;
111  m->res[i++] = m->dy;
112 
113  // Evaluate
114  mem = fwd1_MODELNAME_checkout();
115  flag = fwd1_MODELNAME(m->arg, m->res, m->iw, m->w, mem);
116  fwd1_MODELNAME_release(mem);
117 
118  // Copy from output buffers
119  for (i = 0; i < N_X; ++i) m->d[xdot_vr[i]] = m->dxdot[i];
120  for (i = 0; i < N_Y; ++i) m->d[y_vr[i]] = m->dy[i];
121 
122  // Return evaluation flag
123  return flag;
124 }
125 
126 int evaluate_adjoint(casadi_fmi_memory* m) {
127  // Local variables
128  size_t i;
129  int mem, flag;
130  // Copy seeds for output buffers
131  for (i = 0; i < N_X; ++i) m->dxdot[i] = m->d[xdot_vr[i]];
132  for (i = 0; i < N_Y; ++i) m->dy[i] = m->d[y_vr[i]];
133 
134  // Clear sensitivities
135  for (i = 0; i < N_X; ++i) m->dx[i] = 0;
136  for (i = 0; i < N_P; ++i) m->dp[i] = 0;
137  for (i = 0; i < N_U; ++i) m->du[i] = 0;
138 
139  // Map nondifferentiated inputs to evaluation buffer
140  i = 0;
141  m->arg[i++] = 0; // t
142  m->arg[i++] = m->x;
143  m->arg[i++] = m->p;
144  m->arg[i++] = m->u;
145 
146  // Map nondifferentiated outputs to evaluation buffer
147  m->arg[i++] = m->xdot;
148  m->arg[i++] = m->y;
149 
150  // Map adjoint seeds
151  m->arg[i++] = m->dxdot;
152  m->arg[i++] = m->dy;
153 
154  // Map adjoint sensitivities
155  i = 0;
156  m->res[i++] = 0; // t
157  m->res[i++] = m->dx;
158  m->res[i++] = m->dp;
159  m->res[i++] = m->du;
160 
161  // Evaluate
162  mem = adj1_MODELNAME_checkout();
163  flag = adj1_MODELNAME(m->arg, m->res, m->iw, m->w, mem);
164  adj1_MODELNAME_release(mem);
165 
166  // Copy from input buffers
167  for (i = 0; i < N_X; ++i) m->d[x_vr[i]] = m->dx[i];
168  for (i = 0; i < N_P; ++i) m->d[p_vr[i]] = m->dp[i];
169  for (i = 0; i < N_U; ++i) m->d[u_vr[i]] = m->du[i];
170 
171  // Return evaluation flag
172  return flag;
173 }
174 
175 FMI3_Export fmi3Status fmi3Reset(fmi3Instance instance) {
176  // Local variables
177  size_t i;
179  // Cast to memory struct
180  m = (casadi_fmi_memory*)instance;
181  // Initialize variables
182  for (i = 0; i < SZ_MEM; ++i) m->v[i] = start[i];
183  // Reset derivative buffer
184  for (i = 0; i < SZ_MEM; ++i) m->d[i] = 0;
185  // Not evaluated
186  m->up_to_date = 0;
187  // Always successful return
188  return fmi3OK;
189 }
190 
191 FMI3_Export fmi3Instance fmi3InstantiateModelExchange(
192  fmi3String instanceName,
193  fmi3String instantiationToken,
194  fmi3String resourcePath,
195  fmi3Boolean visible,
196  fmi3Boolean loggingOn,
197  fmi3InstanceEnvironment instanceEnvironment,
198  fmi3LogMessageCallback logMessage) {
199  // Local variables
201  // Unused variables
202  (void)resourcePath; // unused
203  (void)visible; // unused
204  (void)loggingOn; // unused
205  (void)instanceEnvironment; // unused
206  (void)logMessage; // unused
207  // Allocate memory structure
208  m = (casadi_fmi_memory*)malloc(sizeof(casadi_fmi_memory));
209  // If allocation was successful
210  if (m) {
211  // Increase counter for codegen
212  MODELNAME_incref();
213  // Copy meta data
214  m->instance_name = instanceName;
215  // Call reset function (return flag does not need to be checked)
216  (void)fmi3Reset(m);
217  }
218  // Return pointer to instance, or null
219  return m;
220 }
221 
222 FMI3_Export void fmi3FreeInstance(fmi3Instance instance) {
223  if (instance) {
224  // Free memory structure
225  free(instance);
226  // Decrease counter for codegen
227  MODELNAME_decref();
228  }
229 }
230 
231 FMI3_Export fmi3Status fmi3SetFloat64(
232  fmi3Instance instance,
233  const fmi3ValueReference valueReferences[],
234  size_t nValueReferences,
235  const fmi3Float64 values[],
236  size_t nValues) {
237  // Local variables
239  size_t i, j, var_off, var_sz, val_ind;
240  fmi3ValueReference vr;
241  // Cast to memory struct
242  m = (casadi_fmi_memory*)instance;
243  // Not evaluated
244  m->up_to_date = 0;
245  // Position in values vector
246  val_ind = 0;
247  // Loop over provided variables
248  for (i = 0; i < nValueReferences; ++i) {
249  // Get variable
250  vr = valueReferences[i];
251  // Get offset, size of variable
252  var_off = var_offset[vr];
253  var_sz = var_offset[vr + 1] - var_off;
254  // Copy elements
255  for (j = 0; j < var_sz; ++j) m->v[var_off + j] = values[val_ind++];
256  }
257  // Consistency check
258  if (val_ind != nValues) return fmi3Fatal;
259  // Successful return
260  return fmi3OK;
261 }
262 
263 FMI3_Export fmi3Status fmi3GetFloat64(
264  fmi3Instance instance,
265  const fmi3ValueReference valueReferences[],
266  size_t nValueReferences,
267  fmi3Float64 values[],
268  size_t nValues) {
269  // Local variables
271  size_t i, j, var_off, var_sz, val_ind;
272  fmi3ValueReference vr;
273  // Cast to memory struct
274  m = (casadi_fmi_memory*)instance;
275  // Evaluate, if necessary
276  if (!m->up_to_date) {
277  // Evaluate state derivatives and outputs
278  if (evaluate(m)) return fmi3Error;
279  // Now evaluated
280  m->up_to_date = 1;
281  }
282  // Position in values vector
283  val_ind = 0;
284  // Loop over provided variables
285  for (i = 0; i < nValueReferences; ++i) {
286  // Get variable
287  vr = valueReferences[i];
288  // Get offset, size of variable
289  var_off = var_offset[vr];
290  var_sz = var_offset[vr + 1] - var_off;
291  // Copy elements
292  for (j = 0; j < var_sz; ++j) values[val_ind++] = m->v[var_off + j];
293  }
294  // Consistency check
295  if (val_ind != nValues) return fmi3Fatal;
296  // Successful return
297  return fmi3OK;
298 }
299 
300 FMI3_Export fmi3Status fmi3EnterInitializationMode(
301  fmi3Instance instance,
302  fmi3Boolean toleranceDefined,
303  fmi3Float64 tolerance,
304  fmi3Float64 startTime,
305  fmi3Boolean stopTimeDefined,
306  fmi3Float64 stopTime) {
307  // Local variables
309  // Unused variables
310  (void)toleranceDefined; // unused
311  (void)tolerance; // unused
312  (void)stopTimeDefined; // unused
313  (void)stopTime; // unused
314  // Cast to memory struct
315  m = (casadi_fmi_memory*)instance;
316  // Initialize time
317  m->t = startTime;
318  // Always successful return
319  return fmi3OK;
320 }
321 
322 FMI3_Export fmi3Status fmi3ExitInitializationMode(fmi3Instance instance) {
323  // Unused variables
324  (void)instance; // unused
325  // Always successful return
326  return fmi3OK;
327 }
328 
329 FMI3_Export fmi3Status fmi3EnterContinuousTimeMode(fmi3Instance instance) {
330  // Unused variables
331  (void)instance; // unused
332  // Always successful return
333  return fmi3OK;
334 }
335 
336 FMI3_Export fmi3Status fmi3SetTime(fmi3Instance instance, fmi3Float64 time) {
337  // Local variables
339  // Cast to memory struct
340  m = (casadi_fmi_memory*)instance;
341  // Initialize time
342  m->t = time;
343  // Always successful return
344  return fmi3OK;
345 }
346 
347 FMI3_Export fmi3Status fmi3SetContinuousStates(
348  fmi3Instance instance,
349  const fmi3Float64 continuousStates[],
350  size_t nContinuousStates) {
351  return fmi3SetFloat64(instance, x_vr, N_X, continuousStates, nContinuousStates);
352 }
353 
354 FMI3_Export fmi3Status fmi3GetContinuousStates(
355  fmi3Instance instance,
356  fmi3Float64 continuousStates[],
357  size_t nContinuousStates) {
358  return fmi3GetFloat64(instance, x_vr, N_X, continuousStates, nContinuousStates);
359 }
360 
361 fmi3Status fmi3GetDirectionalDerivative(
362  fmi3Instance instance,
363  const fmi3ValueReference unknowns[],
364  size_t nUnknowns,
365  const fmi3ValueReference knowns[],
366  size_t nKnowns,
367  const fmi3Float64 seed[],
368  size_t nSeed,
369  fmi3Float64 sensitivity[],
370  size_t nSensitivity) {
371  // Local variables
373  size_t i, j, var_off, var_sz, val_ind;
374  fmi3ValueReference vr;
375  int flag;
376  // Cast to memory struct
377  m = (casadi_fmi_memory*)instance;
378  // Evaluate, if necessary
379  if (!m->up_to_date) {
380  // Evaluate state derivatives and outputs
381  if (evaluate(m)) return fmi3Error;
382  // Now evaluated
383  m->up_to_date = 1;
384  }
385  // Pass derivative seeds
386  val_ind = 0;
387  for (i = 0; i < nKnowns; ++i) {
388  // Get variable
389  vr = knowns[i];
390  // Get offset, size of variable
391  var_off = var_offset[vr];
392  var_sz = var_offset[vr + 1] - var_off;
393  // Copy elements
394  for (j = 0; j < var_sz; ++j) m->d[var_off + j] = seed[val_ind++];
395  }
396  // Consistency check
397  if (val_ind != nSeed) return fmi3Fatal;
398  // Evaluate forward directional derivatives
399  flag = evaluate_forward(m);
400  // Collect sensitivities
401  val_ind = 0;
402  for (i = 0; i < nUnknowns; ++i) {
403  // Get variable
404  vr = unknowns[i];
405  // Get offset, size of variable
406  var_off = var_offset[vr];
407  var_sz = var_offset[vr + 1] - var_off;
408  // Copy elements, clear d
409  for (j = 0; j < var_sz; ++j) {
410  sensitivity[val_ind++] = m->d[var_off + j];
411  m->d[var_off + j] = 0;
412  }
413  }
414  // Consistency check
415  if (val_ind != nSensitivity) return fmi3Fatal;
416  // Clear derivative seeds
417  val_ind = 0;
418  for (i = 0; i < nKnowns; ++i) {
419  // Get variable
420  vr = knowns[i];
421  // Get offset, size of variable
422  var_off = var_offset[vr];
423  var_sz = var_offset[vr + 1] - var_off;
424  // Clear elements
425  for (j = 0; j < var_sz; ++j) m->d[var_off + j] = 0;
426  }
427  // Check for evaluation error
428  if (flag) return fmi3Error;
429  // Successful return
430  return fmi3OK;
431 }
432 
433 fmi3Status fmi3GetAdjointDerivative(
434  fmi3Instance instance,
435  const fmi3ValueReference unknowns[],
436  size_t nUnknowns,
437  const fmi3ValueReference knowns[],
438  size_t nKnowns,
439  const fmi3Float64 seed[],
440  size_t nSeed,
441  fmi3Float64 sensitivity[],
442  size_t nSensitivity) {
443  // Local variables
445  size_t i, j, var_off, var_sz, val_ind;
446  fmi3ValueReference vr;
447  int flag;
448  // Cast to memory struct
449  m = (casadi_fmi_memory*)instance;
450  // Evaluate, if necessary
451  if (!m->up_to_date) {
452  // Evaluate state derivatives and outputs
453  if (evaluate(m)) return fmi3Error;
454  // Now evaluated
455  m->up_to_date = 1;
456  }
457  // Pass derivative seeds
458  val_ind = 0;
459  for (i = 0; i < nUnknowns; ++i) {
460  // Get variable
461  vr = unknowns[i];
462  // Get offset, size of variable
463  var_off = var_offset[vr];
464  var_sz = var_offset[vr + 1] - var_off;
465  // Copy elements
466  for (j = 0; j < var_sz; ++j) m->d[var_off + j] = seed[val_ind++];
467  }
468  // Consistency check
469  if (val_ind != nSeed) return fmi3Fatal;
470  // Evaluate adjoint directional derivatives
471  flag = evaluate_adjoint(m);
472  // Collect sensitivities
473  val_ind = 0;
474  for (i = 0; i < nKnowns; ++i) {
475  // Get variable
476  vr = knowns[i];
477  // Get offset, size of variable
478  var_off = var_offset[vr];
479  var_sz = var_offset[vr + 1] - var_off;
480  // Copy elements, clear d
481  for (j = 0; j < var_sz; ++j) {
482  sensitivity[val_ind++] = m->d[var_off + j];
483  m->d[var_off + j] = 0;
484  }
485  }
486  // Consistency check
487  if (val_ind != nSensitivity) return fmi3Fatal;
488  // Clear derivative seeds
489  val_ind = 0;
490  for (i = 0; i < nUnknowns; ++i) {
491  // Get variable
492  vr = unknowns[i];
493  // Get offset, size of variable
494  var_off = var_offset[vr];
495  var_sz = var_offset[vr + 1] - var_off;
496  // Clear elements
497  for (j = 0; j < var_sz; ++j) m->d[var_off + j] = 0;
498  }
499  // Check for evaluation error
500  if (flag) return fmi3Error;
501  // Successful return
502  return fmi3OK;
503 }
double d[SZ_MEM]
Definition: casadi_fmu.hpp:26
double p[N_P]
Definition: casadi_fmu.hpp:31
double du[N_U]
Definition: casadi_fmu.hpp:40
double u[N_U]
Definition: casadi_fmu.hpp:34
casadi_int iw[SZ_IW]
Definition: casadi_fmu.hpp:45
double x[N_X]
Definition: casadi_fmu.hpp:32
const char * instance_name
Definition: casadi_fmu.hpp:22
double dx[N_X]
Definition: casadi_fmu.hpp:38
double w[SZ_W]
Definition: casadi_fmu.hpp:46
double v[SZ_MEM]
Definition: casadi_fmu.hpp:24
double * res[SZ_RES]
Definition: casadi_fmu.hpp:44
double dy[N_Y]
Definition: casadi_fmu.hpp:41
double dp[N_P]
Definition: casadi_fmu.hpp:37
double xdot[N_X]
Definition: casadi_fmu.hpp:33
double y[N_Y]
Definition: casadi_fmu.hpp:35
const double * arg[SZ_ARG]
Definition: casadi_fmu.hpp:43
double dxdot[N_X]
Definition: casadi_fmu.hpp:39