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