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