FMI Library: part of JModelica.org
fmi_import_me_test.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 Modelon AB
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the BSD style license.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  FMILIB_License.txt file for more details.
11 
12  You should have received a copy of the FMILIB_License.txt file
13  along with this program. If not, contact Modelon AB <http://www.modelon.com>.
14 */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 
20 #include "config_test.h"
21 #include <fmilib.h>
22 
23 #define BUFFER 1000
24 
25 void do_exit(int code)
26 {
27  printf("Press 'Enter' to exit\n");
28  /* getchar(); */
29  exit(code);
30 }
31 
33 {
34  fmi1_status_t fmistatus;
35  jm_status_enu_t jmstatus;
36  fmi1_real_t tstart = 0.0;
37  fmi1_real_t tcur;
38  fmi1_real_t hcur;
39  fmi1_real_t hdef = 0.1;
40  fmi1_real_t tend = 2.0;
41  size_t n_states;
42  size_t n_event_indicators;
43  fmi1_real_t* states;
44  fmi1_real_t states_end_results[] = {0.362000, -3.962000};
45  fmi1_real_t* states_der;
46  fmi1_real_t* event_indicators;
47  fmi1_real_t* event_indicators_prev;
48  fmi1_boolean_t callEventUpdate;
49  fmi1_boolean_t toleranceControlled = fmi1_true;
50  fmi1_real_t relativeTolerance = 0.001;
51  fmi1_event_info_t eventInfo;
52  fmi1_boolean_t intermediateResults = fmi1_false;
53  size_t k;
54 
55  printf("Version returned from FMU: %s\n", fmi1_import_get_version(fmu));
56  printf("Platform type returned: %s\n", fmi1_import_get_model_types_platform(fmu));
57 
59  n_event_indicators = fmi1_import_get_number_of_event_indicators(fmu);
60 
61  if (sizeof(states_end_results)/sizeof(fmi1_real_t) != n_states) {
62  printf("Number of states and results have different length n_states = %u n_results = %u\n", (unsigned)n_states, (unsigned)sizeof(states_end_results));
63  do_exit(CTEST_RETURN_FAIL);
64  }
65 
66  states = calloc(n_states, sizeof(double));
67  states_der = calloc(n_states, sizeof(double));
68  event_indicators = calloc(n_event_indicators, sizeof(double));
69  event_indicators_prev = calloc(n_event_indicators, sizeof(double));
70 
71  jmstatus = fmi1_import_instantiate_model(fmu, "Test ME model instance");
72  if (jmstatus == jm_status_error) {
73  printf("fmi1_import_instantiate_model failed\n");
74  do_exit(CTEST_RETURN_FAIL);
75  }
76 
77  fmistatus = fmi1_import_set_time(fmu, tstart);
78 
79  fmistatus = fmi1_import_initialize(fmu, toleranceControlled, relativeTolerance, &eventInfo);
80 
81  fmistatus = fmi1_import_get_continuous_states(fmu, states, n_states);
82  fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators_prev, n_event_indicators);
83 
84  fmistatus = fmi1_import_set_debug_logging(fmu, fmi1_false);
85  printf("fmi1_import_set_debug_logging: %s\n", fmi1_status_to_string(fmistatus));
87 
88  tcur = tstart;
89  hcur = hdef;
90  callEventUpdate = fmi1_false;
91 
92  while (tcur < tend) {
93  size_t k;
94  int zero_crossning_event = 0;
95 
96  fmistatus = fmi1_import_set_time(fmu, tcur);
97  fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators, n_event_indicators);
98 
99  /* Check if an event inidcator has triggered */
100  for (k = 0; k < n_event_indicators; k++) {
101  if (event_indicators[k]*event_indicators_prev[k] < 0) {
102  zero_crossning_event = 1;
103  break;
104  }
105  }
106 
107  /* Handle any events */
108  if (callEventUpdate || zero_crossning_event || (eventInfo.upcomingTimeEvent && tcur == eventInfo.nextEventTime)) {
109  fmistatus = fmi1_import_eventUpdate(fmu, intermediateResults, &eventInfo);
110  fmistatus = fmi1_import_get_continuous_states(fmu, states, n_states);
111  fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators, n_event_indicators);
112  fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators_prev, n_event_indicators);
113  }
114 
115  /* Updated next time step */
116  if (eventInfo.upcomingTimeEvent) {
117  if (tcur + hdef < eventInfo.nextEventTime) {
118  hcur = hdef;
119  } else {
120  hcur = eventInfo.nextEventTime - tcur;
121  }
122  } else {
123  hcur = hdef;
124  }
125  tcur += hcur;
126  if(tcur > tend - hcur/1e16) {
127  tcur -= hcur;
128  hcur = (tend - tcur);
129  tcur = tend;
130  }
131  /* Integrate a step */
132  fmistatus = fmi1_import_get_derivatives(fmu, states_der, n_states);
133  for (k = 0; k < n_states; k++) {
134  states[k] = states[k] + hcur*states_der[k];
135  if (k == 0) printf("Ball hight state[%u] = %f\n", (unsigned)k, states[k]);
136  }
137 
138  /* Set states */
139  fmistatus = fmi1_import_set_continuous_states(fmu, states, n_states);
140  /* Step is complete */
141  fmistatus = fmi1_import_completed_integrator_step(fmu, &callEventUpdate);
142  }
143 
144  /* Validate result */
145  for (k = 0; k < n_states; k++) {
146  fmi1_real_t res = states[k] - states_end_results[k];
147  res = res > 0 ? res: -res; /* Take abs */
148  if (res > 1e-10) {
149  printf("Simulation results is wrong states[%u] %f != %f, |res| = %f\n", (unsigned)k, states[k], states_end_results[k], res);
150  do_exit(CTEST_RETURN_FAIL);
151  }
152  }
153 
154 
155  fmistatus = fmi1_import_terminate(fmu);
156 
158 
159  free(states);
160  free(states_der);
161  free(event_indicators);
162  free(event_indicators_prev);
163 
164  return 0;
165 }
166 
167 typedef struct {
172 } fmul_t;
173 
174 fmul_t load(int argc, char *argv[])
175 {
176  fmi1_callback_functions_t callBackFunctions;
177  const char* FMUPath;
178  const char* tmpPath;
180  fmi_import_context_t* context;
181  fmi_version_enu_t version;
182  jm_status_enu_t status;
183  static int isunzipped;
184 
185  fmi1_import_t* fmu;
186 
187  if(argc < 3) {
188  printf("Usage: %s <fmu_file> <temporary_dir>\n", argv[0]);
189  do_exit(CTEST_RETURN_FAIL);
190  }
191 
192  FMUPath = argv[1];
193  tmpPath = argv[2];
194 
195 
196  callbacks = (jm_callbacks*)malloc(sizeof(jm_callbacks));
197  callbacks->malloc = malloc;
198  callbacks->calloc = calloc;
199  callbacks->realloc = realloc;
200  callbacks->free = free;
201  callbacks->logger = jm_default_logger;
202  callbacks->log_level = jm_log_level_debug;
203  callbacks->context = 0;
204 
205  callBackFunctions.logger = fmi1_log_forwarding;
206  callBackFunctions.allocateMemory = calloc;
207  callBackFunctions.freeMemory = free;
208 
209 #ifdef FMILIB_GENERATE_BUILD_STAMP
210  printf("Library build stamp:\n%s\n", fmilib_get_build_stamp());
211 #endif
212 
213 
214  context = fmi_import_allocate_context(callbacks);
215 
216  if (isunzipped == 0) { /* Unzip the FMU only once. Overwriting the dll/so file may cause a segfault. */
217  version = fmi_import_get_fmi_version(context, FMUPath, tmpPath);
218  if(version != fmi_version_1_enu) {
219  printf("Only version 1.0 is supported so far\n");
220  do_exit(CTEST_RETURN_FAIL);
221  }
222  isunzipped = 1;
223  }
224 
225  fmu = fmi1_import_parse_xml(context, tmpPath);
226 
227  if(!fmu) {
228  printf("Error parsing XML, exiting\n");
229  do_exit(CTEST_RETURN_FAIL);
230  }
231 
232  status = fmi1_import_create_dllfmu(fmu, callBackFunctions, 1);
233  if (status == jm_status_error) {
234  printf("Could not create the DLL loading mechanism(C-API test).\n");
235  do_exit(CTEST_RETURN_FAIL);
236  }
237 
238  test_simulate_me(fmu);
239 
240  printf("Everything seems to be OK since you got this far=)!\n");
241  {
242  fmul_t fmus;
243  fmus.callBackFunctions = callBackFunctions;
244  fmus.callbacks = callbacks;
245  fmus.context = context;
246  fmus.fmu = fmu;
247  return fmus;
248  }
249 }
250 
251 void destroy(fmul_t* fmus) {
253  fmi1_import_free(fmus->fmu);
255  free(fmus->callbacks);
256  memset(fmus, 0, sizeof(fmul_t));
257 }
258 
259 /* Load and simulate 150 FMUs. Destroy and free all memory last. Usefull testing speciall for the registerGlobally functionality. */
260 #define NUMBER_OF_TESTS 150
261 int main(int argc, char *argv[])
262 {
263  fmul_t fmul[NUMBER_OF_TESTS];
264  int k;
265 
266  for (k=0;k<NUMBER_OF_TESTS;k++) {
267  fmul[k] = load(argc, argv);
268  }
269 
270  for (k=0;k<NUMBER_OF_TESTS;k++) {
271  destroy(&fmul[k]);
272  }
273 
274  do_exit(CTEST_RETURN_SUCCESS);
275 }
FMILIB_EXPORT jm_status_enu_t fmi1_import_instantiate_model(fmi1_import_t *fmu, fmi1_string_t instanceName)
Wrapper for the FMI function fmiInstantiateModel(...)
FMILIB_EXPORT fmi1_status_t fmi1_import_terminate(fmi1_import_t *fmu)
Wrapper for the FMI function fmiTerminate(...)
FMILIB_EXPORT unsigned int fmi1_import_get_number_of_event_indicators(fmi1_import_t *fmu)
Get the number of event indicators.
jm_calloc_f calloc
Allocate zero initialized memory.
Definition: jm_callbacks.h:77
int test_simulate_me(fmi1_import_t *fmu)
void do_exit(int code)
FMILIB_EXPORT fmi1_status_t fmi1_import_completed_integrator_step(fmi1_import_t *fmu, fmi1_boolean_t *callEventUpdate)
Wrapper for the FMI function fmiCompletedIntegratorStep(...)
FMILIB_EXPORT fmi1_status_t fmi1_import_initialize(fmi1_import_t *fmu, fmi1_boolean_t toleranceControlled, fmi1_real_t relativeTolerance, fmi1_event_info_t *eventInfo)
Wrapper for the FMI function fmiInitialize(...)
FMILIB_EXPORT fmi1_status_t fmi1_import_get_event_indicators(fmi1_import_t *fmu, fmi1_real_t eventIndicators[], size_t ni)
Wrapper for the FMI function fmiGetEventIndicators(...)
fmi1_callback_functions_t callBackFunctions
fmi_version_enu_t
Suported versions of FMI standard.
Definition: fmi_version.h:34
FMILIB_EXPORT fmi1_status_t fmi1_import_eventUpdate(fmi1_import_t *fmu, fmi1_boolean_t intermediateResults, fmi1_event_info_t *eventInfo)
Wrapper for the FMI function fmiEventUpdate(...)
fmi1_callback_logger_ft logger
#define NUMBER_OF_TESTS
fmi1_callback_allocate_memory_ft allocateMemory
FMILIB_EXPORT void fmi1_log_forwarding(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message,...)
An implementation of FMI 1.0 logger that forwards the messages to logger function inside jm_callbacks...
fmi1_real_t nextEventTime
FMILIB_EXPORT fmi1_status_t fmi1_import_set_time(fmi1_import_t *fmu, fmi1_real_t time)
Wrapper for the FMI function fmiSetTime(...)
FMILIB_EXPORT fmi1_status_t fmi1_import_get_continuous_states(fmi1_import_t *fmu, fmi1_real_t states[], size_t nx)
Wrapper for the FMI function fmiGetContinuousStates(...)
FMILIB_EXPORT void fmi1_import_destroy_dllfmu(fmi1_import_t *fmu)
Free a C-API struct. All memory allocated since the struct was created is freed.
jm_log_level_enu_t log_level
Logging level.
Definition: jm_callbacks.h:85
fmi1_boolean_t upcomingTimeEvent
v callbacks
fmi1_capi_t * fmu
fmi1_status_t
fmi_import_context_t * context
FMILIB_EXPORT unsigned int fmi1_import_get_number_of_continuous_states(fmi1_import_t *fmu)
Get the number of contnuous states.
FMILIB_EXPORT jm_status_enu_t fmi1_import_create_dllfmu(fmi1_import_t *fmu, fmi1_callback_functions_t callBackFunctions, int registerGlobally)
Create a C-API struct. The C-API struct is a placeholder for the FMI DLL functions.
FMILIB_EXPORT fmi1_import_t * fmi1_import_parse_xml(fmi_import_context_t *c, const char *dirName)
Parse FMI 1.0 XML file found in the directory dirName.
FMILIB_EXPORT fmi1_status_t fmi1_import_get_derivatives(fmi1_import_t *fmu, fmi1_real_t derivatives[], size_t nx)
Wrapper for the FMI function fmiGetDerivatives(...)
Verbose messages.
Definition: jm_types.h:58
Include file to be used in client applications of the FMI Library.
jm_malloc_f malloc
Allocate non-initialized memory.
Definition: jm_callbacks.h:75
jm_voidp context
Arbitrary context pointer passed to the logger function.
Definition: jm_callbacks.h:87
jm_callbacks * callbacks
void destroy(fmul_t *fmus)
FMILIB_EXPORT void jm_default_logger(jm_callbacks *c, jm_string module, jm_log_level_enu_t log_level, jm_string message)
The default logger implementation prints messages to stderr.
The callbacks struct is sent to all the modules in the library.
Definition: jm_callbacks.h:73
struct fmi_xml_context_t fmi_import_context_t
FMI version independent library context. Opaque struct returned from fmi_import_allocate_context() ...
FMILIB_EXPORT const char * fmi1_import_get_version(fmi1_import_t *fmu)
Wrapper for the FMI function fmiGetVersion()
FMILIB_EXPORT fmi_import_context_t * fmi_import_allocate_context(jm_callbacks *callbacks)
Create fmi_import_context_t structure.
fmi1_callback_free_memory_ft freeMemory
fmul_t load(int argc, char *argv[])
struct fmi1_import_t fmi1_import_t
FMU version 1.0 object.
fmi1_import_t * fmu
FMILIB_EXPORT fmi1_status_t fmi1_import_set_continuous_states(fmi1_import_t *fmu, const fmi1_real_t x[], size_t nx)
Wrapper for the FMI function fmiSetContinuousStates(...)
FMILIB_EXPORT fmi_version_enu_t fmi_import_get_fmi_version(fmi_import_context_t *c, const char *fileName, const char *dirName)
Unzip an FMU specified by the fileName into directory dirName and parse XML to get FMI standard versi...
FMILIB_EXPORT const char * fmi1_status_to_string(fmi1_status_t status)
FMILIB_EXPORT void fmi_import_free_context(fmi_import_context_t *c)
Free memory allocated for the library context.
FMILIB_EXPORT fmi1_status_t fmi1_import_set_debug_logging(fmi1_import_t *fmu, fmi1_boolean_t loggingOn)
Wrapper for the FMI function fmiSetDebugLogging(...)
jm_realloc_f realloc
Re-allocate memory.
Definition: jm_callbacks.h:79
jm_status_enu_t
Return status codes.
Definition: jm_types.h:44
FMILIB_EXPORT void fmi1_import_free(fmi1_import_t *fmu)
Release the memory allocated.
FMILIB_EXPORT void fmi1_import_free_model_instance(fmi1_import_t *fmu)
Wrapper for the FMI function fmiFreeModelInstance(...)
jm_free_f free
Free-allocated memory.
Definition: jm_callbacks.h:81
jm_logger_f logger
Logging callback.
Definition: jm_callbacks.h:83
FMILIB_EXPORT const char * fmi1_import_get_model_types_platform(fmi1_import_t *fmu)
Wrapper for the FMI function fmiGetModelTypesPlatform(...)
int main(int argc, char *argv[])