--- /dev/null
+/*\r
+ Copyright (C) 2012 Modelon AB\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the BSD style license.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ FMILIB_License.txt file for more details.\r
+\r
+ You should have received a copy of the FMILIB_License.txt file\r
+ along with this program. If not, contact Modelon AB <http://www.modelon.com>.\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+\r
+#include "config_test.h"\r
+#include <fmilib.h>\r
+\r
+#define BUFFER 1000\r
+\r
+void do_exit(int code)\r
+{\r
+ printf("Press 'Enter' to exit\n");\r
+ /* getchar(); */\r
+ exit(code);\r
+}\r
+ \r
+int test_simulate_me(fmi1_import_t* fmu)\r
+{ \r
+ fmi1_status_t fmistatus;\r
+ jm_status_enu_t jmstatus;\r
+ fmi1_real_t tstart = 0.0;\r
+ fmi1_real_t tcur;\r
+ fmi1_real_t hcur;\r
+ fmi1_real_t hdef = 0.1;\r
+ fmi1_real_t tend = 2.0;\r
+ size_t n_states;\r
+ size_t n_event_indicators;\r
+ fmi1_real_t* states;\r
+ fmi1_real_t states_end_results[] = {0.362000, -3.962000};\r
+ fmi1_real_t* states_der;\r
+ fmi1_real_t* event_indicators;\r
+ fmi1_real_t* event_indicators_prev;\r
+ fmi1_boolean_t callEventUpdate;\r
+ fmi1_boolean_t toleranceControlled = fmi1_true;\r
+ fmi1_real_t relativeTolerance = 0.001;\r
+ fmi1_event_info_t eventInfo;\r
+ fmi1_boolean_t intermediateResults = fmi1_false;\r
+ size_t k;\r
+\r
+ printf("Version returned from FMU: %s\n", fmi1_import_get_version(fmu));\r
+ printf("Platform type returned: %s\n", fmi1_import_get_model_types_platform(fmu));\r
+\r
+ n_states = fmi1_import_get_number_of_continuous_states(fmu);\r
+ n_event_indicators = fmi1_import_get_number_of_event_indicators(fmu);\r
+\r
+ if (sizeof(states_end_results)/sizeof(fmi1_real_t) != n_states) {\r
+ 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
+ do_exit(CTEST_RETURN_FAIL);\r
+ }\r
+\r
+ states = calloc(n_states, sizeof(double));\r
+ states_der = calloc(n_states, sizeof(double));\r
+ event_indicators = calloc(n_event_indicators, sizeof(double));\r
+ event_indicators_prev = calloc(n_event_indicators, sizeof(double));\r
+\r
+ jmstatus = fmi1_import_instantiate_model(fmu, "Test ME model instance");\r
+ if (jmstatus == jm_status_error) {\r
+ printf("fmi1_import_instantiate_model failed\n");\r
+ do_exit(CTEST_RETURN_FAIL);\r
+ }\r
+\r
+ fmistatus = fmi1_import_set_time(fmu, tstart);\r
+\r
+ fmistatus = fmi1_import_initialize(fmu, toleranceControlled, relativeTolerance, &eventInfo);\r
+\r
+ fmistatus = fmi1_import_get_continuous_states(fmu, states, n_states);\r
+ fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators_prev, n_event_indicators);\r
+\r
+ fmistatus = fmi1_import_set_debug_logging(fmu, fmi1_false);\r
+ printf("fmi1_import_set_debug_logging: %s\n", fmi1_status_to_string(fmistatus)); \r
+ fmi1_import_set_debug_logging(fmu, fmi1_true);\r
+\r
+ tcur = tstart;\r
+ hcur = hdef;\r
+ callEventUpdate = fmi1_false;\r
+\r
+ while (tcur < tend) {\r
+ size_t k;\r
+ int zero_crossning_event = 0;\r
+\r
+ fmistatus = fmi1_import_set_time(fmu, tcur);\r
+ fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators, n_event_indicators);\r
+\r
+ /* Check if an event inidcator has triggered */\r
+ for (k = 0; k < n_event_indicators; k++) {\r
+ if (event_indicators[k]*event_indicators_prev[k] < 0) {\r
+ zero_crossning_event = 1;\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* Handle any events */\r
+ if (callEventUpdate || zero_crossning_event || (eventInfo.upcomingTimeEvent && tcur == eventInfo.nextEventTime)) {\r
+ fmistatus = fmi1_import_eventUpdate(fmu, intermediateResults, &eventInfo);\r
+ fmistatus = fmi1_import_get_continuous_states(fmu, states, n_states);\r
+ fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators, n_event_indicators);\r
+ fmistatus = fmi1_import_get_event_indicators(fmu, event_indicators_prev, n_event_indicators);\r
+ }\r
+\r
+ /* Updated next time step */\r
+ if (eventInfo.upcomingTimeEvent) {\r
+ if (tcur + hdef < eventInfo.nextEventTime) {\r
+ hcur = hdef;\r
+ } else {\r
+ hcur = eventInfo.nextEventTime - tcur;\r
+ }\r
+ } else {\r
+ hcur = hdef;\r
+ }\r
+ tcur += hcur;\r
+ if(tcur > tend - hcur/1e16) {\r
+ tcur -= hcur;\r
+ hcur = (tend - tcur);\r
+ tcur = tend; \r
+ }\r
+ /* Integrate a step */\r
+ fmistatus = fmi1_import_get_derivatives(fmu, states_der, n_states);\r
+ for (k = 0; k < n_states; k++) {\r
+ states[k] = states[k] + hcur*states_der[k]; \r
+ if (k == 0) printf("Ball hight state[%u] = %f\n", (unsigned)k, states[k]);\r
+ }\r
+\r
+ /* Set states */\r
+ fmistatus = fmi1_import_set_continuous_states(fmu, states, n_states);\r
+ /* Step is complete */\r
+ fmistatus = fmi1_import_completed_integrator_step(fmu, &callEventUpdate);\r
+ } \r
+\r
+ /* Validate result */\r
+ for (k = 0; k < n_states; k++) {\r
+ fmi1_real_t res = states[k] - states_end_results[k];\r
+ res = res > 0 ? res: -res; /* Take abs */\r
+ if (res > 1e-10) {\r
+ printf("Simulation results is wrong states[%u] %f != %f, |res| = %f\n", (unsigned)k, states[k], states_end_results[k], res);\r
+ do_exit(CTEST_RETURN_FAIL);\r
+ }\r
+ }\r
+ \r
+\r
+ fmistatus = fmi1_import_terminate(fmu);\r
+\r
+ fmi1_import_free_model_instance(fmu);\r
+\r
+ free(states);\r
+ free(states_der);\r
+ free(event_indicators);\r
+ free(event_indicators_prev);\r
+\r
+ return 0;\r
+}\r
+\r
+typedef struct {\r
+ fmi1_import_t* fmu;\r
+ fmi_import_context_t* context;\r
+ jm_callbacks* callbacks;\r
+ fmi1_callback_functions_t callBackFunctions;\r
+} fmul_t;\r
+\r
+fmul_t load(int argc, char *argv[])\r
+{\r
+ fmi1_callback_functions_t callBackFunctions;\r
+ const char* FMUPath;\r
+ const char* tmpPath;\r
+ jm_callbacks* callbacks;\r
+ fmi_import_context_t* context;\r
+ fmi_version_enu_t version;\r
+ jm_status_enu_t status;\r
+ static int isunzipped;\r
+\r
+ fmi1_import_t* fmu; \r
+\r
+ if(argc < 3) {\r
+ printf("Usage: %s <fmu_file> <temporary_dir>\n", argv[0]);\r
+ do_exit(CTEST_RETURN_FAIL);\r
+ }\r
+\r
+ FMUPath = argv[1];\r
+ tmpPath = argv[2];\r
+\r
+\r
+ callbacks = (jm_callbacks*)malloc(sizeof(jm_callbacks));\r
+ callbacks->malloc = malloc;\r
+ callbacks->calloc = calloc;\r
+ callbacks->realloc = realloc;\r
+ callbacks->free = free;\r
+ callbacks->logger = jm_default_logger;\r
+ callbacks->log_level = jm_log_level_debug;\r
+ callbacks->context = 0;\r
+\r
+ callBackFunctions.logger = fmi1_log_forwarding;\r
+ callBackFunctions.allocateMemory = calloc;\r
+ callBackFunctions.freeMemory = free;\r
+\r
+#ifdef FMILIB_GENERATE_BUILD_STAMP\r
+ printf("Library build stamp:\n%s\n", fmilib_get_build_stamp());\r
+#endif\r
+\r
+\r
+ context = fmi_import_allocate_context(callbacks);\r
+ \r
+ if (isunzipped == 0) { /* Unzip the FMU only once. Overwriting the dll/so file may cause a segfault. */\r
+ version = fmi_import_get_fmi_version(context, FMUPath, tmpPath);\r
+ if(version != fmi_version_1_enu) {\r
+ printf("Only version 1.0 is supported so far\n");\r
+ do_exit(CTEST_RETURN_FAIL);\r
+ }\r
+ isunzipped = 1;\r
+ }\r
+\r
+ fmu = fmi1_import_parse_xml(context, tmpPath);\r
+\r
+ if(!fmu) {\r
+ printf("Error parsing XML, exiting\n");\r
+ do_exit(CTEST_RETURN_FAIL);\r
+ } \r
+\r
+ status = fmi1_import_create_dllfmu(fmu, callBackFunctions, 1);\r
+ if (status == jm_status_error) {\r
+ printf("Could not create the DLL loading mechanism(C-API test).\n");\r
+ do_exit(CTEST_RETURN_FAIL);\r
+ }\r
+ \r
+ test_simulate_me(fmu);\r
+\r
+ printf("Everything seems to be OK since you got this far=)!\n");\r
+ {\r
+ fmul_t fmus;\r
+ fmus.callBackFunctions = callBackFunctions;\r
+ fmus.callbacks = callbacks;\r
+ fmus.context = context;\r
+ fmus.fmu = fmu;\r
+ return fmus;\r
+ }\r
+}\r
+\r
+void destroy(fmul_t* fmus) {\r
+ fmi1_import_destroy_dllfmu(fmus->fmu);\r
+ fmi1_import_free(fmus->fmu);\r
+ fmi_import_free_context(fmus->context);\r
+ free(fmus->callbacks);\r
+ memset(fmus, 0, sizeof(fmul_t));\r
+}\r
+ \r
+/* Load and simulate 150 FMUs. Destroy and free all memory last. Usefull testing speciall for the registerGlobally functionality. */\r
+#define NUMBER_OF_TESTS 150\r
+int main(int argc, char *argv[])\r
+{\r
+ fmul_t fmul[NUMBER_OF_TESTS];\r
+ int k;\r
+ \r
+ for (k=0;k<NUMBER_OF_TESTS;k++) {\r
+ fmul[k] = load(argc, argv);\r
+ }\r
+\r
+ for (k=0;k<NUMBER_OF_TESTS;k++) {\r
+ destroy(&fmul[k]);\r
+ }\r
+\r
+ do_exit(CTEST_RETURN_SUCCESS);\r
+}\r