FMI Library: part of JModelica.org
fmi_import_cs_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 #include <string.h>
20 
21 #include "config_test.h"
22 
23 #include <fmilib.h>
24 
25 
26 #define BUFFER 1000
27 
29 {
30  printf("module = %s, log level = %s: %s\n", module, jm_log_level_to_string(log_level), message);
31 }
32 
33 /* Logger function used by the FMU internally */
34 
35 void fmilogger(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, ...)
36 {
37  /* char msg[BUFFER];*/
38  va_list argp;
39  va_start(argp, message);
40  /* vsnprintf(msg, BUFFER, message, argp); */
41  fmi1_log_forwarding_v(c, instanceName, status, category, message, argp);
42  va_end(argp);
43 }
44 
45 void do_exit(int code)
46 {
47  printf("Press 'Enter' to exit\n");
48  /* getchar(); */
49  exit(code);
50 }
51 
52 /* Testing "...Test\FMI1\fmu_dummy\modelDescription_cs_tc.xml" */
53 void test_xml_modelDescription_cs_tc(const char* xmlFileName, fmi1_import_t* fmu)
54 {
56 
57  { /* Test variable "INTEGER" */
59  const char* name = "INTEGER";
60  printf("Testing ScalarVariable %s\n", name);
61  v = fmi1_import_get_variable_by_name(fmu, name);
63 
64  /* Test min attr */
66  printf("Test of XML file \"%s\" failed. min attribute value missmatch.\n", xmlFileName);
67  do_exit(CTEST_RETURN_FAIL);
68  }
69 
70  /* Test max attr */
72  printf("Test of XML file \"%s\" failed. max attribute value missmatch.\n", xmlFileName);
73  do_exit(CTEST_RETURN_FAIL);
74  }
75  }
76 
77  { /* Test variable "INTEGER_DECLAREDTYPE" */
79  const char* name = "INTEGER_DECLAREDTYPE";
80  printf("Testing ScalarVariable %s\n", name);
81  v = fmi1_import_get_variable_by_name(fmu, name);
83 
84  /* Test min attr */
86  printf("Test of XML file \"%s\" failed. min attribute value missmatch.\n", xmlFileName);
87  do_exit(CTEST_RETURN_FAIL);
88  }
89 
90  /* Test max attr */
92  printf("Test of XML file \"%s\" failed. max attribute value missmatch.\n", xmlFileName);
93  do_exit(CTEST_RETURN_FAIL);
94  }
95  }
96 
97  { /* Test variable "INTEGER_DECLAREDTYPE_OVERWRITE" */
99  const char* name = "INTEGER_DECLAREDTYPE_OVERWRITE";
100  printf("Testing ScalarVariable %s\n", name);
101  v = fmi1_import_get_variable_by_name(fmu, name);
103 
104  /* Test min attr */
106  printf("Test of XML file \"%s\" failed. min attribute value missmatch.\n", xmlFileName);
107  do_exit(CTEST_RETURN_FAIL);
108  }
109 
110  /* Test max attr */
111  if (11 != fmi1_import_get_integer_variable_max(vi)) {
112  printf("Test of XML file \"%s\" failed. max attribute value missmatch.\n", xmlFileName);
113  do_exit(CTEST_RETURN_FAIL);
114  }
115  }
116 
117  { /* Test variable "ENUMERATION_DECLAREDTYPE" */
119  const char* name = "ENUMERATION_DECLAREDTYPE";
120  printf("Testing ScalarVariable %s\n", name);
121  v = fmi1_import_get_variable_by_name(fmu, name);
123 
124  /* Test min attr */
125  if (1 != fmi1_import_get_enum_variable_min(vi)) {
126  printf("Test of XML file \"%s\" failed. min attribute value missmatch.\n", xmlFileName);
127  do_exit(CTEST_RETURN_FAIL);
128  }
129 
130  /* Test max attr */
131  if (5 != fmi1_import_get_enum_variable_max(vi)) {
132  printf("Test of XML file \"%s\" failed. max attribute value missmatch.\n", xmlFileName);
133  do_exit(CTEST_RETURN_FAIL);
134  }
135  }
136 
137  { /* Test variable "ENUMERATION_DECLAREDTYPE_OVERWRITE" */
139  const char* name = "ENUMERATION_DECLAREDTYPE_OVERWRITE";
140  printf("Testing ScalarVariable %s\n", name);
141  v = fmi1_import_get_variable_by_name(fmu, name);
143 
144  /* Test min attr */
145  if (2 != fmi1_import_get_enum_variable_min(vi)) {
146  printf("Test of XML file \"%s\" failed. min attribute value missmatch.\n", xmlFileName);
147  do_exit(CTEST_RETURN_FAIL);
148  }
149 
150  /* Test max attr */
151  if (3 != fmi1_import_get_enum_variable_max(vi)) {
152  printf("Test of XML file \"%s\" failed. max attribute value missmatch.\n", xmlFileName);
153  do_exit(CTEST_RETURN_FAIL);
154  }
155  }
156 }
157 
158 typedef struct {
159  const char* filename;
161  void (*fcn)(const char* xmlFileName, fmi1_import_t* fmu);
163 
165  {"modelDescription_cs_tc.xml", 1, test_xml_modelDescription_cs_tc},
166  {"modelDescription_cs.xml", 0, NULL}
167 };
168 
169 void test_xml(const char* xmlFileName, fmi1_import_t* fmu)
170 {
171  int k;
172  int foundxml = 0;
173 
174  for (k = 0; k < sizeof(xml_test_files)/sizeof(*xml_test_files); k++) {
175  foundxml = strcmp(xmlFileName, xml_test_files[k].filename) == 0 ? 1 : 0;
176  if (foundxml) {
177  if (xml_test_files[k].performTest) {
178  xml_test_files[k].fcn(xmlFileName, fmu); /* Run specific file XML file test */
179  }
180  return;
181  }
182  }
183 
184  if (!foundxml) {
185  printf("XML file test is not properly implemented in " __FILE__ " . Could not find the XML \"%s\" in the list of expected XML-files", xmlFileName);
186  do_exit(CTEST_RETURN_FAIL);
187  }
188 }
189 
190 
192 {
193  fmi1_status_t fmistatus;
194  jm_status_enu_t jmstatus;
195 
196  fmi1_string_t instanceName = "Test CS model instance";
197  fmi1_string_t fmuGUID;
198  fmi1_string_t fmuLocation = "";
199  fmi1_string_t mimeType = "";
200  fmi1_real_t timeout = 0.0;
201  fmi1_boolean_t visible = fmi1_false;
202  fmi1_boolean_t interactive = fmi1_false;
203 /* fmi1_boolean_t loggingOn = fmi1_true; */
204 
205  /* fmi1_real_t simulation_results[] = {-0.001878, -1.722275}; */
206  fmi1_real_t simulation_results[] = {0.0143633, -1.62417};
207  fmi1_value_reference_t compare_real_variables_vr[] = {0, 1};
208  size_t k;
209 
210  fmi1_real_t tstart = 0.0;
211  fmi1_real_t tcur = tstart;
212  fmi1_real_t hstep = 0.1;
213  fmi1_real_t tend = 2.0;
214  fmi1_boolean_t StopTimeDefined = fmi1_false;
215 
216  if (sizeof(compare_real_variables_vr)/sizeof(fmi1_value_reference_t) != sizeof(simulation_results)/sizeof(fmi1_real_t)) {
217  printf("Number of simulation values and reference values are different\n");
218  do_exit(CTEST_RETURN_FAIL);
219  }
220 
221  printf("Version returned from FMU: %s\n", fmi1_import_get_version(fmu));
222  printf("Platform type returned: %s\n", fmi1_import_get_types_platform(fmu));
223 
224  fmuGUID = fmi1_import_get_GUID(fmu);
225  printf("GUID: %s\n", fmuGUID);
226 
227 
228  jmstatus = fmi1_import_instantiate_slave(fmu, instanceName, fmuLocation, mimeType, timeout, visible, interactive);
229  if (jmstatus == jm_status_error) {
230  printf("fmi1_import_instantiate_model failed\n");
231  do_exit(CTEST_RETURN_FAIL);
232  }
233 
234  fmistatus = fmi1_import_initialize_slave(fmu, tstart, StopTimeDefined, tend);
235  if(fmistatus != fmi1_status_ok) {
236  printf("fmi1_import_initialize_slave failed\n");
237  do_exit(CTEST_RETURN_FAIL);
238  }
239 
240  tcur = tstart;
241  printf("%10s %10s\n", "Ball height", "Ball speed");
242  while (tcur < tend) {
243  fmi1_boolean_t newStep = fmi1_true;
244 #if 0 /* Prints a real value.. */
245  fmi1_real_t rvalue;
246  fmi1_value_reference_t vr = 0;
247 
248  fmistatus = fmi1_import_get_real(fmu, &vr, 1, &rvalue);
249  printf("rvalue = %f\n", rvalue);
250 #endif
251  fmistatus = fmi1_import_do_step(fmu, tcur, hstep, newStep);
252 
253  for (k = 0; k < sizeof(compare_real_variables_vr)/sizeof(fmi1_value_reference_t); k++) {
254  fmi1_value_reference_t vr = compare_real_variables_vr[k];
255  fmi1_real_t rvalue;
256  fmistatus = fmi1_import_get_real(fmu, &vr, 1, &rvalue);
257  }
258  {
259  fmi1_real_t val[2];
260  fmi1_import_get_real(fmu, compare_real_variables_vr, 2, val);
261  printf("%10g %10g\n", val[0],val[1]);
262  }
263 
264  tcur += hstep;
265  }
266 
267  printf("Simulation finished. Checking results\n");
268 
269  /* Validate result */
270  for (k = 0; k < sizeof(compare_real_variables_vr)/sizeof(fmi1_value_reference_t); k++) {
271  fmi1_value_reference_t vr = compare_real_variables_vr[k];
272  fmi1_real_t rvalue;
273  fmi1_real_t res;
274  fmistatus = fmi1_import_get_real(fmu, &vr, 1, &rvalue);
275  res = rvalue - simulation_results[k];
276  res = res > 0 ? res: -res; /* Take abs */
277  if (res > 3e-3) {
278  printf("Simulation results is wrong!\n");
279  printf("State [%u] %g != %g, |res| = %g\n", (unsigned)k, rvalue, simulation_results[k], res);
280  printf("\n");
281  do_exit(CTEST_RETURN_FAIL);
282  }
283  }
284 
285  fmistatus = fmi1_import_terminate_slave(fmu);
286 
288 
289  return 0;
290 }
291 
292 int main(int argc, char *argv[])
293 {
294  fmi1_callback_functions_t callBackFunctions;
295  const char* FMUPath;
296  const char* tmpPath;
297  const char* xmlFileName;
299  fmi_import_context_t* context;
300  fmi_version_enu_t version;
301  jm_status_enu_t status;
302  int k;
303 
305 
306  if(argc < 4) {
307  printf("Usage: %s <fmu_file> <temporary_dir> <modelDescription_file>\n", argv[0]);
308  do_exit(CTEST_RETURN_FAIL);
309  }
310  for (k = 0; k < argc; k ++)
311  printf("argv[%d] = %s\n", k, argv[k]);
312 
313  FMUPath = argv[1];
314  tmpPath = argv[2];
315  xmlFileName = argv[3];
316 
317  callbacks.malloc = malloc;
318  callbacks.calloc = calloc;
319  callbacks.realloc = realloc;
320  callbacks.free = free;
321  callbacks.logger = importlogger;
322  callbacks.log_level = jm_log_level_debug;
323  callbacks.context = 0;
324 
325  callBackFunctions.logger = fmi1_log_forwarding;
326  callBackFunctions.allocateMemory = calloc;
327  callBackFunctions.freeMemory = free;
328 
329 #ifdef FMILIB_GENERATE_BUILD_STAMP
330  printf("Library build stamp:\n%s\n", fmilib_get_build_stamp());
331 #endif
332 
333  context = fmi_import_allocate_context(&callbacks);
334 
335  version = fmi_import_get_fmi_version(context, FMUPath, tmpPath);
336 
337  if(version != fmi_version_1_enu) {
338  printf("Only version 1.0 is supported so far\n");
339  do_exit(CTEST_RETURN_FAIL);
340  }
341 
342  fmu = fmi1_import_parse_xml(context, tmpPath);
343 
344  if(!fmu) {
345  printf("Error parsing XML, exiting\n");
346  do_exit(CTEST_RETURN_FAIL);
347  }
348 
349 
350  status = fmi1_import_create_dllfmu(fmu, callBackFunctions, 1);
351  if (status == jm_status_error) {
352  printf("Could not create the DLL loading mechanism(C-API) (error: %s).\n", fmi1_import_get_last_error(fmu));
353  do_exit(CTEST_RETURN_FAIL);
354  }
355 
356  test_simulate_cs(fmu);
357  test_xml(xmlFileName, fmu);
358 
360 
361  fmi1_import_free(fmu);
362  fmi_import_free_context(context);
363 
364  printf("Everything seems to be OK since you got this far=)!\n");
365 
366  do_exit(CTEST_RETURN_SUCCESS);
367 
368  return 0;
369 }
370 
371 
FMILIB_EXPORT const char * fmi1_import_get_GUID(fmi1_import_t *fmu)
Get FMU GUID.
FMILIB_EXPORT fmi1_import_integer_variable_t * fmi1_import_get_variable_as_integer(fmi1_import_variable_t *)
Cast general variable to a one with the specific type.
FMILIB_EXPORT int fmi1_import_get_enum_variable_min(fmi1_import_enum_variable_t *v)
Get minimal value for the variable.
jm_calloc_f calloc
Allocate zero initialized memory.
Definition: jm_callbacks.h:77
void fmilogger(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message,...)
size_t jm_callbacks * c
FMILIB_EXPORT int fmi1_import_get_enum_variable_max(fmi1_import_enum_variable_t *v)
Get max value for the variable.
FMILIB_EXPORT void fmi1_log_forwarding_v(fmi1_component_t c, fmi1_string_t instanceName, fmi1_status_t status, fmi1_string_t category, fmi1_string_t message, va_list args)
An implementation of FMI 1.0 logger that forwards the messages to logger function inside jm_callbacks...
fmi_version_enu_t
Suported versions of FMI standard.
Definition: fmi_version.h:34
fmi1_callback_logger_ft logger
FMILIB_EXPORT int fmi1_import_get_integer_variable_min(fmi1_import_integer_variable_t *v)
Get minimal value for the variable.
FMILIB_EXPORT const char * jm_log_level_to_string(jm_log_level_enu_t level)
Convert log level into a string.
void importlogger(jm_callbacks *c, jm_string module, jm_log_level_enu_t log_level, jm_string message)
FMILIB_EXPORT fmi1_import_enum_variable_t * fmi1_import_get_variable_as_enum(fmi1_import_variable_t *)
Cast general variable to a one with the specific type.
FMILIB_EXPORT jm_status_enu_t fmi1_import_instantiate_slave(fmi1_import_t *fmu, fmi1_string_t instanceName, fmi1_string_t fmuLocation, fmi1_string_t mimeType, fmi1_real_t timeout, fmi1_boolean_t visible, fmi1_boolean_t interactive)
Wrapper for the FMI function fmiInstantiateSlave(...)
jm_log_level_enu_t
Log levels supported via the logger functions in jm_callbacks.
Definition: jm_types.h:51
struct fmi1_xml_integer_variable_t fmi1_import_integer_variable_t
Opaque integer variable.
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...
return v
struct fmi1_xml_variable_t fmi1_import_variable_t
General variable type.
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
v callbacks
void test_xml_modelDescription_cs_tc(const char *xmlFileName, fmi1_import_t *fmu)
fmi1_capi_t * fmu
int test_simulate_cs(fmi1_import_t *fmu)
fmi1_status_t
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.
void test_xml(const char *xmlFileName, fmi1_import_t *fmu)
FMILIB_EXPORT void fmi1_import_free_slave_instance(fmi1_import_t *fmu)
Wrapper for the FMI function fmiFreeSlaveInstance(...)
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.
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
const char * jm_string
A constant string.
Definition: jm_types.h:33
xml_test_files_t xml_test_files[]
FMILIB_EXPORT const char * fmi1_import_get_last_error(fmi1_import_t *fmu)
Retrieve the last error message.
FMILIB_EXPORT fmi1_status_t fmi1_import_initialize_slave(fmi1_import_t *fmu, fmi1_real_t tStart, fmi1_boolean_t StopTimeDefined, fmi1_real_t tStop)
Wrapper for the FMI function fmiInitializeSlave(...)
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
void(* fcn)(const char *xmlFileName, fmi1_import_t *fmu)
FMILIB_EXPORT fmi1_status_t fmi1_import_get_real(fmi1_import_t *fmu, const fmi1_value_reference_t vr[], size_t nvr, fmi1_real_t value[])
Wrapper for the FMI function fmiGetReal(...)
struct fmi1_import_t fmi1_import_t
FMU version 1.0 object.
FMILIB_EXPORT const char * fmi1_import_get_types_platform(fmi1_import_t *fmu)
Wrapper for the FMI function fmiGetTypesPlatform(...)
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...
int main(int argc, char *argv[])
FMILIB_EXPORT fmi1_import_variable_t * fmi1_import_get_variable_by_name(fmi1_import_t *fmu, const char *name)
Get variable by variable name.
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_terminate_slave(fmi1_import_t *fmu)
Wrapper for the FMI function fmiTerminateSlave(...)
jm_realloc_f realloc
Re-allocate memory.
Definition: jm_callbacks.h:79
struct fmi1_xml_enum_variable_t fmi1_import_enum_variable_t
Opaque enumeration variable.
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.
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 fmi1_status_t fmi1_import_do_step(fmi1_import_t *fmu, fmi1_real_t currentCommunicationPoint, fmi1_real_t communicationStepSize, fmi1_boolean_t newStep)
Wrapper for the FMI function fmiDoStep(...)
void do_exit(int code)
FMILIB_EXPORT int fmi1_import_get_integer_variable_max(fmi1_import_integer_variable_t *v)
Get max value for the variable.