diff --git a/Makefile.common b/Makefile.common index 28c82a32ef5..cbc631e066f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -374,9 +374,9 @@ openblas-clean: test ! -d 3rdParty/OpenBLAS-0.2.8 || $(MAKE) -C 3rdParty/OpenBLAS-0.2.8 clean > /dev/null 2>&1 ifeq ($(OMENCRYPTION),yes) -clean: semla-clean fmil-clean opencl_rt_clean gc-clean lis-clean runtimeCPPclean CMinpack-clean metis-clean Cdaskr-clean bootstrap-clean msgpack-clean graphstream-clean openblas-clean umfpack-clean +clean: semla-clean fmil-clean opencl_rt_clean gc-clean lis-clean runtimeCPPclean CMinpack-clean metis-clean Cdaskr-clean bootstrap-clean msgpack-clean graphstream-clean openblas-clean umfpack-clean OMSI-clean else -clean: fmil-clean opencl_rt_clean gc-clean lis-clean runtimeCPPclean CMinpack-clean metis-clean Cdaskr-clean bootstrap-clean msgpack-clean graphstream-clean openblas-clean umfpack-clean +clean: fmil-clean opencl_rt_clean gc-clean lis-clean runtimeCPPclean CMinpack-clean metis-clean Cdaskr-clean bootstrap-clean msgpack-clean graphstream-clean openblas-clean umfpack-clean OMSI-clean endif (cd SimulationRuntime/c && $(MAKE) -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR)) (cd Compiler && $(MAKE) -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR)) diff --git a/Makefile.in b/Makefile.in index 8190f56c87d..d1ff2814b3e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -74,15 +74,16 @@ MINGW_EXTRA_LIBS=@MINGW_EXTRA_LIBS@ SUITESPARSE_LIBS = -DKLU_LIBRARY="libklu$(SHREXT)" -DAMD_LIBRARY="libamd$(SHREXT)" -DCOLAMD_LIBRARY="libcolamd$(SHREXT)" -DBTF_LIBRARY="libbtf$(SHREXT)" include Makefile.common +include Makefile.omsi.common # We don't need OMDEV hacks, but using the same Makefile sure is nice! .testvariables: settings: ifeq ($(OMENCRYPTION),yes) -omc: semla omc-bootstrapped +omc: semla omc-bootstrapped OMSI else -omc: omc-bootstrapped +omc: omc-bootstrapped OMSI endif boehm-gc-lib: @LIBGC@ diff --git a/Makefile.omdev.mingw b/Makefile.omdev.mingw index b9b866415d2..62b24e7f5d9 100644 --- a/Makefile.omdev.mingw +++ b/Makefile.omdev.mingw @@ -13,7 +13,7 @@ ifeq (clang,$(findstring clang,$(CC))) endif # makefile for Windows MinGW OMDev -all : .testvariables settings omc +all : .testvariables settings omc autoconfGeneratedFiles = @@ -93,6 +93,9 @@ BOOTSTRAP_FMIL_DEP=fmil defaultMakefileTarget = Makefile.omdev.mingw MAKEFILE_BOOT = LinkMain.makefile.mingw +include Makefile.common +include Makefile.omsi.common + # For Windows build static FMI lib! FMILIB_SHARED = OFF # For Windows build static CMinpack lib! @@ -105,8 +108,6 @@ else # mingw64 PLATFORM_ARCH = (64-bit) endif -include Makefile.common - getMSVCversion: echo "Check for given VSVERSION (2010|2012|2013|2015) version: [VSVERSION=$(VSVERSION)]" ifeq ("$(VSVERSION)","") @@ -281,9 +282,9 @@ copycppmsvcheader: getMSVCversion (cp -pufr $(BOOST_PATH_MSVC)/boost/* $(OMBUILDDIR)/include/omc/cpp/3rdParty/boost/msvc/boost) ifeq ($(OMENCRYPTION),yes) -omc: interactive fmil omdev_extra_dlls breakprocess opencl_rt CMinpack metis Cdaskr $(IPOPT_TARGET) graphstream semla +omc: interactive fmil omdev_extra_dlls breakprocess opencl_rt CMinpack metis Cdaskr $(IPOPT_TARGET) graphstream semla OMSI else -omc: interactive fmil omdev_extra_dlls breakprocess opencl_rt CMinpack metis Cdaskr $(IPOPT_TARGET) graphstream +omc: interactive fmil omdev_extra_dlls breakprocess opencl_rt CMinpack metis Cdaskr $(IPOPT_TARGET) graphstream OMSI endif (time $(MAKE) -f $(defaultMakefileTarget) CFLAGS="$(CFLAGS)" omc-bootstrapped OMBUILDDIR=$(OMBUILDDIR)) diff --git a/Makefile.omsi.common b/Makefile.omsi.common new file mode 100644 index 00000000000..056a2ab07be --- /dev/null +++ b/Makefile.omsi.common @@ -0,0 +1,86 @@ +# Makefile for build omsi base libraries + +# Specify a list of target platforms, including dynamic, static +PLATFORMS=static dynamic + + +CMAKE_FLAGS=-DCMAKE_BUILD_TYPE=$(BUILDTYPE) + +CMAKE_CALL=cmake -G $(CMAKE_TARGET) --build . -DPLATFORM=$(PLATFORM) $(CMAKE_FLAGS) $(IS_MINGW32) $(IS_MINGW64) -DCMAKE_INSTALL_PREFIX:PATH="$(OMBUILDDIR)" -DLIB_OMC=$(LIB_OMC) .. + +.PHONY: OMSIBaseClean + + +############################# +# Rules for OMSI +############################# + +OMSI: OMSIBaseInstall + + + +OMSI-clean: OMSIBaseClean + cd $(OMBUILDDIR); \ + rm -rf include/omc/omsi; \ + rm -rf $(LIB_OMC)/omsi; + + +############################# +# Rules for OMSIBase library +############################# + +OMSIBase: sundials + cd SimulationRuntime/OMSI; \ + $(foreach PLATFORM, $(PLATFORMS), \ + mkdir -p Build_$(PLATFORM); \ + (cd ./Build_$(PLATFORM); echo "change to Build_$(PLATFORM)"; \ + $(CMAKE_CALL); \ + $(MAKE) );) + +OMSIBaseMSVC: getMSVCversion + test -f """${VSCOMNTOOLS}/../../VC/vcvarsall.bat""" + echo 'Build the cppRuntime with MSVC' buildtype: $(BUILDTYPE) + #rm -rf Build_MSVC + mkdir -p Build_MSVC + echo call '"${VSCOMNTOOLS}\\..\\..\\VC\\vcvarsall.bat" ${VCVARS_PARAMS}' > Build_MSVC/build.bat + + echo echo Running CMake from '%OMDEV%\\bin\\cmake\\bin\\cmake' >> Build_MSVC/build.bat + echo '%OMDEV%\\bin\\cmake\\bin\\cmake -DCMAKE_VERBOSE_MAKEFILE:Bool=ON -DPLATFORM="dynamic" $(CMAKE_FLAGS) -DIS_MINGW32=OFF -DIS_MINGW64=OFF -DCMAKE_INSTALL_PREFIX:PATH=./tmp ../ -G "NMake Makefiles JOM" -D"CMAKE_MAKE_PROGRAM:PATH=%OMDEV%\\tools\\jom\\jom.exe"' >> Build_MSVC/build.bat + + # for some reason, the environment variable 'MAKEFLAGS' was set to 'w' on my and Niklas' machine?! + echo set MAKEFLAGS="" >> Build_MSVC/build.bat + echo echo Running NMake JOM >> Build_MSVC/build.bat + echo %OMDEV%\\tools\\jom\\jom.exe /f Makefile install >> Build_MSVC/build.bat + cd ./Build_MSVC; echo "change to Build_MSVC";\ + cmd /c build.bat + + echo 'Build cppRuntime (static) with MSVC' + #rm -rf Build_MSVC_static + mkdir -p Build_MSVC_static + echo call '"${VSCOMNTOOLS}\\..\\..\\VC\\vcvarsall.bat" ${VCVARS_PARAMS}' > Build_MSVC_static/build.bat + + echo echo Running CMake from '%OMDEV%\\bin\\cmake\\bin\\cmake' >> Build_MSVC_static/build.bat + echo '%OMDEV%\\bin\\cmake\\bin\\cmake -DCMAKE_VERBOSE_MAKEFILE:Bool=ON -DPLATFORM="static" $(CMAKE_FLAGS) -DIS_MINGW32=OFF -DIS_MINGW64=OFF -DCMAKE_INSTALL_PREFIX:PATH=./tmp ../ -G "NMake Makefiles JOM" -D"CMAKE_MAKE_PROGRAM:PATH=%OMDEV%\\tools\\jom\\jom.exe"' >> Build_MSVC_static/build.bat + + # for some reason, the environment variable 'MAKEFLAGS' was set to 'w' on my and Niklas' machine?! + echo set MAKEFLAGS="" >> Build_MSVC_static/build.bat + echo echo Running NMake JOM >> Build_MSVC_static/build.bat + echo %OMDEV%\\tools\\jom\\jom.exe /f Makefile install >> Build_MSVC_static/build.bat + cd ./Build_MSVC_static; echo "change to Build_MSVC_static";\ + cmd /c build.bat + + # move folder to build dir + cp -R --verbose Build_MSVC/tmp/* $(builddir_build) + cp -R --verbose Build_MSVC_static/tmp/lib/* $(builddir_build)/lib + +OMSIBaseInstall: OMSIBase + cd SimulationRuntime/OMSI; \ + $(foreach PLATFORM, $(PLATFORMS), \ + (cd Build_$(PLATFORM); $(MAKE) install);) + +OMSIBaseClean: + cd SimulationRuntime/OMSI; \ + $(foreach PLATFORM, $(PLATFORMS), \ + test -d Build_$(PLATFORM) && cd Build_$(PLATFORM) && $(MAKE) uninstall && $(MAKE) DESTDIR=$(OMBUILDDIR) clean && cd ..; \ + rm -R -f Build_$(PLATFORM); \ + ) diff --git a/SimulationRuntime/OMSI/CMakeLists.txt b/SimulationRuntime/OMSI/CMakeLists.txt new file mode 100644 index 00000000000..60d77971524 --- /dev/null +++ b/SimulationRuntime/OMSI/CMakeLists.txt @@ -0,0 +1,85 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9) +SET(CMAKE_VERBOSE_MAKEFILE ON) +MESSAGE(STATUS "CMake version ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}") + +PROJECT(OMSIBaseSimulationRuntime) + +# enable warnings and use ANSI C compatible compiler +if(CMAKE_COMPILER_IS_GNUCXX) + message(STATUS "GCC detected, adding compile flags") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -ansi -pedantic -g") + IF(NOT WIN32) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + ENDIF() +endif(CMAKE_COMPILER_IS_GNUCXX) +message(STATUS "Compiling with C flags: ${CMAKE_C_FLAGS}") + + + +if(NOT PLATFORM OR PLATFORM STREQUAL "dynamic") + set(BUILD_SHARED_LIBS ON) +elseif(PLATFORM STREQUAL "static") + set(BUILD_SHARED_LIBS OFF) +else() +endif() + + + +IF(BUILD_SHARED_LIBS) + SET(LIBSUFFIX "") +ELSE(BUILD_SHARED_LIBS) + SET(LIBSUFFIX "_static") +ENDIF(BUILD_SHARED_LIBS) + + + +IF(MSVC) + MESSAGE(STATUS "MSVC") + IF(LIB_OMC) + SET(LIBINSTALLEXT "${LIB_OMC}/omsi/msvc" CACHE STRING "library directory" FORCE) + ELSE(LIB_OMC) + SET(LIBINSTALLEXT "omsi/msvc" CACHE STRING "library directory" FORCE) + ENDIF(LIB_OMC) +ELSE(MSVC) + IF(LIB_OMC) + SET(LIBINSTALLEXT "${LIB_OMC}/omsi" CACHE STRING "library directory" FORCE) + ELSE(LIB_OMC) + SET(LIBINSTALLEXT "omsi" CACHE STRING "library directory" FORCE) + ENDIF(LIB_OMC) +ENDIF(MSVC) +message(STATUS "Libs will be installed in ${CMAKE_INSTALL_PREFIX}/${LIBINSTALLEXT}") + +SET(OSUBaseName ${LIBPREFIX}OMSIBase${LIBSUFFIX}) +SET(OMSISolverName ${LIBPREFIX}OMSISolver${LIBSUFFIX}) + +include_directories ("${CMAKE_SOURCE_DIR}/include") +# omsi base simulation runtime +ADD_SUBDIRECTORY(base) +ADD_SUBDIRECTORY(solver) + +install(FILES + ${CMAKE_SOURCE_DIR}/include/omsi.h + ${CMAKE_SOURCE_DIR}/include/omsi_callbacks.h + ${CMAKE_SOURCE_DIR}/include/omsi_api_functions.h + DESTINATION include/omc/omsi) + +install(FILES + ${CMAKE_SOURCE_DIR}/include/fmi2/omsi_fmi2_cs.h + ${CMAKE_SOURCE_DIR}/include/fmi2/omsi_fmi2_me.h + ${CMAKE_SOURCE_DIR}/include/fmi2/omsi_fmi2_wrapper.h + DESTINATION include/omc/omsi/fmi2/) + +# uninstall target +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + + + + diff --git a/SimulationRuntime/OMSI/base/CMakeLists.txt b/SimulationRuntime/OMSI/base/CMakeLists.txt new file mode 100644 index 00000000000..2b27e67aff1 --- /dev/null +++ b/SimulationRuntime/OMSI/base/CMakeLists.txt @@ -0,0 +1,57 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9) +#OMSI base simulation runtime +PROJECT(OMSIBASE) +SET(CMAKE_VERBOSE_MAKEFILE ON) + +#set exapat lib for visual studio compiler +IF(MSVC) + INCLUDE_DIRECTORIES($ENV{OMDEV}/lib/expat-win32-msvc) + link_directories($ENV{OMDEV}/lib/expat-win32-msvc) + link_directories($ENV{OMDEV}/lib/lapack-win32-msvc) + set(expat_lib "libexpat") +ELSE(MSVC) + set(expat_lib "expat") +ENDIF(MSVC) + +include_directories ("${CMAKE_SOURCE_DIR}/base/include" "${CMAKE_SOURCE_DIR}/solver/include") +add_library(${OSUBaseName} + src/omsi_event_helper.c + src/omsi_getters_and_setters.c + src/omsi_initialization.c + src/omsi_input_json.c + src/omsi_input_model_variables.c + src/omsi_input_sim_data.c + src/omsi_input_xml.c + src/omsi_mmap.c + src/omsi_posix_func.c + src/omsi_solve_alg_system.c + src/omsi_utils.c) + +include_directories ("${OMSI_SOURCE_DIR}/solver/include") + +IF(WIN32) + target_link_libraries(${OSUBaseName} ${OMSISolverName} ${CMAKE_DL_LIBS} wsock32 ws2_32 ${expat_lib}) +ELSE(WIN32) + target_link_libraries(${OSUBaseName} ${OMSISolverName} ${CMAKE_DL_LIBS} ) +ENDIF(WIN32) + +install(TARGETS ${OSUBaseName} DESTINATION ${LIBINSTALLEXT}) + +install(FILES + ${CMAKE_SOURCE_DIR}/base/include/omsi_event_helper.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_getters_and_setters.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_global.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_initialization.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_input_json.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_input_model_variables.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_input_sim_data.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_input_xml.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_mmap.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_posix_func.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_solve_alg_system.h + ${CMAKE_SOURCE_DIR}/base/include/omsi_utils.h + ${CMAKE_SOURCE_DIR}/base/include/uthash.h + DESTINATION include/omc/omsi/base) + + + diff --git a/SimulationRuntime/OMSI/base/include/omsi_event_helper.h b/SimulationRuntime/OMSI/base/include/omsi_event_helper.h new file mode 100644 index 00000000000..a74b1ac3a7a --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_event_helper.h @@ -0,0 +1,71 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + + +#ifndef OMSI_EVENT_HELPER__H_ +#define OMSI_EVENT_HELPER__H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include /* fmin, fmod */ + +/* Public OMSI headers */ +#include +#include + + +/* Function prototypes */ +omsi_bool omsi_function_zero_crossings (omsi_function_t* this_function, + omsi_bool new_zero_crossing, + omsi_unsigned_int index, + ModelState model_state); + +omsi_bool omsi_on_sample_event (omsi_function_t* this_function, + omsi_unsigned_int sample_id, + ModelState model_state); + +omsi_real omsi_next_sample(omsi_real time, + omsi_sample* sample_event); + +omsi_real omsi_compute_next_event_time (omsi_real time, + omsi_sample* sample_events, + omsi_unsigned_int n_sample_events); + +omsi_bool omsi_check_discrete_changes (omsi_t* omsi_data); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/SimulationRuntime/OMSI/base/include/omsi_getters_and_setters.h b/SimulationRuntime/OMSI/base/include/omsi_getters_and_setters.h new file mode 100644 index 00000000000..8dbc20c7b94 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_getters_and_setters.h @@ -0,0 +1,121 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef OMSU_INPUT_MODEL_VARIABLES_H +#define OMSU_INPUT_MODEL_VARIABLES_H + +#include +#include + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Public function prototypes */ +omsi_status omsi_get_real(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_real* value); + +omsi_status omsi_get_integer(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_int* value); + +omsi_status omsi_get_boolean(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_bool* value); + +omsi_status omsi_get_string(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_string* value); + +omsi_status omsi_set_real(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_real* value); + +omsi_status omsi_set_integer(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_int* value); + +omsi_status omsi_set_boolean(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_bool* value); + +omsi_status omsi_set_string(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_string* value); + +/* Private function prototypes */ +omsi_real getReal (omsi_t* osu_data, + const omsi_unsigned_int vr); + +omsi_status setReal(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_real value); + +omsi_int getInteger (omsi_t* osu_data, + const omsi_unsigned_int vr); + +omsi_status setInteger(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_int value); + +omsi_bool getBoolean (omsi_t* osu_data, + const omsi_unsigned_int vr); + +omsi_status setBoolean(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_bool value); + +omsi_string getString (omsi_t* osu_data, + const omsi_unsigned_int vr); + +omsi_status setString(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_string value); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_global.h b/SimulationRuntime/OMSI/base/include/omsi_global.h new file mode 100644 index 00000000000..58b217f44a9 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_global.h @@ -0,0 +1,56 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ +#ifndef OMSI_GLOBAL +#define OMSI_GLOBAL + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#ifndef OMSI_GLOBAL_CALLBACK +#define OMSI_GLOBAL_CALLBACK + +/* global callback functions */ +extern omsi_callback_functions* global_callback; + +/* global variables used for filtered_base_logger */ +extern omsi_string global_instance_name; +extern omsi_bool* global_logCategories; + +/* global pointer to model state */ +extern ModelState* global_model_state; + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif +#endif +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_initialization.h b/SimulationRuntime/OMSI/base/include/omsi_initialization.h new file mode 100644 index 00000000000..728178348c0 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_initialization.h @@ -0,0 +1,76 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + + +#ifndef OMSI_INITIALIZATION__H_ +#define OMSI_INITIALIZATION__H_ + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include +#include + +/* Public OMSI headers */ +#include +#include + +/* OMSIBase headers */ +#include +#include +#include +#include +#include + +typedef struct modelDescriptionData { + omsi_char* modelName; +} modelDescriptionData; + + +omsi_t* omsi_instantiate(omsi_string instanceName, + omsu_type fmuType, + omsi_string fmuGUID, + omsi_string fmuResourceLocation, + const omsi_callback_functions* functions, + omsi_template_callback_functions_t* template_functions, + omsi_bool __attribute__((unused)) visible, + omsi_bool loggingOn, + ModelState* model_state); + +omsi_string omsi_get_model_name(omsi_string fmuResourceLocation); + +omsi_status omsi_intialize_callbacks(omsi_t* omsu, + omsi_template_callback_functions_t* template_functions ); +#ifdef __cplusplus +} +#endif +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_input_json.h b/SimulationRuntime/OMSI/base/include/omsi_input_json.h new file mode 100644 index 00000000000..99c96ef0d46 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_input_json.h @@ -0,0 +1,73 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef OMSU_INPUT_JSON_H +#define OMSU_INPUT_JSON_H + +#include +#include + +#include +#include +#include + +#include +#include + + + +/* function prototypes */ +omsi_status omsu_process_input_json(omsi_t* osu_data, + omsi_string fileName, + omsi_string fmuGUID, + omsi_string instanceName, + const omsi_callback_functions* functions); + +omsi_string readEquation(omsi_string str, + equation_info_t* equation_info, + omsi_unsigned_int expected_id, + omsi_unsigned_int* count_init_eq, + omsi_unsigned_int* count_regular_eq, + omsi_unsigned_int* count_alias_eq); + +omsi_string readEquations(omsi_string str, + model_data_t* model_data); + + + + + + + + + + + +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_input_model_variables.h b/SimulationRuntime/OMSI/base/include/omsi_input_model_variables.h new file mode 100644 index 00000000000..c5211fc6163 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_input_model_variables.h @@ -0,0 +1,71 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef OMSU_INPUT_MODEL_VARIABLES_H +#define OMSU_INPUT_MODEL_VARIABLES_H + +#include +#include + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* public function prototypes */ + +omsi_status omsi_allocate_model_variables(omsi_t* omsu, + const omsi_callback_functions* functions); + +omsi_status omsi_initialize_model_variables(omsi_t* omsu, + const omsi_callback_functions* functions, + omsi_string instanceName); + +omsi_status omsi_free_model_variables(sim_data_t* sim_data); + + +void *alignedMalloc(size_t required_bytes, + size_t alignment); + +void alignedFree(void* p); + +omsi_bool model_variables_allocated(omsi_t* omsu, + omsi_string functionName); + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_input_sim_data.h b/SimulationRuntime/OMSI/base/include/omsi_input_sim_data.h new file mode 100644 index 00000000000..a00f93e11eb --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_input_sim_data.h @@ -0,0 +1,102 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef OMSU_INPUT_SIM_DATA_H +#define OMSU_INPUT_SIM_DATA_H + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* function prototypes */ + +omsi_status omsu_setup_sim_data(omsi_t* omsi_data, + omsi_template_callback_functions_t* template_function, + const omsi_callback_functions* callback_functions); + +omsi_status omsu_setup_sim_data_omsi_function(sim_data_t* sim_data, + omsi_string function_name, + omsu_initialize_omsi_function template_instantiate_function); + +omsi_status omsu_allocate_sim_data(omsi_t* omsi_data, const omsi_callback_functions* callback_functions, omsi_string instanceName); + +omsi_status omsu_instantiate_omsi_function_func_vars (omsi_function_t* omsi_function, + omsi_values* function_vars, + omsi_values* pre_vars) ; + +omsi_status omsu_set_zerocrossings_omsi_functions (omsi_function_t* omsi_function, + omsi_real* pointer_to_zerocrossings_vars, + omsi_real* pointer_to_pre_zerocrossings_vars, + omsi_sample* sample_events); + +omsi_function_t* omsu_instantiate_omsi_function (omsi_values* function_vars, + omsi_values* pre_vars); + +omsi_algebraic_system_t* omsu_instantiate_alg_system_array (omsi_unsigned_int n_algebraic_system); + +omsi_status omsu_set_model_vars_and_params_start (omsi_values* model_vars_and_params, + model_data_t* model_data); + +omsi_values* instantiate_omsi_values (omsi_unsigned_int n_reals, + omsi_unsigned_int n_ints, + omsi_unsigned_int n_bools, + omsi_unsigned_int n_externs); + +omsi_status omsu_set_template_functions (omsi_template_callback_functions_t* template_callback); + +omsi_status instantiate_input_inner_output_indices (omsi_function_t* omsi_function, + omsi_unsigned_int n_input_vars, + omsi_unsigned_int n_output_vars); + +omsi_status omsu_set_default_solvers (omsi_function_t* omsi_function, + omsi_string omsi_function_name); + +void omsu_set_initial_guess (omsi_algebraic_system_t* algebraic_system); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_input_xml.h b/SimulationRuntime/OMSI/base/include/omsi_input_xml.h new file mode 100644 index 00000000000..fc7ff803a4a --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_input_xml.h @@ -0,0 +1,188 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef OMSU_INPUT_XML_H +#define OMSU_INPUT_XML_H + + +#include /* use expat XML parser */ +#include /* use uthash as hash table for C*/ + +#include +#include + +#include +#include + +#include + +/* typedefs for structures */ +typedef struct hash_string_string { + omsi_string id; /* key */ + omsi_string val; /* value */ + UT_hash_handle hh; /* makes this structure hashable */ +} hash_string_string; + +typedef hash_string_string omc_ModelDescription; +typedef hash_string_string omc_DefaultExperiment; +typedef hash_string_string omc_ScalarVariable; + +typedef struct hash_long_var { + omsi_long id; /* key */ + omc_ScalarVariable *val; /* value */ + UT_hash_handle hh; /* makes this structure hashable */ +} hash_long_var; + +typedef hash_long_var omc_ModelVariables; + +typedef struct hash_string_long { + omsi_string id; /* key */ + omsi_long val; /* value */ + UT_hash_handle hh; /* makes this structure hashable */ +} hash_string_long; + +/* structure used to collect data from the xml input file */ +typedef struct omc_ModelInput { + omc_ModelDescription *md; /* model description */ + omc_DefaultExperiment *de; /* default experiment */ + + omc_ModelVariables *rSta; /* states */ + omc_ModelVariables *rDer; /* derivatives */ + omc_ModelVariables *rAlg; /* algebraic */ + omc_ModelVariables *rPar; /* parameters */ + omc_ModelVariables *rAli; /* aliases */ + omc_ModelVariables *rSen; /* sensitivities */ + + omc_ModelVariables *iAlg; /* int algebraic */ + omc_ModelVariables *iPar; /* int parameters */ + omc_ModelVariables *iAli; /* int aliases */ + + omc_ModelVariables *bAlg; /* bool algebraic */ + omc_ModelVariables *bPar; /* bool parameters */ + omc_ModelVariables *bAli; /* bool aliases */ + + omc_ModelVariables *sAlg; /* string algebraic */ + omc_ModelVariables *sPar; /* string parameters */ + omc_ModelVariables *sAli; /* string aliases */ + + /* these two we need to know to be able to add + the stuff in , to + the correct variable in the correct map */ + omsi_long lastCI; /* index */ + omc_ModelVariables** lastCT; /* type (classification) */ +} omc_ModelInput; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* public function prototypes */ +omsi_status omsu_process_input_xml(omsi_t* osu_data, + omsi_string filename, + omsi_string fmuGUID, + omsi_string instanceName, + const omsi_callback_functions* functions); + + + +/*private function prototypes */ +omsi_int omsu_find_alias_index(omsi_int alias_valueReference, + omsi_int n_variables); + +void omsu_read_var_info (omc_ScalarVariable* v, + model_variable_info_t* model_var_info, + omsi_data_type type, + omsi_unsigned_int* variable_index, + omsi_int number_of_prev_variables); + +void omsu_read_var_infos(model_data_t* model_data, + omc_ModelInput* mi); + +omsi_string omsu_findHashStringStringNull(hash_string_string* ht, + omsi_string key); + +omsi_string omsu_findHashStringStringEmpty(hash_string_string* ht, + omsi_string key); + +omsi_string omsu_findHashStringString(hash_string_string* ht, + omsi_string key); + +void omsu_addHashLongVar(hash_long_var** ht, + omsi_long key, + omc_ScalarVariable* val); + +void omsu_addHashStringString(hash_string_string** ht, + omsi_string key, + omsi_string val); + +void omsu_read_value_int(omsi_string s, + omsi_int* res, + omsi_int default_value); + +void omsu_read_value_uint(omsi_string s, + omsi_unsigned_int* res); + +omc_ScalarVariable** omsu_findHashLongVar(hash_long_var *ht, + omsi_long key); + +void omsu_read_value_real(omsi_string s, + omsi_real* res, + omsi_real default_value); + +void omsu_read_value_bool(omsi_string s, + omsi_bool* res); + +void omsu_read_value_bool_default (omsi_string s, + omsi_bool* res, + omsi_bool default_bool); + +void omsu_read_value_string(omsi_string s, + omsi_char** str); + +void XMLCALL startElement(void* userData, + omsi_string name, + omsi_string* attr); + +void XMLCALL endElement(void* userData, + omsi_string name); + +void omsu_free_ModelInput(omc_ModelInput* mi); + +void free_hash_string_string (hash_string_string* data); + +void free_hash_long_var (hash_long_var* data); + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_mmap.h b/SimulationRuntime/OMSI/base/include/omsi_mmap.h new file mode 100644 index 00000000000..a262b234b0e --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_mmap.h @@ -0,0 +1,120 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#if !defined(OMC_MMAP_H_) && !defined(OMC_NO_FILESYSTEM) +#define OMC_MMAP_H_ + +#include +#include + + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(HAVE_MMAP) +#if defined(unix) || defined(__APPLE__) +#include +#endif +#if _POSIX_MAPPED_FILES>0 +#define HAVE_MMAP 1 +#else +#define HAVE_MMAP 0 +#endif +#endif + +#if HAVE_MMAP +#include +#include +#include +#include +#include +#endif + +typedef struct { + omsi_unsigned_int size; + omsi_string data; +} omc_mmap_read_unix; + +typedef struct { + omsi_unsigned_int size; + omsi_char *data; +} omc_mmap_write_unix; + +typedef struct { + omsi_unsigned_int size; + omsi_string data; +} omc_mmap_read_inmemory; + +typedef struct { + omsi_unsigned_int size; + FILE *file; + omsi_char *data; +} omc_mmap_write_inmemory; + +omc_mmap_read_inmemory omc_mmap_open_read_inmemory(omsi_string filename); +omc_mmap_write_inmemory omc_mmap_open_write_inmemory(omsi_string filename, omsi_unsigned_int size); +void omc_mmap_close_read_inmemory(omc_mmap_read_inmemory map); +void omc_mmap_close_write_inmemory(omc_mmap_write_inmemory map); + +#if HAVE_MMAP + +omc_mmap_read_unix omc_mmap_open_read_unix(omsi_string filename); +omc_mmap_write_unix omc_mmap_open_write_unix(omsi_string filename, omsi_unsigned_int size); +void omc_mmap_close_read_unix(omc_mmap_read_unix map); +void omc_mmap_close_write_unix(omc_mmap_write_unix map); + +typedef omc_mmap_read_unix omc_mmap_read; +typedef omc_mmap_write_unix omc_mmap_write; +#define omc_mmap_open_read(X) omc_mmap_open_read_unix(X); +#define omc_mmap_open_write(X,Y) omc_mmap_open_write_unix(X,Y); +#define omc_mmap_close_read(X) omc_mmap_close_read_unix(X); +#define omc_mmap_close_write(X) omc_mmap_close_write_unix(X); + +#else + +typedef omc_mmap_read_inmemory omc_mmap_read; +typedef omc_mmap_write_inmemory omc_mmap_write; +#define omc_mmap_open_read(X) omc_mmap_open_read_inmemory(X); +#define omc_mmap_open_write(X,Y) omc_mmap_open_write_inmemory(X,Y); +#define omc_mmap_close_read(X) omc_mmap_close_read_inmemory(X); +#define omc_mmap_close_write(X) omc_mmap_close_write_inmemory(X); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_posix_func.h b/SimulationRuntime/OMSI/base/include/omsi_posix_func.h new file mode 100644 index 00000000000..0bb0e5e1b4b --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_posix_func.h @@ -0,0 +1,56 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + + +#ifndef OMSI_POSIX_FUNC__H_ +#define OMSI_POSIX_FUNC__H_ + +#ifndef POSIX + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +omsi_char* omsi_strdup (const omsi_char *s); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_solve_alg_system.h b/SimulationRuntime/OMSI/base/include/omsi_solve_alg_system.h new file mode 100644 index 00000000000..e62eb0ac6e6 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_solve_alg_system.h @@ -0,0 +1,79 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + + +#ifndef OMSI_SOLVE_ALG_SYSTEM__H_ +#define OMSI_SOLVE_ALG_SYSTEM__H_ + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include +#include + +/* Public OMSI headers */ +#include +#include +#include + +/* OMSI Solver header */ +#include +#include + + +/* Function prototypes */ +omsi_status omsi_solve_algebraic_system (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params); + +omsi_status omsi_get_analytical_jacobian (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params); + +omsi_status omsi_get_right_hand_side (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params); + +omsi_status omsi_get_loop_results (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params, + omsi_values* vars); + +omsi_status omsi_set_up_solver (omsi_algebraic_system_t* alg_system); + +omsi_int omsi_residual_wrapper (omsi_real* x_data, + omsi_real* fval_data, + void* data); + +omsi_int omsi_update_guess (solver_data* solver, + omsi_algebraic_system_t* alg_system_data); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/SimulationRuntime/OMSI/base/include/omsi_utils.h b/SimulationRuntime/OMSI/base/include/omsi_utils.h new file mode 100644 index 00000000000..13af235b1f8 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/omsi_utils.h @@ -0,0 +1,163 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/* + * This file defines functions for the FMI used via the OpenModelica Simulation + * Interface (OMSI). These are helper functions used for the other omsu functions. + */ + +#ifndef OMSU_UTILS__H_ +#define OMSU_UTILS__H_ + + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#if _MSC_VER +#define __attribute__(x) +#endif + + +/* function prototypes */ +void filtered_base_logger(omsi_bool* logCategories, /* Array of categories, that should be logged, can be NULL */ + log_categories category, /* Category of this log call */ + omsi_status status, /* Status for logger */ + omsi_string message, /* Message for logger */ + ...); /* Optional arguments in message */ + +void wrapper_alg_system_logger (solver_log_level log_level, + omsi_string message, ...); + +omsi_bool isCategoryLogged(omsi_bool* logCategories, + log_categories categoryIndex); + +void omsu_free_osu_data(omsi_t* omsi_data); + +void omsu_free_model_data (model_data_t* model_data); + +void omsu_free_model_variable_info(model_variable_info_t* model_vars_info, + omsi_unsigned_int size); + +void omsu_free_modelica_attributes(void* modelica_attribute, + omsi_data_type type); + +void omsu_free_equation_info(equation_info_t* eq_info, + omsi_unsigned_int n_equations ); + +void omsu_free_sim_data (sim_data_t* sim_data); + +void omsu_free_omsi_function(omsi_function_t* omsi_function, + omsi_bool shared_vars); + +void omsu_free_alg_system (omsi_algebraic_system_t* algebraic_system, + omsi_bool shared_vars); + +void omsu_free_omsi_values(omsi_values* values); + +omsi_bool omsi_vr_out_of_range(omsi_t* omsu, + omsi_string function_name, + omsi_unsigned_int vr, + omsi_int end); + +omsi_int omsi_get_negated_index (model_variable_info_t* model_var_info, + omsi_unsigned_int value_reference); + +void omsu_print_omsi_t (omsi_t* omsi, + omsi_string indent); + +void omsu_print_model_data(model_data_t* model_data, + omsi_string indent); + +omsi_status omsu_print_model_variable_info(model_data_t* model_data, + omsi_string indent); + +omsi_status omsu_print_modelica_attributes (void* modelica_attribute, + omsi_index_type* type_index, + omsi_string indent); + +void omsu_print_real_var_attribute (real_var_attribute_t* real_var_attribute, + omsi_string indent); + +void omsu_printf_int_var_attribute(int_var_attribute_t* int_var_attribute, + omsi_string indent); + +omsi_status omsu_print_equation_info(model_data_t* model_data, + omsi_string indent); + +void omsu_print_experiment (omsi_experiment_t* experiment, + omsi_string indent); + +omsi_status omsu_print_sim_data (sim_data_t* sim_data, + omsi_string indent); + +omsi_status omsu_print_omsi_function_rec (omsi_function_t* omsi_function, + omsi_string omsi_function_name, + omsi_string indent); + +omsi_status omsu_print_this_omsi_function (omsi_function_t* omsi_function, + omsi_string omsi_function_name, + omsi_string indent); + +omsi_status omsu_print_omsi_values (omsi_values* omsi_values, + omsi_string omsi_values_name, + omsi_string indent); + +omsi_status omsu_print_algebraic_system(omsi_algebraic_system_t* algebraic_system_t, + omsi_string indent); + +omsi_status omsu_print_index_type (omsi_index_type* vars_indices, + omsi_unsigned_int size, + omsi_string indent); + +omsi_status omsu_print_externs(void* externs, + omsi_unsigned_int n_externs); + +omsi_status omsu_print_solver_data(omsi_string solver_name, + void* solver_data, + omsi_string indent); +#ifdef __cplusplus +} +#endif +#endif diff --git a/SimulationRuntime/OMSI/base/include/uthash.h b/SimulationRuntime/OMSI/base/include/uthash.h new file mode 100644 index 00000000000..26d94ff3ab8 --- /dev/null +++ b/SimulationRuntime/OMSI/base/include/uthash.h @@ -0,0 +1,942 @@ +/* +Copyright (c) 2003-2013, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +#include + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.8 + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) global_callback->allocateMemory(1,sz) /* malloc fcn*/ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) global_callback->freeMemory(ptr) /* free fcn */ +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0 +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + replaced=NULL; \ + HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ + if (replaced!=NULL) { \ + HASH_DELETE(hh,head,replaced); \ + }; \ + HASH_ADD(hh,head,fieldname,keylen_in,add); \ +} while(0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = (unsigned)keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ + HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned char *_hj_key=(unsigned char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = (unsigned)keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned char *_sfh_key=(unsigned char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if ((out)->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#define HASH_OVERHEAD(hh,head) \ + (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + (sizeof(UT_hash_table)) + \ + (HASH_BLOOM_BYTELEN))) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_event_helper.c b/SimulationRuntime/OMSI/base/src/omsi_event_helper.c new file mode 100644 index 00000000000..488c9c19cff --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_event_helper.c @@ -0,0 +1,252 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_event_helper.c + */ + +/** \defgroup EventHelper Base event functions. + * \ingroup OMSIBase + * + * \brief Event helper functions provided for OMSIC and OMSICpp. + * + * Defines basic functionalities for event handling. + */ + +/** \addtogroup EventHelper + * \{ */ + +#include + +#include + + +/** + * \brief Evaluate zero crossing. + * + * Return preValue of zeroCrossing in `modelContinuousTimeMode` and value of + * the zeroCrossing in `modelEventMode` and set `pre_zerocrossing_vars` in + * `modelInitializationMode`. + * + * \param [in] this_function OMSI function containing zero crossing. + * \param [in] new_zero_crossing New value for zero_crossing. Only used in eventMode. + * \param [in] index Index of zero crossing to evaluate. + * \param [in] model_state Event mode or continuous-time mode. + * \return `omsi_bool` Return preValue of zeroCrossing in `modelContinuousTimeMode` and value of + * the zeroCrossing in `modelEventMode` and set `pre_zerocrossing_vars` in + * `modelInitializationMode`. + */ +omsi_bool omsi_function_zero_crossings (omsi_function_t* this_function, + omsi_bool new_zero_crossing, + omsi_unsigned_int index, + ModelState model_state) +{ + if (this_function->zerocrossings_vars == NULL + || this_function->pre_zerocrossings_vars == NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Evaluate: in omsi_function_zero_crossings: No memory for zero crossings allocated."); + return new_zero_crossing; + } + /* Update zerocrossing variable */ + if (new_zero_crossing) { + this_function->zerocrossings_vars[index] = 1; + } else { + this_function->zerocrossings_vars[index] = -1; + } + + + /* Return bool */ + if (model_state == modelEventMode ) { + return this_function->zerocrossings_vars[index]>0; + } else if (model_state == modelContinuousTimeMode) { + return this_function->pre_zerocrossings_vars[index]>0; + } else if (model_state == modelInitializationMode) { + this_function->pre_zerocrossings_vars[index] = this_function->zerocrossings_vars[index]; + return this_function->zerocrossings_vars[index]>0; + } else { + return this_function->zerocrossings_vars[index]>0; + } +} + + +/** + * \brief Helper function for sample events. + * + * Check if on sample event. + * + * \param [in] this_function OMSI function containing sample. + * \param [in] sample_id ID of sample to check for. + * \param [in] model_state State of Model. + * \return omsi_bool Return `omsi_true` at time instants `start + i*interval, (i=0, 1, ...)` + * if in `modelEventMode` and `omsi_false` else. + */ +omsi_bool omsi_on_sample_event (omsi_function_t* this_function, + omsi_unsigned_int sample_id, + ModelState model_state) +{ + /* Variables */ + omsi_real modulo_value; + omsi_real time; + omsi_sample* sample; + omsi_bool is_on_sample; + + time = this_function->function_vars->time_value; + sample = &this_function->sample_events[sample_id]; + is_on_sample = omsi_false; + + if (time>= sample->start_time) { + modulo_value = (omsi_real)fmod(time+sample->start_time, sample->interval); + if ((fabs(modulo_value-sample->interval) < 1e-8) || (modulo_value > -1e-8 && modulo_value < 1e-8)) { /* ToDo: Some epsilon */ + is_on_sample = omsi_true; + } + } + + /* Return bool */ + if (model_state == modelEventMode ) { + return is_on_sample; + } else if (model_state == modelContinuousTimeMode) { + return omsi_false; + } else if (model_state == modelInitializationMode) { + printf("Not implemented yet!"); fflush(stdout); + return omsi_false; + } else { + return omsi_false; + } +} + + +/** + * \brief Compute next sample time for given sample. + * + * Helper function for omsi_compute_next_event_time + * + * \param [in] time Current model time. + * \param [in] sample_event Struct with sample event informations. + * \return `omsi_real` Return time for next sample event for this sample. + */ +omsi_real omsi_next_sample(omsi_real time, + omsi_sample* sample_event) +{ + /* Variables */ + omsi_real dist_prev_event; + + /* Compute next sample time */ + if (time < sample_event->start_time - 1e-8) { /* ToDo: minus some epsilon */ + return sample_event->start_time; + } else { + dist_prev_event = fmod(time+sample_event->start_time, sample_event->interval); + if (fabs(dist_prev_event-sample_event->interval) < 1e-8) { /* nearly on an sample event */ + return time + sample_event->interval; + } else { + return time + sample_event->interval - dist_prev_event; + } + } +} + + +/** + * \brief Compute next event time from samples. + * \param [in] time Current model time. + * \param [in] sample_events Array of samples. + * \param [in] n_sample_events Length of array `ample_events`. + * \return `omsi_real` Return time for next sample event. + */ +omsi_real omsi_compute_next_event_time (omsi_real time, + omsi_sample* sample_events, + omsi_unsigned_int n_sample_events) +{ + /* Variables */ + omsi_real next_event_time; + omsi_unsigned_int i; + + if (n_sample_events>0) { + next_event_time = omsi_next_sample(time, &sample_events[0]); + } + else { + next_event_time = -1; + } + + for (i=1; imodel_data->start_index_disc_reals; + n_discrete_real_vars = omsi_data->model_data->n_discrete_reals; + model_vars_and_params = omsi_data->sim_data->model_vars_and_params; + pre_model_vars_and_params = omsi_data->sim_data->pre_vars; + + /* Compare all real discrete variables to pre variables */ + for (i=start_discrete_real_vars; ireals[i] - pre_model_vars_and_params->reals[i]) > 1e-8) { /* ToDo: insert pre vars mapping */ + return omsi_true; + } + } + + /* Compare all integer variables to pre variables */ + for (i=0; imodel_data->n_int_vars; i++) { + if (model_vars_and_params->ints[i] != pre_model_vars_and_params->ints[i] ) { /* ToDo: insert pre vars mapping */ + return omsi_true; + } + } + + /* Compare all integer variables to pre variables */ + for (i=0; imodel_data->n_bool_vars; i++) { + if (model_vars_and_params->bools[i] != pre_model_vars_and_params->bools[i] ) { /* ToDo: insert pre vars mapping */ + return omsi_true; + } + } + + return omsi_false; +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_getters_and_setters.c b/SimulationRuntime/OMSI/base/src/omsi_getters_and_setters.c new file mode 100644 index 00000000000..f73f885740a --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_getters_and_setters.c @@ -0,0 +1,634 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_getters_and_setters.c + * \brief Containing Base getter and setter functions for OMSI Base. + */ + +/** \defgroup getterAndSetters Base getter and setter + * \ingroup OMSIBase + * + * \brief Getter and setter functions provided for OMSIC and OMSICpp. + * + * Defines basic getters and setters operationg on `omsi_t` structure. + */ + +/** \addtogroup getterAndSetters + * \{ */ + +#include +#include + + +/* + * ============================================================================ + * Getters for + * - reals + * - integers + * - booleans + * - strings + * ============================================================================ + */ + +/** + * \brief Getter function for reals. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for real variables to get. + * \param [in] nvr Length of array `vr`. + * \param [out] value Contains asked reals. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_get_real(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_real* value){ + + /* Variables */ + omsi_unsigned_int i; + omsi_int index; + + if (!model_variables_allocated(omsu, "fmi2GetReal")) { + return omsi_error; + } + + if (nvr > 0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetReal: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr > 0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetReal: Invalid argument value[] = NULL."); + return omsi_error; + } + + /* Get reals */ + for (i = 0; i < nvr; i++) { + /* Check for negated alias */ + index = omsi_get_negated_index(&omsu->model_data->model_vars_info[vr[i]], vr[i]); + + if (index < 0) { + if (omsi_vr_out_of_range(omsu, "fmi2GetReal", -index, omsu->sim_data->model_vars_and_params->n_reals)) { + return omsi_error; + } + value[i] =getReal(omsu, -index); + } else { + if (omsi_vr_out_of_range(omsu, "fmi2GetReal", index, omsu->sim_data->model_vars_and_params->n_reals)) { + return omsi_error; + } + value[i] =getReal(omsu, index); + } + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2GetReal: vr = %i, value = %f", vr[i], value[i]); + } + return omsi_ok; +} + + +/** + * \brief Getter function for integers. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for integer variables to get. + * \param [in] nvr Length of array `vr`. + * \param [out] value Contains asked integers. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_get_integer(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_int* value){ + + /* Variables */ + omsi_unsigned_int i; + omsi_unsigned_int n_prev_model_vars; + omsi_int index; + + if (!model_variables_allocated(omsu, "fmi2GetInteger")) { + return omsi_error; + } + + if (nvr > 0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetInteger: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr > 0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetInteger: Invalid argument value[] = NULL."); + return omsi_error; + } + + /* Get integers */ + for (i = 0; i < nvr; i++) { + /* Check for negated alias */ + n_prev_model_vars = omsu->model_data->n_states +omsu->model_data->n_derivatives + omsu->model_data->n_real_vars + omsu->model_data->n_real_parameters + omsu->model_data->n_real_aliases; + index = omsi_get_negated_index(&omsu->model_data->model_vars_info[vr[i]+n_prev_model_vars], vr[i]); + + if (index < 0) { + if (omsi_vr_out_of_range(omsu, "fmi2GetInteger", -index, omsu->sim_data->model_vars_and_params->n_ints)) { + return omsi_error; + } + value[i] =getInteger(omsu, -index); + } else { + if (omsi_vr_out_of_range(omsu, "fmi2GetInteger", index, omsu->sim_data->model_vars_and_params->n_ints)) { + return omsi_error; + } + value[i] =getInteger(omsu, index); + } + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2GetInteger: #i%u# = %d", vr[i], value[i]); + } + return omsi_ok; +} + + +/** + * \brief Getter function for booleans. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for boolean variables to get. + * \param [in] nvr Length of array `vr`. + * \param [out] value Contains asked booleans. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_get_boolean(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_bool* value){ + + /* Variables */ + omsi_unsigned_int i; + omsi_unsigned_int n_prev_model_vars; + omsi_int index; + + if (!model_variables_allocated(omsu, "fmi2GetBoolean")) { + return omsi_error; + } + + if (nvr > 0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetBoolean: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr > 0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetBoolean: Invalid argument value[] = NULL."); + return omsi_error; + } + + /* Get bool values */ + for (i = 0; i < nvr; i++){ + /* Check for negated alias */ + n_prev_model_vars = omsu->model_data->n_states +omsu->model_data->n_derivatives + omsu->model_data->n_real_vars + omsu->model_data->n_real_parameters + omsu->model_data->n_real_aliases + + omsu->model_data->n_int_vars + omsu->model_data->n_int_parameters + omsu->model_data->n_int_aliases; + index = omsi_get_negated_index(&omsu->model_data->model_vars_info[vr[i]+n_prev_model_vars], vr[i]); + + if (index < 0) { + if (omsi_vr_out_of_range(omsu, "fmi2GetBoolean", -index, omsu->sim_data->model_vars_and_params->n_bools)) { + return omsi_error; + } + value[i] =getBoolean(omsu, -index); + } else { + if (omsi_vr_out_of_range(omsu, "fmi2GetBoolean", index, omsu->sim_data->model_vars_and_params->n_bools)) { + return omsi_error; + } + value[i] =getBoolean(omsu, index); + } + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2GetBoolean: #b%u# = %s", vr[i], value[i] ? "true" : "false"); + } + return omsi_ok; +} + + +/** + * \brief Getter function for strings. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for string variables to get. + * \param [in] nvr Length of array `vr`. + * \param [out] value Contains asked strings. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_get_string(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + omsi_string* value){ + + /* Variables */ + omsi_unsigned_int i; + omsi_unsigned_int n_prev_model_vars; + omsi_int index; + + if (!model_variables_allocated(omsu, "fmi2GetString")) { + return omsi_error; + } + + if (nvr>0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetString: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr>0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2GetString: Invalid argument value[] = NULL."); + return omsi_error; + } + + for (i = 0; i < nvr; i++) { + /* Check for negated alias */ + n_prev_model_vars = omsu->model_data->n_states +omsu->model_data->n_derivatives + omsu->model_data->n_real_vars + omsu->model_data->n_real_parameters + omsu->model_data->n_real_aliases + + omsu->model_data->n_int_vars + omsu->model_data->n_int_parameters + omsu->model_data->n_int_aliases + + omsu->model_data->n_bool_vars + omsu->model_data->n_bool_parameters + omsu->model_data->n_bool_aliases; + index = omsi_get_negated_index(&omsu->model_data->model_vars_info[vr[i]+n_prev_model_vars], vr[i]); + + if (index < 0) { + if (omsi_vr_out_of_range(omsu, "fmi2GetString", -index, omsu->sim_data->model_vars_and_params->n_strings)) { + return omsi_error; + } + value[i] =getString(omsu, -index); + } else { + if (omsi_vr_out_of_range(omsu, "fmi2GetString", index, omsu->sim_data->model_vars_and_params->n_strings)) { + return omsi_error; + } + value[i] =getString(omsu, index); + } + if (omsi_vr_out_of_range(omsu, "fmi2GetString", vr[i], omsu->sim_data->model_vars_and_params->n_strings)) { + return omsi_error; + } + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2GetString: #s%u# = '%s'", vr[i], value[i]); + } + return omsi_ok; +} + + +/* + * ============================================================================ + * Setters for + * - reals + * - integers + * - booleans + * - strings + * ============================================================================ + */ + +/* ToDo: Include code for negated aliases */ + + +/** + * \brief Setter function for reals. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for real variables to set. + * \param [in] nvr Length of array `vr`. + * \param [in] value Contains reals to be set. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_set_real(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_real* value) { + + /* Variables */ + omsi_unsigned_int i; + + if (!model_variables_allocated(omsu, "fmi2SetReal")) + return omsi_error; + + if (nvr>0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetReal: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr>0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetReal: Invalid argument value[] = NULL."); + return omsi_error; + } + + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetReal: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + if (omsi_vr_out_of_range(omsu, "fmi2SetReal", vr[i], omsu->sim_data->model_vars_and_params->n_reals)) + return omsi_error; + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetReal: #r%d# = %.16g", vr[i], value[i]); + setReal(omsu, vr[i], value[i]); + } + + return omsi_ok; +} + + +/** + * \brief Setter function for integers. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for integer variables to set. + * \param [in] nvr Length of array `vr`. + * \param [in] value Contains integers to be set. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_set_integer(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_int* value) { + + /* Variables */ + omsi_unsigned_int i; + + if (!model_variables_allocated(omsu, "fmi2SetInteger")) + return omsi_error; + + if (nvr>0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetInteger: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr>0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetInteger: Invalid argument value[] = NULL."); + return omsi_error; + } + + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetInteger: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + if (omsi_vr_out_of_range(omsu, "fmi2SetInteger", vr[i], omsu->sim_data->model_vars_and_params->n_ints)) + return omsi_error; + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetInteger: #i%d# = %d", vr[i], value[i]); + setInteger(omsu, vr[i], value[i]); + } + + return omsi_ok; +} + + +/** + * \brief Setter function for booleans. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for boolean variables to set. + * \param [in] nvr Length of array `vr`. + * \param [in] value Contains booleans to be set. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_set_boolean(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_bool* value) { + + /* Variables */ + omsi_unsigned_int i; + + if (!model_variables_allocated(omsu, "fmi2SetBoolean")) + return omsi_error; + + if (nvr>0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetBoolean: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr>0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetBoolean: Invalid argument value[] = NULL."); + return omsi_error; + } + + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetBoolean: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + if (omsi_vr_out_of_range(omsu, "fmi2SetBoolean", vr[i], omsu->sim_data->model_vars_and_params->n_bools)) + return omsi_error; + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetBoolean: #b%d# = %s", vr[i], value[i] ? "true" : "false"); + + setBoolean(omsu, vr[i], value[i]); + } + + return omsi_ok; +} + + +/** + * \brief Setter function for strings. + * + * Used by OMSIC or OMSICpp library. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] vr Array of value references for string variables to set. + * \param [in] nvr Length of array `vr`. + * \param [in] value Contains strings to be set. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_set_string(omsi_t* omsu, + const omsi_unsigned_int* vr, + omsi_unsigned_int nvr, + const omsi_string* value) { + + /* Variables */ + omsi_unsigned_int i; + + if (!model_variables_allocated(omsu, "fmi2SetString")) + return omsi_error; + + if (nvr>0 && vr==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetString: Invalid argument vr[] = NULL."); + return omsi_error; + } + if (nvr>0 && value==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2SetString: Invalid argument value[] = NULL."); + return omsi_error; + } + + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetString: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + if (omsi_vr_out_of_range(omsu, "fmi2SetString", vr[i], omsu->sim_data->model_vars_and_params->n_strings)) + return omsi_error; + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2SetString: #s%d# = '%s'", vr[i], value[i]); + + setString(omsu, vr[i], value[i]); + } + + return omsi_ok; +} + + +/* + * ============================================================================ + * Helper functions for getters and setters + * - get/set real + * - get/set integer + * - get/set boolean + * - get/set string + * ============================================================================ + */ + +/* What happens for alias variables for getters and setters? */ + +/* + * Get real number of struct OSU with value reference vr. + */ +omsi_real getReal (omsi_t* osu_data, + const omsi_unsigned_int vr) { + + omsi_real output = osu_data->sim_data->model_vars_and_params->reals[vr]; + return output; +} + + +/* + * Set real number of struct OSU for index reference vr with value +*/ +omsi_status setReal(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_real value) { + + osu_data->sim_data->model_vars_and_params->reals[vr] = value; + return omsi_ok; +} + + +/* + * Get integer number of struct OSU with value reference vr +*/ +omsi_int getInteger (omsi_t* osu_data, + const omsi_unsigned_int vr) { + + /* Variables */ + omsi_int output; + + /*index = vr - osu_data->sim_data->model_vars_and_params->n_reals;*/ + output = osu_data->sim_data->model_vars_and_params->ints[vr]; + return output; +} + + +/* + * Set integer number of struct OSU for index reference vr with value + */ +omsi_status setInteger(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_int value) { + + /* index = vr - osu_data->sim_data->model_vars_and_params->n_reals; */ + osu_data->sim_data->model_vars_and_params->ints[vr] = value; + return omsi_ok; +} + + +/* + * Get boolean variable of struct OSU with value reference vr + */ +omsi_bool getBoolean (omsi_t* osu_data, + const omsi_unsigned_int vr) { + /* Variables */ + omsi_bool output; + + /*index = vr - osu_data->sim_data->model_vars_and_params->n_reals + - osu_data->sim_data->model_vars_and_params->n_ints; */ + output = osu_data->sim_data->model_vars_and_params->bools[vr]; + return output; +} + + +/* + * Set boolean variable of struct OSU for index reference vr with value + */ +omsi_status setBoolean(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_bool value) { + + /* index = vr - osu_data->sim_data->model_vars_and_params->n_reals + - osu_data->sim_data->model_vars_and_params->n_ints; */ + osu_data->sim_data->model_vars_and_params->bools[vr] = value; + return omsi_ok; +} + +/* + * Get string of struct OSU with value reference vr +*/ +omsi_string getString (omsi_t* osu_data, + const omsi_unsigned_int vr) { + + /* Variables */ + omsi_string output; + + output = osu_data->sim_data->model_vars_and_params->strings[vr]; + return output; +} + + +/* + * Set string of struct OSU for index reference vr with value + */ +omsi_status setString(omsi_t* osu_data, + const omsi_unsigned_int vr, + const omsi_string value) { + + osu_data->sim_data->model_vars_and_params->strings[vr] = value; + return omsi_error; +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_initialization.c b/SimulationRuntime/OMSI/base/src/omsi_initialization.c new file mode 100644 index 00000000000..a375878a6cc --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_initialization.c @@ -0,0 +1,380 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_initialization.c + */ + +/** \defgroup Initialization Initialization + * \ingroup OMSIBase + * + * \brief Base initialization functions. + * + * Defines basic functions for creating and setting up an OSU_data instance of + * type `struct omsi_t`. + */ + +/** \addtogroup Initialization + * \{ */ + +#include +#include + +#include + +#ifdef _WIN32 +#define ON_WINDOWS 1 +#else +#define ON_WINDOWS 0 +#endif +omsi_callback_functions* global_callback; +omsi_string global_instance_name; +omsi_bool* global_logCategories; +ModelState* global_model_state; + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + + +/** + * \brief Allocate memory for omsi_t struct + * + * `omsi_t` contains all informations for simulation, the experiment data and model + * infos. Processes modelDescription, init-XML file and optional JASON file + * to allocate memory and initialize structs with constant values. + * Gets called from OMSIC or OMSICpp library + * + * \param [in] instanceName Unique identifier for OMSU instance, e.g. the model name. + * \param [in] fmuType Type of OMSU: ModelExchange or CoSimulation. + * Parameter is ignored at the moment, only ModelExchange is supported. + * \param [in] fmuGUID Globally unique identifier to check that modelDescription.xml + * and generated code are compatible. + * \param [in] fmuResourceLocation URI to get "resources" directory of unzipped OMSU archive. + * \param [in] functions Callback functions to be used from OMSI functions, e.g for + * memory management or logging. + * \param [in] template_functions Callback functions for functions in generated code. + * \param [in] visible Defines, if interaction with user should be minimal or + * OMSU is executed in interactive mode. + * Parameter is ignored at the moment. + * \param [in] loggingOn If `loggingOn=omsi_true` debug logging is enabled. + * If `loggingIn=omsi_false` debug logging is disabled. + * \param [in] model_state Current model state. + * + * \return `omsi_t`* Pointer to newly created struct of type omsi_t. + */ +omsi_t* omsi_instantiate(omsi_string instanceName, + omsu_type fmuType, + omsi_string fmuGUID, + omsi_string fmuResourceLocation, + const omsi_callback_functions* functions, + omsi_template_callback_functions_t* template_functions, + omsi_bool visible, + omsi_bool loggingOn, + ModelState* model_state) +{ + /* Variables */ + omsi_int i; + + omsi_t* osu_data; + omsi_string modelName=NULL; + omsi_char* omsi_resource_location; + omsi_char* initXMLFilename; + omsi_char* infoJsonFilename; + omsi_status status; + + /* check all input arguments */ + /* ignoring arguments: visible and fmuType */ + UNUSED(fmuType); + UNUSED(visible); + + if (!functions->logger) { + printf("(Fatal Error) fmi2Instantiate: No logger function set.\n"); + return NULL; + } + + /* Log function call + filtered_base_logger(NULL, log_fmi2_call, omsi_ok, + "fmi2Instantiate: Instantiate osu_data."); + */ + if (!functions->allocateMemory || !functions->freeMemory) { + filtered_base_logger(NULL, log_statuserror, omsi_error, + "fmi2Instantiate: Missing callback function."); + return NULL; + } + if (!instanceName || strlen(instanceName) == 0) { + filtered_base_logger(NULL, log_statuserror, omsi_error, + "fmi2Instantiate: Missing instance name."); + return NULL; + } + if (!fmuGUID || strlen(fmuGUID) == 0) { + filtered_base_logger(NULL, log_statuserror, omsi_error, + "fmi2Instantiate: Missing GUID."); + return NULL; + } + + /* Allocate memory for osu_data */ + osu_data = functions->allocateMemory(1, sizeof(omsi_t)); + if (!osu_data) { + filtered_base_logger(NULL, log_statuserror, omsi_error, + "fmi2Instantiate: Could not allocate memory for omsi_data."); + return NULL; + } + + /* Set model state to be pointer to OSU model state */ + osu_data->state = model_state; + + /* Set logCategories an loggingOn*/ + for (i = 0; i < NUMBER_OF_CATEGORIES; i++) { /* set all categories to on or off */ + osu_data->logCategories[i] = loggingOn; + } + osu_data->loggingOn = loggingOn; + + /* set global callback functions */ + global_callback = (omsi_callback_functions*) functions; + global_instance_name = instanceName; + global_logCategories = osu_data->logCategories; + global_model_state = osu_data->state; + + /* check fmuResourceLocation for network path e.g. starting with "file://" */ + omsi_resource_location = omsi_strdup(fmuResourceLocation); + if (strncmp(omsi_resource_location, "file:///", 8) == 0 && ON_WINDOWS){ + memmove(omsi_resource_location, omsi_resource_location+8, strlen(omsi_resource_location) - 8 + 1); + } + else if(strncmp(omsi_resource_location, "file://", 7) == 0 ){ + memmove(omsi_resource_location, omsi_resource_location+7, strlen(omsi_resource_location) - 7 + 1); + } + + /* Read model name from modelDescription */ + modelName = omsi_get_model_name(omsi_resource_location); + if (!modelName) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not read modelName from %s/modelDescription.xml.", + omsi_resource_location); + omsu_free_osu_data(osu_data); + functions->freeMemory(omsi_resource_location); + return NULL; + } + + /* process Inti-XML file and read experiment_data and parts of model_data in osu_data*/ + initXMLFilename = functions->allocateMemory(20 + strlen(omsi_resource_location) + strlen(modelName), sizeof(omsi_char)); + sprintf(initXMLFilename, "%s/%s_init.xml", omsi_resource_location, modelName); + if (omsu_process_input_xml(osu_data, initXMLFilename, fmuGUID, instanceName, functions) == omsi_error) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not process %s.", initXMLFilename); + omsu_free_osu_data(osu_data); + functions->freeMemory(initXMLFilename); + functions->freeMemory(omsi_resource_location); + return NULL; + } + + /* process JSON file and read missing parts of model_data in osu_data */ + infoJsonFilename = functions->allocateMemory(20 + strlen(omsi_resource_location) + strlen(modelName), sizeof(omsi_char)); + sprintf(infoJsonFilename, "%s/%s_info.json", omsi_resource_location, modelName); + + /* temporarily disabled because omsicpp doesn't generate the json file */ + /*if (omsu_process_input_json(osu_data, infoJsonFilename, fmuGUID, instanceName, functions) == omsi_error) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not process %s.", infoJsonFilename); + omsu_free_osu_data(osu_data); + functions->freeMemory(infoJsonFilename); + functions->freeMemory(omsi_resource_location); + return NULL; + } + */ + + /* ************************************************************************* */ + + /* Instantiate and initialize sim_data */ + status = omsu_allocate_sim_data(osu_data, functions, instanceName); + if (status != omsi_ok) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not allocate memory for sim_data."); + /* ToDo: free stuff */ + return NULL; + } + + status = omsi_allocate_model_variables(osu_data, functions); /* ToDo: move this function into omsu_allocate_sim_data */ + if (status != omsi_ok) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not allocate memory for sim_data->model_vars_and_params."); + /* Todo: free stuff */ + return NULL; + } + + status = omsu_setup_sim_data(osu_data, template_functions, functions); + if (status != omsi_ok) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not initialize sim_data->simulation."); + /*******temporarily disabled because omsicpp doesn't generate omsi functions**********/ + /* Todo: free stuff */ + /* return NULL; */ + /**********************************************************************************/ + } + + status = omsi_initialize_model_variables(osu_data, functions, instanceName); + if (status != omsi_ok) { + filtered_base_logger(osu_data->logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not initialize sim_data->model_vars_and_params."); + /* Todo: free stuff */ + return NULL; + } + + /* Free local variables */ + functions->freeMemory((omsi_char*) modelName); + functions->freeMemory(infoJsonFilename); + functions->freeMemory(omsi_resource_location); + functions->freeMemory(initXMLFilename); + + return osu_data; +} + + +/** + * \brief Initialize callbacks for initialization and simulation problem. + * + * Gets called from OMSIC or OMSICpp library and uses generated functions for initialization. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] template_functions Struct containing pointers to functions in generated code. + * \return `omsi_status` Returns `omsi_ok` on success. + */ +omsi_status omsi_intialize_callbacks(omsi_t* omsu, + omsi_template_callback_functions_t* template_functions ) +{ + + /* Set up initialization problem. */ + omsu_setup_sim_data_omsi_function(omsu->sim_data, + "initialization", + template_functions->initialize_initialization_problem); + + /* Set up simulation problem */ + omsu_setup_sim_data_omsi_function(omsu->sim_data, + "simulation", + template_functions->initialize_simulation_problem); + + return omsi_ok; +} + +/* + * Helper function for XML parser. + * Defines what happens on start tag in XML files. + */ +void XMLCALL startElement_2(void* userData, + omsi_string name, + omsi_string* attr) { + + omsi_long i = 0; + modelDescriptionData* md = (modelDescriptionData*) userData; + omsi_char* modelName; + + /* handle fmiModelDescription */ + if (!strcmp(name, "ModelExchange")) { + for (i = 0; attr[i]; i += 2) { + if (strcmp("modelIdentifier", attr[i]) == 0 ) { + modelName = omsi_strdup(attr[i+1]); + md->modelName = modelName; + return; + } + } + } + + return; + +} + + +/* + * Reads modelName from modelDescription.xml and returns it as string. + * modelDescription.xml should be located at fmuResourceLocation/.. + */ +omsi_string omsi_get_model_name(omsi_string fmuResourceLocation) { + + /* Variables */ + omsi_int done; + omsi_char* fileName; + modelDescriptionData md = {0}; + + omsi_char buf[BUFSIZ] = {0}; + FILE* file = NULL; + XML_Parser parser = NULL; + + /* file name */ + fileName = global_callback->allocateMemory(26 + strlen(fmuResourceLocation), sizeof(omsi_char)); + sprintf(fileName, "%s/../modelDescription.xml", fmuResourceLocation); + + /* open xml file */ + file = fopen(fileName, "r"); + if(!file) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Can not read input file %s.", fileName); + global_callback->freeMemory(fileName); + return NULL; + } + + /* create the XML parser */ + parser = XML_ParserCreate("UTF-8"); + if(!parser) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Can not create XML parser"); + fclose(file); + global_callback->freeMemory(fileName); + return NULL; + } + + /* set our user data */ + XML_SetUserData(parser, &md); + /* set the handlers for start/end of element. */ + XML_SetElementHandler(parser, startElement_2, endElement); + + /* read XML */ + do { + omsi_unsigned_int len = fread(buf, 1, sizeof(buf), file); + done = len < sizeof(buf); + if(XML_STATUS_ERROR == XML_Parse(parser, buf, len, done)) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: failed to read the XML file %s: %s at line %lu.", + fileName, + XML_ErrorString(XML_GetErrorCode(parser)), + XML_GetCurrentLineNumber(parser)); + + fclose(file); + XML_ParserFree(parser); + global_callback->freeMemory(fileName); + return NULL; + } + } while(!done); + + /* Deallocate memory */ + fclose(file); + XML_ParserFree(parser); + global_callback->freeMemory(fileName); + + return md.modelName; +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_input_json.c b/SimulationRuntime/OMSI/base/src/omsi_input_json.c new file mode 100644 index 00000000000..1b93e942a3d --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_input_json.c @@ -0,0 +1,626 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_input_json.c + */ + +/** \defgroup initJson Initialize JSON + * \ingroup Initialization + * + * \brief Process modelName_info.json file + * + * Functions to process informations from optional modelName_info.json file in + * FMU resources folder. + */ + +/** \addtogroup initJson + * \{ + */ + +#include +#include + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + +/* prototypes for static functions */ +static omsi_string skipSpace(omsi_string str); + +static omsi_string assertStringValue(omsi_string str, + omsi_string value); + +static omsi_string assertChar (omsi_string str, + omsi_char c); + +static omsi_string omsu_assertCharOrEnd (omsi_string str, + omsi_char expected_char, + omsi_bool* endNotFound); + +static omsi_string assertNumber(omsi_string str, + omsi_real expected); + +static omsi_string skipObjectRest(omsi_string str, + omsi_int first); + +static omsi_string skipValue(omsi_string str); + +static omsi_string skipFieldIfExist(omsi_string str, + omsi_string name); + +static void readInfoJson(omsi_string str, + model_data_t* model_data); + + +/** + * \brief Process all informations from input.json file. + * + * Read values, allocates memory and writes everything in model_data->equation_info. + * + * \param [in,out] osu_data Central data structure containing all informations. + * \param [in] fileName Path to JSON file. + * \param [in] fmuGUID GUID of FMU for checking purpose. Ignored at the moment. + * \param [in] instanceName Name of MFU instance for logging. Ignored at the moment. + * \param [in] functions Pointer to callback functions provided by user. + * \return `omsi_status` Returns `omsi_ok` on success. + */ +omsi_status omsu_process_input_json(omsi_t* osu_data, + omsi_string fileName, + omsi_string fmuGUID, + omsi_string instanceName, + const omsi_callback_functions* functions) { + + /* Variables */ + omc_mmap_read mmap_reader; + + UNUSED(fmuGUID); UNUSED(instanceName); /* ToDo: delete or change function */ + + /* set global function pointer */ + global_callback = (omsi_callback_functions*) functions; + global_instance_name = instanceName; + + /* Log function call */ + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Process JSON file %s.", fileName); + + /* read JSON file */ + mmap_reader = omc_mmap_open_read (fileName); + readInfoJson(mmap_reader.data, osu_data->model_data); + + /* free memory */ + omc_mmap_close_read(mmap_reader); + + return omsi_ok; +} + + +/* + * Helper function for reading JSON. + * Skip whitespace. + */ +static omsi_string skipSpace(omsi_string str) { + do { + switch (*str) { + case '\0': return str; + case ' ': + case '\n': + case '\r': + str++; + break; + default: return str; + } + } while (1); +} + + +/* + * Helper function for reading JSON. + * Assert string value is written in `str`. Returns the rest of the string to parse. + * Does not work for escaped strings. + */ +static omsi_string assertStringValue(omsi_string str, + omsi_string value) { + int len = strlen(value); + str = skipSpace(str); + if ('\"' != *str || strncmp(str+1,value,len) || str[len+1] != '\"') { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: JSON string value %s expected, got: %.20s\n", + value, str); + abort(); + } + return str + len + 2; +} + + +/* + * Helper function for reading JSON. + * Assert char value is written in `str`. Returns the rest of the string to parse. + * Does not work for escaped strings. + */ +static omsi_string assertChar (omsi_string str, + omsi_char expected_char) { + str = skipSpace(str); + if (expected_char != *str) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Expected '%c', got: %.20s\n", + expected_char, str); + abort(); + } + return str + 1; +} + +/* + * Helper function for reading JSON. + * Assert pointer `*str` points to char that is equal to expected_char or end + * of array ']' is reached. + */ +static omsi_string omsu_assertCharOrEnd (omsi_string str, + omsi_char expected_char, + omsi_bool* endNotFound) { + str = skipSpace(str); + + if (*str == ']') { + *endNotFound = omsi_false; + return str; + } + + if (*str != expected_char) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Expected '%c', got: %.20s\n", + expected_char, str); + abort(); + } + return str + 1; +} + + +/* + * Helper function for reading JSON. + * Assert real value is written in `str`. Returns the rest of the string to parse. + * Does not work for escaped strings. + */ +static omsi_string assertNumber(omsi_string str, + omsi_real expected) { + omsi_char* endptr = NULL; + omsi_real d; + str = skipSpace(str); + d = strtod(str, &endptr); + if (str == endptr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Expected number, got: %.20s\n", str); + abort(); + } + if (d != expected) { + filtered_base_logger(global_logCategories, log_statuswarning, omsi_warning, + "fmi2Instantiate: Got number %f, expected: %f\nProceeding any way.\n", + d, expected); + } + return endptr; +} + + +/* + * Helper function for reading JSON. + * Skip rest of current object in `str`. + */ +static omsi_string skipObjectRest(omsi_string str, + omsi_int first) { + str=skipSpace(str); + while (*str != '}') { + if (!first) { + if (*str != ',') { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: JSON object expected ',' or '}', got: %.20s\n", str); + abort(); + } + str++; + } else { + first = 0; + } + str = skipValue(str); + str = skipSpace(str); + if (*str++ != ':') { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: JSON object expected ':', got: %.20s\n", str); + abort(); + } + str = skipValue(str); + str = skipSpace(str); + } + return str+1; +} + + +/* + * Helper function for reading JSON. + * Skip everything inside string that is between braces, brackets or + * quotation marks, e.g. everything between {..}, [..] or "..". + */ +static omsi_string skipValue(omsi_string str) { + + /* Variables*/ + omsi_int first; + omsi_char *endptr; + + str = skipSpace(str); + switch (*str) { + case '{': + str = skipObjectRest(str+1,1); + return str; + case '[': + first = 1; + str = skipSpace(str+1); + while (*str != ']') { + if (!first && *str++ != ',') { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: JSON array expected ',' or ']', got: %.20s\n", str); + abort(); + } + first = 0; + str = skipValue(str); + str = skipSpace(str); + } + return str+1; + case '"': + str++; + do { + switch (*str) { + case '\0': + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Found end of file, expected end of string"); + abort(); + case '\\': + if (str+1 == '\0') { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Found end of file, expected end of string"); + abort(); + } + str+=2; + break; + case '"': + return str+1; + default: + str++; + } + } while (1); + abort(); + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + endptr = NULL; + strtod(str,&endptr); + if (str == endptr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Not a number, got %.20s\n", str); + abort(); + } + return endptr; + default: + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: JSON value expected, got: %.20s\n", str); + abort(); + } + + /* function should never reach this point */ + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Function should not be able to reach this point. Report a bug and get a cooky!"); + return str; +} + + +/* + * Helper function for reading JSON. + * Skip everything inside field, if it exists. + */ +static omsi_string skipFieldIfExist(omsi_string str, + omsi_string name) { + omsi_string s = str; + omsi_int len = strlen(name); + + if (*s != ',') { + return str; + } + s++; + if (*s != '\"' || strncmp(s+1,name,len)) { + return str; + } + s += len + 1; + if (strncmp("\":", s, 2)) { + return str; + } + s += 2; + s = skipSpace(s); + s = skipValue(s); + s = skipSpace(s); + s = skipSpace(s); + return s; +} + + +/* + * Helper function for reading JSON. + * Read single equation from string created from JSON file. + * Save detailed informations about equation in equation_info. + */ +omsi_string readEquation(omsi_string str, + equation_info_t* equation_info, + omsi_unsigned_int expected_id, + omsi_unsigned_int* count_init_eq, + omsi_unsigned_int* count_regular_eq, + omsi_unsigned_int* count_alias_eq) { + + /* variables */ + omsi_int n = 0; + omsi_int j = 0; + omsi_string str2; + omsi_char* tmp_number; + + /* read equation index */ + str=assertChar(str,'{'); + str=assertStringValue(str,"eqIndex"); + str=assertChar(str,':'); + str=assertNumber(str,expected_id); /* checks if expected id matches found value */ + str=skipSpace(str); + equation_info->id = expected_id; + + /* read field parent if exists*/ + if (strncmp(",\"parent\"", str, 9) == 0) { + str=assertChar(str,','); + str=assertStringValue(str, "parent"); + str=assertChar(str,':'); + while (*str != ',') { + str = str+1; + j++; + } + tmp_number = (omsi_char *) global_callback->allocateMemory(j+1, sizeof(omsi_char)); + strncpy (tmp_number, str-j, sizeof(omsi_char)*j); + tmp_number[j+1] = '\0'; + equation_info->parent = (omsi_int) strtol(tmp_number,NULL ,10); + global_callback->freeMemory(tmp_number); + } + str=skipSpace(str); + + /* read field section */ + if (strncmp(",\"section\"", str, 9) == 0) { + str=assertChar(str,','); + str=assertStringValue(str, "section"); + str=assertChar(str,':'); + str=skipSpace(str); + if (strncmp("\"initial\"", str, 9) == 0) { + *count_init_eq = *count_init_eq +1; + str += 9; + } + else if (strncmp("\"regular\"", str, 9) == 0) { + *count_regular_eq = *count_regular_eq +1; + str += 9; + } + else if (strncmp("\"start\"", str, 7) == 0) { + *count_init_eq = *count_init_eq +1; + str += 7; + } + else { + str = skipValue(str); + } + } + + if (0==strncmp(",\"tag\":\"system\"", str, 15)) { + equation_info->profileBlockIndex = -1; + str += 15; + } else if (0==strncmp(",\"tag\":\"tornsystem\"", str, 19)) { + equation_info->profileBlockIndex = -1; + str += 19; + } else if (0==strncmp(",\"tag\":\"alias\"", str, 14)) { + *count_alias_eq = *count_alias_eq +1; + equation_info->profileBlockIndex = 0; + } else { + equation_info->profileBlockIndex = 0; + } + str = skipFieldIfExist(str, "tag"); + str = skipFieldIfExist(str, "display"); + str = skipFieldIfExist(str, "unknowns"); + /* read defines */ + if (strncmp(",\"defines\":[", str, 12)) { /* case no ",\"defines\":[" was found */ + equation_info->numVar = 0; + equation_info->variables = NULL; + str = skipObjectRest(str,0); + return str; + } + str += 12; + str = skipSpace(str); + if (*str == ']') { /* case there is nothing in defines */ + equation_info->numVar = 0; + equation_info->variables = NULL; + return skipObjectRest(str-1,0); + } + + /* count number of defining variables */ + str2 = skipSpace(str); + while (1) { + str=skipValue(str); + n++; + str=skipSpace(str); + if (*str != ',') { + break; + } + str++; + }; + assertChar(str, ']'); + equation_info->numVar = n; + equation_info->variables = (omsi_string*) global_callback->allocateMemory(n, sizeof(omsi_string)); + + /* save defining variables */ + str = str2; + for (j=0; jallocateMemory(len+1, sizeof(omsi_char)); + strncpy(tmp, str3+1, len); + tmp[len] = '\0'; + equation_info->variables[j] = tmp; + if (j != n-1) { + str = assertChar(str, ','); + } + } + str = assertChar(skipSpace(str), ']'); + + /* ToDo: read file info */ + + return skipObjectRest(str,0); +} + +/* + * Helper function for reading JSON. + * Read equations part from string created from JSON file. + * For every equation a sub function is called to save detailed informations in equation_info. + */ +omsi_string readEquations(omsi_string str, + model_data_t* model_data) { + + /* Variables */ + omsi_int i = 0; + omsi_bool endNotFound = omsi_true; + omsi_string str_start; + + /* Check model_data */ + if (!model_data) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In function readEquations: Memory for model_data not allocated.\n"); + abort(); + } + + /* Initialize counter for regular and initial equations*/ + model_data->n_regular_equations = 0; + model_data->n_init_equations = 0; + model_data->n_alias_equations = 0; + + /* skip first dummy equation */ + str = assertChar(str,'['); + str = assertChar(str,'{'); + str = assertStringValue(str,"eqIndex"); + str = assertChar(str,':'); + str = assertChar(str,'0'); + str = assertChar(str,','); + str = assertStringValue(str,"tag"); + str = assertChar(str,':'); + str = assertStringValue(str,"dummy"); + str = assertChar(str,'}'); + str = skipSpace(str); + + str_start = str; /*save current location on string */ + + /* count number of equations */ + do { + str = omsu_assertCharOrEnd (str, ',', &endNotFound); + if (!endNotFound) { + break; + } + i++; + str = skipSpace(str); + str = skipValue(str); + }while (omsi_true); + + model_data->n_equations = i; + model_data->equation_info = (equation_info_t*) global_callback->allocateMemory(model_data->n_equations, sizeof(equation_info_t)); + + str = str_start; /* reset str to start of equations */ + endNotFound = omsi_true; + i=0; + do { + str = omsu_assertCharOrEnd (str, ',', &endNotFound); + if (!endNotFound) { + break; + } + i++; + str = skipSpace(str); + str = readEquation(str, &(model_data->equation_info[i-1]), i, &model_data->n_init_equations, &model_data->n_regular_equations, &model_data->n_alias_equations); + }while (omsi_true); + + str=assertChar(str,']'); + return str; +} + + +/** + * \brief Reads all informations from JSON file. + * + * Actually skips everything except for equations, but checks if format of JSON is correct. + * + * \param [in] str String containing content of JSON file. + * \param [in,out] model_data Pointer to struct used for saving data read from JSON file. + */ +static void readInfoJson(omsi_string str, + model_data_t* model_data) { + /* check and skip content until begin of equations */ + str=assertChar(str,'{'); + str=assertStringValue(str,"format"); + str=assertChar(str,':'); + str=assertStringValue(str,"Transformational debugger info"); + str=assertChar(str,','); + str=assertStringValue(str,"version"); + str=assertChar(str,':'); + str=assertChar(str,'1'); + str=assertChar(str,','); + str=assertStringValue(str,"info"); + str=assertChar(str,':'); + str=skipValue(str); + str=assertChar(str,','); + str=assertStringValue(str,"variables"); + str=assertChar(str,':'); + str=skipValue(str); + str=assertChar(str,','); + + /* read equations */ + str=assertStringValue(str,"equations"); + str=assertChar(str,':'); + str=readEquations(str, model_data); + str=assertChar(str,','); + + /* check and skip remaining content */ + str=assertStringValue(str,"functions"); + str=assertChar(str,':'); + str=skipValue(str); + assertChar(str,'}'); +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_input_model_variables.c b/SimulationRuntime/OMSI/base/src/omsi_input_model_variables.c new file mode 100644 index 00000000000..b2cedbe249a --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_input_model_variables.c @@ -0,0 +1,391 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_input_model_variables.c + */ + +/** \addtogroup initSimData + * \{ */ + +#include +#include + + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + + +/** + * \brief Allocates memory for model variables. + * + * Gets called from ´omsi_instantiate`. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] functions Callback functions to be used from OMSI functions, e.g for memory management or logging. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_allocate_model_variables(omsi_t* omsu, + const omsi_callback_functions* functions) { + + /* Variables */ + omsi_unsigned_int n_bools, n_ints, n_reals, n_strings; + + + /* set global function pointer */ + global_callback = (omsi_callback_functions*) functions; + + /* Log function call */ + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Allocates memory for model_variables"); + + /*Todo: Allocate memory for all string model variables*/ + + /*Allocate memory for all boolean model variables*/ + n_bools = omsu->model_data->n_bool_vars + omsu->model_data->n_bool_parameters; + if (n_bools > 0) { + omsu->sim_data->model_vars_and_params->bools = (omsi_bool*)alignedMalloc(sizeof(omsi_bool) * n_bools, 64); + omsu->sim_data->pre_vars->bools = (omsi_bool*)alignedMalloc(sizeof(omsi_bool) * n_bools, 64); + omsu->sim_data->model_vars_and_params->n_bools = n_bools; + omsu->sim_data->pre_vars->n_bools = n_bools; + } + else { + omsu->sim_data->model_vars_and_params->bools = NULL; + omsu->sim_data->pre_vars->bools = NULL; + omsu->sim_data->model_vars_and_params->n_bools = 0; + omsu->sim_data->pre_vars->n_bools = 0; + } + + /* Allocate memory for all integer model variables */ + n_ints = omsu->model_data->n_int_vars+ omsu->model_data->n_int_parameters; + if (n_ints > 0) { + omsu->sim_data->model_vars_and_params->ints = (omsi_int*)alignedMalloc(sizeof(omsi_int) * n_ints, 64); + omsu->sim_data->pre_vars->ints = (omsi_int*)alignedMalloc(sizeof(omsi_int) * n_ints, 64); + omsu->sim_data->model_vars_and_params->n_ints = n_ints; + omsu->sim_data->pre_vars->n_ints = n_ints; + } + else { + omsu->sim_data->model_vars_and_params->ints = NULL; + omsu->sim_data->pre_vars->ints = NULL; + omsu->sim_data->model_vars_and_params->n_ints = 0; + omsu->sim_data->pre_vars->n_ints = 0; + } + + /* Allocate memory for all real model variables */ + n_reals = omsu->model_data->n_states + omsu->model_data->n_derivatives + omsu->model_data->n_real_vars + omsu->model_data->n_real_parameters; + if (n_reals > 0) { + omsu->sim_data->model_vars_and_params->reals = (omsi_real*)alignedMalloc(sizeof(omsi_real) * n_reals, 64); + omsu->sim_data->pre_vars->reals = (omsi_real*)alignedMalloc(sizeof(omsi_real) * n_reals, 64); + omsu->sim_data->model_vars_and_params->n_reals = n_reals; + omsu->sim_data->pre_vars->n_reals = n_reals; + } + else { + omsu->sim_data->model_vars_and_params->reals = NULL; + omsu->sim_data->model_vars_and_params->n_reals = 0; + omsu->sim_data->pre_vars->reals = NULL; + omsu->sim_data->pre_vars->n_reals = 0; + } + + /* ToDo: Allocate memory for all string variables */ + n_strings = omsu->model_data->n_string_vars+ omsu->model_data->n_string_parameters; + if (n_strings > 0) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: String variables / parameters not supported yet!"); + return omsi_error; + } + else { + omsu->sim_data->model_vars_and_params->strings = NULL; + omsu->sim_data->pre_vars->strings = NULL; + omsu->sim_data->model_vars_and_params->strings = 0; + omsu->sim_data->pre_vars->strings = 0; + } + + return omsi_ok; +} + +/** + * \brief Initializes model variables with values from init-XML file. + * + * \param [in,out] omsu Central data structure containing all informations. + * \param [in] functions Callback functions to be used from OMSI functions. Ignored at the moment. + * \param [in] instanceName Name of OMSU instance. Ignored at the moment. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsi_initialize_model_variables(omsi_t* omsu, + const omsi_callback_functions* functions, + omsi_string instanceName) { + + /* Variables */ + omsi_unsigned_int n; + omsi_unsigned_int state, derstate; + omsi_unsigned_int real_algebraic, real_parameter, real_alias; + omsi_unsigned_int int_algebraic, int_algebraic_2; + omsi_unsigned_int int_parameter, int_parameter_2, int_alias; + omsi_unsigned_int bool_parameter, bool_parameter_2; + omsi_unsigned_int bool_algebraic, bool_algebraic_2; + + /* ToDo: Delete me! */ + UNUSED(functions); + UNUSED(instanceName); + + if(!model_variables_allocated(omsu, "fmi2Instantiate")) + return omsi_error; + + if (!omsu->sim_data->model_vars_and_params->reals && omsu->sim_data->model_vars_and_params->n_reals > 0) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Real variables are not yet allocated."); + return omsi_error; + } + if (!omsu->sim_data->model_vars_and_params->ints && omsu->sim_data->model_vars_and_params->n_ints > 0) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Int variables are not yet allocated."); + return omsi_error; + } + if (!omsu->sim_data->model_vars_and_params->bools && omsu->sim_data->model_vars_and_params->n_bools > 0) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Bool variables are not yet allocated."); + return omsi_error; + } + + /* Initialize state variables from init xml file values*/ + n = omsu->model_data->n_states; + for (state = 0; state < n; ++state) { + real_var_attribute_t* attr = (real_var_attribute_t*)(omsu->model_data->model_vars_info[state].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->reals[state] = attr->start; + } + + /* Initialize derivatives variables from init xml file values*/ + n = n + omsu->model_data->n_derivatives; + for (derstate = state; derstate < n; ++derstate) { + real_var_attribute_t* attr = (real_var_attribute_t*)(omsu->model_data->model_vars_info[derstate].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->reals[derstate] = attr->start; + } + + /* Initialize real algebraic variables from init xml file values*/ + n = n + omsu->model_data->n_real_vars; + for (real_algebraic = derstate; real_algebraic < n; ++real_algebraic) { + real_var_attribute_t* attr = (real_var_attribute_t*)(omsu->model_data->model_vars_info[real_algebraic].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->reals[real_algebraic] = attr->start; + } + + /* Initialize real parameter variables from init xml file values*/ + n = n + omsu->model_data->n_real_parameters; + for (real_parameter = real_algebraic; real_parameter < n; ++real_parameter) { + real_var_attribute_t* attr = (real_var_attribute_t*)(omsu->model_data->model_vars_info[real_parameter].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->reals[real_parameter] = attr->start; + } + + /*real alias variables are not extra included in real vars memory,therefore they are skipped*/ + real_alias = omsu->model_data->n_real_aliases; + n = n + real_alias; + + /* Initialize int algebraic variables from init xml file values*/ + n = n + omsu->model_data->n_int_vars; + for (int_algebraic = real_parameter+ real_alias, int_algebraic_2=0; int_algebraic < n; ++int_algebraic, ++int_algebraic_2) { + int_var_attribute_t* attr = (int_var_attribute_t*)(omsu->model_data->model_vars_info[int_algebraic].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->ints[int_algebraic_2] = attr->start; + } + + /* Initialize int parameter from init xml file values*/ + n = n + omsu->model_data->n_int_parameters; + for (int_parameter = int_algebraic, int_parameter_2 = int_algebraic_2; int_parameter < n; ++int_parameter, ++int_parameter_2) { + int_var_attribute_t* attr = (int_var_attribute_t*)(omsu->model_data->model_vars_info[int_parameter].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->ints[int_parameter_2] = attr->start; + } + + /* int alias variables are not extra included in int vars memory, therefore they are skipped */ + int_alias = omsu->model_data->n_int_aliases; + n = n + int_alias; + + /* Initialize bool algebraic variables from init xml file values*/ + n = n + omsu->model_data->n_bool_vars; + for (bool_algebraic = int_parameter+ int_alias, bool_algebraic_2 = 0; bool_algebraic < n; ++bool_algebraic, ++bool_algebraic_2) { + bool_var_attribute_t* attr = (bool_var_attribute_t*)(omsu->model_data->model_vars_info[bool_algebraic].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->bools[bool_algebraic_2] = attr->start; + } + + /* Initialize bool parameter from init xml file values*/ + n = n + omsu->model_data->n_bool_parameters; + for (bool_parameter = bool_algebraic, bool_parameter_2 = bool_algebraic_2; bool_parameter < n; ++bool_parameter, ++bool_parameter_2) { + bool_var_attribute_t* attr = (bool_var_attribute_t*)(omsu->model_data->model_vars_info[bool_parameter].modelica_attributes); + if (!attr) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: could not read start value attribute."); + return omsi_error; + } + omsu->sim_data->model_vars_and_params->bools[bool_parameter_2] = attr->start; + } + + /*Todo: Initialize string algebraic variables from init xml file values*/ + + return omsi_ok; +} + +/** + * \brief Free allocated memory for model variables in simulation data. + * + * \param [in,out] sim_data Pointer to simulation data containing all variables. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_warning` if `sim_data` is NULL. + */ +omsi_status omsi_free_model_variables(sim_data_t* sim_data) { + + /* Check input */ + if (!sim_data) { + return omsi_warning; + } + + if (sim_data->model_vars_and_params) { + if (sim_data->model_vars_and_params->bools) { + alignedFree(sim_data->model_vars_and_params->bools); + } + if (sim_data->model_vars_and_params->ints) { + alignedFree(sim_data->model_vars_and_params->ints); + } + if (sim_data->model_vars_and_params->reals) { + alignedFree(sim_data->model_vars_and_params->reals); + } + + global_callback->freeMemory(sim_data->model_vars_and_params); + } + + if (sim_data->pre_vars) { + if (sim_data->pre_vars->bools) { + alignedFree(sim_data->pre_vars->bools); + } + if (sim_data->pre_vars->ints) { + alignedFree(sim_data->pre_vars->ints); + } + if (sim_data->pre_vars->reals) { + alignedFree(sim_data->pre_vars->reals); + } + + global_callback->freeMemory(sim_data->pre_vars); + } + + return omsi_ok; +} + + +/* + * Helper function. + * Allocates aligned memory. + */ +void* alignedMalloc(size_t required_bytes, + size_t alignment) /* ToDo: change size_t to some omsi type */ +{ + void *p1; + void **p2; + + omsi_int offset = alignment - 1 + sizeof(void*); + p1 = global_callback->allocateMemory(1,required_bytes + offset); + p2 = (void**)(((size_t)(p1)+offset)&~(alignment - 1)); + p2[-1] = p1; + return p2; +} + +/* + * Helper function. + * Frees memory allocated with `alignedMalloc`. + */ +void alignedFree(void* p) +{ + void* p1 = ((void**)p)[-1]; /* get the pointer to the buffer we allocated */ + global_callback->freeMemory(p1); +} + + + +/* + * Check if memory is allocated for model variables. + */ +omsi_bool model_variables_allocated(omsi_t* omsu, + omsi_string functionName) { + + /* TODO: Fix me! */ + UNUSED(omsu); + UNUSED(functionName); +#if 0 + /* Check inputs */ + if (!omsu->model_data) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "%s: No model data available.", functionName); + return omsi_false; + } + if (!omsu->model_data->model_vars_info) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "%s: No model vars info available.", functionName); + return omsi_false; + } + if (!omsu->sim_data->model_vars_and_params) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "%s: No model vars and parameter structure is not yet allocated.", functionName); + return omsi_false; + } +#endif + return omsi_true; +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_input_sim_data.c b/SimulationRuntime/OMSI/base/src/omsi_input_sim_data.c new file mode 100644 index 00000000000..1d961042d8e --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_input_sim_data.c @@ -0,0 +1,585 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_input_sim_data.c + */ + +/** \defgroup initSimData Set SimData + * \ingroup Initialization + * + * \brief Set `sim_data_t` struct with functions from generated code. + * + * Allocate memory for omsi_data->sim_data. Set up variables and parameters, + * create data for initialization and simulation problem and all containg + * algebraic systems. + */ + +/** \addtogroup initSimData + * \{ */ + + +#include + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + + +/** + * \brief Allocates memory and initializes inner sim_data_t struct with functions from generated code. + * + * Assumes memory is already allocated for omsi_data->sim_data. + * + * \param [in,out] omsi_data Pointer to OMSU data + * \param [in] template_function Pointer to struct of callback functions in generated code. + * \param [in] callback_functions Callback functions to be used from OMSI functions, e.g for + * memory management or logging. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_setup_sim_data(omsi_t* omsi_data, + omsi_template_callback_functions_t* template_function, + const omsi_callback_functions* callback_functions) { + + /* set global function pointer */ + global_callback = (omsi_callback_functions*) callback_functions; + solver_init_callbacks (global_callback->allocateMemory, + global_callback->freeMemory, + wrapper_alg_system_logger); + + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Set up sim_data structure."); + + /* Check if memory is already allocated */ + if (!omsi_data->sim_data) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: sim_data struct not allocated."); + return omsi_error; + } + + /* check if template callback functions are set */ + if (!template_function->isSet) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Generated functions not set."); + return omsi_error; + } + + return omsi_ok; +} + + +/** + * \brief Set up omsi_function_t struct for initialization or simulation problem. + * + * \param [in,out] sim_data Pointer to simulation data. + * \param [in] function_name Name of omsi_function to set up. Possible values are + * "initialization" and "simulation". + * \param [in] template_instantiate_function Callback for instantiation function from generated code. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_setup_sim_data_omsi_function(sim_data_t* sim_data, + omsi_string function_name, + omsu_initialize_omsi_function template_instantiate_function) { + + /* Variables */ + omsi_function_t* omsi_function; + + /* Set initialization or simulation problem */ + if (strcmp(function_name, "initialization")==0) { + omsi_function = sim_data->initialization; + } + else if (strcmp(function_name, "simulation")==0) { + omsi_function = sim_data->simulation; + } + else { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Error while instantiating initialization problem with generated code."); + return omsi_error; + } + + /* Call generated initialization function for initialization problem */ + if (template_instantiate_function(omsi_function)==omsi_error) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Error while instantiating initialization problem with generated code."); + return omsi_error; + } + + /* Set function variables. Either local copy or pointer to global model_vars_and_params*/ + if (omsu_instantiate_omsi_function_func_vars(omsi_function, sim_data->model_vars_and_params, sim_data->pre_vars)==omsi_error) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Error while instantiating function variables of sim_data->simulation."); + return omsi_error; + } + + /* Set default solvers for omsi_function */ + if (omsu_set_default_solvers(omsi_function, function_name)) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not instantiate default solvers for algebraic loops in %s problem.", + function_name); + return omsi_error; + } + + return omsi_ok; +} + + +/** + * \brief Allocate memory for `sim_data_t` struct. + * + * Gets called from function omsu_setup_sim_data. + * + * \param [in,out] omsu Pointer to OMSU data + * \param [in] callback_functions pointer to callback functions used for memory management and logging. + * \param [in] instanceName Name of OMSU instance. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_allocate_sim_data(omsi_t* omsu, + const omsi_callback_functions* callback_functions, + omsi_string instanceName ) { + + UNUSED(instanceName); + + /* Set global function pointer */ + global_callback = (omsi_callback_functions*) callback_functions; + + /* Log function call */ + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Allocates memory for sim_data"); + + omsu->sim_data = (sim_data_t*)global_callback->allocateMemory(1, sizeof(sim_data_t)); + if (!omsu->sim_data) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In omsu_allocate_sim_data: Not enough memory."); + return omsi_error; + } + + omsu->sim_data->model_vars_and_params = (omsi_values*)global_callback->allocateMemory(1, sizeof(omsi_values)); + if (!omsu->sim_data->model_vars_and_params) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In omsu_allocate_sim_data: Not enough memory."); + return omsi_error; + } + + omsu->sim_data->pre_vars = (omsi_values*)global_callback->allocateMemory(1, sizeof(omsi_values)); + if (!omsu->sim_data->pre_vars) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In omsu_allocate_sim_data: Not enough memory."); + return omsi_error; + } + + /* Allocate memory for initialization and simulation problem */ + omsu->sim_data->initialization = (omsi_function_t*) global_callback->allocateMemory(1, sizeof(omsi_function_t)); + if (!omsu->sim_data->initialization) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In omsu_allocate_sim_data: Not enough memory."); + return omsi_error; + } + + omsu->sim_data->simulation = (omsi_function_t*) global_callback->allocateMemory(1, sizeof(omsi_function_t)); + if (!omsu->sim_data->simulation) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In omsu_allocate_sim_data: Not enough memory."); + return omsi_error; + } + + /* Instantiate function_vars and pre_vars in all omsi_functions */ + if (omsu_instantiate_omsi_function_func_vars(omsu->sim_data->simulation, omsu->sim_data->model_vars_and_params, omsu->sim_data->pre_vars) != omsi_ok) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: in omsu_allocate_sim_data: Could not instantiate omsi_function variables."); + return omsi_error; + } + + /* Allocate memory for zero crossings and sample events and set pointers in omsi_functions */ + omsu->sim_data->zerocrossings_vars = (omsi_real *) global_callback->allocateMemory(omsu->model_data->n_zerocrossings, sizeof(omsi_real)); + omsu->sim_data->pre_zerocrossings_vars = (omsi_real *) global_callback->allocateMemory(omsu->model_data->n_zerocrossings, sizeof(omsi_real)); + omsu->sim_data->sample_events = (omsi_sample*) global_callback->allocateMemory(omsu->model_data->n_samples, sizeof(omsi_sample)); + if (!omsu->sim_data->zerocrossings_vars || !omsu->sim_data->pre_zerocrossings_vars || !omsu->sim_data->sample_events) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: in omsu_allocate_sim_data: Not enough memory."); + return omsi_error; + } + omsu_set_zerocrossings_omsi_functions(omsu->sim_data->initialization, + omsu->sim_data->zerocrossings_vars, omsu->sim_data->pre_zerocrossings_vars, omsu->sim_data->sample_events); + omsu_set_zerocrossings_omsi_functions(omsu->sim_data->simulation, + omsu->sim_data->zerocrossings_vars, omsu->sim_data->pre_zerocrossings_vars, omsu->sim_data->sample_events); + + /* ToDo: Add error cases */ + return omsi_ok; +} + + +/** + * \brief Instantiate `function_vars` recursive for an `omsi_function_t`. + * + * \param [in,out] omsi_function OMSI function to instantiate. + * \param [in] function_vars Pointer to function variables to be set in `omsi_function`. + * \param [in] pre_vars Pointer to pre variables to be set in `omsi_function`. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_instantiate_omsi_function_func_vars (omsi_function_t* omsi_function, + omsi_values* function_vars, + omsi_values* pre_vars) { + + /* Variables */ + omsi_unsigned_int i; + + /* Set function_vars */ + if (function_vars==NULL) { + omsi_function->function_vars = NULL; + } + else if (pre_vars==NULL) { + omsi_function->pre_vars = NULL; + } + else { /* share function_vars with sim_data->model_vars_and_params and pre_vars with sim_data->pre_vars */ + omsi_function->function_vars = function_vars; + omsi_function->pre_vars = pre_vars; + /* Set function_vars and pre_vars recursive on all sub omsi_functions. */ + for(i=0; in_algebraic_system; i++) { + omsu_instantiate_omsi_function_func_vars(omsi_function->algebraic_system_t[i].jacobian, function_vars, pre_vars); + omsu_instantiate_omsi_function_func_vars(omsi_function->algebraic_system_t[i].functions, function_vars, pre_vars); + } + } + + return omsi_ok; +} + + +/** + * \brief Set pointer to zero-crossing variables in `omsi_function` recursive. + * + * \param [in,out] omsi_function OMSI function to set zero_crossings for. + * \param [in] pointer_to_zerocrossings_vars Pointer to function zero-crossing variables to be set in `omsi_function`. + * \param [in] pointer_to_pre_zerocrossings_vars Pointer to function zero-crossing pre-variables to be set in `omsi_function`. + * \param [in] sample_events Sample event to set in `omsi_function`. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_set_zerocrossings_omsi_functions (omsi_function_t* omsi_function, + omsi_real* pointer_to_zerocrossings_vars, + omsi_real* pointer_to_pre_zerocrossings_vars, + omsi_sample* sample_events) +{ + /* Variables */ + omsi_unsigned_int i; + + if (omsi_function==NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Error in function omsu_set_zerocrossings_omsi_functions."); + return omsi_error; + } + + omsi_function->zerocrossings_vars = pointer_to_zerocrossings_vars; + omsi_function->pre_zerocrossings_vars = pointer_to_pre_zerocrossings_vars; + omsi_function->sample_events = sample_events; + + /* ToDo: Do for all alg systems recursively */ + for (i=0; in_algebraic_system; i++){ + omsu_set_zerocrossings_omsi_functions (omsi_function->algebraic_system_t[i].functions, + pointer_to_zerocrossings_vars, + pointer_to_pre_zerocrossings_vars, + sample_events); + omsu_set_zerocrossings_omsi_functions (omsi_function->algebraic_system_t[i].jacobian, + pointer_to_zerocrossings_vars, + pointer_to_pre_zerocrossings_vars, + sample_events); + } + + return omsi_ok; +} + + +/** + * \brief Create new `omsi_function_t` `function`. + * + * Allocate memory except for algebraic system parts. + * + * \param [in] function_vars Values for variables of created function. + * \param [in] pre_vars Values for pre-variables of created function. + * \return `omsi_function_t function` + */ +omsi_function_t* omsu_instantiate_omsi_function (omsi_values* function_vars, + omsi_values* pre_vars) { + + omsi_function_t* function; + + function = (omsi_function_t*) global_callback->allocateMemory(1, sizeof(omsi_function_t)); + if (!function) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not allocate memory for omsi_function_t struct."); + return NULL; + } + + function->algebraic_system_t = NULL; + function->local_vars = NULL; + + omsu_instantiate_omsi_function_func_vars(function, function_vars, pre_vars); + + return function; +} + + +/** + * \brief Create new instantiated `omsi_algebraic_system_t` array. + * + * Allocates memory for `omsi_algebraic_system` struct. + * Since `algebraic_system->n_conditions` is unknown memory for + * `algebraic_system->zerocrossing_indices` is not allocated! + * + * \param [in] n_algebraic_system Number of algebraic systems to create. + * \return New created `omsi_algebraic_system_t* algebraic_system` + * or `NULL` in error case. + */ +omsi_algebraic_system_t* omsu_instantiate_alg_system_array (omsi_unsigned_int n_algebraic_system) { + + /* Variables */ + omsi_algebraic_system_t* algebraic_system; + + if (n_algebraic_system==0) { + return NULL; + } + + /* allocate memory */ + algebraic_system = (omsi_algebraic_system_t*) global_callback->allocateMemory(n_algebraic_system, sizeof(omsi_algebraic_system_t)); + + if (!algebraic_system) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Could not allocate memory for omsi_algebraic_system_t struct."); + return NULL; + } + + return algebraic_system; +} + + +/** + * \brief Create `values` struct of type `omsi_values`. + * + * Needs length for arrays reals, ints, bools and externs as input. + * Returns `NULL` in error case. + * + * \param [in] n_reals Length of array `values->reals`. + * \param [in] n_ints Length of array `values->ints`. + * \param [in] n_bools Length of array `values->bools`. + * \param [in] n_externs Length of array `values->externs`. + * \return New created `omsi_values* values` + * or `NULL` in error case. + */ +omsi_values* instantiate_omsi_values (omsi_unsigned_int n_reals, + omsi_unsigned_int n_ints, + omsi_unsigned_int n_bools, + omsi_unsigned_int n_externs){ + + /* Variables */ + omsi_values* values; + + /* catch not implemented case */ + if (n_externs > 0) { + /* ToDo: Log error, not implemented yet */ + return NULL; + } + + /* Allocate memory */ + values = (omsi_values*) global_callback->allocateMemory(1, sizeof(omsi_values)); + + if (n_reals>0) { + values->reals = alignedMalloc(sizeof(omsi_real) * n_reals, 64); /* ToDo: Switch 64 to some OS depending macro */ + if (!values->reals) { + /* ToDo: log Error */ + return NULL; + } + } + else { + values->reals = NULL; + } + + if (n_ints>0) { + values->ints = alignedMalloc(sizeof(omsi_int) * n_reals, 64); + if (!values->ints) { + /* ToDo: log Error */ + return NULL; + } + } + else { + values->ints = NULL; + } + + if (n_bools>0) { + values->bools = alignedMalloc(sizeof(omsi_bool) * n_reals, 64); + if (!values->bools) { + /* ToDo: log Error */ + return NULL; + } + } + else { + values->bools = NULL; + } + + values->externs = NULL; + + return values; +} + + +/** + * \brief Allocate memory for input and output variables of `omsi_function` + * + * \param [in,out] omsi_function OMSI function to instantiate input and output indices for. + * \param [in] n_input_vars Length or input variables array. + * \param [in] n_output_vars Length or output variables array. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status instantiate_input_inner_output_indices (omsi_function_t* omsi_function, + omsi_unsigned_int n_input_vars, + omsi_unsigned_int n_output_vars) { + + /* Check omsi_function */ + if (!omsi_function) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Memory for omsi_function not allocated."); + return omsi_error; + } + + omsi_function->input_vars_indices = (omsi_index_type*) global_callback->allocateMemory(n_input_vars, sizeof(omsi_index_type)); + /* TODO CHECK_MEMORY_ERROR(omsi_function->input_vars_indices) */ + + omsi_function->output_vars_indices = (omsi_index_type*) global_callback->allocateMemory(n_output_vars, sizeof(omsi_index_type)); + /* TODO CHECK_MEMORY_ERROR(omsi_function->output_vars_indices) */ + + return omsi_ok; +} + + +/** + * \brief Set default solver for all algebraic systems in given `omsi_function`. + * + * Set LAPACK solver for linear systems and kinsol solver for non-linear systems. + * + * \param [in,out] omsi_function OMSI function to set default solvers for. + * \param [in] omsi_function_name Name of OMSI function for logging. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_set_default_solvers (omsi_function_t* omsi_function, + omsi_string omsi_function_name) { + + /* Variables */ + omsi_unsigned_int i, dim_n; + omsi_status status; + + status = omsi_ok; + + if (omsi_function==NULL) { + return omsi_ok; + } + + /* Log function call */ + if (omsi_function->n_algebraic_system > 0) { + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Set default solver for algebraic systems in omsi_function %s.", + omsi_function_name); + } + + for(i=0; in_algebraic_system; i++) { + dim_n = omsi_function->algebraic_system_t[i].n_iteration_vars; /* Dimension of algebraic system */ + + /* Check if solver_data still unallocated */ + if (omsi_function->algebraic_system_t[i].solver_data!=NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Memory for solver_data in algebraic loop %i already allocated.", + i); + return omsi_error; + } + + if (omsi_function->algebraic_system_t[i].isLinear) { + /* Set default linear solver */ + omsi_function->algebraic_system_t[i].solver_data = solver_allocate(solver_lapack, dim_n); + } + else { + /* Set default non-linear solver */ + omsi_function->algebraic_system_t[i].solver_data = solver_allocate(solver_kinsol, dim_n); + } + + if (!omsi_function->algebraic_system_t[i].isLinear) { + omsu_set_initial_guess(&omsi_function->algebraic_system_t[i]); + solver_prepare_specific_data(omsi_function->algebraic_system_t[i].solver_data, + omsi_residual_wrapper, + &omsi_function->algebraic_system_t[i]); + } + else { + solver_prepare_specific_data(omsi_function->algebraic_system_t[i].solver_data, + NULL, + NULL); + } + + /* recursive call for all */ + status = omsu_set_default_solvers (omsi_function->algebraic_system_t[i].jacobian, "jacobian"); + if (status != omsi_ok) { + return status; + } + + status = omsu_set_default_solvers (omsi_function->algebraic_system_t[i].functions, "residual"); + if (status != omsi_ok) { + return status; + } + } + + return status; +} + + +/** + * \brief Set start values for iterative solvers. + * + * Needed for non-linear algebraic systems. + * + * \param [in,out] algebraic_system Algebraic system to set initial guess for. + */ +void omsu_set_initial_guess (omsi_algebraic_system_t* algebraic_system) +{ + /* Variables */ + omsi_real* initial_guess; + omsi_unsigned_int i, index; + + /* Allocate memory */ + initial_guess = (omsi_real*) global_callback->allocateMemory(algebraic_system->solver_data->dim_n, sizeof(omsi_real)); + + /* Read start values for initial guess */ + for (i=0; isolver_data->dim_n; i++) { + index = algebraic_system->functions->output_vars_indices[i].index; + initial_guess[i] = algebraic_system->functions->function_vars->reals[index]; + } + + /* Set initial guess in solver data */ + solver_set_start_vector(algebraic_system->solver_data, initial_guess); +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_input_xml.c b/SimulationRuntime/OMSI/base/src/omsi_input_xml.c new file mode 100644 index 00000000000..8fc87219a04 --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_input_xml.c @@ -0,0 +1,932 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_input_xml.c + */ + +/** \defgroup initXML Initialize XML + * \ingroup Initialization + * + * \brief Process modelName_init.xml file + * + * Functions to process informations from \_init.xml file in + * resources folder. + */ + +/** \addtogroup initXML + * \{ */ + + +#include +#include + +#include + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + + +/** + * \brief Processes modelName_init.xml file to get additional model infos. + * + * Reads input values from input xml file and allocates memory for + * `osu_data->experiment`and `osu_data->model_data` struct. + * + * \param [in] osu_data Pointer to OSU data. + * \param filename Absolute path to modelName_init.xml file + * \param fmuGUID Globally unique identifier to check that modelName_init.xml + * and generated code are compatible. + * \param instanceName Unique identifier for OMSU instance. + * \param functions Callback functions to be used from OMSI functions, e.g for + * memory management or logging. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +omsi_status omsu_process_input_xml(omsi_t* osu_data, + omsi_string filename, + omsi_string fmuGUID, + omsi_string instanceName, + const omsi_callback_functions* functions) { + + /* Variables */ + omsi_int done; + omsi_int n_model_vars_and_params; + omsi_string guid; + omsi_char buf[BUFSIZ] = {0}; + omsi_status status; + + omc_ModelInput mi = {0}; + FILE* file = NULL; + XML_Parser parser = NULL; + + status = omsi_ok; + + /* set global function pointer */ + global_callback = (omsi_callback_functions*) functions; + global_instance_name = instanceName; + + /* Log function call */ + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Process XML file %s.", filename); + + /* open xml file */ + file = fopen(filename, "r"); + if(!file) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Can not read input file %s.", filename); + return omsi_error; + } + + /* create the XML parser */ + parser = XML_ParserCreate("UTF-8"); + if(!parser) { + fclose(file); + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Out of memory."); + return omsi_error; + } + /* set our user data */ + XML_SetUserData(parser, &mi); + /* set the handlers for start/end of element. */ + XML_SetElementHandler(parser, startElement, endElement); + + /* read XML */ + do { + omsi_unsigned_int len = fread(buf, 1, sizeof(buf), file); + done = len < sizeof(buf); + if(XML_STATUS_ERROR == XML_Parse(parser, buf, len, done)) { + fclose(file); + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: failed to read the XML file %s: %s at line %lu.", + filename, + XML_ErrorString(XML_GetErrorCode(parser)), + XML_GetCurrentLineNumber(parser)); + XML_ParserFree(parser); + return omsi_error; + } + } while(!done); + + fclose(file); + XML_ParserFree(parser); + + /* check model GUID */ + guid = omsu_findHashStringStringNull(mi.md,"guid"); + if (NULL==guid) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Model GUID %s is not set in model description %s.", + fmuGUID, filename); + return omsi_error; + } + else if (strcmp(fmuGUID, guid)) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Wrong GUID %s in file %s. Expected %s.", + guid, filename, fmuGUID); + status = omsi_warning; + } + + /* process experiment data */ + osu_data->experiment = functions->allocateMemory(1, sizeof(omsi_experiment_t)); + if (!osu_data->experiment) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Not enough memory to allocate osu_data->experiment."); + return omsi_error; + } + + /* read osu_data */ + omsu_read_value_real(omsu_findHashStringString(mi.de,"startTime"), &(osu_data->experiment->start_time), 0); + omsu_read_value_real(omsu_findHashStringString(mi.de,"stopTime"), &(osu_data->experiment->stop_time), osu_data->experiment->start_time+1); + omsu_read_value_real(omsu_findHashStringString(mi.de,"stepSize"), &(osu_data->experiment->step_size), (osu_data->experiment->stop_time - osu_data->experiment->start_time) / 500); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfOutputVariables"), &(osu_data->experiment->num_outputs)); + omsu_read_value_real(omsu_findHashStringString(mi.de,"tolerance"), &(osu_data->experiment->tolerance), 1e-5); + omsu_read_value_string(omsu_findHashStringString(mi.de,"solver"), (omsi_char**) &(osu_data->experiment->solver_name)); + + /* process all model data */ + osu_data->model_data = functions->allocateMemory(1, sizeof(model_data_t)); + if (!osu_data->model_data) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Not enough memory to allocate osu_data->model_data."); + return omsi_error; + } + omsu_read_value_string(omsu_findHashStringStringNull(mi.md,"guid"), (omsi_char**) &(osu_data->model_data->modelGUID)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfContinuousStates"), &(osu_data->model_data->n_states)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfContinuousStates"), &(osu_data->model_data->n_derivatives)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfRealAlgebraicVariables"), &(osu_data->model_data->n_real_vars)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfIntegerAlgebraicVariables"), &(osu_data->model_data->n_int_vars)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfBooleanAlgebraicVariables"), &(osu_data->model_data->n_bool_vars)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfStringAlgebraicVariables"), &(osu_data->model_data->n_string_vars)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfRealParameters"), &(osu_data->model_data->n_real_parameters)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfIntegerParameters"), &(osu_data->model_data->n_int_parameters)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfBooleanParameters"), &(osu_data->model_data->n_bool_parameters)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfStringParameters"), &(osu_data->model_data->n_string_parameters)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfRealAlgebraicAliasVariables"), &(osu_data->model_data->n_real_aliases)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfIntegerAliasVariables"), &(osu_data->model_data->n_int_aliases)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfBooleanAliasVariables"), &(osu_data->model_data->n_bool_aliases)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfStringAliasVariables"), &(osu_data->model_data->n_string_aliases)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfEventIndicators"), &(osu_data->model_data->n_zerocrossings)); + omsu_read_value_uint(omsu_findHashStringString(mi.md,"numberOfTimeEvents"), &(osu_data->model_data->n_samples)); /* ToDo: Is numberOfTimeEvents also part of n_zerocrossings???? */ + osu_data->model_data->n_equations = -1; /* numberOfEquations is read from JSON */ + osu_data->model_data->n_discrete_reals = 0; + osu_data->model_data->start_index_disc_reals = -1; /* Gets set in omsu_read_var_infos */ + + /* read model_vars_info */ + n_model_vars_and_params = osu_data->model_data->n_states + osu_data->model_data->n_derivatives + + osu_data->model_data->n_real_vars + osu_data->model_data->n_int_vars + + osu_data->model_data->n_bool_vars + osu_data->model_data->n_string_vars + + osu_data->model_data->n_real_parameters + osu_data->model_data->n_int_parameters + + osu_data->model_data->n_bool_parameters + osu_data->model_data->n_string_parameters + + osu_data->model_data->n_real_aliases + osu_data->model_data->n_int_aliases + + osu_data->model_data->n_bool_aliases + osu_data->model_data->n_string_aliases; + + osu_data->model_data->model_vars_info = (model_variable_info_t*) functions->allocateMemory(n_model_vars_and_params, sizeof(model_variable_info_t)); + if (!osu_data->model_data->model_vars_info) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Not enough memory to allocate osu_data->model_data->model_vars_info."); + return omsi_error; + } + + /*read model_vars_info inner stuff */ + omsu_read_var_infos(osu_data->model_data, &mi); + + /* Free stuff */ + omsu_free_ModelInput(&mi); + + return status; +} + + +/* + * ============================================================================ + * Helper functions for XML parsing + * ============================================================================ + */ + +/* + * Helper function for omsu_read_var_info. + * Compute corresponding index for alias variable. + */ +omsi_int omsu_find_alias_index(omsi_int alias_valueReference, + omsi_int n_variables) { + /* + * Solution 1: read name of alias, search variables and parameters for that name, + * save index and id. Write in model_vars_info + * Drawback: Expensive search + */ + + /* + * Solution 2: read modelDescription.xml which contains this information. + * Drawback: parse two in stead of one xml-file + */ + + /* + * ToDo: Solution 3: Edit generation of ..._init.xml and add aliasVariableValueReference + */ + if (alias_valueReference <= n_variables) { + return alias_valueReference; + } + else { + return alias_valueReference-n_variables; + } +} + + +/* + * Helper function for omsu_read_var_infos. + * Read variable info and attributes and write in model_vars_info. + * If one attribute is not found a default value is used. + */ +void omsu_read_var_info (omc_ScalarVariable* v, + model_variable_info_t* model_var_info, + omsi_data_type type, + omsi_unsigned_int* variable_index, + omsi_int number_of_prev_variables) { + + /* Variables */ + omsi_char* tmp_caus_var_init_attribute; + omsi_string aliasTmp; + real_var_attribute_t * attribute_real; + int_var_attribute_t * attribute_int; + bool_var_attribute_t * attribute_bool; + string_var_attribute_t * attribute_string; + + omsu_read_value_string(omsu_findHashStringString(v,"name"), (omsi_char**) &model_var_info->name); + omsu_read_value_int(omsu_findHashStringString(v,"valueReference"), &model_var_info->id, 0); + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"description"), (omsi_char**) &model_var_info->comment); + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"causality"), &tmp_caus_var_init_attribute); + if (0 == strcmp(tmp_caus_var_init_attribute,"parameter")) { + model_var_info->causality = parameter; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"calculatedParameter")) { + model_var_info->causality = calculatedParameter; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"input")) { + model_var_info->causality = input; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"output")) { + model_var_info->causality = output; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"local")) { + model_var_info->causality = local; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"independent")) { + model_var_info->causality = independent; + }else if (tmp_caus_var_init_attribute==NULL) { + model_var_info->causality = local; + }else { + /* ToDo: Add error */ + } + global_callback->freeMemory(tmp_caus_var_init_attribute); + + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"variability"), &tmp_caus_var_init_attribute); + if (0 == strcmp(tmp_caus_var_init_attribute,"constant")) { + model_var_info->variability = constant; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"fixed")) { + model_var_info->variability = fixed; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"tunable")) { + model_var_info->variability = tunable; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"discrete")) { + model_var_info->variability = discrete; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"continous")) { + model_var_info->variability = continous; + }else if (tmp_caus_var_init_attribute==NULL) { + model_var_info->variability = continous; + }else { + /* ToDo: Add error */ + } + global_callback->freeMemory(tmp_caus_var_init_attribute); + + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"initial"), &tmp_caus_var_init_attribute); + if (0 == strcmp(tmp_caus_var_init_attribute,"exact")) { + model_var_info->initial = exact; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"approx")) { + model_var_info->initial = approx; + }else if (0 == strcmp(tmp_caus_var_init_attribute,"calculated")) { + model_var_info->initial = calculated; + }else if (tmp_caus_var_init_attribute==NULL) { + if (model_var_info->variability==constant || model_var_info->causality==parameter) { + model_var_info->initial = exact; + }else if (model_var_info->variability==fixed || model_var_info->variability==tunable + || model_var_info->causality==output || model_var_info->causality==local) { + model_var_info->initial = calculated; + }else { + model_var_info->initial = no_initial; + } + }else { + /* ToDo: Add error */ + } + global_callback->freeMemory(tmp_caus_var_init_attribute); + + model_var_info->type_index.type = type; + + /* read attributes in dependence of variable_type */ + switch(type) { + default: + case OMSI_TYPE_UNKNOWN: + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Unknown OMSI type for modelica attributes."); + break; + + case OMSI_TYPE_REAL: + attribute_real = (real_var_attribute_t *) global_callback->allocateMemory(1, sizeof(real_var_attribute_t)); + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"unit"), (omsi_char**) &attribute_real->unit); + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"displayUnit"), (omsi_char**) &attribute_real->displayUnit); + omsu_read_value_real(omsu_findHashStringString(v,"min"), &attribute_real->min, -OMSI_DBL_MAX); + omsu_read_value_real(omsu_findHashStringString(v,"max"), &attribute_real->max, OMSI_DBL_MAX); + omsu_read_value_bool(omsu_findHashStringString(v,"fixed"), &attribute_real->fixed); + omsu_read_value_real(omsu_findHashStringString(v,"nominal"), &attribute_real->nominal, 1); + omsu_read_value_real(omsu_findHashStringString(v,"start"), &attribute_real->start, 0); + model_var_info->modelica_attributes = attribute_real; + break; + + case OMSI_TYPE_INTEGER: + attribute_int = (int_var_attribute_t *) global_callback->allocateMemory(1, sizeof(int_var_attribute_t)); + omsu_read_value_int(omsu_findHashStringString(v,"min"), &attribute_int->min, -OMSI_INT_MAX); + omsu_read_value_int(omsu_findHashStringString(v,"max"), &attribute_int->min, OMSI_INT_MAX); + omsu_read_value_bool(omsu_findHashStringString(v,"fixed"), &attribute_int->fixed); + omsu_read_value_int(omsu_findHashStringString(v,"start"), &attribute_int->start, 0); + model_var_info->modelica_attributes = attribute_int; + break; + + case OMSI_TYPE_BOOLEAN: + attribute_bool = (bool_var_attribute_t *) global_callback->allocateMemory(1, sizeof(bool_var_attribute_t)); + omsu_read_value_bool(omsu_findHashStringString(v,"fixed"), &attribute_bool->fixed); + omsu_read_value_bool_default(omsu_findHashStringString(v,"start"), &attribute_bool->start, 0); + model_var_info->modelica_attributes = attribute_bool; + break; + + case OMSI_TYPE_STRING: + attribute_string = (string_var_attribute_t *) global_callback->allocateMemory(1, sizeof(string_var_attribute_t)); + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"start"), &attribute_string->start); + model_var_info->modelica_attributes = attribute_string; + break; + } + + omsu_read_value_string(omsu_findHashStringStringNull(v,"alias"), (omsi_char**) &aliasTmp); + if (0 == strcmp(aliasTmp,"noAlias")) { + model_var_info->isAlias = omsi_false; + model_var_info->negate = 1; + model_var_info->aliasID = -1; + model_var_info->type_index.index = *variable_index; + (*variable_index)++; + } + else if (0 == strcmp(aliasTmp,"negatedAlias")){ + model_var_info->isAlias = omsi_true; + model_var_info->negate = -1; + /* ToDo: find alias id */ + omsu_read_value_int(omsu_findHashStringString(v,"aliasVariableId"), &model_var_info->aliasID, -1); + model_var_info->type_index.index = omsu_find_alias_index(model_var_info->aliasID, number_of_prev_variables); + } + else { + model_var_info->isAlias = omsi_true; + model_var_info->negate = 1; + /* ToDo: find alias id */ + omsu_read_value_int(omsu_findHashStringString(v,"aliasVariableId"), &model_var_info->aliasID, -1); + model_var_info->type_index.index = omsu_find_alias_index(model_var_info->aliasID, number_of_prev_variables); + } + + omsu_read_value_string(omsu_findHashStringStringEmpty(v,"fileName"), (omsi_char**) &model_var_info->info.filename); + omsu_read_value_int(omsu_findHashStringString(v,"startLine"), &model_var_info->info.lineStart, 0); + omsu_read_value_int(omsu_findHashStringString(v,"startColumn"), &model_var_info->info.colStart, 0); + omsu_read_value_int(omsu_findHashStringString(v,"endLine"), &model_var_info->info.lineEnd, 0); + omsu_read_value_int(omsu_findHashStringString(v,"endColumn"), &model_var_info->info.colEnd, 0); + omsu_read_value_bool(omsu_findHashStringString(v,"fileWritable"), &model_var_info->info.fileWritable); + + /* Free memory */ + global_callback->freeMemory((omsi_char*) aliasTmp); +} + + +/* + * Helper function for omsu_process_input_xml. + * Fill model_vars_info for all states, derivatives, variables and parameters. + * Allocates memory for strings. + */ +void omsu_read_var_infos(model_data_t* model_data, + omc_ModelInput* mi) { + + /* Variables */ + omsi_unsigned_int i, j=0; + omsi_unsigned_int variable_index = 0; + omsi_int prev_variables; + + /* Log function call */ + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Instantiate: Read variable informations from XML file."); + + /* model vars info for states and derivatives */ + for (i=0; in_states; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->rSta ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_REAL, &variable_index, -1); + } + for (i=0; in_states; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->rDer ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_REAL, &variable_index, -1); + } + + /* model vars info for reals */ + for (i=0; in_real_vars; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->rAlg ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_REAL, &variable_index, -1); + /* Count discrete real variables and set start index */ + if (model_data->model_vars_info[j].variability==discrete) { + model_data->n_discrete_reals++; + if (model_data->start_index_disc_reals == -1) + model_data->start_index_disc_reals=j; + } + } + for (i=0; in_real_parameters; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->rPar ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_REAL, &variable_index, -1); + } + for (i=0; in_real_aliases; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->rAli ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_REAL, NULL, 0); + } + /* ToDo: add sensitives? */ + + /* model vars info for intgers */ + variable_index = 0; + prev_variables = model_data->n_real_vars+model_data->n_real_parameters; + for (i=0; in_int_vars; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->iAlg ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_INTEGER, &variable_index, -1); + } + for (i=0; in_int_parameters; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->iPar ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_INTEGER, &variable_index, -1); + } + for (i=0; in_int_aliases; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->iAli ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_INTEGER, NULL, prev_variables); + } + + /* model vars info for booleans */ + variable_index = 0; + prev_variables += model_data->n_int_vars+model_data->n_int_parameters; + for (i=0; in_bool_vars; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->bAlg ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_BOOLEAN, &variable_index, -1); + } + for (i=0; in_bool_parameters; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->bPar ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_BOOLEAN, &variable_index, -1); + } + for (i=0; in_bool_aliases; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->bAli ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_BOOLEAN, NULL, prev_variables); + } + + /* model vars info for strings */ + variable_index = 0; + prev_variables += model_data->n_bool_vars+model_data->n_bool_parameters; + for (i=0; in_string_vars; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->sAlg ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_STRING, &variable_index, -1); + } + for (i=0; in_string_parameters; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->sPar ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_STRING, &variable_index, -1); + } + for (i=0; in_string_aliases; i++, j++) { + omc_ScalarVariable *v = *omsu_findHashLongVar(mi->sAli ,i); + omsu_read_var_info(v, &model_data->model_vars_info[j], OMSI_TYPE_STRING, NULL, prev_variables); + } +} + + +/* + * Return string from hash table or NULL if not found. + */ +omsi_string omsu_findHashStringStringNull(hash_string_string* ht, + omsi_string key) { + + hash_string_string *res; + HASH_FIND_STR( ht, key, res ); + return res ? res->val : NULL; +} + + +/* + * Return string from hash table or empty string if not found. + */ +omsi_string omsu_findHashStringStringEmpty(hash_string_string* ht, + omsi_string key) { + + omsi_string res = omsu_findHashStringStringNull(ht,key); + return res ? res : ""; +} + + +/* + * Return string from hash table or log error if not found. + * ToDo: Error logging disabled at the moment. Change! + */ +omsi_string omsu_findHashStringString(hash_string_string* ht, + omsi_string key) { + + omsi_string res = omsu_findHashStringStringNull(ht,key); + if (0==res) { + hash_string_string *c, *tmp; + HASH_ITER(hh, ht, c, tmp) { + /* ToDo: To much noise */ + /* LOG_FILTER(global_callback->componentEnvironment, LOG_STATUSWARNING, + global_callback->logger(global_callback->componentEnvironment, global_instance_name, + omsi_warning, logCategoriesNames[LOG_STATUSWARNING], "HashMap contained: %s->%s\n", c->id, c->val)) */ + } + /* ToDo: Log error for non optional keys */ + /*LOG_FILTER(global_callback->componentEnvironment, LOG_STATUSWARNING, + global_callback->logger(global_callback->componentEnvironment, global_instance_name, + omsi_warning, logCategoriesNames[LOG_STATUSWARNING], "fmi2Instantiate: Failed to lookup string %s in hashmap %p", key, ht))*/ + } + return res; +} + +/* + * Add long variable to hash table. + */ +void omsu_addHashLongVar(hash_long_var** ht, + omsi_long key, + omc_ScalarVariable* val) { + + hash_long_var *v = (hash_long_var*) global_callback->allocateMemory(1, sizeof(hash_long_var)); /* ToDo: where is this memory freed? */ + v->id=key; + v->val=val; + HASH_ADD_INT( *ht, id, v ); +} + + +/* + * Add string variable to hash table. + */ +void omsu_addHashStringString(hash_string_string** ht, + omsi_string key, + omsi_string val) { + + hash_string_string *v = (hash_string_string*) global_callback->allocateMemory(1, sizeof(hash_string_string)); + v->id=omsi_strdup(key); + v->val=omsi_strdup(val); + HASH_ADD_KEYPTR( hh, *ht, v->id, strlen(v->id), v ); +} + + +/* + * Read integer value from a string. + */ +void omsu_read_value_int(omsi_string s, + omsi_int* res, + omsi_int default_value) { + + if (s==NULL || *s == '\0') { + *res = default_value; + } else if (0 == strcmp(s, "true")) { + *res = 1; + } else if (0 == strcmp(s, "false")) { + *res = 0; + } else { + *res = strtol(s, (omsi_char **) NULL, 10); + } +} + + +/* + * Read unsigned integer value from a string. + */ +void omsu_read_value_uint(omsi_string s, + omsi_unsigned_int* res) { + if (s==NULL) { + *res = 0; /*default value, if no string was found */ + return; + } + if (0 == strcmp(s, "true")) { + *res = 1; + } else if (0 == strcmp(s, "false")) { + *res = 0; + } else { + *res = strtol(s, (omsi_char **) NULL, 10); + } +} + + +/* + * Find long variable in hash table or log error. + */ +omc_ScalarVariable** omsu_findHashLongVar(hash_long_var* ht, + omsi_long key) { + + hash_long_var *res; + HASH_FIND_INT( ht, &key, res ); + if (0==res) { + hash_long_var *c, *tmp; + HASH_ITER(hh, ht, c, tmp) { + /* ToDo: to much noise */ + /* LOG_FILTER(global_callback->componentEnvironment, LOG_STATUSWARNING, + global_callback->logger(global_callback->componentEnvironment, global_instance_name, + omsi_warning, logCategoriesNames[LOG_STATUSWARNING], "HashMap contained: %ld->*map*\n", c->id)) */ + } + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Failed to lookup long %s in hashmap %p", key, ht); + } + return &res->val; +} + + +/* + * Read double value from string. + */ +void omsu_read_value_real(omsi_string s, + omsi_real* res, + omsi_real default_value) { + + if (s== NULL || *s == '\0') { + *res = default_value; + } else if (0 == strcmp(s, "true")) { + *res = 1.0; + } else if (0 == strcmp(s, "false")) { + *res = 0.0; + } else { + *res = atof(s); /* ToDo: use strtod() */ + } +} + + +/* + * Read boolean value from string. + */ +void omsu_read_value_bool(omsi_string s, + omsi_bool* res) { + + *res = 0 == strcmp(s, "true"); +} + + +/* + * Read boolean value from string or return default value. + */ +void omsu_read_value_bool_default (omsi_string s, + omsi_bool* res, + omsi_bool default_bool) { + + if (s == NULL || *s == '\0') { + *res = default_bool; + } + else{ + *res = 0 == strcmp(s, "true"); + } +} + + +/* + * Read string value from string. + * Allocates memory for string and copies string s into str. + */ +void omsu_read_value_string(omsi_string s, + omsi_char** str) { + + if(str == NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: In function omsu_read_value_string: \ + Memory for string not allocated."); + return; + } + + *str = omsi_strdup(s); + if (str == NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Out of memory."); + return; + } +} + + +/* + * ============================================================================ + * Helper functions for Expat. + * https://libexpat.github.io/doc/ + * ============================================================================ + */ + +/* + * Helper function used for Expat. + */ +void XMLCALL startElement(void* userData, + omsi_string name, + omsi_string* attr) { + + omc_ModelInput* mi = (omc_ModelInput*) userData; + omsi_long i = 0; + + /* handle fmiModelDescription */ + if (!strcmp(name, "fmiModelDescription")) { + for (i = 0; attr[i]; i += 2) { + omsu_addHashStringString(&mi->md, attr[i], attr[i + 1]); + } + return; + } + /* handle DefaultExperiment */ + if (!strcmp(name, "DefaultExperiment")) { + for (i = 0; attr[i]; i += 2) { + omsu_addHashStringString(&mi->de, attr[i], attr[i + 1]); + } + return; + } + + /* handle ScalarVariable */ + if (!strcmp(name, "ScalarVariable")) { + omc_ScalarVariable *v = NULL; + omsi_string ci, ct; + omsi_int fail = 0; + mi->lastCI = -1; + mi->lastCT = NULL; + for (i = 0; attr[i]; i += 2) { + omsu_addHashStringString(&v, attr[i], attr[i + 1]); + } + /* fetch the class index/type */ + ci = omsu_findHashStringString(v, "classIndex"); + ct = omsu_findHashStringString(v, "classType"); + /* transform to omsi_long */ + mi->lastCI = strtol(ci, NULL, 10); + + /* which one of the classifications? */ + if (strlen(ct) == 4) { + if (ct[0] == 'r') { + if (0 == strcmp(ct + 1, "Sta")) { + mi->lastCT = &mi->rSta; + } else if (0 == strcmp(ct + 1, "Der")) { + mi->lastCT = &mi->rDer; + } else if (0 == strcmp(ct + 1, "Alg")) { + mi->lastCT = &mi->rAlg; + } else if (0 == strcmp(ct + 1, "Par")) { + mi->lastCT = &mi->rPar; + } else if (0 == strcmp(ct + 1, "Ali")) { + mi->lastCT = &mi->rAli; + } else if (0 == strcmp(ct + 1, "Sen")) { + mi->lastCT = &mi->rSen; + } else { + fail = 1; + } + } else if (ct[0] == 'i') { + if (0 == strcmp(ct + 1, "Alg")) { + mi->lastCT = &mi->iAlg; + } else if (0 == strcmp(ct + 1, "Par")) { + mi->lastCT = &mi->iPar; + } else if (0 == strcmp(ct + 1, "Ali")) { + mi->lastCT = &mi->iAli; + } else { + fail = 1; + } + } else if (ct[0] == 'b') { + if (0 == strcmp(ct + 1, "Alg")) { + mi->lastCT = &mi->bAlg; + } else if (0 == strcmp(ct + 1, "Par")) { + mi->lastCT = &mi->bPar; + } else if (0 == strcmp(ct + 1, "Ali")) { + mi->lastCT = &mi->bAli; + } else { + fail = 1; + } + } else if (ct[0] == 's') { + if (0 == strcmp(ct + 1, "Alg")) { + mi->lastCT = &mi->sAlg; + } else if (0 == strcmp(ct + 1, "Par")) { + mi->lastCT = &mi->sPar; + } else if (0 == strcmp(ct + 1, "Ali")) { + mi->lastCT = &mi->sAli; + } else { + fail = 1; + } + } else { + fail = 1; + } + } else { + fail = 1; + } + + if (fail) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Instantiate: Found unknown class: %s for variable: %s while reading XML.", + ct, omsu_findHashStringString(v,"name")); + } + + /* add the ScalarVariable map to the correct map! */ + omsu_addHashLongVar(mi->lastCT, mi->lastCI, v); + + return; + } + + /* handle Real/Integer/Boolean/String */ + if (!strcmp(name, "Real") || !strcmp(name, "Integer") + || !strcmp(name, "Boolean") || !strcmp(name, "String")) { + /* add keys/value to the last variable */ + for (i = 0; attr[i]; i += 2) { + /* add more key/value pairs to the last variable */ + omsu_addHashStringString( + omsu_findHashLongVar(*mi->lastCT, mi->lastCI), attr[i], + attr[i + 1]); + } + omsu_addHashStringString(omsu_findHashLongVar(*mi->lastCT, mi->lastCI), + "variableType", name); + return; + } + /* anything else, we don't handle! */ + /* ToDo: Error mesage or warning??? */ +} + + +/* + * Helper function used for Expat. + */ +void XMLCALL endElement(void* userData, + omsi_string name) { + + /* do nothing! */ + UNUSED(userData); UNUSED(name); +} + + +/* + * ============================================================================ + * Functions for memory management. + * ============================================================================ + */ + +/* + * Deallocate memory for omc_ModelInput struct + * ToDo: is full of bugs + */ +void omsu_free_ModelInput(omc_ModelInput* mi) { + + free_hash_string_string(mi->md); + free_hash_string_string(mi->de); + + free_hash_long_var(mi->rSta); + free_hash_long_var(mi->rDer); + free_hash_long_var(mi->rAlg); + free_hash_long_var(mi->rPar); + free_hash_long_var(mi->rAli); + free_hash_long_var(mi->rSen); + + free_hash_long_var(mi->iAlg); + free_hash_long_var(mi->iPar); + free_hash_long_var(mi->iAli); + + free_hash_long_var(mi->bAlg); + free_hash_long_var(mi->bPar); + free_hash_long_var(mi->bAli); + + free_hash_long_var(mi->sAlg); + free_hash_long_var(mi->sPar); + free_hash_long_var(mi->sAli); +} + + +/* + * Delete all items from hash and free memory for hash table hash_string_string + */ +void free_hash_string_string (hash_string_string* data) { + + hash_string_string* current, *tmp; + + HASH_ITER(hh, data, current, tmp) { + HASH_DEL(data, current); /* delete; current advances to next */ + global_callback->freeMemory((omsi_char *)current->id); + global_callback->freeMemory((omsi_char *)current->val); + global_callback->freeMemory(current); + } +} + + +/* + * Delete all items from hash and free memory for hash table hash_long_var + */ +void free_hash_long_var (hash_long_var* data) { + + hash_long_var* current, *tmp; + + HASH_ITER(hh, data, current, tmp) { + HASH_DEL(data, current); /* delete; current advances to next */ + free_hash_string_string(current->val); + global_callback->freeMemory(current); + } +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_mmap.c b/SimulationRuntime/OMSI/base/src/omsi_mmap.c new file mode 100644 index 00000000000..4bab24af335 --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_mmap.c @@ -0,0 +1,163 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_mmap.c + * \brief Helper functions for omc mmap. + */ + +#if !defined(OMS_NO_FILESYSTEM) +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if HAVE_MMAP + + +omc_mmap_read_unix omc_mmap_open_read_unix(omsi_string fileName) +{ + struct stat s; + omc_mmap_read_unix res = {0}; + omsi_int fd = open(fileName, O_RDONLY); + if (fd < 0) { + /*throwStreamPrint(NULL, "Failed to open file %s for reading: %s\n", fileName, strerror(errno)); ToDo: add logger*/ + } + if (fstat(fd, &s) < 0) { + close(fd); + /*throwStreamPrint(NULL, "fstat %s failed: %s\n", fileName, strerror(errno)); ToDo: add logger*/ + } + res.size = s.st_size; + res.data = (omsi_string) mmap(0, res.size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + if (res.data == MAP_FAILED) { + /*throwStreamPrint(NULL, "mmap(file=\"%s\",fd=%d,size=%ld kB) failed: %s\n", fileName, fd, (long) s.st_size, strerror(errno)); ToDo: add logger*/ + } + return res; +} + +omc_mmap_write_unix omc_mmap_open_write_unix(omsi_string fileName, omsi_unsigned_int size) +{ + omc_mmap_write_unix res = {0}; + omsi_int fd = open(fileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + /*throwStreamPrint(NULL, "Failed to open file %s for reading: %s\n", fileName, strerror(errno)); ToDo: add logger*/ + } + if (size == 0) { + struct stat s; + if (fstat(fd, &s) < 0) { + close(fd); + /*throwStreamPrint(NULL, "fstat %s failed: %s\n", fileName, strerror(errno)); ToDo: add logger*/ + } + res.size = s.st_size; + } else { + res.size = size; + lseek(fd, size, SEEK_SET); + } + res.data = res.size == 0 ? NULL : (omsi_char*) mmap(0, res.size, PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + if (res.data == MAP_FAILED) { + /*throwStreamPrint(NULL, "mmap(file=\"%s\",fd=%d,size=%ld kB) failed: %s\n", fileName, fd, (long) res.size, strerror(errno)); ToDo: add logger*/ + } + return res; +} + +void omc_mmap_close_read_unix(omc_mmap_read_unix map) +{ + munmap((void*)map.data, map.size); +} + +void omc_mmap_close_write_unix(omc_mmap_write_unix map) +{ + munmap((void*)map.data, map.size); +} + +#endif /* HAVE_MMAP */ + +static FILE* omc_mmap_common(omsi_string fileName, omsi_string mode, omsi_unsigned_int *size, omsi_char **data) +{ + FILE *file = fopen(fileName, mode); + omsi_unsigned_int fileSize; + if (!file) { + /*throwStreamPrint(NULL, "Failed to open file %s for reading: %s\n", fileName, strerror(errno)); */ + } + fseek(file, 0, SEEK_END); + fileSize = ftell(file); + rewind(file); + if (*size == 0) { + *size = fileSize; + } + + *data = (omsi_char*) global_callback->allocateMemory(*size, 1); + + if (1 != fread(*data, (*size > fileSize ? fileSize : *size), 1, file)) { + /*throwStreamPrint(NULL, "Failed to read file data: %s\n", fileName); ToDo: add logger */ + } + return file; +} + +omc_mmap_read_inmemory omc_mmap_open_read_inmemory(omsi_string fileName) +{ + omc_mmap_read_inmemory res = {0}; + res.size = 0; + fclose(omc_mmap_common(fileName, "rb", &res.size, (omsi_char**)&res.data)); + return res; +} + +omc_mmap_write_inmemory omc_mmap_open_write_inmemory(omsi_string fileName, omsi_unsigned_int size) +{ + omc_mmap_write_inmemory res = {0}; + res.size = size; + res.file = omc_mmap_common(fileName, "rb+", &res.size, &res.data); + return res; +} + +void omc_mmap_close_read_inmemory(omc_mmap_read_inmemory map) +{ + global_callback->freeMemory((void*)map.data); +} + +void omc_mmap_close_write_inmemory(omc_mmap_write_inmemory map) +{ + rewind(map.file); + if (1 != fwrite(map.data, map.size, 1, map.file)) { + global_callback->freeMemory(map.data); + /*throwStreamPrint(NULL, "Failed to write back to file"); ToDo: add logger*/ + } + global_callback->freeMemory((void*)map.data); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* OMC_NO_FILESYSTEM */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_posix_func.c b/SimulationRuntime/OMSI/base/src/omsi_posix_func.c new file mode 100644 index 00000000000..886654930ae --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_posix_func.c @@ -0,0 +1,54 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/* Write own POSIX functions, since ANSI C does not has them. */ + +#ifndef POSIX + +#include +#include + +omsi_char* omsi_strdup (const omsi_char *s) { + omsi_char* d = (omsi_char*) global_callback->allocateMemory (strlen (s) + 1, sizeof(omsi_char)); + if (d == NULL) { + return NULL; + } + strcpy (d,s); + return d; +} + +#else + +omsi_char* omsi_strdup (const omsi_char *s) { + return strdup(s); +} + + +#endif diff --git a/SimulationRuntime/OMSI/base/src/omsi_solve_alg_system.c b/SimulationRuntime/OMSI/base/src/omsi_solve_alg_system.c new file mode 100644 index 00000000000..bcc6b6e8021 --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_solve_alg_system.c @@ -0,0 +1,401 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_solve_alg_system.c + * \brief Contains functions for algebraic system evaluation using OMSISolver library. + */ + +/** \defgroup AlgSyst Algebraic system evaluation + * \ingroup OMSIBase + * + * Functions and wrapper to use OMSISolver library with OMSI structure from + * generated code functions. + */ + +/** \addtogroup AlgSyst + * \{ */ + +#include +#include + + +/** + * \brief Solve algebraic system defined in `omsi_algebraic_system_t alg_system` + * + * Evaluate jacobian matrix and residual function to get all informations needed + * for linear or non-linear solver. + * Gets called from generated code equation evaluation function. + * + * \param [in,out] alg_system Pointer to struct containing algebraic system. + * \param [in] read_only_model_vars_and_params Pointer to read only `model_vars_and_params` + * to forward to next equation function in generated code. + * \return Returns `omsi_fatal` on critical error
+ * and returns `omsi_ok` otherwise. + */ +omsi_status omsi_solve_algebraic_system (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params) { + + /* Variables */ + omsi_int status; + + /* Check if solver is ready */ + if (alg_system->solver_data == NULL ) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_fatal, + "fmi2Evaluate: Solver for %s system %u not set.", + alg_system->isLinear ? "linear":"nonlinear", + alg_system->id); + return omsi_fatal; + } + + /* Log solver call */ + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2Evaluate: Solve %s system %u of size %u with solver %s.", + alg_system->isLinear ? "linear":"nonlinear", + alg_system->id, + alg_system->n_iteration_vars, + solver_get_name(alg_system->solver_data)); + + /* Check if it is possible to reuse matrix A or vector b */ + /* ToDo */ + + /* Update solver specific data */ + if (alg_system->isLinear) { + omsi_get_analytical_jacobian(alg_system, read_only_model_vars_and_params); + omsi_get_right_hand_side(alg_system, read_only_model_vars_and_params); + } else { + omsi_update_guess(alg_system->solver_data, alg_system); + } + + alg_system->solver_data->state = solver_ready; + + /* Call solver */ + if (alg_system->isLinear) { + status = solver_linear_solve(alg_system->solver_data); + } else { + status = solver_non_linear_solve(alg_system->solver_data); + } + + if (status == solver_error) { + return omsi_error; + } else if (status == solver_warning) { + return omsi_warning; + } + + /* Save results */ + status = omsi_get_loop_results(alg_system, read_only_model_vars_and_params, alg_system->functions->function_vars); + /* ToDo: change alg_system->functions->function_vars to next higher function_vars + * only works because at the moment all function vars are pointer to model_vars_and_params */ + + return status; +} + + +/** + * \brief Evaluate `omsi_function` jacobian to get the analytical jacobian. + * + * Build jacobian row wise with directional derivatives. + * + * \param [in,out] alg_system Pointer to struct containing algebraic system. + * \param [in] read_only_model_vars_and_params Pointer to read only `model_vars_and_params` + * to forward to next equation function in generated code. + * \return Returns `omsi_fatal` on critical error
+ * and returns `omsi_ok` otherwise. + */ +omsi_status omsi_get_analytical_jacobian (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params) { + + /* Variables */ + omsi_unsigned_int i; + omsi_unsigned_int seed_index; + + /* Set seed vars */ + for (i=0; ijacobian->n_input_vars; i++) { + seed_index = alg_system->jacobian->input_vars_indices[i].index; + alg_system->jacobian->local_vars->reals[seed_index] = 0; + } + + /* Build jacobian row wise with directional derivatives */ /* ToDo: check if realy row wise and not column wise... */ + for (i=0; ijacobian->n_output_vars; i++) { /* ToDo: Add coloring here */ + /* Activate seed for current row*/ + seed_index = alg_system->jacobian->input_vars_indices[i].index; + alg_system->jacobian->local_vars->reals[seed_index] = 1; + + /* Evaluate directional derivative */ + alg_system->jacobian->evaluate(alg_system->jacobian, read_only_model_vars_and_params, NULL); + + /* Set i-th row of matrix A */ + solver_set_matrix_A(alg_system->solver_data, + NULL, alg_system->jacobian->n_output_vars, + &i, 1, + &alg_system->jacobian->local_vars->reals[alg_system->jacobian->output_vars_indices[0].index]); + + /* Reset seed vector */ + alg_system->jacobian->local_vars->reals[seed_index] = 0; + } + + return omsi_ok; +} + + +/** + * \brief Get right hand side `b` of linear equation system `A*x=b`. + * + * Evaluate residual function with loop iteration variables set to zero to get `-b`. + * + * \param [in,out] alg_system Pointer to struct containing algebraic system. + * \param [in] read_only_model_vars_and_params Pointer to read only `model_vars_and_params` + * to forward to next equation function in generated code. + * \return Returns `omsi_fatal` on critical error
+ * and returns `omsi_ok` otherwise. + */ +omsi_status omsi_get_right_hand_side (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params) { + + /* Variables */ + omsi_real* residual; + omsi_unsigned_int i, n_loop_iteration_vars; + omsi_unsigned_int loop_iter_var_index; + + n_loop_iteration_vars = alg_system->jacobian->n_output_vars; + + /* Allocate memory */ + residual = global_callback->allocateMemory(alg_system->jacobian->n_input_vars, sizeof(omsi_real)); + + /* Set loop iteration variables zero. */ + for (i=0; ifunctions->output_vars_indices[i].index; + alg_system->functions->function_vars->reals[loop_iter_var_index] = 0; + } + + /* Evaluate residuum function */ + alg_system->functions->evaluate(alg_system->functions, read_only_model_vars_and_params, residual); + + /* Flip signs of residual to get b*/ + for (i=0; ijacobian->n_input_vars;i++) { + residual[i] = - residual[i]; + } + solver_set_vector_b(alg_system->solver_data, NULL, alg_system->jacobian->n_input_vars, residual); + + + /* Free memory */ + global_callback->freeMemory(residual); + + return omsi_ok; +} + + +/** + * + * \param [in,out] alg_system Pointer to struct containing algebraic system. + * \param [in] read_only_model_vars_and_params Pointer to read only `model_vars_and_params` + * to forward to next equation function in generated code. + * \param [in, out] vars On input pointer to `omsi_values`.
+ * Contains result of algebraic system evaluation on exit. + * Overwrites information in `vars` with indices saved in + * `alg_system->functions->output_vars_indices`. + * \return Returns `omsi_fatal` on critical error,
+ * `omsi_warning` if the solution is not within error tolerance
+ * and returns `omsi_ok` otherwise. + */ +omsi_status omsi_get_loop_results (omsi_algebraic_system_t* alg_system, + const omsi_values* read_only_model_vars_and_params, + omsi_values* vars) { + + /* Variables */ + omsi_unsigned_int i; + omsi_unsigned_int n_loop_iteration_vars; + omsi_real *res; + omsi_status status; + + status = omsi_ok; + + /* Allocate memory */ + n_loop_iteration_vars = alg_system->jacobian->n_output_vars; + res = (omsi_real*) global_callback->allocateMemory(n_loop_iteration_vars ,sizeof(omsi_real)); + if (res == NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Evaluate: Could not allocate memory."); + return omsi_fatal; + } + + if (alg_system->isLinear) { + for (i=0; ijacobian->n_output_vars; i++) { + solver_get_lin_solution(alg_system->solver_data, + &i, + 1, + &vars->reals[alg_system->functions->output_vars_indices[i].index]); + } + } else { + for (i=0; ijacobian->n_output_vars; i++) { + solver_get_nonlin_solution(alg_system->solver_data, + &i, + 1, + &vars->reals[alg_system->functions->output_vars_indices[i].index]); + } + } + + /* evaluate residuum function to get LOOP_SOLVED variables */ + alg_system->functions->evaluate(alg_system->functions, read_only_model_vars_and_params, res); + + /* Check result */ + for (i=0; i 1e-8) { + filtered_base_logger(global_logCategories, log_statusdiscard, omsi_warning, + "fmi2Evaluate: Solution of %s system %u is not within accepted error tollerance 1e-8.", + alg_system->isLinear? "linear":"non-linear", + alg_system->id); + break; + status = omsi_error; + } + } + + /* Free memory */ + global_callback->freeMemory(res); + + return status; +} + +/** + * \brief Set up solver instance for one algebraic system. + * + * Allocate memory and set constant data like dimensions. + * + * \param [in, out] alg_system Algebraic system instance. + * \return Returns `omsi_ok` on success, otherwise `omsi_error`. + */ +omsi_status omsi_set_up_solver (omsi_algebraic_system_t* alg_system) { + + /* Allocate memory */ + alg_system->solver_data = solver_allocate(solver_lapack, alg_system->n_iteration_vars); + if (alg_system->solver_data == NULL) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Something: Can not allocate memory for solver instance."); + return omsi_error; + } + + /* Prepare specific solver data */ + if(solver_prepare_specific_data(alg_system->solver_data, omsi_residual_wrapper, alg_system) != solver_ok) { + solver_free(alg_system->solver_data); + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Something: Could not prepare specific solver data for solver instance."); + return omsi_error; + } + + return omsi_ok; +} + + +/** + * \brief Callback function for OMSISolver of function type `evaluate_res_func`. + * + * Map input vector `x_data` to `alg_system->residual->function_vars` and vice + * versa residual to `fval_data`. + * + * \param [in,out] x_data Gets mapped to`alg_system->residual->function_vars`. + * Input for residuum function. + * \param [out] fval_data Contains result of residuum evaluation. + * \param [in,out] data Contains `omsi_algebraic_system_t* alg_system_data`. + * \return Return `omsi_ok` on success and `omsi_error` otherwise, + * returning as `omsi_int`. + */ +omsi_int omsi_residual_wrapper (omsi_real* x_data, + omsi_real* fval_data, + void* data) { + + /* Variables */ + omsi_unsigned_int i, index; + omsi_algebraic_system_t* alg_system_data; + omsi_function_t* residual; + + alg_system_data = (omsi_algebraic_system_t*) data; + residual = alg_system_data->functions; + + /* Copy x_data to residuum->function_vars */ + for (i=0; ijacobian->n_input_vars; i++) { /* ToDo: Count number of loop_iteration_vars of residuum function */ + + switch (residual->output_vars_indices[i].type) { + case OMSI_TYPE_REAL: + index = residual->output_vars_indices[i].index; + residual->function_vars->reals[index] = x_data[i]; + break; + default: + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Evaluate: Could not copy data for residual evaluation." + "Data type was not a real."); + return omsi_error; + } + } + + /* Evaluate residum */ + residual->evaluate(residual, residual->function_vars, fval_data); + + return omsi_ok; +} + + +/** + * \brief Update initial guess for iterative solvers to last solution. + * + * \param [in,out] solver Solver initial guess should be updated for. + * \param [in] alg_system_data Containing solution of last time step. + * \return Return `0` on success and `-1` on failure. + */ +omsi_int omsi_update_guess (solver_data* solver, + omsi_algebraic_system_t* alg_system_data) { + + /* Variables */ + omsi_unsigned_int i, index, n_loop_iteration_vars; + omsi_real* initial_guess; + + /* Get pointer to initial_guess */ + initial_guess = solver_get_start_vector(solver); + + n_loop_iteration_vars = alg_system_data->jacobian->n_output_vars; + + for (i=0; ifunctions->output_vars_indices[i].type) { + case OMSI_TYPE_REAL: + index = alg_system_data->functions->output_vars_indices[i].index; + break; + default: + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "fmi2Evaluate: Could not copy data for initial guess." + "Data type was not a real."); + return -1; + } + initial_guess[i] = alg_system_data->functions->function_vars->reals[index]; + } + + solver_set_start_vector(solver, initial_guess); + + return 0; +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/base/src/omsi_utils.c b/SimulationRuntime/OMSI/base/src/omsi_utils.c new file mode 100644 index 00000000000..de167ecb126 --- /dev/null +++ b/SimulationRuntime/OMSI/base/src/omsi_utils.c @@ -0,0 +1,1009 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_utils.c + */ + +/** \addtogroup OMSIBase OMSI Base Library + * \ingroup OMSI + * \{ */ + +#include +#include + +#define DEBUG_FILTER_FLUSH omsi_true +#define DEBUG_FLUSH if (DEBUG_FILTER_FLUSH) fflush(stdout); + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + +#define OVERFLOW_PROTECTED omsi_false + + +/* + * ============================================================================ + * Section for logger functions + * ============================================================================ + */ +/** \brief Filter function for logger + * + * Logs message for given logging category if `logCategories[category]` is set to `true` for + * that category. Otherwise nothing is logged. + * + * \param [in] logCategories Array of categories, that should be logged. If + * pointer equals `NULL` function `filtered_base_logger` + * will ignore `category` and log message. + * \param [in] category Category of this log call. + * \param [in] status Status of OSU for logger. + * \param [in] message Message for logger. + * \param [in] ... Optional arguments in message. + */ +void filtered_base_logger(omsi_bool* logCategories, + log_categories category, + omsi_status status, + omsi_string message, + ...) +{ + /* Variables */ + va_list args; + +#if OVERFLOW_PROTECTED + omsi_int size; + omsi_char* buffer; +#else + omsi_char buffer[BUFSIZ]; +#endif + + va_start(args, message); + +#if OVERFLOW_PROTECTED + size = vsnprintf(NULL, 0, message, args); + buffer = (omsi_char*) global_callback->allocateMemory(size+1, sizeof(omsi_char)); +#endif + + vsprintf(buffer, message, args); + + if(isCategoryLogged(logCategories, category)) { + global_callback->logger(global_callback->componentEnvironment, + global_instance_name, + status, + log_categories_names[category], + buffer); + DEBUG_FLUSH + } + + /* free stuff */ +#if OVERFLOW_PROTECTED + global_callback->freeMemory(buffer); +#endif + va_end(args); + +} + + +/** + * \brief Wrapper for filtered_base_logger + * + * ... to give OMSISolver Library as logger function for linear algebraic systems. + * + * \param [in] log_level Log level of current message to filter logs. + * \param [in] message Message for logger. + * \param [in] ... Optional arguments in message. + */ +void wrapper_alg_system_logger (solver_log_level log_level, + omsi_string message, ...) { + + /* Variables */ + va_list args; + +#if OVERFLOW_PROTECTED + omsi_int size; + omsi_char* buffer; +#else + omsi_char buffer[BUFSIZ]; +#endif + + va_start(args, message); + +#if OVERFLOW_PROTECTED + size = vsnprintf(NULL, 0, message, args); + buffer = (omsi_char*) global_callback->allocateMemory(size+1, sizeof(omsi_char)); +#endif + + vsprintf(buffer, message, args); + + switch (log_level){ + case log_solver_error: + filtered_base_logger(global_logCategories, log_all, omsi_error, buffer); + break; + case log_solver_warning: + filtered_base_logger(global_logCategories, log_statuswarning, omsi_warning, buffer); + break; + case log_solver_nonlinear: + filtered_base_logger(global_logCategories, log_nonlinearsystems, omsi_ok, buffer); + break; + case log_solver_linear: + filtered_base_logger(global_logCategories, log_linearsystems, omsi_ok, buffer); + break; + case log_solver_all: + default: + filtered_base_logger(global_logCategories, log_all, omsi_ok, buffer); + } + + /* free stuff */ +#if OVERFLOW_PROTECTED + global_callback->freeMemory(buffer); +#endif + va_end(args); +} + + +/* + * Return true, if categoryIndex should be logged or OSU was not set. + */ +omsi_bool isCategoryLogged(omsi_bool* logCategories, + log_categories categoryIndex) { + + if (logCategories==NULL) { + return omsi_true; + } + + /* ToDo: Fix UNADRESSABLE ACCESS of freed memory error (reported with Dr. Memory on Windows */ + if (categoryIndex < NUMBER_OF_CATEGORIES && (logCategories[categoryIndex] || logCategories[log_all])) { + return omsi_true; + } + return omsi_false; +} + + +/* + * Return true if vr is out of range of end and emit error message. + * Otherwise return false. + */ +omsi_bool omsi_vr_out_of_range(omsi_t* omsu, + omsi_string function_name, + omsi_unsigned_int vr, + omsi_int end) { + + UNUSED(omsu); + + if ((omsi_int)vr >= end) { + filtered_base_logger(global_logCategories, log_statuserror, omsi_error, + "%s: Illegal value reference %u.", function_name, vr); + + return omsi_true; + } + return omsi_false; +} + + +/* + * Helper function to get negated alias for negative alias IDs. + */ +omsi_int omsi_get_negated_index (model_variable_info_t* model_var_info, + omsi_unsigned_int value_reference) +{ + if (model_var_info->isAlias) { + if (model_var_info->negate == -1) { + return -model_var_info->aliasID; + } else { + return model_var_info->aliasID; + } + } + + return value_reference; +} + +/* + * ============================================================================ + * Section for allocating and deallocating stuff + * ============================================================================ + */ + +/** + * \brief Frees memory for `omsi_t` struct and all its components. + * + * \param omsi_data [in,out] Pointer to OMSI data. + */ +void omsu_free_osu_data(omsi_t* omsi_data) { + + filtered_base_logger(global_logCategories, log_all, omsi_ok, + "fmi2FreeInstance: Free omsi data."); + + if (omsi_data==NULL) { + return; + } + + /* free memory for model data */ + omsu_free_model_data(omsi_data->model_data); + + /* free memory for simulation data */ + omsu_free_sim_data(omsi_data->sim_data); + + /* free memory for experiment data */ + if (omsi_data->experiment != NULL) { + global_callback->freeMemory((omsi_char *)omsi_data->experiment->solver_name); + global_callback->freeMemory(omsi_data->experiment); + } + + global_callback->freeMemory(omsi_data); + +} + + +/* + * Free memory for model_data_t structure and all its components. + */ +void omsu_free_model_data (model_data_t* model_data) { + + /* Variables */ + omsi_unsigned_int size; + + if (model_data==NULL) { + return; + } + + global_callback->freeMemory((omsi_char*) model_data->modelGUID); + + /* free model_variable_info_t */ + size = model_data->n_states + model_data->n_derivatives + + model_data->n_real_vars+model_data->n_real_parameters + + model_data->n_real_aliases + + model_data->n_int_vars + model_data->n_int_parameters + model_data->n_int_aliases + + model_data->n_bool_vars + model_data->n_bool_parameters + model_data->n_bool_aliases + + model_data->n_string_vars + model_data->n_string_parameters + model_data->n_string_aliases; + omsu_free_model_variable_info(model_data->model_vars_info, size); + + /* free equation_info */ + omsu_free_equation_info(model_data->equation_info, model_data->n_equations); + + global_callback->freeMemory (model_data); +} + + +/* + * Free array of model_variable_info struct. + */ +void omsu_free_model_variable_info(model_variable_info_t* model_vars_info, + omsi_unsigned_int size) { + + /* Variables */ + omsi_unsigned_int i; + + if (model_vars_info == NULL) { + return; + } + + for (i=0; ifreeMemory((omsi_char *)model_vars_info[i].name); + global_callback->freeMemory((omsi_char *)model_vars_info[i].comment); + + omsu_free_modelica_attributes(model_vars_info[i].modelica_attributes, model_vars_info[i].type_index.type); + global_callback->freeMemory((omsi_char *)model_vars_info[i].info.filename); + } + + global_callback->freeMemory (model_vars_info); +} + + +/* + * Free modelica_attributes of real variables. + */ +void omsu_free_modelica_attributes(void* modelica_attribute, + omsi_data_type type) { + + /* Variables */ + real_var_attribute_t* attribute_real; + + if (type==OMSI_TYPE_REAL) { + attribute_real = modelica_attribute; + + global_callback->freeMemory((omsi_char *)attribute_real->unit); + global_callback->freeMemory((omsi_char *)attribute_real->displayUnit); + global_callback->freeMemory (attribute_real); + } + else { + global_callback->freeMemory (modelica_attribute); + } +} + + +/* + * Free memory of array of equation_info_t structs. + */ +void omsu_free_equation_info(equation_info_t* eq_info, + omsi_unsigned_int n_equations ) { + + /* Variables */ + omsi_unsigned_int i; + omsi_int j; + + if (eq_info == NULL) { + return; + } + + for (i=0; ifreeMemory((omsi_char*) eq_info[i].variables[j]); + } + + global_callback->freeMemory(eq_info[i].variables); + } + + global_callback->freeMemory(eq_info); +} + + +/* + * Free memory for sim_data_t structure and all its components. + */ +void omsu_free_sim_data (sim_data_t* sim_data) { + + if (sim_data==NULL) { + return; + } + + omsi_free_model_variables(sim_data); + + omsu_free_omsi_function (sim_data->initialization, omsi_true); + omsu_free_omsi_function (sim_data->simulation, omsi_true); + + global_callback->freeMemory(sim_data->zerocrossings_vars); + global_callback->freeMemory(sim_data->pre_zerocrossings_vars); + global_callback->freeMemory(sim_data->sample_events); + + global_callback->freeMemory(sim_data); +} + + +/* + * Free memory for omsi_function struct and all its components. + */ +void omsu_free_omsi_function(omsi_function_t* omsi_function, + omsi_bool shared_vars) { + + /* Variables */ + omsi_unsigned_int i; + + if (omsi_function==NULL) { + return; + } + + if (!shared_vars) { + omsu_free_omsi_values(omsi_function->function_vars); + } + omsu_free_omsi_values(omsi_function->local_vars); + + /* Free algebraic systems */ + for(i=0; in_algebraic_system; i++) { + omsu_free_alg_system(&omsi_function->algebraic_system_t[i], shared_vars); + } + + global_callback->freeMemory(omsi_function->input_vars_indices); + global_callback->freeMemory(omsi_function->output_vars_indices); + + global_callback->freeMemory(omsi_function); +} + + +/* + * Deallocate memory of omsi_algebraic_system_t struct. + */ +void omsu_free_alg_system (omsi_algebraic_system_t* algebraic_system, + omsi_bool shared_vars) { + + global_callback->freeMemory(algebraic_system->zerocrossing_indices); + omsu_free_omsi_function(algebraic_system->jacobian, shared_vars); + omsu_free_omsi_function(algebraic_system->functions, shared_vars); + + /* Free solver data */ + solver_free(algebraic_system->solver_data); + + global_callback->freeMemory(algebraic_system); +} + + +/* + * Free memory for omsi_values struct and all its components +*/ +void omsu_free_omsi_values(omsi_values* values) { + + if (values==NULL) { + return; + } + + if (values->reals) { + alignedFree(values->reals); + } + if (values->ints) { + alignedFree(values->ints); + } + if (values->bools) { + alignedFree(values->bools); + } + if (values->strings) { + alignedFree(values->strings); + } + + if (values->externs) { + alignedFree(values->externs); + } + + global_callback->freeMemory(values); +} + + +/* + * ============================================================================ + * Section for print and debug functions + * ============================================================================ + */ + +/** + * \brief Print all data in omsi_t structure. + * + * Used for debugging. + * + * \param [in] omsi OMSI struct to print. + * \param [in] indent String with indentation in form of "| " strings or "" + */ +void omsu_print_omsi_t (omsi_t* omsi, + omsi_string indent) { + + /* compute next indentation */ + omsi_char* nextIndent; + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + /* print content of omsi_data */ + printf("%sstruct omsi_t:\n", indent); + + /* print model data */ + omsu_print_model_data (omsi->model_data, nextIndent); + printf("%s\n", indent); + + /* print sim_data */ + omsu_print_sim_data(omsi->sim_data, nextIndent); + printf("%s\n", indent); + + /* print experiment_data */ + omsu_print_experiment(omsi->experiment, nextIndent); + + /* free memory */ + global_callback->freeMemory(nextIndent); +} + + +/* + * Print all data in model_data_t structure. + * Indent is string with indentation in form of "| " strings or "". + */ +void omsu_print_model_data(model_data_t* model_data, + omsi_string indent) { + + /* compute next indentation */ + omsi_char* nextIndent; + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + /* print content */ + printf("%sstruct model_data_t:\n", indent); + printf("%s| modelGUID:\t\t\t%s\n", indent, model_data->modelGUID); + printf("%s| n_states:\t\t\t%d\n", indent, model_data->n_states); + printf("%s| n_derivatives:\t\t%d\n", indent, model_data->n_derivatives); + printf("%s| n_real_vars:\t\t%d\n", indent, model_data->n_real_vars); + printf("%s| n_int_vars:\t\t\t%d\n", indent, model_data->n_int_vars); + printf("%s| n_bool_vars:\t\t%d\n", indent, model_data->n_bool_vars); + printf("%s| n_string_vars:\t\t%d\n", indent, model_data->n_string_vars); + printf("%s| n_real_parameters:\t\t%d\n", indent, model_data->n_real_parameters); + printf("%s| n_int_parameters:\t\t%d\n", indent, model_data->n_int_parameters); + printf("%s| n_bool_parameters:\t\t%d\n", indent, model_data->n_bool_parameters); + printf("%s| n_string_parameters:\t%d\n", indent, model_data->n_string_parameters); + printf("%s| n_real_aliases:\t\t%d\n", indent, model_data->n_real_aliases); + printf("%s| n_int_aliases:\t\t%d\n", indent, model_data->n_int_aliases); + printf("%s| n_bool_aliases:\t\t%d\n", indent, model_data->n_bool_aliases); + printf("%s| n_string_aliases:\t\t%d\n", indent, model_data->n_string_aliases); + printf("%s| n_zerocrossings:\t\t%d\n", indent, model_data->n_zerocrossings); + printf("%s| n_regular_equations:\t%d\n", indent, model_data->n_regular_equations); + printf("%s| n_init_equations:\t\t%d\n", indent, model_data->n_init_equations); + printf("%s| n_alias_equations:\t\t%d\n", indent, model_data->n_alias_equations); + printf("%s| n_equations:\t\t%d\n", indent, model_data->n_equations); + + /* print model_vars_info */ + omsu_print_model_variable_info(model_data, nextIndent); + + /* print equation_info */ + omsu_print_equation_info(model_data, nextIndent); + + /* free memory */ + global_callback->freeMemory(nextIndent); +} + + +/* + * Prints all model variables informations of array model_data->model_vars_info. + * Indent is string with indentation in form of "| " strings or "". + * Returns with omsi_warning if model_data is NULL pointer. + */ +omsi_status omsu_print_model_variable_info(model_data_t* model_data, + omsi_string indent) { + + /* variables */ + omsi_unsigned_int i, size; + omsi_char* nextnextIndent; + + printf("%smodel_vars_info:\n", indent); + + if (model_data==NULL) { + printf("%s| No model_data\n", indent); + return omsi_error; + } + + if (model_data->model_vars_info==NULL) { + printf("%s| No model_vars_info\n", indent); + return omsi_warning; + } + + /* compute next indentation */ + nextnextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+4, sizeof(omsi_char)); + strcat(nextnextIndent, "| | "); + + /* print variables */ + size = model_data->n_states + model_data->n_derivatives + + model_data->n_real_vars + model_data->n_real_parameters + + model_data->n_real_aliases + + model_data->n_int_vars + model_data->n_int_parameters + + model_data->n_int_aliases + + model_data->n_bool_vars + model_data->n_bool_parameters + + model_data->n_bool_aliases + + model_data->n_string_vars + model_data->n_string_parameters + + model_data->n_string_aliases; + + for (i=0; imodel_vars_info[i].id); + printf("%s| name:\t\t\t%s\n", indent, model_data->model_vars_info[i].name); + printf("%s| comment:\t\t\t%s\n", indent, model_data->model_vars_info[i].comment); + printf("%s| variable type:\t\t%s\n", indent, omsiDataTypesNames[model_data->model_vars_info[i].type_index.type]); + printf("%s| variable index:\t\t%i\n", indent, model_data->model_vars_info[i].type_index.index); + + omsu_print_modelica_attributes(model_data->model_vars_info[i].modelica_attributes, &model_data->model_vars_info[i].type_index, nextnextIndent); + + printf("%s| alias:\t\t\t%s\n", indent, model_data->model_vars_info[i].isAlias ? "true" : "false"); + printf("%s| negate:\t\t\t%i\n", indent, model_data->model_vars_info[i].negate); + printf("%s| aliasID:\t\t\t%i\n", indent, model_data->model_vars_info[i].aliasID); + + printf("%s| file info:\n", indent); + printf("| | %sfilename:\t\t\t%s\n", indent, model_data->model_vars_info[i].info.filename); + printf("| | %slineStart:\t\t%i\n", indent, model_data->model_vars_info[i].info.lineStart); + printf("| | %scolStart:\t\t\t%i\n", indent, model_data->model_vars_info[i].info.colStart); + printf("| | %slineEnd:\t\t\t%i\n", indent, model_data->model_vars_info[i].info.lineEnd); + printf("| | %scolEnd:\t\t\t%i\n", indent, model_data->model_vars_info[i].info.colEnd); + printf("| | %sfileWritable:\t\t%s\n", indent, model_data->model_vars_info[i].info.fileWritable ? "true" : "false"); + printf("| %s\n", indent); + } + + /* free memory */ + global_callback->freeMemory(nextnextIndent); + return omsi_ok; +} + + +/* + * Print modelica attribute. + * Type_index determines the data type of the modelica attribute (real|int|bool|string). + * Indent is string with indentation in form of "| " strings or "". + * Returns with omsi_error if data type is not one of real, int, bool or string. + */ +omsi_status omsu_print_modelica_attributes (void* modelica_attribute, + omsi_index_type* type_index, + omsi_string indent) { + + /* variables */ + real_var_attribute_t* attribute_real; + int_var_attribute_t* attribute_integer; + bool_var_attribute_t* attribute_bool; + string_var_attribute_t* attribute_string; + omsi_char* nextIndent; + + /* compute next indentation */ + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + printf("%sattribute:\n", indent); + + switch (type_index->type) { + case OMSI_TYPE_REAL: + attribute_real = modelica_attribute; + omsu_print_real_var_attribute(attribute_real, nextIndent); + break; + case OMSI_TYPE_INTEGER: + attribute_integer = modelica_attribute; + omsu_printf_int_var_attribute(attribute_integer, nextIndent); + break; + case OMSI_TYPE_BOOLEAN: + attribute_bool = modelica_attribute; + printf("| %sfixed:\t\t\t%s\n", indent, attribute_bool->fixed ? "true" : "false"); + printf("| %sstart:\t\t\t%s\n", indent, attribute_bool->start ? "true" : "false"); + break; + case OMSI_TYPE_STRING: + attribute_string = modelica_attribute; + printf("| %sstart:\t\t\t%s\n", indent, attribute_string->start); + break; + default: + /* free memory */ + global_callback->freeMemory(nextIndent); + return omsi_error; + } + + /* free memory */ + global_callback->freeMemory(nextIndent); + return omsi_ok; +} + + +/* + * Print modelica attributes of real variable. + * Indent is string with indentation in form of "| " strings or "". + */ +void omsu_print_real_var_attribute (real_var_attribute_t* real_var_attribute, + omsi_string indent) { + + printf("%sunit:\t\t\t\t%s\n", indent, real_var_attribute->unit); + printf("%sdisplayUnit:\t\t%s\n", indent, real_var_attribute->displayUnit); + if (real_var_attribute->min <= -OMSI_DBL_MAX) { + printf("%smin:\t\t\t\t-infinity\n", indent); + } + else { + printf("%smin:\t\t\t\t%f\n", indent, real_var_attribute->min); + } + if (real_var_attribute->max >= OMSI_DBL_MAX) { + printf("%smax:\t\t\t\tinfinity\n", indent); + } + else { + printf("%smax:\t\t\t\t%f\n", indent, real_var_attribute->max); + } + printf("%sfixed:\t\t\t%s\n", indent, real_var_attribute->fixed ? "true" : "false"); + printf("%snominal:\t\t\t%f\n", indent, real_var_attribute->nominal); + printf("%sstart:\t\t\t%f\n", indent, real_var_attribute->start); +} + + +/* + * Print modelica attributes of integer variable. + * Indent is string with indentation in form of "| " strings or "". + */ +void omsu_printf_int_var_attribute(int_var_attribute_t* int_var_attribute, + omsi_string indent) { + + if (int_var_attribute->min <= -OMSI_INT_MAX) { + printf("%smin:\t\t\t-infinity\n", indent); + } + else { + printf("%smin:\t\t\t%i\n", indent, int_var_attribute->min); + } + if (int_var_attribute->max >= OMSI_INT_MAX) { + printf("%smax:\t\t\tininity\n", indent); + } + else { + printf("%smax:\t\t\t%i\n", indent, int_var_attribute->max); + } + printf("%sfixed:\t\t\t%s\n", indent, int_var_attribute->fixed ? "true" : "false"); + printf("%sstart:\t\t\t%i\n", indent, int_var_attribute->start); +} + + +/* + * Print all equation informations of model_data->equation_info. + * Indent is string with indentation in form of "| " strings or "". + * Return with omsi_warning if equation_info is NULL pointer. + */ +omsi_status omsu_print_equation_info(model_data_t* model_data, + omsi_string indent) { + + /* Variables */ + omsi_unsigned_int i; + omsi_int j; + + if (model_data==NULL) { + return omsi_error; + } + + printf("%sequation_info:\n", indent); + + if (model_data->equation_info==NULL) { + printf("%s| No data\n", indent); + return omsi_warning; + } + + for(i=0; in_equations; i++) { + printf("%s| id:\t\t\t\t%i\n", indent, model_data->equation_info[i].id); + printf("%s| ProfileBlockIndex:\t\t%i\n", indent, model_data->equation_info[i].profileBlockIndex); + printf("%s| parent: \t\t\t%i\n", indent, model_data->equation_info[i].parent); + printf("%s| numVar:\t\t\t%i\n", indent, model_data->equation_info[i].numVar); + printf("%s| variables:\t\t\t", indent); + for (j=0; jequation_info[i].numVar; j++) { + printf("%s ", model_data->equation_info[i].variables[j]); + } + printf("\n"); + printf("%s| file info:\n", indent); + printf("%s| | filename:\t\t\t%s\n", indent, model_data->equation_info[i].info.filename); + printf("%s| | lineStart:\t\t%i\n", indent, model_data->equation_info[i].info.lineStart); + printf("%s| | colStart:\t\t\t%i\n", indent, model_data->equation_info[i].info.colStart); + printf("%s| | lineEnd:\t\t\t%i\n", indent, model_data->equation_info[i].info.lineEnd); + printf("%s| | colEnd:\t\t\t%i\n", indent, model_data->equation_info[i].info.colEnd); + printf("%s| | fileWritable:\t\t%s\n", indent, model_data->equation_info[i].info.fileWritable ? "true" : "false"); + printf("%s\n", indent); + } + + return omsi_ok; +} + + +/* + * Print all data in omsi_experiment_t structure. + * Indent is string with indentation in form of "| " strings or "". + */ +void omsu_print_experiment (omsi_experiment_t* experiment, + omsi_string indent) { + + printf("%sstruct omsi_experiment_t:\n", indent); + printf("%s| start_time:\t\t\t%f\n", indent, experiment->start_time); + printf("%s| stop_time:\t\t\t%f\n", indent, experiment->stop_time); + printf("%s| step_size:\t\t\t%f\n", indent, experiment->step_size); + printf("%s| num_outputss:\t\t%u\n", indent, experiment->num_outputs); + printf("%s| tolerance:\t\t\t%1.e\n", indent, experiment->tolerance); + printf("%s| solver_name:\t\t%s\n", indent, experiment->solver_name); +} + + +/* + * Print all data in sim_data_t structure. + * Indent is string with indentation in form of "| " strings or "". + */ +omsi_status omsu_print_sim_data (sim_data_t* sim_data, + omsi_string indent) { + + omsi_char* nextIndent; + + if (sim_data==NULL) { + printf("%sNo sim_data\n",indent); + return omsi_warning; + } + + /* compute next indentation */ + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + printf("%sstruct sim_data:\n", indent); + + omsu_print_omsi_function_rec (sim_data->initialization, "initialization", nextIndent); + omsu_print_omsi_function_rec (sim_data->simulation, "simulation", nextIndent); + + omsu_print_omsi_values(sim_data->model_vars_and_params, "model_vars_and_params", nextIndent); + omsu_print_omsi_values(sim_data->pre_vars, "pre_vars", nextIndent); + + /* ToDo: print rest of sim_data */ + + /* free memory */ + global_callback->freeMemory(nextIndent); + return omsi_ok; +} + + +/* + * Print all data in omsi_function_t structure and its containing structures. + * Indent is string with indentation in form of "| " strings or "". + */ +omsi_status omsu_print_omsi_function_rec (omsi_function_t* omsi_function, + omsi_string omsi_function_name, + omsi_string indent) { + + /* Variables */ + omsi_unsigned_int i; + omsi_char* nextIndent; + + if (omsi_function==NULL) { + printf("%sNo omsi_function_t %s\n",indent, omsi_function_name); + return omsi_warning; + } + else { + printf("%somsi_function_t %s\n",indent, omsi_function_name); + } + + /* compute next indentation */ + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + printf("%sn_algebraic_system:\t\t%u\n", indent, omsi_function->n_algebraic_system); + for (i=0; in_algebraic_system; i++) { + omsu_print_algebraic_system(&omsi_function->algebraic_system_t[i], nextIndent); + } + omsu_print_this_omsi_function (omsi_function, omsi_function_name, indent); + + /* free memory */ + global_callback->freeMemory(nextIndent); + return omsi_ok; +} + + +/* + * Print all data in this omsi_function_t structure except algebraic systems. + * Indent is string with indentation in form of "| " strings or "". + */ +omsi_status omsu_print_this_omsi_function (omsi_function_t* omsi_function, + omsi_string omsi_function_name, + omsi_string indent) { + + /* Variables */ + omsi_char* nextIndent; + + if (omsi_function==NULL) { + printf("%sNo omsi_function_t %s\n",indent, omsi_function_name); + return omsi_warning; + } + + /* compute next indentation */ + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + omsu_print_omsi_values(omsi_function->function_vars, "function_vars", indent); + + printf("%sevaluate function pointer set: %s\n", indent, omsi_function->evaluate!=NULL? "true" : "false"); + + omsu_print_index_type(omsi_function->input_vars_indices, omsi_function->n_input_vars, nextIndent); + omsu_print_index_type(omsi_function->input_vars_indices, omsi_function->n_output_vars, nextIndent); + + printf("%sn_input_vars:\t\t\t%i\n", indent, omsi_function->n_input_vars); + printf("%sn_inner_vars:\t\t\t%i\n", indent, omsi_function->n_inner_vars); + printf("%sn_output_vars:\t\t%i\n", indent, omsi_function->n_output_vars); + + /* free memory */ + global_callback->freeMemory(nextIndent); + return omsi_ok; +} + + +/* + * Print all values of omsi_values. + */ +omsi_status omsu_print_omsi_values (omsi_values* omsi_values, + omsi_string omsi_values_name, + omsi_string indent) { + + omsi_unsigned_int i; + + if (omsi_values==NULL) { + printf("%sNo omsi_values %s\n",indent, omsi_values_name); + return omsi_warning; + } + + printf("%somsi_values %s\n",indent, omsi_values_name); + printf("%sreals:\n", indent); + for(i=0; in_reals; i++) { + printf("%s| \t\t\t\t%f\n", indent, omsi_values->reals[i]); + } + + printf("%sints:\n", indent); + for(i=0; in_ints; i++) { + printf("%s| \t\t\t\t%i\n", indent, omsi_values->ints[i]); + } + + printf("%sbools:\n", indent); + for(i=0; in_bools; i++) { + printf("%s| \t\t\t\t%s\n", indent, omsi_values->bools[i] ? "true" : "false"); + } + + /* omsu_print_externs(omsi_values->externs, omsi_values->n_externs); */ + + printf("%stime_value: \t\t\t%f\n", indent, omsi_values->time_value); + + return omsi_ok; +} + + +/* + * Print all informations of algebraic_system_t structure. + */ +omsi_status omsu_print_algebraic_system(omsi_algebraic_system_t* algebraic_system_t, + omsi_string indent) { + + omsi_unsigned_int i; + omsi_char* nextIndent; + + /* compute next indentation */ + nextIndent = (omsi_char*) global_callback->allocateMemory(strlen(indent)+2, sizeof(omsi_char)); + strcat(nextIndent, "| "); + + printf("%sn_iteration_vars %u\n", indent, algebraic_system_t->n_iteration_vars); + printf("%sn_conditions %u\n", indent, algebraic_system_t->n_conditions); + + printf("%szerocrossing indices; ", indent); + for (i=0; in_conditions; i++) { + printf("%s| %i",indent, algebraic_system_t->zerocrossing_indices[i]); + } + printf("\n"); + + printf("%sis linear: %s", indent, algebraic_system_t->isLinear ? "true" : "false"); + + omsu_print_this_omsi_function(algebraic_system_t->jacobian, "jacobian", nextIndent); + omsu_print_this_omsi_function(algebraic_system_t->functions, "residual functions", nextIndent); + + omsu_print_solver_data("lapack_solver", algebraic_system_t->solver_data, nextIndent); + + /* free memory */ + global_callback->freeMemory(nextIndent); + + return omsi_ok; +} + + +/* + * Print solver data. + * TODO Not working at the moment. + */ +omsi_status omsu_print_solver_data(omsi_string solver_name, + void* solver_data, + omsi_string indent) { + + /* TODO */ + UNUSED(solver_data); UNUSED(indent); + + if (strcmp("lapack_solver", solver_name)==0) { + /* printLapackData(solver_data, indent); ToDo Uncomment*/ + } + else { + printf("WARING in function omsu_print_solver_data: type of solver_data unknown\n"); + return omsi_warning; + } + + return omsi_ok; +} + + +/* ToDo: finish function */ +omsi_status omsu_print_index_type (omsi_index_type* vars_indices, + omsi_unsigned_int size, + omsi_string indent) { + + UNUSED(vars_indices); UNUSED(size); UNUSED(indent); + return omsi_ok; +} + + +/* ToDo: finish function */ +omsi_status omsu_print_externs(void* externs, + omsi_unsigned_int n_externs) { + + UNUSED(externs); UNUSED(n_externs); + + printf("ERROR: omsu_print_externs not implemented yet\n"); + return omsi_error; +} + +/** \} */ diff --git a/SimulationRuntime/OMSI/cmake_uninstall.cmake.in b/SimulationRuntime/OMSI/cmake_uninstall.cmake.in new file mode 100644 index 00000000000..96e0d95a909 --- /dev/null +++ b/SimulationRuntime/OMSI/cmake_uninstall.cmake.in @@ -0,0 +1,19 @@ +if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") +endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_cs.h b/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_cs.h new file mode 100644 index 00000000000..49e4ecdd288 --- /dev/null +++ b/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_cs.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif \ No newline at end of file diff --git a/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_me.h b/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_me.h new file mode 100644 index 00000000000..9b43bb4ff71 --- /dev/null +++ b/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_me.h @@ -0,0 +1,194 @@ +#ifndef OIS_FMI2_ME_H +#define OIS_FMI2_ME_H +#include "fmi2Functions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct fmi2_me_t +{ + //OSI data structur + omsi_t osi; + //Model exchange or co simulation fmu + fmi2Type fmu_type; + //Name of fmu + fmi2String fmu_instance_name; + //GUID of fmu + fmi2String fmu_GUID; + + const fmi2CallbackFunctions* fmi_functions; + + +}; + + + +fmi2Status omsi_fmi2_set_debug_logging(fmi2Component c,fmi2Boolean loggingOn,size_t nCategories,const fmi2String categories[]); + + + + +//fmi2Instantiate +fmi2Component omsi_fmi2_instantiate(fmi2String instanceName, + fmi2Type fmuType, + fmi2String fmuGUID, + fmi2String fmuResourceLocation, + const fmi2CallbackFunctions* functions, + fmi2Boolean visible, + fmi2Boolean loggingOn); + +//fmi2FreeInstance +void omsi_fmi2_free_instance(fmi2Component c); + +//fmi2SetupExperiment +fmi2Status omsi_fmi2_setup_experiment(fmi2Component c, + fmi2Boolean toleranceDefined, + fmi2Real tolerance, + fmi2Real startTime, + fmi2Boolean stopTimeDefined, + fmi2Real stopTime); + +//fmi2EnterInitializationMode +fmi2Status omsi_fmi2_enter_initialization_mode(fmi2Component c); + +//fmi2ExitInitializationMode +fmi2Status omsi_fmi2_exit_initialization_mode(fmi2Component c); + +//fmi2Terminate +fmi2Status omsi_fmi2_terminate(fmi2Component c); + +//fmi2Reset +fmi2Status omsi_fmi2_reset(fmi2Component c); + +//fmi2GetReal +fmi2Status omsi_fmi2_get_real(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, fmi2Real value[]); + +//fmi2GetInteger +fmi2Status omsi_fmi2_get_integer(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, fmi2Integer value[]); + +//fmi2GetBoolean +fmi2Status omsi_fmi2_get_boolean(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, fmi2Boolean value[]); + +//fmi2GetString +fmi2Status omsi_fmi2_get_string(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, fmi2String value[]); + +//fmi2SetReal +fmi2Status omsi_fmi2_set_real(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, const fmi2Real value[]); + +//fmi2SetInteger +fmi2Status omsi_fmi2_set_integer(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, const fmi2Integer value[]); + +//fmi2SetBoolean +fmi2Status omsi_fmi2_set_boolean(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, const fmi2Boolean value[]); + +//fmi2SetString +fmi2Status omsi_fmi2_set_string(fmi2Component c, const fmi2ValueReference vr[], + size_t nvr, const fmi2String value[]); + + +//fmi2GetFMUstate +fmi2Status omsi_fmi2_get_fmu_state(fmi2Component c, fmi2FMUstate* FMUstate); + +//fmi2SetFMUstate +fmi2Status omsi_fmi2_set_fmu_state(fmi2Component c, fmi2FMUstate FMUstate); + +//fmi2FreeFMUstate +fmi2Status omsi_fmi2_free_fmu_state(fmi2Component c, fmi2FMUstate* FMUstate); + +//fmi2SerializedFMUstateSize +fmi2Status omsi_fmi2_serialized_fmu_state_size(fmi2Component c, fmi2FMUstate FMUstate, + size_t* size); + +//fmi2SerializeFMUstate +fmi2Status omsi_fmi2_serialize_fmu_state(fmi2Component c, fmi2FMUstate FMUstate, + fmi2Byte serializedState[], size_t size); + +//fmi2DeSerializeFMUstate +fmi2Status omsi_fmi2_de_serialize_fmu_state(fmi2Component c, + const fmi2Byte serializedState[], + size_t size, fmi2FMUstate* FMUstate); + +//fmi2GetDirectionalDerivative +fmi2Status omsi_fmi2_get_directional_derivative(fmi2Component c, + const fmi2ValueReference vUnknown_ref[], size_t nUnknown, + const fmi2ValueReference vKnown_ref[], size_t nKnown, + const fmi2Real dvKnown[], fmi2Real dvUnknown[]); + +//fmi2EnterEventMode +fmi2Status omsi_fmi2_enter_event_mode(fmi2Component c); + +//fmi2NewDiscreteStates +fmi2Status omsi_fmi2_new_discrete_state(fmi2Component c, + fmi2EventInfo* fmiEventInfo); +//fmi2EnterContinuousTimeMode +fmi2Status omsi_fmi2_enter_continuous_time_mode(fmi2Component c); + +//fmi2CompletedIntegratorStep +fmi2Status omsi_fmi2_completed_integrator_step(fmi2Component c, + fmi2Boolean noSetFMUStatePriorToCurrentPoint, + fmi2Boolean* enterEventMode, + fmi2Boolean* terminateSimulation); + + fmi2Status fmi2_get_fmu_state(fmi2Component c, fmi2FMUstate* FMUstate); + +fmi2Status omsi_fmi2_get_fmu_state(fmi2Component c, fmi2FMUstate* FMUstate); +fmi2Status omsi_fmi2_set_fmu_state(fmi2Component c, fmi2FMUstate FMUstate); +fmi2Status omsi_fmi2_free_fmu_state(fmi2Component c, fmi2FMUstate* FMUstate); +fmi2Status omsi_fmi2_serialized_fmu_state_size(fmi2Component c, fmi2FMUstate FMUstate,size_t* size); +fmi2Status omsi_fmi2_serialize_fmu_state(fmi2Component c, fmi2FMUstate FMUstate,fmi2Byte serializedState[], size_t size); + + +//fmi2SetTime +fmi2Status omsi_fmi2_set_time(fmi2Component c, fmi2Real time); + +//fmi2SetContinuousStates +fmi2Status omsi_fmi2_set_continuous_states(fmi2Component c, const fmi2Real x[], + size_t nx); + +//fmi2GetDerivatives +fmi2Status omsi_fmi2_get_derivatives(fmi2Component c, fmi2Real derivatives[], size_t nx); + +//fmi2GetEventIndicators +fmi2Status omsi_fmi2_get_event_indicators(fmi2Component c, + fmi2Real eventIndicators[], size_t ni); +//fmi2GetContinuousStates +fmi2Status omsi_fmi2_get_continuous_states(fmi2Component c, fmi2Real x[], size_t nx); + +//fmi2GetNominalsOfContinuousStates +fmi2Status omsi_fmi2_get_nominals_of_continuous_states(fmi2Component c, + fmi2Real x_nominal[], + size_t nx); + + +fmi2Component omsi_fmi2_me_instantiate( + fmi2String instanceName, + fmi2Type fmuType, + fmi2String fmuGUID, + fmi2String fmuResourceLocation, + const fmi2CallbackFunctions* functions, + fmi2Boolean visible, + fmi2Boolean loggingOn); + + +void omsi_fmi2_me_free_instance(fmi2Component c); + + +fmi2Status omsi_fmi2_get_clock(fmi2Component c,const fmi2Integer clockIndex[],size_t nClockIndex, fmi2Boolean tick[]); +fmi2Status omsi_fmi2_get_interval(fmi2Component c, const fmi2Integer clockIndex[],size_t nClockIndex, fmi2Real interval[]); +fmi2Status omsi_fmi2_set_clock(fmi2Component c, const fmi2Integer clockIndex[], size_t nClockIndex, const fmi2Boolean tick[],const fmi2Boolean subactive[]); +fmi2Status omsi_fmi2_set_interval(fmi2Component c,const fmi2Integer clockIndex[],size_t nClockIndex, const fmi2Real interval[]); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_wrapper.h b/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_wrapper.h new file mode 100644 index 00000000000..a1c472362a1 --- /dev/null +++ b/SimulationRuntime/OMSI/include/fmi2/omsi_fmi2_wrapper.h @@ -0,0 +1,89 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/* + * ToDo: insert description + */ + + +#ifndef OSI_FMI2_WRAPPER_H +#define OSI_FMI2_WRAPPER_H + +/* FMI2 interface */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function prototypes */ +FMI2_Export const char* fmi2GetTypesPlatform(void); +FMI2_Export const char* fmi2GetVersion(void); +FMI2_Export fmi2Status fmi2SetDebugLogging(fmi2Component c,fmi2Boolean loggingOn,size_t nCategories,const fmi2String categories[]); +FMI2_Export fmi2Component fmi2Instantiate(fmi2String instanceName,fmi2Type fmuType,fmi2String fmuGUID,fmi2String fmuResourceLocation,const fmi2CallbackFunctions* functions, fmi2Boolean visible,fmi2Boolean loggingOn); +FMI2_Export void fmi2FreeInstance(fmi2Component c); +FMI2_Export fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined,fmi2Real tolerance, fmi2Real tartTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime); +FMI2_Export fmi2Status fmi2EnterInitializationMode(fmi2Component c); +FMI2_Export fmi2Status fmi2ExitInitializationMode(fmi2Component c); +FMI2_Export fmi2Status fmi2Terminate(fmi2Component c); +FMI2_Export fmi2Status fmi2Reset(fmi2Component c); +FMI2_Export fmi2Status fmi2GetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]); +FMI2_Export fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[],size_t nvr, fmi2Integer value[]); +FMI2_Export fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[],size_t nvr, fmi2Boolean value[]); +FMI2_Export fmi2Status fmi2GetString(fmi2Component c, const fmi2ValueReference vr[],size_t nvr, fmi2String value[]); +FMI2_Export fmi2Status fmi2SetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]); +FMI2_Export fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[],size_t nvr, const fmi2Integer value[]); +FMI2_Export fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[],size_t nvr, const fmi2Boolean value[]); +FMI2_Export fmi2Status fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]); +FMI2_Export fmi2Status fmi2GetFMUstate(fmi2Component c, fmi2FMUstate* FMUstate); +FMI2_Export fmi2Status fmi2SetFMUstate(fmi2Component c, fmi2FMUstate FMUstate); +FMI2_Export fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate* FMUstate); +FMI2_Export fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate FMUstate,size_t* size); +FMI2_Export fmi2Status fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate FMUstate,fmi2Byte serializedState[], size_t size); +FMI2_Export fmi2Status fmi2DeSerializeFMUstate(fmi2Component c, const fmi2Byte serializedState[],size_t size, fmi2FMUstate* FMUstate); +FMI2_Export fmi2Status fmi2GetDirectionalDerivative(fmi2Component c,const fmi2ValueReference vUnknown_ref[], size_t nUnknown,const fmi2ValueReference vKnown_ref[], size_t nKnown, const fmi2Real dvKnown[], fmi2Real dvUnknown[]); +FMI2_Export fmi2Status fmi2EnterEventMode(fmi2Component c); +FMI2_Export fmi2Status fmi2NewDiscreteStates(fmi2Component c, fmi2EventInfo* fmiEventInfo); +FMI2_Export fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c); +FMI2_Export fmi2Status fmi2CompletedIntegratorStep(fmi2Component c,fmi2Boolean noSetFMUStatePriorToCurrentPoint, fmi2Boolean* enterEventMode, fmi2Boolean* terminateSimulation); +FMI2_Export fmi2Status fmi2SetTime(fmi2Component c, fmi2Real time); +FMI2_Export fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[],size_t nx); +FMI2_Export fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx); +FMI2_Export fmi2Status fmi2GetEventIndicators(fmi2Component c, fmi2Real eventIndicators[], size_t ni); +FMI2_Export fmi2Status fmi2GetContinuousStates(fmi2Component c, fmi2Real x[],size_t nx); +FMI2_Export fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c,fmi2Real x_nominal[],size_t nx); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/include/omsi.h b/SimulationRuntime/OMSI/include/omsi.h new file mode 100644 index 00000000000..234b3c4704b --- /dev/null +++ b/SimulationRuntime/OMSI/include/omsi.h @@ -0,0 +1,622 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi.h + */ + +/** \defgroup OMSI OpenModelica Simulation Interface + * + * Long description of OMSI group. + */ + + + +/** \addtogroup OMSIBase OMSI Base Library + * \ingroup OMSI + * + * \brief Base functionalities used by OMSIC and OMSICpp runtimes. + * + * Basic data types for representing OMSI structure and functions to operate + * on OMSU data. Mostly memory management functions, functions to call OMSI + * Solver Library for solving algebraic systems and operate directly on + * simulation data. + * \{ */ + + + +#ifndef _OMSI_H +#define _OMSI_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * type definitions of variables + */ +#ifdef OSI_FMI2_WRAPPER_H +#include /* ToDo: delete, is duplicate but silences warnings in my eclipse :-P */ + +typedef fmi2ValueReference omsi_unsigned_int; +typedef fmi2Real omsi_real; +typedef fmi2Integer omsi_int; +typedef fmi2Integer omsi_long; +typedef fmi2Boolean omsi_bool; +#define omsi_true fmi2True +#define omsi_false fmi2False +#ifndef true +#define true fmi2True +#endif +#ifndef false +#define false fmi2False +#endif +typedef fmi2Char omsi_char; +typedef fmi2String omsi_string; +#else +typedef unsigned int omsi_unsigned_int; /**< OMSI unsigned integer data type. Defaults to `unsigned int`. */ +typedef double omsi_real; /**< OMSI real data type. Defaults to `double`. */ +typedef int omsi_int; /**< OMSI integer data type. Defaults to `int`. */ +typedef long omsi_long; /**< OMSI long integer data type. Defaults to `long`. */ +typedef int omsi_bool; /**< OMSI boolean data type. Defaults to `int`. */ +#define omsi_true 1 /**< Boolean true. */ +#define omsi_false 0 /**< Boolean false. */ +typedef char omsi_char; /**< OMSI char data type. Defaults to `char`. */ +typedef const omsi_char* omsi_string; /**< OMSI string data type. Defaults to `const omsi_char*`. */ +#endif + +#define OMSI_TYPES_DEFINED + + +/* Typedef modelica types, so we don't need to change so much in CodegenCFunctions.tpl */ +/* ToDo: Change */ +#ifndef MODELICATYPES_TYPEDEF +#define MODELICATYPES_TYPEDEF +typedef omsi_real modelica_real; +typedef omsi_int modelica_integer; +#endif + + +/* macros */ +#define OMSI_DBL_MAX DBL_MAX +#define OMSI_INT_MAX INT_MAX + +/* used for filtered_log */ +#define NUMBER_OF_CATEGORIES 12 +typedef enum { + log_events, + log_singulalinearsystems, + log_nonlinearsystems, + log_linearsystems, + log_dynamicstateselection, + log_statuswarning, + log_statusdiscard, + log_statuserror, + log_statusfatal, + log_statuspending, + log_all, + log_fmi2_call +} log_categories; + + +static const omsi_string log_categories_names[NUMBER_OF_CATEGORIES] = { + "logEvents", + "logSingularLinearSystems", + "logNonlinearSystems", + "logLinearSystems", + "logDynamicStateSelection", + "logStatusWarning", + "logStatusDiscard", + "logStatusError", + "logStatusFatal", + "logStatusPending", + "logAll", + "logFmi2Call" +}; + + +/* Model FMU/ OSU states */ +typedef enum { + modelInstantiated = 1<<0, /* ME and CS */ + modelInitializationMode = 1<<1, /* ME and CS */ + modelContinuousTimeMode = 1<<2, /* ME only */ + modelEventMode = 1<<3, /* ME only */ + modelSlaveInitialized = 1<<4, /* CS only */ + modelTerminated = 1<<5, /* ME and CS */ + modelError = 1<<6 /* ME and CS */ +} ModelState; + +/* Event informations */ +typedef struct { + omsi_bool newDiscreteStatesNeeded; + omsi_bool terminateSimulation; + omsi_bool nominalsOfContinuousStatesChanged; + omsi_bool valuesOfContinuousStatesChanged; + omsi_bool nextEventTimeDefined; + omsi_real nextEventTime; +} omsi_event_info; + + +/* forward some structs */ +struct omsi_function_t; + + +/** + * Variable basic data types + */ +typedef enum { + OMSI_TYPE_UNKNOWN,/**< Unknown type*/ + OMSI_TYPE_REAL, /**< Real type */ + OMSI_TYPE_INTEGER,/**< Integer type */ + OMSI_TYPE_BOOLEAN,/**< Boolean type */ + OMSI_TYPE_STRING /**< String type */ +}omsi_data_type; + +static const omsi_string omsiDataTypesNames[] = { + "Unknown", + "Real", + "Integer", + "Boolean", + "String"}; + + +/** + * OMSU or FMU type. + */ +typedef enum { + omsi_model_exchange, /**< Model Exchange */ + omsi_co_simulation /* not supported yet */ /**< Co-Simulation (not supported yet) */ +}omsu_type; + + +/** + * OpenModelic Simulation Unit (OMSU) solving mode + */ +typedef enum { + omsi_instantiated_mode, /**< Is instantiated */ + omsi_initialization_mode,/**< Is initialized */ + omsi_continuousTime_mode,/**< Is in continuous-time mode */ + omsi_event_mode, /**< Is in event mode */ + omsi_none_mode /**< Is in no mode */ +} omsi_solving_mode_t; + + +/** + * Status for an OpenModelica Simulation Unit (OMSU) + */ +typedef enum { + omsi_ok, /**< Okay */ + omsi_warning,/**< Warning */ + omsi_discard,/**< Discard */ + omsi_error, /**< Error */ + omsi_fatal, /**< Fatal */ + omsi_pending /**< Pending */ +}omsi_status; + + +/** + * Enumeration that defines the causality of the variable. + */ +typedef enum { + parameter, /**< Independent parameter. */ + calculatedParameter, /**< A data value that is constant during the + * simulation and is computed during initialization + * or when tunable parameters change. */ + input, /**< The variable value can be provided from another + * model or slave. */ + output, /**< The variable value can be used by another model + * or slave. */ + local, /**< Local variable that is calculated from other + * variables or is a continuous time sate. */ + independent /**< The independent variable (usually `time`). */ +}omsi_causality; + +/** + * Enumeration that defines the time dependency of the variable, in other words + * it defines the time instants when a variable can change its value. + */ +typedef enum { + constant, /**< The value of the variable never changes. */ + fixed, /**< The value of the variable is fixed after initialization. */ + tunable, /**< The value of the variable is constant between external + * events (ModelExchange) and between Communication Points + * (CoSimulation). */ + discrete, /**< ModelExchange: The value of the variable is constant + * between external and internal events.
+ * CoSimulation: By convention, the variable is from a "real" + * sampled data system and its value is only changed at + * Communication Points. */ + continous /**< Only a variable of type = `Real` can be `continuous`. */ +}omsi_variability; + +/** + * Enumeration that defines how the variable is initialized. + */ +typedef enum { + exact, /**< The variable is initialized with the start value. */ + approx, /**< The variable is an iteration variable of an algebraic loop + * and the iteration at initialization starts with the start + * value. */ + calculated, /**< The variable is calculated from other variables during + * initialization. */ + no_initial /**< The variable is not initial (input variable or + * independent variable). */ +}omsi_initial; + + + +/* + * ============================================================================ + * Definitions for simulation data + * ============================================================================ + */ + +/** + * \brief Contains information where to find variables in `sim_data->model_vars_and_params`. + */ +typedef struct omsi_index_type { + omsi_data_type type; /**< Data type*/ + omsi_unsigned_int index; /**< Index in sim_data->model_vars_and_params->[datatype] + * where [datatype]=reals|ints|bools depending on type */ +} omsi_index_type; + + +/** + * \brief Struct of arrays containing values. + * + * Containing values for variables, parameters, + * aliases for corresponding time value. + * Also containing number of containing reals, integers and booleans, strings and externs. + */ +typedef struct omsi_values { + omsi_real* reals; /* array of omsi_real */ + omsi_int* ints; /* array of omsi_int */ + omsi_bool* bools; /* array of omsi_bool */ + omsi_string* strings; /* array of omsi_string */ + void* externs; /* array of pointer to extern objects */ + omsi_real time_value; /* current system time */ + + omsi_unsigned_int n_reals; /* length of array reals */ + omsi_unsigned_int n_ints; /* length of array ints */ + omsi_unsigned_int n_bools; /* length of array bools */ + omsi_unsigned_int n_strings; /* length of array strings */ + omsi_unsigned_int n_externs; /* length of array externs */ +} omsi_values; + + +/** + * Struct containing sample event. + */ +typedef struct omsi_sample { + omsi_unsigned_int id; /**< Unique id for each sample. */ + omsi_real start_time; /**< Start time of sample event. */ + omsi_real interval; /**< Interval length of sample event. */ +}omsi_sample; + + +/** \brief General algebraic system. + * + * Struct containing information for one linear or non-linear algebraic system + * and solver_data to solve the described equation system. + * + * Linear case: A*x=b + * + * Non-linear case: f(x)=0 + */ +typedef struct omsi_algebraic_system_t { + omsi_unsigned_int id; /**< Unique identification for algebraic system. */ + + omsi_unsigned_int n_iteration_vars; /**< Number of iteration variables. */ + + omsi_unsigned_int n_conditions; /**< Number of zerocrossing conditions. */ + omsi_int* zerocrossing_indices; /**< Array of zerocrossing indices of size `n_conditions`. */ + + omsi_bool isLinear; /**< Describes if algebraic system is linear. + * * `isLinear=true`: algebraic system is linear + * * `isLinear=false`: algebraic system is linear. */ + struct omsi_function_t* jacobian; /**< Pointer to `omsi_function_t` to describe + * * linear case: jacobian describes matrix A + * * non-linear case: jacobian describes f' */ + + struct omsi_function_t* functions; /**< Pointer to omsi_function for residual function. */ + solver_data* solver_data; /**< Pointer to solver instance. */ +}omsi_algebraic_system_t; + + +/** \brief Structure containing all data to evaluate equations or system of equations. + * + * For example the initialization system would be one `omsi_function_t` containing all + * potential linear and non-linear loops, which include in turn `omsi_function_t` structs + * for residual functions and Jacobi matrix. + * + */ +typedef struct omsi_function_t { + omsi_unsigned_int n_algebraic_system; /**< Number of algebraic systems. */ + omsi_algebraic_system_t* algebraic_system_t; /**< Array of algebraic systems. */ + + omsi_values* function_vars; /**< Pointer to variables and parameters. + * Either local copy of needed variables for evaluation or + * pointer to next higher struct with `omsi_values` array. */ + + omsi_values* pre_vars; /**< Pointer to pre values of `function_vars` + * Either local copy of needed variables for evaluation or + * pointer to next higher struct with `omsi_values` array. */ + + omsi_values* local_vars; /**< Pointer to local variables like seed variables and + * and dummy derivative variables. */ + + omsi_real* zerocrossings_vars; /**< Conditions of zerocrossing functions. */ + omsi_real* pre_zerocrossings_vars; /**< Pre conditions of zerocrossing functions. */ + + omsi_sample* sample_events; /**< Pointer to array of sample events in `sim_data_t struct`. */ + + /** evaluate function + * \param [in,out] this_function Pointer to this `omsi_fucntion_t` struct. + * \param [in] read_only_vars_and_params Pointer to read only struct with variables and parameters. + * from next higher struct with `omsi_values` array. + * \param [in] data Pointer to optional data for evaluated function. Can be `NULL`. + * + * Points to function in generated code. + */ + omsi_status (*evaluate) (struct omsi_function_t* this_function, + const omsi_values* read_only_vars_and_params, + void* data); + + omsi_index_type* input_vars_indices; /* index to next higher omsi_values pointer */ + omsi_index_type* output_vars_indices; /* e.g to sim_data_t->model_vars_and_params */ + + omsi_unsigned_int n_input_vars; /* number of input variables */ + omsi_unsigned_int n_inner_vars; /* number of inner variables */ + omsi_unsigned_int n_output_vars; /* number of output variables */ +} omsi_function_t; + + +/** \brief Structure containing all dynamic simulation data. + * Detailed Description + */ +typedef struct sim_data_t{ + omsi_function_t* initialization; /**< Pointer to omsi_function_t struct + * necessary for initialization. */ + omsi_function_t* simulation; /**< Pointer to omsi_function_t struct + * necessary for simulation. */ + + omsi_values* model_vars_and_params; /**< Pointer to struct of arrays containing + * values for all variables, parameters and so on. */ + + omsi_values* pre_vars; /**< Pointer to all pre variables. */ + omsi_index_type* pre_vars_mapping; /**< Mapping pre_vars to corresponding + * variables in model_vars_and_params. */ + + omsi_real* zerocrossings_vars; /**< Conditions of zerocrossing functions. */ + omsi_real* pre_zerocrossings_vars; /**< Pre conditions of zerocrossing functions. */ + + omsi_sample* sample_events; /**< Array of sample events */ + + /* start indices to model_vars_and_params */ + omsi_unsigned_int inputs_real_index; /*start index of input real variables */ + omsi_unsigned_int inputs_int_index; /*start index of input integer variables */ + omsi_unsigned_int inputs_bool_index; /*start index of input boolean variables */ + omsi_unsigned_int outputs_real_index; /*start index of output real variables */ + omsi_unsigned_int outputs_int_index; /*start index of output integer variables */ + omsi_unsigned_int outputs_bool_index; /*start index of output boolean variables */ + +} sim_data_t; + + +/* + * ============================================================================ + * Definitions for model informations + * ============================================================================ + */ +/* + * additional file information for debugging + */ +typedef struct file_info { + omsi_string filename; /* filename where variable is defined */ + omsi_int lineStart; /* number of line where definition of variable starts */ + omsi_int colStart; /* number of columns where definition of variable starts */ + omsi_int lineEnd; /* number of line where definition of variable ends */ + omsi_int colEnd; /* number of columns where definition of variable ends */ + omsi_bool fileWritable; /* =true if file writable, else =false */ +} file_info; + + +/* + * additional equation information for debugging + */ +typedef struct equation_info_t{ + omsi_int id; /* unique equation reference from info.json */ + omsi_int profileBlockIndex; + omsi_int parent; + omsi_int numVar; /* number of defining variables */ + omsi_string* variables; /* array of unknown variables */ + file_info info; /* file informations for equation */ +} equation_info_t; + + +/* + * Modelica attributes for real variables + */ +typedef struct real_var_attribute_t { + omsi_string unit; /* default = "" */ + omsi_string displayUnit; /* default = "" */ + omsi_real min; /* default = -Inf */ + omsi_real max; /* default = +Inf */ + omsi_bool fixed; /* depends on the type */ + omsi_real nominal; /* default = 1.0 */ + omsi_real start; /* default = 0.0 */ +} real_var_attribute_t; + + +/* + * Modelica attributes for integer variables + */ +typedef struct int_var_attribute_t { + omsi_int min; /* = -Inf */ + omsi_int max; /* = +Inf */ + omsi_bool fixed; /* depends on the type */ + omsi_int start; /* = 0 */ +} int_var_attribute_t; + + +/* + * Modelica attributes for boolean variables + */ +typedef struct bool_var_attribute_t { + omsi_bool fixed; /* depends on the type */ + omsi_bool start; /* = false */ +} bool_var_attribute_t; + + +/* + * Modelica attributes for string variables + */ +typedef struct string_var_attribute_t { + omsi_char * start; /* = "" */ +} string_var_attribute_t; + + +/* + * Informations for single variable or parameter + */ +typedef struct model_variable_info_t { + omsi_string name; /* name of variable|parameter|alias */ + omsi_int id; /* unique value reference from *_init.xml */ + omsi_string comment; /* variable description or modelica comment*/ + omsi_causality causality; /* Causality if variable. */ + omsi_variability variability; /* Variability of Variable. */ + omsi_initial initial; /* How the variable is initialized. */ + omsi_index_type type_index; /* tuple of data_type and index in sim_data->model_vars_and_params->..., if isAlias=true then index from alias variable */ + void* modelica_attributes; /* pointer to modelica attributes ( real_var_attribute | int_var_attribute | bool_var_attribute | string_var_attribute ) */ + omsi_bool isAlias; /* true if alias, else false */ + omsi_int negate; /* if negated -1 else 1 */ + omsi_int aliasID; /* pointer to alias if >= 0 */ + file_info info; /* file informations for variable|parameter|alias */ +} model_variable_info_t; + + +/** \brief Structure containing all static simulation informations. + * + * Used for debugging features. + */ +typedef struct model_data_t { + omsi_string modelGUID; /**< Model GUID. */ + omsi_unsigned_int n_states; /**< Number of continuous states. */ + omsi_unsigned_int n_derivatives; /**< Number of derivatives. */ + omsi_unsigned_int n_real_vars; /**< Number of real algebraic variables. */ + omsi_unsigned_int n_discrete_reals; /**< Number of discrete real variables */ + omsi_unsigned_int n_real_parameters; /**< Number of real parameters. */ + omsi_unsigned_int n_real_aliases; /**< Number of real alias variables. */ + omsi_unsigned_int n_int_vars; /**< Number of integer algebraic variables. */ + omsi_unsigned_int n_int_parameters; /**< Number of integer parameters. */ + omsi_unsigned_int n_int_aliases; /**< Number of integer alias variables. */ + omsi_unsigned_int n_bool_vars; /**< Number of boolean algebraic variables. */ + omsi_unsigned_int n_bool_parameters; /**< Number of boolean parameters. */ + omsi_unsigned_int n_bool_aliases; /**< Number of boolean alias variables. */ + omsi_unsigned_int n_string_vars; /**< Number of string algebraic variables. */ + omsi_unsigned_int n_string_parameters; /**< Number of string parameters. */ + omsi_unsigned_int n_string_aliases; /**< Number of string alias variables. */ + omsi_unsigned_int n_zerocrossings; /**< Number of zero crossings. */ + omsi_unsigned_int n_equations; /**< Number of all equations. */ + omsi_unsigned_int n_init_equations; /**< Number of initial equations. */ + omsi_unsigned_int n_regular_equations; /**< Number of regular equations. */ + omsi_unsigned_int n_alias_equations; /**< Number of alias equations. */ + omsi_unsigned_int n_samples; /**< Number of samples. */ + omsi_int start_index_disc_reals; /**< Start index of discrete real variables */ + + model_variable_info_t* model_vars_info; /**< Array of variable informations for all N variables and parameters, + * N = `n_states` + `n_derivatives` `n_$all_vars` + `n_$all_parameters`, $all={real,int,bool}. */ + equation_info_t* equation_info; /**< Array of equation informations for all equations. */ +} model_data_t; + + +/* + * ============================================================================ + * Definitions for experiment informations + * ============================================================================ + */ + +/** \brief Structure containing experiment informations. + * + * E.g. containing time intervall for simulation and chosen ODE/DAE solver. + */ +typedef struct omsi_experiment_t { + omsi_real start_time; /**< Start time of experment, default=0. */ + omsi_real stop_time; /**< End time of experiment, defalut=`start_time`+1 */ + omsi_real step_size; /**< Step size for solvers, default (`stop_time`-`start_time`)/500 */ + omsi_unsigned_int num_outputs; /**< Number of outputs of model. */ + omsi_real tolerance; /**< Tolerance for solver, default=1e-5. */ + omsi_string solver_name; /**< Name of used solver, default="dassl". */ +} omsi_experiment_t; + + +/* + * ============================================================================ + * Structure containing simulation, experiment and model informations + * ============================================================================ + */ + +/** \brief Structure containing simulation, experiment and model informations. + * + */ +typedef struct omsi_t { + sim_data_t* sim_data; /**< Containing data for simulation. */ + omsi_experiment_t* experiment; /**< Containing infos for experiment. */ + model_data_t* model_data; /**< Containing additional model infos. */ + + omsi_bool logCategories[NUMBER_OF_CATEGORIES]; /* Containing information for filtered logger */ + omsi_bool loggingOn; /* Set logging on or off*/ + ModelState* state; /** Pointer to model state of OSU*/ +} omsi_t; + + +/* + * ============================================================================ + * Function prototypes + * ============================================================================ + */ +omsi_int omsi_initiatiate_osu(omsi_t** omsi); +omsi_int omsi_initialize_model(omsi_t** omsi); +omsi_int omsi_initialize_solver(omsi_t** omsi); +omsi_int omsi_intialize_simulation(omsi_t** omsi); + + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif + +/** \} */ diff --git a/SimulationRuntime/OMSI/include/omsi_api_functions.h b/SimulationRuntime/OMSI/include/omsi_api_functions.h new file mode 100644 index 00000000000..6482b202633 --- /dev/null +++ b/SimulationRuntime/OMSI/include/omsi_api_functions.h @@ -0,0 +1,178 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/*! \file omsi_api_functions.h + * \brief API functions for OMSI Model Exchange and Co-Simulation + * + * Description: Header file for all usable API functions for OpenModelica + * Simulation Interface (OMSI) Model Exchange (ME) and Co-Simulation (CS). + * In fact all Functional Mockup Interface (FMI) ME and CS function with some + * additional functions are provided. + */ + +#ifndef OMSI_API_FUNC_H +#define OMSI_API_FUNC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Export for dynamic linking on Windows */ +#if !defined(FMI2_Export) + #if defined(__MINGW32__) || defined(_MSC_VER) || defined(_WIN32) || definded(__CYGWIN__) + #define OMSI_DLLImport __declspec( dllimport ) + #define OMSI_DLLExport __declspec( dllexport ) + #else + #if __GNUC__>=4 + #define OMSI_DLLExport __attribute__ ((visibility ("default"))) + #define OMSI_DLLImport /* nothing */ + #else + #define OMSI_DLLImport /* extern */ + #define OMSI_DLLExport /* nothing */ + #endif + #endif + + #if defined(IMPORT_INTO) + #define OMSI_DLLDirection OMSI_DLLImport + #else /* we export from the dll */ + #define OMSI_DLLDirection OMSI_DLLExport + #endif + +#else /* Use defined FMI2_Export */ + #define OMSI_DLLDirection FMI2_Export +#endif + + + +/* ToDo: Add all added functions for ME here */ +/* ToDo: Add Doxygen documentation */ + +/* + * ============================================================================ + * Common functions + * ============================================================================ + */ + +/*! \fn omsi_instantiate + * + * This function instantiates the osu instance. + * + * \param [ref] [data] + */ +OMSI_DLLDirection osu_t* omsi_instantiate(omsi_string instanceName, + omsu_type fmuType, + omsi_string fmuGUID, + omsi_string fmuResourceLocation, + const omsi_callback_functions* functions, + omsi_bool visible, + omsi_bool loggingOn); + + + + + + +/* + * ============================================================================ + * Model Exchange functions + * ============================================================================ + */ + + + +/* + * ============================================================================ + * Co-Simulation functions + * ============================================================================ + */ + + + +/* + * ============================================================================ + * Additional API functions + * ============================================================================ + */ + + +/* call from fmi2_setup_expriment */ +OMSI_DLLDirection void omsi_setup_experiment(omsi_t* omsi, bool tolerance_defined, + double relative_tolerance); +/* called from fmi2_enter_intialization_mode */ +OMSI_DLLDirection int omsi_initialize(omsi_t* omsi); +/* called from fmi2_set_real */ +OMSI_DLLDirection int omsi_set_real(omsi_t* omsi, const int* vr, size_t nvr, const double* value); +/* called from fmi2_set_integer */ +OMSI_DLLDirection int omsi_set_integer(omsi_t* omsi, const int* vr, size_t nvr, const int* value); +/* called from fmi2_set_booleanomsi_vector_t */ +OMSI_DLLDirection int omsi_set_boolean(omsi_t* omsi, const int* vr, size_t nvr, const bool* value); +/* called from fmi2_set_string */ +OMSI_DLLDirection int omsi_set_string(omsi_t* omsi, const int* vr, size_t nvr, const const char** value); +/* called from fmi2_get_real */ +OMSI_DLLDirection int omsi_get_real(omsi_t* omsi, const int* vr, size_t nvr, double* value); +/* called from fmi2_get_integer */ +OMSI_DLLDirection int omsi_get_integer(omsi_t* omsi, const int* vr, size_t nvr, int* value); +/* called from fmi2_get_boolean */ +OMSI_DLLDirection int omsi_get_boolean(omsi_t* omsi, const int* vr, size_t nvr, bool* value); +/* called from fmi2_get_string */ +OMSI_DLLDirection int omsi_get_string(omsi_t* omsi, const int* vr, size_t nvr, const char** value); +/* called from fmi2_get_directional_derivative */ +OMSI_DLLDirection int omsi_get_directional_derivative(omsi_t* omsi, + const int* vUnknown_ref, size_t nUnknown, + const int* vKnown_ref, size_t nKnown, + const double* dvKnown, double* dvUnknown); + +/* called from fmi2_get_derivatives */ +OMSI_DLLDirection int omsi_get_derivatives(omsi_t* omsi, double* derivatives , size_t nx); +/* called from fmi2_get_event_indicators */ +OMSI_DLLDirection int omsi_get_event_indicators(omsi_t* omsi, double* eventIndicators, size_t ni); +/* called from fmi2_get_nominals_of_continuous_states */ +OMSI_DLLDirection int omsi_get_nominal_continuous_states(omsi_t* omsi, double* x_nominal, size_t nx); +/* called from fmi2_completed_integrator_step */ +OMSI_DLLDirection int omsi_completed_integrator_step(omsi_t* omsi, double* triggered_event); +/* called from fmi2_set_time */ +OMSI_DLLDirection int omsi_set_time(omsi_t* omsi, double time); +/* called from fmi2_set_continuous_states */ +OMSI_DLLDirection int omsi_set_continuous_states(omsi_t* omsi, const double* x, size_t nx); +/* called from fmi2_terminate */ +OMSI_DLLDirection int omsi_terminate(omsi_t* omsi); +/* called from fmi2_terminate */ +OMSI_DLLDirection int omsi_terminate(omsi_t* omsi); + +OMSI_DLLDirection int omsi_next_time_event(omsi_t* omsi); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/include/omsi_callbacks.h b/SimulationRuntime/OMSI/include/omsi_callbacks.h new file mode 100644 index 00000000000..2c349634b2d --- /dev/null +++ b/SimulationRuntime/OMSI/include/omsi_callbacks.h @@ -0,0 +1,176 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_callbacks.h + */ + +/** \addtogroup OMSIBase OMSI Base Library + * \ingroup OMSI + * \{ */ + +#ifndef OMSI_CALLBACKS_H +#define OMSI_CALLBACKS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int evaluate_ode(omsi_t); +int evaluate_outputs(omsi_t); +int evaluate_zerocrossings(omsi_t); +int evaluate_discrete_system(omsi_t); +int evaluate_bound_parameter(omsi_t); +int evaluate_intial_system(omsi_t); + + +/* + * ============================================================================ + * OMSI callback functions + * ============================================================================ + */ + +/** + * \brief Function type for logger functions. + * + * \param [in] componentEnvironment OSU component + * \param [in] instanceName Unique identifier for OMSU instance, e.g. the model name. + * \param [in] status Status for current log. + * \param [in] category Category for which message should be logged. + * \param [in] message String with message to log. Can contain string formatters, e.g. %d. + * \param [in] ... Optional arguments for string formatters. + */ +typedef void (*omsi_callback_logger) (const void* componentEnvironment, + omsi_string instanceName, + omsi_status status, + omsi_string category, + omsi_string message, ...); + + +/** + * \brief Function type for allocating memory. + * + * \param [in] num Number of elements. + * \param [in] size Size of each element in bytes. + * + * \return Pointer to allocated memory. + */ +typedef void* (*omsi_callback_allocate_memory) (omsi_unsigned_int num, + omsi_unsigned_int size); + + +/** + * \brief Function type for deallocating memory. + * + * \param [in] pointer Pointer to previously memory allocated. + */ +typedef void (*omsi_callback_free_memory) (void* pointer); + + +/** + * \brief Function type to signal if the computation of communication step of + * co-simulation slave is finished. + * + * Optional function. Is not used for modelExchange. + * + * \param [in] componentEnvironment OSU component + * \param [in] status Status for current log. + */ +typedef void (*omsi_step_finished) (void* componentEnvironment, + omsi_status status); + + +/** + * \brief Callback functions to be used by OMSI library functions. + * + * Containing functions for logging of messages and memory handling. + */ +typedef struct omsi_callback_functions{ + const omsi_callback_logger logger; /**< Logger function */ + const omsi_callback_allocate_memory allocateMemory; /**< Allocate memory function */ + const omsi_callback_free_memory freeMemory; /**< Free memory function */ + const omsi_step_finished stepFinished; /**< Communication function for slaves */ + void* componentEnvironment; /**< Pointer to component environment (not the OSU) */ +}omsi_callback_functions; + + + +/* + * ============================================================================ + * Callbacks for template functions + * ============================================================================ + */ + +/** + * \brief Function type for allocating `omsi_function initialization` or `simulation` + * from generated code. + * + * \param [in] omsi_function Pointer to `omsi_function initialization` or `simulation` + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +typedef omsi_status (*omsu_initialize_omsi_function) (omsi_function_t* omsi_function); + + +/** + *\brief Function type for evaluating omsi_function->evaluate. + * + * Evaluate equations from generated code. + * + * \param [in] function Pointer to this omsi_function. + * \param [in] variables Pointer to global model variables and parameters from `sim_data`. + * \param [in,out] data Pointer to optional argument for evaluation function. Can be `NULL`. + * \return `omsi_status omsi_ok` if successful
+ * `omsi_status omsi_error` if something went wrong. + */ +typedef omsi_status (*evaluate_function) (omsi_function_t* function, + omsi_values* variables, + void* data); + +/** + * \brief Callback functions to generated code. + */ +typedef struct omsi_template_callback_functions_t { + omsi_bool isSet; /**< Boolean if template functions are set */ + omsu_initialize_omsi_function initialize_initialization_problem; /**< Function pointer to initialize the initialization problem */ + omsu_initialize_omsi_function initialize_simulation_problem; /**< Function pointer to initialize the simulation problem */ + + void (*initialize_samples) (omsi_sample* sample_events); /**< Function to initialize sampleEvents. */ +}omsi_template_callback_functions_t; + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif + +/** \} */ diff --git a/SimulationRuntime/OMSI/solver/CMakeLists.txt b/SimulationRuntime/OMSI/solver/CMakeLists.txt new file mode 100644 index 00000000000..d925e834073 --- /dev/null +++ b/SimulationRuntime/OMSI/solver/CMakeLists.txt @@ -0,0 +1,72 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9) +#OpenModelica Simulation Interface solver +PROJECT(OMSISolver) +SET(CMAKE_VERBOSE_MAKEFILE ON) + +# Find blas and lapack +IF(IS_MINGW32) + SET(LAPACK_MINGW $ENV{OMDEV}/tools/msys/mingw32/bin/libopenblas.dll) + SET(LAPACK_LIBRARIES ${LAPACK_MINGW}) +ELSEIF(IS_MINGW64) + SET(LAPACK_MINGW $ENV{OMDEV}/tools/msys/mingw64/bin/libopenblas.dll) + SET(LAPACK_LIBRARIES ${LAPACK_MINGW}) +ELSE() + FIND_PACKAGE(BLAS) + FIND_PACKAGE(LAPACK) +ENDIF() + +IF (BLAS_FOUND STREQUAL "NOTFOUND") + MESSAGE(FATAL_ERROR "Error: Blas Libraries not found!") +ENDIF() +IF (LAPACK_FOUND STREQUAL "NOTFOUND") + MESSAGE(FATAL_ERROR "Error: Lapack Libraries not found!") +ENDIF() +MESSAGE(STATUS "Lapack Libraries: ${LAPACK_LIBRARIES}") + +IF(MSVC) + #workaround because cmake does not find the lapack libraries for Visual Studio 10 + SET(LAPACK_MSVC_10 $ENV{OMDEV}/lib/3rdParty/Lapack/Lib/lapack_win32.lib ) + SET(BLAS_MSVC_10 $ENV{OMDEV}/lib/3rdParty/Lapack/Lib/blas_win32.lib ) + SET(LAPACK_LIBRARIES ${LAPACK_MSVC_10} ${BLAS_MSVC_10} ) + MESSAGE(STATUS "Using manual set Lapack Libraries: ${LAPACK_LIBRARIES}") +ENDIF(MSVC) + +# Find SUNDIALS KINSOL libraries +FIND_LIBRARY(KINSOL_LIBRARIE sundials_kinsol + PATH ${CMAKE_INSTALL_PREFIX}/${LIB_OMC}) +IF (NOT KINSOL_LIBRARIE) + MESSAGE(FATAL_ERROR "Error: SUNDIALS KINSOL library not found!") +ENDIF() + +FIND_LIBRARY(SUNDIALS_NVEC_LIBRARIE sundials_nvecserial + PATH ${CMAKE_INSTALL_PREFIX}/${LIB_OMC}) +IF(NOT SUNDIALS_NVEC_LIBRARIE) + MESSAGE(FATAL_ERROR "Error: sundials_nvec_serial library not found!") +ENDIF() + +include_directories ("${CMAKE_INSTALL_PREFIX}/include/omc/c/sundials") +MESSAGE(STATUS "Location of SUNDIALS headers: ${CMAKE_INSTALL_PREFIX}/include/omc/c/sundials") + +SET(SUNDIALS_LIBRARIES ${KINSOL_LIBRARIE} ${SUNDIALS_NVEC_LIBRARIE}) +MESSAGE(STATUS "KINSOL Libraries: ${SUNDIALS_LIBRARIES}") + +# OMSISolver includes +include_directories ("${CMAKE_SOURCE_DIR}/solver/include") + +add_library(${OMSISolverName} + src/solver_api.c + src/solver_helper.c + src/solver_kinsol.c + src/solver_lapack.c +) + + +target_link_libraries(${OMSISolverName} ${CMAKE_DL_LIBS} ${LAPACK_LIBRARIES} ${SUNDIALS_LIBRARIES}) + +install(TARGETS ${OMSISolverName} DESTINATION ${LIBINSTALLEXT}) + +install(FILES + ${CMAKE_SOURCE_DIR}/solver/include/omsi_solver.h + ${CMAKE_SOURCE_DIR}/solver/include/solver_api.h + ${CMAKE_SOURCE_DIR}/solver/include/solver_helper.h +DESTINATION include/omc/omsi/solver) diff --git a/SimulationRuntime/OMSI/solver/include/omsi_solver.h b/SimulationRuntime/OMSI/solver/include/omsi_solver.h new file mode 100644 index 00000000000..b4d923fd2fd --- /dev/null +++ b/SimulationRuntime/OMSI/solver/include/omsi_solver.h @@ -0,0 +1,315 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file omsi_solver.h + * Solver application interface to solve linear and non-linear equation systems + * in shape of + * A*x = b or F(x) = 0, + * with square Matrix A of dimension n or F:R^n --> R^n. + * + */ + + +/** \defgroup SOLVER OMSI Solver Library + * \ingroup OMSI + * + * \brief Solver library for OpenSimultionInterface. + * + * ... containing linear and non-linear + * solver to compute algebraic loops within OMSI. + * + * Can also be used as stand-alone solver library. + */ + +/** \defgroup LIN_SOLVER Linear OMSI Solver + * \ingroup SOLVER + * + * \brief Linear solver collection. + * + * Linear solver to compute algebraic equation systems of form A*x=b. + * A is an `n` x `n` square matrix, b is vector of dimension `n`. + */ + +/** \defgroup NONLIN_SOLVER Non-Linear OMSI Solver + * \ingroup SOLVER + * + * \brief Non-linear solver collection. + * + * Non-linear solver to compute algebraic equation systems of form f(x)=0. + */ + + +/** \addtogroup SOLVER OMSI Solver Library + * \{ */ + +#ifndef SOLVER_API_H +#define SOLVER_API_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Type definitions of variables + */ +#ifdef OMSI_TYPES_DEFINED + +typedef omsi_unsigned_int solver_unsigned_int; +typedef omsi_real solver_real; +typedef omsi_int solver_int; +typedef omsi_long solver_long; +typedef omsi_bool solver_bool; +#define solver_true omsi_true +#define solver_false omsi_false +#ifndef true +#define true omsi_true +#endif +#ifndef false +#define false omsi_false +#endif +typedef omsi_char solver_char; +typedef omsi_string solver_string; +#else +typedef unsigned int solver_unsigned_int; +typedef double solver_real; +typedef int solver_int; +typedef long solver_long; +typedef int solver_bool; +#define solver_true 1 +#define solver_false 0 +typedef char solver_char; +typedef const solver_char* solver_string; +#endif + +/* Maximum buffer size for print functions. */ +#define MAX_BUFFER_SIZE BUFSIZ + + +/** + * Solver name to specify used solver in solver_data + */ +typedef enum { + solver_unregistered, /**< No solver selected. */ + solver_lapack, /**< LAPACK solver using DGESV routine for generale matrices.
+ [DGESV Documentation](http://www.netlib.org/lapack/explore-html/d7/d3b/group__double_g_esolve_ga5ee879032a8365897c3ba91e3dc8d512.html#ga5ee879032a8365897c3ba91e3dc8d512) */ + solver_newton, /**< solver_newton */ + solver_kinsol, /**< SUNDIALS KINSOL solver */ + solver_extern /**< solver_extern */ +}solver_name; + + +/** + * Current state of solver instance. + */ +typedef enum { + solver_uninitialized = 0, /**< Solver is not initialized yet. */ + solver_instantiated, /**< Memory for `solver_data` is allocated. */ + solver_initializated, /**< Solver is initialized for selected `solver_name` + and memory was allocated. */ + solver_ready, /**< Solver is ready to compute solution of algebraic system. */ + solver_finished_ok, /**< Solver computed solution successfully. */ + solver_finished_error, /**< Solver could not solve algebraic system successfully. */ + solver_error_state /**< Solver is in critical error state. */ +}solver_state; + + +/** + * Status for error handling. + */ +typedef enum { + solver_ok, /**< Everything is just fine. */ + solver_warning, /**< Something is not totally correct, but carrying on. */ + solver_error /**< Encountered a serious problem, need to abort. */ +}solver_status; + + +#define NUMBER_OF_SOLVER_CATEGORIES 5 +typedef enum { + log_solver_error, + log_solver_warning, + log_solver_nonlinear, + log_solver_linear, + log_solver_all +}solver_log_level; + +/** Information about solution and its quality. + * + * Multiple values are possible. + */ +typedef enum { + solver_successful_exit = 1<<0, /**< Solver solved algebraic system successful. */ + + /* linear informations */ + solver_singular = 1<<1, /**< Solver encountered singularity, e.g. in LU decomposition. */ + + /* non-linear informations */ + solver_max_iteration_reached = 1<<2, /**< Solver reached maximum number of iterations (only for non-linear solvers). */ + solver_min_step_size_reached = 1<<3, /**< Solver step size has fallen below minimum step size (only for non-linear solvers). */ + solver_got_assert = 1<<4 /**< Got an assert, e.g. while evaluating function f. */ +}solver_info; + + +/* callback functions */ +/** \fn void (*solver_callback_logger) (solver_string format, ...) + * \brief Logger function. + * + * Used to report messages and prints. + * Must accept format tags in `format` in form of + * `%[flags][width][.precision][length]specifier` as specified for `printf` of + * the C standard library.. + * E.g. use `printf` from the C standard library. + * + * \param [in] log_level Log level of current message to filter logs. + * \param [in] format Text to be written. Can optionally contain embedded + * format tags similar to `printf`. + */ +typedef void (*solver_callback_logger) (solver_log_level, + solver_string, ...); + + +/** \fn void* (*solver_callback_allocate_memory) (solver_unsigned_int n_objects, solver_unsigned_int size) + * \brief Callback function to allocate memory. + * + * The space is initialized to zero bytes. E.g. use `calloc` from the C standard + * library. + * + * \param [in] n_objects Number of objects to allocate memory for. + * \param [in] size Size of each object. + * + * \return Returns pointer to allocated memory for a vector of + * `n_objects` objects, each of size `size`, or `NULL` on failure. + */ +typedef void* (*solver_callback_allocate_memory) (solver_unsigned_int, solver_unsigned_int); + + +/** \fn void (*solver_callback_free_memory) (void* pointer) + * \brief Callback function to free memory allocated with `solver_allocate_memory` + * function. + * + * If a null pointer is provided as input no action is performed. + * + * \param [in] pointer Pointer to memory allocated previously with + * `solver_allocate_memory` function or `NULL`. + */ +typedef void (*solver_callback_free_memory) (void*); + +typedef void (*solver_interact_matrix_element) (void*, + solver_unsigned_int, + solver_unsigned_int, + solver_real*); + +typedef void (*solver_interact_vector_element) (void*, + solver_unsigned_int, + solver_real*); + +typedef void (*solver_get_set_F_func) (void); + + +typedef solver_state (*solver_solve_func) (void*); + + +/** \fn solver_status (*evaluate_res_func) (void* data); + * \brief Evaluate residuum function `f(x)` for non-linear equation systems. + * + * \param [in] x_vector Vector x + * \param [out] fval Function value `f(x)` + */ +typedef void (*evaluate_res_func) (solver_real* x_vector, + solver_real* fval, + void* data); + +typedef solver_int (*residual_wrapper_func) (solver_real*, + solver_real*, + void*); + +/** + * Struct for callback functions for linear solvers. + */ +typedef struct solver_linear_callbacks { + solver_interact_matrix_element get_A_element; /**< Callback function to get element(s) of `A`. */ + solver_interact_matrix_element set_A_element; /**< Callback function to set element(s) of `A`. */ + + solver_interact_vector_element get_b_element; /**< Callback function to get element(s) of `b`. */ + solver_interact_vector_element set_b_element; /**< Callback function to set element(s) of `b`. */ + + solver_interact_vector_element get_x_element; /**< Callback function to get element(s) of solution vector `x`. */ + + solver_solve_func solve_eq_system; /**< Callback function to solve equation system `A*x=b`. */ +} solver_linear_callbacks; + + +/** + * Struct for callback functions for non-linear solvers. + */ +typedef struct solver_non_linear_callbacks { + solver_solve_func solve_eq_system; + + solver_interact_vector_element get_x_element; /**< Callback function to get element(s) of solution vector `x`. */ + + solver_interact_matrix_element set_jacobian_element; /**< Callback function to set element of Jacobian matrix*/ +} solver_non_linear_callbacks; + + +/** \brief General solver structure. + * + * Containing informations and function callbacks for a general solver instance. + * Solver specific data is stored in `specific_data` in it's own data formats. + * + * + */ +typedef struct solver_data { + solver_name name; /**< Name of solver instance. */ + solver_bool linear; /**< `solver_true` if solver can only solve linear problems, + * `solver_false` if non-linear. */ + + solver_state state; /**< Current state of solver instance, e.g if already initialized or finished. */ + solver_info info; /**< Informations about solution quality. */ + + solver_unsigned_int dim_n; /**< Dimension of algebraic loop. In linear + case dimension `n` of square matrix `A`. + For non-linear loops dimension `n` of function `f`. */ + void* specific_data; /**< Solver specific data, depending on named solver. + Contains it's own data formats to save variables, settings and so on. */ + + void* solver_callbacks; /**< Linear case: Pointer to `solver_linear_callbacks`
+ * Non-linear case: Pointer to `solver_non_linear_callbacks`. */ +} solver_data; + + + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif + +/** \} */ diff --git a/SimulationRuntime/OMSI/solver/include/solver_api.h b/SimulationRuntime/OMSI/solver/include/solver_api.h new file mode 100644 index 00000000000..d822177fb7b --- /dev/null +++ b/SimulationRuntime/OMSI/solver/include/solver_api.h @@ -0,0 +1,118 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_api.h + * + * Application interface for OMSI solver. + */ + +/** \addtogroup SOLVER OMSI Solver Library + * \{ */ + +#ifndef _SOLVER_API_H +#define _SOLVER_API_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function prototypes */ +void solver_init_callbacks (solver_callback_allocate_memory allocateMemoryFunction, + solver_callback_free_memory freeMemoryFunction, + solver_callback_logger loggerFunction); + +solver_data* solver_allocate(solver_name name, + solver_unsigned_int dim_n); + +void solver_free(solver_data* solver); + +solver_status solver_prepare_specific_data (solver_data* solver, + residual_wrapper_func user_wrapper_res_function, + void* user_data); + +solver_status solver_set_start_vector (solver_data* solver, + solver_real* initial_guess); + +solver_real* solver_get_start_vector (solver_data* solver); + +void solver_set_matrix_A(const solver_data* solver, + const solver_unsigned_int* column, + const solver_unsigned_int n_column, + const solver_unsigned_int* row, + const solver_unsigned_int n_row, + solver_real* value); + +void solver_get_matrix_A(solver_data* solver, + solver_unsigned_int* column, + solver_unsigned_int n_column, + solver_unsigned_int* row, + solver_unsigned_int n_row, + solver_real* value); + +void solver_set_vector_b (solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int size_of_b, + solver_real* value); + +void solver_get_vector_b (solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int size_of_b, + solver_real* value); + +void solver_get_lin_solution(solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int n_index, + solver_real* values); + +void solver_get_nonlin_solution(solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int n_index, + solver_real* values); + +solver_string solver_get_name (solver_data* solver); + +void solver_print_data (solver_data* solver, + solver_string header); + +solver_status solver_linear_solve(solver_data* solver); + +solver_status solver_non_linear_solve(solver_data* solver); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif + +/** \} */ diff --git a/SimulationRuntime/OMSI/solver/include/solver_global.h b/SimulationRuntime/OMSI/solver/include/solver_global.h new file mode 100644 index 00000000000..4c8b8dbdaff --- /dev/null +++ b/SimulationRuntime/OMSI/solver/include/solver_global.h @@ -0,0 +1,49 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef _SOLVER_GLOBAL_H_ +#define _SOLVER_GLOBAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global functions */ +extern solver_callback_logger solver_logger; +extern solver_callback_allocate_memory solver_allocateMemory; +extern solver_callback_free_memory solver_freeMemory; + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/solver/include/solver_helper.h b/SimulationRuntime/OMSI/solver/include/solver_helper.h new file mode 100644 index 00000000000..043e298da93 --- /dev/null +++ b/SimulationRuntime/OMSI/solver/include/solver_helper.h @@ -0,0 +1,62 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +#ifndef _SOLVERHELPER_H_ +#define _SOLVERHELPER_H_ + +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* function prototypes */ +solver_bool solver_instance_correct(solver_data* general_solver_data, + solver_name given_name, + solver_string function_name); + +solver_string solver_name2string(solver_name name); + +solver_bool solver_func_call_allowed (solver_data* general_solver_data, + solver_state expected_state, + solver_string function_name); + +solver_string solver_state2string(solver_state state); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/SimulationRuntime/OMSI/solver/include/solver_kinsol.h b/SimulationRuntime/OMSI/solver/include/solver_kinsol.h new file mode 100644 index 00000000000..e4d9a7ad81e --- /dev/null +++ b/SimulationRuntime/OMSI/solver/include/solver_kinsol.h @@ -0,0 +1,133 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_kinsol.h + */ + +/** \addtogroup kinsol_SOLVER kinsol solver + * \ingroup NONLIN_SOLVER + * \{ */ + + +#ifndef _NONLINEARSOLVERKINSOL_H_ +#define _NONLINEARSOLVERKINSOL_H_ + +#include +#include +#include + +#include +#include + +/* Headers for sundials kinsol */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +struct solver_data_kinsol; + +/** + * User data used in kinsol functions. + */ +typedef struct kinsol_user_data { + void* user_data; + struct solver_data_kinsol* kinsol_data; +}kinsol_user_data; + + +/** + * Solver data for kinsol solver. + */ +typedef struct solver_data_kinsol { + void* kinsol_solver_object; /**< KINSOL memory block */ + kinsol_user_data* kin_user_data; /**< Pointer to user_data given to all kinsol functions */ + + residual_wrapper_func f_function_eval; /**< Pointer to function to evaluate residual of `f` */ + + N_Vector initial_guess; /**< Initial guess for first solver call, containing solution after solver call. */ + N_Vector u_scale; + N_Vector f_scale; + + DlsMat Jacobian; /**< Optional Jacobian matrix used by Kinsol. */ + + solver_int strategy; /**< Strategy used by KINSOL solver. Possible values: + `KIN_NONE`, `KIN_LINESEARCH`, `KIN_FP` or `KIN_PICARD` */ +}solver_data_kinsol; + + +/* Function prototypes */ +solver_status solver_kinsol_allocate_data(solver_data* general_solver_data); + +solver_status solver_kinsol_free_data(solver_data* general_solver_data); + +solver_status solver_kinsol_init_data(solver_data* general_solver_data, + residual_wrapper_func user_wrapper_res_function, + void* user_data); + +solver_status solver_kinsol_set_start_vector (solver_data* general_solver_data, + solver_real* initial_guess); + +solver_real* solver_kinsol_get_start_vector (solver_data* general_solver_data); + +solver_int solver_kinsol_residual_wrapper(N_Vector x, + N_Vector fval, + void* user_data_in); + +solver_state solver_kinsol_solve(void* specific_data); + +void solver_kinsol_get_x_element(void* solver_specififc_data, + solver_unsigned_int index, + solver_real* value); + +void solver_kinsol_set_jacobian_element(void* solver_specififc_data, + solver_unsigned_int row, + solver_unsigned_int column, + solver_real* value); + +solver_status solver_kinsol_scaling (solver_data* general_solver_data); + +solver_status solver_kinsol_error_handler(solver_data* solver, + solver_int flag, + solver_string function_name, + solver_string message); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif + +/** \} */ diff --git a/SimulationRuntime/OMSI/solver/include/solver_lapack.h b/SimulationRuntime/OMSI/solver/include/solver_lapack.h new file mode 100644 index 00000000000..9acec9e4521 --- /dev/null +++ b/SimulationRuntime/OMSI/solver/include/solver_lapack.h @@ -0,0 +1,126 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_lapack.h + */ + +/** \addtogroup LAPACK_SOLVER LAPACK solver + * \ingroup LIN_SOLVER + * + * \brief Linear solver using LAPACK routines. + * + * Using DGESV() function from LAPACK to solve `A*x=b` with square matrix `A`. + * [DGESV Documentation](http://www.netlib.org/lapack/explore-html/d7/d3b/group__double_g_esolve_ga5ee879032a8365897c3ba91e3dc8d512.html#ga5ee879032a8365897c3ba91e3dc8d512) + * + * \{ */ + + +#ifndef _LINEARSOLVERLAPACK_H_ +#define _LINEARSOLVERLAPACK_H_ + +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Struct for LAPACK solver specific data. + */ +typedef struct solver_data_lapack { + solver_int n; /**< Number of linear equations. */ + solver_int nrhs; /**< Number of right hand sides, always `1`. */ + solver_real* A; /**< Array of dimension (`lda`,`n`) containing matrix in + * row major order. */ + solver_int lda; /**< Leading dimension of array `A`. */ + solver_int* ipiv; /**< Array of dimension `n`, stores pivot indices for + * permutation matrix `P`. */ + solver_real* b; /**< Array of dimension (`ldb`, `nrhs`), containing right + * hand side of equation system in row major order on entry. + * On exit if `info=0` solution (`n` x `nrhs`) Matrix `X` */ + solver_int ldb; /**< Leading dimension of array `B`. */ + solver_int info; /**< `=0` if successful, `<0` if for `info=-i` the + * `i`-th diagonal element is singular. */ +} solver_data_lapack; + + +/* extern function prototypes */ +extern solver_int dgesv_(solver_int *n, solver_int *nrhs, solver_real *a, solver_int *lda, + solver_int *ipiv, solver_real *b, solver_int *ldb, solver_int *info); +extern solver_real ddot_(solver_int* n, solver_real* dx, solver_int* incx, solver_real* dy, solver_int* incy); + +/* function prototypes */ +solver_status solver_lapack_allocate_data(solver_data* general_solver_data); + +solver_status solver_lapack_free_data(solver_data* general_solver_data); + +solver_status solver_lapack_set_dim_data(solver_data* general_solver_data); + +void solver_lapack_get_A_element(void* solver_specififc_data, + solver_unsigned_int row, + solver_unsigned_int column, + solver_real* value); + +void solver_lapack_set_A_element(void* solver_specififc_data, + solver_unsigned_int row, + solver_unsigned_int column, + solver_real* value); + +void solver_lapack_get_b_element(void* solver_specififc_data, + solver_unsigned_int index, + solver_real* value); + +void solver_lapack_set_b_element(void* solver_specififc_data, + solver_unsigned_int index, + solver_real* value); + +void solver_lapack_get_x_element(void* specific_data, + solver_unsigned_int index, + solver_real* value); + +solver_state solver_lapack_solve(void* specific_data); + +void solver_lapack_print_data(solver_char* buffer, + solver_unsigned_int buffer_size, + solver_int* length, + solver_data* general_solver_data); + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif +#endif + +/** \} */ diff --git a/SimulationRuntime/OMSI/solver/src/solver_api.c b/SimulationRuntime/OMSI/solver/src/solver_api.c new file mode 100644 index 00000000000..470846d0514 --- /dev/null +++ b/SimulationRuntime/OMSI/solver/src/solver_api.c @@ -0,0 +1,803 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_api.c + * + * Application interface for OMSI solver. + */ + +/** \addtogroup SOLVER OMSI Solver Library + * \{ */ + +#include + +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif +/* set global functions */ +solver_callback_logger solver_logger; +solver_callback_allocate_memory solver_allocateMemory; +solver_callback_free_memory solver_freeMemory; + +/** + * \brief Set callback functions for memory management and logging. + * + * \param allocateMemoryFunction Pointer to function for memory allocation. + * \param freeMemoryFunction Pointer to function for memory deallocation. + * \param loggerFunction Pointer to function for logging. + */ +void solver_init_callbacks (solver_callback_allocate_memory allocateMemoryFunction, + solver_callback_free_memory freeMemoryFunction, + solver_callback_logger loggerFunction) { + + /* set global callback functions */ + solver_allocateMemory = allocateMemoryFunction; + solver_freeMemory = freeMemoryFunction; + solver_logger = loggerFunction; +} + + +/* + * ============================================================================ + * Memory management + * ============================================================================ + */ + + + +/** + * \brief Allocate memory for solver instance. + * + * \param [in] name Name of solver to use in this solver instance. + * \param [in] dim_n Dimension `n` of square matrix ´A´. + * \return Returns newly allocated `solver_data* solver` instance. + */ +solver_data* solver_allocate(solver_name name, + solver_unsigned_int dim_n) { + + /* Variables */ + solver_data* solver; + solver_linear_callbacks* lin_callbacks; + solver_non_linear_callbacks* non_lin_callbacks; + + /* allocate memory */ + solver = (solver_data*) solver_allocateMemory(1, sizeof(solver_data)); + + /* set dimension */ + solver->dim_n = dim_n; + + /* Set solver specific data */ + switch (name) { + case solver_lapack: + solver->name = solver_lapack; + solver_lapack_allocate_data(solver); + break; + case solver_kinsol: + solver->name = solver_kinsol; + solver_kinsol_allocate_data(solver); + break; + default: + solver_logger(log_solver_error, "In function solver_allocate: No valid solver_name given."); + solver_freeMemory(solver); + return NULL; + } + + /* set callback functions */ + switch (name) { + case solver_lapack: + lin_callbacks = (solver_linear_callbacks*) solver_allocateMemory(1, sizeof(solver_linear_callbacks)); + + lin_callbacks->get_A_element = &solver_lapack_get_A_element; + lin_callbacks->set_A_element = &solver_lapack_set_A_element; + + lin_callbacks->get_b_element = &solver_lapack_get_b_element; + lin_callbacks->set_b_element = &solver_lapack_set_b_element; + + lin_callbacks->get_x_element = &solver_lapack_get_x_element; + + lin_callbacks->solve_eq_system = &solver_lapack_solve; + + solver->solver_callbacks = lin_callbacks; + break; + case solver_kinsol: + non_lin_callbacks = (solver_non_linear_callbacks*) solver_allocateMemory(1, sizeof(solver_non_linear_callbacks)); + non_lin_callbacks->solve_eq_system = solver_kinsol_solve; + non_lin_callbacks->get_x_element = solver_kinsol_get_x_element; + non_lin_callbacks->set_jacobian_element = solver_kinsol_set_jacobian_element; + solver->solver_callbacks = non_lin_callbacks; + break; + default: + solver_logger(log_solver_error, "In function solver_allocate: No valid solver_name given."); + solver_freeMemory(solver); + return NULL; + } + + /* Set solver state */ + solver->state = solver_initializated; + solver_logger(log_solver_all, "Solver instance allocated."); + + return solver; + +} + + +/** \brief Free memory of struct solver_data. + * + * \param [in,out] solver Pointer to solver instance. + */ +void solver_free(solver_data* solver) { + + /* free solver specific data */ + switch (solver->name) { + case solver_lapack: + solver_lapack_free_data(solver); + break; + case solver_kinsol: + solver_kinsol_free_data(solver); + break; + default: + if (solver->specific_data != NULL) { + solver_logger(log_solver_error, "In function solver_free: No solver" + "specified in solver_name, but solver->specific_data is not NULL"); + } + } + + solver_freeMemory(solver->solver_callbacks); + solver_freeMemory(solver); +} + + +/** + * \brief Prepare specific solver data. + * + * E.g. set dimensions for matrices or functions. + * + * \param [in] solver Pointer to solver instance. + * \param [in] user_wrapper_res_function Pointer to wrapper function for residual function.
+ * Only used for kinsol solver. + * \param [in] user_data Pointer to user supplied data.
+ * Only used by kinsol solver. + * \return Returns `solver_status` `solver_okay` if solved successful, + * otherwise `solver_error`. + */ +solver_status solver_prepare_specific_data (solver_data* solver, + residual_wrapper_func user_wrapper_res_function, + void* user_data) { + + switch (solver->name) { + case solver_lapack: + solver->linear = solver_true; + return solver_lapack_set_dim_data(solver); + case solver_kinsol: + solver->linear = solver_false; + return solver_kinsol_init_data(solver, user_wrapper_res_function, user_data); + default: + solver_logger(log_solver_error, "In function prepare_specific_solver_data:" + "No solver specified in solver_name."); + return solver_error; + } +} + + +/* + * ============================================================================ + * Getters and setters + * ============================================================================ + */ + +/** + * \brief Set initial guess for start vector for non-linear solver. + * + * \param [in] solver Pointer to solver instance. + * \param [in] initial_guess Array of length solver->dim_n containing initial guess. + * \return Returns `solver_status` `solver_okay` if solved successful, + * otherwise `solver_error`. + */ +solver_status solver_set_start_vector (solver_data* solver, + solver_real* initial_guess) { + + switch (solver->name) { + case solver_lapack: + solver_logger(log_solver_warning, "In function solver_set_start_vector:" + "Linear solver LAPACK does not need a start vector. Ignoring function call."); + return solver_warning; + case solver_kinsol: + solver_kinsol_set_start_vector (solver, initial_guess); + break; + default: + solver_logger(log_solver_error, "In function solver_set_start_vector:" + "No solver specified in solver_name."); + return solver_error; + } + + return solver_ok; +} + + +/** + * \brief Get pointer to initial guess for start vector for non-linear solver. + * + * \param [in] solver Pointer to solver instance. + * \return `solver_real *` Returns pointer to initial_guess if successful, + * otherwise `NULL`. + */ +solver_real* solver_get_start_vector (solver_data* solver) +{ + switch (solver->name) { + case solver_lapack: + solver_logger(log_solver_warning, "In function solver_set_start_vector:" + "Linear solver LAPACK does not need a start vector. Ignoring function call."); + return NULL; + case solver_kinsol: + return solver_kinsol_get_start_vector(solver); + default: + solver_logger(log_solver_error, "In function solver_set_start_vector:" + "No solver specified in solver_name."); + return NULL; + } +} + + +/** \brief Set matrix A with values from array value. + * + * Sets specified columns and rows of matrix A in solver specific data to + * values from array value. If no columns and/or rows are specified (set to + * NULL) all elements in those rows / columns are set to given values. + * + * e.g set_matrix_A(solver, [1,2], 2, [2,3,5], 3, [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]); + * will set n-times-n matrix A, for some n>= 5, to something like:
+ * / a_11 a_12 a_13 ... \
+ * | 0.1 0.2 a_23 |
+ * | 0.3 0.4 a_33 |
+ * A = | a_41 a_42 a_43 |
+ * | 0.5 0.6 a_53 |
+ * \ ... ... /
+ * + * \param [in,out] solver Struct with used solver, containing matrix A in + * solver specific format. Has to be a linear solver. + * \param [in] column Array of dimension `n_column` of unsigned integers, + * specifying which columns of matrix A to get. If + * column equals `NULL`, get the first `n_column` + * columns of A. + * \param [in] n_column Size of array `column`. Must be greater then 0 + * and less or equal to number of columns of matrix A. + * \param [in] row Array of dimension `n_row` of unsigned integers, + * specifying which rows of matrix A to get. If rows + * equals `NULL`, get the first `n_row` rows of A. + * \param [in] n_row Size of array `row`. Must be greater then 0 and + * less or equal to number of rows of matrix A. + * \param [in] value Pointer to matrix with values, stored as array + * in column-major order of size `n_column*n_row`. + */ +void solver_set_matrix_A(const solver_data* solver, + const solver_unsigned_int* column, + const solver_unsigned_int n_column, + const solver_unsigned_int* row, + const solver_unsigned_int n_row, + solver_real* value) +{ + /* Variables */ + solver_unsigned_int i, j; + solver_linear_callbacks* lin_callbacks; + + if (!solver->linear) { + /* ToDo: log error, no matrix A in non-linear case */ + return; + } + + lin_callbacks = solver->solver_callbacks; + + if (column==NULL && row==NULL) { + /* copy values element wise */ + for (i=0; iset_A_element(solver->specific_data, i, j, &value[i+j*solver->dim_n]); + } + } + } + else if (column==NULL && row != NULL) { + for (i=0; iset_A_element(solver->specific_data, i, row[j], &value[i+j*solver->dim_n]); + } + } + } + else if (column!=NULL && row == NULL) { + for (i=0; iset_A_element(solver->specific_data, column[i], j, &value[i+j*solver->dim_n]); + } + } + } + else { + for (i=0; iset_A_element(solver->specific_data, column[i], row[j], &value[i+j*solver->dim_n]); + } + } + } +} + + +/** \brief Read matrix A and saves result in array value. + * + * Used for linear solvers, to get values of matrix A stored in its solver + * specific data. + * + * \param [in] solver Struct with used solver, containing matrix A in + * solver specific format. Has to be a linear solver. + * \param [in] column Array of dimension `n_column` of unsigned integers, + * specifying which columns of matrix A to get. If + * column equals `NULL`, get the first `n_column` + * columns of A. + * \param [in] n_column Size of array `column`. Must be greater then 0 + * and less or equal to number of columns of matrix A. + * \param [in] row Array of dimension `n_row` of unsigned integers, + * specifying which rows of matrix A to get. If rows + * equals `NULL`, get the first `n_row` rows of A. + * \param [in] n_row Size of array `row`. Must be greater then 0 and + * less or equal to number of rows of matrix A. + * \param [in,out] value On input: Pointer to allocated memory of size + * `sizeof(solver_real)*n_column*n_row`.
+ * On output: Pointer to array containing specified + * columns and rows of matrix A in row-major-order. + */ +void solver_get_matrix_A(solver_data* solver, + solver_unsigned_int* column, + solver_unsigned_int n_column, + solver_unsigned_int* row, + solver_unsigned_int n_row, + solver_real* value) +{ + /* Variables */ + solver_unsigned_int i, j; + solver_linear_callbacks* lin_callbacks; + + lin_callbacks = solver->solver_callbacks; + + if (column==NULL && row==NULL) { + /* copy values element wise */ + for (i=0; iget_A_element(solver->specific_data, i, j, &value[i*solver->dim_n+j]); + } + } + } + else if (column==NULL && row != NULL) { + for (i=0; iget_A_element(solver->specific_data, i, row[j], &value[i*solver->dim_n+j]); + } + } + } + else if (column!=NULL && row == NULL) { + for (i=0; iget_A_element(solver->specific_data, column[i], j, &value[i*solver->dim_n+j]); + } + } + } + else { + for (i=0; iget_A_element(solver->specific_data, column[i], row[j], &value[i*solver->dim_n+j]); + } + } + } +} + + + +/** \brief Set values of vector b with values from `value`. + * + * Used for right hand side vector `b` of linear systems `A*x=b`. + * + * \param [in,out] solver Struct with used solver, containing vector `b` in + * solver specific format. Has to be a linear solver. + * \param [in] index Array of indices of `b` to set. If `NULL` for all + * indices up to `n_index` vector b will be returned. + * \param [in] n_index Size of index array `index`. + * \param [in] value Pointer to vector with values, stored as array + * of size `n_index`. + */ +void solver_set_vector_b (solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int n_index, + solver_real* value) { + + /* Variables */ + solver_unsigned_int i; + solver_linear_callbacks* lin_callbacks; + + lin_callbacks = solver->solver_callbacks; + + if (index==NULL) { + for (i=0; iset_b_element(solver->specific_data, i, &value[i]); + } + } + else { + for (i=0; iset_b_element(solver->specific_data, index[i], &value[i]); + } + } +} + + +/** \brief Get values of vector b with values from `value`. + * + * Used for right hand side vector `b` of linear systems `A*x=b`. + * + * \param [in] solver Struct with used solver, containing vector `b` in + * solver specific format. Has to be a linear solver. + * \param [in] index Array of indices of `b` to set. If `NULL` for all + * indices up to `n_index` vector b will be set. + * \param [in] n_index Size of index array `index`. + * \param [in,out] values On input: Pointer to allocated memory of size + * `n_index`.
+ * On output: Pointer to array containing specified + * values of vector `b`. + */ +void solver_get_vector_b (solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int n_index, + solver_real* values) { + + /* Variables */ + solver_unsigned_int i; + solver_linear_callbacks* lin_callbacks; + + lin_callbacks = solver->solver_callbacks; + + if (index==NULL) { + for (i=0; iget_b_element(solver->specific_data, i, &values[i]); + } + } + else { + for (i=0; iget_b_element(solver->specific_data, index[i], &values[i]); + } + } +} + + +/** \brief Set jacobian matrix with values from array value. + * + * Sets specified columns and rows of jacobian matrix in solver specific data to + * values from array value. If no columns and/or rows are specified (set to + * NULL) all elements in those rows / columns are set to given values. + * + * \param [in,out] solver Struct with used solver, containing jacobian matrix in + * solver specific format. Has to be a linear solver. + * \param [in] column Array of dimension `n_column` of unsigned integers, + * specifying which columns of jacobian matrix to get. If + * column equals `NULL`, get the first `n_column` + * columns of jacobian. + * \param [in] n_column Size of array `column`. Must be greater then 0 + * and less or equal to number of columns of jacobian matrix. + * \param [in] row Array of dimension `n_row` of unsigned integers, + * specifying which rows of jacobian matrix to get. If rows + * equals `NULL`, get the first `n_row` rows of jacobian. + * \param [in] n_row Size of array `row`. Must be greater then 0 and + * less or equal to number of rows of jacobian matrix. + * \param [in] value Pointer to matrix with values, stored as array + * in column-major order of size `n_column*n_row`. + */ +void solver_set_Jacobian(const solver_data* solver, + const solver_unsigned_int* column, + const solver_unsigned_int n_column, + const solver_unsigned_int* row, + const solver_unsigned_int n_row, + solver_real* value) +{ + /* Variables */ + solver_unsigned_int i, j; + solver_non_linear_callbacks* non_lin_callbacks; + + if (solver->linear) { + /* ToDo: log error, no jacobian in linear case */ + return; + } + + non_lin_callbacks = solver->solver_callbacks; + + if (column==NULL && row==NULL) { + /* copy values element wise */ + for (i=0; iset_jacobian_element(solver->specific_data, i, j, &value[i+j*solver->dim_n]); + } + } + } + else if (column==NULL && row != NULL) { + for (i=0; iset_jacobian_element(solver->specific_data, i, row[j], &value[i+j*solver->dim_n]); + } + } + } + else if (column!=NULL && row == NULL) { + for (i=0; iset_jacobian_element(solver->specific_data, column[i], j, &value[i+j*solver->dim_n]); + } + } + } + else { + for (i=0; iset_jacobian_element(solver->specific_data, column[i], row[j], &value[i+j*solver->dim_n]); + } + } + } +} + + + +/** + * \brief Get solution `x` of linear problem `A*x=b`. + * + * \param [in] solver Struct containing solution in solver specific + * format. Has to be a linear solver. + * \param [in] index Array of indices of `x` to get. If `NULL` get + * solution for all indices up to `n_index`. + * \param [in] n_index Size of index array `index`. + * \param [in,out] values On input: Pointer to allocated memory of size + * `n_index`.
+ * On output: Pointer to array containing specified + * values of vector `x`. + */ +void solver_get_lin_solution(solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int n_index, + solver_real* values) { + + /* Variables */ + solver_unsigned_int i; + solver_linear_callbacks* lin_callbacks; + + lin_callbacks = solver->solver_callbacks; + + if (index==NULL) { + for (i=0; iget_x_element(solver->specific_data, i, &values[i]); + } + } + else { + for (i=0; iget_x_element(solver->specific_data, index[i], &values[i]); + } + } +} + + + +/** + * \brief Get solution `x` of non-linear problem `f(x)=0`. + * + * \param [in] solver Struct with used solver, containing solution in + * solver specific format. Has to be a non-linear solver. + * \param [in] index Array of indices of `x` to get. If `NULL` get + * solution for all indices up to `n_index`. + * \param [in] n_index Size of index array `index`. + * \param [in,out] values On input: Pointer to allocated memory of size + * `n_index`.
+ * On output: Pointer to array containing specified + * values of vector `x`. + */ +void solver_get_nonlin_solution(solver_data* solver, + solver_unsigned_int* index, + solver_unsigned_int n_index, + solver_real* values) { + + /* Variables */ + solver_unsigned_int i; + solver_non_linear_callbacks* callbacks; + + callbacks = solver->solver_callbacks; + + if (index==NULL) { + for (i=0; iget_x_element(solver->specific_data, i, &values[i]); + } + } + else { + for (i=0; iget_x_element(solver->specific_data, index[i], &values[i]); + } + } +} + + + +/** + * \brief Return solver name as string. + * + * \param [in] solver Pointer to solver instance. + * \return String with solver name. + */ +solver_string solver_get_name (solver_data* solver) { + + return solver_name2string(solver->name); +} + + +/* + * ============================================================================ + * Print and debug functions + * ============================================================================ + */ + +/** + * Print all data in solver_instance. + * + * \param [in] solver Solver instance. + * \param [in] header String for header of printed output. Can be NULL. + */ +void solver_print_data (solver_data* solver, + solver_string header) { + + /* Variables */ + solver_char buffer[MAX_BUFFER_SIZE] = ""; + solver_int length; + solver_linear_callbacks* lin_callbacks; + + length = 0; + if (header) { + length += snprintf(buffer, MAX_BUFFER_SIZE-length, header); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, "\n"); + } + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "Solver data print:\n"); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t name: \t %s\n", solver_name2string(solver->name)); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t linear: %s\n", solver->linear ? "solver_true":"solver_false"); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t info: \t %d\n", solver->info); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t dim_n:\t %u\n", solver->dim_n); + + switch (solver->name) { + case solver_lapack: + solver_lapack_print_data(buffer, MAX_BUFFER_SIZE, &length, solver); + break; + default: + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "No solver specific data.\n"); + break; + } + + if (length >= MAX_BUFFER_SIZE*0.5) { + solver_logger(log_solver_all, buffer); + length = 0; + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, "Solver data print continue:\n"); + } + + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t solver_callbacks set: \t\t %s \t ( Address: %x )\n", solver->solver_callbacks?"yes":"no", solver->solver_callbacks); + switch (solver->linear) { + case solver_true: + lin_callbacks = solver->solver_callbacks; + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t\t get_A_element set: \t %s \t ( Address: %x )\n", lin_callbacks->get_A_element?"yes":"no", lin_callbacks->get_A_element); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t\t set_A_element set: \t %s \t ( Address: %x )\n", lin_callbacks->set_A_element?"yes":"no", lin_callbacks->set_A_element); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t\t get_b_element set: \t %s \t ( Address: %x )\n", lin_callbacks->get_b_element?"yes":"no", lin_callbacks->get_b_element); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t\t set_b_element set: \t %s \t ( Address: %x )\n", lin_callbacks->set_b_element?"yes":"no", lin_callbacks->set_b_element); + length += snprintf(buffer+length, MAX_BUFFER_SIZE-length, + "\t\t solve_eq_system set: \t %s \t ( Address: %x )\n", lin_callbacks->solve_eq_system?"yes":"no", lin_callbacks->solve_eq_system); + break; + default: + + break; + } + + /* print buffer */ + solver_logger(log_solver_all, buffer); +} + + +/* + * ============================================================================ + * Solve call + * ============================================================================ + */ + +/** + * \brief Call solve function for registered linear solver. + * + * Checks if all necessary data is already set and solves linear equation system + * with registered linear solver. + * + * \param solver Solver instance. + * \return Returns `solver_status` `solver_okay` if solved successful, + * otherwise `solver_error`. + */ +solver_status solver_linear_solve(solver_data* solver) { + + /* Variables */ + solver_linear_callbacks* lin_callbacks; + + + /* Check if solver is ready */ + if (!solver_func_call_allowed (solver, solver_ready, "solver_linear_solver")) { + return solver_error; + } + + lin_callbacks = solver->solver_callbacks; + + /* Call solve function */ + return lin_callbacks->solve_eq_system(solver->specific_data); +} + + +/** + * \brief Call solve function for registered non-linear solver. + * + * Checks if all necessary data is already set and solves linear or non-linear + * equation system with the registered non-linear solver. + * + * \param solver Solver instance. + * \return Returns `solver_status` `solver_okay` if solved successful, + * otherwise `solver_error`. + */ +solver_status solver_non_linear_solve(solver_data* solver) { + + /* Variables */ + solver_non_linear_callbacks* non_lin_callbacks; + + + /* Check if solver is ready */ + if (!solver_func_call_allowed (solver, solver_ready, "solver_non_linear_solver")) { + return solver_error; + } + + non_lin_callbacks = solver->solver_callbacks; + + /* Call solve function */ + return non_lin_callbacks->solve_eq_system(solver->specific_data); +} + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + + +/** \} */ diff --git a/SimulationRuntime/OMSI/solver/src/solver_helper.c b/SimulationRuntime/OMSI/solver/src/solver_helper.c new file mode 100644 index 00000000000..3189fdee5e3 --- /dev/null +++ b/SimulationRuntime/OMSI/solver/src/solver_helper.c @@ -0,0 +1,118 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_helper.c + * + * Helper functions for OMSI solver. + */ + +/** @addtogroup SOLVER OMSI Solver Library + * @{ */ + +#include + +solver_bool solver_instance_correct(solver_data* general_solver_data, + solver_name given_name, + solver_string function_name) { + + if (general_solver_data->name != given_name) { + solver_logger(log_solver_error, "In function %s:" + "Solver instance is not %s.", + function_name, + solver_name2string(given_name)); + general_solver_data->state = solver_error_state; + return solver_false; + } + + return solver_true; +} + + +solver_string solver_name2string(solver_name name) { + + switch (name) { + case solver_lapack: + return "LAPACK"; + case solver_newton: + return "Newton"; + case solver_kinsol: + return "SUNDIALS KINSOL"; + case solver_extern: + return "Extern solver"; + case solver_unregistered: + return "No solver name set"; + default: + return "Unknown solver name"; + } +} + + +solver_bool solver_func_call_allowed (solver_data* general_solver_data, + solver_state expected_state, + solver_string function_name) { + + if (general_solver_data->state != expected_state) { + solver_logger(log_solver_error, "In function %s: " + "Function call was not allowed for current state %s. " + "Expected state %s.", + function_name, + solver_state2string(general_solver_data->state), + solver_state2string(expected_state)); + general_solver_data->state = solver_error_state; + return solver_false; + } + + return solver_true; +} + + +solver_string solver_state2string(solver_state state) { + + switch (state) { + case solver_uninitialized: + return "solver_uninitialized"; + case solver_instantiated: + return "solver_instantiated"; + case solver_initializated: + return "solver_initializated"; + case solver_ready: + return "solver_ready"; + case solver_finished_ok: + return "solver_finished_ok"; + case solver_finished_error: + return "solver_finished_error"; + case solver_error_state: + return "solver_error_state"; + default: + return "Unknown solver state"; + } +} + +/** @} */ diff --git a/SimulationRuntime/OMSI/solver/src/solver_kinsol.c b/SimulationRuntime/OMSI/solver/src/solver_kinsol.c new file mode 100644 index 00000000000..84b2a279926 --- /dev/null +++ b/SimulationRuntime/OMSI/solver/src/solver_kinsol.c @@ -0,0 +1,624 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_kinsol.c + * + * Solver specific functions for kinsol solver. + */ + +/** @addtogroup kinsol_SOLVER kinsol solver + * \ingroup NONLIN_SOLVER + * @{ */ + +#include + +#define UNUSED(x) (void)(x) /* ToDo: delete later */ + +/* + * ============================================================================ + * Allocaten, Initialization and freeing of solver_specific_data + * ============================================================================ + */ + + +/** + * Allocates memory for kinsol specific solver data and saves it in solver instance. + * + * \param [in,out] general_solver_data Solver instance. + * \return solver_status solver_ok on success and + * solver_error on failure. + */ +solver_status solver_kinsol_allocate_data(solver_data* general_solver_data) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + solver_real* u_scale; + solver_real* f_scale; + + /* Check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_kinsol, "allocate_kinsol_data")) { + return solver_error; + } + + /* Check if general_solver_data has already specific data */ + if (general_solver_data->specific_data!=NULL) { + solver_logger(log_solver_error, "In function allocate_kinsol_data: Pointer to solver specific data is not NULL."); + general_solver_data->state = solver_error_state; + return solver_error; + } + + /* Allocate memory */ + kinsol_data = (solver_data_kinsol*) solver_allocateMemory(1, sizeof(solver_data_kinsol)); + if (!kinsol_data) { + solver_logger(log_solver_error, "In function allocate_kinsol_data: Can't allocate memory for kinsol_data."); + general_solver_data->specific_data = NULL; + general_solver_data->state = solver_error_state; + return solver_error; + } + + /* Create Kinsol solver object */ + kinsol_data->kinsol_solver_object = KINCreate(); + if (kinsol_data->kinsol_solver_object == NULL) { + solver_logger(log_solver_error, "In function allocate_kinsol_data: Could not create KINSOL solver object."); + solver_freeMemory(kinsol_data); + general_solver_data->specific_data = NULL; + general_solver_data->state = solver_error_state; + return solver_error; + } + + kinsol_data->f_function_eval = NULL; + + kinsol_data->initial_guess = N_VNewEmpty_Serial(general_solver_data->dim_n); + + u_scale = (solver_real*) solver_allocateMemory(general_solver_data->dim_n, sizeof(solver_real)); + kinsol_data->u_scale = N_VMake_Serial(general_solver_data->dim_n, u_scale); + + f_scale = (solver_real*) solver_allocateMemory(general_solver_data->dim_n, sizeof(solver_real)); + kinsol_data->f_scale = N_VMake_Serial(general_solver_data->dim_n, f_scale); + + general_solver_data->specific_data = kinsol_data; + general_solver_data->state = solver_instantiated; + + return solver_ok; +} + + +/** + * \brief Set initial guess for vector `x`. + * + * \param [in,out] general_solver_data Solver instance. + * \param [in] initial_guess Array with initial guess for vector `x` to start iteration. + * Has length general_solver_data->dim_n + * \return solver_status solver_ok on success and + * solver_error on failure. + */ +solver_status solver_kinsol_set_start_vector (solver_data* general_solver_data, + solver_real* initial_guess) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + + /* check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_kinsol, "solver_kinsol_free_data")) { + return solver_error; + } + + kinsol_data = general_solver_data->specific_data; + + /* Set initial_guess vector */ + NV_DATA_S(kinsol_data->initial_guess) = initial_guess; + + return solver_ok; +} + + +solver_real* solver_kinsol_get_start_vector (solver_data* general_solver_data) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + + kinsol_data = general_solver_data->specific_data; + + return NV_DATA_S(kinsol_data->initial_guess); +} + + +/** + * Set dimension `dim_n` of function `f` in kinsol specific solver data. + * + * \param [in,out] general_solver_data Solver instance. + * \param [in] user_wrapper_res_function User provided residual wrapper function. + * \param [in] user_data Pointer to `user_data` needed in user provided + * residual wrapper function. Can be `NULL`. + * \return solver_status `solver_ok` on success and + * `solver_error` on failure. + */ +solver_status solver_kinsol_init_data(solver_data* general_solver_data, + residual_wrapper_func user_wrapper_res_function, + void* user_data) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + solver_int flag; + + /* check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_kinsol, "solver_kinsol_free_data")) { + return solver_error; + } + + /* Access data */ + kinsol_data = general_solver_data->specific_data; + + if (kinsol_data->initial_guess == NULL) { + solver_logger(log_solver_error, "In function kinsol_init_data: Initial guess not set. " + "Use API function solver_set_start_vector to set initial guess.."); + general_solver_data->state = solver_error_state; + return solver_error; + } + + /* Set Kinsol print level */ + flag = KINSetPrintLevel(kinsol_data->kinsol_solver_object, 0); + if (flag != KIN_SUCCESS) { + return solver_kinsol_error_handler(general_solver_data, flag, + "kinsol_init_data", + "Could not set print level."); + } + + /* Set KINSOL user data */ + kinsol_data->kin_user_data = (kinsol_user_data*) solver_allocateMemory(1, sizeof(kinsol_user_data)); + kinsol_data->kin_user_data->user_data = user_data; + kinsol_data->kin_user_data->kinsol_data = kinsol_data; + flag = KINSetUserData(kinsol_data->kinsol_solver_object, kinsol_data->kin_user_data); + if (flag != KIN_SUCCESS) { + return solver_kinsol_error_handler(general_solver_data, flag, + "kinsol_init_data", + "Could not set KINSOL user data."); + } + + /* Set user supplied wrapper function */ + kinsol_data->f_function_eval = user_wrapper_res_function; + + /* Set problem-defining function and initialize KINSOL*/ + flag = KINInit(kinsol_data->kinsol_solver_object, + solver_kinsol_residual_wrapper, + kinsol_data->initial_guess); + if (flag != KIN_SUCCESS) { + return solver_kinsol_error_handler(general_solver_data, flag, + "kinsol_init_data", + "Could not initialize KINSOL solver object."); + } + + /* Set KINSOL strategy */ + kinsol_data->strategy = KIN_LINESEARCH; + + /* Create Jacobian matrix object */ + + + + /* Create linear solver object */ + + + + /* Attach linear solver module */ + flag = KINDense(kinsol_data->kinsol_solver_object, general_solver_data->dim_n); + if (flag != KIN_SUCCESS) { + return solver_kinsol_error_handler(general_solver_data, flag, + "kinsol_init_data", + "Could not initialize KINSOL solver object."); + } + + /* Set scaling vectors */ + solver_kinsol_scaling(general_solver_data); + + /* Set state and exit*/ + general_solver_data->state = solver_initializated; + return solver_ok; +} + + +/** + * \brief Frees kinsol specific solver data. + * + * \param [in,out] general_solver_data Solver instance. + * \return solver_status solver_ok on success and + * solver_error on failure. + */ +solver_status solver_kinsol_free_data(solver_data* general_solver_data) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + + /* check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_kinsol, "kinsol_free_data")) { + return solver_error; + } + + kinsol_data = general_solver_data->specific_data; + + /* Free data */ + KINFree((void*)kinsol_data); + solver_freeMemory(kinsol_data->kin_user_data); + + solver_freeMemory(NV_DATA_S(kinsol_data->initial_guess)); /* ToDo: Is it smart to free a user supplied aray??? + Well the free Function is also provided by user, so it should work any way... + Maybe... */ + N_VDestroy_Serial(kinsol_data->initial_guess); + + solver_freeMemory(NV_DATA_S(kinsol_data->u_scale)); + N_VDestroy_Serial(kinsol_data->u_scale); + + solver_freeMemory(NV_DATA_S(kinsol_data->f_scale)); + N_VDestroy_Serial(kinsol_data->f_scale); + + solver_freeMemory(kinsol_data); + + /* Set solver state */ + general_solver_data->state = solver_uninitialized; + return solver_ok; +} + + +/* + * ============================================================================ + * Kinsol wrapper functions + * ============================================================================ + */ + +/** + * \brief Computes system function `f` of non-linear problem. + * + * This function is of type `KINSysFn` and will be used by Kinsol solver + * to evaluate `f(x)` + * + * \param [in] x Dependent variable vector `x` + * \param [out] fval Set fval to `f(x)`. + * \param [in,out] user_data_in + * \return solver_int Return value is ignored from Kinsol. + */ +solver_int solver_kinsol_residual_wrapper(N_Vector x, + N_Vector fval, + void* user_data_in) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + solver_real* x_data; + solver_real* fval_data; + kinsol_user_data* user_data; + + /* Access input data */ + user_data = (kinsol_user_data*) user_data_in; + kinsol_data = user_data->kinsol_data; + x_data = NV_DATA_S(x); + fval_data = NV_DATA_S(fval); + + /* Call residual function */ + kinsol_data->f_function_eval(x_data, fval_data, user_data->user_data); + + /* Log function call */ + + + return 0; +} + + +/** + * \brief Wrapper function for KINSOL to compute dense Jacobian + * + * Computes dense Jacobian `J(u)` using `omsi_function` + * `algebraic_system_t->jacobian`. + * + * @param N + * @param u + * @param fu + * @param J + * @param user_data + * @param tmp1 + * @param tmp2 + * @return + */ +solver_int solver_kinsol_jacobian_wrapper(long int N, + N_Vector u, + N_Vector fu, + DlsMat J, + void* user_data, + N_Vector tmp1, + N_Vector tmp2) +{ + + /* ToDo: Insert smart stuff here */ + UNUSED(N); + UNUSED(u); + UNUSED(fu); + UNUSED(J); + UNUSED(user_data); + UNUSED(tmp1); + UNUSED(tmp2); + + return -1; +} + + + + + + + + +/* + * ============================================================================ + * Solve call + * ============================================================================ + */ + +solver_state solver_kinsol_solve(void* specific_data) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + solver_int flag; + + kinsol_data = specific_data; + + /* ToDo: Scale f and x */ + + /* Solver call */ + flag = KINSol(kinsol_data->kinsol_solver_object, + kinsol_data->initial_guess, + kinsol_data->strategy, + kinsol_data->u_scale, + kinsol_data->f_scale); + + if (flag != KIN_SUCCESS) { + return solver_kinsol_error_handler(NULL, flag, + "solver_kinsol_solve", + "Error while solving equation system."); + } + + return solver_ok; +} + + + +/* + * ============================================================================ + * Getters and setters + * ============================================================================ + */ + +void solver_kinsol_get_x_element(void* solver_specififc_data, + solver_unsigned_int index, + solver_real* value) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + solver_real* x_vector; + + kinsol_data = solver_specififc_data; + + /* Access initial_guess(index) */ + x_vector = N_VGetArrayPointer(kinsol_data->initial_guess); + value[0]=x_vector[index]; +} + + +void solver_kinsol_set_jacobian_element(void* solver_specififc_data, + solver_unsigned_int row, + solver_unsigned_int column, + solver_real* value) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + + kinsol_data = solver_specififc_data; + + /* Set element Jacobian(row,column) to value */ + DENSE_ELEM(kinsol_data->Jacobian, row, column)=*value; +} + + +/* + * ============================================================================ + * Helper functions + * ============================================================================ + */ + +solver_status solver_kinsol_scaling(solver_data* general_solver_data) +{ + /* Variables */ + solver_data_kinsol* kinsol_data; + solver_real* u_scale_data; + solver_real* f_scale_data; + + solver_unsigned_int i; + + kinsol_data = general_solver_data->specific_data; + + f_scale_data = NV_DATA_S(kinsol_data->f_scale); + u_scale_data = NV_DATA_S(kinsol_data->u_scale); + + for (i=0; idim_n; i++) { + u_scale_data[i] = 1; /* ToDo: Do smarter stuff here */ + f_scale_data[i] = 1; + } + + return solver_ok; +} + + + + + + + + +solver_status solver_kinsol_error_handler(solver_data* solver, + solver_int flag, + solver_string function_name, + solver_string message) { + + /* Set error state */ + if (solver != NULL) { + if (flag < 0) { + solver->state = solver_error_state; + } + } + + /* Log error message */ + switch (flag) { + case KIN_SUCCESS: + return solver_ok; + + case KIN_INITIAL_GUESS_OK: + return solver_ok; + + case KIN_STEP_LT_STPTOL: + solver_logger(log_solver_warning, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_STEP_LT_STPTOL", + function_name, message); + return solver_warning; + + case KIN_MEM_NULL: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_MEM_NULL", + function_name, message); + return solver_error; + + case KIN_ILL_INPUT: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_ILL_INPUT", + function_name, message); + return solver_error; + + case KIN_NO_MALLOC: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_NO_MALLOC", + function_name, message); + return solver_error; + + case KIN_MEM_FAIL: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_MEM_FAIL", + function_name, message); + return solver_error; + + case KIN_LINESEARCH_NONCONV: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_LINESEARCH_NONCONV", + function_name, message); + return solver_error; + + case KIN_MAXITER_REACHED: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_MAXITER_REACHED", + function_name, message); + return solver_error; + + case KIN_MXNEWT_5X_EXCEEDED: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_MXNEWT_5X_EXCEEDED", + function_name, message); + return solver_error; + + case KIN_LINESEARCH_BCFAIL: + solver_logger(log_solver_warning, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_LINESEARCH_BCFAIL", + function_name, message); + return solver_warning; + + case KIN_LINSOLV_NO_RECOVERY: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_LINSOLV_NO_RECOVERY", + function_name, message); + return solver_error; + + case KIN_LINIT_FAIL: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_LINIT_FAIL", + function_name, message); + return solver_error; + + case KIN_LSETUP_FAIL: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_LSETUP_FAIL", + function_name, message); + return solver_error; + + case KIN_LSOLVE_FAIL: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_LSOLVE_FAIL", + function_name, message); + return solver_error; + + case KIN_SYSFUNC_FAIL: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_SYSFUNC_FAIL", + function_name, message); + return solver_error; + + case KIN_FIRST_SYSFUNC_ERR: + solver_logger(log_solver_warning, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_FIRST_SYSFUNC_ERR", + function_name, message); + return solver_warning; + + case KIN_REPTD_SYSFUNC_ERR: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: KIN_REPTD_SYSFUNC_ERR", + function_name, message); + return solver_error; + + default: + solver_logger(log_solver_error, + "Warning in function %s: %s\n" + "\tKINSOL_ERROR: unknown ERROR", + function_name, message); + return solver_error; + + /* ToDo: Add more error cases */ + } +} + + +/** @} */ diff --git a/SimulationRuntime/OMSI/solver/src/solver_lapack.c b/SimulationRuntime/OMSI/solver/src/solver_lapack.c new file mode 100644 index 00000000000..e5e04bfb6ab --- /dev/null +++ b/SimulationRuntime/OMSI/solver/src/solver_lapack.c @@ -0,0 +1,404 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) + * Public License (OSMC-PL) are obtained from OSMC, either from the above + * address, from the URLs: http://www.openmodelica.org or + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica + * distribution. GNU version 3 is obtained from: + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: + * http://www.opensource.org/licenses/BSD-3-Clause. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE + * CONDITIONS OF OSMC-PL. + * + */ + +/** \file solver_lapack.c + * + * Solver specific functions for LAPACK solver. + */ + +/** @addtogroup LAPACK_SOLVER LAPACK solver + * \ingroup LIN_SOLVER + * @{ */ + + +#include + +/* + * ============================================================================ + * Allocaten, Initialization and freeing of solver_specific_data + * ============================================================================ + */ + +/** + * Allocates memory for LAPACK specific solver data and saves it in solver instance. + * + * \param [in,out] general_solver_data Solver instance. + * \return solver_status solver_ok on success and + * solver_error on failure. + */ +solver_status solver_lapack_allocate_data(solver_data* general_solver_data) { + + /* Variables */ + solver_data_lapack* lapack_data; + + /* Check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_lapack, "allocate_lapack_data")) { + return solver_error; + } + + /* Check if general_solver_data has already specific data */ + if (general_solver_data->specific_data != NULL) { + solver_logger(log_solver_error, "In function allocate_lapack_data: Pointer to solver specific data is not NULL."); + general_solver_data->state = solver_error_state; + return solver_error; + } + + /* Allocate memory */ + lapack_data = (solver_data_lapack*) solver_allocateMemory(1, sizeof(solver_data_lapack)); + if (!lapack_data) { + solver_logger(log_solver_error, "In function allocate_lapack_data: Can't allocate memory for lapack_data."); + general_solver_data->specific_data = NULL; + general_solver_data->state = solver_error_state; + return solver_error; + } + + lapack_data->A = (solver_real*) solver_allocateMemory(general_solver_data->dim_n*general_solver_data->dim_n, sizeof(solver_real)); + lapack_data->ipiv = (solver_int*) solver_allocateMemory(general_solver_data->dim_n, sizeof(solver_int)); + lapack_data->b = (solver_real*) solver_allocateMemory(general_solver_data->dim_n, sizeof(solver_real)); + if (!lapack_data->A || !lapack_data->ipiv || !lapack_data->b) { + solver_logger(log_solver_error, "In function allocate_lapack_data: Can't allocate memory for lapack_data."); + general_solver_data->specific_data = NULL; + general_solver_data->state = solver_error_state; + return solver_error; + } + + /* Set specific data and model status*/ + general_solver_data->specific_data = lapack_data; + general_solver_data->state = solver_instantiated; + + return solver_ok; +} + + +/** + * Frees LAPACK specific solver data. + * + * \param [in,out] general_solver_data Solver instance. + * \return solver_status solver_ok on success and + * solver_error on failure. + */ +solver_status solver_lapack_free_data(solver_data* general_solver_data) { + + /* Variables */ + solver_data_lapack* lapack_data; + + /* check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_lapack, "lapack_free_data")) { + return solver_error; + } + + lapack_data = general_solver_data->specific_data; + + solver_freeMemory(lapack_data->A); + solver_freeMemory(lapack_data->ipiv); + solver_freeMemory(lapack_data->b); + + solver_freeMemory(lapack_data); + + return solver_ok; +} + + + +/** + * Set dimension `dim_n` of matrix `A` in LAPACK specific solver data. + * + * \param [in,out] general_solver_data Solver instance. + * \return solver_status solver_ok on success and + * solver_error on failure. + */ +solver_status solver_lapack_set_dim_data(solver_data* general_solver_data) { + + /* Variables */ + solver_data_lapack* lapack_data; + + /* check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_lapack, "set_dim_lapack_data")) { + return solver_error; + } + + lapack_data = general_solver_data->specific_data; + + /* Set dimensions for matrices and arrays */ + lapack_data->n = general_solver_data->dim_n; + lapack_data->nrhs = 1; + lapack_data->lda = general_solver_data->dim_n; + lapack_data->ldb = general_solver_data->dim_n; + + return solver_ok; +} + + +/* + * ============================================================================ + * Getters and Setters + * ============================================================================ + */ + +/** + * Get value of element `A(row, column)`. + * + * \param [in] solver_specififc_data LAPACK specific solver data. + * \param [in] row Row index. + * \param [in] column Column index. + * \param [in,out] value On input: Pointer to previously allocated memory.
+ * On output: Value of `A(row, column)` written in `*value`. + */ +void solver_lapack_get_A_element(void* solver_specififc_data, + solver_unsigned_int row, + solver_unsigned_int column, + solver_real* value) { + + /* Variables */ + solver_data_lapack* lapack_data; + + lapack_data = solver_specififc_data; + + /* Access A(row,column) */ + *value = lapack_data->A[row+column*lapack_data->lda]; + +} + + +/** + * Set value of element `A(row, column)` in LAPACK solver specific data. + * + * \param [in,out] specific_data LAPACK specific solver data. Value of + * `A(row,column)` gets overwritten with `*value`. + * \param [in] row Row index. + * \param [in] column Column index. + * \param [in] value Pointer to value for`A(row,column)`. + */ +void solver_lapack_set_A_element(void* specific_data, + solver_unsigned_int row, + solver_unsigned_int column, + solver_real* value) { + + /* Variables */ + solver_data_lapack* lapack_data; + + lapack_data = specific_data; + + /* Access A(row,column) */ + lapack_data->A[row+column*lapack_data->lda] = *value; +} + + +/** + * Get value of element `b(index)` in LAPACK solver specific data. + * + * \param [in] specific_data LAPACK specific solver data. Value of + * `b(index)` gets overwritten with `*value`. + * \param [in] index Index. + * \param [in, out] value On input: Pointer to previously allocated memory.
+ * On output: Value of `b(index)` written in `*value`. + */ +void solver_lapack_get_b_element(void* specific_data, + solver_unsigned_int index, + solver_real* value) { + /* Variables */ + solver_data_lapack* lapack_data; + + lapack_data = specific_data; + + /* Access b(index) */ + *value = lapack_data->b[index]; +} + + +/** + * Set value of element `b(index)` in LAPACK solver specific data. + * + * \param [in,out] specific_data LAPACK specific solver data. Value of + * `b(index)` gets overwritten with `*value`. + * \param [in] index Index. + * \param [in] value Pointer to value for `b(index)`. + */ +void solver_lapack_set_b_element(void* specific_data, + solver_unsigned_int index, + solver_real* value) { + + /* Variables */ + solver_data_lapack* lapack_data; + + lapack_data = specific_data; + + /* Access b(index) */ + lapack_data->b[index] = *value; +} + + +void solver_lapack_get_x_element(void* specific_data, + solver_unsigned_int index, + solver_real* value) { + + /* Variables */ + solver_data_lapack* lapack_data; + + lapack_data = specific_data; + + /* Access b(index) */ + value[0] = lapack_data->b[index]; +} + +/* + * ============================================================================ + * Solve call + * ============================================================================ + */ + +/** + * Call LAPACK DGESV to solve linear equation system. + * + * \param [in,out] specific_data LAPACK specific solver data. + * Gets overwritten by DGESV call. + * + * \return Returns `solver_status` `solver_okay` if solved successful, + * otherwise `solver_error`. + */ +solver_state solver_lapack_solve(void* specific_data) { + + /* Variables */ + solver_data_lapack* lapack_data; + + lapack_data = specific_data; + + /* solve equation system */ + dgesv_(&lapack_data->n, + &lapack_data->nrhs, + lapack_data->A, + &lapack_data->lda, + lapack_data->ipiv, + lapack_data->b, + &lapack_data->ldb, + &lapack_data->info); + + if (lapack_data->info < 0) { + solver_logger(log_solver_error, + "In function solver_lapack_solve: the %d-th argument had an illegal value.", (-1)*lapack_data->info); + return solver_error; + } + else if (lapack_data->info > 0) { + solver_logger(log_solver_error, + "In function solver_lapack_solve: U(%d,%d) is exactly zero.\n " + "The factorization has been completed, but the factor U is exactly " + "singular, so the solution could not be computed", + lapack_data->info, lapack_data->info); + return solver_error; + } + + return solver_ok; +} + + +/* + * ============================================================================ + * Print and debug functions + * ============================================================================ + */ + +/** + * \brief Debug function to print all informations in LAPACK specific solver data. + * + * Writes into `buffer`. If `buffer` is nearly full print buffer with logger function. + * + * \param [in] buffer Buffer to write into. + * \param [in] buffer_size Size of `buffer`. + * \param [in] length Pointer to current position on buffer to write. + * \param [in] general_solver_data Solver instance. + */ +void solver_lapack_print_data(solver_char* buffer, + solver_unsigned_int buffer_size, + solver_int* length, + solver_data* general_solver_data) { + + /* Variables */ + solver_data_lapack* lapack_data; + solver_int i, j; + + lapack_data = general_solver_data->specific_data; + + /* check for correct solver */ + if (!solver_instance_correct(general_solver_data, solver_lapack, "print_lapack_data")) { + return; + } + + *length += snprintf(buffer+*length, buffer_size-*length, "\t Number of linear equations: %i\n", lapack_data->n); + *length += snprintf(buffer+*length, buffer_size-*length, "\t Number of right hand sides: %i\n", lapack_data->nrhs); + + *length += snprintf(buffer+*length, buffer_size-*length, "\t A in row major order:\n"); + for (i=0; ilda; i++) { + + *length += snprintf(buffer+*length, buffer_size-*length, "\t\t |"); + for(j=0; jn;j++) { + *length += snprintf(buffer+*length, buffer_size-*length, " %.3f", lapack_data->A[i+j*lapack_data->lda]); + } + *length += snprintf(buffer+*length, buffer_size-*length, "\n"); + + /* check if buffer is nearly full */ + if (*length >= buffer_size*0.5) { + solver_logger(log_solver_all, buffer); + *length = 0; + *length += snprintf(buffer+*length, buffer_size-*length, "Solver data print continue:\n"); + } + } + + *length += snprintf(buffer+*length, buffer_size-*length, "\t Leading dimension of A: %i\n", lapack_data->lda); + *length += snprintf(buffer+*length, buffer_size-*length, "\t Pivot indices:"); + /* check if buffer is nearly full */ + if (*length >= buffer_size*0.5) { + solver_logger(log_solver_all, buffer); + *length = 0; + *length += snprintf(buffer+*length, buffer_size-*length, "Solver data print continue:\n"); + } + for (i=0; in; i++) { + *length += snprintf(buffer+*length, buffer_size-*length, " %i", lapack_data->ipiv[i]); + } + *length += snprintf(buffer+*length, buffer_size-*length, "\n"); + + *length += snprintf(buffer+*length, buffer_size-*length, "\t b in row major order:\n"); + for (i=0; ildb*lapack_data->nrhs; i++) { + *length += snprintf(buffer+*length, buffer_size-*length, "\t \t | %f\t\n", lapack_data->b[i]); + + /* check if buffer is nearly full */ + if (*length >= buffer_size*0.5) { + solver_logger(log_solver_all, buffer); + *length = 0; + *length += snprintf(buffer+*length, buffer_size-*length, "Solver data print continue:\n"); + } + } + *length += snprintf(buffer+*length, buffer_size-*length, "\n"); + + *length += snprintf(buffer+*length, buffer_size-*length, "\t Leading dimension of b: %i\n", lapack_data->ldb); + *length += snprintf(buffer+*length, buffer_size-*length, "\t LAPACK info: %i\n", lapack_data->info); +} + + +/** @} */