]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/Test/FMI2/fmi2_import_me_test.c
Merge remote-tracking branch 'origin/master' into release/1.35.1
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / Test / FMI2 / fmi2_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 void do_event_iteration(fmi2_import_t *fmu, fmi2_event_info_t *eventInfo)\r
33 {\r
34     eventInfo->newDiscreteStatesNeeded = fmi2_true;\r
35     eventInfo->terminateSimulation     = fmi2_false;\r
36     while (eventInfo->newDiscreteStatesNeeded && !eventInfo->terminateSimulation) {\r
37         fmi2_import_new_discrete_states(fmu, eventInfo);\r
38     }\r
39 }\r
40 \r
41 int test_parsed_all_varialbes(fmi2_import_t* fmu)\r
42 { /* Test that all variables where parsed */\r
43     fmi2_import_model_counts_t  mc;\r
44     unsigned int                n_total;\r
45     \r
46     fmi2_import_collect_model_counts(fmu, &mc);\r
47     n_total = mc.num_constants\r
48             + mc.num_fixed\r
49             + mc.num_tunable\r
50             + mc.num_discrete\r
51             + mc.num_continuous\r
52             + mc.num_independent;\r
53     \r
54     \r
55     if (n_total != 12) {\r
56         do_exit(CTEST_RETURN_FAIL);\r
57     }\r
58 }\r
59            \r
60 int test_simulate_me(fmi2_import_t* fmu)\r
61 {       \r
62         fmi2_status_t fmistatus;\r
63         jm_status_enu_t jmstatus;\r
64         fmi2_real_t tstart = 0.0;\r
65         fmi2_real_t tcur;\r
66         fmi2_real_t hcur;\r
67         fmi2_real_t hdef = 0.1;\r
68         fmi2_real_t tend = 2.0;\r
69         size_t n_states;\r
70         size_t n_event_indicators;\r
71         fmi2_real_t* states;\r
72         fmi2_real_t states_end_results[] = {0.362000, -3.962000};\r
73         fmi2_real_t* states_der;\r
74         fmi2_real_t* event_indicators;\r
75         fmi2_real_t* event_indicators_prev;\r
76         fmi2_boolean_t callEventUpdate;\r
77         fmi2_boolean_t terminateSimulation = fmi2_false;\r
78         fmi2_boolean_t toleranceControlled = fmi2_true;\r
79         fmi2_real_t relativeTolerance = 0.001;\r
80         fmi2_event_info_t eventInfo;\r
81         size_t k;\r
82 \r
83         printf("Version returned from FMU:   %s\n", fmi2_import_get_version(fmu));\r
84         printf("Platform type returned:      %s\n", fmi2_import_get_types_platform(fmu));\r
85 \r
86         n_states = fmi2_import_get_number_of_continuous_states(fmu);\r
87         n_event_indicators = fmi2_import_get_number_of_event_indicators(fmu);\r
88 \r
89         if (sizeof(states_end_results)/sizeof(fmi2_real_t) != n_states) {\r
90                 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
91                 do_exit(CTEST_RETURN_FAIL);\r
92         }\r
93 \r
94         states = calloc(n_states, sizeof(double));\r
95         states_der = calloc(n_states, sizeof(double));\r
96         event_indicators = calloc(n_event_indicators, sizeof(double));\r
97         event_indicators_prev = calloc(n_event_indicators, sizeof(double));\r
98 \r
99         jmstatus = fmi2_import_instantiate(fmu, "Test ME model instance",fmi2_model_exchange,0,0);\r
100         if (jmstatus == jm_status_error) {\r
101                 printf("fmi2_import_instantiate failed\n");\r
102                 do_exit(CTEST_RETURN_FAIL);\r
103         }\r
104 \r
105         fmistatus = fmi2_import_set_debug_logging(fmu, fmi2_false,0,0);\r
106         printf("fmi2_import_set_debug_logging:  %s\n", fmi2_status_to_string(fmistatus));       \r
107         fmi2_import_set_debug_logging(fmu, fmi2_true, 0, 0);\r
108 \r
109     fmistatus = fmi2_import_setup_experiment(fmu, toleranceControlled,\r
110         relativeTolerance, tstart, fmi2_false, 0.0);\r
111 \r
112     fmistatus = fmi2_import_enter_initialization_mode(fmu);\r
113     fmistatus = fmi2_import_exit_initialization_mode(fmu);\r
114 \r
115         tcur = tstart;\r
116         hcur = hdef;\r
117         callEventUpdate = fmi2_false;\r
118 \r
119         eventInfo.newDiscreteStatesNeeded           = fmi2_false;\r
120         eventInfo.terminateSimulation               = fmi2_false;\r
121         eventInfo.nominalsOfContinuousStatesChanged = fmi2_false;\r
122         eventInfo.valuesOfContinuousStatesChanged   = fmi2_true;\r
123         eventInfo.nextEventTimeDefined              = fmi2_false;\r
124         eventInfo.nextEventTime                     = -0.0;\r
125 \r
126     /* fmiExitInitializationMode leaves FMU in event mode */\r
127     do_event_iteration(fmu, &eventInfo);\r
128     fmi2_import_enter_continuous_time_mode(fmu);\r
129 \r
130         fmistatus = fmi2_import_get_continuous_states(fmu, states, n_states);\r
131         fmistatus = fmi2_import_get_event_indicators(fmu, event_indicators, n_event_indicators);\r
132 \r
133         while ((tcur < tend) && (!(eventInfo.terminateSimulation || terminateSimulation))) {\r
134                 size_t k;\r
135         fmi2_real_t tlast;\r
136                 int zero_crossing_event = 0;\r
137 \r
138                 fmistatus = fmi2_import_set_time(fmu, tcur);\r
139 \r
140         { /* Swap event_indicators and event_indicators_prev so that we can get new indicators */\r
141             fmi2_real_t *temp = event_indicators;\r
142             event_indicators = event_indicators_prev;\r
143             event_indicators_prev = temp;\r
144         }\r
145                 fmistatus = fmi2_import_get_event_indicators(fmu, event_indicators, n_event_indicators);\r
146 \r
147                 /* Check if an event indicator has triggered */\r
148                 for (k = 0; k < n_event_indicators; k++) {\r
149                         if ((event_indicators[k] > 0) != (event_indicators_prev[k] > 0)) {\r
150                                 zero_crossing_event = 1;\r
151                                 break;\r
152                         }\r
153                 }\r
154 \r
155                 /* Handle any events */\r
156                 if (callEventUpdate || zero_crossing_event ||\r
157                   (eventInfo.nextEventTimeDefined && tcur == eventInfo.nextEventTime)) {\r
158             fmistatus = fmi2_import_enter_event_mode(fmu);\r
159             do_event_iteration(fmu, &eventInfo);\r
160             fmistatus = fmi2_import_enter_continuous_time_mode(fmu);\r
161 \r
162                         fmistatus = fmi2_import_get_continuous_states(fmu, states, n_states);\r
163                         fmistatus = fmi2_import_get_event_indicators(fmu, event_indicators, n_event_indicators);\r
164                 }\r
165 \r
166                 /* Calculate next time step */\r
167         tlast = tcur;\r
168         tcur += hdef;\r
169                 if (eventInfo.nextEventTimeDefined && (tcur >= eventInfo.nextEventTime)) {\r
170             tcur = eventInfo.nextEventTime;\r
171                 }\r
172         hcur = tcur - tlast;\r
173                 if(tcur > tend - hcur/1e16) {\r
174                         tcur = tend;                            \r
175                         hcur = tcur - tlast;\r
176                 }\r
177 \r
178                 /* Integrate a step */\r
179                 fmistatus = fmi2_import_get_derivatives(fmu, states_der, n_states);\r
180                 for (k = 0; k < n_states; k++) {\r
181                         states[k] = states[k] + hcur*states_der[k];     \r
182                         if (k == 0) printf("Ball height state[%u] = %f\n", (unsigned)k, states[k]);\r
183                 }\r
184 \r
185                 /* Set states */\r
186                 fmistatus = fmi2_import_set_continuous_states(fmu, states, n_states);\r
187                 /* Step is complete */\r
188                 fmistatus = fmi2_import_completed_integrator_step(fmu, fmi2_true, &callEventUpdate,\r
189                                                           &terminateSimulation);\r
190         }       \r
191 \r
192         /* Validate result */\r
193         for (k = 0; k < n_states; k++) {\r
194                 fmi2_real_t res = states[k] - states_end_results[k];\r
195                 res = res > 0 ? res: -res; /* Take abs */\r
196                 if (res > 1e-10) {\r
197                         printf("Simulation results is wrong  states[%u] %f != %f, |res| = %f\n", (unsigned)k, states[k], states_end_results[k], res);\r
198                         do_exit(CTEST_RETURN_FAIL);\r
199                 }\r
200         }\r
201         \r
202 \r
203         fmistatus = fmi2_import_terminate(fmu);\r
204 \r
205         fmi2_import_free_instance(fmu);\r
206 \r
207         free(states);\r
208         free(states_der);\r
209         free(event_indicators);\r
210         free(event_indicators_prev);\r
211 \r
212         return 0;\r
213 }\r
214 \r
215 int main(int argc, char *argv[])\r
216 {\r
217         fmi2_callback_functions_t callBackFunctions;\r
218         const char* FMUPath;\r
219         const char* tmpPath;\r
220         jm_callbacks callbacks;\r
221         fmi_import_context_t* context;\r
222         fmi_version_enu_t version;\r
223         jm_status_enu_t status;\r
224 \r
225         fmi2_import_t* fmu;     \r
226 \r
227         if(argc < 3) {\r
228                 printf("Usage: %s <fmu_file> <temporary_dir>\n", argv[0]);\r
229                 do_exit(CTEST_RETURN_FAIL);\r
230         }\r
231 \r
232         FMUPath = argv[1];\r
233         tmpPath = argv[2];\r
234 \r
235 \r
236         callbacks.malloc = malloc;\r
237     callbacks.calloc = calloc;\r
238     callbacks.realloc = realloc;\r
239     callbacks.free = free;\r
240     callbacks.logger = jm_default_logger;\r
241         callbacks.log_level = jm_log_level_debug;\r
242     callbacks.context = 0;\r
243 \r
244 #ifdef FMILIB_GENERATE_BUILD_STAMP\r
245         printf("Library build stamp:\n%s\n", fmilib_get_build_stamp());\r
246 #endif\r
247 \r
248 \r
249         context = fmi_import_allocate_context(&callbacks);\r
250 \r
251         version = fmi_import_get_fmi_version(context, FMUPath, tmpPath);\r
252 \r
253         if(version != fmi_version_2_0_enu) {\r
254                 printf("Only version 2.0 is supported by this code\n");\r
255                 do_exit(CTEST_RETURN_FAIL);\r
256         }\r
257 \r
258         fmu = fmi2_import_parse_xml(context, tmpPath,0);\r
259 \r
260         if(!fmu) {\r
261                 printf("Error parsing XML, exiting\n");\r
262                 do_exit(CTEST_RETURN_FAIL);\r
263         }       \r
264 \r
265         if(fmi2_import_get_fmu_kind(fmu) == fmi2_fmu_kind_cs) {\r
266                 printf("Only ME 2.0 is supported by this code\n");\r
267                 do_exit(CTEST_RETURN_FAIL);\r
268         }\r
269 \r
270         callBackFunctions.logger = fmi2_log_forwarding;\r
271         callBackFunctions.allocateMemory = calloc;\r
272         callBackFunctions.freeMemory = free;\r
273         callBackFunctions.componentEnvironment = fmu;\r
274 \r
275         status = fmi2_import_create_dllfmu(fmu, fmi2_fmu_kind_me, &callBackFunctions);\r
276         if (status == jm_status_error) {\r
277                 printf("Could not create the DLL loading mechanism(C-API test).\n");\r
278                 do_exit(CTEST_RETURN_FAIL);\r
279         }\r
280     \r
281     test_parsed_all_varialbes(fmu);\r
282     \r
283         test_simulate_me(fmu);\r
284 \r
285         fmi2_import_destroy_dllfmu(fmu);\r
286 \r
287         fmi2_import_free(fmu);\r
288         fmi_import_free_context(context);\r
289         \r
290         printf("Everything seems to be OK since you got this far=)!\n");\r
291 \r
292         do_exit(CTEST_RETURN_SUCCESS);\r
293 \r
294         return 0;\r
295 }\r
296 \r
297 \r