adevs
adevs_fmi.h
1 
31 #ifndef _adevs_fmi_h_
32 #define _adevs_fmi_h_
33 #include <algorithm>
34 #include <cmath>
35 #include <iostream>
36 #include <cstdlib>
37 #include <cstdio>
38 #include <cassert>
39 #include "adevs_hybrid.h"
40 #include "fmi2Functions.h"
41 #include "fmi2FunctionTypes.h"
42 #include "fmi2TypesPlatform.h"
43 
44 // Functions for loading DLL and so files
45 #ifdef _WIN32
46 #include <windows.h>
47 #define OPEN_LIB(name) LoadLibrary(name)
48 #define GET_FUNC(hndl,name) GetProcAddress(hndl,name)
49 #define CLOSE_LIB(hndl) FreeLibrary(hndl)
50 #else
51 #include <dlfcn.h>
52 #define OPEN_LIB(name) dlopen(name,RTLD_LAZY)
53 #define GET_FUNC(hndl,name) dlsym(hndl,name)
54 #define CLOSE_LIB(hndl) dlclose(hndl)
55 #endif
56 
57 namespace adevs
58 {
59 
71 template <typename X> class FMI:
72  public ode_system<X>
73 {
74  public:
81  FMI(const char* modelname,
82  const char* guid,
83  int num_state_variables,
84  int num_event_indicators,
85  const char* shared_lib_name,
86  const double tolerance = 1E-8,
87  int num_extra_event_indicators = 0,
88  double start_time = 0.0);
90  virtual void init(double* q);
92  virtual void der_func(const double* q, double* dq);
94  virtual void state_event_func(const double* q, double* z);
96  virtual double time_event_func(const double* q);
102  virtual void postStep(double* q);
103  virtual void postTrialStep(double* q);
110  virtual void internal_event(double* q,
111  const bool* state_event);
116  virtual void external_event(double* q, double e,
117  const Bag<X>& xb);
122  virtual void confluent_event(double *q, const bool* state_event,
123  const Bag<X>& xb);
128  virtual void output_func(const double *q, const bool* state_event,
129  Bag<X>& yb);
134  virtual void gc_output(Bag<X>& gb);
136  virtual ~FMI();
137  // Get the current time
138  double get_time() const { return t_now; }
139  // Get the value of a real variable
140  double get_real(int k);
141  // Set the value of a real variable
142  void set_real(int k, double val);
143  // Get the value of an integer variable
144  int get_int(int k);
145  // Set the value of an integer variable
146  void set_int(int k, int val);
147  // Get the value of a boolean variable
148  bool get_bool(int k);
149  // Set the value of a boolean variable
150  void set_bool(int k, bool val);
151  // Get the value of a string variable
152  std::string get_string(int k);
153  // Set the value of a string variable
154  void set_string(int k, std::string& val);
155  private:
156  // Reference to the FMI
157  fmi2Component c;
158  // Pointer to the FMI interface
159  fmi2Component (*_fmi2Instantiate)(fmi2String, fmi2Type,
160  fmi2String, fmi2String, const fmi2CallbackFunctions*,
161  fmi2Boolean, fmi2Boolean);
162  void (*_fmi2FreeInstance)(fmi2Component);
163  fmi2Status (*_fmi2SetupExperiment)(fmi2Component, fmi2Boolean,
164  fmi2Real, fmi2Real, fmi2Boolean, fmi2Real);
165  fmi2Status (*_fmi2EnterInitializationMode)(fmi2Component);
166  fmi2Status (*_fmi2ExitInitializationMode)(fmi2Component);
167  fmi2Status (*_fmi2GetReal)(fmi2Component, const fmi2ValueReference*, size_t, fmi2Real*);
168  fmi2Status (*_fmi2GetInteger)(fmi2Component, const fmi2ValueReference*, size_t, fmi2Integer*);
169  fmi2Status (*_fmi2GetBoolean)(fmi2Component, const fmi2ValueReference*, size_t, fmi2Boolean*);
170  fmi2Status (*_fmi2GetString)(fmi2Component, const fmi2ValueReference*, size_t, fmi2String*);
171  fmi2Status (*_fmi2SetReal)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2Real*);
172  fmi2Status (*_fmi2SetInteger)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2Integer*);
173  fmi2Status (*_fmi2SetBoolean)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2Boolean*);
174  fmi2Status (*_fmi2SetString)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2String*);
175  fmi2Status (*_fmi2EnterEventMode)(fmi2Component);
176  fmi2Status (*_fmi2NewDiscreteStates)(fmi2Component,fmi2EventInfo*);
177  fmi2Status (*_fmi2EnterContinuousTimeMode)(fmi2Component);
178  fmi2Status (*_fmi2CompletedIntegratorStep)(fmi2Component, fmi2Boolean, fmi2Boolean*, fmi2Boolean*);
179  fmi2Status (*_fmi2SetTime)(fmi2Component, fmi2Real);
180  fmi2Status (*_fmi2SetContinuousStates)(fmi2Component, const fmi2Real*, size_t);
181  fmi2Status (*_fmi2GetDerivatives)(fmi2Component, fmi2Real*, size_t);
182  fmi2Status (*_fmi2GetEventIndicators)(fmi2Component, fmi2Real*, size_t);
183  fmi2Status (*_fmi2GetContinuousStates)(fmi2Component, fmi2Real*, size_t);
184 
185  // Instant of the next time event
186  double next_time_event;
187  // Current time
188  double t_now;
189  // so library handle
190  #ifdef _WIN32
191  HINSTANCE so_hndl;
192  #else
193  void* so_hndl;
194  #endif
195  // Are we in continuous time mode?
196  bool cont_time_mode;
197  // Number of event indicators that are not governed by the FMI
198  int num_extra_event_indicators;
199  // Start time of the simulation
200  double start_time;
201 
202  static void fmilogger(
203  fmi2ComponentEnvironment componentEnvironment,
204  fmi2String instanceName,
205  fmi2Status status,
206  fmi2String category,
207  fmi2String message,...)
208  {
209  if (message != NULL){
210 
211  fprintf(stderr, message,"\n");
212  }
213  }
214 
215  fmi2CallbackFunctions* callbackFuncs;
216 
217  void iterate_events();
218 };
219 
220 template <typename X>
221 FMI<X>::FMI(const char* modelname,
222  const char* guid,
223  int num_state_variables,
224  int num_event_indicators,
225  const char* so_file_name,
226  const double tolerance,
227  int num_extra_event_indicators,
228  double start_time):
229  // One extra variable at the end for time
230  ode_system<X>(num_state_variables+1,num_event_indicators+num_extra_event_indicators),
231  next_time_event(adevs_inf<double>()),
232  t_now(start_time),
233  so_hndl(NULL),
234  cont_time_mode(false),
235  num_extra_event_indicators(num_extra_event_indicators)
236 {
237  fmi2CallbackFunctions tmp = {adevs::FMI<X>::fmilogger,calloc,free,NULL,NULL};
238  callbackFuncs = new fmi2CallbackFunctions(tmp);
239  so_hndl = OPEN_LIB(so_file_name);
240  if (so_hndl == NULL)
241  {
242  throw adevs::exception("Could not load so file",this);
243  }
244  // This only works with a POSIX compliant compiler/system
245  _fmi2Instantiate = (fmi2Component (*)(fmi2String, fmi2Type,
246  fmi2String, fmi2String, const fmi2CallbackFunctions*,
247  fmi2Boolean, fmi2Boolean))GET_FUNC(so_hndl,"fmi2Instantiate");
248  assert(_fmi2Instantiate != NULL);
249  _fmi2FreeInstance = (void (*)(fmi2Component))GET_FUNC(so_hndl,"fmi2FreeInstance");
250  assert(_fmi2FreeInstance != NULL);
251  _fmi2SetupExperiment = (fmi2Status (*)(fmi2Component, fmi2Boolean,
252  fmi2Real, fmi2Real, fmi2Boolean, fmi2Real))GET_FUNC(so_hndl,"fmi2SetupExperiment");
253  assert(_fmi2SetupExperiment != NULL);
254  _fmi2EnterInitializationMode = (fmi2Status (*)(fmi2Component))GET_FUNC(so_hndl,"fmi2EnterInitializationMode");
255  assert(_fmi2EnterInitializationMode != NULL);
256  _fmi2ExitInitializationMode = (fmi2Status (*)(fmi2Component))GET_FUNC(so_hndl,"fmi2ExitInitializationMode");
257  assert(_fmi2ExitInitializationMode != NULL);
258  _fmi2GetReal = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, fmi2Real*))
259  GET_FUNC(so_hndl,"fmi2GetReal");
260  assert(_fmi2GetReal != NULL);
261  _fmi2GetInteger = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, fmi2Integer*))
262  GET_FUNC(so_hndl,"fmi2GetInteger");
263  assert(_fmi2GetInteger != NULL);
264  _fmi2GetBoolean = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, fmi2Boolean*))
265  GET_FUNC(so_hndl,"fmi2GetBoolean");
266  assert(_fmi2GetBoolean != NULL);
267  _fmi2GetString = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, fmi2String*))
268  GET_FUNC(so_hndl,"fmi2GetString");
269  assert(_fmi2GetString != NULL);
270  _fmi2SetReal = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2Real*))
271  GET_FUNC(so_hndl,"fmi2SetReal");
272  assert(_fmi2SetReal != NULL);
273  _fmi2SetInteger = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2Integer*))
274  GET_FUNC(so_hndl,"fmi2SetInteger");
275  assert(_fmi2SetInteger != NULL);
276  _fmi2SetBoolean = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2Boolean*))
277  GET_FUNC(so_hndl,"fmi2SetBoolean");
278  assert(_fmi2SetBoolean != NULL);
279  _fmi2SetString = (fmi2Status (*)(fmi2Component, const fmi2ValueReference*, size_t, const fmi2String*))
280  GET_FUNC(so_hndl,"fmi2SetString");
281  assert(_fmi2SetString != NULL);
282  _fmi2EnterEventMode = (fmi2Status (*)(fmi2Component))GET_FUNC(so_hndl,"fmi2EnterEventMode");
283  assert(_fmi2EnterEventMode != NULL);
284  _fmi2NewDiscreteStates = (fmi2Status (*)(fmi2Component,fmi2EventInfo*))GET_FUNC(so_hndl,"fmi2NewDiscreteStates");
285  assert(_fmi2NewDiscreteStates != NULL);
286  _fmi2EnterContinuousTimeMode = (fmi2Status (*)(fmi2Component))GET_FUNC(so_hndl,"fmi2EnterContinuousTimeMode");
287  assert(_fmi2EnterContinuousTimeMode != NULL);
288  _fmi2CompletedIntegratorStep = (fmi2Status (*)(fmi2Component, fmi2Boolean, fmi2Boolean*, fmi2Boolean*))
289  GET_FUNC(so_hndl,"fmi2CompletedIntegratorStep");
290  assert(_fmi2CompletedIntegratorStep != NULL);
291  _fmi2SetTime = (fmi2Status (*)(fmi2Component, fmi2Real))GET_FUNC(so_hndl,"fmi2SetTime");
292  assert(_fmi2SetTime != NULL);
293  _fmi2SetContinuousStates = (fmi2Status (*)(fmi2Component, const fmi2Real*, size_t))
294  GET_FUNC(so_hndl,"fmi2SetContinuousStates");
295  assert(_fmi2SetContinuousStates != NULL);
296  _fmi2GetDerivatives = (fmi2Status (*)(fmi2Component, fmi2Real*, size_t))GET_FUNC(so_hndl,"fmi2GetDerivatives");
297  assert(_fmi2GetDerivatives != NULL);
298  _fmi2GetEventIndicators = (fmi2Status (*)(fmi2Component, fmi2Real*, size_t))GET_FUNC(so_hndl,"fmi2GetEventIndicators");
299  assert(_fmi2GetEventIndicators != NULL);
300  _fmi2GetContinuousStates = (fmi2Status (*)(fmi2Component, fmi2Real*, size_t))GET_FUNC(so_hndl,"fmi2GetContinuousStates");
301  assert(_fmi2GetContinuousStates != NULL);
302  // Create the FMI component
303  c = _fmi2Instantiate(modelname,fmi2ModelExchange,guid,"",callbackFuncs,fmi2False,fmi2False);
304  assert(c != NULL);
305  _fmi2SetupExperiment(c,fmi2True,tolerance,-1.0,fmi2False,-1.0);
306 }
307 
308 template <typename X>
310 {
311  fmi2Status status;
312  // Put into consistent initial state
313  fmi2EventInfo eventInfo;
314  do
315  {
316  status = _fmi2NewDiscreteStates(c,&eventInfo);
317  assert(status == fmi2OK);
318  }
319  while (eventInfo.newDiscreteStatesNeeded == fmi2True);
320  if (eventInfo.nextEventTimeDefined == fmi2True)
321  next_time_event = eventInfo.nextEventTime;
322  assert(status == fmi2OK);
323 }
324 
325 template <typename X>
326 void FMI<X>::init(double* q)
327 {
328  fmi2Status status;
329  // Set initial value for time
330  status = _fmi2SetTime(c,t_now);
331  assert(status == fmi2OK);
332  // Initialize all variables
333  status = _fmi2EnterInitializationMode(c);
334  assert(status == fmi2OK);
335  // Done with initialization
336  status = _fmi2ExitInitializationMode(c);
337  assert(status == fmi2OK);
338  // Put into consistent initial state
339  iterate_events();
340  // Enter continuous time mode to start integration
341  status = _fmi2EnterContinuousTimeMode(c);
342  assert(status == fmi2OK);
343  status = _fmi2GetContinuousStates(c,q,this->numVars()-1);
344  assert(status == fmi2OK);
345  q[this->numVars()-1] = t_now;
346  cont_time_mode = true;
347 }
348 
349 template <typename X>
350 void FMI<X>::der_func(const double* q, double* dq)
351 {
352  fmi2Status status;
353  if (!cont_time_mode)
354  {
355  status = _fmi2EnterContinuousTimeMode(c);
356  assert(status == fmi2OK);
357  cont_time_mode = true;
358  }
359  status =_fmi2SetTime(c,q[this->numVars()-1]);
360  assert(status == fmi2OK);
361  status = _fmi2SetContinuousStates(c,q,this->numVars()-1);
362  assert(status == fmi2OK);
363  status = _fmi2GetDerivatives(c,dq,this->numVars()-1);
364  assert(status == fmi2OK);
365  dq[this->numVars()-1] = 1.0;
366 }
367 
368 template <typename X>
369 void FMI<X>::state_event_func(const double* q, double* z)
370 {
371  fmi2Status status;
372  if (!cont_time_mode)
373  {
374  status = _fmi2EnterContinuousTimeMode(c);
375  assert(status == fmi2OK);
376  cont_time_mode = true;
377  }
378  status = _fmi2SetTime(c,q[this->numVars()-1]);
379  assert(status == fmi2OK);
380  status = _fmi2SetContinuousStates(c,q,this->numVars()-1);
381  assert(status == fmi2OK);
382  status = _fmi2GetEventIndicators(c,z,this->numEvents()-num_extra_event_indicators);
383  assert(status == fmi2OK);
384 }
385 
386 template <typename X>
387 double FMI<X>::time_event_func(const double* q)
388 {
389  return next_time_event-q[this->numVars()-1];
390 }
391 
392 template <typename X>
393 void FMI<X>::postStep(double* q)
394 {
395  assert(cont_time_mode);
396  // Don't advance the FMI state by zero units of time
397  // when in continuous mode
398  if (q[this->numVars()-1] <= t_now)
399  return;
400  // Try to complete the integration step
401  fmi2Status status;
402  fmi2Boolean enterEventMode;
403  fmi2Boolean terminateSimulation;
404  t_now = q[this->numVars()-1];
405  status = _fmi2SetTime(c,t_now);
406  assert(status == fmi2OK);
407  status = _fmi2SetContinuousStates(c,q,this->numVars()-1);
408  assert(status == fmi2OK);
409  status = _fmi2CompletedIntegratorStep(c,fmi2True,&enterEventMode,&terminateSimulation);
410  assert(status == fmi2OK);
411  // Force an event if one is indicated
412  if (enterEventMode == fmi2True)
413  next_time_event = t_now;
414 }
415 
416 template <typename X>
417 void FMI<X>::postTrialStep(double* q)
418 {
419  assert(cont_time_mode);
420  // Restore values changed by der_func and state_event_func
421  fmi2Status status;
422  status = _fmi2SetTime(c,q[this->numVars()]-1);
423  assert(status == fmi2OK);
424  status = _fmi2SetContinuousStates(c,q,this->numVars()-1);
425  assert(status == fmi2OK);
426 }
427 
428 template <typename X>
429 void FMI<X>::internal_event(double* q, const bool* state_event)
430 {
431  fmi2Status status;
432  // postStep will have updated the continuous variables, so
433  // we just process discrete events here.
434  if (cont_time_mode)
435  {
436  status = _fmi2EnterEventMode(c);
437  assert(status == fmi2OK);
438  cont_time_mode = false;
439  }
440  // Process events
441  iterate_events();
442  // Update the state variable array
443  status = _fmi2GetContinuousStates(c,q,this->numVars()-1);
444  assert(status == fmi2OK);
445 }
446 
447 template <typename X>
448 void FMI<X>::external_event(double* q, double e, const Bag<X>& xb)
449 {
450  fmi2Status status;
451  // Go to event mode if we have not yet done so
452  if (cont_time_mode)
453  {
454  status = _fmi2EnterEventMode(c);
455  assert(status == fmi2OK);
456  cont_time_mode = false;
457  }
458  // process any events that need processing
459  iterate_events();
460  status = _fmi2GetContinuousStates(c,q,this->numVars()-1);
461  assert(status == fmi2OK);
462 }
463 
464 template <typename X>
465 void FMI<X>::confluent_event(double *q, const bool* state_event, const Bag<X>& xb)
466 {
467  fmi2Status status;
468  // postStep will have updated the continuous variables, so
469  // we just process discrete events here.
470  if (cont_time_mode)
471  {
472  status = _fmi2EnterEventMode(c);
473  assert(status == fmi2OK);
474  cont_time_mode = false;
475  }
476  iterate_events();
477  status = _fmi2GetContinuousStates(c,q,this->numVars()-1);
478  assert(status == fmi2OK);
479 }
480 
481 template <typename X>
482 void FMI<X>::output_func(const double *q, const bool* state_event, Bag<X>& yb)
483 {
484 }
485 
486 template <typename X>
488 {
489 }
490 
491 template <typename X>
493 {
494  _fmi2FreeInstance(c);
495  delete callbackFuncs;
496  CLOSE_LIB(so_hndl);
497 }
498 
499 template <typename X>
500 double FMI<X>::get_real(int k)
501 {
502  const fmi2ValueReference ref = k;
503  fmi2Real val;
504  fmi2Status status = _fmi2GetReal(c,&ref,1,&val);
505  assert(status == fmi2OK);
506  return val;
507 }
508 
509 template <typename X>
510 void FMI<X>::set_real(int k, double val)
511 {
512  const fmi2ValueReference ref = k;
513  fmi2Real fmi_val = val;
514  fmi2Status status = _fmi2SetReal(c,&ref,1,&fmi_val);
515  assert(status == fmi2OK);
516 }
517 
518 template <typename X>
519 int FMI<X>::get_int(int k)
520 {
521  const fmi2ValueReference ref = k;
522  fmi2Integer val;
523  fmi2Status status = _fmi2GetInteger(c,&ref,1,&val);
524  assert(status == fmi2OK);
525  return val;
526 }
527 
528 template <typename X>
529 void FMI<X>::set_int(int k, int val)
530 {
531  const fmi2ValueReference ref = k;
532  fmi2Integer fmi_val = val;
533  fmi2Status status = _fmi2SetInteger(c,&ref,1,&fmi_val);
534  assert(status == fmi2OK);
535 }
536 
537 template <typename X>
538 bool FMI<X>::get_bool(int k)
539 {
540  const fmi2ValueReference ref = k;
541  fmi2Boolean val;
542  fmi2Status status = _fmi2GetBoolean(c,&ref,1,&val);
543  assert(status == fmi2OK);
544  return (val == fmi2True);
545 }
546 
547 template <typename X>
548 void FMI<X>::set_bool(int k, bool val)
549 {
550  const fmi2ValueReference ref = k;
551  fmi2Boolean fmi_val = fmi2False;
552  if (val) fmi_val = fmi2True;
553  fmi2Status status = _fmi2SetBoolean(c,&ref,1,&fmi_val);
554  assert(status == fmi2OK);
555 }
556 
557 template <typename X>
558 std::string FMI<X>::get_string(int k)
559 {
560  const fmi2ValueReference ref = k;
561  fmi2String val;
562  fmi2Status status = _fmi2GetString(c,&ref,1,&val);
563  assert(status == fmi2OK);
564  return val;
565 }
566 
567 template <typename X>
568 void FMI<X>::set_string(int k, std::string& val)
569 {
570  const fmi2ValueReference ref = k;
571  fmi2String fmi_val = fmi2False;
572  fmi2Status status = _fmi2SetString(c,&ref,1,&fmi_val);
573  assert(status == fmi2OK);
574 }
575 
576 } // end of namespace
577 
578 #endif
virtual void confluent_event(double *q, const bool *state_event, const Bag< X > &xb)
Definition: adevs_fmi.h:465
int numEvents() const
Get the number of state events.
Definition: adevs_hybrid.h:54
virtual void internal_event(double *q, const bool *state_event)
Definition: adevs_fmi.h:429
virtual void state_event_func(const double *q, double *z)
Compute the state event functions for state q and put them in z.
Definition: adevs_fmi.h:369
virtual void gc_output(Bag< X > &gb)
Definition: adevs_fmi.h:487
virtual double time_event_func(const double *q)
Compute the time event function using state q.
Definition: adevs_fmi.h:387
virtual void init(double *q)
Copy the initial state of the model to q.
Definition: adevs_fmi.h:326
Definition: adevs_exception.h:43
Definition: adevs_fmi.h:71
int numVars() const
Get the number of state variables.
Definition: adevs_hybrid.h:52
virtual void postStep(double *q)
Definition: adevs_fmi.h:393
Definition: adevs_fmi.h:57
virtual void postTrialStep(double *q)
Definition: adevs_fmi.h:417
virtual void external_event(double *q, double e, const Bag< X > &xb)
Definition: adevs_fmi.h:448
virtual void der_func(const double *q, double *dq)
Compute the derivative for state q and put it in dq.
Definition: adevs_fmi.h:350
FMI(const char *modelname, const char *guid, int num_state_variables, int num_event_indicators, const char *shared_lib_name, const double tolerance=1E-8, int num_extra_event_indicators=0, double start_time=0.0)
Definition: adevs_fmi.h:221
virtual void output_func(const double *q, const bool *state_event, Bag< X > &yb)
Definition: adevs_fmi.h:482
virtual ~FMI()
Destructor.
Definition: adevs_fmi.h:492
Definition: adevs_hybrid.h:45