From 7481fcfd9ce96715a901f24834cca3255ce06e32 Mon Sep 17 00:00:00 2001 From: Benjamin Uekermann Date: Wed, 13 Mar 2024 08:18:51 +0100 Subject: [PATCH] Add flow around controlled moving cylinder (coupling FMI with OpenFOAM) (#474) Co-authored-by: Leonard Willeke Co-authored-by: Gerasimos Chourdakis --- .../.gitignore | 3 + .../README.md | 114 ++ .../clean-tutorial.sh | 8 + .../controller-fmi/clean.sh | 7 + .../controller-fmi/fmi-settings.json | 28 + .../controller-fmi/fmu/CMakeLists.txt | 273 +++ .../fmu/PIDcontroller/FMI1CS.xml | 157 ++ .../fmu/PIDcontroller/FMI1ME.xml | 143 ++ .../controller-fmi/fmu/PIDcontroller/FMI2.xml | 214 +++ .../controller-fmi/fmu/PIDcontroller/FMI3.xml | 194 +++ .../fmu/PIDcontroller/buildDescription.xml | 11 + .../controller-fmi/fmu/PIDcontroller/config.h | 69 + .../controller-fmi/fmu/PIDcontroller/model.c | 219 +++ .../fmu/PIDcontroller/readme.md | 35 + .../controller-fmi/fmu/README.md | 19 + .../controller-fmi/fmu/include/FMI.h | 163 ++ .../controller-fmi/fmu/include/FMI1.h | 123 ++ .../controller-fmi/fmu/include/FMI2.h | 219 +++ .../controller-fmi/fmu/include/FMI3.h | 560 ++++++ .../controller-fmi/fmu/include/cosimulation.h | 8 + .../fmu/include/fmi1Functions.h | 116 ++ .../fmu/include/fmi2FunctionTypes.h | 266 +++ .../fmu/include/fmi2Functions.h | 321 ++++ .../fmu/include/fmi2TypesPlatform.h | 107 ++ .../fmu/include/fmi3FunctionTypes.h | 637 +++++++ .../fmu/include/fmi3Functions.h | 343 ++++ .../fmu/include/fmi3PlatformTypes.h | 93 + .../controller-fmi/fmu/include/fmiFunctions.h | 228 +++ .../fmu/include/fmiModelFunctions.h | 207 +++ .../fmu/include/fmiModelTypes.h | 91 + .../fmu/include/fmiPlatformTypes.h | 73 + .../controller-fmi/fmu/include/model.h | 235 +++ .../controller-fmi/fmu/set_tool_version.py | 45 + .../controller-fmi/fmu/src/FMI.c | 330 ++++ .../controller-fmi/fmu/src/FMI1.c | 525 ++++++ .../controller-fmi/fmu/src/FMI2.c | 569 ++++++ .../controller-fmi/fmu/src/FMI3.c | 1186 +++++++++++++ .../controller-fmi/fmu/src/cosimulation.c | 656 +++++++ .../controller-fmi/fmu/src/fmi1Functions.c | 638 +++++++ .../controller-fmi/fmu/src/fmi2Functions.c | 923 ++++++++++ .../controller-fmi/fmu/src/fmi3Functions.c | 1544 +++++++++++++++++ .../controller-fmi/fmu/thirdparty/LICENSE.txt | 148 ++ .../controller-fmi/precice-settings.json | 9 + .../controller-fmi/run.sh | 15 + .../fluid-openfoam/0.orig/U | 44 + .../fluid-openfoam/0.orig/p | 41 + .../fluid-openfoam/0.orig/pointDisplacement | 44 + .../fluid-openfoam/clean.sh | 9 + .../fluid-openfoam/constant/dynamicMeshDict | 19 + .../constant/transportProperties | 11 + .../constant/turbulenceProperties | 10 + .../fluid-openfoam/run.sh | 14 + .../fluid-openfoam/system/blockMeshDict | 303 ++++ .../fluid-openfoam/system/controlDict | 52 + .../fluid-openfoam/system/decomposeParDict | 16 + .../fluid-openfoam/system/forces | 13 + .../fluid-openfoam/system/fvSchemes | 42 + .../fluid-openfoam/system/fvSolution | 116 ++ .../fluid-openfoam/system/preciceDict | 40 + ...round-controlled-moving-cylinder-setup.png | Bin 0 -> 22535 bytes ...-controlled-moving-cylinder-watchpoint.png | Bin 0 -> 123068 bytes .../plot-timeseries.py | 64 + .../plot-watchpoint.sh | 45 + .../precice-config.xml | 101 ++ .../solid-python/clean.sh | 4 + .../solid-python/run.sh | 6 + .../solid-python/solid.py | 105 ++ 67 files changed, 12971 insertions(+) create mode 100644 flow-around-controlled-moving-cylinder/.gitignore create mode 100644 flow-around-controlled-moving-cylinder/README.md create mode 100755 flow-around-controlled-moving-cylinder/clean-tutorial.sh create mode 100755 flow-around-controlled-moving-cylinder/controller-fmi/clean.sh create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmi-settings.json create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/CMakeLists.txt create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1CS.xml create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1ME.xml create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI2.xml create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI3.xml create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/buildDescription.xml create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/config.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/model.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/readme.md create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/README.md create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI1.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI2.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI3.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/cosimulation.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi1Functions.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2FunctionTypes.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2Functions.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2TypesPlatform.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3FunctionTypes.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3Functions.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3PlatformTypes.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiFunctions.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelFunctions.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelTypes.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiPlatformTypes.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/model.h create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/set_tool_version.py create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI1.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI2.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI3.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/cosimulation.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi1Functions.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi2Functions.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi3Functions.c create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/fmu/thirdparty/LICENSE.txt create mode 100644 flow-around-controlled-moving-cylinder/controller-fmi/precice-settings.json create mode 100755 flow-around-controlled-moving-cylinder/controller-fmi/run.sh create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/U create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/p create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/pointDisplacement create mode 100755 flow-around-controlled-moving-cylinder/fluid-openfoam/clean.sh create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/constant/dynamicMeshDict create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/constant/transportProperties create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/constant/turbulenceProperties create mode 100755 flow-around-controlled-moving-cylinder/fluid-openfoam/run.sh create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/blockMeshDict create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/controlDict create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/decomposeParDict create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/forces create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSchemes create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSolution create mode 100644 flow-around-controlled-moving-cylinder/fluid-openfoam/system/preciceDict create mode 100644 flow-around-controlled-moving-cylinder/images/tutorials-flow-around-controlled-moving-cylinder-setup.png create mode 100644 flow-around-controlled-moving-cylinder/images/tutorials-flow-around-controlled-moving-cylinder-watchpoint.png create mode 100644 flow-around-controlled-moving-cylinder/plot-timeseries.py create mode 100755 flow-around-controlled-moving-cylinder/plot-watchpoint.sh create mode 100644 flow-around-controlled-moving-cylinder/precice-config.xml create mode 100755 flow-around-controlled-moving-cylinder/solid-python/clean.sh create mode 100755 flow-around-controlled-moving-cylinder/solid-python/run.sh create mode 100644 flow-around-controlled-moving-cylinder/solid-python/solid.py diff --git a/flow-around-controlled-moving-cylinder/.gitignore b/flow-around-controlled-moving-cylinder/.gitignore new file mode 100644 index 000000000..043bb5f18 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/.gitignore @@ -0,0 +1,3 @@ +controller-fmi/PIDcontroller.fmu +controller-fmi/output/ +fluid-openfoam/0/ # Since we start from 0.orig diff --git a/flow-around-controlled-moving-cylinder/README.md b/flow-around-controlled-moving-cylinder/README.md new file mode 100644 index 000000000..a28063f65 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/README.md @@ -0,0 +1,114 @@ +--- +title: Flow around controlled moving cylinder +permalink: tutorials-flow-around-controlled-moving-cylinder.html +keywords: FMI, FSI, OpenFOAM, controller, multi coupling, PID +summary: Flow around a rigid moving cylinder. A FMI-based controller is used to dampen out the oscillation. +--- + +{% note %} +Get the [case files of this tutorial](https://github.com/precice/tutorials/tree/master/flow-around-controlled-moving-cylinder). Read how in the [tutorials introduction](https://www.precice.org/tutorials.html). +{% endnote %} + +## Setup + +We simulate a 2D flow around a cylinder. The cylinder is not fixed, but mounted on a spring-damper system which allows it to move in the y-direction. The vortex shedding of the flow brings the cylinder to oscillate up and down. This setup has received attention as a test case for numerical simulations [2] in the past and is backed up with experimental data [3]. The oscillation can be counteracted by moving the root point of the spring [4]. To adjust the root point accordingly, a PID controller is implemented. The full setup is shown below: + +![Setup of flow around controlled moving cylinder](images/tutorials-flow-around-controlled-moving-cylinder-setup.png) + +This case was contributed by Leonard Willeke et al. [1]. To reduce the overall runtime compared to the original contribution, this case uses a larger time step size 2.5e-3 (instead of 1e-3) and the controller switches on at t=2 (instead of t=40). Still, the scenario requires around an hour to complete. + +## Available solvers + +OpenFOAM is used for the `Fluid` participant. The spring-damper system is solved in a separate Python `Solid` participant. Finally, the PID algorithm is calculated in an FMU as participant `Controller`. + +- *OpenFOAM*: To run this case, you need the preCICE [OpenFOAM Adapter](https://precice.org/adapter-openfoam-get.html). OpenFOAM is used to simulate the laminar flow around the cylinder with the solver `pimpleFoam`. +- *FMI*: A solver using the [preCICE-FMI Runner](https://github.com/precice/fmi-runner) (requires at least v0.2). The Runner executes the FMU model `PIDcontroller.fmu` for computation. The provided run script (see below) builds this model if not already there. If you want to change the model parameters or simulation setup, have a look inside `fmi-settings.json` and `precice-settings.json` (see folder `controller-fmi`). +- *Python*: A python script solving the spring damper system. It uses the preCICE [Python bindings](https://www.precice.org/installation-bindings-python.html) and depends on the Python library `numpy`. You can install `numpy` from your system package manager or with `pip3 install --user `. + +## Running the simulation + +Open three separate terminals. The commands for the `Solid` and the `Controller` are: + +```bash +cd solid-python +./run.sh +``` + +and + +```bash +cd controller-fmi +./run.sh +``` + +For the `Fluid` participant, you can run OpenFOAM either in serial or in parallel. To run the case in serial, you can use the same command as before + +```bash +cd fluid-openfoam +./run.sh +``` + +while for the parallel computation, you need to set an additional flag + +```bash +cd fluid-openfoam +./run.sh -parallel +``` + +## Post-processing + +There are multiple options for post-processing, depending on what you want to visualize. + +### Plot displacement and forces + +The `Solid` participant writes a `watchpoint` during the simulation. To plot this data in four individual windows, run the command + +```bash +./plot-watchpoint.sh solid-python +``` + +The displacement of the cylinder clearly shows the onset of the controller after t=2: + +![Displacement of controlled moving cylinder](images/tutorials-flow-around-controlled-moving-cylinder-watchpoint.png) + +### Plot controller variables + +Upon completion of the scenario, the preCICE-FMI Runner stores some of the internal controller variables such as output values and the terms of the different gains. To plot for example the error between measured and wanted state, run the command + +```bash +python3 plot-timeseries.py ./controller-fmi/output/controller-output.csv E_OVER_T +``` + +To get a full list of the plot options, run `python3 plot-timeseries.py -h`. Please note: This script requires a few standard python libraries (pandas, matplotlib, argparse, enum). + +### View the simulation results in ParaView + +OpenFOAM creates `.vtk` files during the simulation which you can visualize and animate in [ParaView](https://www.paraview.org/download/). To do so, run + +```bash +cd fluid-openfoam +paraFoam +``` + +The displacements of the cylinder are very small, however, and, thus, not directly visible. With a `WarpByVector` filter based on the `cellDisplacement` data, try scaling them up by a factor of 100. + +## Acknowledgements + +Many thanks to [Mosayeb Shams](https://github.com/mosayebshams) from Herriot Watt University, UK, who helped to set up this simulation case. + +## Sources + +- The general idea was taken from [4]. +- The OpenFOAM case files make use of the following work: + - An [OpenFOAM tutorial](https://gitlab.com/mAlletto/openfoamtutorials/-/tree/master/transverseRe100m*10) to study vortex induced vibrations on a 2D cylinder + - An [online article](https://curiosityfluids.com/2016/07/19/oscillating-cylinder-in-crossflow-pimpledymfoam/) discussing the setup of a similar OpenFOAM case + +## References + +[1] L. Willeke, D. Schneider, B. Uekermann, [A preCICE-FMI Runner to Couple FMUs to PDE-Based Simulations](https://doi.org/10.3384/ecp204), Proceedings 15th Intern. Modelica Conference, 2023 + +[2] Placzek, A. and Sigrist, J.F. and Hamdouni, A. [Numerical Simulation of an oscillating cylinder in a cross-flow at low Reynolds number: Forced and free oscillations](https://dx.doi.org/10.1016/j.compfluid.2008.01.007), Computers and Fluids, 2009, 38 (1), pp.80-100 + +[3] Anagnostopoulus, P. and Bearman, P.W. Response Characteristics of a vortex-excited cylinder at low Reynolds numbers, Journal of Fluids and Structures, January 1992, DOI: 10.1016/0889-9746(92)90054-7 + +[4] Sicklinger, S. [Stabilized Co-Simulation of Coupled Problems including Fields and Signals](https://www.researchgate.net/publication/269705153_Stabilized_Co-Simulation_of_Coupled_Problems_Including_Fields_and_Signals), Technical University of Munich, Dissertation diff --git a/flow-around-controlled-moving-cylinder/clean-tutorial.sh b/flow-around-controlled-moving-cylinder/clean-tutorial.sh new file mode 100755 index 000000000..7cc460c25 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/clean-tutorial.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e -u + +# shellcheck disable=SC1091 +. ../tools/cleaning-tools.sh + +clean_tutorial . +clean_precice_logs . diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/clean.sh b/flow-around-controlled-moving-cylinder/controller-fmi/clean.sh new file mode 100755 index 000000000..f7f371eab --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/clean.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e -u + +. ../../tools/cleaning-tools.sh + +rm -rfv ./output/ +clean_precice_logs . diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmi-settings.json b/flow-around-controlled-moving-cylinder/controller-fmi/fmi-settings.json new file mode 100644 index 000000000..85569c5b7 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmi-settings.json @@ -0,0 +1,28 @@ +{ + "simulation_params": { + "fmu_file_name": "./PIDcontroller.fmu", + "output_file_name": "./output/controller-output.csv", + "output": ["e", "P", "I", "D", "u_1", "u_2", "y_1", "y_2"], + "fmu_read_data_names": ["y_1", "y_2"], + "fmu_write_data_names":["u_1", "u_2"], + "fmu_instance_name": "pid_controller" + }, + "model_params": { + "r": 0.0, + "use_implicit_method": true, + "compute_u_1": false + }, + "initial_conditions": { + "kp": 0, + "ki": 0, + "kd": 0 + + }, + "input_signals": { + "names": ["time", "kp", "ki", "kd"], + "data": [ + [0.0, 0.0, 0.0, 0.0], + [2.0, 0.02, 0.02, 0.01] + ] + } +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/CMakeLists.txt b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/CMakeLists.txt new file mode 100644 index 000000000..4205e0681 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/CMakeLists.txt @@ -0,0 +1,273 @@ +cmake_minimum_required (VERSION 3.16) + +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + +FUNCTION(cat IN_FILE OUT_FILE) + file(READ ${IN_FILE} CONTENTS) + file(APPEND ${OUT_FILE} "${CONTENTS}") +ENDFUNCTION() + +project (Reference-FMUs) + +find_package (Python3) +find_package (Git) + +set(FMI_VERSION 2 CACHE STRING "FMI Version") +set_property(CACHE FMI_VERSION PROPERTY STRINGS 1 2 3) + +set(FMI_TYPE ME CACHE STRING "FMI Type (FMI 1.0 only)") +set_property(CACHE FMI_TYPE PROPERTY STRINGS ME CS) + +if (${FMI_VERSION} GREATER 1) + set(FMI_TYPE "") +endif () + +set(WITH_FMUSIM OFF CACHE BOOL "Add fmusim project") + +if (MSVC) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + + # Minimum supported MSVC version is 1800 = Visual Studio 12.0/2013 + # See also https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html + if (MSVC_VERSION VERSION_LESS 1800) + message (SEND_ERROR "MSVC_VERSION ${MSVC_VERSION} is not a supported Visual Studio compiler version. Please use Visual Studio 2013 or any later version.") + endif () +endif () + +add_compile_definitions(FMI_VERSION=${FMI_VERSION}) + +if (${FMI_VERSION} GREATER 2) + + if (WIN32) + set(FMI_PLATFORM windows) + elseif (APPLE) + set(FMI_PLATFORM darwin) + else () + set(FMI_PLATFORM linux) + endif () + + if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set (FMI_PLATFORM x86_64-${FMI_PLATFORM}) + else () + set (FMI_PLATFORM x86-${FMI_PLATFORM}) + endif () + +else () + + if (WIN32) + set(FMI_PLATFORM win) + elseif (APPLE) + set(FMI_PLATFORM darwin) + else () + set(FMI_PLATFORM linux) + endif () + + if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set (FMI_PLATFORM ${FMI_PLATFORM}64) + else () + set (FMI_PLATFORM ${FMI_PLATFORM}32) + endif () + +endif () + +MESSAGE("FMI_PLATFORM: " ${FMI_PLATFORM}) + +if (${FMI_VERSION} LESS 3) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/all.c" "#define FMI_VERSION ${FMI_VERSION} + +#include \"fmi${FMI_VERSION}Functions.c\" +#include \"model.c\" +#include \"cosimulation.c\" +") +endif () + +set (MODEL_NAMES PIDcontroller) + +foreach (MODEL_NAME ${MODEL_NAMES}) + +set(TARGET_NAME ${MODEL_NAME}) + +SET(HEADERS + ${MODEL_NAME}/config.h + include/cosimulation.h + include/model.h +) + +if (${FMI_VERSION} EQUAL 2) + SET(HEADERS + ${HEADERS} + include/fmi2Functions.h + include/fmi2FunctionTypes.h + include/fmi2TypesPlatform.h + ) +elseif (${FMI_VERSION} EQUAL 3) + SET(HEADERS + ${HEADERS} + include/fmi3Functions.h + include/fmi3FunctionTypes.h + include/fmi3PlatformTypes.h + ) +endif() + +SET(SOURCES + ${MODEL_NAME}/model.c + src/fmi${FMI_VERSION}Functions.c + src/cosimulation.c +) + +add_library(${TARGET_NAME} SHARED + ${HEADERS} + ${SOURCES} + ${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml +) + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../..) + +target_compile_definitions(${TARGET_NAME} PRIVATE + DISABLE_PREFIX +) + +if (MSVC) + target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX) +else() + target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror) +endif() + +if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${TARGET_NAME} PRIVATE "-static-libgcc") +endif() + +if (CMAKE_C_COMPILER_ID STREQUAL "Intel") + target_link_options(${TARGET_NAME} PRIVATE "-static-intel" "-static-libgcc") +endif() + +if (${FMI_VERSION} EQUAL 1 AND "${FMI_TYPE}" STREQUAL CS) + target_compile_definitions(${TARGET_NAME} PRIVATE FMI_COSIMULATION) +endif() + +target_include_directories(${TARGET_NAME} PRIVATE + include + ${MODEL_NAME} +) + +set(FMU_BUILD_DIR temp/${MODEL_NAME}) + +set_target_properties(${TARGET_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + LIBRARY_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + ARCHIVE_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" +) + +set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "") +set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${MODEL_NAME}) + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +# modelDescription.xml +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml + "${FMU_BUILD_DIR}/modelDescription.xml" +) + +if (${Python3_Interpreter_FOUND} AND ${Git_FOUND}) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/set_tool_version.py" + "${FMU_BUILD_DIR}/modelDescription.xml" "${GIT_EXECUTABLE}" + ) +endif() + +# model specific header and source +foreach (SOURCE_FILE config.h model.c) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/${SOURCE_FILE}" + "${FMU_BUILD_DIR}/sources/${SOURCE_FILE}" + ) +endforeach(SOURCE_FILE) + +# documentation +if (${FMI_VERSION} EQUAL 1) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/readme.html" + "${FMU_BUILD_DIR}/documentation/_main.html" + ) +else() + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/readme.html" + "${FMU_BUILD_DIR}/documentation/index.html" + ) +endif() + +# license +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/LICENSE.txt" + "${FMU_BUILD_DIR}/documentation/LICENSE.txt" +) + +# common headers +foreach (SOURCE_FILE model.h cosimulation.h) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/include/${SOURCE_FILE}" + "${FMU_BUILD_DIR}/sources/${SOURCE_FILE}" + ) +endforeach(SOURCE_FILE) + +# common sources +foreach (SOURCE_FILE fmi${FMI_VERSION}Functions.c cosimulation.c) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/src/${SOURCE_FILE}" + "${FMU_BUILD_DIR}/sources/${SOURCE_FILE}" + ) +endforeach(SOURCE_FILE) + +# all.c / buildDescription.xml +if (${FMI_VERSION} LESS 3) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_BINARY_DIR}/all.c" + "${FMU_BUILD_DIR}/sources/all.c" + ) +else() + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/buildDescription.xml" + "${FMU_BUILD_DIR}/sources/buildDescription.xml" + ) +endif() + +set(ARCHIVE_FILES "modelDescription.xml" "binaries" "documentation" "sources") + +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources") + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources" + "${FMU_BUILD_DIR}/resources/" + ) + set(ARCHIVE_FILES ${ARCHIVE_FILES} "resources") +endif() + +# delete unintended files from binaries (Release configuration only) +if (MSVC) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND if $ neq 0 ( + ${CMAKE_COMMAND} -E rm -f + "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}/${MODEL_NAME}.exp" + "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}/${MODEL_NAME}.lib" + ) + ) +endif() + +# create ZIP archive +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E tar "cfv" ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_NAME}.fmu --format=zip + ${ARCHIVE_FILES} + WORKING_DIRECTORY ${FMU_BUILD_DIR} COMMENT "Creating ZIP archive" +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_NAME}.fmu DESTINATION ${CMAKE_INSTALL_PREFIX}) + +endforeach(MODEL_NAME) + +if (WITH_FMUSIM) + add_subdirectory(fmusim) +endif () diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1CS.xml b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1CS.xml new file mode 100644 index 000000000..1cec06a90 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1CS.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1ME.xml b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1ME.xml new file mode 100644 index 000000000..3408f64d6 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI1ME.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI2.xml b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI2.xml new file mode 100644 index 000000000..8bcc5c706 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI2.xml @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI3.xml b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI3.xml new file mode 100644 index 000000000..92e8aeb7a --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/FMI3.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/buildDescription.xml b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/buildDescription.xml new file mode 100644 index 000000000..12ec75970 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/buildDescription.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/config.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/config.h new file mode 100644 index 000000000..e5d2dfe0b --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/config.h @@ -0,0 +1,69 @@ +#ifndef config_h +#define config_h + +#include // for bool + +// define class name and unique id +#define MODEL_IDENTIFIER PIDcontroller +#define INSTANTIATION_TOKEN "{1AE5E10D-9521-4DE3-80B9-D0EAAA7D5AF1}" + +#define CO_SIMULATION +#define MODEL_EXCHANGE + +// define model size +#define NX 2 +#define NZ 1 + +#define SET_FLOAT64 +#define SET_BOOLEAN +#define GET_OUTPUT_DERIVATIVE +#define GET_BOOLEAN +#define EVENT_UPDATE + +#define FIXED_SOLVER_STEP 1e-3 +#define DEFAULT_STOP_TIME 3 + +typedef enum { + + vr_time, + vr_r, + vr_e, + vr_e_ls, + vr_kp, + vr_ki, + vr_kd, + vr_P, + vr_I, + vr_D, + vr_y_1, + vr_y_2, + vr_u_1, + vr_u_2, + vr_I_max, + vr_use_implicit_method, + vr_compute_u_1 + +} ValueReference; + +typedef struct { + + double r; + double e; + double e_ls; + double kp; + double ki; + double kd; + double P; + double I; + double D; + double y_1; + double y_2; + double u_1; + double u_2; + double I_max; + bool use_implicit_method; + bool compute_u_1; + +} ModelData; + +#endif /* config_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/model.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/model.c new file mode 100644 index 000000000..bd21edd82 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/model.c @@ -0,0 +1,219 @@ +#include "model.h" +#include // for DBL_MIN +#include // for fabs() +#include "config.h" + +#define V_MIN (0.1) +#define EVENT_EPSILON (1e-10) + +void setStartValues(ModelInstance *comp) +{ + + M(r) = 0; + M(e_ls) = 0; + M(kp) = 0; + M(ki) = 0; + M(kd) = 0; + M(P) = 0; + M(I) = 0; + M(D) = 0; + M(y_1) = 0; + M(y_2) = 0; + M(u_1) = 0; + M(u_2) = 0; + M(I_max) = 100; + + M(use_implicit_method) = false; + M(compute_u_1) = true; +} + +Status calculateValues(ModelInstance *comp) +{ + + UNUSED(comp); + return OK; +} + +Status getFloat64(ModelInstance *comp, ValueReference vr, double *value, size_t *index) +{ + switch (vr) { + case vr_time: + value[(*index)++] = comp->time; + return OK; + case vr_r: + value[(*index)++] = M(r); + return OK; + case vr_e: + value[(*index)++] = M(e); + return OK; + case vr_e_ls: + value[(*index)++] = M(e_ls); + return OK; + case vr_kp: + value[(*index)++] = M(kp); + return OK; + case vr_ki: + value[(*index)++] = M(ki); + return OK; + case vr_kd: + value[(*index)++] = M(kd); + return OK; + case vr_P: + value[(*index)++] = M(P); + return OK; + case vr_I: + value[(*index)++] = M(I); + return OK; + case vr_D: + value[(*index)++] = M(D); + return OK; + case vr_y_1: + value[(*index)++] = M(y_1); + return OK; + case vr_y_2: + value[(*index)++] = M(y_2); + return OK; + case vr_u_1: + value[(*index)++] = M(u_1); + return OK; + case vr_u_2: + value[(*index)++] = M(u_2); + return OK; + case vr_I_max: + value[(*index)++] = M(I_max); + return OK; + default: + logError(comp, "Get Float64 is not allowed for value reference %u.", vr); + return Error; + } +} + +Status getBoolean(ModelInstance *comp, ValueReference vr, bool *value, size_t *index) +{ + + switch (vr) { + case vr_use_implicit_method: + value[(*index)++] = M(use_implicit_method); + break; + case vr_compute_u_1: + value[(*index)++] = M(compute_u_1); + break; + default: + logError(comp, "Get Boolean is not allowed for value reference %u.", vr); + return Error; + } + + return OK; +} + +Status setFloat64(ModelInstance *comp, ValueReference vr, const double *value, size_t *index) +{ + switch (vr) { + + case vr_r: + M(r) = value[(*index)++]; + return OK; + case vr_kp: + M(kp) = value[(*index)++]; + return OK; + case vr_ki: + M(ki) = value[(*index)++]; + return OK; + case vr_kd: + M(kd) = value[(*index)++]; + return OK; + case vr_y_1: + M(y_1) = value[(*index)++]; + return OK; + case vr_y_2: + M(y_2) = value[(*index)++]; + return OK; + case vr_I_max: + M(I_max) = value[(*index)++]; + return OK; + default: + logError(comp, "Unexpected value reference: %u.", vr); + return Error; + } +} + +Status setBoolean(ModelInstance *comp, ValueReference vr, const bool *value, size_t *index) +{ + + switch (vr) { + case vr_use_implicit_method: + M(use_implicit_method) = value[(*index)++]; + break; + case vr_compute_u_1: + M(compute_u_1) = value[(*index)++]; + break; + default: + logError(comp, "Set Boolean is not allowed for value reference %u.", vr); + return Error; + } + + comp->isDirtyValues = true; + + return OK; +} + +Status getOutputDerivative(ModelInstance *comp, ValueReference valueReference, int order, double *value) +{ + + if (order != 1) { + logError(comp, "The output derivative order %d for value reference %u is not available.", order, valueReference); + return Error; + } + + switch (valueReference) { + + default: + logError(comp, "The output derivative for value reference %u is not available.", valueReference); + return Error; + } + + UNUSED(value); +} + +void eventUpdate(ModelInstance *comp) +{ + + if (false) { + + } else { + comp->valuesOfContinuousStatesChanged = false; + } + + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} + +void getContinuousStates(ModelInstance *comp, double x[], size_t nx) +{ + UNUSED(comp); + UNUSED(nx); + UNUSED(x); +} + +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) +{ + UNUSED(comp); + UNUSED(nx); + UNUSED(x); +} + +void getDerivatives(ModelInstance *comp, double dx[], size_t nx) +{ + UNUSED(comp); + UNUSED(nx); + UNUSED(dx); +} + +void getEventIndicators(ModelInstance *comp, double z[], size_t nz) +{ + + UNUSED(nz); + UNUSED(comp); + UNUSED(z); +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/readme.md b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/readme.md new file mode 100644 index 000000000..5e7356544 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/PIDcontroller/readme.md @@ -0,0 +1,35 @@ +# PID Controller + +The PID Controller implements the following system of equations: + +```txt +explicit: forward Euler +e = r - y +u = kp*e + ki* (I + e*dt) + kd*(e-e_ls)*(1/dt) + +implicit: trapezoidal +e = r - y +u = kp*e + ki * (I + (e + e_ls) * dt) + kd*(e-e_ls)*(1/dt) +``` + +with the variables + +| Variable | Start | Causality | Variability | Description +|:---------------------|------:|-----------|-------------|:--------------- +| u_1 | 0 | output | continuous | Control output 1 +| u_2 | 0 | output | continuous | Control output 2 +| y_1 | 0 | parameter | tunable | Control input 1 +| y_2 | 0 | parameter | tunable | Control input 2 +| r | 0 | parameter | tunable | Reference value +| e | - | local | continuous | Error between input and reference +| e_ls | - | local | continuous | Error between input and reference from last time step +| kp | 0 | parameter | tunable | Proportional gain +| ki | 0 | parameter | tunable | Integral gain +| kd | 0 | parameter | tunable | Derivative gain +| dt | 1e-2 | parameter | tunable | Solver step size +| P | - | local | continuous | Proportional term +| I | - | local | continuous | Integral term +| D | - | local | continuous | Differential term +| I_max | 100 | local | continuous | Maximumim for I to avoid integrator windup +| compute_u_1 | true | local | continuous | Flag to compute either u_1 or u_2 +| use_implicit_method | false | local | continuous | Flag to use explicit or implicit method diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/README.md b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/README.md new file mode 100644 index 000000000..5b0344a1a --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/README.md @@ -0,0 +1,19 @@ +# Build instruction + +To build the Oscillator FMU you need [CMake](https://cmake.org/) ≥ 3.16 and a supported [build tool](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) e.g. Visual Studio ≥ 2013 , Xcode or make. + +Compile the model with the following commands: + +```bash +mkdir build +cd build +cmake -DFMI_TYPE=CS -DFMI_VERSION=3 .. +make +cp ./PIDcontroller.fmu ../.. +``` + +Instead of `make`, you can also use your preferred build tool to create the FMU. + +## License + +The FMU model `PIDcontroller.fmu` used for this tutorial is based on the [Reference-FMUs](https://github.com/modelica/Reference-FMUs) from the Modelica Association Project "FMI", which are released under the 2-Clause BSD License (see folder "thirdparty"). diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI.h new file mode 100644 index 000000000..ef5909fe6 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI.h @@ -0,0 +1,163 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +#include +#include + +#ifndef FMI_MAX_MESSAGE_LENGTH +#define FMI_MAX_MESSAGE_LENGTH 4096 +#endif + +#ifndef FMI_STATIC +#define FMI_STATIC +#endif + +typedef enum { + FMIOK, + FMIWarning, + FMIDiscard, + FMIError, + FMIFatal, + FMIPending +} FMIStatus; + +typedef enum { + + // FMI 3.0 variable types + FMIFloat32Type, + FMIDiscreteFloat32Type, + FMIFloat64Type, + FMIDiscreteFloat64Type, + FMIInt8Type, + FMIUInt8Type, + FMIInt16Type, + FMIUInt16Type, + FMIInt32Type, + FMIUInt32Type, + FMIInt64Type, + FMIUInt64Type, + FMIBooleanType, + FMIStringType, + FMIBinaryType, + FMIClockType, + + // Aliases for FMI 1.0 and 2.0 + FMIRealType = FMIFloat64Type, + FMIDiscreteRealType = FMIDiscreteFloat64Type, + FMIIntegerType = FMIInt32Type, + +} FMIVariableType; + +typedef enum { + FMIVersion1 = 1, + FMIVersion2 = 2, + FMIVersion3 = 3 +} FMIVersion; + +typedef enum { + FMIModelExchange, + FMICoSimulation, + FMIScheduledExecution +} FMIInterfaceType; + +typedef enum { + FMI2StartAndEndState = 1 << 0, + FMI2InstantiatedState = 1 << 1, + FMI2InitializationModeState = 1 << 2, + + // model exchange states + FMI2EventModeState = 1 << 3, + FMI2ContinuousTimeModeState = 1 << 4, + + // co-simulation states + FMI2StepCompleteState = 1 << 5, + FMI2StepInProgressState = 1 << 6, + FMI2StepFailedState = 1 << 7, + FMI2StepCanceledState = 1 << 8, + + FMI2TerminatedState = 1 << 9, + FMI2ErrorState = 1 << 10, + FMI2FatalState = 1 << 11, +} FMI2State; + +typedef unsigned int FMIValueReference; + +typedef struct FMIInstance_ FMIInstance; + +typedef struct FMI1Functions_ FMI1Functions; + +typedef struct FMI2Functions_ FMI2Functions; + +typedef struct FMI3Functions_ FMI3Functions; + +typedef void FMILogFunctionCall(FMIInstance *instance, FMIStatus status, const char *message, ...); + +typedef void FMILogMessage(FMIInstance *instance, FMIStatus status, const char *category, const char *message); + +struct FMIInstance_ { + + FMI1Functions *fmi1Functions; + FMI2Functions *fmi2Functions; + FMI3Functions *fmi3Functions; + +#ifdef _WIN32 + HMODULE libraryHandle; +#else + void *libraryHandle; +#endif + + void *userData; + + FMILogMessage * logMessage; + FMILogFunctionCall *logFunctionCall; + + double time; + + char *buf1; + char *buf2; + + size_t bufsize1; + size_t bufsize2; + + void *component; + + const char *name; + + bool logFMICalls; + + FMI2State state; + + FMIStatus status; + + FMIVersion fmiVersion; + + FMIInterfaceType interfaceType; +}; + +FMI_STATIC FMIInstance *FMICreateInstance(const char *instanceName, const char *libraryPath, FMILogMessage *logMessage, FMILogFunctionCall *logFunctionCall); + +FMI_STATIC void FMIFreeInstance(FMIInstance *instance); + +FMI_STATIC const char *FMIValueReferencesToString(FMIInstance *instance, const FMIValueReference vr[], size_t nvr); + +FMI_STATIC const char *FMIValuesToString(FMIInstance *instance, size_t vValues, const size_t sizes[], const void *values, FMIVariableType variableType); + +FMI_STATIC FMIStatus FMIURIToPath(const char *uri, char *path, const size_t pathLength); + +FMI_STATIC FMIStatus FMIPathToURI(const char *path, char *uri, const size_t uriLength); + +FMI_STATIC FMIStatus FMIPlatformBinaryPath(const char *unzipdir, const char *modelIdentifier, FMIVersion fmiVersion, char *platformBinaryPath, size_t size); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI1.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI1.h new file mode 100644 index 000000000..a6a14b438 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI1.h @@ -0,0 +1,123 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "FMI.h" +#include "fmi1Functions.h" + +struct FMI1Functions_ { + + /*************************************************** + Common Functions for FMI 1.0 + ****************************************************/ + + fmi1CallbackFunctions callbacks; + fmi1EventInfo eventInfo; + + fmi1SetRealTYPE * fmi1SetReal; + fmi1SetIntegerTYPE * fmi1SetInteger; + fmi1SetBooleanTYPE * fmi1SetBoolean; + fmi1SetStringTYPE * fmi1SetString; + fmi1GetRealTYPE * fmi1GetReal; + fmi1GetIntegerTYPE * fmi1GetInteger; + fmi1GetBooleanTYPE * fmi1GetBoolean; + fmi1GetStringTYPE * fmi1GetString; + fmi1SetDebugLoggingTYPE *fmi1SetDebugLogging; + + /*************************************************** + FMI 1.0 for Model Exchange Functions + ****************************************************/ + + fmi1GetModelTypesPlatformTYPE * fmi1GetModelTypesPlatform; + fmi1GetVersionTYPE * fmi1GetVersion; + fmi1InstantiateModelTYPE * fmi1InstantiateModel; + fmi1FreeModelInstanceTYPE * fmi1FreeModelInstance; + fmi1SetTimeTYPE * fmi1SetTime; + fmi1SetContinuousStatesTYPE * fmi1SetContinuousStates; + fmi1CompletedIntegratorStepTYPE * fmi1CompletedIntegratorStep; + fmi1InitializeTYPE * fmi1Initialize; + fmi1GetDerivativesTYPE * fmi1GetDerivatives; + fmi1GetEventIndicatorsTYPE * fmi1GetEventIndicators; + fmi1EventUpdateTYPE * fmi1EventUpdate; + fmi1GetContinuousStatesTYPE * fmi1GetContinuousStates; + fmi1GetNominalContinuousStatesTYPE *fmi1GetNominalContinuousStates; + fmi1GetStateValueReferencesTYPE * fmi1GetStateValueReferences; + fmi1TerminateTYPE * fmi1Terminate; + + /*************************************************** + FMI 1.0 for Co-Simulation Functions + ****************************************************/ + + fmi1GetTypesPlatformTYPE * fmi1GetTypesPlatform; + fmi1InstantiateSlaveTYPE * fmi1InstantiateSlave; + fmi1InitializeSlaveTYPE * fmi1InitializeSlave; + fmi1TerminateSlaveTYPE * fmi1TerminateSlave; + fmi1ResetSlaveTYPE * fmi1ResetSlave; + fmi1FreeSlaveInstanceTYPE * fmi1FreeSlaveInstance; + fmi1SetRealInputDerivativesTYPE * fmi1SetRealInputDerivatives; + fmi1GetRealOutputDerivativesTYPE *fmi1GetRealOutputDerivatives; + fmi1CancelStepTYPE * fmi1CancelStep; + fmi1DoStepTYPE * fmi1DoStep; + fmi1GetStatusTYPE * fmi1GetStatus; + fmi1GetRealStatusTYPE * fmi1GetRealStatus; + fmi1GetIntegerStatusTYPE * fmi1GetIntegerStatus; + fmi1GetBooleanStatusTYPE * fmi1GetBooleanStatus; + fmi1GetStringStatusTYPE * fmi1GetStringStatus; +}; + +/*************************************************** + Common Functions for FMI 1.0 +****************************************************/ +FMI_STATIC FMIStatus FMI1SetReal(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Real value[]); +FMI_STATIC FMIStatus FMI1SetInteger(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer value[]); +FMI_STATIC FMIStatus FMI1SetBoolean(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Boolean value[]); +FMI_STATIC FMIStatus FMI1SetString(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1String value[]); +FMI_STATIC FMIStatus FMI1GetReal(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1Real value[]); +FMI_STATIC FMIStatus FMI1GetInteger(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1Integer value[]); +FMI_STATIC FMIStatus FMI1GetBoolean(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1Boolean value[]); +FMI_STATIC FMIStatus FMI1GetString(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1String value[]); +FMI_STATIC FMIStatus FMI1SetDebugLogging(FMIInstance *instance, fmi1Boolean loggingOn); + +/*************************************************** + FMI 1.0 for Model Exchange Functions +****************************************************/ +FMI_STATIC const char *FMI1GetModelTypesPlatform(FMIInstance *instance); +FMI_STATIC const char *FMI1GetVersion(FMIInstance *instance); +FMI_STATIC FMIStatus FMI1InstantiateModel(FMIInstance *instance, fmi1String modelIdentifier, fmi1String GUID, fmi1Boolean loggingOn); +FMI_STATIC void FMI1FreeModelInstance(FMIInstance *instance); +FMI_STATIC FMIStatus FMI1SetTime(FMIInstance *instance, fmi1Real time); +FMI_STATIC FMIStatus FMI1SetContinuousStates(FMIInstance *instance, const fmi1Real x[], size_t nx); +FMI_STATIC FMIStatus FMI1CompletedIntegratorStep(FMIInstance *instance, fmi1Boolean *callEventUpdate); +FMI_STATIC FMIStatus FMI1Initialize(FMIInstance *instance, fmi1Boolean toleranceControlled, fmi1Real relativeTolerance); +FMI_STATIC FMIStatus FMI1GetDerivatives(FMIInstance *instance, fmi1Real derivatives[], size_t nx); +FMI_STATIC FMIStatus FMI1GetEventIndicators(FMIInstance *instance, fmi1Real eventIndicators[], size_t ni); +FMI_STATIC FMIStatus FMI1EventUpdate(FMIInstance *instance, fmi1Boolean intermediateResults, fmi1EventInfo *eventInfo); +FMI_STATIC FMIStatus FMI1GetContinuousStates(FMIInstance *instance, fmi1Real states[], size_t nx); +FMI_STATIC FMIStatus FMI1GetNominalContinuousStates(FMIInstance *instance, fmi1Real x_nominal[], size_t nx); +FMI_STATIC FMIStatus FMI1GetStateValueReferences(FMIInstance *instance, fmi1ValueReference vrx[], size_t nx); +FMI_STATIC FMIStatus FMI1Terminate(FMIInstance *instance); + +/*************************************************** + FMI 1.0 for Co-Simulation Functions +****************************************************/ +FMI_STATIC const char *FMI1GetTypesPlatform(FMIInstance *instance); +FMI_STATIC FMIStatus FMI1InstantiateSlave(FMIInstance *instance, fmi1String modelIdentifier, fmi1String fmuGUID, fmi1String fmuLocation, fmi1String mimeType, fmi1Real timeout, fmi1Boolean visible, fmi1Boolean interactive, fmi1Boolean loggingOn); +FMI_STATIC FMIStatus FMI1InitializeSlave(FMIInstance *instance, fmi1Real tStart, fmi1Boolean StopTimeDefined, fmi1Real tStop); +FMI_STATIC FMIStatus FMI1TerminateSlave(FMIInstance *instance); +FMI_STATIC FMIStatus FMI1ResetSlave(FMIInstance *instance); +FMI_STATIC void FMI1FreeSlaveInstance(FMIInstance *instance); +FMI_STATIC FMIStatus FMI1SetRealInputDerivatives(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer order[], const fmi1Real value[]); +FMI_STATIC FMIStatus FMI1GetRealOutputDerivatives(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer order[], fmi1Real value[]); +FMI_STATIC FMIStatus FMI1CancelStep(FMIInstance *instance); +FMI_STATIC FMIStatus FMI1DoStep(FMIInstance *instance, fmi1Real currentCommunicationPoint, fmi1Real communicationStepSize, fmi1Boolean newStep); +FMI_STATIC FMIStatus FMI1GetStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Status *value); +FMI_STATIC FMIStatus FMI1GetRealStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Real *value); +FMI_STATIC FMIStatus FMI1GetIntegerStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Integer *value); +FMI_STATIC FMIStatus FMI1GetBooleanStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Boolean *value); +FMI_STATIC FMIStatus FMI1GetStringStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1String *value); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI2.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI2.h new file mode 100644 index 000000000..5deb36a47 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI2.h @@ -0,0 +1,219 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "FMI.h" +#include "fmi2Functions.h" + +struct FMI2Functions_ { + + fmi2CallbackFunctions callbacks; + fmi2EventInfo eventInfo; + + /*************************************************** + Common Functions for FMI 2.0 + ****************************************************/ + + /* required functions */ + fmi2GetTypesPlatformTYPE * fmi2GetTypesPlatform; + fmi2GetVersionTYPE * fmi2GetVersion; + fmi2SetDebugLoggingTYPE * fmi2SetDebugLogging; + fmi2InstantiateTYPE * fmi2Instantiate; + fmi2FreeInstanceTYPE * fmi2FreeInstance; + fmi2SetupExperimentTYPE * fmi2SetupExperiment; + fmi2EnterInitializationModeTYPE *fmi2EnterInitializationMode; + fmi2ExitInitializationModeTYPE * fmi2ExitInitializationMode; + fmi2TerminateTYPE * fmi2Terminate; + fmi2ResetTYPE * fmi2Reset; + fmi2GetRealTYPE * fmi2GetReal; + fmi2GetIntegerTYPE * fmi2GetInteger; + fmi2GetBooleanTYPE * fmi2GetBoolean; + fmi2GetStringTYPE * fmi2GetString; + fmi2SetRealTYPE * fmi2SetReal; + fmi2SetIntegerTYPE * fmi2SetInteger; + fmi2SetBooleanTYPE * fmi2SetBoolean; + fmi2SetStringTYPE * fmi2SetString; + + /* optional functions */ + fmi2GetFMUstateTYPE * fmi2GetFMUstate; + fmi2SetFMUstateTYPE * fmi2SetFMUstate; + fmi2FreeFMUstateTYPE * fmi2FreeFMUstate; + fmi2SerializedFMUstateSizeTYPE * fmi2SerializedFMUstateSize; + fmi2SerializeFMUstateTYPE * fmi2SerializeFMUstate; + fmi2DeSerializeFMUstateTYPE * fmi2DeSerializeFMUstate; + fmi2GetDirectionalDerivativeTYPE *fmi2GetDirectionalDerivative; + + /*************************************************** + Functions for FMI 2.0 for Model Exchange + ****************************************************/ + + fmi2EnterEventModeTYPE * fmi2EnterEventMode; + fmi2NewDiscreteStatesTYPE * fmi2NewDiscreteStates; + fmi2EnterContinuousTimeModeTYPE * fmi2EnterContinuousTimeMode; + fmi2CompletedIntegratorStepTYPE * fmi2CompletedIntegratorStep; + fmi2SetTimeTYPE * fmi2SetTime; + fmi2SetContinuousStatesTYPE * fmi2SetContinuousStates; + fmi2GetDerivativesTYPE * fmi2GetDerivatives; + fmi2GetEventIndicatorsTYPE * fmi2GetEventIndicators; + fmi2GetContinuousStatesTYPE * fmi2GetContinuousStates; + fmi2GetNominalsOfContinuousStatesTYPE *fmi2GetNominalsOfContinuousStates; + + /*************************************************** + Functions for FMI 2.0 for Co-Simulation + ****************************************************/ + + fmi2SetRealInputDerivativesTYPE * fmi2SetRealInputDerivatives; + fmi2GetRealOutputDerivativesTYPE *fmi2GetRealOutputDerivatives; + fmi2DoStepTYPE * fmi2DoStep; + fmi2CancelStepTYPE * fmi2CancelStep; + fmi2GetStatusTYPE * fmi2GetStatus; + fmi2GetRealStatusTYPE * fmi2GetRealStatus; + fmi2GetIntegerStatusTYPE * fmi2GetIntegerStatus; + fmi2GetBooleanStatusTYPE * fmi2GetBooleanStatus; + fmi2GetStringStatusTYPE * fmi2GetStringStatus; +}; + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers of header files and setting logging status */ +FMI_STATIC const char *FMI2GetTypesPlatform(FMIInstance *instance); + +FMI_STATIC const char *FMI2GetVersion(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2SetDebugLogging(FMIInstance *instance, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]); + +FMI_STATIC FMIStatus FMI2Instantiate(FMIInstance *instance, const char *fmuResourceLocation, fmi2Type fmuType, fmi2String fmuGUID, + fmi2Boolean visible, fmi2Boolean loggingOn); + +FMI_STATIC void FMI2FreeInstance(FMIInstance *instance); + +/* Enter and exit initialization mode, terminate and reset */ +FMI_STATIC FMIStatus FMI2SetupExperiment(FMIInstance *instance, + fmi2Boolean toleranceDefined, + fmi2Real tolerance, + fmi2Real startTime, + fmi2Boolean stopTimeDefined, + fmi2Real stopTime); + +FMI_STATIC FMIStatus FMI2EnterInitializationMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2ExitInitializationMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2Terminate(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2Reset(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2SetupExperiment(FMIInstance *instance, + fmi2Boolean toleranceDefined, + fmi2Real tolerance, + fmi2Real startTime, + fmi2Boolean stopTimeDefined, + fmi2Real stopTime); + +/* Getting and setting variable values */ +FMI_STATIC FMIStatus FMI2GetReal(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]); + +FMI_STATIC FMIStatus FMI2GetInteger(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]); + +FMI_STATIC FMIStatus FMI2GetBoolean(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]); + +FMI_STATIC FMIStatus FMI2GetString(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]); + +FMI_STATIC FMIStatus FMI2SetReal(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]); + +FMI_STATIC FMIStatus FMI2SetInteger(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]); + +FMI_STATIC FMIStatus FMI2SetBoolean(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]); + +FMI_STATIC FMIStatus FMI2SetString(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]); + +/* Getting and setting the internal FMU state */ +FMI_STATIC FMIStatus FMI2GetFMUstate(FMIInstance *instance, fmi2FMUstate *FMUstate); + +FMI_STATIC FMIStatus FMI2SetFMUstate(FMIInstance *instance, fmi2FMUstate FMUstate); + +FMI_STATIC FMIStatus FMI2FreeFMUstate(FMIInstance *instance, fmi2FMUstate *FMUstate); + +FMI_STATIC FMIStatus FMI2SerializedFMUstateSize(FMIInstance *instance, fmi2FMUstate FMUstate, size_t *size); + +FMI_STATIC FMIStatus FMI2SerializeFMUstate(FMIInstance *instance, fmi2FMUstate FMUstate, fmi2Byte serializedState[], size_t size); + +FMI_STATIC FMIStatus FMI2DeSerializeFMUstate(FMIInstance *instance, const fmi2Byte serializedState[], size_t size, fmi2FMUstate *FMUstate); + +/* Getting partial derivatives */ +FMI_STATIC FMIStatus FMI2GetDirectionalDerivative(FMIInstance * instance, + const fmi2ValueReference vUnknown_ref[], size_t nUnknown, + const fmi2ValueReference vKnown_ref[], size_t nKnown, + const fmi2Real dvKnown[], + fmi2Real dvUnknown[]); + +/*************************************************** +Types for Functions for FMI2 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ +FMI_STATIC FMIStatus FMI2EnterEventMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2NewDiscreteStates(FMIInstance *instance, fmi2EventInfo *eventInfo); + +FMI_STATIC FMIStatus FMI2EnterContinuousTimeMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI2CompletedIntegratorStep(FMIInstance *instance, + fmi2Boolean noSetFMUStatePriorToCurrentPoint, + fmi2Boolean *enterEventMode, + fmi2Boolean *terminateSimulation); + +/* Providing independent variables and re-initialization of caching */ +FMI_STATIC FMIStatus FMI2SetTime(FMIInstance *instance, fmi2Real time); + +FMI_STATIC FMIStatus FMI2SetContinuousStates(FMIInstance *instance, const fmi2Real x[], size_t nx); + +/* Evaluation of the model equations */ +FMI_STATIC FMIStatus FMI2GetDerivatives(FMIInstance *instance, fmi2Real derivatives[], size_t nx); + +FMI_STATIC FMIStatus FMI2GetEventIndicators(FMIInstance *instance, fmi2Real eventIndicators[], size_t ni); + +FMI_STATIC FMIStatus FMI2GetContinuousStates(FMIInstance *instance, fmi2Real x[], size_t nx); + +FMI_STATIC FMIStatus FMI2GetNominalsOfContinuousStates(FMIInstance *instance, fmi2Real x_nominal[], size_t nx); + +/*************************************************** +Types for Functions for FMI2 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ +FMI_STATIC FMIStatus FMI2SetRealInputDerivatives(FMIInstance * instance, + const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], + const fmi2Real value[]); + +FMI_STATIC FMIStatus FMI2GetRealOutputDerivatives(FMIInstance * instance, + const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], + fmi2Real value[]); + +FMI_STATIC FMIStatus FMI2DoStep(FMIInstance *instance, + fmi2Real currentCommunicationPoint, + fmi2Real communicationStepSize, + fmi2Boolean noSetFMUStatePriorToCurrentPoint); + +FMI_STATIC FMIStatus FMI2CancelStep(FMIInstance *instance); + +/* Inquire slave status */ +FMI_STATIC FMIStatus FMI2GetStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Status *value); + +FMI_STATIC FMIStatus FMI2GetRealStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Real *value); + +FMI_STATIC FMIStatus FMI2GetIntegerStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Integer *value); + +FMI_STATIC FMIStatus FMI2GetBooleanStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Boolean *value); + +FMI_STATIC FMIStatus FMI2GetStringStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2String *value); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI3.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI3.h new file mode 100644 index 000000000..8af3ec956 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/FMI3.h @@ -0,0 +1,560 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "FMI.h" +#include "fmi3FunctionTypes.h" + +struct FMI3Functions_ { + + fmi3Boolean eventModeUsed; + + fmi3Boolean discreteStatesNeedUpdate; + fmi3Boolean terminateSimulation; + fmi3Boolean nominalsOfContinuousStatesChanged; + fmi3Boolean valuesOfContinuousStatesChanged; + fmi3Boolean nextEventTimeDefined; + fmi3Float64 nextEventTime; + + /*************************************************** + Common Functions for FMI 3.0 + ****************************************************/ + + /* Inquire version numbers and set debug logging */ + fmi3GetVersionTYPE * fmi3GetVersion; + fmi3SetDebugLoggingTYPE *fmi3SetDebugLogging; + + /* Creation and destruction of FMU instances */ + fmi3InstantiateModelExchangeTYPE * fmi3InstantiateModelExchange; + fmi3InstantiateCoSimulationTYPE * fmi3InstantiateCoSimulation; + fmi3InstantiateScheduledExecutionTYPE *fmi3InstantiateScheduledExecution; + fmi3FreeInstanceTYPE * fmi3FreeInstance; + + /* Enter and exit initialization mode, terminate and reset */ + fmi3EnterInitializationModeTYPE *fmi3EnterInitializationMode; + fmi3ExitInitializationModeTYPE * fmi3ExitInitializationMode; + fmi3EnterEventModeTYPE * fmi3EnterEventMode; + fmi3TerminateTYPE * fmi3Terminate; + fmi3ResetTYPE * fmi3Reset; + + /* Getting and setting variable values */ + fmi3GetFloat32TYPE *fmi3GetFloat32; + fmi3GetFloat64TYPE *fmi3GetFloat64; + fmi3GetInt8TYPE * fmi3GetInt8; + fmi3GetUInt8TYPE * fmi3GetUInt8; + fmi3GetInt16TYPE * fmi3GetInt16; + fmi3GetUInt16TYPE * fmi3GetUInt16; + fmi3GetInt32TYPE * fmi3GetInt32; + fmi3GetUInt32TYPE * fmi3GetUInt32; + fmi3GetInt64TYPE * fmi3GetInt64; + fmi3GetUInt64TYPE * fmi3GetUInt64; + fmi3GetBooleanTYPE *fmi3GetBoolean; + fmi3GetStringTYPE * fmi3GetString; + fmi3GetBinaryTYPE * fmi3GetBinary; + fmi3GetClockTYPE * fmi3GetClock; + fmi3SetFloat32TYPE *fmi3SetFloat32; + fmi3SetFloat64TYPE *fmi3SetFloat64; + fmi3SetInt8TYPE * fmi3SetInt8; + fmi3SetUInt8TYPE * fmi3SetUInt8; + fmi3SetInt16TYPE * fmi3SetInt16; + fmi3SetUInt16TYPE * fmi3SetUInt16; + fmi3SetInt32TYPE * fmi3SetInt32; + fmi3SetUInt32TYPE * fmi3SetUInt32; + fmi3SetInt64TYPE * fmi3SetInt64; + fmi3SetUInt64TYPE * fmi3SetUInt64; + fmi3SetBooleanTYPE *fmi3SetBoolean; + fmi3SetStringTYPE * fmi3SetString; + fmi3SetBinaryTYPE * fmi3SetBinary; + fmi3SetClockTYPE * fmi3SetClock; + + /* Getting Variable Dependency Information */ + fmi3GetNumberOfVariableDependenciesTYPE *fmi3GetNumberOfVariableDependencies; + fmi3GetVariableDependenciesTYPE * fmi3GetVariableDependencies; + + /* Getting and setting the internal FMU state */ + fmi3GetFMUStateTYPE * fmi3GetFMUState; + fmi3SetFMUStateTYPE * fmi3SetFMUState; + fmi3FreeFMUStateTYPE * fmi3FreeFMUState; + fmi3SerializedFMUStateSizeTYPE *fmi3SerializedFMUStateSize; + fmi3SerializeFMUStateTYPE * fmi3SerializeFMUState; + fmi3DeserializeFMUStateTYPE * fmi3DeserializeFMUState; + + /* Getting partial derivatives */ + fmi3GetDirectionalDerivativeTYPE *fmi3GetDirectionalDerivative; + fmi3GetAdjointDerivativeTYPE * fmi3GetAdjointDerivative; + + /* Entering and exiting the Configuration or Reconfiguration Mode */ + fmi3EnterConfigurationModeTYPE *fmi3EnterConfigurationMode; + fmi3ExitConfigurationModeTYPE * fmi3ExitConfigurationMode; + + /* Clock related functions */ + fmi3GetIntervalDecimalTYPE * fmi3GetIntervalDecimal; + fmi3GetIntervalFractionTYPE * fmi3GetIntervalFraction; + fmi3GetShiftDecimalTYPE * fmi3GetShiftDecimal; + fmi3GetShiftFractionTYPE * fmi3GetShiftFraction; + fmi3SetIntervalDecimalTYPE * fmi3SetIntervalDecimal; + fmi3SetIntervalFractionTYPE * fmi3SetIntervalFraction; + fmi3SetShiftDecimalTYPE * fmi3SetShiftDecimal; + fmi3SetShiftFractionTYPE * fmi3SetShiftFraction; + fmi3EvaluateDiscreteStatesTYPE *fmi3EvaluateDiscreteStates; + fmi3UpdateDiscreteStatesTYPE * fmi3UpdateDiscreteStates; + + /*************************************************** + Functions for Model Exchange + ****************************************************/ + + fmi3EnterContinuousTimeModeTYPE *fmi3EnterContinuousTimeMode; + fmi3CompletedIntegratorStepTYPE *fmi3CompletedIntegratorStep; + + /* Providing independent variables and re-initialization of caching */ + fmi3SetTimeTYPE * fmi3SetTime; + fmi3SetContinuousStatesTYPE *fmi3SetContinuousStates; + + /* Evaluation of the model equations */ + fmi3GetContinuousStateDerivativesTYPE *fmi3GetContinuousStateDerivatives; + fmi3GetEventIndicatorsTYPE * fmi3GetEventIndicators; + fmi3GetContinuousStatesTYPE * fmi3GetContinuousStates; + fmi3GetNominalsOfContinuousStatesTYPE *fmi3GetNominalsOfContinuousStates; + fmi3GetNumberOfEventIndicatorsTYPE * fmi3GetNumberOfEventIndicators; + fmi3GetNumberOfContinuousStatesTYPE * fmi3GetNumberOfContinuousStates; + + /*************************************************** + Functions for FMI 3.0 for Co-Simulation + ****************************************************/ + + fmi3EnterStepModeTYPE * fmi3EnterStepMode; + fmi3GetOutputDerivativesTYPE *fmi3GetOutputDerivatives; + fmi3DoStepTYPE * fmi3DoStep; + + /*************************************************** + Functions for Scheduled Execution + ****************************************************/ + + fmi3ActivateModelPartitionTYPE *fmi3ActivateModelPartition; +}; + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers and setting logging status */ +FMI_STATIC const char *FMI3GetVersion(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3SetDebugLogging(FMIInstance * instance, + fmi3Boolean loggingOn, + size_t nCategories, + const fmi3String categories[]); + +/* Creation and destruction of FMU instances and setting debug status */ +FMI_STATIC FMIStatus FMI3InstantiateModelExchange( + FMIInstance *instance, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn); + +FMI_STATIC FMIStatus FMI3InstantiateCoSimulation( + FMIInstance * instance, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3Boolean eventModeUsed, + fmi3Boolean earlyReturnAllowed, + const fmi3ValueReference requiredIntermediateVariables[], + size_t nRequiredIntermediateVariables, + fmi3IntermediateUpdateCallback intermediateUpdate); + +FMI_STATIC FMIStatus FMI3InstantiateScheduledExecution( + FMIInstance * instance, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage, + fmi3ClockUpdateCallback clockUpdate, + fmi3LockPreemptionCallback lockPreemption, + fmi3UnlockPreemptionCallback unlockPreemption); + +FMI_STATIC FMIStatus FMI3FreeInstance(FMIInstance *instance); + +/* Enter and exit initialization mode, enter event mode, terminate and reset */ +FMI_STATIC FMIStatus FMI3EnterInitializationMode(FMIInstance *instance, + fmi3Boolean toleranceDefined, + fmi3Float64 tolerance, + fmi3Float64 startTime, + fmi3Boolean stopTimeDefined, + fmi3Float64 stopTime); + +FMI_STATIC FMIStatus FMI3ExitInitializationMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3EnterEventMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3Terminate(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3Reset(FMIInstance *instance); + +/* Getting and setting variable values */ +FMI_STATIC FMIStatus FMI3GetFloat32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float32 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetFloat64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int8 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetUInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt8 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int16 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetUInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt16 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int32 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetUInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt32 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetUInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetBoolean(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Boolean values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetString(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3String values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetBinary(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + size_t sizes[], + fmi3Binary values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3GetClock(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Clock values[]); + +FMI_STATIC FMIStatus FMI3SetFloat32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float32 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetFloat64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int8 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetUInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt8 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int16 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetUInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt16 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetUInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt32 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetUInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetBoolean(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Boolean values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetString(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3String values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetBinary(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const size_t sizes[], + const fmi3Binary values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3SetClock(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Clock values[]); + +/* Getting Variable Dependency Information */ +FMI_STATIC FMIStatus FMI3GetNumberOfVariableDependencies(FMIInstance * instance, + fmi3ValueReference valueReference, + size_t * nDependencies); + +FMI_STATIC FMIStatus FMI3GetVariableDependencies(FMIInstance * instance, + fmi3ValueReference dependent, + size_t elementIndicesOfDependent[], + fmi3ValueReference independents[], + size_t elementIndicesOfIndependents[], + fmi3DependencyKind dependencyKinds[], + size_t nDependencies); + +/* Getting and setting the internal FMU state */ +FMI_STATIC FMIStatus FMI3GetFMUState(FMIInstance *instance, fmi3FMUState *FMUState); + +FMI_STATIC FMIStatus FMI3SetFMUState(FMIInstance *instance, fmi3FMUState FMUState); + +FMI_STATIC FMIStatus FMI3FreeFMUState(FMIInstance *instance, fmi3FMUState *FMUState); + +FMI_STATIC FMIStatus FMI3SerializedFMUStateSize(FMIInstance *instance, + fmi3FMUState FMUState, + size_t * size); + +FMI_STATIC FMIStatus FMI3SerializeFMUState(FMIInstance *instance, + fmi3FMUState FMUState, + fmi3Byte serializedState[], + size_t size); + +FMI_STATIC FMIStatus FMI3DeserializeFMUState(FMIInstance * instance, + const fmi3Byte serializedState[], + size_t size, + fmi3FMUState * FMUState); + +/* Getting partial derivatives */ +FMI_STATIC FMIStatus FMI3GetDirectionalDerivative(FMIInstance * instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity); + +FMI_STATIC FMIStatus FMI3GetAdjointDerivative(FMIInstance * instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity); + +/* Entering and exiting the Configuration or Reconfiguration Mode */ +FMI_STATIC FMIStatus FMI3EnterConfigurationMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3ExitConfigurationMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3GetIntervalDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 intervals[], + fmi3IntervalQualifier qualifiers[]); + +FMI_STATIC FMIStatus FMI3GetIntervalFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 intervalCounters[], + fmi3UInt64 resolutions[], + fmi3IntervalQualifier qualifiers[]); + +FMI_STATIC FMIStatus FMI3GetShiftDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 shifts[]); + +FMI_STATIC FMIStatus FMI3GetShiftFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 shiftCounters[], + fmi3UInt64 resolutions[]); + +FMI_STATIC FMIStatus FMI3SetIntervalDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 intervals[]); + +FMI_STATIC FMIStatus FMI3SetIntervalFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 intervalCounters[], + const fmi3UInt64 resolutions[]); + +FMI_STATIC FMIStatus FMI3SetShiftDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 shifts[]); + +FMI_STATIC FMIStatus FMI3SetShiftFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 shiftCounters[], + const fmi3UInt64 resolutions[]); + +FMI_STATIC FMIStatus FMI3EvaluateDiscreteStates(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3UpdateDiscreteStates(FMIInstance *instance, + fmi3Boolean *discreteStatesNeedUpdate, + fmi3Boolean *terminateSimulation, + fmi3Boolean *nominalsOfContinuousStatesChanged, + fmi3Boolean *valuesOfContinuousStatesChanged, + fmi3Boolean *nextEventTimeDefined, + fmi3Float64 *nextEventTime); + +/*************************************************** +Functions for Model Exchange +****************************************************/ + +FMI_STATIC FMIStatus FMI3EnterContinuousTimeMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3CompletedIntegratorStep(FMIInstance *instance, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *enterEventMode, + fmi3Boolean *terminateSimulation); + +/* Providing independent variables and re-initialization of caching */ +FMI_STATIC FMIStatus FMI3SetTime(FMIInstance *instance, fmi3Float64 time); + +FMI_STATIC FMIStatus FMI3SetContinuousStates(FMIInstance * instance, + const fmi3Float64 continuousStates[], + size_t nContinuousStates); + +/* Evaluation of the model equations */ +FMI_STATIC FMIStatus FMI3GetContinuousStateDerivatives(FMIInstance *instance, + fmi3Float64 derivatives[], + size_t nContinuousStates); + +FMI_STATIC FMIStatus FMI3GetEventIndicators(FMIInstance *instance, + fmi3Float64 eventIndicators[], + size_t nEventIndicators); + +FMI_STATIC FMIStatus FMI3GetContinuousStates(FMIInstance *instance, + fmi3Float64 continuousStates[], + size_t nContinuousStates); + +FMI_STATIC FMIStatus FMI3GetNominalsOfContinuousStates(FMIInstance *instance, + fmi3Float64 nominals[], + size_t nContinuousStates); + +FMI_STATIC FMIStatus FMI3GetNumberOfEventIndicators(FMIInstance *instance, + size_t * nEventIndicators); + +FMI_STATIC FMIStatus FMI3GetNumberOfContinuousStates(FMIInstance *instance, + size_t * nContinuousStates); + +/*************************************************** +Functions for Co-Simulation +****************************************************/ + +/* Simulating the FMU */ + +FMI_STATIC FMIStatus FMI3EnterStepMode(FMIInstance *instance); + +FMI_STATIC FMIStatus FMI3GetOutputDerivatives(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 orders[], + fmi3Float64 values[], + size_t nValues); + +FMI_STATIC FMIStatus FMI3DoStep(FMIInstance *instance, + fmi3Float64 currentCommunicationPoint, + fmi3Float64 communicationStepSize, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *eventHandlingNeeded, + fmi3Boolean *terminateSimulation, + fmi3Boolean *earlyReturn, + fmi3Float64 *lastSuccessfulTime); + +/*************************************************** +Functions for Scheduled Execution +****************************************************/ + +FMI_STATIC FMIStatus FMI3ActivateModelPartition(FMIInstance * instance, + fmi3ValueReference clockReference, + fmi3Float64 activationTime); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/cosimulation.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/cosimulation.h new file mode 100644 index 000000000..03cf8fe80 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/cosimulation.h @@ -0,0 +1,8 @@ +#pragma once + +#include "model.h" + +#define EPSILON (FIXED_SOLVER_STEP * 1e-6) + +void doFixedStep(ModelInstance *comp, bool *stateEvent, bool *timeEvent); +void doAdaptiveStep(ModelInstance *comp, bool *stateEvent, bool *timeEvent); diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi1Functions.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi1Functions.h new file mode 100644 index 000000000..6bcb97d30 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi1Functions.h @@ -0,0 +1,116 @@ +#pragma once + +/* ------------------------------------------------------------------------- + * Combined FMI 1.0 Functions for Model Exchange & Co-Simulation + * -------------------------------------------------------------------------*/ + +/* Type definitions */ +typedef void * fmi1Component; +typedef unsigned int fmi1ValueReference; +typedef double fmi1Real; +typedef int fmi1Integer; +typedef char fmi1Boolean; +typedef const char * fmi1String; + +/* Values for fmi1Boolean */ +#define fmi1True 1 +#define fmi1False 0 + +/* Undefined value for fmi1ValueReference (largest unsigned int value) */ +#define fmi1UndefinedValueReference (fmi1ValueReference)(-1) + +/* make sure all compiler use the same alignment policies for structures */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(push, 8) +#endif + +typedef enum { + fmi1OK, + fmi1Warning, + fmi1Discard, + fmi1Error, + fmi1Fatal +} fmi1Status; + +typedef enum { + fmi1DoStepStatus, + fmi1PendingStatus, + fmi1LastSuccessfulTime +} fmi1StatusKind; + +typedef void (*fmi1CallbackLogger)(fmi1Component c, fmi1String instanceName, fmi1Status status, fmi1String category, fmi1String message, ...); +typedef void *(*fmi1CallbackAllocateMemory)(size_t nobj, size_t size); +typedef void (*fmi1CallbackFreeMemory)(void *obj); +typedef void (*fmi1StepFinished)(fmi1Component c, fmi1Status status); + +typedef struct { + fmi1CallbackLogger logger; + fmi1CallbackAllocateMemory allocateMemory; + fmi1CallbackFreeMemory freeMemory; + fmi1StepFinished stepFinished; +} fmi1CallbackFunctions; + +typedef struct { + fmi1Boolean iterationConverged; + fmi1Boolean stateValueReferencesChanged; + fmi1Boolean stateValuesChanged; + fmi1Boolean terminateSimulation; + fmi1Boolean upcomingTimeEvent; + fmi1Real nextEventTime; +} fmi1EventInfo; + +/* reset alignment policy to the one set before reading this file */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(pop) +#endif + +/*************************************************** + Common Functions for FMI 1.0 +****************************************************/ +typedef fmi1Status fmi1SetRealTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, const fmi1Real value[]); +typedef fmi1Status fmi1SetIntegerTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer value[]); +typedef fmi1Status fmi1SetBooleanTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, const fmi1Boolean value[]); +typedef fmi1Status fmi1SetStringTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, const fmi1String value[]); +typedef fmi1Status fmi1GetRealTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, fmi1Real value[]); +typedef fmi1Status fmi1GetIntegerTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, fmi1Integer value[]); +typedef fmi1Status fmi1GetBooleanTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, fmi1Boolean value[]); +typedef fmi1Status fmi1GetStringTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, fmi1String value[]); +typedef fmi1Status fmi1SetDebugLoggingTYPE(fmi1Component c, fmi1Boolean loggingOn); + +/*************************************************** + FMI 1.0 for Model Exchange Functions +****************************************************/ +typedef const char * fmi1GetModelTypesPlatformTYPE(); +typedef const char * fmi1GetVersionTYPE(); +typedef fmi1Component fmi1InstantiateModelTYPE(fmi1String instanceName, fmi1String GUID, fmi1CallbackFunctions functions, fmi1Boolean loggingOn); +typedef void fmi1FreeModelInstanceTYPE(fmi1Component c); +typedef fmi1Status fmi1SetTimeTYPE(fmi1Component c, fmi1Real time); +typedef fmi1Status fmi1SetContinuousStatesTYPE(fmi1Component c, const fmi1Real x[], size_t nx); +typedef fmi1Status fmi1CompletedIntegratorStepTYPE(fmi1Component c, fmi1Boolean *callEventUpdate); +typedef fmi1Status fmi1InitializeTYPE(fmi1Component c, fmi1Boolean toleranceControlled, fmi1Real relativeTolerance, fmi1EventInfo *eventInfo); +typedef fmi1Status fmi1GetDerivativesTYPE(fmi1Component c, fmi1Real derivatives[], size_t nx); +typedef fmi1Status fmi1GetEventIndicatorsTYPE(fmi1Component c, fmi1Real eventIndicators[], size_t ni); +typedef fmi1Status fmi1EventUpdateTYPE(fmi1Component c, fmi1Boolean intermediateResults, fmi1EventInfo *eventInfo); +typedef fmi1Status fmi1GetContinuousStatesTYPE(fmi1Component c, fmi1Real states[], size_t nx); +typedef fmi1Status fmi1GetNominalContinuousStatesTYPE(fmi1Component c, fmi1Real x_nominal[], size_t nx); +typedef fmi1Status fmi1GetStateValueReferencesTYPE(fmi1Component c, fmi1ValueReference vrx[], size_t nx); +typedef fmi1Status fmi1TerminateTYPE(fmi1Component c); + +/*************************************************** + FMI 1.0 for Co-Simulation Functions +****************************************************/ +typedef const char * fmi1GetTypesPlatformTYPE(); +typedef fmi1Component fmi1InstantiateSlaveTYPE(fmi1String instanceName, fmi1String fmuGUID, fmi1String fmuLocation, fmi1String mimeType, fmi1Real timeout, fmi1Boolean visible, fmi1Boolean interactive, fmi1CallbackFunctions functions, fmi1Boolean loggingOn); +typedef fmi1Status fmi1InitializeSlaveTYPE(fmi1Component c, fmi1Real tStart, fmi1Boolean StopTimeDefined, fmi1Real tStop); +typedef fmi1Status fmi1TerminateSlaveTYPE(fmi1Component c); +typedef fmi1Status fmi1ResetSlaveTYPE(fmi1Component c); +typedef void fmi1FreeSlaveInstanceTYPE(fmi1Component c); +typedef fmi1Status fmi1SetRealInputDerivativesTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer order[], const fmi1Real value[]); +typedef fmi1Status fmi1GetRealOutputDerivativesTYPE(fmi1Component c, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer order[], fmi1Real value[]); +typedef fmi1Status fmi1CancelStepTYPE(fmi1Component c); +typedef fmi1Status fmi1DoStepTYPE(fmi1Component c, fmi1Real currentCommunicationPoint, fmi1Real communicationStepSize, fmi1Boolean newStep); +typedef fmi1Status fmi1GetStatusTYPE(fmi1Component c, const fmi1StatusKind s, fmi1Status *value); +typedef fmi1Status fmi1GetRealStatusTYPE(fmi1Component c, const fmi1StatusKind s, fmi1Real *value); +typedef fmi1Status fmi1GetIntegerStatusTYPE(fmi1Component c, const fmi1StatusKind s, fmi1Integer *value); +typedef fmi1Status fmi1GetBooleanStatusTYPE(fmi1Component c, const fmi1StatusKind s, fmi1Boolean *value); +typedef fmi1Status fmi1GetStringStatusTYPE(fmi1Component c, const fmi1StatusKind s, fmi1String *value); diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2FunctionTypes.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2FunctionTypes.h new file mode 100644 index 000000000..916a6edee --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2FunctionTypes.h @@ -0,0 +1,266 @@ +#ifndef fmi2FunctionTypes_h +#define fmi2FunctionTypes_h + +#include "fmi2TypesPlatform.h" + +/* This header file must be utilized when compiling an FMU or an FMI master. + It declares data and function types for FMI 2.0.1 + + Revisions: + - Sep. 30, 2019: License changed to 2-clause BSD License (without extensions) + - Jul. 5, 2019: Remove const modifier from fields of fmi2CallbackFunctions (#216) + - Sep. 6, 2018: Parameter names added to function prototypes + - Apr. 9, 2014: all prefixes "fmi" renamed to "fmi2" (decision from April 8) + - Apr. 3, 2014: Added #include for size_t definition + - Mar. 27, 2014: Added #include "fmiTypesPlatform.h" (#179) + - Mar. 26, 2014: Introduced function argument "void" for the functions (#171) + fmiGetTypesPlatformTYPE and fmiGetVersionTYPE + - Oct. 11, 2013: Functions of ModelExchange and CoSimulation merged: + fmiInstantiateModelTYPE , fmiInstantiateSlaveTYPE -> fmiInstantiateTYPE + fmiFreeModelInstanceTYPE, fmiFreeSlaveInstanceTYPE -> fmiFreeInstanceTYPE + fmiEnterModelInitializationModeTYPE, fmiEnterSlaveInitializationModeTYPE -> fmiEnterInitializationModeTYPE + fmiExitModelInitializationModeTYPE , fmiExitSlaveInitializationModeTYPE -> fmiExitInitializationModeTYPE + fmiTerminateModelTYPE , fmiTerminateSlaveTYPE -> fmiTerminate + fmiResetSlave -> fmiReset (now also for ModelExchange and not only for CoSimulation) + Functions renamed + fmiUpdateDiscreteStatesTYPE -> fmiNewDiscreteStatesTYPE + Renamed elements of the enumeration fmiEventInfo + upcomingTimeEvent -> nextEventTimeDefined // due to generic naming scheme: varDefined + var + newUpdateDiscreteStatesNeeded -> newDiscreteStatesNeeded; + - June 13, 2013: Changed type fmiEventInfo + Functions removed: + fmiInitializeModelTYPE + fmiEventUpdateTYPE + fmiCompletedEventIterationTYPE + fmiInitializeSlaveTYPE + Functions added: + fmiEnterModelInitializationModeTYPE + fmiExitModelInitializationModeTYPE + fmiEnterEventModeTYPE + fmiUpdateDiscreteStatesTYPE + fmiEnterContinuousTimeModeTYPE + fmiEnterSlaveInitializationModeTYPE; + fmiExitSlaveInitializationModeTYPE; + - Feb. 17, 2013: Added third argument to fmiCompletedIntegratorStepTYPE + Changed function name "fmiTerminateType" to "fmiTerminateModelType" (due to #113) + Changed function name "fmiGetNominalContinuousStateTYPE" to + "fmiGetNominalsOfContinuousStatesTYPE" + Removed fmiGetStateValueReferencesTYPE. + - Nov. 14, 2011: First public Version + + + Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2019 Modelica Association Project "FMI" + All rights reserved. + + This file is licensed by the copyright holders under the 2-Clause BSD License + (https://opensource.org/licenses/BSD-2-Clause): + + ---------------------------------------------------------------------------- + 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. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* make sure all compiler use the same alignment policies for structures */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(push, 8) +#endif + +/* Include stddef.h, in order that size_t etc. is defined */ +#include + +/* Type definitions */ +typedef enum { + fmi2OK, + fmi2Warning, + fmi2Discard, + fmi2Error, + fmi2Fatal, + fmi2Pending +} fmi2Status; + +typedef enum { + fmi2ModelExchange, + fmi2CoSimulation +} fmi2Type; + +typedef enum { + fmi2DoStepStatus, + fmi2PendingStatus, + fmi2LastSuccessfulTime, + fmi2Terminated +} fmi2StatusKind; + +typedef void (*fmi2CallbackLogger)(fmi2ComponentEnvironment componentEnvironment, + fmi2String instanceName, + fmi2Status status, + fmi2String category, + fmi2String message, + ...); +typedef void *(*fmi2CallbackAllocateMemory)(size_t nobj, size_t size); +typedef void (*fmi2CallbackFreeMemory)(void *obj); +typedef void (*fmi2StepFinished)(fmi2ComponentEnvironment componentEnvironment, + fmi2Status status); + +typedef struct { + fmi2CallbackLogger logger; + fmi2CallbackAllocateMemory allocateMemory; + fmi2CallbackFreeMemory freeMemory; + fmi2StepFinished stepFinished; + fmi2ComponentEnvironment componentEnvironment; +} fmi2CallbackFunctions; + +typedef struct { + fmi2Boolean newDiscreteStatesNeeded; + fmi2Boolean terminateSimulation; + fmi2Boolean nominalsOfContinuousStatesChanged; + fmi2Boolean valuesOfContinuousStatesChanged; + fmi2Boolean nextEventTimeDefined; + fmi2Real nextEventTime; +} fmi2EventInfo; + +/* reset alignment policy to the one set before reading this file */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(pop) +#endif + +/* Define fmi2 function pointer types to simplify dynamic loading */ + +/*************************************************** +Types for Common Functions +****************************************************/ + +/* Inquire version numbers of header files and setting logging status */ +typedef const char *fmi2GetTypesPlatformTYPE(void); +typedef const char *fmi2GetVersionTYPE(void); +typedef fmi2Status fmi2SetDebugLoggingTYPE(fmi2Component c, + fmi2Boolean loggingOn, + size_t nCategories, + const fmi2String categories[]); + +/* Creation and destruction of FMU instances and setting debug status */ +typedef fmi2Component fmi2InstantiateTYPE(fmi2String instanceName, + fmi2Type fmuType, + fmi2String fmuGUID, + fmi2String fmuResourceLocation, + const fmi2CallbackFunctions *functions, + fmi2Boolean visible, + fmi2Boolean loggingOn); +typedef void fmi2FreeInstanceTYPE(fmi2Component c); + +/* Enter and exit initialization mode, terminate and reset */ +typedef fmi2Status fmi2SetupExperimentTYPE(fmi2Component c, + fmi2Boolean toleranceDefined, + fmi2Real tolerance, + fmi2Real startTime, + fmi2Boolean stopTimeDefined, + fmi2Real stopTime); +typedef fmi2Status fmi2EnterInitializationModeTYPE(fmi2Component c); +typedef fmi2Status fmi2ExitInitializationModeTYPE(fmi2Component c); +typedef fmi2Status fmi2TerminateTYPE(fmi2Component c); +typedef fmi2Status fmi2ResetTYPE(fmi2Component c); + +/* Getting and setting variable values */ +typedef fmi2Status fmi2GetRealTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]); +typedef fmi2Status fmi2GetIntegerTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]); +typedef fmi2Status fmi2GetBooleanTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]); +typedef fmi2Status fmi2GetStringTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]); + +typedef fmi2Status fmi2SetRealTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]); +typedef fmi2Status fmi2SetIntegerTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]); +typedef fmi2Status fmi2SetBooleanTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]); +typedef fmi2Status fmi2SetStringTYPE(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]); + +/* Getting and setting the internal FMU state */ +typedef fmi2Status fmi2GetFMUstateTYPE(fmi2Component c, fmi2FMUstate *FMUstate); +typedef fmi2Status fmi2SetFMUstateTYPE(fmi2Component c, fmi2FMUstate FMUstate); +typedef fmi2Status fmi2FreeFMUstateTYPE(fmi2Component c, fmi2FMUstate *FMUstate); +typedef fmi2Status fmi2SerializedFMUstateSizeTYPE(fmi2Component c, fmi2FMUstate FMUstate, size_t *size); +typedef fmi2Status fmi2SerializeFMUstateTYPE(fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte[], size_t size); +typedef fmi2Status fmi2DeSerializeFMUstateTYPE(fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate *FMUstate); + +/* Getting partial derivatives */ +typedef fmi2Status fmi2GetDirectionalDerivativeTYPE(fmi2Component c, + const fmi2ValueReference vUnknown_ref[], size_t nUnknown, + const fmi2ValueReference vKnown_ref[], size_t nKnown, + const fmi2Real dvKnown[], + fmi2Real dvUnknown[]); + +/*************************************************** +Types for Functions for FMI2 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ +typedef fmi2Status fmi2EnterEventModeTYPE(fmi2Component c); +typedef fmi2Status fmi2NewDiscreteStatesTYPE(fmi2Component c, fmi2EventInfo *fmi2eventInfo); +typedef fmi2Status fmi2EnterContinuousTimeModeTYPE(fmi2Component c); +typedef fmi2Status fmi2CompletedIntegratorStepTYPE(fmi2Component c, + fmi2Boolean noSetFMUStatePriorToCurrentPoint, + fmi2Boolean * enterEventMode, + fmi2Boolean * terminateSimulation); + +/* Providing independent variables and re-initialization of caching */ +typedef fmi2Status fmi2SetTimeTYPE(fmi2Component c, fmi2Real time); +typedef fmi2Status fmi2SetContinuousStatesTYPE(fmi2Component c, const fmi2Real x[], size_t nx); + +/* Evaluation of the model equations */ +typedef fmi2Status fmi2GetDerivativesTYPE(fmi2Component c, fmi2Real derivatives[], size_t nx); +typedef fmi2Status fmi2GetEventIndicatorsTYPE(fmi2Component c, fmi2Real eventIndicators[], size_t ni); +typedef fmi2Status fmi2GetContinuousStatesTYPE(fmi2Component c, fmi2Real x[], size_t nx); +typedef fmi2Status fmi2GetNominalsOfContinuousStatesTYPE(fmi2Component c, fmi2Real x_nominal[], size_t nx); + +/*************************************************** +Types for Functions for FMI2 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ +typedef fmi2Status fmi2SetRealInputDerivativesTYPE(fmi2Component c, + const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], + const fmi2Real value[]); +typedef fmi2Status fmi2GetRealOutputDerivativesTYPE(fmi2Component c, + const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], + fmi2Real value[]); +typedef fmi2Status fmi2DoStepTYPE(fmi2Component c, + fmi2Real currentCommunicationPoint, + fmi2Real communicationStepSize, + fmi2Boolean noSetFMUStatePriorToCurrentPoint); +typedef fmi2Status fmi2CancelStepTYPE(fmi2Component c); + +/* Inquire slave status */ +typedef fmi2Status fmi2GetStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2Status *value); +typedef fmi2Status fmi2GetRealStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2Real *value); +typedef fmi2Status fmi2GetIntegerStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value); +typedef fmi2Status fmi2GetBooleanStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value); +typedef fmi2Status fmi2GetStringStatusTYPE(fmi2Component c, const fmi2StatusKind s, fmi2String *value); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi2FunctionTypes_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2Functions.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2Functions.h new file mode 100644 index 000000000..dbdb03ee2 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2Functions.h @@ -0,0 +1,321 @@ +#ifndef fmi2Functions_h +#define fmi2Functions_h + +/* This header file must be utilized when compiling a FMU. + It defines all functions of the + FMI 2.0.1 Model Exchange and Co-Simulation Interface. + + In order to have unique function names even if several FMUs + are compiled together (e.g. for embedded systems), every "real" function name + is constructed by prepending the function name by "FMI2_FUNCTION_PREFIX". + Therefore, the typical usage is: + + #define FMI2_FUNCTION_PREFIX MyModel_ + #include "fmi2Functions.h" + + As a result, a function that is defined as "fmi2GetDerivatives" in this header file, + is actually getting the name "MyModel_fmi2GetDerivatives". + + This only holds if the FMU is shipped in C source code, or is compiled in a + static link library. For FMUs compiled in a DLL/sharedObject, the "actual" function + names are used and "FMI2_FUNCTION_PREFIX" must not be defined. + + Revisions: + - Sep. 29, 2019: License changed to 2-clause BSD License (without extensions) + - Apr. 9, 2014: All prefixes "fmi" renamed to "fmi2" (decision from April 8) + - Mar. 26, 2014: FMI_Export set to empty value if FMI_Export and FMI_FUNCTION_PREFIX + are not defined (#173) + - Oct. 11, 2013: Functions of ModelExchange and CoSimulation merged: + fmiInstantiateModel , fmiInstantiateSlave -> fmiInstantiate + fmiFreeModelInstance, fmiFreeSlaveInstance -> fmiFreeInstance + fmiEnterModelInitializationMode, fmiEnterSlaveInitializationMode -> fmiEnterInitializationMode + fmiExitModelInitializationMode , fmiExitSlaveInitializationMode -> fmiExitInitializationMode + fmiTerminateModel, fmiTerminateSlave -> fmiTerminate + fmiResetSlave -> fmiReset (now also for ModelExchange and not only for CoSimulation) + Functions renamed: + fmiUpdateDiscreteStates -> fmiNewDiscreteStates + - June 13, 2013: Functions removed: + fmiInitializeModel + fmiEventUpdate + fmiCompletedEventIteration + fmiInitializeSlave + Functions added: + fmiEnterModelInitializationMode + fmiExitModelInitializationMode + fmiEnterEventMode + fmiUpdateDiscreteStates + fmiEnterContinuousTimeMode + fmiEnterSlaveInitializationMode; + fmiExitSlaveInitializationMode; + - Feb. 17, 2013: Portability improvements: + o DllExport changed to FMI_Export + o FUNCTION_PREFIX changed to FMI_FUNCTION_PREFIX + o Allow undefined FMI_FUNCTION_PREFIX (meaning no prefix is used) + Changed function name "fmiTerminate" to "fmiTerminateModel" (due to #113) + Changed function name "fmiGetNominalContinuousState" to + "fmiGetNominalsOfContinuousStates" + Removed fmiGetStateValueReferences. + - Nov. 14, 2011: Adapted to FMI 2.0: + o Split into two files (fmiFunctions.h, fmiTypes.h) in order + that code that dynamically loads an FMU can directly + utilize the header files). + o Added C++ encapsulation of C-part, in order that the header + file can be directly utilized in C++ code. + o fmiCallbackFunctions is passed as pointer to fmiInstantiateXXX + o stepFinished within fmiCallbackFunctions has as first + argument "fmiComponentEnvironment" and not "fmiComponent". + o New functions to get and set the complete FMU state + and to compute partial derivatives. + - Nov. 4, 2010: Adapted to specification text: + o fmiGetModelTypesPlatform renamed to fmiGetTypesPlatform + o fmiInstantiateSlave: Argument GUID replaced by fmuGUID + Argument mimetype replaced by mimeType + o tabs replaced by spaces + - Oct. 16, 2010: Functions for FMI for Co-simulation added + - Jan. 20, 2010: stateValueReferencesChanged added to struct fmiEventInfo (ticket #27) + (by M. Otter, DLR) + Added WIN32 pragma to define the struct layout (ticket #34) + (by J. Mauss, QTronic) + - Jan. 4, 2010: Removed argument intermediateResults from fmiInitialize + Renamed macro fmiGetModelFunctionsVersion to fmiGetVersion + Renamed macro fmiModelFunctionsVersion to fmiVersion + Replaced fmiModel by fmiComponent in decl of fmiInstantiateModel + (by J. Mauss, QTronic) + - Dec. 17, 2009: Changed extension "me" to "fmi" (by Martin Otter, DLR). + - Dez. 14, 2009: Added eventInfo to meInitialize and added + meGetNominalContinuousStates (by Martin Otter, DLR) + - Sept. 9, 2009: Added DllExport (according to Peter Nilsson's suggestion) + (by A. Junghanns, QTronic) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + meInquireModelTypesVersion -> meGetModelTypesPlatform + meInquireModelFunctionsVersion -> meGetModelFunctionsVersion + meSetStates -> meSetContinuousStates + meGetStates -> meGetContinuousStates + removal of meInitializeModelClass + removal of meGetTime + change of arguments of meInstantiateModel + change of arguments of meCompletedIntegratorStep + (by Martin Otter, DLR): + - July 19, 2009: Added "me" as prefix to file names (by Martin Otter, DLR). + - March 2, 2009: Changed function definitions according to the last design + meeting with additional improvements (by Martin Otter, DLR). + - Dec. 3 , 2008: First version by Martin Otter (DLR) and Hans Olsson (Dynasim). + + + Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2019 Modelica Association Project "FMI" + All rights reserved. + + This file is licensed by the copyright holders under the 2-Clause BSD License + (https://opensource.org/licenses/BSD-2-Clause): + + ---------------------------------------------------------------------------- + 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. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "fmi2FunctionTypes.h" +#include "fmi2TypesPlatform.h" + +/* + Export FMI2 API functions on Windows and under GCC. + If custom linking is desired then the FMI2_Export must be + defined before including this file. For instance, + it may be set to __declspec(dllimport). +*/ +#if !defined(FMI2_Export) +#if !defined(FMI2_FUNCTION_PREFIX) +#if defined _WIN32 || defined __CYGWIN__ +/* Note: both gcc & MSVC on Windows support this syntax. */ +#define FMI2_Export __declspec(dllexport) +#else +#if __GNUC__ >= 4 +#define FMI2_Export __attribute__((visibility("default"))) +#else +#define FMI2_Export +#endif +#endif +#else +#define FMI2_Export +#endif +#endif + +/* Macros to construct the real function name + (prepend function name by FMI2_FUNCTION_PREFIX) */ +#if defined(FMI2_FUNCTION_PREFIX) +#define fmi2Paste(a, b) a##b +#define fmi2PasteB(a, b) fmi2Paste(a, b) +#define fmi2FullName(name) fmi2PasteB(FMI2_FUNCTION_PREFIX, name) +#else +#define fmi2FullName(name) name +#endif + +/*************************************************** +Common Functions +****************************************************/ +#define fmi2GetTypesPlatform fmi2FullName(fmi2GetTypesPlatform) +#define fmi2GetVersion fmi2FullName(fmi2GetVersion) +#define fmi2SetDebugLogging fmi2FullName(fmi2SetDebugLogging) +#define fmi2Instantiate fmi2FullName(fmi2Instantiate) +#define fmi2FreeInstance fmi2FullName(fmi2FreeInstance) +#define fmi2SetupExperiment fmi2FullName(fmi2SetupExperiment) +#define fmi2EnterInitializationMode fmi2FullName(fmi2EnterInitializationMode) +#define fmi2ExitInitializationMode fmi2FullName(fmi2ExitInitializationMode) +#define fmi2Terminate fmi2FullName(fmi2Terminate) +#define fmi2Reset fmi2FullName(fmi2Reset) +#define fmi2GetReal fmi2FullName(fmi2GetReal) +#define fmi2GetInteger fmi2FullName(fmi2GetInteger) +#define fmi2GetBoolean fmi2FullName(fmi2GetBoolean) +#define fmi2GetString fmi2FullName(fmi2GetString) +#define fmi2SetReal fmi2FullName(fmi2SetReal) +#define fmi2SetInteger fmi2FullName(fmi2SetInteger) +#define fmi2SetBoolean fmi2FullName(fmi2SetBoolean) +#define fmi2SetString fmi2FullName(fmi2SetString) +#define fmi2GetFMUstate fmi2FullName(fmi2GetFMUstate) +#define fmi2SetFMUstate fmi2FullName(fmi2SetFMUstate) +#define fmi2FreeFMUstate fmi2FullName(fmi2FreeFMUstate) +#define fmi2SerializedFMUstateSize fmi2FullName(fmi2SerializedFMUstateSize) +#define fmi2SerializeFMUstate fmi2FullName(fmi2SerializeFMUstate) +#define fmi2DeSerializeFMUstate fmi2FullName(fmi2DeSerializeFMUstate) +#define fmi2GetDirectionalDerivative fmi2FullName(fmi2GetDirectionalDerivative) + +/*************************************************** +Functions for FMI2 for Model Exchange +****************************************************/ +#define fmi2EnterEventMode fmi2FullName(fmi2EnterEventMode) +#define fmi2NewDiscreteStates fmi2FullName(fmi2NewDiscreteStates) +#define fmi2EnterContinuousTimeMode fmi2FullName(fmi2EnterContinuousTimeMode) +#define fmi2CompletedIntegratorStep fmi2FullName(fmi2CompletedIntegratorStep) +#define fmi2SetTime fmi2FullName(fmi2SetTime) +#define fmi2SetContinuousStates fmi2FullName(fmi2SetContinuousStates) +#define fmi2GetDerivatives fmi2FullName(fmi2GetDerivatives) +#define fmi2GetEventIndicators fmi2FullName(fmi2GetEventIndicators) +#define fmi2GetContinuousStates fmi2FullName(fmi2GetContinuousStates) +#define fmi2GetNominalsOfContinuousStates fmi2FullName(fmi2GetNominalsOfContinuousStates) + +/*************************************************** +Functions for FMI2 for Co-Simulation +****************************************************/ +#define fmi2SetRealInputDerivatives fmi2FullName(fmi2SetRealInputDerivatives) +#define fmi2GetRealOutputDerivatives fmi2FullName(fmi2GetRealOutputDerivatives) +#define fmi2DoStep fmi2FullName(fmi2DoStep) +#define fmi2CancelStep fmi2FullName(fmi2CancelStep) +#define fmi2GetStatus fmi2FullName(fmi2GetStatus) +#define fmi2GetRealStatus fmi2FullName(fmi2GetRealStatus) +#define fmi2GetIntegerStatus fmi2FullName(fmi2GetIntegerStatus) +#define fmi2GetBooleanStatus fmi2FullName(fmi2GetBooleanStatus) +#define fmi2GetStringStatus fmi2FullName(fmi2GetStringStatus) + +/* Version number */ +#define fmi2Version "2.0" + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers of header files */ +FMI2_Export fmi2GetTypesPlatformTYPE fmi2GetTypesPlatform; +FMI2_Export fmi2GetVersionTYPE fmi2GetVersion; +FMI2_Export fmi2SetDebugLoggingTYPE fmi2SetDebugLogging; + +/* Creation and destruction of FMU instances */ +FMI2_Export fmi2InstantiateTYPE fmi2Instantiate; +FMI2_Export fmi2FreeInstanceTYPE fmi2FreeInstance; + +/* Enter and exit initialization mode, terminate and reset */ +FMI2_Export fmi2SetupExperimentTYPE fmi2SetupExperiment; +FMI2_Export fmi2EnterInitializationModeTYPE fmi2EnterInitializationMode; +FMI2_Export fmi2ExitInitializationModeTYPE fmi2ExitInitializationMode; +FMI2_Export fmi2TerminateTYPE fmi2Terminate; +FMI2_Export fmi2ResetTYPE fmi2Reset; + +/* Getting and setting variables values */ +FMI2_Export fmi2GetRealTYPE fmi2GetReal; +FMI2_Export fmi2GetIntegerTYPE fmi2GetInteger; +FMI2_Export fmi2GetBooleanTYPE fmi2GetBoolean; +FMI2_Export fmi2GetStringTYPE fmi2GetString; + +FMI2_Export fmi2SetRealTYPE fmi2SetReal; +FMI2_Export fmi2SetIntegerTYPE fmi2SetInteger; +FMI2_Export fmi2SetBooleanTYPE fmi2SetBoolean; +FMI2_Export fmi2SetStringTYPE fmi2SetString; + +/* Getting and setting the internal FMU state */ +FMI2_Export fmi2GetFMUstateTYPE fmi2GetFMUstate; +FMI2_Export fmi2SetFMUstateTYPE fmi2SetFMUstate; +FMI2_Export fmi2FreeFMUstateTYPE fmi2FreeFMUstate; +FMI2_Export fmi2SerializedFMUstateSizeTYPE fmi2SerializedFMUstateSize; +FMI2_Export fmi2SerializeFMUstateTYPE fmi2SerializeFMUstate; +FMI2_Export fmi2DeSerializeFMUstateTYPE fmi2DeSerializeFMUstate; + +/* Getting partial derivatives */ +FMI2_Export fmi2GetDirectionalDerivativeTYPE fmi2GetDirectionalDerivative; + +/*************************************************** +Functions for FMI2 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ +FMI2_Export fmi2EnterEventModeTYPE fmi2EnterEventMode; +FMI2_Export fmi2NewDiscreteStatesTYPE fmi2NewDiscreteStates; +FMI2_Export fmi2EnterContinuousTimeModeTYPE fmi2EnterContinuousTimeMode; +FMI2_Export fmi2CompletedIntegratorStepTYPE fmi2CompletedIntegratorStep; + +/* Providing independent variables and re-initialization of caching */ +FMI2_Export fmi2SetTimeTYPE fmi2SetTime; +FMI2_Export fmi2SetContinuousStatesTYPE fmi2SetContinuousStates; + +/* Evaluation of the model equations */ +FMI2_Export fmi2GetDerivativesTYPE fmi2GetDerivatives; +FMI2_Export fmi2GetEventIndicatorsTYPE fmi2GetEventIndicators; +FMI2_Export fmi2GetContinuousStatesTYPE fmi2GetContinuousStates; +FMI2_Export fmi2GetNominalsOfContinuousStatesTYPE fmi2GetNominalsOfContinuousStates; + +/*************************************************** +Functions for FMI2 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ +FMI2_Export fmi2SetRealInputDerivativesTYPE fmi2SetRealInputDerivatives; +FMI2_Export fmi2GetRealOutputDerivativesTYPE fmi2GetRealOutputDerivatives; + +FMI2_Export fmi2DoStepTYPE fmi2DoStep; +FMI2_Export fmi2CancelStepTYPE fmi2CancelStep; + +/* Inquire slave status */ +FMI2_Export fmi2GetStatusTYPE fmi2GetStatus; +FMI2_Export fmi2GetRealStatusTYPE fmi2GetRealStatus; +FMI2_Export fmi2GetIntegerStatusTYPE fmi2GetIntegerStatus; +FMI2_Export fmi2GetBooleanStatusTYPE fmi2GetBooleanStatus; +FMI2_Export fmi2GetStringStatusTYPE fmi2GetStringStatus; + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi2Functions_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2TypesPlatform.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2TypesPlatform.h new file mode 100644 index 000000000..21439522d --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi2TypesPlatform.h @@ -0,0 +1,107 @@ +#ifndef fmi2TypesPlatform_h +#define fmi2TypesPlatform_h + +/* Standard header file to define the argument types of the + functions of the Functional Mock-up Interface 2.0.1 + This header file must be utilized both by the model and + by the simulation engine. + + Revisions: + - Sep. 29, 2019: License changed to 2-clause BSD License (without extensions) + - Apr. 9, 2014: All prefixes "fmi" renamed to "fmi2" (decision from April 8) + - Mar 31, 2014: New datatype fmiChar introduced. + - Feb. 17, 2013: Changed fmiTypesPlatform from "standard32" to "default". + Removed fmiUndefinedValueReference since no longer needed + (because every state is defined in ScalarVariables). + - March 20, 2012: Renamed from fmiPlatformTypes.h to fmiTypesPlatform.h + - Nov. 14, 2011: Use the header file "fmiPlatformTypes.h" for FMI 2.0 + both for "FMI for model exchange" and for "FMI for co-simulation" + New types "fmiComponentEnvironment", "fmiState", and "fmiByte". + The implementation of "fmiBoolean" is change from "char" to "int". + The #define "fmiPlatform" changed to "fmiTypesPlatform" + (in order that #define and function call are consistent) + - Oct. 4, 2010: Renamed header file from "fmiModelTypes.h" to fmiPlatformTypes.h" + for the co-simulation interface + - Jan. 4, 2010: Renamed meModelTypes_h to fmiModelTypes_h (by Mauss, QTronic) + - Dec. 21, 2009: Changed "me" to "fmi" and "meModel" to "fmiComponent" + according to meeting on Dec. 18 (by Martin Otter, DLR) + - Dec. 6, 2009: Added meUndefinedValueReference (by Martin Otter, DLR) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + Changed "version" to "platform", "standard" to "standard32", + Added a precise definition of "standard32" as comment + (by Martin Otter, DLR) + - July 19, 2009: Added "me" as prefix to file names, added meTrue/meFalse, + and changed meValueReferenced from int to unsigned int + (by Martin Otter, DLR). + - March 2, 2009: Moved enums and function pointer definitions to + ModelFunctions.h (by Martin Otter, DLR). + - Dec. 3, 2008 : First version by Martin Otter (DLR) and + Hans Olsson (Dynasim). + + + Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2019 Modelica Association Project "FMI" + All rights reserved. + + This file is licensed by the copyright holders under the 2-Clause BSD License + (https://opensource.org/licenses/BSD-2-Clause): + + ---------------------------------------------------------------------------- + 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. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- +*/ + +/* Platform (unique identification of this header file) */ +#define fmi2TypesPlatform "default" + +/* Type definitions of variables passed as arguments + Version "default" means: + + fmi2Component : an opaque object pointer + fmi2ComponentEnvironment: an opaque object pointer + fmi2FMUstate : an opaque object pointer + fmi2ValueReference : handle to the value of a variable + fmi2Real : double precision floating-point data type + fmi2Integer : basic signed integer data type + fmi2Boolean : basic signed integer data type + fmi2Char : character data type + fmi2String : a pointer to a vector of fmi2Char characters + ('\0' terminated, UTF8 encoded) + fmi2Byte : smallest addressable unit of the machine, typically one byte. +*/ +typedef void * fmi2Component; /* Pointer to FMU instance */ +typedef void * fmi2ComponentEnvironment; /* Pointer to FMU environment */ +typedef void * fmi2FMUstate; /* Pointer to internal FMU state */ +typedef unsigned int fmi2ValueReference; +typedef double fmi2Real; +typedef int fmi2Integer; +typedef int fmi2Boolean; +typedef char fmi2Char; +typedef const fmi2Char *fmi2String; +typedef char fmi2Byte; + +/* Values for fmi2Boolean */ +#define fmi2True 1 +#define fmi2False 0 + +#endif /* fmi2TypesPlatform_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3FunctionTypes.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3FunctionTypes.h new file mode 100644 index 000000000..1e76c4a82 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3FunctionTypes.h @@ -0,0 +1,637 @@ +#ifndef fmi3FunctionTypes_h +#define fmi3FunctionTypes_h + +#include "fmi3PlatformTypes.h" + +/* +This header file defines the data and function types of FMI 3.0. +It must be used when compiling an FMU or an FMI importer. + +Copyright (C) 2011 MODELISAR consortium, + 2012-2022 Modelica Association Project "FMI" + All rights reserved. + +This file is licensed by the copyright holders under the 2-Clause BSD License +(https://opensource.org/licenses/BSD-2-Clause): + +---------------------------------------------------------------------------- +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. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +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 HOLDER 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. +---------------------------------------------------------------------------- +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Include stddef.h, in order that size_t etc. is defined */ +#include + +/* Type definitions */ + +/* tag::Status[] */ +typedef enum { + fmi3OK, + fmi3Warning, + fmi3Discard, + fmi3Error, + fmi3Fatal, +} fmi3Status; +/* end::Status[] */ + +/* tag::DependencyKind[] */ +typedef enum { + fmi3Independent, + fmi3Constant, + fmi3Fixed, + fmi3Tunable, + fmi3Discrete, + fmi3Dependent +} fmi3DependencyKind; +/* end::DependencyKind[] */ + +/* tag::IntervalQualifier[] */ +typedef enum { + fmi3IntervalNotYetKnown, + fmi3IntervalUnchanged, + fmi3IntervalChanged +} fmi3IntervalQualifier; +/* end::IntervalQualifier[] */ + +/* tag::CallbackLogMessage[] */ +typedef void (*fmi3LogMessageCallback)(fmi3InstanceEnvironment instanceEnvironment, + fmi3Status status, + fmi3String category, + fmi3String message); +/* end::CallbackLogMessage[] */ + +/* tag::CallbackClockUpdate[] */ +typedef void (*fmi3ClockUpdateCallback)( + fmi3InstanceEnvironment instanceEnvironment); +/* end::CallbackClockUpdate[] */ + +/* tag::CallbackIntermediateUpdate[] */ +typedef void (*fmi3IntermediateUpdateCallback)( + fmi3InstanceEnvironment instanceEnvironment, + fmi3Float64 intermediateUpdateTime, + fmi3Boolean intermediateVariableSetRequested, + fmi3Boolean intermediateVariableGetAllowed, + fmi3Boolean intermediateStepFinished, + fmi3Boolean canReturnEarly, + fmi3Boolean * earlyReturnRequested, + fmi3Float64 * earlyReturnTime); +/* end::CallbackIntermediateUpdate[] */ + +/* tag::CallbackPreemptionLock[] */ +typedef void (*fmi3LockPreemptionCallback)(); +typedef void (*fmi3UnlockPreemptionCallback)(); +/* end::CallbackPreemptionLock[] */ + +/* Define fmi3 function pointer types to simplify dynamic loading */ + +/*************************************************** +Types for Common Functions +****************************************************/ + +/* Inquire version numbers and setting logging status */ +/* tag::GetVersion[] */ +typedef const char *fmi3GetVersionTYPE(void); +/* end::GetVersion[] */ + +/* tag::SetDebugLogging[] */ +typedef fmi3Status fmi3SetDebugLoggingTYPE(fmi3Instance instance, + fmi3Boolean loggingOn, + size_t nCategories, + const fmi3String categories[]); +/* end::SetDebugLogging[] */ + +/* Creation and destruction of FMU instances and setting debug status */ +/* tag::Instantiate[] */ +typedef fmi3Instance fmi3InstantiateModelExchangeTYPE( + fmi3String instanceName, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage); + +typedef fmi3Instance fmi3InstantiateCoSimulationTYPE( + fmi3String instanceName, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3Boolean eventModeUsed, + fmi3Boolean earlyReturnAllowed, + const fmi3ValueReference requiredIntermediateVariables[], + size_t nRequiredIntermediateVariables, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage, + fmi3IntermediateUpdateCallback intermediateUpdate); + +typedef fmi3Instance fmi3InstantiateScheduledExecutionTYPE( + fmi3String instanceName, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage, + fmi3ClockUpdateCallback clockUpdate, + fmi3LockPreemptionCallback lockPreemption, + fmi3UnlockPreemptionCallback unlockPreemption); +/* end::Instantiate[] */ + +/* tag::FreeInstance[] */ +typedef void fmi3FreeInstanceTYPE(fmi3Instance instance); +/* end::FreeInstance[] */ + +/* Enter and exit initialization mode, enter event mode, terminate and reset */ +/* tag::EnterInitializationMode[] */ +typedef fmi3Status fmi3EnterInitializationModeTYPE(fmi3Instance instance, + fmi3Boolean toleranceDefined, + fmi3Float64 tolerance, + fmi3Float64 startTime, + fmi3Boolean stopTimeDefined, + fmi3Float64 stopTime); +/* end::EnterInitializationMode[] */ + +/* tag::ExitInitializationMode[] */ +typedef fmi3Status fmi3ExitInitializationModeTYPE(fmi3Instance instance); +/* end::ExitInitializationMode[] */ + +/* tag::EnterEventMode[] */ +typedef fmi3Status fmi3EnterEventModeTYPE(fmi3Instance instance); +/* end::EnterEventMode[] */ + +/* tag::Terminate[] */ +typedef fmi3Status fmi3TerminateTYPE(fmi3Instance instance); +/* end::Terminate[] */ + +/* tag::Reset[] */ +typedef fmi3Status fmi3ResetTYPE(fmi3Instance instance); +/* end::Reset[] */ + +/* Getting and setting variable values */ +/* tag::Getters[] */ +typedef fmi3Status fmi3GetFloat32TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float32 values[], + size_t nValues); + +typedef fmi3Status fmi3GetFloat64TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 values[], + size_t nValues); + +typedef fmi3Status fmi3GetInt8TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int8 values[], + size_t nValues); + +typedef fmi3Status fmi3GetUInt8TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt8 values[], + size_t nValues); + +typedef fmi3Status fmi3GetInt16TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int16 values[], + size_t nValues); + +typedef fmi3Status fmi3GetUInt16TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt16 values[], + size_t nValues); + +typedef fmi3Status fmi3GetInt32TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int32 values[], + size_t nValues); + +typedef fmi3Status fmi3GetUInt32TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt32 values[], + size_t nValues); + +typedef fmi3Status fmi3GetInt64TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int64 values[], + size_t nValues); + +typedef fmi3Status fmi3GetUInt64TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 values[], + size_t nValues); + +typedef fmi3Status fmi3GetBooleanTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Boolean values[], + size_t nValues); + +typedef fmi3Status fmi3GetStringTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3String values[], + size_t nValues); + +typedef fmi3Status fmi3GetBinaryTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + size_t valueSizes[], + fmi3Binary values[], + size_t nValues); +/* end::Getters[] */ + +/* tag::GetClock[] */ +typedef fmi3Status fmi3GetClockTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Clock values[]); +/* end::GetClock[] */ + +/* tag::Setters[] */ +typedef fmi3Status fmi3SetFloat32TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float32 values[], + size_t nValues); + +typedef fmi3Status fmi3SetFloat64TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 values[], + size_t nValues); + +typedef fmi3Status fmi3SetInt8TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int8 values[], + size_t nValues); + +typedef fmi3Status fmi3SetUInt8TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt8 values[], + size_t nValues); + +typedef fmi3Status fmi3SetInt16TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int16 values[], + size_t nValues); + +typedef fmi3Status fmi3SetUInt16TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt16 values[], + size_t nValues); + +typedef fmi3Status fmi3SetInt32TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 values[], + size_t nValues); + +typedef fmi3Status fmi3SetUInt32TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt32 values[], + size_t nValues); + +typedef fmi3Status fmi3SetInt64TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int64 values[], + size_t nValues); + +typedef fmi3Status fmi3SetUInt64TYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 values[], + size_t nValues); + +typedef fmi3Status fmi3SetBooleanTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Boolean values[], + size_t nValues); + +typedef fmi3Status fmi3SetStringTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3String values[], + size_t nValues); + +typedef fmi3Status fmi3SetBinaryTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const size_t valueSizes[], + const fmi3Binary values[], + size_t nValues); +/* end::Setters[] */ +/* tag::SetClock[] */ +typedef fmi3Status fmi3SetClockTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Clock values[]); +/* end::SetClock[] */ + +/* Getting Variable Dependency Information */ +/* tag::GetNumberOfVariableDependencies[] */ +typedef fmi3Status fmi3GetNumberOfVariableDependenciesTYPE(fmi3Instance instance, + fmi3ValueReference valueReference, + size_t * nDependencies); +/* end::GetNumberOfVariableDependencies[] */ + +/* tag::GetVariableDependencies[] */ +typedef fmi3Status fmi3GetVariableDependenciesTYPE(fmi3Instance instance, + fmi3ValueReference dependent, + size_t elementIndicesOfDependent[], + fmi3ValueReference independents[], + size_t elementIndicesOfIndependents[], + fmi3DependencyKind dependencyKinds[], + size_t nDependencies); +/* end::GetVariableDependencies[] */ + +/* Getting and setting the internal FMU state */ +/* tag::GetFMUState[] */ +typedef fmi3Status fmi3GetFMUStateTYPE(fmi3Instance instance, fmi3FMUState *FMUState); +/* end::GetFMUState[] */ + +/* tag::SetFMUState[] */ +typedef fmi3Status fmi3SetFMUStateTYPE(fmi3Instance instance, fmi3FMUState FMUState); +/* end::SetFMUState[] */ + +/* tag::FreeFMUState[] */ +typedef fmi3Status fmi3FreeFMUStateTYPE(fmi3Instance instance, fmi3FMUState *FMUState); +/* end::FreeFMUState[] */ + +/* tag::SerializedFMUStateSize[] */ +typedef fmi3Status fmi3SerializedFMUStateSizeTYPE(fmi3Instance instance, + fmi3FMUState FMUState, + size_t * size); +/* end::SerializedFMUStateSize[] */ + +/* tag::SerializeFMUState[] */ +typedef fmi3Status fmi3SerializeFMUStateTYPE(fmi3Instance instance, + fmi3FMUState FMUState, + fmi3Byte serializedState[], + size_t size); +/* end::SerializeFMUState[] */ + +/* tag::DeserializeFMUState[] */ +typedef fmi3Status fmi3DeserializeFMUStateTYPE(fmi3Instance instance, + const fmi3Byte serializedState[], + size_t size, + fmi3FMUState * FMUState); +/* end::DeserializeFMUState[] */ + +/* Getting partial derivatives */ +/* tag::GetDirectionalDerivative[] */ +typedef fmi3Status fmi3GetDirectionalDerivativeTYPE(fmi3Instance instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity); +/* end::GetDirectionalDerivative[] */ + +/* tag::GetAdjointDerivative[] */ +typedef fmi3Status fmi3GetAdjointDerivativeTYPE(fmi3Instance instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity); +/* end::GetAdjointDerivative[] */ + +/* Entering and exiting the Configuration or Reconfiguration Mode */ + +/* tag::EnterConfigurationMode[] */ +typedef fmi3Status fmi3EnterConfigurationModeTYPE(fmi3Instance instance); +/* end::EnterConfigurationMode[] */ + +/* tag::ExitConfigurationMode[] */ +typedef fmi3Status fmi3ExitConfigurationModeTYPE(fmi3Instance instance); +/* end::ExitConfigurationMode[] */ + +/* tag::GetIntervalDecimal[] */ +typedef fmi3Status fmi3GetIntervalDecimalTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 intervals[], + fmi3IntervalQualifier qualifiers[]); +/* end::GetIntervalDecimal[] */ + +/* tag::GetIntervalFraction[] */ +typedef fmi3Status fmi3GetIntervalFractionTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 counters[], + fmi3UInt64 resolutions[], + fmi3IntervalQualifier qualifiers[]); +/* end::GetIntervalFraction[] */ + +/* tag::GetShiftDecimal[] */ +typedef fmi3Status fmi3GetShiftDecimalTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 shifts[]); +/* end::GetShiftDecimal[] */ + +/* tag::GetShiftFraction[] */ +typedef fmi3Status fmi3GetShiftFractionTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 counters[], + fmi3UInt64 resolutions[]); +/* end::GetShiftFraction[] */ + +/* tag::SetIntervalDecimal[] */ +typedef fmi3Status fmi3SetIntervalDecimalTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 intervals[]); +/* end::SetIntervalDecimal[] */ + +/* tag::SetIntervalFraction[] */ +typedef fmi3Status fmi3SetIntervalFractionTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 counters[], + const fmi3UInt64 resolutions[]); +/* end::SetIntervalFraction[] */ + +/* tag::SetShiftDecimal[] */ +typedef fmi3Status fmi3SetShiftDecimalTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 shifts[]); +/* end::SetShiftDecimal[] */ + +/* tag::SetShiftFraction[] */ +typedef fmi3Status fmi3SetShiftFractionTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 counters[], + const fmi3UInt64 resolutions[]); +/* end::SetShiftFraction[] */ + +/* tag::EvaluateDiscreteStates[] */ +typedef fmi3Status fmi3EvaluateDiscreteStatesTYPE(fmi3Instance instance); +/* end::EvaluateDiscreteStates[] */ + +/* tag::UpdateDiscreteStates[] */ +typedef fmi3Status fmi3UpdateDiscreteStatesTYPE(fmi3Instance instance, + fmi3Boolean *discreteStatesNeedUpdate, + fmi3Boolean *terminateSimulation, + fmi3Boolean *nominalsOfContinuousStatesChanged, + fmi3Boolean *valuesOfContinuousStatesChanged, + fmi3Boolean *nextEventTimeDefined, + fmi3Float64 *nextEventTime); +/* end::UpdateDiscreteStates[] */ + +/*************************************************** +Types for Functions for Model Exchange +****************************************************/ + +/* tag::EnterContinuousTimeMode[] */ +typedef fmi3Status fmi3EnterContinuousTimeModeTYPE(fmi3Instance instance); +/* end::EnterContinuousTimeMode[] */ + +/* tag::CompletedIntegratorStep[] */ +typedef fmi3Status fmi3CompletedIntegratorStepTYPE(fmi3Instance instance, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *enterEventMode, + fmi3Boolean *terminateSimulation); +/* end::CompletedIntegratorStep[] */ + +/* Providing independent variables and re-initialization of caching */ +/* tag::SetTime[] */ +typedef fmi3Status fmi3SetTimeTYPE(fmi3Instance instance, fmi3Float64 time); +/* end::SetTime[] */ + +/* tag::SetContinuousStates[] */ +typedef fmi3Status fmi3SetContinuousStatesTYPE(fmi3Instance instance, + const fmi3Float64 continuousStates[], + size_t nContinuousStates); +/* end::SetContinuousStates[] */ + +/* Evaluation of the model equations */ +/* tag::GetDerivatives[] */ +typedef fmi3Status fmi3GetContinuousStateDerivativesTYPE(fmi3Instance instance, + fmi3Float64 derivatives[], + size_t nContinuousStates); +/* end::GetDerivatives[] */ + +/* tag::GetEventIndicators[] */ +typedef fmi3Status fmi3GetEventIndicatorsTYPE(fmi3Instance instance, + fmi3Float64 eventIndicators[], + size_t nEventIndicators); +/* end::GetEventIndicators[] */ + +/* tag::GetContinuousStates[] */ +typedef fmi3Status fmi3GetContinuousStatesTYPE(fmi3Instance instance, + fmi3Float64 continuousStates[], + size_t nContinuousStates); +/* end::GetContinuousStates[] */ + +/* tag::GetNominalsOfContinuousStates[] */ +typedef fmi3Status fmi3GetNominalsOfContinuousStatesTYPE(fmi3Instance instance, + fmi3Float64 nominals[], + size_t nContinuousStates); +/* end::GetNominalsOfContinuousStates[] */ + +/* tag::GetNumberOfEventIndicators[] */ +typedef fmi3Status fmi3GetNumberOfEventIndicatorsTYPE(fmi3Instance instance, + size_t * nEventIndicators); +/* end::GetNumberOfEventIndicators[] */ + +/* tag::GetNumberOfContinuousStates[] */ +typedef fmi3Status fmi3GetNumberOfContinuousStatesTYPE(fmi3Instance instance, + size_t * nContinuousStates); +/* end::GetNumberOfContinuousStates[] */ + +/*************************************************** +Types for Functions for Co-Simulation +****************************************************/ + +/* Simulating the FMU */ + +/* tag::EnterStepMode[] */ +typedef fmi3Status fmi3EnterStepModeTYPE(fmi3Instance instance); +/* end::EnterStepMode[] */ + +/* tag::GetOutputDerivatives[] */ +typedef fmi3Status fmi3GetOutputDerivativesTYPE(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 orders[], + fmi3Float64 values[], + size_t nValues); +/* end::GetOutputDerivatives[] */ + +/* tag::DoStep[] */ +typedef fmi3Status fmi3DoStepTYPE(fmi3Instance instance, + fmi3Float64 currentCommunicationPoint, + fmi3Float64 communicationStepSize, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *eventHandlingNeeded, + fmi3Boolean *terminateSimulation, + fmi3Boolean *earlyReturn, + fmi3Float64 *lastSuccessfulTime); +/* end::DoStep[] */ + +/*************************************************** +Types for Functions for Scheduled Execution +****************************************************/ + +/* tag::ActivateModelPartition[] */ +typedef fmi3Status fmi3ActivateModelPartitionTYPE(fmi3Instance instance, + fmi3ValueReference clockReference, + fmi3Float64 activationTime); +/* end::ActivateModelPartition[] */ + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi3FunctionTypes_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3Functions.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3Functions.h new file mode 100644 index 000000000..36733ebf1 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3Functions.h @@ -0,0 +1,343 @@ +#ifndef fmi3Functions_h +#define fmi3Functions_h + +/* +This header file declares the functions of FMI 3.0. +It must be used when compiling an FMU. + +In order to have unique function names even if several FMUs +are compiled together (e.g. for embedded systems), every "real" function name +is constructed by prepending the function name by "FMI3_FUNCTION_PREFIX". +Therefore, the typical usage is: + + #define FMI3_FUNCTION_PREFIX MyModel_ + #include "fmi3Functions.h" + +As a result, a function that is defined as "fmi3GetContinuousStateDerivatives" in this header file, +is actually getting the name "MyModel_fmi3GetContinuousStateDerivatives". + +This only holds if the FMU is shipped in C source code, or is compiled in a +static link library. For FMUs compiled in a DLL/sharedObject, the "actual" function +names are used and "FMI3_FUNCTION_PREFIX" must not be defined. + +Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2022 Modelica Association Project "FMI" + All rights reserved. + +This file is licensed by the copyright holders under the 2-Clause BSD License +(https://opensource.org/licenses/BSD-2-Clause): + +---------------------------------------------------------------------------- +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. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +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 HOLDER 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. +---------------------------------------------------------------------------- +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "fmi3FunctionTypes.h" +#include "fmi3PlatformTypes.h" + +/* +Allow override of FMI3_FUNCTION_PREFIX: If FMI3_OVERRIDE_FUNCTION_PREFIX +is defined, then FMI3_ACTUAL_FUNCTION_PREFIX will be used, if defined, +or no prefix if undefined. Otherwise FMI3_FUNCTION_PREFIX will be used, +if defined. +*/ +#if !defined(FMI3_OVERRIDE_FUNCTION_PREFIX) && defined(FMI3_FUNCTION_PREFIX) +#define FMI3_ACTUAL_FUNCTION_PREFIX FMI3_FUNCTION_PREFIX +#endif + +/* +Export FMI3 API functions on Windows and under GCC. +If custom linking is desired then the FMI3_Export must be +defined before including this file. For instance, +it may be set to __declspec(dllimport). +*/ +#if !defined(FMI3_Export) +#if !defined(FMI3_ACTUAL_FUNCTION_PREFIX) +#if defined _WIN32 || defined __CYGWIN__ +/* Note: both gcc & MSVC on Windows support this syntax. */ +#define FMI3_Export __declspec(dllexport) +#else +#if __GNUC__ >= 4 +#define FMI3_Export __attribute__((visibility("default"))) +#else +#define FMI3_Export +#endif +#endif +#else +#define FMI3_Export +#endif +#endif + +/* Macros to construct the real function name (prepend function name by FMI3_FUNCTION_PREFIX) */ +#if defined(FMI3_ACTUAL_FUNCTION_PREFIX) +#define fmi3Paste(a, b) a##b +#define fmi3PasteB(a, b) fmi3Paste(a, b) +#define fmi3FullName(name) fmi3PasteB(FMI3_ACTUAL_FUNCTION_PREFIX, name) +#else +#define fmi3FullName(name) name +#endif + +/* FMI version */ +#define fmi3Version "3.0" + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers and set debug logging */ +#define fmi3GetVersion fmi3FullName(fmi3GetVersion) +#define fmi3SetDebugLogging fmi3FullName(fmi3SetDebugLogging) + +/* Creation and destruction of FMU instances */ +#define fmi3InstantiateModelExchange fmi3FullName(fmi3InstantiateModelExchange) +#define fmi3InstantiateCoSimulation fmi3FullName(fmi3InstantiateCoSimulation) +#define fmi3InstantiateScheduledExecution fmi3FullName(fmi3InstantiateScheduledExecution) +#define fmi3FreeInstance fmi3FullName(fmi3FreeInstance) + +/* Enter and exit initialization mode, terminate and reset */ +#define fmi3EnterInitializationMode fmi3FullName(fmi3EnterInitializationMode) +#define fmi3ExitInitializationMode fmi3FullName(fmi3ExitInitializationMode) +#define fmi3EnterEventMode fmi3FullName(fmi3EnterEventMode) +#define fmi3Terminate fmi3FullName(fmi3Terminate) +#define fmi3Reset fmi3FullName(fmi3Reset) + +/* Getting and setting variable values */ +#define fmi3GetFloat32 fmi3FullName(fmi3GetFloat32) +#define fmi3GetFloat64 fmi3FullName(fmi3GetFloat64) +#define fmi3GetInt8 fmi3FullName(fmi3GetInt8) +#define fmi3GetUInt8 fmi3FullName(fmi3GetUInt8) +#define fmi3GetInt16 fmi3FullName(fmi3GetInt16) +#define fmi3GetUInt16 fmi3FullName(fmi3GetUInt16) +#define fmi3GetInt32 fmi3FullName(fmi3GetInt32) +#define fmi3GetUInt32 fmi3FullName(fmi3GetUInt32) +#define fmi3GetInt64 fmi3FullName(fmi3GetInt64) +#define fmi3GetUInt64 fmi3FullName(fmi3GetUInt64) +#define fmi3GetBoolean fmi3FullName(fmi3GetBoolean) +#define fmi3GetString fmi3FullName(fmi3GetString) +#define fmi3GetBinary fmi3FullName(fmi3GetBinary) +#define fmi3GetClock fmi3FullName(fmi3GetClock) +#define fmi3SetFloat32 fmi3FullName(fmi3SetFloat32) +#define fmi3SetFloat64 fmi3FullName(fmi3SetFloat64) +#define fmi3SetInt8 fmi3FullName(fmi3SetInt8) +#define fmi3SetUInt8 fmi3FullName(fmi3SetUInt8) +#define fmi3SetInt16 fmi3FullName(fmi3SetInt16) +#define fmi3SetUInt16 fmi3FullName(fmi3SetUInt16) +#define fmi3SetInt32 fmi3FullName(fmi3SetInt32) +#define fmi3SetUInt32 fmi3FullName(fmi3SetUInt32) +#define fmi3SetInt64 fmi3FullName(fmi3SetInt64) +#define fmi3SetUInt64 fmi3FullName(fmi3SetUInt64) +#define fmi3SetBoolean fmi3FullName(fmi3SetBoolean) +#define fmi3SetString fmi3FullName(fmi3SetString) +#define fmi3SetBinary fmi3FullName(fmi3SetBinary) +#define fmi3SetClock fmi3FullName(fmi3SetClock) + +/* Getting Variable Dependency Information */ +#define fmi3GetNumberOfVariableDependencies fmi3FullName(fmi3GetNumberOfVariableDependencies) +#define fmi3GetVariableDependencies fmi3FullName(fmi3GetVariableDependencies) + +/* Getting and setting the internal FMU state */ +#define fmi3GetFMUState fmi3FullName(fmi3GetFMUState) +#define fmi3SetFMUState fmi3FullName(fmi3SetFMUState) +#define fmi3FreeFMUState fmi3FullName(fmi3FreeFMUState) +#define fmi3SerializedFMUStateSize fmi3FullName(fmi3SerializedFMUStateSize) +#define fmi3SerializeFMUState fmi3FullName(fmi3SerializeFMUState) +#define fmi3DeserializeFMUState fmi3FullName(fmi3DeserializeFMUState) + +/* Getting partial derivatives */ +#define fmi3GetDirectionalDerivative fmi3FullName(fmi3GetDirectionalDerivative) +#define fmi3GetAdjointDerivative fmi3FullName(fmi3GetAdjointDerivative) + +/* Entering and exiting the Configuration or Reconfiguration Mode */ +#define fmi3EnterConfigurationMode fmi3FullName(fmi3EnterConfigurationMode) +#define fmi3ExitConfigurationMode fmi3FullName(fmi3ExitConfigurationMode) + +/* Clock related functions */ +#define fmi3GetIntervalDecimal fmi3FullName(fmi3GetIntervalDecimal) +#define fmi3GetIntervalFraction fmi3FullName(fmi3GetIntervalFraction) +#define fmi3GetShiftDecimal fmi3FullName(fmi3GetShiftDecimal) +#define fmi3GetShiftFraction fmi3FullName(fmi3GetShiftFraction) +#define fmi3SetIntervalDecimal fmi3FullName(fmi3SetIntervalDecimal) +#define fmi3SetIntervalFraction fmi3FullName(fmi3SetIntervalFraction) +#define fmi3SetShiftDecimal fmi3FullName(fmi3SetShiftDecimal) +#define fmi3SetShiftFraction fmi3FullName(fmi3SetShiftFraction) +#define fmi3EvaluateDiscreteStates fmi3FullName(fmi3EvaluateDiscreteStates) +#define fmi3UpdateDiscreteStates fmi3FullName(fmi3UpdateDiscreteStates) + +/*************************************************** +Functions for Model Exchange +****************************************************/ + +#define fmi3EnterContinuousTimeMode fmi3FullName(fmi3EnterContinuousTimeMode) +#define fmi3CompletedIntegratorStep fmi3FullName(fmi3CompletedIntegratorStep) + +/* Providing independent variables and re-initialization of caching */ +#define fmi3SetTime fmi3FullName(fmi3SetTime) +#define fmi3SetContinuousStates fmi3FullName(fmi3SetContinuousStates) + +/* Evaluation of the model equations */ +#define fmi3GetContinuousStateDerivatives fmi3FullName(fmi3GetContinuousStateDerivatives) +#define fmi3GetEventIndicators fmi3FullName(fmi3GetEventIndicators) +#define fmi3GetContinuousStates fmi3FullName(fmi3GetContinuousStates) +#define fmi3GetNominalsOfContinuousStates fmi3FullName(fmi3GetNominalsOfContinuousStates) +#define fmi3GetNumberOfEventIndicators fmi3FullName(fmi3GetNumberOfEventIndicators) +#define fmi3GetNumberOfContinuousStates fmi3FullName(fmi3GetNumberOfContinuousStates) + +/*************************************************** +Functions for Co-Simulation +****************************************************/ + +/* Simulating the FMU */ +#define fmi3EnterStepMode fmi3FullName(fmi3EnterStepMode) +#define fmi3GetOutputDerivatives fmi3FullName(fmi3GetOutputDerivatives) +#define fmi3DoStep fmi3FullName(fmi3DoStep) +#define fmi3ActivateModelPartition fmi3FullName(fmi3ActivateModelPartition) + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers and set debug logging */ +FMI3_Export fmi3GetVersionTYPE fmi3GetVersion; +FMI3_Export fmi3SetDebugLoggingTYPE fmi3SetDebugLogging; + +/* Creation and destruction of FMU instances */ +FMI3_Export fmi3InstantiateModelExchangeTYPE fmi3InstantiateModelExchange; +FMI3_Export fmi3InstantiateCoSimulationTYPE fmi3InstantiateCoSimulation; +FMI3_Export fmi3InstantiateScheduledExecutionTYPE fmi3InstantiateScheduledExecution; +FMI3_Export fmi3FreeInstanceTYPE fmi3FreeInstance; + +/* Enter and exit initialization mode, terminate and reset */ +FMI3_Export fmi3EnterInitializationModeTYPE fmi3EnterInitializationMode; +FMI3_Export fmi3ExitInitializationModeTYPE fmi3ExitInitializationMode; +FMI3_Export fmi3EnterEventModeTYPE fmi3EnterEventMode; +FMI3_Export fmi3TerminateTYPE fmi3Terminate; +FMI3_Export fmi3ResetTYPE fmi3Reset; + +/* Getting and setting variables values */ +FMI3_Export fmi3GetFloat32TYPE fmi3GetFloat32; +FMI3_Export fmi3GetFloat64TYPE fmi3GetFloat64; +FMI3_Export fmi3GetInt8TYPE fmi3GetInt8; +FMI3_Export fmi3GetUInt8TYPE fmi3GetUInt8; +FMI3_Export fmi3GetInt16TYPE fmi3GetInt16; +FMI3_Export fmi3GetUInt16TYPE fmi3GetUInt16; +FMI3_Export fmi3GetInt32TYPE fmi3GetInt32; +FMI3_Export fmi3GetUInt32TYPE fmi3GetUInt32; +FMI3_Export fmi3GetInt64TYPE fmi3GetInt64; +FMI3_Export fmi3GetUInt64TYPE fmi3GetUInt64; +FMI3_Export fmi3GetBooleanTYPE fmi3GetBoolean; +FMI3_Export fmi3GetStringTYPE fmi3GetString; +FMI3_Export fmi3GetBinaryTYPE fmi3GetBinary; +FMI3_Export fmi3GetClockTYPE fmi3GetClock; +FMI3_Export fmi3SetFloat32TYPE fmi3SetFloat32; +FMI3_Export fmi3SetFloat64TYPE fmi3SetFloat64; +FMI3_Export fmi3SetInt8TYPE fmi3SetInt8; +FMI3_Export fmi3SetUInt8TYPE fmi3SetUInt8; +FMI3_Export fmi3SetInt16TYPE fmi3SetInt16; +FMI3_Export fmi3SetUInt16TYPE fmi3SetUInt16; +FMI3_Export fmi3SetInt32TYPE fmi3SetInt32; +FMI3_Export fmi3SetUInt32TYPE fmi3SetUInt32; +FMI3_Export fmi3SetInt64TYPE fmi3SetInt64; +FMI3_Export fmi3SetUInt64TYPE fmi3SetUInt64; +FMI3_Export fmi3SetBooleanTYPE fmi3SetBoolean; +FMI3_Export fmi3SetStringTYPE fmi3SetString; +FMI3_Export fmi3SetBinaryTYPE fmi3SetBinary; +FMI3_Export fmi3SetClockTYPE fmi3SetClock; + +/* Getting Variable Dependency Information */ +FMI3_Export fmi3GetNumberOfVariableDependenciesTYPE fmi3GetNumberOfVariableDependencies; +FMI3_Export fmi3GetVariableDependenciesTYPE fmi3GetVariableDependencies; + +/* Getting and setting the internal FMU state */ +FMI3_Export fmi3GetFMUStateTYPE fmi3GetFMUState; +FMI3_Export fmi3SetFMUStateTYPE fmi3SetFMUState; +FMI3_Export fmi3FreeFMUStateTYPE fmi3FreeFMUState; +FMI3_Export fmi3SerializedFMUStateSizeTYPE fmi3SerializedFMUStateSize; +FMI3_Export fmi3SerializeFMUStateTYPE fmi3SerializeFMUState; +FMI3_Export fmi3DeserializeFMUStateTYPE fmi3DeserializeFMUState; + +/* Getting partial derivatives */ +FMI3_Export fmi3GetDirectionalDerivativeTYPE fmi3GetDirectionalDerivative; +FMI3_Export fmi3GetAdjointDerivativeTYPE fmi3GetAdjointDerivative; + +/* Entering and exiting the Configuration or Reconfiguration Mode */ +FMI3_Export fmi3EnterConfigurationModeTYPE fmi3EnterConfigurationMode; +FMI3_Export fmi3ExitConfigurationModeTYPE fmi3ExitConfigurationMode; + +/* Clock related functions */ +FMI3_Export fmi3GetIntervalDecimalTYPE fmi3GetIntervalDecimal; +FMI3_Export fmi3GetIntervalFractionTYPE fmi3GetIntervalFraction; +FMI3_Export fmi3GetShiftDecimalTYPE fmi3GetShiftDecimal; +FMI3_Export fmi3GetShiftFractionTYPE fmi3GetShiftFraction; +FMI3_Export fmi3SetIntervalDecimalTYPE fmi3SetIntervalDecimal; +FMI3_Export fmi3SetIntervalFractionTYPE fmi3SetIntervalFraction; +FMI3_Export fmi3SetShiftDecimalTYPE fmi3SetShiftDecimal; +FMI3_Export fmi3SetShiftFractionTYPE fmi3SetShiftFraction; +FMI3_Export fmi3EvaluateDiscreteStatesTYPE fmi3EvaluateDiscreteStates; +FMI3_Export fmi3UpdateDiscreteStatesTYPE fmi3UpdateDiscreteStates; + +/*************************************************** +Functions for Model Exchange +****************************************************/ + +FMI3_Export fmi3EnterContinuousTimeModeTYPE fmi3EnterContinuousTimeMode; +FMI3_Export fmi3CompletedIntegratorStepTYPE fmi3CompletedIntegratorStep; + +/* Providing independent variables and re-initialization of caching */ +/* tag::SetTimeTYPE[] */ +FMI3_Export fmi3SetTimeTYPE fmi3SetTime; +/* end::SetTimeTYPE[] */ +FMI3_Export fmi3SetContinuousStatesTYPE fmi3SetContinuousStates; + +/* Evaluation of the model equations */ +FMI3_Export fmi3GetContinuousStateDerivativesTYPE fmi3GetContinuousStateDerivatives; +FMI3_Export fmi3GetEventIndicatorsTYPE fmi3GetEventIndicators; +FMI3_Export fmi3GetContinuousStatesTYPE fmi3GetContinuousStates; +FMI3_Export fmi3GetNominalsOfContinuousStatesTYPE fmi3GetNominalsOfContinuousStates; +FMI3_Export fmi3GetNumberOfEventIndicatorsTYPE fmi3GetNumberOfEventIndicators; +FMI3_Export fmi3GetNumberOfContinuousStatesTYPE fmi3GetNumberOfContinuousStates; + +/*************************************************** +Functions for Co-Simulation +****************************************************/ + +/* Simulating the FMU */ +FMI3_Export fmi3EnterStepModeTYPE fmi3EnterStepMode; +FMI3_Export fmi3GetOutputDerivativesTYPE fmi3GetOutputDerivatives; +FMI3_Export fmi3DoStepTYPE fmi3DoStep; + +/*************************************************** +Functions for Scheduled Execution +****************************************************/ + +FMI3_Export fmi3ActivateModelPartitionTYPE fmi3ActivateModelPartition; + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi3Functions_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3PlatformTypes.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3PlatformTypes.h new file mode 100644 index 000000000..d83f6340f --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmi3PlatformTypes.h @@ -0,0 +1,93 @@ +#ifndef fmi3PlatformTypes_h +#define fmi3PlatformTypes_h + +/* +This header file defines the data types of FMI 3.0. +It must be used by both FMU and FMI master. + +Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2022 Modelica Association Project "FMI" + All rights reserved. + +This file is licensed by the copyright holders under the 2-Clause BSD License +(https://opensource.org/licenses/BSD-2-Clause): + +---------------------------------------------------------------------------- +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. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +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 HOLDER 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. +---------------------------------------------------------------------------- +*/ + +/* Include the integer and boolean type definitions */ +#include +#include + +/* tag::Component[] */ +typedef void *fmi3Instance; /* Pointer to the FMU instance */ +/* end::Component[] */ + +/* tag::ComponentEnvironment[] */ +typedef void *fmi3InstanceEnvironment; /* Pointer to the FMU environment */ +/* end::ComponentEnvironment[] */ + +/* tag::FMUState[] */ +typedef void *fmi3FMUState; /* Pointer to the internal FMU state */ +/* end::FMUState[] */ + +/* tag::ValueReference[] */ +typedef uint32_t fmi3ValueReference; /* Handle to the value of a variable */ +/* end::ValueReference[] */ + +/* tag::VariableTypes[] */ +typedef float fmi3Float32; /* Single precision floating point (32-bit) */ +/* tag::fmi3Float64[] */ +typedef double fmi3Float64; /* Double precision floating point (64-bit) */ +/* end::fmi3Float64[] */ +typedef int8_t fmi3Int8; /* 8-bit signed integer */ +typedef uint8_t fmi3UInt8; /* 8-bit unsigned integer */ +typedef int16_t fmi3Int16; /* 16-bit signed integer */ +typedef uint16_t fmi3UInt16; /* 16-bit unsigned integer */ +typedef int32_t fmi3Int32; /* 32-bit signed integer */ +typedef uint32_t fmi3UInt32; /* 32-bit unsigned integer */ +typedef int64_t fmi3Int64; /* 64-bit signed integer */ +typedef uint64_t fmi3UInt64; /* 64-bit unsigned integer */ +typedef bool fmi3Boolean; /* Data type to be used with fmi3True and fmi3False */ +typedef char fmi3Char; /* Data type for one character */ +typedef const fmi3Char *fmi3String; /* Data type for character strings + ('\0' terminated, UTF-8 encoded) */ +typedef uint8_t fmi3Byte; /* Smallest addressable unit of the machine + (typically one byte) */ +typedef const fmi3Byte *fmi3Binary; /* Data type for binary data + (out-of-band length terminated) */ +typedef bool fmi3Clock; /* Data type to be used with fmi3ClockActive and + fmi3ClockInactive */ + +/* Values for fmi3Boolean */ +#define fmi3True true +#define fmi3False false + +/* Values for fmi3Clock */ +#define fmi3ClockActive true +#define fmi3ClockInactive false +/* end::VariableTypes[] */ + +#endif /* fmi3PlatformTypes_h */ diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiFunctions.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiFunctions.h new file mode 100644 index 000000000..635348509 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiFunctions.h @@ -0,0 +1,228 @@ +#ifndef fmiFunctions_h +#define fmiFunctions_h + +/* This header file must be utilized when compiling a FMU. + It defines all functions of Co-Simulation Interface. + In order to have unique function names even if several FMUs + are compiled together (e.g. for embedded systems), every "real" function name + is constructed by prepending the function name by + "MODEL_IDENTIFIER" + "_" where "MODEL_IDENTIFIER" is the short name + of the model used as the name of the zip-file where the model is stored. + Therefore, the typical usage is: + + #define MODEL_IDENTIFIER MyModel + #include "fmiFunctions.h" + + As a result, a function that is defined as "fmiGetDerivatives" in this header file, + is actually getting the name "MyModel_fmiGetDerivatives". + + Revisions: + - November 4, 2010: Adapted to specification text: + o fmiGetModelTypesPlatform renamed to fmiGetTypesPlatform + o fmiInstantiateSlave: Argument GUID replaced by fmuGUID + Argument mimetype replaced by mimeType + o tabs replaced by spaces + - October 16, 2010: First public Version + + + Copyright(c) 2017, MODELICA Association Project FMI. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + 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. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- +*/ + +#include +#include "fmiPlatformTypes.h" + +/* Export fmi functions on Windows */ +#ifdef _MSC_VER +#define DllExport __declspec(dllexport) +#else +#define DllExport +#endif + +/* Macros to construct the real function name + (prepend function name by MODEL_IDENTIFIER + "_") */ + +#define fmiPaste(a, b) a##b +#define fmiPasteB(a, b) fmiPaste(a, b) +#define fmiFullName(name) fmiPasteB(MODEL_IDENTIFIER, name) + +/*************************************************** +Common Functions +****************************************************/ +#define fmiGetTypesPlatform fmiFullName(_fmiGetTypesPlatform) +#define fmiGetVersion fmiFullName(_fmiGetVersion) +#define fmiSetDebugLogging fmiFullName(_fmiSetDebugLogging) + +/*Data Exchange*/ +#define fmiSetReal fmiFullName(_fmiSetReal) +#define fmiSetInteger fmiFullName(_fmiSetInteger) +#define fmiSetBoolean fmiFullName(_fmiSetBoolean) +#define fmiSetString fmiFullName(_fmiSetString) + +#define fmiGetReal fmiFullName(_fmiGetReal) +#define fmiGetInteger fmiFullName(_fmiGetInteger) +#define fmiGetBoolean fmiFullName(_fmiGetBoolean) +#define fmiGetString fmiFullName(_fmiGetString) + +/*************************************************** +Functions for FMI for Co-Simulation +****************************************************/ +#define fmiInstantiateSlave fmiFullName(_fmiInstantiateSlave) +#define fmiInitializeSlave fmiFullName(_fmiInitializeSlave) +#define fmiTerminateSlave fmiFullName(_fmiTerminateSlave) +#define fmiResetSlave fmiFullName(_fmiResetSlave) +#define fmiFreeSlaveInstance fmiFullName(_fmiFreeSlaveInstance) +#define fmiSetRealInputDerivatives fmiFullName(_fmiSetRealInputDerivatives) +#define fmiGetRealOutputDerivatives fmiFullName(_fmiGetRealOutputDerivatives) +#define fmiDoStep fmiFullName(_fmiDoStep) +#define fmiCancelStep fmiFullName(_fmiCancelStep) +#define fmiGetStatus fmiFullName(_fmiGetStatus) +#define fmiGetRealStatus fmiFullName(_fmiGetRealStatus) +#define fmiGetIntegerStatus fmiFullName(_fmiGetIntegerStatus) +#define fmiGetBooleanStatus fmiFullName(_fmiGetBooleanStatus) +#define fmiGetStringStatus fmiFullName(_fmiGetStringStatus) + +/* Version number */ +#define fmiVersion "1.0" + +/* make sure all compiler use the same alignment policies for structures */ +#ifdef WIN32 +#pragma pack(push, 8) +#endif + +/* Type definitions */ +typedef enum { fmiOK, + fmiWarning, + fmiDiscard, + fmiError, + fmiFatal, + fmiPending } fmiStatus; + +typedef void (*fmiCallbackLogger)(fmiComponent c, fmiString instanceName, fmiStatus status, + fmiString category, fmiString message, ...); +typedef void *(*fmiCallbackAllocateMemory)(size_t nobj, size_t size); +typedef void (*fmiCallbackFreeMemory)(void *obj); +typedef void (*fmiStepFinished)(fmiComponent c, fmiStatus status); + +typedef struct { + fmiCallbackLogger logger; + fmiCallbackAllocateMemory allocateMemory; + fmiCallbackFreeMemory freeMemory; + fmiStepFinished stepFinished; +} fmiCallbackFunctions; + +typedef struct { + fmiBoolean iterationConverged; + fmiBoolean stateValueReferencesChanged; + fmiBoolean stateValuesChanged; + fmiBoolean terminateSimulation; + fmiBoolean upcomingTimeEvent; + fmiReal nextEventTime; +} fmiEventInfo; + +/* reset alignment policy to the one set before reading this file */ +#ifdef WIN32 +#pragma pack(pop) +#endif + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers of header files */ +DllExport const char *fmiGetTypesPlatform(); +DllExport const char *fmiGetVersion(); + +DllExport fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn); + +/* Data Exchange Functions*/ +DllExport fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]); +DllExport fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]); +DllExport fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]); +DllExport fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]); + +DllExport fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]); +DllExport fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]); +DllExport fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]); +DllExport fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]); + +/*************************************************** +Functions for FMI for Co-Simulation +****************************************************/ + +/* Creation and destruction of slave instances and setting debug status */ +DllExport fmiComponent fmiInstantiateSlave(fmiString instanceName, + fmiString fmuGUID, + fmiString fmuLocation, + fmiString mimeType, + fmiReal timeout, + fmiBoolean visible, + fmiBoolean interactive, + fmiCallbackFunctions functions, + fmiBoolean loggingOn); + +DllExport fmiStatus fmiInitializeSlave(fmiComponent c, + fmiReal tStart, + fmiBoolean StopTimeDefined, + fmiReal tStop); + +DllExport fmiStatus fmiTerminateSlave(fmiComponent c); +DllExport fmiStatus fmiResetSlave(fmiComponent c); +DllExport void fmiFreeSlaveInstance(fmiComponent c); + +DllExport fmiStatus fmiSetRealInputDerivatives(fmiComponent c, + const fmiValueReference vr[], + size_t nvr, + const fmiInteger order[], + const fmiReal value[]); + +DllExport fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, + const fmiValueReference vr[], + size_t nvr, + const fmiInteger order[], + fmiReal value[]); + +DllExport fmiStatus fmiCancelStep(fmiComponent c); +DllExport fmiStatus fmiDoStep(fmiComponent c, + fmiReal currentCommunicationPoint, + fmiReal communicationStepSize, + fmiBoolean newStep); + +typedef enum { fmiDoStepStatus, + fmiPendingStatus, + fmiLastSuccessfulTime } fmiStatusKind; + +DllExport fmiStatus fmiGetStatus(fmiComponent c, const fmiStatusKind s, fmiStatus *value); +DllExport fmiStatus fmiGetRealStatus(fmiComponent c, const fmiStatusKind s, fmiReal *value); +DllExport fmiStatus fmiGetIntegerStatus(fmiComponent c, const fmiStatusKind s, fmiInteger *value); +DllExport fmiStatus fmiGetBooleanStatus(fmiComponent c, const fmiStatusKind s, fmiBoolean *value); +DllExport fmiStatus fmiGetStringStatus(fmiComponent c, const fmiStatusKind s, fmiString *value); + +#endif // fmiFunctions_h diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelFunctions.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelFunctions.h new file mode 100644 index 000000000..092495138 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelFunctions.h @@ -0,0 +1,207 @@ +#ifndef fmiModelFunctions_h +#define fmiModelFunctions_h + +/* This header file must be utilized when compiling a model. + It defines all functions of the Model Execution Interface. + In order to have unique function names even if several models + are compiled together (e.g. for embedded systems), every "real" function name + is constructed by prepending the function name by + "MODEL_IDENTIFIER" + "_" where "MODEL_IDENTIFIER" is the short name + of the model used as the name of the zip-file where the model is stored. + Therefore, the typical usage is: + + #define MODEL_IDENTIFIER MyModel + #include "fmiModelFunctions.h" + + As a result, a function that is defined as "fmiGetDerivatives" in this header file, + is actually getting the name "MyModel_fmiGetDerivatives". + + Revisions: + - Jan. 20, 2010: stateValueReferencesChanged added to struct fmiEventInfo (ticket #27) + (by M. Otter, DLR) + Added WIN32 pragma to define the struct layout (ticket #34) + (by J. Mauss, QTronic) + - Jan. 4, 2010: Removed argument intermediateResults from fmiInitialize + Renamed macro fmiGetModelFunctionsVersion to fmiGetVersion + Renamed macro fmiModelFunctionsVersion to fmiVersion + Replaced fmiModel by fmiComponent in decl of fmiInstantiateModel + (by J. Mauss, QTronic) + - Dec. 17, 2009: Changed extension "me" to "fmi" (by Martin Otter, DLR). + - Dez. 14, 2009: Added eventInfo to meInitialize and added + meGetNominalContinuousStates (by Martin Otter, DLR) + - Sept. 9, 2009: Added DllExport (according to Peter Nilsson's suggestion) + (by A. Junghanns, QTronic) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + meInquireModelTypesVersion -> meGetModelTypesPlatform + meInquireModelFunctionsVersion -> meGetModelFunctionsVersion + meSetStates -> meSetContinuousStates + meGetStates -> meGetContinuousStates + removal of meInitializeModelClass + removal of meGetTime + change of arguments of meInstantiateModel + change of arguments of meCompletedIntegratorStep + (by Martin Otter, DLR): + - July 19, 2009: Added "me" as prefix to file names (by Martin Otter, DLR). + - March 2, 2009: Changed function definitions according to the last design + meeting with additional improvements (by Martin Otter, DLR). + - Dec. 3 , 2008: First version by Martin Otter (DLR) and Hans Olsson (Dynasim). + + + Copyright(c) 2017, MODELICA Association Project FMI. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + 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. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. +*/ + +#include +#include "fmiModelTypes.h" + +/* Export fmi functions on Windows */ +#ifdef _MSC_VER +#define DllExport __declspec(dllexport) +#else +#define DllExport +#endif + +/* Macros to construct the real function name + (prepend function name by MODEL_IDENTIFIER + "_") */ + +#define fmiPaste(a, b) a##b +#define fmiPasteB(a, b) fmiPaste(a, b) +#define fmiFullName(name) fmiPasteB(MODEL_IDENTIFIER, name) + +#define fmiGetModelTypesPlatform fmiFullName(_fmiGetModelTypesPlatform) +#define fmiGetVersion fmiFullName(_fmiGetVersion) +#define fmiInstantiateModel fmiFullName(_fmiInstantiateModel) +#define fmiFreeModelInstance fmiFullName(_fmiFreeModelInstance) +#define fmiSetDebugLogging fmiFullName(_fmiSetDebugLogging) +#define fmiSetTime fmiFullName(_fmiSetTime) +#define fmiSetContinuousStates fmiFullName(_fmiSetContinuousStates) +#define fmiCompletedIntegratorStep fmiFullName(_fmiCompletedIntegratorStep) +#define fmiSetReal fmiFullName(_fmiSetReal) +#define fmiSetInteger fmiFullName(_fmiSetInteger) +#define fmiSetBoolean fmiFullName(_fmiSetBoolean) +#define fmiSetString fmiFullName(_fmiSetString) +#define fmiInitialize fmiFullName(_fmiInitialize) +#define fmiGetDerivatives fmiFullName(_fmiGetDerivatives) +#define fmiGetEventIndicators fmiFullName(_fmiGetEventIndicators) +#define fmiGetReal fmiFullName(_fmiGetReal) +#define fmiGetInteger fmiFullName(_fmiGetInteger) +#define fmiGetBoolean fmiFullName(_fmiGetBoolean) +#define fmiGetString fmiFullName(_fmiGetString) +#define fmiEventUpdate fmiFullName(_fmiEventUpdate) +#define fmiGetContinuousStates fmiFullName(_fmiGetContinuousStates) +#define fmiGetNominalContinuousStates fmiFullName(_fmiGetNominalContinuousStates) +#define fmiGetStateValueReferences fmiFullName(_fmiGetStateValueReferences) +#define fmiTerminate fmiFullName(_fmiTerminate) + +/* Version number */ +#define fmiVersion "1.0" + +/* Inquire version numbers of header files */ +DllExport const char *fmiGetModelTypesPlatform(); +DllExport const char *fmiGetVersion(); + +/* make sure all compiler use the same alignment policies for structures */ +#ifdef WIN32 +#pragma pack(push, 8) +#endif + +/* Type definitions */ +typedef enum { fmiOK, + fmiWarning, + fmiDiscard, + fmiError, + fmiFatal } fmiStatus; + +typedef void (*fmiCallbackLogger)(fmiComponent c, fmiString instanceName, fmiStatus status, + fmiString category, fmiString message, ...); +typedef void *(*fmiCallbackAllocateMemory)(size_t nobj, size_t size); +typedef void (*fmiCallbackFreeMemory)(void *obj); + +typedef struct { + fmiCallbackLogger logger; + fmiCallbackAllocateMemory allocateMemory; + fmiCallbackFreeMemory freeMemory; +} fmiCallbackFunctions; + +typedef struct { + fmiBoolean iterationConverged; + fmiBoolean stateValueReferencesChanged; + fmiBoolean stateValuesChanged; + fmiBoolean terminateSimulation; + fmiBoolean upcomingTimeEvent; + fmiReal nextEventTime; +} fmiEventInfo; + +/* reset alignment policy to the one set before reading this file */ +#ifdef WIN32 +#pragma pack(pop) +#endif + +/* Creation and destruction of model instances and setting debug status */ +DllExport fmiComponent fmiInstantiateModel(fmiString instanceName, + fmiString GUID, + fmiCallbackFunctions functions, + fmiBoolean loggingOn); +DllExport void fmiFreeModelInstance(fmiComponent c); +DllExport fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn); + +/* Providing independent variables and re-initialization of caching */ +DllExport fmiStatus fmiSetTime(fmiComponent c, fmiReal time); +DllExport fmiStatus fmiSetContinuousStates(fmiComponent c, const fmiReal x[], size_t nx); +DllExport fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean *callEventUpdate); +DllExport fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]); +DllExport fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]); +DllExport fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]); +DllExport fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]); + +/* Evaluation of the model equations */ +DllExport fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, + fmiReal relativeTolerance, fmiEventInfo *eventInfo); + +DllExport fmiStatus fmiGetDerivatives(fmiComponent c, fmiReal derivatives[], size_t nx); +DllExport fmiStatus fmiGetEventIndicators(fmiComponent c, fmiReal eventIndicators[], size_t ni); + +DllExport fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]); +DllExport fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]); +DllExport fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]); +DllExport fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]); + +DllExport fmiStatus fmiEventUpdate(fmiComponent c, fmiBoolean intermediateResults, fmiEventInfo *eventInfo); +DllExport fmiStatus fmiGetContinuousStates(fmiComponent c, fmiReal states[], size_t nx); +DllExport fmiStatus fmiGetNominalContinuousStates(fmiComponent c, fmiReal x_nominal[], size_t nx); +DllExport fmiStatus fmiGetStateValueReferences(fmiComponent c, fmiValueReference vrx[], size_t nx); +DllExport fmiStatus fmiTerminate(fmiComponent c); + +#endif // fmiModelFunctions_h diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelTypes.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelTypes.h new file mode 100644 index 000000000..5adfcf919 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiModelTypes.h @@ -0,0 +1,91 @@ +#ifndef fmiModelTypes_h +#define fmiModelTypes_h + +/* Standard header file to define the argument types of the + functions of the Model Execution Interface. + This header file must be utilized both by the model and + by the simulation engine. + + Revisions: + - Jan. 4, 2010: Renamed meModelTypes_h to fmiModelTypes_h (by Mauss, QTronic) + - Dec. 21, 2009: Changed "me" to "fmi" and "meModel" to "fmiComponent" + according to meeting on Dec. 18 (by Martin Otter, DLR) + - Dec. 6, 2009: Added meUndefinedValueReference (by Martin Otter, DLR) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + Changed "version" to "platform", "standard" to "standard32", + Added a precise definition of "standard32" as comment + (by Martin Otter, DLR) + - July 19, 2009: Added "me" as prefix to file names, added meTrue/meFalse, + and changed meValueReferenced from int to unsigned int + (by Martin Otter, DLR). + - March 2, 2009: Moved enums and function pointer definitions to + ModelFunctions.h (by Martin Otter, DLR). + - Dec. 3, 2008 : First version by Martin Otter (DLR) and + Hans Olsson (Dynasim). + + + Copyright(c) 2017, MODELICA Association Project FMI. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html) + + ---------------------------------------------------------------------------- + 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. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. +*/ + +/* Platform (combination of machine, compiler, operating system) */ +#define fmiModelTypesPlatform "standard32" + +/* Type definitions of variables passed as arguments + Version "standard32" means: + + fmiComponent : 32 bit pointer + fmiValueReference: 32 bit + fmiReal : 64 bit + fmiInteger : 32 bit + fmiBoolean : 8 bit + fmiString : 32 bit pointer + +*/ +typedef void * fmiComponent; +typedef unsigned int fmiValueReference; +typedef double fmiReal; +typedef int fmiInteger; +typedef char fmiBoolean; +typedef const char * fmiString; + +/* Values for fmiBoolean */ +#define fmiTrue 1 +#define fmiFalse 0 + +/* Undefined value for fmiValueReference (largest unsigned int value) */ +#define fmiUndefinedValueReference (fmiValueReference)(-1) + +#endif diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiPlatformTypes.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiPlatformTypes.h new file mode 100644 index 000000000..2e36b9043 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/fmiPlatformTypes.h @@ -0,0 +1,73 @@ +#ifndef fmiPlatformTypes_h +#define fmiPlatformTypes_h + +/* Standard header file to define the argument types of the + functions of the Model Execution Interface. + This header file must be utilized both by the model and + by the simulation engine. + + Revisions: + - October 2010: First public Version + + + Copyright(c) 2017, MODELICA Association Project FMI. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html): + + + ---------------------------------------------------------------------------- + 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. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + 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 HOLDER 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. + ---------------------------------------------------------------------------- +*/ + +/* Platform (combination of machine, compiler, operating system) */ +#define fmiPlatform "standard32" + +/* Type definitions of variables passed as arguments + Version "standard32" means: + + fmiComponent : 32 bit pointer + fmiValueReference: 32 bit + fmiReal : 64 bit + fmiInteger : 32 bit + fmiBoolean : 8 bit + fmiString : 32 bit pointer + +*/ +typedef void * fmiComponent; +typedef unsigned int fmiValueReference; +typedef double fmiReal; +typedef int fmiInteger; +typedef char fmiBoolean; +typedef const char * fmiString; + +/* Values for fmiBoolean */ +#define fmiTrue 1 +#define fmiFalse 0 + +/* Undefined value for fmiValueReference (largest unsigned int value) */ +#define fmiUndefinedValueReference (fmiValueReference)(-1) + +#endif diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/model.h b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/model.h new file mode 100644 index 000000000..88c294854 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/include/model.h @@ -0,0 +1,235 @@ +#pragma once + +#if FMI_VERSION != 1 && FMI_VERSION != 2 && FMI_VERSION != 3 +#error FMI_VERSION must be one of 1, 2 or 3 +#endif + +#define UNUSED(x) (void) (x) + +#include // for bool +#include // for size_t +#include + +#include "config.h" + +#if FMI_VERSION == 1 + +#define not_modelError (Instantiated | Initialized | Terminated) + +typedef enum { + Instantiated = 1 << 0, + Initialized = 1 << 1, + Terminated = 1 << 2, + modelError = 1 << 3 +} ModelState; + +#elif FMI_VERSION == 2 + +typedef enum { + StartAndEnd = 1 << 0, + Instantiated = 1 << 1, + InitializationMode = 1 << 2, + + // ME states + EventMode = 1 << 3, + ContinuousTimeMode = 1 << 4, + + // CS states + StepComplete = 1 << 5, + StepInProgress = 1 << 6, + StepFailed = 1 << 7, + StepCanceled = 1 << 8, + + Terminated = 1 << 9, + modelError = 1 << 10, + modelFatal = 1 << 11, +} ModelState; + +#else + +typedef enum { + StartAndEnd = 1 << 0, + ConfigurationMode = 1 << 1, + Instantiated = 1 << 2, + InitializationMode = 1 << 3, + EventMode = 1 << 4, + ContinuousTimeMode = 1 << 5, + StepMode = 1 << 6, + ClockActivationMode = 1 << 7, + StepDiscarded = 1 << 8, + ReconfigurationMode = 1 << 9, + IntermediateUpdateMode = 1 << 10, + Terminated = 1 << 11, + modelError = 1 << 12, + modelFatal = 1 << 13, +} ModelState; + +#endif + +typedef enum { + ModelExchange, + CoSimulation, + ScheduledExecution, +} InterfaceType; + +typedef enum { + OK, + Warning, + Discard, + Error, + Fatal, + Pending +} Status; + +#if FMI_VERSION < 3 +typedef void (*loggerType)(void *componentEnvironment, const char *instanceName, int status, const char *category, const char *message, ...); +#else +typedef void (*loggerType)(void *componentEnvironment, int status, const char *category, const char *message); +#endif + +typedef void (*lockPreemptionType)(); +typedef void (*unlockPreemptionType)(); + +typedef void (*intermediateUpdateType)(void * instanceEnvironment, + double intermediateUpdateTime, + bool intermediateVariableSetRequested, + bool intermediateVariableGetAllowed, + bool intermediateStepFinished, + bool canReturnEarly, + bool * earlyReturnRequested, + double *earlyReturnTime); + +typedef void (*clockUpdateType)(void *instanceEnvironment); + +typedef struct { + + double startTime; + double time; + double solverStepSize; + const char * instanceName; + InterfaceType type; + const char * resourceLocation; + + Status status; + + // callback functions + loggerType logger; + intermediateUpdateType intermediateUpdate; + clockUpdateType clockUpdate; + + lockPreemptionType lockPreemtion; + unlockPreemptionType unlockPreemtion; + + bool logEvents; + bool logErrors; + + void * componentEnvironment; + ModelState state; + + // event info + bool newDiscreteStatesNeeded; + bool terminateSimulation; + bool nominalsOfContinuousStatesChanged; + bool valuesOfContinuousStatesChanged; + bool nextEventTimeDefined; + double nextEventTime; + bool clocksTicked; + + bool isDirtyValues; + + ModelData modelData; + +#if NZ > 0 + // event indicators + double z[NZ]; +#endif + + // internal solver steps + uint64_t nSteps; + + // Co-Simulation + bool earlyReturnAllowed; + bool eventModeUsed; + +} ModelInstance; + +ModelInstance *createModelInstance( + loggerType logger, + intermediateUpdateType intermediateUpdate, + void * componentEnvironment, + const char * instanceName, + const char * instantiationToken, + const char * resourceLocation, + bool loggingOn, + InterfaceType interfaceType); + +void freeModelInstance(ModelInstance *comp); + +void reset(ModelInstance *comp); + +void setStartValues(ModelInstance *comp); + +Status calculateValues(ModelInstance *comp); + +Status getFloat32(ModelInstance *comp, ValueReference vr, float value[], size_t *index); +Status getFloat64(ModelInstance *comp, ValueReference vr, double value[], size_t *index); +Status getInt8(ModelInstance *comp, ValueReference vr, int8_t value[], size_t *index); +Status getUInt8(ModelInstance *comp, ValueReference vr, uint8_t value[], size_t *index); +Status getInt16(ModelInstance *comp, ValueReference vr, int16_t value[], size_t *index); +Status getUInt16(ModelInstance *comp, ValueReference vr, uint16_t value[], size_t *index); +Status getInt32(ModelInstance *comp, ValueReference vr, int32_t value[], size_t *index); +Status getUInt32(ModelInstance *comp, ValueReference vr, uint32_t value[], size_t *index); +Status getInt64(ModelInstance *comp, ValueReference vr, int64_t value[], size_t *index); +Status getUInt64(ModelInstance *comp, ValueReference vr, uint64_t value[], size_t *index); +Status getBoolean(ModelInstance *comp, ValueReference vr, bool value[], size_t *index); +Status getString(ModelInstance *comp, ValueReference vr, const char *value[], size_t *index); +Status getBinary(ModelInstance *comp, ValueReference vr, size_t size[], const char *value[], size_t *index); + +Status setFloat32(ModelInstance *comp, ValueReference vr, const float value[], size_t *index); +Status setFloat64(ModelInstance *comp, ValueReference vr, const double value[], size_t *index); +Status setInt8(ModelInstance *comp, ValueReference vr, const int8_t value[], size_t *index); +Status setUInt8(ModelInstance *comp, ValueReference vr, const uint8_t value[], size_t *index); +Status setInt16(ModelInstance *comp, ValueReference vr, const int16_t value[], size_t *index); +Status setUInt16(ModelInstance *comp, ValueReference vr, const uint16_t value[], size_t *index); +Status setInt32(ModelInstance *comp, ValueReference vr, const int32_t value[], size_t *index); +Status setUInt32(ModelInstance *comp, ValueReference vr, const uint32_t value[], size_t *index); +Status setInt64(ModelInstance *comp, ValueReference vr, const int64_t value[], size_t *index); +Status setUInt64(ModelInstance *comp, ValueReference vr, const uint64_t value[], size_t *index); +Status setBoolean(ModelInstance *comp, ValueReference vr, const bool value[], size_t *index); +Status setString(ModelInstance *comp, ValueReference vr, const char *const value[], size_t *index); +Status setBinary(ModelInstance *comp, ValueReference vr, const size_t size[], const char *const value[], size_t *index); + +Status activateClock(ModelInstance *comp, ValueReference vr); +Status getClock(ModelInstance *comp, ValueReference vr, bool *value); +Status setClock(ModelInstance *comp, ValueReference vr, const bool *value); + +Status getInterval(ModelInstance *comp, ValueReference vr, double *interval, int *qualifier); + +Status activateModelPartition(ModelInstance *comp, ValueReference vr, double activationTime); + +void getContinuousStates(ModelInstance *comp, double x[], size_t nx); +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx); +void getDerivatives(ModelInstance *comp, double dx[], size_t nx); +Status getOutputDerivative(ModelInstance *comp, ValueReference valueReference, int order, double *value); +Status getPartialDerivative(ModelInstance *comp, ValueReference unknown, ValueReference known, double *partialDerivative); +void getEventIndicators(ModelInstance *comp, double z[], size_t nz); +void eventUpdate(ModelInstance *comp); +//void updateEventTime(ModelInstance *comp); + +bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, size_t actual, size_t expected); +bool invalidState(ModelInstance *comp, const char *f, int statesExpected); +bool nullPointer(ModelInstance *comp, const char *f, const char *arg, const void *p); +void logError(ModelInstance *comp, const char *message, ...); +Status setDebugLogging(ModelInstance *comp, bool loggingOn, size_t nCategories, const char *const categories[]); +void logEvent(ModelInstance *comp, const char *message, ...); +void logError(ModelInstance *comp, const char *message, ...); + +void *getFMUState(ModelInstance *comp); +void setFMUState(ModelInstance *comp, void *FMUState); + +// shorthand to access the variables +#define M(u) (comp->modelData.u) + +// "stringification" macros +#define xstr(s) str(s) +#define str(s) #s diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/set_tool_version.py b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/set_tool_version.py new file mode 100644 index 000000000..9a544bb5e --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/set_tool_version.py @@ -0,0 +1,45 @@ +import os.path +import subprocess +import sys + + +def set_tool_version(filename, git_executable='git'): + """ Set the Git tag or hash in the generationTool attribute if the repo is clean """ + + cwd = os.path.dirname(__file__) + + changed_files = subprocess.check_output( + [git_executable, 'status', '--porcelain', '--untracked=no'], cwd=cwd).decode('ascii').strip() + + if changed_files: + return + + version = subprocess.check_output([git_executable, 'tag', '--contains'], cwd=cwd).decode('ascii').strip() + + if not version: + version = subprocess.check_output([git_executable, 'rev-parse', '--short', + 'HEAD'], cwd=cwd).decode('ascii').strip() + + if not version: + return + + with open(filename, 'r') as f: + lines = f.read() + + lines = lines.replace('"Reference FMUs (development build)"', f'"Reference FMUs ({version})"') + + with open(filename, 'w') as f: + f.write(lines) + + +if __name__ == '__main__': + + try: + if len(sys.argv) > 2: + set_tool_version(sys.argv[1], sys.argv[2]) + elif len(sys.argv) > 1: + set_tool_version(sys.argv[1]) + else: + raise RuntimeError('Not enough arguments') + except Exception as e: + print(e) diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI.c new file mode 100644 index 000000000..e4278db57 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#pragma comment(lib, "shlwapi.lib") +#else +#include +#include +#endif + +#ifdef _MSC_VER +#define strdup _strdup +#endif + +#include "FMI.h" + +#define INITIAL_MESSAGE_BUFFER_SIZE 1024 + +FMIInstance *FMICreateInstance(const char *instanceName, const char *libraryPath, FMILogMessage *logMessage, FMILogFunctionCall *logFunctionCall) +{ + +#ifdef _WIN32 + TCHAR Buffer[1024]; + GetCurrentDirectory(1024, Buffer); + + WCHAR dllDirectory[MAX_PATH]; + + // convert path to unicode + mbstowcs(dllDirectory, libraryPath, MAX_PATH); + + // remove the file name + PathRemoveFileSpecW(dllDirectory); + + // add the binaries directory temporarily to the DLL path to allow discovery of dependencies + DLL_DIRECTORY_COOKIE dllDirectoryCookie = AddDllDirectory(dllDirectory); + + // TODO: log getLastSystemError() + + HMODULE libraryHandle = LoadLibraryExA(libraryPath, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + + // remove the binaries directory from the DLL path + if (dllDirectoryCookie) { + RemoveDllDirectory(dllDirectoryCookie); + } + + // TODO: log error + +#else + void *libraryHandle = dlopen(libraryPath, RTLD_LAZY); +#endif + + if (!libraryHandle) { + return NULL; + } + + FMIInstance *instance = (FMIInstance *) calloc(1, sizeof(FMIInstance)); + + instance->libraryHandle = libraryHandle; + + instance->logMessage = logMessage; + instance->logFunctionCall = logFunctionCall; + + instance->bufsize1 = INITIAL_MESSAGE_BUFFER_SIZE; + instance->bufsize2 = INITIAL_MESSAGE_BUFFER_SIZE; + + instance->buf1 = (char *) calloc(instance->bufsize1, sizeof(char)); + instance->buf2 = (char *) calloc(instance->bufsize1, sizeof(char)); + + instance->name = strdup(instanceName); + + instance->status = FMIOK; + + return instance; +} + +void FMIFreeInstance(FMIInstance *instance) +{ + + if (!instance) { + return; + } + + // unload the shared library + if (instance->libraryHandle) { +#ifdef _WIN32 + FreeLibrary(instance->libraryHandle); +#else + dlclose(instance->libraryHandle); +#endif + instance->libraryHandle = NULL; + } + + free(instance->buf1); + free(instance->buf2); + free((void *) instance->name); + + free(instance->fmi1Functions); + free(instance->fmi2Functions); + free(instance->fmi3Functions); + + free(instance); +} + +const char *FMIValueReferencesToString(FMIInstance *instance, const FMIValueReference vr[], size_t nvr) +{ + + size_t pos = 0; + + do { + pos += snprintf(&instance->buf1[pos], instance->bufsize1 - pos, "{"); + + for (size_t i = 0; i < nvr; i++) { + + pos += snprintf(&instance->buf1[pos], instance->bufsize1 - pos, i < nvr - 1 ? "%u, " : "%u", vr[i]); + + if (pos > instance->bufsize1 - 2) { + pos = 0; + instance->bufsize1 *= 2; + instance->buf1 = (char *) realloc(instance->buf1, instance->bufsize1); + break; + } + } + } while (pos == 0); + + pos += snprintf(&instance->buf1[pos], instance->bufsize1 - pos, "}"); + + return instance->buf1; +} + +const char *FMIValuesToString(FMIInstance *instance, size_t vValues, const size_t sizes[], const void *values, FMIVariableType variableType) +{ + + size_t pos = 0; + + do { + pos += snprintf(&instance->buf2[pos], instance->bufsize2 - pos, "{"); + + for (size_t i = 0; i < vValues; i++) { + + char * s = &instance->buf2[pos]; + size_t n = instance->bufsize2 - pos; + + switch (variableType) { + case FMIFloat32Type: + case FMIDiscreteFloat32Type: + pos += snprintf(s, n, "%.7g", ((float *) values)[i]); + break; + case FMIFloat64Type: + case FMIDiscreteFloat64Type: + pos += snprintf(s, n, "%.16g", ((double *) values)[i]); + break; + case FMIInt8Type: + pos += snprintf(s, n, "%" PRId8, ((int8_t *) values)[i]); + break; + case FMIUInt8Type: + pos += snprintf(s, n, "%" PRIu8, ((uint8_t *) values)[i]); + break; + case FMIInt16Type: + pos += snprintf(s, n, "%" PRId16, ((int16_t *) values)[i]); + break; + case FMIUInt16Type: + pos += snprintf(s, n, "%" PRIu16, ((uint16_t *) values)[i]); + break; + case FMIInt32Type: + pos += snprintf(s, n, "%" PRId32, ((int32_t *) values)[i]); + break; + case FMIUInt32Type: + pos += snprintf(s, n, "%" PRIu32, ((uint32_t *) values)[i]); + break; + case FMIInt64Type: + pos += snprintf(s, n, "%" PRId64, ((int64_t *) values)[i]); + break; + case FMIUInt64Type: + pos += snprintf(s, n, "%" PRIu64, ((uint64_t *) values)[i]); + break; + case FMIBooleanType: + switch (instance->fmiVersion) { + case FMIVersion1: + pos += snprintf(s, n, "%d", ((char *) values)[i]); + break; + case FMIVersion2: + pos += snprintf(s, n, "%d", ((int *) values)[i]); + break; + case FMIVersion3: + pos += snprintf(s, n, "%d", ((bool *) values)[i]); + break; + } + break; + case FMIStringType: + pos += snprintf(s, n, "\"%s\"", ((const char **) values)[i]); + break; + case FMIBinaryType: { + const size_t size = sizes[i]; + const unsigned char *v = ((const unsigned char **) values)[i]; + for (size_t j = 0; j < size; j++) { + pos += snprintf(&instance->buf2[pos], instance->bufsize2 - pos, "%02hhx", v[j]); + } + break; + } + case FMIClockType: + pos += snprintf(s, n, "%d", ((bool *) values)[i]); + break; + } + + if (i < vValues - 1) { + pos += snprintf(&instance->buf2[pos], instance->bufsize2 - pos, ", "); + } + + // resize the buffer if we ran out of space + if (pos > instance->bufsize2 - 2) { + pos = 0; + instance->bufsize2 *= 2; + instance->buf2 = (char *) realloc(instance->buf2, instance->bufsize2); + break; + } + } + + } while (pos == 0); // run again if the buffer has been resized + + pos += snprintf(&instance->buf2[pos], instance->bufsize2 - pos, "}"); + + return instance->buf2; +} + +FMIStatus FMIURIToPath(const char *uri, char *path, const size_t pathLength) +{ + +#ifdef _WIN32 + DWORD pcchPath = (DWORD) pathLength; + + if (PathCreateFromUrlA(uri, path, &pcchPath, 0) != S_OK) { + return FMIError; + } +#else + const char *scheme1 = "file:///"; + const char *scheme2 = "file:/"; + + strncpy(path, uri, pathLength); + + if (strncmp(uri, scheme1, strlen(scheme1)) == 0) { + strncpy(path, &uri[strlen(scheme1)] - 1, pathLength); + } else if (strncmp(uri, scheme2, strlen(scheme2)) == 0) { + strncpy(path, &uri[strlen(scheme2) - 1], pathLength); + } else { + return FMIError; + } +#endif + +#ifdef _WIN32 + const char *sep = "\\"; +#else + const char *sep = "/"; +#endif + + if (path[strlen(path) - 1] != sep[0]) { + strncat(path, sep, pathLength); + } + + return FMIOK; +} + +FMIStatus FMIPathToURI(const char *path, char *uri, const size_t uriLength) +{ + +#ifdef _WIN32 + DWORD pcchUri = (DWORD) uriLength; + + if (UrlCreateFromPathA(path, uri, &pcchUri, 0) != S_OK) { + return FMIError; + } +#else + snprintf(uri, uriLength, "file://%s", path); + + if (path[strlen(path) - 1] != '/') { + strncat(uri, "/", uriLength); + } +#endif + + return FMIOK; +} + +FMIStatus FMIPlatformBinaryPath(const char *unzipdir, const char *modelIdentifier, FMIVersion fmiVersion, char *platformBinaryPath, size_t size) +{ + +#if defined(_WIN32) + const char *platform = "win"; + const char *system = "windows"; + const char sep = '\\'; + const char *ext = ".dll"; +#elif defined(__APPLE__) + const char *platform = "darwin"; + const char *system = "darwin"; + const char sep = '/'; + const char *ext = ".dylib"; +#else + const char *platform = "linux"; + const char *system = "linux"; + const char sep = '/'; + const char *ext = ".so"; +#endif + +#if defined(_WIN64) || defined(__x86_64__) + const char *bits = "64"; + const char *arch = "x86_64"; +#else + const char *bits = "32"; + const char *arch = "x86"; +#endif + const char *bin = "binaries"; + char optSep[2] = ""; + int rc; + + if (unzipdir[strlen(unzipdir) - 1] != sep) { + optSep[0] = sep; + } + if (fmiVersion == 3) { + rc = snprintf(platformBinaryPath, size, "%s%s%s%c%s-%s%c%s%s", unzipdir, optSep, bin, sep, arch, system, sep, modelIdentifier, ext); + } else { + rc = snprintf(platformBinaryPath, size, "%s%s%s%c%s%s%c%s%s", unzipdir, optSep, bin, sep, platform, bits, sep, modelIdentifier, ext); + } + + if (rc >= size) { + return FMIError; + } + + return FMIOK; +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI1.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI1.c new file mode 100644 index 000000000..5d9361ef0 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI1.c @@ -0,0 +1,525 @@ +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include "FMI1.h" + +// keep track of the current instance for the log callback +static FMIInstance *currentInstance = NULL; + +static void cb_logMessage1(fmi1Component c, fmi1String instanceName, fmi1Status status, fmi1String category, fmi1String message, ...) +{ + + if (!currentInstance) + return; + + char buf[FMI_MAX_MESSAGE_LENGTH]; + + va_list args; + + va_start(args, message); + vsnprintf(buf, FMI_MAX_MESSAGE_LENGTH, message, args); + va_end(args); + + if (!currentInstance->logMessage) + return; + + currentInstance->logMessage(currentInstance, (FMIStatus) status, category, buf); +} + +#define MAX_SYMBOL_LENGTH 256 + +static void *loadSymbol(FMIInstance *instance, const char *prefix, const char *name) +{ + char fname[MAX_SYMBOL_LENGTH]; + strcpy(fname, prefix); + strcat(fname, name); +#ifdef _WIN32 + void *addr = GetProcAddress(instance->libraryHandle, fname); +#else + void *addr = dlsym(instance->libraryHandle, fname); +#endif + if (!addr) { + instance->logFunctionCall(instance, FMIError, "Failed to load function \"%s\".", fname); + } + return addr; +} + +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi1Functions->fmi1##f = (fmi1##f##TYPE *) loadSymbol(instance, modelIdentifier, "_fmi" #f); \ + if (!instance->fmi1Functions->fmi1##f) { \ + status = FMIError; \ + goto fail; \ + } \ + } while (0) + +#define CALL(f) \ + do { \ + currentInstance = instance; \ + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1##f(instance->component); \ + if (instance->logFunctionCall) { \ + instance->logFunctionCall(instance, status, "fmi" #f "()"); \ + } \ + return status; \ + } while (0) + +#define CALL_ARGS(f, m, ...) \ + do { \ + currentInstance = instance; \ + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1##f(instance->component, __VA_ARGS__); \ + if (instance->logFunctionCall) { \ + instance->logFunctionCall(instance, status, "fmi" #f "(" m ")", __VA_ARGS__); \ + } \ + return status; \ + } while (0) + +#define CALL_ARRAY(s, t) \ + do { \ + currentInstance = instance; \ + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1##s##t(instance->component, vr, nvr, value); \ + if (instance->logFunctionCall) { \ + FMIValueReferencesToString(instance, vr, nvr); \ + FMIValuesToString(instance, nvr, NULL, value, FMI##t##Type); \ + instance->logFunctionCall(instance, status, "fmi" #s #t "(vr=%s, nvr=%zu, value=%s)", instance->buf1, nvr, instance->buf2); \ + } \ + return status; \ + } while (0) + +/*************************************************** + Common Functions for FMI 1.0 +****************************************************/ + +FMIStatus FMI1SetReal(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Real value[]) +{ + CALL_ARRAY(Set, Real); +} + +FMIStatus FMI1SetInteger(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer value[]) +{ + CALL_ARRAY(Set, Integer); +} + +FMIStatus FMI1SetBoolean(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Boolean value[]) +{ + CALL_ARRAY(Set, Boolean); +} + +FMIStatus FMI1SetString(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1String value[]) +{ + CALL_ARRAY(Set, String); +} + +FMIStatus FMI1GetReal(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1Real value[]) +{ + CALL_ARRAY(Get, Real); +} + +FMIStatus FMI1GetInteger(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1Integer value[]) +{ + CALL_ARRAY(Get, Integer); +} + +FMIStatus FMI1GetBoolean(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1Boolean value[]) +{ + CALL_ARRAY(Get, Boolean); +} + +FMIStatus FMI1GetString(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, fmi1String value[]) +{ + CALL_ARRAY(Get, String); +} + +FMIStatus FMI1SetDebugLogging(FMIInstance *instance, fmi1Boolean loggingOn) +{ + CALL_ARGS(SetDebugLogging, "loggingOn=%d", loggingOn); +} + +/*************************************************** + FMI 1.0 for Model Exchange Functions +****************************************************/ + +const char *FMI1GetModelTypesPlatform(FMIInstance *instance) +{ + currentInstance = instance; + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmiGetModelTypesPlatform()"); + } + return instance->fmi1Functions->fmi1GetModelTypesPlatform(); +} + +const char *FMI1GetVersion(FMIInstance *instance) +{ + currentInstance = instance; + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmiGetVersion()"); + } + return instance->fmi1Functions->fmi1GetVersion(); +} + +FMIStatus FMI1InstantiateModel(FMIInstance *instance, fmi1String modelIdentifier, fmi1String GUID, fmi1Boolean loggingOn) +{ + + currentInstance = instance; + + instance->fmiVersion = FMIVersion1; + + instance->interfaceType = FMIModelExchange; + + FMIStatus status = FMIOK; + + instance->fmi1Functions = calloc(1, sizeof(FMI1Functions)); + + if (!instance->fmi1Functions) { + return FMIError; + } + + /*************************************************** + Common Functions for FMI 1.0 + ****************************************************/ + LOAD_SYMBOL(SetReal); + LOAD_SYMBOL(SetInteger); + LOAD_SYMBOL(SetBoolean); + LOAD_SYMBOL(SetString); + LOAD_SYMBOL(GetReal); + LOAD_SYMBOL(GetInteger); + LOAD_SYMBOL(GetBoolean); + LOAD_SYMBOL(GetString); + LOAD_SYMBOL(SetDebugLogging); + + /*************************************************** + FMI 1.0 for Model Exchange Functions + ****************************************************/ + LOAD_SYMBOL(GetModelTypesPlatform); + LOAD_SYMBOL(GetVersion); + LOAD_SYMBOL(InstantiateModel); + LOAD_SYMBOL(FreeModelInstance); + LOAD_SYMBOL(SetTime); + LOAD_SYMBOL(SetContinuousStates); + LOAD_SYMBOL(CompletedIntegratorStep); + LOAD_SYMBOL(Initialize); + LOAD_SYMBOL(GetDerivatives); + LOAD_SYMBOL(GetEventIndicators); + LOAD_SYMBOL(EventUpdate); + LOAD_SYMBOL(GetContinuousStates); + LOAD_SYMBOL(GetNominalContinuousStates); + LOAD_SYMBOL(GetStateValueReferences); + LOAD_SYMBOL(Terminate); + + instance->fmi1Functions->callbacks.logger = cb_logMessage1; + instance->fmi1Functions->callbacks.allocateMemory = calloc; + instance->fmi1Functions->callbacks.freeMemory = free; + instance->fmi1Functions->callbacks.stepFinished = NULL; + + instance->component = instance->fmi1Functions->fmi1InstantiateModel(instance->name, GUID, instance->fmi1Functions->callbacks, loggingOn); + + status = instance->component ? FMIOK : FMIError; + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi1InstantiateModel(instanceName=\"%s\", GUID=\"%s\", functions=0x%p, loggingOn=%d)", + instance->name, GUID, &instance->fmi1Functions->callbacks, loggingOn); + } + +fail: + return status; +} + +void FMI1FreeModelInstance(FMIInstance *instance) +{ + + if (!instance) { + return; + } + + currentInstance = instance; + + instance->fmi1Functions->fmi1FreeModelInstance(instance->component); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi1FreeModelInstance()"); + } +} + +FMIStatus FMI1SetTime(FMIInstance *instance, fmi1Real time) +{ + CALL_ARGS(SetTime, "time=%.16g", time); +} + +FMIStatus FMI1SetContinuousStates(FMIInstance *instance, const fmi1Real x[], size_t nx) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1SetContinuousStates(instance->component, x, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, x, FMIRealType); + instance->logFunctionCall(instance, status, "fmi1SetContinuousStates(x=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +FMIStatus FMI1CompletedIntegratorStep(FMIInstance *instance, fmi1Boolean *callEventUpdate) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1CompletedIntegratorStep(instance->component, callEventUpdate); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi1CompletedIntegratorStep(callEventUpdate=%d)", *callEventUpdate); + } + return status; +} + +FMIStatus FMI1Initialize(FMIInstance *instance, fmi1Boolean toleranceControlled, fmi1Real relativeTolerance) +{ + fmi1EventInfo *e = &instance->fmi1Functions->eventInfo; + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1Initialize(instance->component, toleranceControlled, relativeTolerance, e); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi1Initialize(toleranceControlled=%d, relativeTolerance=%.16g, eventInfo={iterationConverged=%d, stateValueReferencesChanged=%d, stateValuesChanged=%d, terminateSimulation=%d, upcomingTimeEvent=%d, nextEventTime=%.16g})", + toleranceControlled, relativeTolerance, e->iterationConverged, e->stateValueReferencesChanged, e->stateValuesChanged, e->terminateSimulation, e->upcomingTimeEvent, e->nextEventTime); + } + return status; +} + +FMIStatus FMI1GetDerivatives(FMIInstance *instance, fmi1Real derivatives[], size_t nx) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1GetDerivatives(instance->component, derivatives, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, derivatives, FMIRealType); + instance->logFunctionCall(instance, status, "fmi1GetDerivatives(derivatives=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +FMIStatus FMI1GetEventIndicators(FMIInstance *instance, fmi1Real eventIndicators[], size_t ni) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1GetEventIndicators(instance->component, eventIndicators, ni); + if (instance->logFunctionCall) { + FMIValuesToString(instance, ni, NULL, eventIndicators, FMIRealType); + instance->logFunctionCall(instance, status, "fmi1GetEventIndicators(eventIndicators=%s, ni=%zu)", instance->buf2, ni); + } + return status; +} + +FMIStatus FMI1EventUpdate(FMIInstance *instance, fmi1Boolean intermediateResults, fmi1EventInfo *eventInfo) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1EventUpdate(instance->component, intermediateResults, eventInfo); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi1Initialize(intermediateResults=%d, eventInfo={iterationConverged=%d, stateValueReferencesChanged=%d, stateValuesChanged=%d, terminateSimulation=%d, upcomingTimeEvent=%d, nextEventTime=%.16g})", + intermediateResults, eventInfo->iterationConverged, eventInfo->stateValueReferencesChanged, eventInfo->stateValuesChanged, eventInfo->terminateSimulation, eventInfo->upcomingTimeEvent, eventInfo->nextEventTime); + } + return status; +} + +FMIStatus FMI1GetContinuousStates(FMIInstance *instance, fmi1Real states[], size_t nx) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1GetContinuousStates(instance->component, states, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, states, FMIRealType); + instance->logFunctionCall(instance, status, "fmi2GetContinuousStates(x=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +FMIStatus FMI1GetNominalContinuousStates(FMIInstance *instance, fmi1Real x_nominal[], size_t nx) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1GetNominalContinuousStates(instance->component, x_nominal, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, x_nominal, FMIRealType); + instance->logFunctionCall(instance, status, "fmi1GetNominalContinuousStates(x_nominal=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +FMIStatus FMI1GetStateValueReferences(FMIInstance *instance, fmi1ValueReference vrx[], size_t nx) +{ + currentInstance = instance; + FMIStatus status = (FMIStatus) instance->fmi1Functions->fmi1GetStateValueReferences(instance->component, vrx, nx); + if (instance->logFunctionCall) { + // TODO + } + return status; +} + +FMIStatus FMI1Terminate(FMIInstance *instance) +{ + CALL(Terminate); +} + +/*************************************************** + FMI 1.0 for Co-Simulation Functions +****************************************************/ + +const char *FMI1GetTypesPlatform(FMIInstance *instance) +{ + currentInstance = instance; + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi1GetTypesPlatform()"); + } + return instance->fmi1Functions->fmi1GetTypesPlatform(); +} + +FMIStatus FMI1InstantiateSlave(FMIInstance *instance, fmi1String modelIdentifier, fmi1String fmuGUID, fmi1String fmuLocation, fmi1String mimeType, fmi1Real timeout, fmi1Boolean visible, fmi1Boolean interactive, fmi1Boolean loggingOn) +{ + + currentInstance = instance; + + instance->fmiVersion = FMIVersion1; + + instance->interfaceType = FMICoSimulation; + + FMIStatus status = FMIOK; + + instance->fmi1Functions = calloc(1, sizeof(FMI1Functions)); + + if (!instance->fmi1Functions) { + return FMIError; + } + + /*************************************************** + Common Functions for FMI 1.0 + ****************************************************/ + LOAD_SYMBOL(SetReal); + LOAD_SYMBOL(SetInteger); + LOAD_SYMBOL(SetBoolean); + LOAD_SYMBOL(SetString); + LOAD_SYMBOL(GetReal); + LOAD_SYMBOL(GetInteger); + LOAD_SYMBOL(GetBoolean); + LOAD_SYMBOL(GetString); + LOAD_SYMBOL(SetDebugLogging); + + /*************************************************** + FMI 1.0 for Co-Simulation Functions + ****************************************************/ + LOAD_SYMBOL(GetTypesPlatform); + LOAD_SYMBOL(InstantiateSlave); + LOAD_SYMBOL(InitializeSlave); + LOAD_SYMBOL(TerminateSlave); + LOAD_SYMBOL(ResetSlave); + LOAD_SYMBOL(FreeSlaveInstance); + LOAD_SYMBOL(SetRealInputDerivatives); + LOAD_SYMBOL(GetRealOutputDerivatives); + LOAD_SYMBOL(CancelStep); + LOAD_SYMBOL(DoStep); + LOAD_SYMBOL(GetStatus); + LOAD_SYMBOL(GetRealStatus); + LOAD_SYMBOL(GetIntegerStatus); + LOAD_SYMBOL(GetBooleanStatus); + LOAD_SYMBOL(GetStringStatus); + + instance->fmi1Functions->callbacks.logger = cb_logMessage1; + instance->fmi1Functions->callbacks.allocateMemory = calloc; + instance->fmi1Functions->callbacks.freeMemory = free; + instance->fmi1Functions->callbacks.stepFinished = NULL; + + instance->component = instance->fmi1Functions->fmi1InstantiateSlave(instance->name, fmuGUID, fmuLocation, mimeType, timeout, visible, interactive, instance->fmi1Functions->callbacks, loggingOn); + + status = instance->component ? FMIOK : FMIError; + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi1InstantiateSlave(instanceName=\"%s\", fmuGUID=\"%s\", fmuLocation=\"%s\", mimeType=\"%s\", timeout=%.16g, visible=%d, interactive=%d, functions=0x%p, loggingOn=%d)", + instance->name, fmuGUID, fmuLocation, mimeType, timeout, visible, interactive, &instance->fmi1Functions->callbacks, loggingOn); + } + +fail: + return status; +} + +FMIStatus FMI1InitializeSlave(FMIInstance *instance, fmi1Real tStart, fmi1Boolean stopTimeDefined, fmi1Real tStop) +{ + CALL_ARGS(InitializeSlave, "tStart=%.16g, stopTimeDefined=%d, tStop=%.16g", tStart, stopTimeDefined, tStop); +} + +FMIStatus FMI1TerminateSlave(FMIInstance *instance) +{ + CALL(TerminateSlave); +} + +FMIStatus FMI1ResetSlave(FMIInstance *instance) +{ + CALL(ResetSlave); +} + +void FMI1FreeSlaveInstance(FMIInstance *instance) +{ + + if (!instance) { + return; + } + + currentInstance = instance; + + instance->fmi1Functions->fmi1FreeSlaveInstance(instance->component); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi1FreeSlaveInstance()"); + } +} + +FMIStatus FMI1SetRealInputDerivatives(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer order[], const fmi1Real value[]) +{ + CALL_ARGS(SetRealInputDerivatives, "vr=0x%p, nvr=%zu, order=0x%p, value=0x%p", vr, nvr, order, value); +} + +FMIStatus FMI1GetRealOutputDerivatives(FMIInstance *instance, const fmi1ValueReference vr[], size_t nvr, const fmi1Integer order[], fmi1Real value[]) +{ + CALL_ARGS(GetRealOutputDerivatives, "vr=0x%p, nvr=%zu, order=0x%p, value=0x%p", vr, nvr, order, value); +} + +FMIStatus FMI1CancelStep(FMIInstance *instance) +{ + CALL(CancelStep); +} + +FMIStatus FMI1DoStep(FMIInstance *instance, fmi1Real currentCommunicationPoint, fmi1Real communicationStepSize, fmi1Boolean newStep) +{ + + currentInstance = instance; + + instance->time = currentCommunicationPoint + communicationStepSize; + + CALL_ARGS(DoStep, "currentCommunicationPoint=%.16g, communicationStepSize=%.16g, newStep=%d", + currentCommunicationPoint, communicationStepSize, newStep); +} + +FMIStatus FMI1GetStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Status *value) +{ + CALL_ARGS(GetStatus, "s=%d, value=0x%p", s, value); +} + +FMIStatus FMI1GetRealStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Real *value) +{ + CALL_ARGS(GetRealStatus, "s=%d, value=0x%p", s, value); +} + +FMIStatus FMI1GetIntegerStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Integer *value) +{ + CALL_ARGS(GetIntegerStatus, "s=%d, value=0x%p", s, value); +} + +FMIStatus FMI1GetBooleanStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1Boolean *value) +{ + CALL_ARGS(GetBooleanStatus, "s=%d, value=0x%p", s, value); +} + +FMIStatus FMI1GetStringStatus(FMIInstance *instance, const fmi1StatusKind s, fmi1String *value) +{ + CALL_ARGS(GetStringStatus, "s=%d, value=0x%p", s, value); +} + +#undef LOAD_SYMBOL +#undef CALL +#undef CALL_ARGS +#undef CALL_ARRAY diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI2.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI2.c new file mode 100644 index 000000000..106b530a6 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI2.c @@ -0,0 +1,569 @@ +#ifdef _WIN32 +#include +#include "Shlwapi.h" +#pragma comment(lib, "shlwapi.lib") +#define strdup _strdup +#define INTERNET_MAX_URL_LENGTH 2083 // from wininet.h +#else +#include +#include +#endif + +#include +#include +#include + +#include "FMI2.h" + +static void cb_logMessage2(fmi2ComponentEnvironment componentEnvironment, fmi2String instanceName, fmi2Status status, fmi2String category, fmi2String message, ...) +{ + + if (!componentEnvironment) + return; + + FMIInstance *instance = componentEnvironment; + + char buf[FMI_MAX_MESSAGE_LENGTH]; + + va_list args; + + va_start(args, message); + vsnprintf(buf, FMI_MAX_MESSAGE_LENGTH, message, args); + va_end(args); + + if (!instance->logMessage) + return; + + instance->logMessage(instance, (FMIStatus) status, category, buf); +} + +#if defined(FMI2_FUNCTION_PREFIX) +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi2Functions->fmi2##f = fmi2##f; \ + } while (0) +#elif defined(_WIN32) +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi2Functions->fmi2##f = (fmi2##f##TYPE *) GetProcAddress(instance->libraryHandle, "fmi2" #f); \ + if (!instance->fmi2Functions->fmi2##f) { \ + instance->logMessage(instance, FMIFatal, "fatal", "Symbol fmi2" #f " is missing in shared library."); \ + return fmi2Fatal; \ + } \ + } while (0) +#else +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi2Functions->fmi2##f = (fmi2##f##TYPE *) dlsym(instance->libraryHandle, "fmi2" #f); \ + if (!instance->fmi2Functions->fmi2##f) { \ + instance->logMessage(instance, FMIFatal, "fatal", "Symbol fmi2" #f " is missing in shared library."); \ + return FMIFatal; \ + } \ + } while (0) +#endif + +#define CALL(f) \ + do { \ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2##f(instance->component); \ + if (instance->logFunctionCall) { \ + instance->logFunctionCall(instance, status, "fmi2" #f "()"); \ + } \ + return status; \ + } while (0) + +#define CALL_ARGS(f, m, ...) \ + do { \ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2##f(instance->component, __VA_ARGS__); \ + if (instance->logFunctionCall) { \ + instance->logFunctionCall(instance, status, "fmi2" #f "(" m ")", __VA_ARGS__); \ + } \ + return status; \ + } while (0) + +#define CALL_ARRAY(s, t) \ + do { \ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2##s##t(instance->component, vr, nvr, value); \ + if (instance->logFunctionCall) { \ + FMIValueReferencesToString(instance, vr, nvr); \ + FMIValuesToString(instance, nvr, NULL, value, FMI##t##Type); \ + instance->logFunctionCall(instance, status, "fmi2" #s #t "(vr=%s, nvr=%zu, value=%s)", instance->buf1, nvr, instance->buf2); \ + } \ + return status; \ + } while (0) + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers of header files and setting logging status */ +const char *FMI2GetTypesPlatform(FMIInstance *instance) +{ + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi2GetTypesPlatform()"); + } + return instance->fmi2Functions->fmi2GetTypesPlatform(); +} + +const char *FMI2GetVersion(FMIInstance *instance) +{ + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi2GetVersion()"); + } + return instance->fmi2Functions->fmi2GetVersion(); +} + +FMIStatus FMI2SetDebugLogging(FMIInstance *instance, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2SetDebugLogging(instance->component, loggingOn, nCategories, categories); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nCategories, NULL, categories, FMIStringType); + instance->logFunctionCall(instance, status, "fmi2SetDebugLogging(loggingOn=%d, nCategories=%zu, categories=%s)", + loggingOn, nCategories, instance->buf2); + } + return status; +} + +/* Creation and destruction of FMU instances and setting debug status */ +FMIStatus FMI2Instantiate(FMIInstance *instance, const char *fmuResourceLocation, fmi2Type fmuType, fmi2String fmuGUID, + fmi2Boolean visible, fmi2Boolean loggingOn) +{ + + instance->fmiVersion = FMIVersion2; + + instance->fmi2Functions = calloc(1, sizeof(FMI2Functions)); + + if (!instance->fmi2Functions) { + return FMIError; + } + + instance->fmi2Functions->eventInfo.newDiscreteStatesNeeded = fmi2False; + instance->fmi2Functions->eventInfo.terminateSimulation = fmi2False; + instance->fmi2Functions->eventInfo.nominalsOfContinuousStatesChanged = fmi2False; + instance->fmi2Functions->eventInfo.valuesOfContinuousStatesChanged = fmi2False; + instance->fmi2Functions->eventInfo.nextEventTimeDefined = fmi2False; + instance->fmi2Functions->eventInfo.nextEventTime = 0.0; + + instance->state = FMI2StartAndEndState; + +#if !defined(FMI_VERSION) || FMI_VERSION == 2 + + /*************************************************** + Common Functions + ****************************************************/ + + /* required functions */ + LOAD_SYMBOL(GetTypesPlatform); + LOAD_SYMBOL(GetVersion); + LOAD_SYMBOL(SetDebugLogging); + LOAD_SYMBOL(Instantiate); + LOAD_SYMBOL(FreeInstance); + LOAD_SYMBOL(SetupExperiment); + LOAD_SYMBOL(EnterInitializationMode); + LOAD_SYMBOL(ExitInitializationMode); + LOAD_SYMBOL(Terminate); + LOAD_SYMBOL(Reset); + LOAD_SYMBOL(GetReal); + LOAD_SYMBOL(GetInteger); + LOAD_SYMBOL(GetBoolean); + LOAD_SYMBOL(GetString); + LOAD_SYMBOL(SetReal); + LOAD_SYMBOL(SetInteger); + LOAD_SYMBOL(SetBoolean); + LOAD_SYMBOL(SetString); + + /* optional functions */ + LOAD_SYMBOL(GetFMUstate); + LOAD_SYMBOL(SetFMUstate); + LOAD_SYMBOL(FreeFMUstate); + LOAD_SYMBOL(SerializedFMUstateSize); + LOAD_SYMBOL(SerializeFMUstate); + LOAD_SYMBOL(DeSerializeFMUstate); + LOAD_SYMBOL(GetDirectionalDerivative); + + if (fmuType == fmi2ModelExchange) { +#ifndef CO_SIMULATION + /*************************************************** + Model Exchange + ****************************************************/ + + LOAD_SYMBOL(EnterEventMode); + LOAD_SYMBOL(NewDiscreteStates); + LOAD_SYMBOL(EnterContinuousTimeMode); + LOAD_SYMBOL(CompletedIntegratorStep); + LOAD_SYMBOL(SetTime); + LOAD_SYMBOL(SetContinuousStates); + LOAD_SYMBOL(GetDerivatives); + LOAD_SYMBOL(GetEventIndicators); + LOAD_SYMBOL(GetContinuousStates); + LOAD_SYMBOL(GetNominalsOfContinuousStates); +#endif + } else { +#ifndef MODEL_EXCHANGE + /*************************************************** + Co-Simulation + ****************************************************/ + + LOAD_SYMBOL(SetRealInputDerivatives); + LOAD_SYMBOL(GetRealOutputDerivatives); + LOAD_SYMBOL(DoStep); + LOAD_SYMBOL(CancelStep); + LOAD_SYMBOL(GetStatus); + LOAD_SYMBOL(GetRealStatus); + LOAD_SYMBOL(GetIntegerStatus); + LOAD_SYMBOL(GetBooleanStatus); + LOAD_SYMBOL(GetStringStatus); +#endif + } + +#endif + + instance->fmi2Functions->callbacks.logger = cb_logMessage2; + instance->fmi2Functions->callbacks.allocateMemory = calloc; + instance->fmi2Functions->callbacks.freeMemory = free; + instance->fmi2Functions->callbacks.stepFinished = NULL; + instance->fmi2Functions->callbacks.componentEnvironment = instance; + + instance->component = instance->fmi2Functions->fmi2Instantiate(instance->name, fmuType, fmuGUID, fmuResourceLocation, &instance->fmi2Functions->callbacks, visible, loggingOn); + + if (instance->logFunctionCall) { + fmi2CallbackFunctions *f = &instance->fmi2Functions->callbacks; + instance->logFunctionCall(instance, instance->component ? FMIOK : FMIError, + "fmi2Instantiate(instanceName=\"%s\", fmuType=%d, fmuGUID=\"%s\", fmuResourceLocation=\"%s\", functions={logger=0x%p, allocateMemory=0x%p, freeMemory=0x%p, stepFinished=0x%p, componentEnvironment=0x%p}, visible=%d, loggingOn=%d)", + instance->name, fmuType, fmuGUID, fmuResourceLocation, f->logger, f->allocateMemory, f->freeMemory, f->stepFinished, f->componentEnvironment, visible, loggingOn); + } + + if (!instance->component) { + return FMIError; + } + + instance->interfaceType = (FMIInterfaceType) fmuType; + instance->state = FMI2InstantiatedState; + + return FMIOK; +} + +void FMI2FreeInstance(FMIInstance *instance) +{ + + if (!instance) { + return; + } + + instance->fmi2Functions->fmi2FreeInstance(instance->component); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi2FreeInstance()"); + } +} + +/* Enter and exit initialization mode, terminate and reset */ +FMIStatus FMI2SetupExperiment(FMIInstance *instance, + fmi2Boolean toleranceDefined, + fmi2Real tolerance, + fmi2Real startTime, + fmi2Boolean stopTimeDefined, + fmi2Real stopTime) +{ + + instance->time = startTime; + + CALL_ARGS(SetupExperiment, "toleranceDefined=%d, tolerance=%.16g, startTime=%.16g, stopTimeDefined=%d, stopTime=%.16g", toleranceDefined, tolerance, startTime, stopTimeDefined, stopTime); +} + +FMIStatus FMI2EnterInitializationMode(FMIInstance *instance) +{ + instance->state = FMI2InitializationModeState; + CALL(EnterInitializationMode); +} + +FMIStatus FMI2ExitInitializationMode(FMIInstance *instance) +{ + instance->state = instance->interfaceType == FMIModelExchange ? FMI2EventModeState : FMI2StepCompleteState; + CALL(ExitInitializationMode); +} + +FMIStatus FMI2Terminate(FMIInstance *instance) +{ + instance->state = FMI2TerminatedState; + CALL(Terminate); +} + +FMIStatus FMI2Reset(FMIInstance *instance) +{ + instance->state = FMI2InstantiatedState; + CALL(Reset); +} + +/* Getting and setting variable values */ +FMIStatus FMI2GetReal(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) +{ + CALL_ARRAY(Get, Real); +} + +FMIStatus FMI2GetInteger(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) +{ + CALL_ARRAY(Get, Integer); +} + +FMIStatus FMI2GetBoolean(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) +{ + CALL_ARRAY(Get, Boolean); +} + +FMIStatus FMI2GetString(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) +{ + CALL_ARRAY(Get, String); +} + +FMIStatus FMI2SetReal(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) +{ + CALL_ARRAY(Set, Real); +} + +FMIStatus FMI2SetInteger(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) +{ + CALL_ARRAY(Set, Integer); +} + +FMIStatus FMI2SetBoolean(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) +{ + CALL_ARRAY(Set, Boolean); +} + +FMIStatus FMI2SetString(FMIInstance *instance, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) +{ + CALL_ARRAY(Set, String); +} + +/* Getting and setting the internal FMU state */ +FMIStatus FMI2GetFMUstate(FMIInstance *instance, fmi2FMUstate *FMUstate) +{ + CALL_ARGS(GetFMUstate, "FMUstate=0x%p", FMUstate); +} + +FMIStatus FMI2SetFMUstate(FMIInstance *instance, fmi2FMUstate FMUstate) +{ + CALL_ARGS(SetFMUstate, "FMUstate=0x%p", FMUstate); +} + +FMIStatus FMI2FreeFMUstate(FMIInstance *instance, fmi2FMUstate *FMUstate) +{ + CALL_ARGS(FreeFMUstate, "FMUstate=0x%p", FMUstate); +} + +FMIStatus FMI2SerializedFMUstateSize(FMIInstance *instance, fmi2FMUstate FMUstate, size_t *size) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2SerializedFMUstateSize(instance->component, FMUstate, size); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2SerializedFMUstateSize(FMUstate=0x%p, size=%zu)", FMUstate, *size); + } + return status; +} + +FMIStatus FMI2SerializeFMUstate(FMIInstance *instance, fmi2FMUstate FMUstate, fmi2Byte serializedState[], size_t size) +{ + CALL_ARGS(SerializeFMUstate, "FMUstate=0x%p, serializedState=0x%p, size=%zu", FMUstate, serializedState, size); +} + +FMIStatus FMI2DeSerializeFMUstate(FMIInstance *instance, const fmi2Byte serializedState[], size_t size, fmi2FMUstate *FMUstate) +{ + CALL_ARGS(DeSerializeFMUstate, "serializedState=0x%p, size=%zu, FMUstate=0x%p", serializedState, size, FMUstate); +} + +/* Getting partial derivatives */ +FMIStatus FMI2GetDirectionalDerivative(FMIInstance * instance, + const fmi2ValueReference vUnknown_ref[], size_t nUnknown, + const fmi2ValueReference vKnown_ref[], size_t nKnown, + const fmi2Real dvKnown[], + fmi2Real dvUnknown[]) +{ + CALL_ARGS(GetDirectionalDerivative, "vUnknown_ref=0x%p, nUnknown=%zu, vKnown_ref=0x%p, nKnown=%zu, dvKnown=0x%p, dvUnknown=0x%p", + vUnknown_ref, nUnknown, vKnown_ref, nKnown, dvKnown, dvUnknown); +} + +/*************************************************** +Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ +FMIStatus FMI2EnterEventMode(FMIInstance *instance) +{ + instance->state = FMI2EventModeState; + CALL(EnterEventMode); +} + +FMIStatus FMI2NewDiscreteStates(FMIInstance *instance, fmi2EventInfo *eventInfo) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2NewDiscreteStates(instance->component, eventInfo); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi2NewDiscreteStates(eventInfo={newDiscreteStatesNeeded=%d, terminateSimulation=%d, nominalsOfContinuousStatesChanged=%d, valuesOfContinuousStatesChanged=%d, nextEventTimeDefined=%d, nextEventTime=%.16g})", + eventInfo->newDiscreteStatesNeeded, eventInfo->terminateSimulation, eventInfo->nominalsOfContinuousStatesChanged, eventInfo->valuesOfContinuousStatesChanged, eventInfo->nextEventTimeDefined, eventInfo->nextEventTime); + } + return status; +} + +FMIStatus FMI2EnterContinuousTimeMode(FMIInstance *instance) +{ + instance->state = FMI2ContinuousTimeModeState; + CALL(EnterContinuousTimeMode); +} + +FMIStatus FMI2CompletedIntegratorStep(FMIInstance *instance, + fmi2Boolean noSetFMUStatePriorToCurrentPoint, + fmi2Boolean *enterEventMode, + fmi2Boolean *terminateSimulation) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2CompletedIntegratorStep(instance->component, noSetFMUStatePriorToCurrentPoint, enterEventMode, terminateSimulation); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2CompletedIntegratorStep(noSetFMUStatePriorToCurrentPoint=%d, enterEventMode=%d, terminateSimulation=%d)", noSetFMUStatePriorToCurrentPoint, *enterEventMode, *terminateSimulation); + } + return status; +} + +/* Providing independent variables and re-initialization of caching */ +FMIStatus FMI2SetTime(FMIInstance *instance, fmi2Real time) +{ + instance->time = time; + CALL_ARGS(SetTime, "time=%.16g", time); +} + +FMIStatus FMI2SetContinuousStates(FMIInstance *instance, const fmi2Real x[], size_t nx) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2SetContinuousStates(instance->component, x, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, x, FMIRealType); + instance->logFunctionCall(instance, status, "fmi2SetContinuousStates(x=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +/* Evaluation of the model equations */ +FMIStatus FMI2GetDerivatives(FMIInstance *instance, fmi2Real derivatives[], size_t nx) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetDerivatives(instance->component, derivatives, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, derivatives, FMIRealType); + instance->logFunctionCall(instance, status, "fmi2GetDerivatives(derivatives=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +FMIStatus FMI2GetEventIndicators(FMIInstance *instance, fmi2Real eventIndicators[], size_t ni) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetEventIndicators(instance->component, eventIndicators, ni); + if (instance->logFunctionCall) { + FMIValuesToString(instance, ni, NULL, eventIndicators, FMIRealType); + instance->logFunctionCall(instance, status, "fmi2GetEventIndicators(eventIndicators=%s, ni=%zu)", instance->buf2, ni); + } + return status; +} + +FMIStatus FMI2GetContinuousStates(FMIInstance *instance, fmi2Real x[], size_t nx) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetContinuousStates(instance->component, x, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, x, FMIRealType); + instance->logFunctionCall(instance, status, "fmi2GetContinuousStates(x=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +FMIStatus FMI2GetNominalsOfContinuousStates(FMIInstance *instance, fmi2Real x_nominal[], size_t nx) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetNominalsOfContinuousStates(instance->component, x_nominal, nx); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nx, NULL, x_nominal, FMIRealType); + instance->logFunctionCall(instance, status, "fmi2GetNominalsOfContinuousStates(x_nominal=%s, nx=%zu)", instance->buf2, nx); + } + return status; +} + +/*************************************************** +Co-Simulation +****************************************************/ + +/* Simulating the slave */ +FMIStatus FMI2SetRealInputDerivatives(FMIInstance * instance, + const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], + const fmi2Real value[]) +{ + CALL_ARGS(SetRealInputDerivatives, "vr=0x%p, nvr=%zu, order=0x%p, value=0x%p", vr, nvr, order, value); +} + +FMIStatus FMI2GetRealOutputDerivatives(FMIInstance * instance, + const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], + fmi2Real value[]) +{ + CALL_ARGS(GetRealOutputDerivatives, "vr=0x%p, nvr=%zu, order=0x%p, value=0x%p", vr, nvr, order, value); +} + +FMIStatus FMI2DoStep(FMIInstance *instance, + fmi2Real currentCommunicationPoint, + fmi2Real communicationStepSize, + fmi2Boolean noSetFMUStatePriorToCurrentPoint) +{ + + instance->time = currentCommunicationPoint + communicationStepSize; + + CALL_ARGS(DoStep, "currentCommunicationPoint=%.16g, communicationStepSize=%.16g, noSetFMUStatePriorToCurrentPoint=%d", + currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint); +} + +FMIStatus FMI2CancelStep(FMIInstance *instance) +{ + CALL(CancelStep); +} + +/* Inquire slave status */ +FMIStatus FMI2GetStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Status *value) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetStatus(instance->component, s, value); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2GetStatus(s=%d, value=%d)", s, *value); + } + return status; +} + +FMIStatus FMI2GetRealStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Real *value) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetRealStatus(instance->component, s, value); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2GetRealStatus(s=%d, value=%.16g)", s, *value); + } + return status; +} + +FMIStatus FMI2GetIntegerStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Integer *value) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetIntegerStatus(instance->component, s, value); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2GetIntegerStatus(s=%d, value=%d)", s, *value); + } + return status; +} + +FMIStatus FMI2GetBooleanStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2Boolean *value) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetBooleanStatus(instance->component, s, value); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2GetBooleanStatus(s=%d, value=%d)", s, *value); + } + return status; +} + +FMIStatus FMI2GetStringStatus(FMIInstance *instance, const fmi2StatusKind s, fmi2String *value) +{ + FMIStatus status = (FMIStatus) instance->fmi2Functions->fmi2GetStringStatus(instance->component, s, value); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi2GetStringStatus(s=%d, value=%s)", s, *value); + } + return status; +} + +#undef LOAD_SYMBOL +#undef CALL +#undef CALL_ARGS +#undef CALL_ARRAY diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI3.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI3.c new file mode 100644 index 000000000..4c3b20d7b --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/FMI3.c @@ -0,0 +1,1186 @@ +#ifdef _WIN32 +#include +#include "Shlwapi.h" +#pragma comment(lib, "shlwapi.lib") +#else +#include +#include +#endif + +#include +#include +#include + +#include "FMI3.h" + +static void cb_logMessage3(fmi3InstanceEnvironment instanceEnvironment, + fmi3Status status, + fmi3String category, + fmi3String message) +{ + + if (!instanceEnvironment) + return; + + FMIInstance *instance = instanceEnvironment; + + if (!instance->logMessage) + return; + + instance->logMessage(instance, (FMIStatus) status, category, message); +} + +#if defined(FMI2_FUNCTION_PREFIX) +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi3Functions->fmi3##f = fmi3##f; \ + } while (0) +#elif defined(_WIN32) +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi3Functions->fmi3##f = (fmi3##f##TYPE *) GetProcAddress(instance->libraryHandle, "fmi3" #f); \ + if (!instance->fmi3Functions->fmi3##f) { \ + instance->logMessage(instance, FMIFatal, "fatal", "Symbol fmi3" #f " is missing in shared library."); \ + return fmi3Fatal; \ + } \ + } while (0) +#else +#define LOAD_SYMBOL(f) \ + do { \ + instance->fmi3Functions->fmi3##f = (fmi3##f##TYPE *) dlsym(instance->libraryHandle, "fmi3" #f); \ + if (!instance->fmi3Functions->fmi3##f) { \ + instance->logMessage(instance, FMIFatal, "fatal", "Symbol fmi3" #f " is missing in shared library."); \ + return FMIFatal; \ + } \ + } while (0) +#endif + +#define CALL(f) \ + do { \ + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3##f(instance->component); \ + if (instance->logFunctionCall) { \ + instance->logFunctionCall(instance, status, "fmi3" #f "()"); \ + } \ + instance->status = status > instance->status ? status : instance->status; \ + return status; \ + } while (0) + +#define CALL_ARGS(f, m, ...) \ + do { \ + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3##f(instance->component, __VA_ARGS__); \ + if (instance->logFunctionCall) { \ + instance->logFunctionCall(instance, status, "fmi3" #f "(" m ")", __VA_ARGS__); \ + } \ + instance->status = status > instance->status ? status : instance->status; \ + return status; \ + } while (0) + +#define CALL_ARRAY(s, t) \ + do { \ + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3##s##t(instance->component, valueReferences, nValueReferences, values, nValues); \ + if (instance->logFunctionCall) { \ + FMIValueReferencesToString(instance, valueReferences, nValueReferences); \ + FMIValuesToString(instance, nValues, NULL, values, FMI##t##Type); \ + instance->logFunctionCall(instance, status, "fmi3" #s #t "(valueReferences=%s, nValueReferences=%zu, values=%s, nValues=%zu)", instance->buf1, nValueReferences, instance->buf2, nValues); \ + } \ + instance->status = status > instance->status ? status : instance->status; \ + return status; \ + } while (0) + +/*************************************************** +Types for Common Functions +****************************************************/ + +/* Inquire version numbers and setting logging status */ +const char *FMI3GetVersion(FMIInstance *instance) +{ + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi3GetVersion()"); + } + return instance->fmi3Functions->fmi3GetVersion(); +} + +FMIStatus FMI3SetDebugLogging(FMIInstance * instance, + fmi3Boolean loggingOn, + size_t nCategories, + const fmi3String categories[]) +{ + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3SetDebugLogging(instance->component, loggingOn, nCategories, categories); + if (instance->logFunctionCall) { + FMIValuesToString(instance, nCategories, NULL, categories, FMIStringType); + instance->logFunctionCall(instance, status, "fmi3SetDebugLogging(loggingOn=%d, nCategories=%zu, categories=%s)", + loggingOn, nCategories, instance->buf2); + } + return status; +} + +static FMIStatus loadSymbols3(FMIInstance *instance) +{ + +#if !defined(FMI_VERSION) || FMI_VERSION == 3 + + instance->fmi3Functions = calloc(1, sizeof(FMI3Functions)); + + if (!instance->fmi3Functions) { + return FMIError; + } + + instance->fmiVersion = FMIVersion3; + + /*************************************************** + Common Functions + ****************************************************/ + + /* Inquire version numbers and set debug logging */ + LOAD_SYMBOL(GetVersion); + LOAD_SYMBOL(SetDebugLogging); + + /* Creation and destruction of FMU instances */ + LOAD_SYMBOL(InstantiateModelExchange); + LOAD_SYMBOL(InstantiateCoSimulation); + LOAD_SYMBOL(InstantiateScheduledExecution); + LOAD_SYMBOL(FreeInstance); + + /* Enter and exit initialization mode, terminate and reset */ + LOAD_SYMBOL(EnterInitializationMode); + LOAD_SYMBOL(ExitInitializationMode); + LOAD_SYMBOL(EnterEventMode); + LOAD_SYMBOL(Terminate); + LOAD_SYMBOL(Reset); + + /* Getting and setting variable values */ + LOAD_SYMBOL(GetFloat32); + LOAD_SYMBOL(GetFloat64); + LOAD_SYMBOL(GetInt8); + LOAD_SYMBOL(GetUInt8); + LOAD_SYMBOL(GetInt16); + LOAD_SYMBOL(GetUInt16); + LOAD_SYMBOL(GetInt32); + LOAD_SYMBOL(GetUInt32); + LOAD_SYMBOL(GetInt64); + LOAD_SYMBOL(GetUInt64); + LOAD_SYMBOL(GetBoolean); + LOAD_SYMBOL(GetString); + LOAD_SYMBOL(GetBinary); + LOAD_SYMBOL(GetClock); + LOAD_SYMBOL(SetFloat32); + LOAD_SYMBOL(SetFloat64); + LOAD_SYMBOL(SetInt8); + LOAD_SYMBOL(SetUInt8); + LOAD_SYMBOL(SetInt16); + LOAD_SYMBOL(SetUInt16); + LOAD_SYMBOL(SetInt32); + LOAD_SYMBOL(SetUInt32); + LOAD_SYMBOL(SetInt64); + LOAD_SYMBOL(SetUInt64); + LOAD_SYMBOL(SetBoolean); + LOAD_SYMBOL(SetString); + LOAD_SYMBOL(SetBinary); + LOAD_SYMBOL(SetClock); + + /* Getting Variable Dependency Information */ + LOAD_SYMBOL(GetNumberOfVariableDependencies); + LOAD_SYMBOL(GetVariableDependencies); + + /* Getting and setting the internal FMU state */ + LOAD_SYMBOL(GetFMUState); + LOAD_SYMBOL(SetFMUState); + LOAD_SYMBOL(FreeFMUState); + LOAD_SYMBOL(SerializedFMUStateSize); + LOAD_SYMBOL(SerializeFMUState); + LOAD_SYMBOL(DeserializeFMUState); + + /* Getting partial derivatives */ + LOAD_SYMBOL(GetDirectionalDerivative); + LOAD_SYMBOL(GetAdjointDerivative); + + /* Entering and exiting the Configuration or Reconfiguration Mode */ + LOAD_SYMBOL(EnterConfigurationMode); + LOAD_SYMBOL(ExitConfigurationMode); + + /* Clock related functions */ + LOAD_SYMBOL(GetIntervalDecimal); + LOAD_SYMBOL(GetIntervalFraction); + LOAD_SYMBOL(GetShiftDecimal); + LOAD_SYMBOL(GetShiftFraction); + LOAD_SYMBOL(SetIntervalDecimal); + LOAD_SYMBOL(SetIntervalFraction); + LOAD_SYMBOL(EvaluateDiscreteStates); + LOAD_SYMBOL(UpdateDiscreteStates); + + /*************************************************** + Functions for Model Exchange + ****************************************************/ + + LOAD_SYMBOL(EnterContinuousTimeMode); + LOAD_SYMBOL(CompletedIntegratorStep); + + /* Providing independent variables and re-initialization of caching */ + LOAD_SYMBOL(SetTime); + LOAD_SYMBOL(SetContinuousStates); + + /* Evaluation of the model equations */ + LOAD_SYMBOL(GetContinuousStateDerivatives); + LOAD_SYMBOL(GetEventIndicators); + LOAD_SYMBOL(GetContinuousStates); + LOAD_SYMBOL(GetNominalsOfContinuousStates); + LOAD_SYMBOL(GetNumberOfEventIndicators); + LOAD_SYMBOL(GetNumberOfContinuousStates); + + /*************************************************** + Functions for Co-Simulation + ****************************************************/ + + /* Simulating the FMU */ + LOAD_SYMBOL(EnterStepMode); + LOAD_SYMBOL(GetOutputDerivatives); + LOAD_SYMBOL(DoStep); + LOAD_SYMBOL(ActivateModelPartition); + + instance->state = FMI2StartAndEndState; + + return FMIOK; + +#else + + return FMIError; + +#endif +} + +/* Creation and destruction of FMU instances and setting debug status */ +FMIStatus FMI3InstantiateModelExchange( + FMIInstance *instance, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn) +{ + + FMIStatus status = loadSymbols3(instance); + + fmi3LogMessageCallback logMessage = instance->logMessage ? cb_logMessage3 : NULL; + + instance->component = instance->fmi3Functions->fmi3InstantiateModelExchange(instance->name, instantiationToken, resourcePath, visible, loggingOn, instance, logMessage); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, instance->component ? FMIOK : FMIError, + "fmi3InstantiateModelExchange(" + "instanceName=\"%s\", " + "instantiationToken=\"%s\", " + "resourcePath=\"%s\", " + "visible=%d, " + "loggingOn=%d, " + "instanceEnvironment=0x%p, " + "logMessage=0x%p)", + instance->name, + instantiationToken, + resourcePath, + visible, + loggingOn, + instance, + logMessage); + } + + if (!instance->component) { + return FMIError; + } + + instance->interfaceType = FMIModelExchange; + instance->state = FMI2InstantiatedState; + + return status; +} + +FMIStatus FMI3InstantiateCoSimulation( + FMIInstance * instance, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3Boolean eventModeUsed, + fmi3Boolean earlyReturnAllowed, + const fmi3ValueReference requiredIntermediateVariables[], + size_t nRequiredIntermediateVariables, + fmi3IntermediateUpdateCallback intermediateUpdate) +{ + + if (loadSymbols3(instance) != FMIOK) { + return FMIFatal; + } + + fmi3LogMessageCallback logMessage = instance->logMessage ? cb_logMessage3 : NULL; + + instance->component = instance->fmi3Functions->fmi3InstantiateCoSimulation( + instance->name, + instantiationToken, + resourcePath, + visible, + loggingOn, + eventModeUsed, + earlyReturnAllowed, + requiredIntermediateVariables, + nRequiredIntermediateVariables, + instance, + logMessage, + intermediateUpdate); + + instance->fmi3Functions->eventModeUsed = eventModeUsed; + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, instance->component ? FMIOK : FMIError, + "fmi3InstantiateCoSimulation(" + "instanceName=\"%s\", " + "instantiationToken=\"%s\", " + "resourcePath=\"%s\", " + "visible=%d, " + "loggingOn=%d, " + "eventModeUsed=%d, " + "earlyReturnAllowed=%d, " + "requiredIntermediateVariables=0x%p, " + "nRequiredIntermediateVariables=%zu, " + "instanceEnvironment=0x%p, " + "logMessage=0x%p, " + "intermediateUpdate=0x%p)", + instance->name, + instantiationToken, + resourcePath, + visible, + loggingOn, + eventModeUsed, + earlyReturnAllowed, + requiredIntermediateVariables, + nRequiredIntermediateVariables, + instance, + logMessage, + intermediateUpdate); + } + + if (!instance->component) { + return FMIError; + } + + instance->interfaceType = FMICoSimulation; + instance->state = FMI2InstantiatedState; + + return FMIOK; +} + +FMIStatus FMI3InstantiateScheduledExecution( + FMIInstance * instance, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage, + fmi3ClockUpdateCallback clockUpdate, + fmi3LockPreemptionCallback lockPreemption, + fmi3UnlockPreemptionCallback unlockPreemption) +{ + + if (loadSymbols3(instance) != FMIOK) { + return FMIError; + } + + fmi3LogMessageCallback _logMessage = instance->logMessage ? cb_logMessage3 : NULL; + + instance->component = instance->fmi3Functions->fmi3InstantiateScheduledExecution( + instance->name, + instantiationToken, + resourcePath, + visible, + loggingOn, + instance, + _logMessage, + clockUpdate, + lockPreemption, + unlockPreemption); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, instance->component ? FMIOK : FMIError, + "fmi3InstantiateScheduledExecution(" + "instanceName=\"%s\", " + "instantiationToken=\"%s\", " + "resourcePath=\"%s\", " + "visible=%d, " + "loggingOn=%d, " + "instanceEnvironment=0x%p, " + "logMessage=0x%p, " + "clockUpdate=0x%p, " + "lockPreemption=0x%p, " + "unlockPreemption=0x%p)", + instance->name, + instantiationToken, + resourcePath, + visible, + loggingOn, + instance, + _logMessage, + clockUpdate, + lockPreemption, + unlockPreemption); + } + + if (!instance->component) { + return FMIError; + } + + instance->interfaceType = FMIScheduledExecution; + instance->state = FMI2InstantiatedState; + + return FMIOK; +} + +FMIStatus FMI3FreeInstance(FMIInstance *instance) +{ + + if (!instance) { + return FMIError; + } + + instance->fmi3Functions->fmi3FreeInstance(instance->component); + + instance->component = NULL; + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, FMIOK, "fmi3FreeInstance()"); + } + + return FMIOK; +} + +/* Enter and exit initialization mode, enter event mode, terminate and reset */ +FMIStatus FMI3EnterInitializationMode(FMIInstance *instance, + fmi3Boolean toleranceDefined, + fmi3Float64 tolerance, + fmi3Float64 startTime, + fmi3Boolean stopTimeDefined, + fmi3Float64 stopTime) +{ + + instance->state = FMI2InitializationModeState; + + CALL_ARGS(EnterInitializationMode, + "fmi3EnterInitializationMode(toleranceDefined=%d, tolerance=%.16g, startTime=%.16g, stopTimeDefined=%d, stopTime=%.16g)", + toleranceDefined, tolerance, startTime, stopTimeDefined, stopTime); +} + +FMIStatus FMI3ExitInitializationMode(FMIInstance *instance) +{ + + if (instance->interfaceType == FMIModelExchange || (instance->fmiVersion == FMIVersion3 && instance->interfaceType == FMICoSimulation && instance->fmi3Functions->eventModeUsed)) { + instance->state = FMI2EventModeState; + } else { + instance->state = FMI2StepCompleteState; + } + + CALL(ExitInitializationMode); +} + +FMIStatus FMI3EnterEventMode(FMIInstance *instance) +{ + instance->state = FMI2EventModeState; + CALL(EnterEventMode); +} + +FMIStatus FMI3Terminate(FMIInstance *instance) +{ + instance->state = FMI2TerminatedState; + CALL(Terminate); +} + +FMIStatus FMI3Reset(FMIInstance *instance) +{ + instance->state = FMI2InstantiatedState; + CALL(Reset); +} + +/* Getting and setting variable values */ +FMIStatus FMI3GetFloat32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float32 values[], + size_t nValues) +{ + CALL_ARRAY(Get, Float32); +} + +FMIStatus FMI3GetFloat64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 values[], + size_t nValues) +{ + CALL_ARRAY(Get, Float64); +} + +FMIStatus FMI3GetInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int8 values[], + size_t nValues) +{ + CALL_ARRAY(Get, Int8); +} + +FMIStatus FMI3GetUInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt8 values[], + size_t nValues) +{ + CALL_ARRAY(Get, UInt8); +} + +FMIStatus FMI3GetInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int16 values[], + size_t nValues) +{ + CALL_ARRAY(Get, Int16); +} + +FMIStatus FMI3GetUInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt16 values[], + size_t nValues) +{ + CALL_ARRAY(Get, UInt16); +} + +FMIStatus FMI3GetInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int32 values[], + size_t nValues) +{ + CALL_ARRAY(Get, Int32); +} + +FMIStatus FMI3GetUInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt32 values[], + size_t nValues) +{ + CALL_ARRAY(Get, UInt32); +} + +FMIStatus FMI3GetInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int64 values[], + size_t nValues) +{ + CALL_ARRAY(Get, Int64); +} + +FMIStatus FMI3GetUInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 values[], + size_t nValues) +{ + CALL_ARRAY(Get, UInt64); +} + +FMIStatus FMI3GetBoolean(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Boolean values[], + size_t nValues) +{ + CALL_ARRAY(Get, Boolean); +} + +FMIStatus FMI3GetString(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3String values[], + size_t nValues) +{ + CALL_ARRAY(Get, String); +} + +FMIStatus FMI3GetBinary(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + size_t sizes[], + fmi3Binary values[], + size_t nValues) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3GetBinary(instance->component, valueReferences, nValueReferences, sizes, values, nValues); + + if (instance->logFunctionCall) { + FMIValueReferencesToString(instance, valueReferences, nValueReferences); + FMIValuesToString(instance, nValues, sizes, values, FMIBinaryType); + instance->logFunctionCall(instance, status, "fmi3GetBinary(valueReferences=%s, nValueReferences=%zu, sizes=%p, values=%s, nValues=%zu)", instance->buf1, nValueReferences, sizes, instance->buf2, nValues); + } + + return status; +} + +FMIStatus FMI3GetClock(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Clock values[]) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3GetClock(instance->component, valueReferences, nValueReferences, values); + + if (instance->logFunctionCall) { + FMIValueReferencesToString(instance, valueReferences, nValueReferences); + FMIValuesToString(instance, nValueReferences, NULL, values, FMIClockType); + instance->logFunctionCall(instance, status, "fmi3GetClock(valueReferences=%s, nValueReferences=%zu, values=%s)", instance->buf1, nValueReferences, instance->buf2); + } + + return status; +} + +FMIStatus FMI3SetFloat32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float32 values[], + size_t nValues) +{ + CALL_ARRAY(Set, Float32); +} + +FMIStatus FMI3SetFloat64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 values[], + size_t nValues) +{ + CALL_ARRAY(Set, Float64); +} + +FMIStatus FMI3SetInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int8 values[], + size_t nValues) +{ + CALL_ARRAY(Set, Int8); +} + +FMIStatus FMI3SetUInt8(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt8 values[], + size_t nValues) +{ + CALL_ARRAY(Set, UInt8); +} + +FMIStatus FMI3SetInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int16 values[], + size_t nValues) +{ + CALL_ARRAY(Set, Int16); +} + +FMIStatus FMI3SetUInt16(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt16 values[], + size_t nValues) +{ + CALL_ARRAY(Set, UInt16); +} + +FMIStatus FMI3SetInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 values[], + size_t nValues) +{ + CALL_ARRAY(Set, Int32); +} + +FMIStatus FMI3SetUInt32(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt32 values[], + size_t nValues) +{ + CALL_ARRAY(Set, UInt32); +} + +FMIStatus FMI3SetInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int64 values[], + size_t nValues) +{ + CALL_ARRAY(Set, Int64); +} + +FMIStatus FMI3SetUInt64(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 values[], + size_t nValues) +{ + CALL_ARRAY(Set, UInt64); +} + +FMIStatus FMI3SetBoolean(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Boolean values[], + size_t nValues) +{ + CALL_ARRAY(Set, Boolean); +} + +FMIStatus FMI3SetString(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3String values[], + size_t nValues) +{ + CALL_ARRAY(Set, String); +} + +FMIStatus FMI3SetBinary(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const size_t sizes[], + const fmi3Binary values[], + size_t nValues) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3SetBinary(instance->component, valueReferences, nValueReferences, sizes, values, nValues); + + if (instance->logFunctionCall) { + FMIValueReferencesToString(instance, valueReferences, nValueReferences); + FMIValuesToString(instance, nValues, sizes, values, FMIBinaryType); + instance->logFunctionCall(instance, status, "fmi3SetBinary(valueReferences=%s, nValueReferences=%zu, sizes=0x%p, values=%s, nValues=%zu", instance->buf1, nValueReferences, sizes, instance->buf2, nValues); + } + + return status; +} + +FMIStatus FMI3SetClock(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Clock values[]) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3SetClock(instance->component, valueReferences, nValueReferences, values); + + if (instance->logFunctionCall) { + FMIValueReferencesToString(instance, valueReferences, nValueReferences); + FMIValuesToString(instance, nValueReferences, NULL, values, FMIClockType); + instance->logFunctionCall(instance, status, "fmi3SetClock(valueReferences=%s, nValueReferences=%zu, values=%s)", instance->buf1, nValueReferences, instance->buf2); + } + + return status; +} + +/* Getting Variable Dependency Information */ +FMIStatus FMI3GetNumberOfVariableDependencies(FMIInstance * instance, + fmi3ValueReference valueReference, + size_t * nDependencies) +{ + CALL_ARGS(GetNumberOfVariableDependencies, "valueReference=%u, nDependencies=0x%p", valueReference, nDependencies); +} + +FMIStatus FMI3GetVariableDependencies(FMIInstance * instance, + fmi3ValueReference dependent, + size_t elementIndicesOfDependent[], + fmi3ValueReference independents[], + size_t elementIndicesOfIndependents[], + fmi3DependencyKind dependencyKinds[], + size_t nDependencies) +{ + CALL_ARGS(GetVariableDependencies, "dependent=%u, elementIndicesOfDependent=0x%p, independents=0x%p, elementIndicesOfIndependents=0x%p, dependencyKinds=0x%p, nDependencies=%zu", + dependent, elementIndicesOfDependent, independents, elementIndicesOfIndependents, dependencyKinds, nDependencies); +} + +/* Getting and setting the internal FMU state */ +FMIStatus FMI3GetFMUState(FMIInstance *instance, fmi3FMUState *FMUState) +{ + CALL_ARGS(GetFMUState, "FMUState=0x%p", FMUState); +} + +FMIStatus FMI3SetFMUState(FMIInstance *instance, fmi3FMUState FMUState) +{ + CALL_ARGS(SetFMUState, "FMUState=0x%p", FMUState); +} + +FMIStatus FMI3FreeFMUState(FMIInstance *instance, fmi3FMUState *FMUState) +{ + CALL_ARGS(FreeFMUState, "FMUState=0x%p", FMUState); +} + +FMIStatus FMI3SerializedFMUStateSize(FMIInstance *instance, + fmi3FMUState FMUState, + size_t * size) +{ + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3SerializedFMUStateSize(instance->component, FMUState, size); + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, "fmi3SerializedFMUStateSize(FMUState=0x%p, size=%zu)", FMUState, *size); + } + return status; +} + +FMIStatus FMI3SerializeFMUState(FMIInstance *instance, + fmi3FMUState FMUState, + fmi3Byte serializedState[], + size_t size) +{ + CALL_ARGS(SerializeFMUState, "FMUstate=0x%p, serializedState=0x%p, size=%zu", FMUState, serializedState, size); +} + +FMIStatus FMI3DeserializeFMUState(FMIInstance * instance, + const fmi3Byte serializedState[], + size_t size, + fmi3FMUState * FMUState) +{ + CALL_ARGS(DeserializeFMUState, "serializedState=0x%p, size=%zu, FMUState=0x%p", serializedState, size, FMUState); +} + +/* Getting partial derivatives */ +FMIStatus FMI3GetDirectionalDerivative(FMIInstance * instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity) +{ + CALL_ARGS(GetDirectionalDerivative, + "unknowns=0x%p, nUnknowns=%zu, knowns=0x%p, nKnowns=%zu, seed=0x%p, nSeed=%zu, sensitivity=0x%p, nSensitivity=%zu", + unknowns, nUnknowns, knowns, nKnowns, seed, nSeed, sensitivity, nSensitivity); +} + +FMIStatus FMI3GetAdjointDerivative(FMIInstance * instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity) +{ + CALL_ARGS(GetAdjointDerivative, + "unknowns=0x%p, nUnknowns=%zu, knowns=0x%p, nKnowns=%zu, seed=0x%p, nSeed=%zu, sensitivity=0x%p, nSensitivity=%zu", + unknowns, nUnknowns, knowns, nKnowns, seed, nSeed, sensitivity, nSensitivity); +} + +/* Entering and exiting the Configuration or Reconfiguration Mode */ +FMIStatus FMI3EnterConfigurationMode(FMIInstance *instance) +{ + CALL(EnterConfigurationMode); +} + +FMIStatus FMI3ExitConfigurationMode(FMIInstance *instance) +{ + CALL(ExitConfigurationMode); +} + +/* Clock related functions */ + +FMI_STATIC FMIStatus FMI3GetIntervalDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 intervals[], + fmi3IntervalQualifier qualifiers[]) +{ + CALL_ARGS(GetIntervalDecimal, + "valueReferences=0x%p, nValueReferences=%zu, intervals=0x%p, qualifiers=0x%p", + valueReferences, nValueReferences, intervals, qualifiers); +} + +FMIStatus FMI3GetIntervalFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 intervalCounters[], + fmi3UInt64 resolutions[], + fmi3IntervalQualifier qualifiers[]) +{ + CALL_ARGS(GetIntervalFraction, + "valueReferences=0x%p, nValueReferences=%zu, intervalCounters=0x%p, resolutions=0x%p, qualifiers=%d", + valueReferences, nValueReferences, intervalCounters, resolutions, qualifiers); +} + +FMIStatus FMI3GetShiftDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 shifts[]) +{ + CALL_ARGS(GetShiftDecimal, + "valueReferences=0x%p, nValueReferences=%zu, shifts=0x%p", + valueReferences, nValueReferences, shifts); +} + +FMIStatus FMI3GetShiftFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 shiftCounters[], + fmi3UInt64 resolutions[]) +{ + CALL_ARGS(GetShiftFraction, + "valueReferences=0x%p, nValueReferences=%zu, shiftCounters=0x%p, resolutions=0x%p", + valueReferences, nValueReferences, shiftCounters, resolutions); +} + +FMIStatus FMI3SetIntervalDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 intervals[]) +{ + CALL_ARGS(SetIntervalDecimal, + "valueReferences=0x%p, nValueReferences=%zu, intervals=0x%p", + valueReferences, nValueReferences, intervals); +} + +FMIStatus FMI3SetIntervalFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 intervalCounters[], + const fmi3UInt64 resolutions[]) +{ + CALL_ARGS(SetIntervalFraction, + "valueReferences=0x%p, nValueReferences=%zu, intervalCounters=0x%p, resolutions=0x%p", + valueReferences, nValueReferences, intervalCounters, resolutions); +} + +FMIStatus FMI3SetShiftDecimal(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 shifts[]) +{ + CALL_ARGS(SetShiftDecimal, + "valueReferences=0x%p, nValueReferences=%zu, shifts=0x%p", + valueReferences, nValueReferences, shifts); +} + +FMIStatus FMI3SetShiftFraction(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 shiftCounters[], + const fmi3UInt64 resolutions[]) +{ + CALL_ARGS(SetShiftFraction, + "valueReferences=0x%p, nValueReferences=%zu, shiftCounters=0x%p, resolutions=0x%p", + valueReferences, nValueReferences, shiftCounters, resolutions); +} + +FMIStatus FMI3EvaluateDiscreteStates(FMIInstance *instance) +{ + CALL(EvaluateDiscreteStates); +} + +FMIStatus FMI3UpdateDiscreteStates(FMIInstance *instance, + fmi3Boolean *discreteStatesNeedUpdate, + fmi3Boolean *terminateSimulation, + fmi3Boolean *nominalsOfContinuousStatesChanged, + fmi3Boolean *valuesOfContinuousStatesChanged, + fmi3Boolean *nextEventTimeDefined, + fmi3Float64 *nextEventTime) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3UpdateDiscreteStates(instance->component, discreteStatesNeedUpdate, terminateSimulation, nominalsOfContinuousStatesChanged, valuesOfContinuousStatesChanged, nextEventTimeDefined, nextEventTime); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi3UpdateDiscreteStates(discreteStatesNeedUpdate=%d, terminateSimulation=%d, nominalsOfContinuousStatesChanged=%d, valuesOfContinuousStatesChanged=%d, nextEventTimeDefined=%d, nextEventTime=%.16g)", + *discreteStatesNeedUpdate, *terminateSimulation, *nominalsOfContinuousStatesChanged, *valuesOfContinuousStatesChanged, *nextEventTimeDefined, *nextEventTime); + } + + return status; +} + +/*************************************************** +Types for Functions for Model Exchange +****************************************************/ + +FMIStatus FMI3EnterContinuousTimeMode(FMIInstance *instance) +{ + instance->state = FMI2ContinuousTimeModeState; + CALL(EnterContinuousTimeMode); +} + +FMIStatus FMI3CompletedIntegratorStep(FMIInstance *instance, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *enterEventMode, + fmi3Boolean *terminateSimulation) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3CompletedIntegratorStep(instance->component, noSetFMUStatePriorToCurrentPoint, enterEventMode, terminateSimulation); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi3CompletedIntegratorStep(noSetFMUStatePriorToCurrentPoint=%d, enterEventMode=%d, terminateSimulation=%d)", + noSetFMUStatePriorToCurrentPoint, *enterEventMode, *terminateSimulation); + } + + return status; +} + +/* Providing independent variables and re-initialization of caching */ +FMIStatus FMI3SetTime(FMIInstance *instance, fmi3Float64 time) +{ + instance->time = time; + CALL_ARGS(SetTime, "time=%.16g", time); +} + +FMIStatus FMI3SetContinuousStates(FMIInstance * instance, + const fmi3Float64 continuousStates[], + size_t nContinuousStates) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3SetContinuousStates(instance->component, continuousStates, nContinuousStates); + + if (instance->logFunctionCall) { + FMIValuesToString(instance, nContinuousStates, NULL, continuousStates, FMIFloat64Type); + instance->logFunctionCall(instance, status, + "fmi3SetContinuousStates(continuousStates=%s, nContinuousStates=%zu)", + instance->buf2, nContinuousStates); + } + + return status; +} + +/* Evaluation of the model equations */ +FMIStatus FMI3GetContinuousStateDerivatives(FMIInstance *instance, + fmi3Float64 derivatives[], + size_t nContinuousStates) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3GetContinuousStateDerivatives(instance->component, derivatives, nContinuousStates); + + if (instance->logFunctionCall) { + FMIValuesToString(instance, nContinuousStates, NULL, derivatives, FMIFloat64Type); + instance->logFunctionCall(instance, status, + "fmi3GetDerivatives(derivatives=%s, nContinuousStates=%zu)", + instance->buf2, nContinuousStates); + } + + return status; +} + +FMIStatus FMI3GetEventIndicators(FMIInstance *instance, + fmi3Float64 eventIndicators[], + size_t nEventIndicators) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3GetEventIndicators(instance->component, eventIndicators, nEventIndicators); + + if (instance->logFunctionCall) { + FMIValuesToString(instance, nEventIndicators, NULL, eventIndicators, FMIFloat64Type); + instance->logFunctionCall(instance, status, + "fmi3GetEventIndicators(eventIndicators=%s, nEventIndicators=%zu)", + instance->buf2, nEventIndicators); + } + + return status; +} + +FMIStatus FMI3GetContinuousStates(FMIInstance *instance, + fmi3Float64 continuousStates[], + size_t nContinuousStates) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3GetContinuousStates(instance->component, continuousStates, nContinuousStates); + + if (instance->logFunctionCall) { + FMIValuesToString(instance, nContinuousStates, NULL, continuousStates, FMIFloat64Type); + instance->logFunctionCall(instance, status, + "fmi3GetContinuousStates(continuousStates=%s, nContinuousStates=%zu)", + instance->buf2, nContinuousStates); + } + + return status; +} + +FMIStatus FMI3GetNominalsOfContinuousStates(FMIInstance *instance, + fmi3Float64 nominals[], + size_t nContinuousStates) +{ + CALL_ARGS(GetNominalsOfContinuousStates, "nominals=0x%p, nContinuousStates=%zu", nominals, nContinuousStates); +} + +FMIStatus FMI3GetNumberOfEventIndicators(FMIInstance *instance, + size_t * nEventIndicators) +{ + CALL_ARGS(GetNumberOfEventIndicators, "nEventIndicators=0x%p", nEventIndicators); +} + +FMIStatus FMI3GetNumberOfContinuousStates(FMIInstance *instance, + size_t * nContinuousStates) +{ + CALL_ARGS(GetNumberOfContinuousStates, "nContinuousStates=0x%p", nContinuousStates); +} + +/*************************************************** +Types for Functions for Co-Simulation +****************************************************/ + +/* Simulating the FMU */ + +FMIStatus FMI3EnterStepMode(FMIInstance *instance) +{ + CALL(EnterStepMode); +} + +FMIStatus FMI3GetOutputDerivatives(FMIInstance * instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 orders[], + fmi3Float64 values[], + size_t nValues) +{ + CALL_ARGS(GetOutputDerivatives, + "valueReferences=0x%p, nValueReferences=%zu, orders=0x%p, values=0x%p, nValues=%zu", + valueReferences, nValueReferences, orders, values, nValues); +} + +FMIStatus FMI3DoStep(FMIInstance *instance, + fmi3Float64 currentCommunicationPoint, + fmi3Float64 communicationStepSize, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *eventEncountered, + fmi3Boolean *terminate, + fmi3Boolean *earlyReturn, + fmi3Float64 *lastSuccessfulTime) +{ + + FMIStatus status = (FMIStatus) instance->fmi3Functions->fmi3DoStep(instance->component, currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint, eventEncountered, terminate, earlyReturn, lastSuccessfulTime); + + if (instance->logFunctionCall) { + instance->logFunctionCall(instance, status, + "fmi3DoStep(currentCommunicationPoint=%.16g, communicationStepSize=%.16g, noSetFMUStatePriorToCurrentPoint=%d, eventEncountered=%d, terminate=%d, earlyReturn=%d, lastSuccessfulTime=%.16g)", + currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint, *eventEncountered, *terminate, *earlyReturn, *lastSuccessfulTime); + } + + instance->time = *lastSuccessfulTime; + + return status; +} + +FMIStatus FMI3ActivateModelPartition(FMIInstance * instance, + fmi3ValueReference clockReference, + fmi3Float64 activationTime) +{ + CALL_ARGS(ActivateModelPartition, + "clockReference=%u, activationTime=%.16g", + clockReference, activationTime); +} + +#undef LOAD_SYMBOL +#undef CALL +#undef CALL_ARGS +#undef CALL_ARRAY diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/cosimulation.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/cosimulation.c new file mode 100644 index 000000000..860d06321 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/cosimulation.c @@ -0,0 +1,656 @@ +#include "cosimulation.h" +#include // for DBL_EPSILON +#include // for fabs() +#include +#include +#include // for calloc(), free() +#include +#include "config.h" + +#if FMI_VERSION == 3 +#include "fmi3Functions.h" +#endif + +#ifdef _MSC_VER +#define strdup _strdup +#endif + +ModelInstance *createModelInstance( + loggerType cbLogger, + intermediateUpdateType intermediateUpdate, + void * componentEnvironment, + const char * instanceName, + const char * instantiationToken, + const char * resourceLocation, + bool loggingOn, + InterfaceType interfaceType) +{ + + ModelInstance *comp = NULL; + + if (!instanceName || strlen(instanceName) == 0) { + if (cbLogger) { +#if FMI_VERSION < 3 + cbLogger(componentEnvironment, "?", Error, "error", "Missing instance name."); +#else + cbLogger(componentEnvironment, Error, "error", "Missing instance name."); +#endif + } + return NULL; + } + + if (!instantiationToken || strlen(instantiationToken) == 0) { + if (cbLogger) { +#if FMI_VERSION < 3 + cbLogger(componentEnvironment, instanceName, Error, "error", "Missing GUID."); +#else + cbLogger(componentEnvironment, Error, "error", "Missing instantiationToken."); +#endif + } + return NULL; + } + + if (strcmp(instantiationToken, INSTANTIATION_TOKEN)) { + if (cbLogger) { +#if FMI_VERSION < 3 + cbLogger(componentEnvironment, instanceName, Error, "error", "Wrong GUID."); +#else + cbLogger(componentEnvironment, Error, "error", "Wrong instantiationToken."); +#endif + } + return NULL; + } + + comp = (ModelInstance *) calloc(1, sizeof(ModelInstance)); + + if (comp) { + comp->componentEnvironment = componentEnvironment; + comp->logger = cbLogger; + comp->intermediateUpdate = intermediateUpdate; + comp->lockPreemtion = NULL; + comp->unlockPreemtion = NULL; + comp->instanceName = strdup(instanceName); + comp->resourceLocation = resourceLocation ? strdup(resourceLocation) : NULL; + comp->status = OK; + comp->logEvents = loggingOn; + comp->logErrors = true; // always log errors + comp->nSteps = 0; + comp->solverStepSize = 1e-3; + comp->earlyReturnAllowed = false; + comp->eventModeUsed = false; + } + + if (!comp || !comp->instanceName) { + logError(comp, "Out of memory."); + return NULL; + } + + comp->time = 0.0; // overwrite in fmi*SetupExperiment, fmi*SetTime + comp->type = interfaceType; + + comp->state = Instantiated; + + comp->newDiscreteStatesNeeded = false; + comp->terminateSimulation = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->valuesOfContinuousStatesChanged = false; + comp->nextEventTimeDefined = false; + comp->nextEventTime = 0; + + setStartValues(comp); + + comp->isDirtyValues = true; + + return comp; +} + +void freeModelInstance(ModelInstance *comp) +{ + free((void *) comp->instanceName); + free(comp); +} + +void reset(ModelInstance *comp) +{ + comp->state = Instantiated; + comp->startTime = 0.0; + comp->time = 0.0; + comp->nSteps = 0; + comp->solverStepSize = 1e-3; + comp->status = OK; + setStartValues(comp); + comp->isDirtyValues = true; +} + +bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, size_t actual, size_t expected) +{ + + if (actual != expected) { + comp->state = modelError; + logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, actual, expected); + return true; + } + + return false; +} + +bool invalidState(ModelInstance *comp, const char *f, int statesExpected) +{ + + UNUSED(f); + UNUSED(statesExpected); + + if (!comp) { + return true; + } + + // TODO: add missing states and check state + return false; + + // if (!(comp->state & statesExpected)) { + // comp->state = modelError; + // logError(comp, "%s: Illegal call sequence.", f); + // return true; + // } + // + // return false; +} + +bool nullPointer(ModelInstance *comp, const char *f, const char *arg, const void *p) +{ + + if (!p) { + comp->state = modelError; + logError(comp, "%s: Invalid argument %s = NULL.", f, arg); + return true; + } + + return false; +} + +Status setDebugLogging(ModelInstance *comp, bool loggingOn, size_t nCategories, const char *const categories[]) +{ + + if (loggingOn) { + for (size_t i = 0; i < nCategories; i++) { + if (categories[i] == NULL) { + logError(comp, "Log category[%d] must not be NULL", i); + return Error; + } else if (strcmp(categories[i], "logEvents") == 0) { + comp->logEvents = true; + } else if (strcmp(categories[i], "logStatusError") == 0) { + comp->logErrors = true; + } else { + logError(comp, "Log category[%d] must be one of logEvents or logStatusError but was %s", i, categories[i]); + return Error; + } + } + } else { + // disable logging + comp->logEvents = false; + comp->logErrors = false; + } + + return OK; +} + +static void logMessage(ModelInstance *comp, int status, const char *category, const char *message, va_list args) +{ + + if (!comp->logger) { + return; + } + + va_list args1; + size_t len = 0; + char * buf = ""; + + va_copy(args1, args); + len = vsnprintf(buf, len, message, args1); + va_end(args1); + + va_copy(args1, args); + buf = (char *) calloc(len + 1, sizeof(char)); + vsnprintf(buf, len + 1, message, args); + va_end(args1); + + // no need to distinguish between FMI versions since we're not using variadic arguments +#if FMI_VERSION < 3 + comp->logger(comp->componentEnvironment, comp->instanceName, status, category, buf); +#else + comp->logger(comp->componentEnvironment, status, category, buf); +#endif + + free(buf); +} + +void logEvent(ModelInstance *comp, const char *message, ...) +{ + + if (!comp || !comp->logEvents) + return; + + va_list args; + va_start(args, message); + logMessage(comp, OK, "logEvents", message, args); + va_end(args); +} + +void logError(ModelInstance *comp, const char *message, ...) +{ + + if (!comp || !comp->logErrors) + return; + + va_list args; + va_start(args, message); + logMessage(comp, Error, "logStatusError", message, args); + va_end(args); +} + +// default implementations +#if NZ < 1 +void getEventIndicators(ModelInstance *comp, double z[], size_t nz) +{ + UNUSED(comp); + UNUSED(z); + UNUSED(nz); + // do nothing +} +#endif + +#define GET_NOT_ALLOWED(t) \ + do { \ + UNUSED(vr); \ + UNUSED(value); \ + UNUSED(index); \ + logError(comp, "Getting " t " is not allowed."); \ + return Error; \ + } while (false) + +#ifndef GET_FLOAT32 +Status getFloat32(ModelInstance *comp, ValueReference vr, float value[], size_t *index) +{ + GET_NOT_ALLOWED("Float32"); +} +#endif + +#ifndef GET_INT8 +Status getInt8(ModelInstance *comp, ValueReference vr, int8_t value[], size_t *index) +{ + GET_NOT_ALLOWED("Int8"); +} +#endif + +#ifndef GET_UINT8 +Status getUInt8(ModelInstance *comp, ValueReference vr, uint8_t value[], size_t *index) +{ + GET_NOT_ALLOWED("UInt8"); +} +#endif + +#ifndef GET_INT16 +Status getInt16(ModelInstance *comp, ValueReference vr, int16_t value[], size_t *index) +{ + GET_NOT_ALLOWED("Int16"); +} +#endif + +#ifndef GET_UINT16 +Status getUInt16(ModelInstance *comp, ValueReference vr, uint16_t value[], size_t *index) +{ + GET_NOT_ALLOWED("UInt16"); +} +#endif + +#ifndef GET_INT32 +Status getInt32(ModelInstance *comp, ValueReference vr, int32_t value[], size_t *index) +{ + GET_NOT_ALLOWED("Int32"); +} +#endif + +#ifndef GET_UINT32 +Status getUInt32(ModelInstance *comp, ValueReference vr, uint32_t value[], size_t *index) +{ + GET_NOT_ALLOWED("UInt32"); +} +#endif + +#ifndef GET_INT64 +Status getInt64(ModelInstance *comp, ValueReference vr, int64_t value[], size_t *index) +{ + GET_NOT_ALLOWED("Int64"); +} +#endif + +#ifndef GET_UINT64 +Status getUInt64(ModelInstance *comp, ValueReference vr, uint64_t value[], size_t *index) +{ + GET_NOT_ALLOWED("UInt64"); +} +#endif + +#ifndef GET_BOOLEAN +Status getBoolean(ModelInstance *comp, ValueReference vr, bool value[], size_t *index) +{ + GET_NOT_ALLOWED("Boolean"); +} +#endif + +#ifndef GET_STRING +Status getString(ModelInstance *comp, ValueReference vr, const char *value[], size_t *index) +{ + GET_NOT_ALLOWED("String"); +} +#endif + +#ifndef GET_BINARY +Status getBinary(ModelInstance *comp, ValueReference vr, size_t size[], const char *value[], size_t *index) +{ + UNUSED(size); + GET_NOT_ALLOWED("Binary"); +} +#endif + +#define SET_NOT_ALLOWED(t) \ + do { \ + UNUSED(vr); \ + UNUSED(value); \ + UNUSED(index); \ + logError(comp, "Setting " t " is not allowed."); \ + return Error; \ + } while (false) + +#ifndef SET_FLOAT32 +Status setFloat32(ModelInstance *comp, ValueReference vr, const float value[], size_t *index) +{ + SET_NOT_ALLOWED("Float32"); +} +#endif + +#ifndef SET_FLOAT64 +Status setFloat64(ModelInstance *comp, ValueReference vr, const double value[], size_t *index) +{ + SET_NOT_ALLOWED("Float64"); +} +#endif + +#ifndef SET_INT8 +Status setInt8(ModelInstance *comp, ValueReference vr, const int8_t value[], size_t *index) +{ + SET_NOT_ALLOWED("Int8"); +} +#endif + +#ifndef SET_UINT8 +Status setUInt8(ModelInstance *comp, ValueReference vr, const uint8_t value[], size_t *index) +{ + SET_NOT_ALLOWED("UInt8"); +} +#endif + +#ifndef SET_INT16 +Status setInt16(ModelInstance *comp, ValueReference vr, const int16_t value[], size_t *index) +{ + SET_NOT_ALLOWED("Int16"); +} +#endif + +#ifndef SET_UINT16 +Status setUInt16(ModelInstance *comp, ValueReference vr, const uint16_t value[], size_t *index) +{ + SET_NOT_ALLOWED("UInt16"); +} +#endif + +#ifndef SET_INT32 +Status setInt32(ModelInstance *comp, ValueReference vr, const int32_t value[], size_t *index) +{ + SET_NOT_ALLOWED("Int32"); +} +#endif + +#ifndef SET_UINT32 +Status setUInt32(ModelInstance *comp, ValueReference vr, const uint32_t value[], size_t *index) +{ + SET_NOT_ALLOWED("UInt32"); +} +#endif + +#ifndef SET_INT64 +Status setInt64(ModelInstance *comp, ValueReference vr, const int64_t value[], size_t *index) +{ + SET_NOT_ALLOWED("Int64"); +} +#endif + +#ifndef SET_UINT64 +Status setUInt64(ModelInstance *comp, ValueReference vr, const uint64_t value[], size_t *index) +{ + SET_NOT_ALLOWED("UInt64"); +} +#endif + +#ifndef SET_BOOLEAN +Status setBoolean(ModelInstance *comp, ValueReference vr, const bool value[], size_t *index) +{ + SET_NOT_ALLOWED("Boolean"); +} +#endif + +#ifndef SET_STRING +Status setString(ModelInstance *comp, ValueReference vr, const char *const value[], size_t *index) +{ + SET_NOT_ALLOWED("String"); +} +#endif + +#ifndef SET_BINARY +Status setBinary(ModelInstance *comp, ValueReference vr, const size_t size[], const char *const value[], size_t *index) +{ + UNUSED(size); + SET_NOT_ALLOWED("Binary"); +} +#endif + +#ifndef ACTIVATE_CLOCK +Status activateClock(ModelInstance *comp, ValueReference vr) +{ + UNUSED(comp); + UNUSED(vr); + return Error; +} +#endif + +#ifndef GET_CLOCK +Status getClock(ModelInstance *comp, ValueReference vr, bool *value) +{ + UNUSED(comp); + UNUSED(vr); + UNUSED(value); + return Error; +} +#endif + +#ifndef GET_INTERVAL +Status getInterval(ModelInstance *comp, ValueReference vr, double *interval, int *qualifier) +{ + UNUSED(comp); + UNUSED(vr); + UNUSED(interval); + UNUSED(qualifier); + return Error; +} +#endif + +#ifndef ACTIVATE_MODEL_PARTITION +Status activateModelPartition(ModelInstance *comp, ValueReference vr, double activationTime) +{ + UNUSED(comp); + UNUSED(vr); + UNUSED(activationTime); + return Error; +} +#endif + +#if NX < 1 +void getContinuousStates(ModelInstance *comp, double x[], size_t nx) +{ + UNUSED(comp); + UNUSED(x); + UNUSED(nx); +} + +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) +{ + UNUSED(comp); + UNUSED(x); + UNUSED(nx); +} + +void getDerivatives(ModelInstance *comp, double dx[], size_t nx) +{ + UNUSED(comp); + UNUSED(dx); + UNUSED(nx); +} +#endif + +#ifndef GET_PARTIAL_DERIVATIVE +Status getPartialDerivative(ModelInstance *comp, ValueReference unknown, ValueReference known, double *partialDerivative) +{ + UNUSED(comp); + UNUSED(unknown); + UNUSED(known); + UNUSED(partialDerivative); + return Error; +} +#endif + +void *getFMUState(ModelInstance *comp) +{ + + ModelInstance *fmuState = (ModelInstance *) calloc(1, sizeof(ModelInstance)); + + memcpy(fmuState, comp, sizeof(ModelInstance)); + + return fmuState; +} + +void setFMUState(ModelInstance *comp, void *FMUState) +{ + + ModelInstance *s = (ModelInstance *) FMUState; + + comp->startTime = s->startTime; + comp->time = s->time; + comp->solverStepSize = s->solverStepSize; + comp->status = s->status; + comp->state = s->state; + comp->newDiscreteStatesNeeded = s->newDiscreteStatesNeeded; + comp->terminateSimulation = s->terminateSimulation; + comp->nominalsOfContinuousStatesChanged = s->nominalsOfContinuousStatesChanged; + comp->valuesOfContinuousStatesChanged = s->valuesOfContinuousStatesChanged; + comp->nextEventTimeDefined = s->nextEventTimeDefined; + comp->nextEventTime = s->nextEventTime; + comp->clocksTicked = s->clocksTicked; + comp->isDirtyValues = s->isDirtyValues; + comp->modelData = s->modelData; +#if NZ > 0 + memcpy(comp->z, s->z, NZ * sizeof(double)); +#endif + comp->nSteps = s->nSteps; +} + +void doFixedStep(ModelInstance *comp, bool *stateEvent, bool *timeEvent) +{ + + // not implemented + UNUSED(comp); + UNUSED(stateEvent); + UNUSED(timeEvent); +} + +void doAdaptiveStep(ModelInstance *comp, bool *stateEvent, bool *timeEvent) +{ + + // create local variables + double t = comp->time; + double dt = comp->solverStepSize; + + // compute control output according to flags "compute_u_1" and "use_implicit_method" + + if (M(compute_u_1)) { + + // compute error + M(e) = M(r) - M(y_1); + + // calculate u_1 + if (M(use_implicit_method)) { + // implicit trapezoid + M(P) = M(kp) * M(e); + M(I) = M(ki) * (M(I) + (M(e) + M(e_ls)) * dt / 2); + M(D) = M(kd) * (M(e) - M(e_ls)) / dt; + + } else { + // explicit euler + M(P) = M(kp) * M(e); + M(I) = M(ki) * (M(I) + M(e) * dt); + M(D) = M(kd) * (M(e) - M(e_ls)) / dt; + } + + // limit I to avoid integrator windup + if (M(I) > M(I_max)) { + M(I) = M(I_max); + } + + // compute u_1 + M(u_1) = M(P) + M(I) + M(D); + + // set u_2 to default value + M(u_2) = 0; + } + + else { + + // compute error + M(e) = M(r) - M(y_2); + + // calculate u_2 + if (M(use_implicit_method)) { + // implicit trapezoid + M(P) = M(kp) * M(e); + M(I) = M(ki) * (M(I) + (M(e) + M(e_ls)) * dt / 2); + M(D) = M(kd) * (M(e) - M(e_ls)) / dt; + + } else { + // explicit euler + M(P) = M(kp) * M(e); + M(I) = M(ki) * (M(I) + M(e) * dt); + M(D) = M(kd) * (M(e) - M(e_ls)) / dt; + } + + // limit I to avoid integrator windup + if (M(I) > M(I_max)) { + M(I) = M(I_max); + } + + // compute u_2 + M(u_2) = M(P) + M(I) + M(D); + + // set u_1 to default value + M(u_1) = 0; + } + + // save error for next timestep + M(e_ls) = M(e); + + // advance nSteps and time + comp->nSteps++; + comp->time = t + dt; + + // state event + *stateEvent = false; + UNUSED(timeEvent); +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi1Functions.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi1Functions.c new file mode 100644 index 000000000..a1d8b3314 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi1Functions.c @@ -0,0 +1,638 @@ +#if FMI_VERSION != 1 +#error FMI_VERSION must be 1 +#endif + +#include +#include +#include +#include + +#include "config.h" +#include "cosimulation.h" +#include "model.h" + +#ifdef FMI_COSIMULATION +#include "fmiFunctions.h" +#else +#include "fmiModelFunctions.h" +#endif + +#define ASSERT_NOT_NULL(p) \ + do { \ + if (!p) { \ + logError(S, "Argument %s must not be NULL.", xstr(p)); \ + S->state = modelError; \ + return (fmiStatus) Error; \ + } \ + } while (0) + +#define GET_VARIABLES(T) \ + do { \ + ASSERT_NOT_NULL(vr); \ + ASSERT_NOT_NULL(value); \ + size_t index = 0; \ + Status status = OK; \ + if (nvr == 0) \ + return (fmiStatus) status; \ + if (S->isDirtyValues) { \ + Status s = calculateValues(S); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmiStatus) status; \ + S->isDirtyValues = false; \ + } \ + for (size_t i = 0; i < nvr; i++) { \ + Status s = get##T(S, vr[i], value, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmiStatus) status; \ + } \ + return (fmiStatus) status; \ + } while (0) + +#define SET_VARIABLES(T) \ + do { \ + ASSERT_NOT_NULL(vr); \ + ASSERT_NOT_NULL(value); \ + size_t index = 0; \ + Status status = OK; \ + for (size_t i = 0; i < nvr; i++) { \ + Status s = set##T(S, vr[i], value, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmiStatus) status; \ + } \ + if (nvr > 0) \ + S->isDirtyValues = true; \ + return (fmiStatus) status; \ + } while (0) + +#define GET_BOOLEAN_VARIABLES \ + do { \ + Status status = OK; \ + for (size_t i = 0; i < nvr; i++) { \ + bool v = false; \ + size_t index = 0; \ + Status s = getBoolean(S, vr[i], &v, &index); \ + value[i] = v; \ + status = max(status, s); \ + if (status > Warning) \ + return (fmiStatus) status; \ + } \ + return (fmiStatus) status; \ + } while (0) + +#define SET_BOOLEAN_VARIABLES \ + do { \ + Status status = OK; \ + for (size_t i = 0; i < nvr; i++) { \ + bool v = value[i]; \ + size_t index = 0; \ + Status s = setBoolean(S, vr[i], &v, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmiStatus) status; \ + } \ + return (fmiStatus) status; \ + } while (0) + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef DT_EVENT_DETECT +#define DT_EVENT_DETECT 1e-10 +#endif + +#define ASSERT_STATE(F, A) \ + if (!c) \ + return fmiError; \ + ModelInstance *S = (ModelInstance *) c; \ + if (invalidState(S, F, not_modelError)) \ + return fmiError; + +// --------------------------------------------------------------------------- +// Private helpers used below to implement functions +// --------------------------------------------------------------------------- + +// fname is fmiInitialize or fmiInitializeSlave +static fmiStatus init(fmiComponent c) +{ + ModelInstance *instance = (ModelInstance *) c; + instance->state = Initialized; + calculateValues(instance); + return fmiOK; +} + +// fname is fmiTerminate or fmiTerminateSlave +static fmiStatus terminate(char *fname, fmiComponent c) +{ + ModelInstance *instance = (ModelInstance *) c; + if (invalidState(instance, fname, Initialized)) + return fmiError; + instance->state = Terminated; + return fmiOK; +} + +// --------------------------------------------------------------------------- +// FMI functions: class methods not depending of a specific model instance +// --------------------------------------------------------------------------- + +const char *fmiGetVersion() +{ + return fmiVersion; +} + +// --------------------------------------------------------------------------- +// FMI functions: for FMI Model Exchange 1.0 and for FMI Co-Simulation 1.0 +// logging control, setters and getters for Real, Integer, Boolean, String +// --------------------------------------------------------------------------- + +fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn) +{ + ASSERT_STATE("fmiSetDebugLogging", not_modelError); + return (fmiStatus) setDebugLogging(S, loggingOn, 0, NULL); +} + +fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) +{ + ASSERT_STATE("fmiSetReal", Instantiated | Initialized); + SET_VARIABLES(Float64); +} + +fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]) +{ + ASSERT_STATE("fmiSetInteger", Instantiated | Initialized); + SET_VARIABLES(Int32); +} + +fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]) +{ + ASSERT_STATE("fmiSetBoolean", Instantiated | Initialized); + SET_BOOLEAN_VARIABLES; +} + +fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]) +{ + ASSERT_STATE("fmiSetString", not_modelError); + SET_VARIABLES(String); +} + +fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]) +{ + ASSERT_STATE("fmiGetReal", not_modelError); + GET_VARIABLES(Float64); +} + +fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]) +{ + ASSERT_STATE("fmiGetInteger", not_modelError); + GET_VARIABLES(Int32); +} + +fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) +{ + ASSERT_STATE("fmiGetBoolean", not_modelError); + GET_BOOLEAN_VARIABLES; +} + +fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]) +{ + ASSERT_STATE("fmiGetString", not_modelError); + GET_VARIABLES(String); +} + +#ifdef FMI_COSIMULATION +// --------------------------------------------------------------------------- +// FMI functions: only for FMI Co-Simulation 1.0 +// --------------------------------------------------------------------------- + +const char *fmiGetTypesPlatform() +{ + return fmiPlatform; +} + +fmiComponent fmiInstantiateSlave(fmiString instanceName, fmiString GUID, + fmiString fmuLocation, fmiString mimeType, fmiReal timeout, fmiBoolean visible, + fmiBoolean interactive, fmiCallbackFunctions functions, fmiBoolean loggingOn) +{ + + UNUSED(mimeType); + UNUSED(timeout); + UNUSED(visible); + UNUSED(interactive); + + if (!functions.logger) { + return NULL; + } + + // ignoring arguments: mimeType, timeout, visible, interactive + return createModelInstance( + (loggerType) functions.logger, + NULL, + NULL, + instanceName, + GUID, + fmuLocation, + loggingOn, + CoSimulation); +} + +fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) +{ + + UNUSED(tStart); + UNUSED(StopTimeDefined); + UNUSED(tStop); + + return init(c); +} + +fmiStatus fmiTerminateSlave(fmiComponent c) +{ + return terminate("fmiTerminateSlave", c); +} + +fmiStatus fmiResetSlave(fmiComponent c) +{ + ModelInstance *instance = (ModelInstance *) c; + if (invalidState(instance, "fmiResetSlave", Initialized)) + return fmiError; + reset(instance); + return fmiOK; +} + +void fmiFreeSlaveInstance(fmiComponent c) +{ + ModelInstance *instance = (ModelInstance *) c; + freeModelInstance(instance); +} + +fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, + const fmiInteger order[], const fmiReal value[]) +{ + + UNUSED(vr); + UNUSED(nvr); + UNUSED(order); + UNUSED(value); + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiSetRealInputDerivatives", Initialized)) + return fmiError; + + logError(instance, "fmiSetRealInputDerivatives: This model cannot interpolate inputs: canInterpolateInputs=\"fmiFalse\""); + + return fmiError; +} + +fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger order[], fmiReal value[]) +{ + + UNUSED(vr); + UNUSED(nvr); + UNUSED(order); + UNUSED(value); + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiGetRealOutputDerivatives", Initialized)) + return fmiError; + + logError(instance, "fmiGetRealOutputDerivatives: This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); + + return fmiError; +} + +fmiStatus fmiCancelStep(fmiComponent c) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiCancelStep", Initialized)) + return fmiError; + + logError(instance, "fmiCancelStep: Can be called when fmiDoStep returned fmiPending." + " This is not the case."); + + return fmiError; +} + +fmiStatus fmiDoStep(fmiComponent c, fmiReal currentCommunicationPoint, fmiReal communicationStepSize, fmiBoolean newStep) +{ + + UNUSED(newStep); + + ModelInstance *instance = (ModelInstance *) c; + + const fmiReal nextCommunicationPoint = currentCommunicationPoint + communicationStepSize + EPSILON; + + instance->solverStepSize = communicationStepSize; + + fmiBoolean nextCommunicationPointReached; + + while (true) { + + nextCommunicationPointReached = instance->time + instance->solverStepSize > nextCommunicationPoint; + + if (nextCommunicationPointReached) { + break; // next communcation point reached + } + + bool stateEvent, timeEvent; + + doAdaptiveStep(instance, &stateEvent, &timeEvent); +#ifdef EVENT_UPDATE + if (stateEvent || timeEvent) { + eventUpdate(instance); + } +#endif + } + + return fmiOK; +} + +fmiStatus fmiGetStatus(fmiComponent c, const fmiStatusKind s, fmiStatus *value) +{ + + UNUSED(s); + UNUSED(value); + + logError((ModelInstance *) c, "Not implemented."); + + return fmiError; +} + +fmiStatus fmiGetRealStatus(fmiComponent c, const fmiStatusKind s, fmiReal *value) +{ + + UNUSED(c); + UNUSED(s); + UNUSED(value); + + logError((ModelInstance *) c, "Not implemented."); + + return fmiError; +} + +fmiStatus fmiGetIntegerStatus(fmiComponent c, const fmiStatusKind s, fmiInteger *value) +{ + + UNUSED(c); + UNUSED(s); + UNUSED(value); + + logError((ModelInstance *) c, "Not implemented."); + + return fmiError; +} + +fmiStatus fmiGetBooleanStatus(fmiComponent c, const fmiStatusKind s, fmiBoolean *value) +{ + + UNUSED(c); + UNUSED(s); + UNUSED(value); + + logError((ModelInstance *) c, "Not implemented."); + + return fmiError; +} + +fmiStatus fmiGetStringStatus(fmiComponent c, const fmiStatusKind s, fmiString *value) +{ + + UNUSED(c); + UNUSED(s); + UNUSED(value); + + logError((ModelInstance *) c, "Not implemented."); + + return fmiError; +} + +#else +// --------------------------------------------------------------------------- +// FMI functions: only for Model Exchange 1.0 +// --------------------------------------------------------------------------- + +const char *fmiGetModelTypesPlatform() +{ + return fmiModelTypesPlatform; +} + +fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID, fmiCallbackFunctions functions, fmiBoolean loggingOn) +{ + + if (!functions.logger) { + return NULL; + } + + return createModelInstance( + (loggerType) functions.logger, + NULL, + NULL, + instanceName, + GUID, + NULL, + loggingOn, + ModelExchange); +} + +fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance, fmiEventInfo *eventInfo) +{ + + UNUSED(toleranceControlled); + UNUSED(relativeTolerance); + + ModelInstance *instance = (ModelInstance *) c; + + fmiStatus status = init(c); + +#ifdef EVENT_UPDATE + eventUpdate(instance); +#endif + + eventInfo->iterationConverged = instance->newDiscreteStatesNeeded; + eventInfo->stateValueReferencesChanged = fmiFalse; + eventInfo->stateValuesChanged = instance->valuesOfContinuousStatesChanged; + eventInfo->terminateSimulation = instance->terminateSimulation; + eventInfo->upcomingTimeEvent = instance->nextEventTimeDefined; + eventInfo->nextEventTime = instance->nextEventTime; + + return status; +} + +fmiStatus fmiSetTime(fmiComponent c, fmiReal time) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiSetTime", Instantiated | Initialized)) + return fmiError; + + instance->time = time; + + return fmiOK; +} + +fmiStatus fmiSetContinuousStates(fmiComponent c, const fmiReal x[], size_t nx) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiSetContinuousStates", Initialized)) + return fmiError; + + if (invalidNumber(instance, "fmiSetContinuousStates", "nx", nx, NX)) + return fmiError; + + if (nullPointer(instance, "fmiSetContinuousStates", "x[]", x)) + return fmiError; + + setContinuousStates(instance, x, nx); + + return fmiOK; +} + +fmiStatus fmiEventUpdate(fmiComponent c, fmiBoolean intermediateResults, fmiEventInfo *eventInfo) +{ + + UNUSED(intermediateResults); + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiEventUpdate", Initialized)) + return fmiError; + + if (nullPointer(instance, "fmiEventUpdate", "eventInfo", eventInfo)) + return fmiError; + +#ifdef EVENT_UPDATE + eventUpdate(instance); +#endif + + // copy internal eventInfo of component to output eventInfo + eventInfo->iterationConverged = fmiTrue; + eventInfo->stateValueReferencesChanged = fmiFalse; + eventInfo->stateValuesChanged = instance->valuesOfContinuousStatesChanged; + eventInfo->terminateSimulation = instance->terminateSimulation; + eventInfo->upcomingTimeEvent = instance->nextEventTimeDefined; + eventInfo->nextEventTime = instance->nextEventTime; + + return fmiOK; +} + +fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean *callEventUpdate) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiCompletedIntegratorStep", Initialized)) + return fmiError; + + if (nullPointer(instance, "fmiCompletedIntegratorStep", "callEventUpdate", callEventUpdate)) + return fmiError; + + return fmiOK; +} + +fmiStatus fmiGetStateValueReferences(fmiComponent c, fmiValueReference vrx[], size_t nx) +{ + + UNUSED(vrx); + UNUSED(nx); + + logError((ModelInstance *) c, "Not implemented."); + + return fmiError; +} + +fmiStatus fmiGetContinuousStates(fmiComponent c, fmiReal states[], size_t nx) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiGetContinuousStates", not_modelError)) + return fmiError; + + if (invalidNumber(instance, "fmiGetContinuousStates", "nx", nx, NX)) + return fmiError; + + if (nullPointer(instance, "fmiGetContinuousStates", "states[]", states)) + return fmiError; + + getContinuousStates(instance, states, nx); + + return fmiOK; +} + +fmiStatus fmiGetNominalContinuousStates(fmiComponent c, fmiReal x_nominal[], size_t nx) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiGetNominalContinuousStates", not_modelError)) + return fmiError; + + if (invalidNumber(instance, "fmiGetNominalContinuousStates", "nx", nx, NX)) + return fmiError; + + if (nullPointer(instance, "fmiGetNominalContinuousStates", "x_nominal[]", x_nominal)) + return fmiError; + + for (size_t i = 0; i < nx; i++) { + x_nominal[i] = 1; + } + + return fmiOK; +} + +fmiStatus fmiGetDerivatives(fmiComponent c, fmiReal derivatives[], size_t nx) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiGetDerivatives", not_modelError)) + return fmiError; + + if (invalidNumber(instance, "fmiGetDerivatives", "nx", nx, NX)) + return fmiError; + + if (nullPointer(instance, "fmiGetDerivatives", "derivatives[]", derivatives)) + return fmiError; + + getDerivatives(instance, derivatives, nx); + + return fmiOK; +} + +fmiStatus fmiGetEventIndicators(fmiComponent c, fmiReal eventIndicators[], size_t ni) +{ + + ModelInstance *instance = (ModelInstance *) c; + + if (invalidState(instance, "fmiGetEventIndicators", not_modelError)) + return fmiError; + + if (invalidNumber(instance, "fmiGetEventIndicators", "ni", ni, NZ)) + return fmiError; + + getEventIndicators(instance, eventIndicators, ni); + + return fmiOK; +} + +fmiStatus fmiTerminate(fmiComponent c) +{ + return terminate("fmiTerminate", c); +} + +void fmiFreeModelInstance(fmiComponent c) +{ + ModelInstance *instance = (ModelInstance *) c; + freeModelInstance(instance); +} + +#endif // Model Exchange 1.0 diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi2Functions.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi2Functions.c new file mode 100644 index 000000000..3e8a5fb5a --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi2Functions.c @@ -0,0 +1,923 @@ +#if FMI_VERSION != 2 +#error FMI_VERSION must be 2 +#endif + +#include +#include +#include +#include + +#include "config.h" +#include "cosimulation.h" +#include "model.h" + +// C-code FMUs have functions names prefixed with MODEL_IDENTIFIER_. +// Define DISABLE_PREFIX to build a binary FMU. +#ifndef DISABLE_PREFIX +#define pasteA(a, b) a##b +#define pasteB(a, b) pasteA(a, b) +#define FMI2_FUNCTION_PREFIX pasteB(MODEL_IDENTIFIER, _) +#endif +#include "fmi2Functions.h" + +#define ASSERT_NOT_NULL(p) \ + do { \ + if (!p) { \ + logError(S, "Argument %s must not be NULL.", xstr(p)); \ + S->state = modelError; \ + return (fmi2Status) Error; \ + } \ + } while (0) + +#define GET_VARIABLES(T) \ + do { \ + Status status = OK; \ + if (nvr == 0) \ + return (fmi2Status) status; \ + ASSERT_NOT_NULL(vr); \ + ASSERT_NOT_NULL(value); \ + size_t index = 0; \ + if (S->isDirtyValues) { \ + Status s = calculateValues(S); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi2Status) status; \ + S->isDirtyValues = false; \ + } \ + for (size_t i = 0; i < nvr; i++) { \ + Status s = get##T(S, vr[i], value, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi2Status) status; \ + } \ + return (fmi2Status) status; \ + } while (0) + +#define SET_VARIABLES(T) \ + do { \ + Status status = OK; \ + if (nvr == 0) \ + return (fmi2Status) status; \ + ASSERT_NOT_NULL(vr); \ + ASSERT_NOT_NULL(value); \ + size_t index = 0; \ + for (size_t i = 0; i < nvr; i++) { \ + Status s = set##T(S, vr[i], value, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi2Status) status; \ + } \ + if (nvr > 0) \ + S->isDirtyValues = true; \ + return (fmi2Status) status; \ + } while (0) + +#define GET_BOOLEAN_VARIABLES \ + do { \ + Status status = OK; \ + for (size_t i = 0; i < nvr; i++) { \ + bool v = false; \ + size_t index = 0; \ + Status s = getBoolean(S, vr[i], &v, &index); \ + value[i] = v; \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi2Status) status; \ + } \ + return (fmi2Status) status; \ + } while (0) + +#define SET_BOOLEAN_VARIABLES \ + do { \ + Status status = OK; \ + for (size_t i = 0; i < nvr; i++) { \ + bool v = value[i]; \ + size_t index = 0; \ + Status s = setBoolean(S, vr[i], &v, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi2Status) status; \ + } \ + return (fmi2Status) status; \ + } while (0) + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef DT_EVENT_DETECT +#define DT_EVENT_DETECT 1e-10 +#endif + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for both Model-exchange and Co-simulation +// --------------------------------------------------------------------------- +#define MASK_fmi2GetTypesPlatform (StartAndEnd | Instantiated | InitializationMode | EventMode | ContinuousTimeMode | StepComplete | StepInProgress | StepFailed | StepCanceled | Terminated | Error) +#define MASK_fmi2GetVersion MASK_fmi2GetTypesPlatform +#define MASK_fmi2SetDebugLogging (Instantiated | InitializationMode | EventMode | ContinuousTimeMode | StepComplete | StepInProgress | StepFailed | StepCanceled | Terminated | Error) +#define MASK_fmi2Instantiate (StartAndEnd) +#define MASK_fmi2FreeInstance (Instantiated | InitializationMode | EventMode | ContinuousTimeMode | StepComplete | StepFailed | StepCanceled | Terminated | Error) +#define MASK_fmi2SetupExperiment Instantiated +#define MASK_fmi2EnterInitializationMode Instantiated +#define MASK_fmi2ExitInitializationMode InitializationMode +#define MASK_fmi2Terminate (EventMode | ContinuousTimeMode | StepComplete | StepFailed) +#define MASK_fmi2Reset MASK_fmi2FreeInstance +#define MASK_fmi2GetReal (InitializationMode | EventMode | ContinuousTimeMode | StepComplete | StepFailed | StepCanceled | Terminated | Error) +#define MASK_fmi2GetInteger MASK_fmi2GetReal +#define MASK_fmi2GetBoolean MASK_fmi2GetReal +#define MASK_fmi2GetString MASK_fmi2GetReal +#define MASK_fmi2SetReal (Instantiated | InitializationMode | EventMode | ContinuousTimeMode | StepComplete) +#define MASK_fmi2SetInteger (Instantiated | InitializationMode | EventMode | StepComplete) +#define MASK_fmi2SetBoolean MASK_fmi2SetInteger +#define MASK_fmi2SetString MASK_fmi2SetInteger +#define MASK_fmi2GetFMUstate MASK_fmi2FreeInstance +#define MASK_fmi2SetFMUstate MASK_fmi2FreeInstance +#define MASK_fmi2FreeFMUstate MASK_fmi2FreeInstance +#define MASK_fmi2SerializedFMUstateSize MASK_fmi2FreeInstance +#define MASK_fmi2SerializeFMUstate MASK_fmi2FreeInstance +#define MASK_fmi2DeSerializeFMUstate MASK_fmi2FreeInstance +#define MASK_fmi2GetDirectionalDerivative (InitializationMode | EventMode | ContinuousTimeMode | StepComplete | StepFailed | StepCanceled | Terminated | Error) + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for Model-exchange +// --------------------------------------------------------------------------- +#define MASK_fmi2EnterEventMode (EventMode | ContinuousTimeMode) +#define MASK_fmi2NewDiscreteStates EventMode +#define MASK_fmi2EnterContinuousTimeMode EventMode +#define MASK_fmi2CompletedIntegratorStep ContinuousTimeMode +#define MASK_fmi2SetTime (EventMode | ContinuousTimeMode) +#define MASK_fmi2SetContinuousStates ContinuousTimeMode +#define MASK_fmi2GetEventIndicators (InitializationMode | EventMode | ContinuousTimeMode | Terminated | Error) +#define MASK_fmi2GetContinuousStates MASK_fmi2GetEventIndicators +#define MASK_fmi2GetDerivatives (EventMode | ContinuousTimeMode | Terminated | Error) +#define MASK_fmi2GetNominalsOfContinuousStates (Instantiated | EventMode | ContinuousTimeMode | Terminated | Error) + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for Co-simulation +// --------------------------------------------------------------------------- +#define MASK_fmi2SetRealInputDerivatives (Instantiated | InitializationMode | StepComplete) +#define MASK_fmi2GetRealOutputDerivatives (StepComplete | StepFailed | StepCanceled | Terminated | Error) +#define MASK_fmi2DoStep StepComplete +#define MASK_fmi2CancelStep StepInProgress +#define MASK_fmi2GetStatus (StepComplete | StepInProgress | StepFailed | Terminated) +#define MASK_fmi2GetRealStatus MASK_fmi2GetStatus +#define MASK_fmi2GetIntegerStatus MASK_fmi2GetStatus +#define MASK_fmi2GetBooleanStatus MASK_fmi2GetStatus +#define MASK_fmi2GetStringStatus MASK_fmi2GetStatus + +// shorthand to access the instance +#define S ((ModelInstance *) c) + +#define ASSERT_STATE(S) \ + if (!allowedState(c, MASK_fmi2##S, #S)) \ + return fmi2Error; + +static bool allowedState(ModelInstance *instance, int statesExpected, char *name) +{ + + if (!instance) { + return false; + } + + if (!(instance->state & statesExpected)) { + logError(instance, "fmi2%s: Illegal call sequence.", name); + return false; + } + + return true; +} + +// --------------------------------------------------------------------------- +// FMI functions +// --------------------------------------------------------------------------- + +fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID, + fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions, + fmi2Boolean visible, fmi2Boolean loggingOn) +{ + + UNUSED(visible); + + if (!functions || !functions->logger) { + return NULL; + } + + return createModelInstance( + (loggerType) functions->logger, + NULL, + functions->componentEnvironment, + instanceName, + fmuGUID, + fmuResourceLocation, + loggingOn, + (InterfaceType) fmuType); +} + +fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance, + fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime) +{ + + UNUSED(toleranceDefined); + UNUSED(tolerance); + UNUSED(stopTimeDefined); + UNUSED(stopTime); + + ASSERT_STATE(SetupExperiment) + + S->startTime = startTime; + S->time = startTime; + + return fmi2OK; +} + +fmi2Status fmi2EnterInitializationMode(fmi2Component c) +{ + + ASSERT_STATE(EnterInitializationMode) + + S->state = InitializationMode; + + return fmi2OK; +} + +fmi2Status fmi2ExitInitializationMode(fmi2Component c) +{ + + ASSERT_STATE(ExitInitializationMode); + + fmi2Status status = fmi2OK; + + // if values were set and no fmi2GetXXX triggered update before, + // ensure calculated values are updated now + if (S->isDirtyValues) { + status = (fmi2Status) calculateValues(S); + S->isDirtyValues = false; + } + + if (S->type == ModelExchange) { + S->state = EventMode; + } else { + S->state = StepComplete; + } + + return status; +} + +fmi2Status fmi2Terminate(fmi2Component c) +{ + + ASSERT_STATE(Terminate) + + S->state = Terminated; + + return fmi2OK; +} + +fmi2Status fmi2Reset(fmi2Component c) +{ + + ASSERT_STATE(Reset); + + reset(S); + + return fmi2OK; +} + +void fmi2FreeInstance(fmi2Component c) +{ + + if (S) { + freeModelInstance(S); + } +} + +// --------------------------------------------------------------------------- +// FMI functions: class methods not depending of a specific model instance +// --------------------------------------------------------------------------- + +const char *fmi2GetVersion() +{ + return fmi2Version; +} + +const char *fmi2GetTypesPlatform() +{ + return fmi2TypesPlatform; +} + +// --------------------------------------------------------------------------- +// FMI functions: logging control, setters and getters for Real, Integer, +// Boolean, String +// --------------------------------------------------------------------------- + +fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) +{ + + ASSERT_STATE(SetDebugLogging) + + return (fmi2Status) setDebugLogging(S, loggingOn, nCategories, categories); +} + +fmi2Status fmi2GetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) +{ + + ASSERT_STATE(GetReal) + + if (nvr > 0 && nullPointer(S, "fmi2GetReal", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2GetReal", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && S->isDirtyValues) { + calculateValues(S); + S->isDirtyValues = false; + } + + GET_VARIABLES(Float64); +} + +fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) +{ + + ASSERT_STATE(GetInteger) + + if (nvr > 0 && nullPointer(S, "fmi2GetInteger", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2GetInteger", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && S->isDirtyValues) { + calculateValues(S); + S->isDirtyValues = false; + } + + GET_VARIABLES(Int32); +} + +fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) +{ + + ASSERT_STATE(GetBoolean) + + if (nvr > 0 && nullPointer(S, "fmi2GetBoolean", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2GetBoolean", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && S->isDirtyValues) { + calculateValues(S); + S->isDirtyValues = false; + } + + GET_BOOLEAN_VARIABLES; +} + +fmi2Status fmi2GetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) +{ + + ASSERT_STATE(GetString) + + if (nvr > 0 && nullPointer(S, "fmi2GetString", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2GetString", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && S->isDirtyValues) { + calculateValues(S); + S->isDirtyValues = false; + } + + GET_VARIABLES(String); +} + +fmi2Status fmi2SetReal(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) +{ + + ASSERT_STATE(SetReal) + + if (invalidState(S, "fmi2SetReal", MASK_fmi2SetReal)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2SetReal", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2SetReal", "value[]", value)) + return fmi2Error; + + SET_VARIABLES(Float64); +} + +fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) +{ + + ASSERT_STATE(SetInteger) + + if (nvr > 0 && nullPointer(S, "fmi2SetInteger", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2SetInteger", "value[]", value)) + return fmi2Error; + + SET_VARIABLES(Int32); +} + +fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) +{ + + ASSERT_STATE(SetBoolean) + + if (nvr > 0 && nullPointer(S, "fmi2SetBoolean", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2SetBoolean", "value[]", value)) + return fmi2Error; + + SET_BOOLEAN_VARIABLES; +} + +fmi2Status fmi2SetString(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) +{ + + ASSERT_STATE(SetString); + + if (nvr > 0 && nullPointer(S, "fmi2SetString", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(S, "fmi2SetString", "value[]", value)) + return fmi2Error; + + SET_VARIABLES(String); +} + +fmi2Status fmi2GetFMUstate(fmi2Component c, fmi2FMUstate *FMUstate) +{ + + ASSERT_STATE(GetFMUstate); + + *FMUstate = getFMUState(S); + + return fmi2OK; +} + +fmi2Status fmi2SetFMUstate(fmi2Component c, fmi2FMUstate FMUstate) +{ + + ASSERT_STATE(SetFMUstate); + + if (nullPointer(S, "fmi2SetFMUstate", "FMUstate", FMUstate)) { + return fmi2Error; + } + + setFMUState(S, FMUstate); + + return fmi2OK; +} + +fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate *FMUstate) +{ + + ASSERT_STATE(FreeFMUstate); + + free(*FMUstate); + + *FMUstate = NULL; + + return fmi2OK; +} + +fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate FMUstate, size_t *size) +{ + + UNUSED(c); + UNUSED(FMUstate); + + ASSERT_STATE(SerializedFMUstateSize); + + *size = sizeof(ModelInstance); + + return fmi2OK; +} + +fmi2Status fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte serializedState[], size_t size) +{ + + ASSERT_STATE(SerializeFMUstate); + + if (nullPointer(S, "fmi2SerializeFMUstate", "FMUstate", FMUstate)) { + return fmi2Error; + } + + if (invalidNumber(S, "fmi2SerializeFMUstate", "size", size, sizeof(ModelInstance))) { + return fmi2Error; + } + + memcpy(serializedState, FMUstate, sizeof(ModelInstance)); + + return fmi2OK; +} + +fmi2Status fmi2DeSerializeFMUstate(fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate *FMUstate) +{ + + ASSERT_STATE(DeSerializeFMUstate); + + if (invalidNumber(S, "fmi2DeSerializeFMUstate", "size", size, sizeof(ModelInstance))) { + return fmi2Error; + } + + if (*FMUstate == NULL) { + *FMUstate = calloc(1, sizeof(ModelInstance)); + } + + memcpy(*FMUstate, serializedState, sizeof(ModelInstance)); + + return fmi2OK; +} + +fmi2Status fmi2GetDirectionalDerivative(fmi2Component c, const fmi2ValueReference vUnknown_ref[], size_t nUnknown, + const fmi2ValueReference vKnown_ref[], size_t nKnown, + const fmi2Real dvKnown[], fmi2Real dvUnknown[]) +{ + + ASSERT_STATE(GetDirectionalDerivative); + + // TODO: check value references + // TODO: assert nUnknowns == nDeltaOfUnknowns + // TODO: assert nKnowns == nDeltaKnowns + + Status status = OK; + + for (size_t i = 0; i < nUnknown; i++) { + dvUnknown[i] = 0; + for (size_t j = 0; j < nKnown; j++) { + double partialDerivative = 0; + Status s = getPartialDerivative(S, vUnknown_ref[i], vKnown_ref[j], &partialDerivative); + status = max(status, s); + if (status > Warning) { + return (fmi2Status) status; + } + dvUnknown[i] += partialDerivative * dvKnown[j]; + } + } + + return fmi2OK; +} + +// --------------------------------------------------------------------------- +// Functions for FMI for Co-Simulation +// --------------------------------------------------------------------------- +/* Simulating the slave */ +fmi2Status fmi2SetRealInputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], const fmi2Real value[]) +{ + + UNUSED(vr); + UNUSED(nvr); + UNUSED(order); + UNUSED(value); + + ASSERT_STATE(SetRealInputDerivatives); + + logError(S, "fmi2SetRealInputDerivatives: ignoring function call." + " This model cannot interpolate inputs: canInterpolateInputs=\"fmi2False\""); + + return fmi2Error; +} + +fmi2Status fmi2GetRealOutputDerivatives(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, + const fmi2Integer order[], fmi2Real value[]) +{ + + ASSERT_STATE(GetRealOutputDerivatives); + +#ifdef GET_OUTPUT_DERIVATIVE + Status status = OK; + + for (size_t i = 0; i < nvr; i++) { + const Status s = getOutputDerivative(S, vr[i], order[i], &value[i]); + status = max(status, s); + if (status > Warning) { + return (fmi2Status) status; + } + } + + return (fmi2Status) status; +#else + UNUSED(vr); + UNUSED(nvr); + UNUSED(order); + UNUSED(value); + + logError(S, "fmi2GetRealOutputDerivatives: ignoring function call." + " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); + + return fmi2Error; +#endif +} + +fmi2Status fmi2CancelStep(fmi2Component c) +{ + + ASSERT_STATE(CancelStep); + + logError(S, "fmi2CancelStep: Can be called when fmi2DoStep returned fmi2Pending." + " This is not the case."); + + return fmi2Error; +} + +fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint, + fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) +{ + + UNUSED(noSetFMUStatePriorToCurrentPoint); + + ASSERT_STATE(DoStep); + + if (communicationStepSize <= 0) { + logError(S, "fmi2DoStep: communication step size must be > 0 but was %g.", communicationStepSize); + S->state = modelError; + return fmi2Error; + } + + const fmi2Real nextCommunicationPoint = currentCommunicationPoint + communicationStepSize + EPSILON; + + fmi2Boolean nextCommunicationPointReached; + + S->solverStepSize = communicationStepSize; + + while (true) { + + nextCommunicationPointReached = S->time + S->solverStepSize > nextCommunicationPoint; + + if (nextCommunicationPointReached) { + break; // next communcation point reached + } + + bool stateEvent, timeEvent; + + doAdaptiveStep(S, &stateEvent, &timeEvent); + +#ifdef EVENT_UPDATE + if (stateEvent || timeEvent) { + eventUpdate(S); + } +#endif + } + + return S->terminateSimulation ? fmi2Discard : fmi2OK; +} + +/* Inquire slave status */ +static fmi2Status getStatus(char *fname, fmi2Component c, const fmi2StatusKind s) +{ + + if (invalidState(S, fname, MASK_fmi2GetStatus)) // all get status have the same MASK_fmi2GetStatus + return fmi2Error; + + switch (s) { + case fmi2DoStepStatus: + logError(S, + "%s: Can be called with fmi2DoStepStatus when fmi2DoStep returned fmi2Pending." + " This is not the case.", + fname); + break; + case fmi2PendingStatus: + logError(S, + "%s: Can be called with fmi2PendingStatus when fmi2DoStep returned fmi2Pending." + " This is not the case.", + fname); + break; + case fmi2LastSuccessfulTime: + logError(S, + "%s: Can be called with fmi2LastSuccessfulTime when fmi2DoStep returned fmi2Discard." + " This is not the case.", + fname); + break; + case fmi2Terminated: + logError(S, + "%s: Can be called with fmi2Terminated when fmi2DoStep returned fmi2Discard." + " This is not the case.", + fname); + break; + } + + return fmi2Discard; +} + +fmi2Status fmi2GetStatus(fmi2Component c, const fmi2StatusKind s, fmi2Status *value) +{ + + UNUSED(value); + + ASSERT_STATE(GetStatus); + + return getStatus("fmi2GetStatus", c, s); +} + +fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real *value) +{ + + ASSERT_STATE(GetRealStatus); + + if (s == fmi2LastSuccessfulTime) { + *value = S->time; + return fmi2OK; + } + + return getStatus("fmi2GetRealStatus", c, s); +} + +fmi2Status fmi2GetIntegerStatus(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value) +{ + + UNUSED(value); + + ASSERT_STATE(GetIntegerStatus); + + return getStatus("fmi2GetIntegerStatus", c, s); +} + +fmi2Status fmi2GetBooleanStatus(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value) +{ + + ASSERT_STATE(GetBooleanStatus); + + if (s == fmi2Terminated) { + *value = S->terminateSimulation; + return fmi2OK; + } + + return getStatus("fmi2GetBooleanStatus", c, s); +} + +fmi2Status fmi2GetStringStatus(fmi2Component c, const fmi2StatusKind s, fmi2String *value) +{ + UNUSED(value); + ASSERT_STATE(GetStringStatus); + return getStatus("fmi2GetStringStatus", c, s); +} + +// --------------------------------------------------------------------------- +// Functions for FMI2 for Model Exchange +// --------------------------------------------------------------------------- +/* Enter and exit the different modes */ +fmi2Status fmi2EnterEventMode(fmi2Component c) +{ + + ASSERT_STATE(EnterEventMode); + + S->state = EventMode; + + return fmi2OK; +} + +fmi2Status fmi2NewDiscreteStates(fmi2Component c, fmi2EventInfo *eventInfo) +{ + + ASSERT_STATE(NewDiscreteStates); + +#ifdef EVENT_UPDATE + eventUpdate(S); +#endif + + eventInfo->newDiscreteStatesNeeded = S->newDiscreteStatesNeeded; + eventInfo->terminateSimulation = S->terminateSimulation; + eventInfo->nominalsOfContinuousStatesChanged = S->nominalsOfContinuousStatesChanged; + eventInfo->valuesOfContinuousStatesChanged = S->valuesOfContinuousStatesChanged; + eventInfo->nextEventTimeDefined = S->nextEventTimeDefined; + eventInfo->nextEventTime = S->nextEventTime; + + return fmi2OK; +} + +fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c) +{ + + ASSERT_STATE(EnterContinuousTimeMode); + + S->state = ContinuousTimeMode; + + return fmi2OK; +} + +fmi2Status fmi2CompletedIntegratorStep(fmi2Component c, fmi2Boolean noSetFMUStatePriorToCurrentPoint, + fmi2Boolean *enterEventMode, fmi2Boolean *terminateSimulation) +{ + + UNUSED(noSetFMUStatePriorToCurrentPoint); + + ASSERT_STATE(CompletedIntegratorStep); + + if (nullPointer(S, "fmi2CompletedIntegratorStep", "enterEventMode", enterEventMode)) + return fmi2Error; + + if (nullPointer(S, "fmi2CompletedIntegratorStep", "terminateSimulation", terminateSimulation)) + return fmi2Error; + + *enterEventMode = fmi2False; + *terminateSimulation = fmi2False; + + return fmi2OK; +} + +/* Providing independent variables and re-initialization of caching */ +fmi2Status fmi2SetTime(fmi2Component c, fmi2Real time) +{ + + ASSERT_STATE(SetTime); + + S->time = time; + + return fmi2OK; +} + +fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t nx) +{ + + ASSERT_STATE(SetContinuousStates); + + if (invalidNumber(S, "fmi2SetContinuousStates", "nx", nx, NX)) + return fmi2Error; + + if (nullPointer(S, "fmi2SetContinuousStates", "x[]", x)) + return fmi2Error; + + setContinuousStates(S, x, nx); + + return fmi2OK; +} + +/* Evaluation of the model equations */ +fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx) +{ + + ASSERT_STATE(GetDerivatives); + + if (invalidNumber(S, "fmi2GetDerivatives", "nx", nx, NX)) + return fmi2Error; + + if (nullPointer(S, "fmi2GetDerivatives", "derivatives[]", derivatives)) + return fmi2Error; + + getDerivatives(S, derivatives, nx); + + return fmi2OK; +} + +fmi2Status fmi2GetEventIndicators(fmi2Component c, fmi2Real eventIndicators[], size_t ni) +{ + + ASSERT_STATE(GetEventIndicators); + +#if NZ > 0 + + if (invalidNumber(S, "fmi2GetEventIndicators", "ni", ni, NZ)) + return fmi2Error; + + getEventIndicators(S, eventIndicators, ni); +#else + UNUSED(c); + UNUSED(eventIndicators); + if (ni > 0) + return fmi2Error; +#endif + return fmi2OK; +} + +fmi2Status fmi2GetContinuousStates(fmi2Component c, fmi2Real states[], size_t nx) +{ + + ASSERT_STATE(GetContinuousStates); + + if (invalidNumber(S, "fmi2GetContinuousStates", "nx", nx, NX)) + return fmi2Error; + + if (nullPointer(S, "fmi2GetContinuousStates", "states[]", states)) + return fmi2Error; + + getContinuousStates(S, states, nx); + + return fmi2OK; +} + +fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c, fmi2Real x_nominal[], size_t nx) +{ + + ASSERT_STATE(GetNominalsOfContinuousStates); + + if (invalidNumber(S, "fmi2GetNominalContinuousStates", "nx", nx, NX)) + return fmi2Error; + + if (nullPointer(S, "fmi2GetNominalContinuousStates", "x_nominal[]", x_nominal)) + return fmi2Error; + + for (size_t i = 0; i < nx; i++) + x_nominal[i] = 1; + + return fmi2OK; +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi3Functions.c b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi3Functions.c new file mode 100644 index 000000000..40ece8e42 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/src/fmi3Functions.c @@ -0,0 +1,1544 @@ +#if FMI_VERSION != 3 +#error FMI_VERSION must be 3 +#endif + +#include +#include +#include +#include + +#include "config.h" +#include "cosimulation.h" +#include "model.h" + +// C-code FMUs have functions names prefixed with MODEL_IDENTIFIER_. +// Define DISABLE_PREFIX to build a binary FMU. +#if !defined(DISABLE_PREFIX) && !defined(FMI3_FUNCTION_PREFIX) +#define pasteA(a, b) a##b +#define pasteB(a, b) pasteA(a, b) +#define FMI3_FUNCTION_PREFIX pasteB(MODEL_IDENTIFIER, _) +#endif +#include "fmi3Functions.h" + +#define ASSERT_NOT_NULL(p) \ + do { \ + if (!p) { \ + logError(S, "Argument %s must not be NULL.", xstr(p)); \ + S->state = modelError; \ + return (fmi3Status) Error; \ + } \ + } while (0) + +#define GET_VARIABLES(T) \ + do { \ + Status status = OK; \ + if (nValueReferences == 0) \ + return (fmi3Status) status; \ + ASSERT_NOT_NULL(valueReferences); \ + ASSERT_NOT_NULL(values); \ + size_t index = 0; \ + if (nValueReferences == 0) \ + return (fmi3Status) status; \ + if (S->isDirtyValues) { \ + Status s = calculateValues(S); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi3Status) status; \ + S->isDirtyValues = false; \ + } \ + for (size_t i = 0; i < nValueReferences; i++) { \ + Status s = get##T(S, (ValueReference) valueReferences[i], values, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi3Status) status; \ + } \ + return (fmi3Status) status; \ + } while (0) + +#define SET_VARIABLES(T) \ + do { \ + Status status = OK; \ + if (nValueReferences == 0) \ + return (fmi3Status) status; \ + ASSERT_NOT_NULL(valueReferences); \ + ASSERT_NOT_NULL(values); \ + size_t index = 0; \ + for (size_t i = 0; i < nValueReferences; i++) { \ + Status s = set##T(S, (ValueReference) valueReferences[i], values, &index); \ + status = max(status, s); \ + if (status > Warning) \ + return (fmi3Status) status; \ + } \ + if (nValueReferences > 0) \ + S->isDirtyValues = true; \ + return (fmi3Status) status; \ + } while (0) + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef DT_EVENT_DETECT +#define DT_EVENT_DETECT 1e-10 +#endif + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for both Model-exchange and Co-simulation +// --------------------------------------------------------------------------- +#define MASK_AnyState (~0) + +/* Inquire version numbers and set debug logging */ +#define MASK_fmi3GetVersion MASK_AnyState +#define MASK_fmi3SetDebugLogging MASK_AnyState + +/* Creation and destruction of FMU instances */ +#define MASK_fmi3InstantiateInstantiateModelExchange MASK_AnyState +#define MASK_fmi3InstantiateCoSimulation MASK_AnyState +#define MASK_fmi3InstantiateScheduledExectuion MASK_AnyState +#define MASK_fmi3FreeInstance MASK_AnyState + +/* Enter and exit initialization mode, terminate and reset */ +#define MASK_fmi3EnterInitializationMode Instantiated +#define MASK_fmi3ExitInitializationMode InitializationMode +#define MASK_fmi3EnterEventMode (ContinuousTimeMode | StepMode) +#define MASK_fmi3Terminate (ContinuousTimeMode | StepMode | StepDiscarded | EventMode | ClockActivationMode | ReconfigurationMode) +#define MASK_fmi3Reset MASK_AnyState + +/* Common Functions */ + +/* Getting and setting variable values */ +#define MASK_fmi3GetFloat32 (InitializationMode | ConfigurationMode | ReconfigurationMode | EventMode | ContinuousTimeMode | StepMode | ClockActivationMode | IntermediateUpdateMode | Terminated) +#define MASK_fmi3GetFloat64 MASK_fmi3GetFloat32 +#define MASK_fmi3GetInt8 MASK_fmi3GetFloat32 +#define MASK_fmi3GetUInt8 MASK_fmi3GetFloat32 +#define MASK_fmi3GetInt16 MASK_fmi3GetFloat32 +#define MASK_fmi3GetUInt16 MASK_fmi3GetFloat32 +#define MASK_fmi3GetInt32 MASK_fmi3GetFloat32 +#define MASK_fmi3GetUInt32 MASK_fmi3GetFloat32 +#define MASK_fmi3GetInt64 MASK_fmi3GetFloat32 +#define MASK_fmi3GetUInt64 MASK_fmi3GetFloat32 +#define MASK_fmi3GetBoolean MASK_fmi3GetFloat32 +#define MASK_fmi3GetString MASK_fmi3GetFloat32 +#define MASK_fmi3GetBinary MASK_fmi3GetFloat32 +#define MASK_fmi3GetClock MASK_AnyState + +#define MASK_fmi3SetFloat32 (Instantiated | InitializationMode | ConfigurationMode | ReconfigurationMode | EventMode | ContinuousTimeMode | StepMode | ClockActivationMode | IntermediateUpdateMode | Terminated) +#define MASK_fmi3SetFloat64 MASK_fmi3SetFloat32 +#define MASK_fmi3SetInt8 (Instantiated | ConfigurationMode | ReconfigurationMode | InitializationMode | EventMode | StepMode | ClockActivationMode | Terminated) +#define MASK_fmi3SetUInt8 MASK_fmi3SetInt8 +#define MASK_fmi3SetInt16 MASK_fmi3SetInt8 +#define MASK_fmi3SetUInt16 MASK_fmi3SetInt8 +#define MASK_fmi3SetInt32 MASK_fmi3SetInt8 +#define MASK_fmi3SetUInt32 MASK_fmi3SetInt8 +#define MASK_fmi3SetInt64 MASK_fmi3SetInt8 +#define MASK_fmi3SetUInt64 MASK_fmi3SetInt8 +#define MASK_fmi3SetBoolean MASK_fmi3SetInt8 +#define MASK_fmi3SetString MASK_fmi3SetInt8 +#define MASK_fmi3SetBinary MASK_fmi3SetInt8 +#define MASK_fmi3SetClock MASK_AnyState + +/* Getting Variable Dependency Information */ +#define MASK_fmi3GetNumberOfVariableDependencies MASK_AnyState +#define MASK_fmi3GetVariableDependencies MASK_AnyState + +/* Getting and setting the internal FMU state */ +#define MASK_fmi3GetFMUState MASK_AnyState +#define MASK_fmi3SetFMUState MASK_AnyState +#define MASK_fmi3FreeFMUState MASK_AnyState +#define MASK_fmi3SerializedFMUStateSize MASK_AnyState +#define MASK_fmi3SerializeFMUState MASK_AnyState +#define MASK_fmi3DeserializeFMUState MASK_AnyState + +/* Getting partial derivatives */ +#define MASK_fmi3GetDirectionalDerivative (InitializationMode | StepMode | EventMode | ContinuousTimeMode | Terminated) +#define MASK_fmi3GetAdjointDerivative MASK_fmi3GetDirectionalDerivative + +/* Entering and exiting the Configuration or Reconfiguration Mode */ +#define MASK_fmi3EnterConfigurationMode (Instantiated | StepMode | EventMode | ClockActivationMode) +#define MASK_fmi3ExitConfigurationMode (ConfigurationMode | ReconfigurationMode) + +/* Clock related functions */ +// TODO: fix masks +#define MASK_fmi3GetIntervalDecimal MASK_AnyState +#define MASK_fmi3GetIntervalFraction MASK_AnyState +#define MASK_fmi3SetIntervalDecimal MASK_AnyState +#define MASK_fmi3SetIntervalFraction MASK_AnyState +#define MASK_fmi3NewDiscreteStates MASK_AnyState + +/* Functions for Model Exchange */ + +#define MASK_fmi3EnterContinuousTimeMode EventMode +#define MASK_fmi3CompletedIntegratorStep ContinuousTimeMode + +/* Providing independent variables and re-initialization of caching */ +#define MASK_fmi3SetTime (EventMode | ContinuousTimeMode) +#define MASK_fmi3SetContinuousStates ContinuousTimeMode + +/* Evaluation of the model equations */ +#define MASK_fmi3GetContinuousStateDerivatives (InitializationMode | EventMode | ContinuousTimeMode | Terminated) +#define MASK_fmi3GetEventIndicators MASK_fmi3GetContinuousStateDerivatives +#define MASK_fmi3GetContinuousStates MASK_fmi3GetContinuousStateDerivatives +#define MASK_fmi3GetNominalsOfContinuousStates MASK_fmi3GetContinuousStateDerivatives + +#define MASK_fmi3GetNumberOfContinuousStates MASK_AnyState +#define MASK_fmi3GetNumberOfEventIndicators MASK_AnyState + +/* Functions for Co-Simulation */ + +#define MASK_fmi3EnterStepMode (InitializationMode | EventMode) +#define MASK_fmi3SetInputDerivatives (Instantiated | InitializationMode | StepMode) +#define MASK_fmi3GetOutputDerivatives (StepMode | StepDiscarded | Terminated | Error) +#define MASK_fmi3DoStep StepMode +#define MASK_fmi3ActivateModelPartition ClockActivationMode +#define MASK_fmi3DoEarlyReturn IntermediateUpdateMode +#define MASK_fmi3GetDoStepDiscardedStatus StepMode + +// --------------------------------------------------------------------------- +// Private helpers used below to validate function arguments +// --------------------------------------------------------------------------- + +#define NOT_IMPLEMENTED \ + do { \ + ModelInstance *comp = (ModelInstance *) instance; \ + logError(comp, "Function is not implemented."); \ + return fmi3Error; \ + } while (0) + +#define ASSERT_STATE(F) \ + if (!instance) \ + return fmi3Error; \ + ModelInstance *S = (ModelInstance *) instance; \ + if (!allowedState(S, MASK_fmi3##F, #F)) \ + return fmi3Error; + +static bool allowedState(ModelInstance *instance, int statesExpected, char *name) +{ + + if (!instance) { + return false; + } + + if (!(instance->state & statesExpected)) { + logError(instance, "fmi3%s: Illegal call sequence.", name); + return false; + } + + return true; +} + +/*************************************************** + Common Functions + ****************************************************/ + +const char *fmi3GetVersion() +{ + return fmi3Version; +} + +fmi3Status fmi3SetDebugLogging(fmi3Instance instance, + fmi3Boolean loggingOn, + size_t nCategories, + const fmi3String categories[]) +{ + + ASSERT_STATE(SetDebugLogging) + + return (fmi3Status) setDebugLogging(S, loggingOn, nCategories, categories); +} + +fmi3Instance fmi3InstantiateModelExchange( + fmi3String instanceName, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage) +{ + + UNUSED(visible); + +#ifndef MODEL_EXCHANGE + UNUSED(instanceName); + UNUSED(instantiationToken); + UNUSED(resourcePath); + UNUSED(loggingOn); + UNUSED(instanceEnvironment); + UNUSED(logMessage); + + return NULL; +#else + return createModelInstance( + (loggerType) logMessage, + NULL, + instanceEnvironment, + instanceName, + instantiationToken, + resourcePath, + loggingOn, + ModelExchange); +#endif +} + +fmi3Instance fmi3InstantiateCoSimulation( + fmi3String instanceName, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3Boolean eventModeUsed, + fmi3Boolean earlyReturnAllowed, + const fmi3ValueReference requiredIntermediateVariables[], + size_t nRequiredIntermediateVariables, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage, + fmi3IntermediateUpdateCallback intermediateUpdate) +{ + + UNUSED(visible); + UNUSED(requiredIntermediateVariables); + UNUSED(nRequiredIntermediateVariables); + +#ifndef EVENT_UPDATE + if (eventModeUsed) { + if (logMessage) { + logMessage(instanceEnvironment, fmi3Error, "error", "Event Mode is not supported."); + } + return NULL; + } +#endif + + ModelInstance *instance = createModelInstance( + (loggerType) logMessage, + (intermediateUpdateType) intermediateUpdate, + instanceEnvironment, + instanceName, + instantiationToken, + resourcePath, + loggingOn, + CoSimulation); + + if (instance) { + instance->earlyReturnAllowed = earlyReturnAllowed; + instance->eventModeUsed = eventModeUsed; + instance->state = Instantiated; + } + + return instance; +} + +fmi3Instance fmi3InstantiateScheduledExecution( + fmi3String instanceName, + fmi3String instantiationToken, + fmi3String resourcePath, + fmi3Boolean visible, + fmi3Boolean loggingOn, + fmi3InstanceEnvironment instanceEnvironment, + fmi3LogMessageCallback logMessage, + fmi3ClockUpdateCallback clockUpdate, + fmi3LockPreemptionCallback lockPreemption, + fmi3UnlockPreemptionCallback unlockPreemption) +{ + + UNUSED(visible); + +#ifndef SCHEDULED_CO_SIMULATION + + UNUSED(instanceName); + UNUSED(instantiationToken); + UNUSED(resourcePath); + UNUSED(loggingOn); + UNUSED(instanceEnvironment); + UNUSED(logMessage); + UNUSED(clockUpdate); + UNUSED(lockPreemption); + UNUSED(unlockPreemption); + + return NULL; +#else + ModelInstance *instance = createModelInstance( + (loggerType) logMessage, + NULL, + instanceEnvironment, + instanceName, + instantiationToken, + resourcePath, + loggingOn, + ScheduledExecution); + + if (instance) { + instance->state = Instantiated; + instance->clockUpdate = clockUpdate; + instance->lockPreemtion = lockPreemption; + instance->unlockPreemtion = unlockPreemption; + } + + return instance; +#endif +} + +void fmi3FreeInstance(fmi3Instance instance) +{ + + if (!instance) + return; + + freeModelInstance((ModelInstance *) instance); +} + +fmi3Status fmi3EnterInitializationMode(fmi3Instance instance, + fmi3Boolean toleranceDefined, + fmi3Float64 tolerance, + fmi3Float64 startTime, + fmi3Boolean stopTimeDefined, + fmi3Float64 stopTime) +{ + + UNUSED(toleranceDefined); + UNUSED(tolerance); + UNUSED(stopTimeDefined); + UNUSED(stopTime); + + ASSERT_STATE(EnterInitializationMode); + + S->startTime = startTime; + S->time = startTime; + S->state = InitializationMode; + + return fmi3OK; +} + +fmi3Status fmi3ExitInitializationMode(fmi3Instance instance) +{ + + ASSERT_STATE(ExitInitializationMode); + + fmi3Status status = fmi3OK; + + // if values were set and no fmi3GetXXX triggered update before, + // ensure calculated values are updated now + if (S->isDirtyValues) { + + status = (fmi3Status) calculateValues(S); + + if (status > fmi3Warning) { + return status; + } + + S->isDirtyValues = false; + } + + switch (S->type) { + case ModelExchange: + S->state = EventMode; + break; + case CoSimulation: + S->state = S->eventModeUsed ? EventMode : StepMode; + break; + case ScheduledExecution: + S->state = ClockActivationMode; + break; + } + +#if NZ > 0 + // initialize event indicators + getEventIndicators(S, S->z, NZ); +#endif + + return status; +} + +fmi3Status fmi3EnterEventMode(fmi3Instance instance) +{ + + ASSERT_STATE(EnterEventMode); + + S->state = EventMode; + + return fmi3OK; +} + +fmi3Status fmi3Terminate(fmi3Instance instance) +{ + + ASSERT_STATE(Terminate); + + S->state = Terminated; + + return fmi3OK; +} + +fmi3Status fmi3Reset(fmi3Instance instance) +{ + + ASSERT_STATE(Reset); + + reset(S); + + return fmi3OK; +} + +fmi3Status fmi3GetFloat32(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float32 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetFloat32); + GET_VARIABLES(Float32); +} + +fmi3Status fmi3GetFloat64(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetFloat64); + GET_VARIABLES(Float64); +} + +fmi3Status fmi3GetInt8(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int8 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetInt8); + GET_VARIABLES(Int8); +} + +fmi3Status fmi3GetUInt8(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt8 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetUInt8); + GET_VARIABLES(UInt8); +} + +fmi3Status fmi3GetInt16(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int16 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetInt16); + GET_VARIABLES(Int16); +} + +fmi3Status fmi3GetUInt16(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt16 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetUInt16); + GET_VARIABLES(UInt16); +} + +fmi3Status fmi3GetInt32(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int32 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetInt32); + GET_VARIABLES(Int32); +} + +fmi3Status fmi3GetUInt32(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt32 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetUInt32); + GET_VARIABLES(UInt32); +} + +fmi3Status fmi3GetInt64(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Int64 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetInt64); + GET_VARIABLES(Int64); +} + +fmi3Status fmi3GetUInt64(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetUInt64); + GET_VARIABLES(UInt64); +} + +fmi3Status fmi3GetBoolean(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Boolean values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetBoolean); + GET_VARIABLES(Boolean); +} + +fmi3Status fmi3GetString(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3String values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(GetString); + GET_VARIABLES(String); +} + +fmi3Status fmi3GetBinary(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + size_t valueSizes[], + fmi3Binary values[], + size_t nValues) +{ + + UNUSED(nValues); + + ASSERT_STATE(GetBinary); + + Status status = OK; + + for (size_t i = 0; i < nValueReferences; i++) { + size_t index = 0; + Status s = getBinary(S, (ValueReference) valueReferences[i], valueSizes, (const char **) values, &index); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + } + + return (fmi3Status) status; +} + +fmi3Status fmi3GetClock(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Clock values[]) +{ + + ASSERT_STATE(GetClock); + + Status status = OK; + + for (size_t i = 0; i < nValueReferences; i++) { + Status s = getClock(instance, (ValueReference) valueReferences[i], &values[i]); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + } + + return (fmi3Status) status; +} + +fmi3Status fmi3SetFloat32(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float32 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetFloat32); + SET_VARIABLES(Float32); +} + +fmi3Status fmi3SetFloat64(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetFloat64); + SET_VARIABLES(Float64); +} + +fmi3Status fmi3SetInt8(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int8 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetInt8); + SET_VARIABLES(Int8); +} + +fmi3Status fmi3SetUInt8(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt8 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetUInt8); + SET_VARIABLES(UInt8); +} + +fmi3Status fmi3SetInt16(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int16 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetInt16); + SET_VARIABLES(Int16); +} + +fmi3Status fmi3SetUInt16(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt16 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetUInt16); + SET_VARIABLES(UInt16); +} + +fmi3Status fmi3SetInt32(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetInt32); + SET_VARIABLES(Int32); +} + +fmi3Status fmi3SetUInt32(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt32 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetUInt32); + SET_VARIABLES(UInt32); +} + +fmi3Status fmi3SetInt64(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int64 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetInt64); + SET_VARIABLES(Int64); +} + +fmi3Status fmi3SetUInt64(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetUInt64); + SET_VARIABLES(UInt64); +} + +fmi3Status fmi3SetBoolean(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Boolean values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetBoolean); + SET_VARIABLES(Boolean); +} + +fmi3Status fmi3SetString(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3String values[], + size_t nValues) +{ + + UNUSED(nValues); + ASSERT_STATE(SetString); + SET_VARIABLES(String); +} + +fmi3Status fmi3SetBinary(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const size_t valueSizes[], + const fmi3Binary values[], + size_t nValues) +{ + + UNUSED(nValues); + + ASSERT_STATE(SetBinary); + + Status status = OK; + + for (size_t i = 0; i < nValueReferences; i++) { + size_t index = 0; + Status s = setBinary(S, (ValueReference) valueReferences[i], valueSizes, (const char *const *) values, &index); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + } + + return (fmi3Status) status; +} + +fmi3Status fmi3SetClock(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Clock values[]) +{ + + ASSERT_STATE(SetClock); + + Status status = OK; + + for (size_t i = 0; i < nValueReferences; i++) { + if (values[i]) { + Status s = activateClock(instance, (ValueReference) valueReferences[i]); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + } + } + + return (fmi3Status) status; +} + +fmi3Status fmi3GetNumberOfVariableDependencies(fmi3Instance instance, + fmi3ValueReference valueReference, + size_t * nDependencies) +{ + UNUSED(valueReference); + UNUSED(nDependencies); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3GetVariableDependencies(fmi3Instance instance, + fmi3ValueReference dependent, + size_t elementIndicesOfDependent[], + fmi3ValueReference independents[], + size_t elementIndicesOfIndependents[], + fmi3DependencyKind dependencyKinds[], + size_t nDependencies) +{ + + UNUSED(dependent); + UNUSED(elementIndicesOfDependent); + UNUSED(independents); + UNUSED(elementIndicesOfIndependents); + UNUSED(dependencyKinds); + UNUSED(nDependencies); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3GetFMUState(fmi3Instance instance, fmi3FMUState *FMUState) +{ + + ASSERT_STATE(GetFMUState); + + *FMUState = getFMUState(S); + + return fmi3OK; +} + +fmi3Status fmi3SetFMUState(fmi3Instance instance, fmi3FMUState FMUState) +{ + + ASSERT_STATE(SetFMUState); + + if (nullPointer(S, "fmi3SetFMUState", "FMUState", FMUState)) { + return fmi3Error; + } + + setFMUState(S, FMUState); + + return fmi3OK; +} + +fmi3Status fmi3FreeFMUState(fmi3Instance instance, fmi3FMUState *FMUState) +{ + + ASSERT_STATE(FreeFMUState); + + free(*FMUState); + + *FMUState = NULL; + + return fmi3OK; +} + +fmi3Status fmi3SerializedFMUStateSize(fmi3Instance instance, + fmi3FMUState FMUState, + size_t * size) +{ + + UNUSED(instance); + UNUSED(FMUState); + + ASSERT_STATE(SerializedFMUStateSize); + + *size = sizeof(ModelInstance); + + return fmi3OK; +} + +fmi3Status fmi3SerializeFMUState(fmi3Instance instance, + fmi3FMUState FMUState, + fmi3Byte serializedState[], + size_t size) +{ + + ASSERT_STATE(SerializeFMUState); + + if (nullPointer(S, "fmi3SerializeFMUState", "FMUstate", FMUState)) { + return fmi3Error; + } + + if (invalidNumber(S, "fmi3SerializeFMUState", "size", size, sizeof(ModelInstance))) { + return fmi3Error; + } + + memcpy(serializedState, FMUState, sizeof(ModelInstance)); + + return fmi3OK; +} + +fmi3Status fmi3DeserializeFMUState(fmi3Instance instance, + const fmi3Byte serializedState[], + size_t size, + fmi3FMUState * FMUState) +{ + + ASSERT_STATE(DeserializeFMUState); + + if (invalidNumber(S, "fmi3DeserializeFMUState", "size", size, sizeof(ModelInstance))) { + return fmi3Error; + } + + if (*FMUState == NULL) { + *FMUState = calloc(1, sizeof(ModelInstance)); + } + + memcpy(*FMUState, serializedState, sizeof(ModelInstance)); + + return fmi3OK; +} + +fmi3Status fmi3GetDirectionalDerivative(fmi3Instance instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity) +{ + + UNUSED(nSeed); + UNUSED(nSensitivity); + + ASSERT_STATE(GetDirectionalDerivative); + + // TODO: check value references + // TODO: assert nUnknowns == nDeltaOfUnknowns + // TODO: assert nKnowns == nDeltaKnowns + + Status status = OK; + + for (size_t i = 0; i < nUnknowns; i++) { + sensitivity[i] = 0; + for (size_t j = 0; j < nKnowns; j++) { + double partialDerivative = 0; + Status s = getPartialDerivative(S, (ValueReference) unknowns[i], (ValueReference) knowns[j], &partialDerivative); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + sensitivity[i] += partialDerivative * seed[j]; + } + } + + return fmi3OK; +} + +fmi3Status fmi3GetAdjointDerivative(fmi3Instance instance, + const fmi3ValueReference unknowns[], + size_t nUnknowns, + const fmi3ValueReference knowns[], + size_t nKnowns, + const fmi3Float64 seed[], + size_t nSeed, + fmi3Float64 sensitivity[], + size_t nSensitivity) +{ + + UNUSED(nSeed); + UNUSED(nSensitivity); + + ASSERT_STATE(GetAdjointDerivative); + + // TODO: check value references + + Status status = OK; + + for (size_t i = 0; i < nKnowns; i++) { + sensitivity[i] = 0; + for (size_t j = 0; j < nUnknowns; j++) { + double partialDerivative = 0; + Status s = getPartialDerivative(S, (ValueReference) unknowns[j], (ValueReference) knowns[i], &partialDerivative); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + sensitivity[i] += partialDerivative * seed[j]; + } + } + + return fmi3OK; +} + +fmi3Status fmi3EnterConfigurationMode(fmi3Instance instance) +{ + + ASSERT_STATE(EnterConfigurationMode); + + S->state = (S->state == Instantiated) ? ConfigurationMode : ReconfigurationMode; + + return fmi3OK; +} + +fmi3Status fmi3ExitConfigurationMode(fmi3Instance instance) +{ + + ASSERT_STATE(ExitConfigurationMode); + + if (S->state == ConfigurationMode) { + S->state = Instantiated; + } else { + switch (S->type) { + case ModelExchange: + S->state = EventMode; + break; + case CoSimulation: + S->state = StepMode; + break; + case ScheduledExecution: + S->state = ClockActivationMode; + break; + } + } + + return fmi3OK; +} + +fmi3Status fmi3GetIntervalDecimal(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 intervals[], + fmi3IntervalQualifier qualifiers[]) +{ + + ASSERT_STATE(GetIntervalDecimal); + + // ? Check nValueReferences != nValues + Status status = OK; + + for (size_t i = 0; i < nValueReferences; i++) { + Status s = getInterval(instance, (ValueReference) valueReferences[i], &intervals[i], (int *) &qualifiers[i]); + status = max(status, s); + if (status > Warning) + return (fmi3Status) status; + } + + return (fmi3Status) status; +} + +fmi3Status fmi3GetIntervalFraction(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 intervalCounters[], + fmi3UInt64 resolutions[], + fmi3IntervalQualifier qualifiers[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(intervalCounters); + UNUSED(resolutions); + UNUSED(qualifiers); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3GetShiftDecimal(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3Float64 shifts[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(shifts); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3GetShiftFraction(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + fmi3UInt64 shiftCounters[], + fmi3UInt64 resolutions[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(shiftCounters); + UNUSED(resolutions); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3SetIntervalDecimal(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 intervals[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(intervals); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3SetIntervalFraction(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 intervalCounters[], + const fmi3UInt64 resolutions[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(intervalCounters); + UNUSED(resolutions); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3SetShiftDecimal(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Float64 shifts[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(shifts); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3SetShiftFraction(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3UInt64 shiftCounters[], + const fmi3UInt64 resolutions[]) +{ + + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(shiftCounters); + UNUSED(resolutions); + + NOT_IMPLEMENTED; +} + +fmi3Status fmi3EvaluateDiscreteStates(fmi3Instance instance) +{ + NOT_IMPLEMENTED; +} + +fmi3Status fmi3UpdateDiscreteStates(fmi3Instance instance, + fmi3Boolean *discreteStatesNeedUpdate, + fmi3Boolean *terminateSimulation, + fmi3Boolean *nominalsOfContinuousStatesChanged, + fmi3Boolean *valuesOfContinuousStatesChanged, + fmi3Boolean *nextEventTimeDefined, + fmi3Float64 *nextEventTime) +{ + + ASSERT_STATE(NewDiscreteStates); + +#ifdef EVENT_UPDATE + eventUpdate(S); +#endif + + // copy internal eventInfo of component to output arguments + if (discreteStatesNeedUpdate) + *discreteStatesNeedUpdate = S->newDiscreteStatesNeeded; + if (terminateSimulation) + *terminateSimulation = S->terminateSimulation; + if (nominalsOfContinuousStatesChanged) + *nominalsOfContinuousStatesChanged = S->nominalsOfContinuousStatesChanged; + if (valuesOfContinuousStatesChanged) + *valuesOfContinuousStatesChanged = S->valuesOfContinuousStatesChanged; + if (nextEventTimeDefined) + *nextEventTimeDefined = S->nextEventTimeDefined; + if (nextEventTime) + *nextEventTime = S->nextEventTime; + + return fmi3OK; +} + +/*************************************************** + Functions for Model Exchange + ****************************************************/ + +fmi3Status fmi3EnterContinuousTimeMode(fmi3Instance instance) +{ + + ASSERT_STATE(EnterContinuousTimeMode); + + S->state = ContinuousTimeMode; + + return fmi3OK; +} + +fmi3Status fmi3CompletedIntegratorStep(fmi3Instance instance, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *enterEventMode, + fmi3Boolean *terminateSimulation) +{ + + UNUSED(noSetFMUStatePriorToCurrentPoint); + + ASSERT_STATE(CompletedIntegratorStep); + + ASSERT_NOT_NULL(enterEventMode); + ASSERT_NOT_NULL(terminateSimulation); + + *enterEventMode = fmi3False; + *terminateSimulation = fmi3False; + + return fmi3OK; +} + +/* Providing independent variables and re-initialization of caching */ +fmi3Status fmi3SetTime(fmi3Instance instance, fmi3Float64 time) +{ + + ASSERT_STATE(SetTime); + + S->time = time; + + return fmi3OK; +} + +fmi3Status fmi3SetContinuousStates(fmi3Instance instance, + const fmi3Float64 continuousStates[], + size_t nContinuousStates) +{ + + ASSERT_STATE(SetContinuousStates); + + if (invalidNumber(S, "fmi3SetContinuousStates", "nContinuousStates", nContinuousStates, NX)) + return fmi3Error; + + ASSERT_NOT_NULL(continuousStates); + + setContinuousStates(S, continuousStates, nContinuousStates); + + return fmi3OK; +} + +/* Evaluation of the model equations */ +fmi3Status fmi3GetContinuousStateDerivatives(fmi3Instance instance, + fmi3Float64 derivatives[], + size_t nContinuousStates) +{ + + ASSERT_STATE(GetContinuousStateDerivatives); + + if (invalidNumber(S, "fmi3GetContinuousStateDerivatives", "nContinuousStates", nContinuousStates, NX)) + return fmi3Error; + + if (nullPointer(S, "fmi3GetContinuousStateDerivatives", "derivatives[]", derivatives)) + return fmi3Error; + + getDerivatives(S, derivatives, nContinuousStates); + + return fmi3OK; +} + +fmi3Status fmi3GetEventIndicators(fmi3Instance instance, + fmi3Float64 eventIndicators[], + size_t nEventIndicators) +{ + + ASSERT_STATE(GetEventIndicators); + +#if NZ > 0 + if (invalidNumber(S, "fmi3GetEventIndicators", "nEventIndicators", nEventIndicators, NZ)) { + return fmi3Error; + } + + getEventIndicators(S, eventIndicators, nEventIndicators); +#else + + UNUSED(eventIndicators); + + if (nEventIndicators > 0) { + // TODO: log error + return fmi3Error; + } +#endif + + return fmi3OK; +} + +fmi3Status fmi3GetContinuousStates(fmi3Instance instance, + fmi3Float64 continuousStates[], + size_t nContinuousStates) +{ + + ASSERT_STATE(GetContinuousStates); + + if (invalidNumber(S, "fmi3GetContinuousStates", "nContinuousStates", nContinuousStates, NX)) + return fmi3Error; + + if (nullPointer(S, "fmi3GetContinuousStates", "continuousStates[]", continuousStates)) + return fmi3Error; + + getContinuousStates(S, continuousStates, nContinuousStates); + + return fmi3OK; +} + +fmi3Status fmi3GetNominalsOfContinuousStates(fmi3Instance instance, + fmi3Float64 nominals[], + size_t nContinuousStates) +{ + + ASSERT_STATE(GetNominalsOfContinuousStates); + + if (invalidNumber(S, "fmi3GetNominalContinuousStates", "nContinuousStates", nContinuousStates, NX)) + return fmi3Error; + + if (nullPointer(S, "fmi3GetNominalContinuousStates", "nominals[]", nominals)) + return fmi3Error; + + for (size_t i = 0; i < nContinuousStates; i++) { + nominals[i] = 1; + } + + return fmi3OK; +} + +fmi3Status fmi3GetNumberOfEventIndicators(fmi3Instance instance, + size_t * nEventIndicators) +{ + + ASSERT_STATE(GetNumberOfEventIndicators); + + ASSERT_NOT_NULL(nEventIndicators); + + *nEventIndicators = NZ; + + return fmi3OK; +} + +fmi3Status fmi3GetNumberOfContinuousStates(fmi3Instance instance, + size_t * nContinuousStates) +{ + + ASSERT_STATE(GetNumberOfContinuousStates); + + ASSERT_NOT_NULL(nContinuousStates); + + *nContinuousStates = NX; + + return fmi3OK; +} + +/*************************************************** + Functions for Co-Simulation + ****************************************************/ + +fmi3Status fmi3EnterStepMode(fmi3Instance instance) +{ + + ASSERT_STATE(EnterStepMode); + + S->state = StepMode; + + return fmi3OK; +} + +fmi3Status fmi3GetOutputDerivatives(fmi3Instance instance, + const fmi3ValueReference valueReferences[], + size_t nValueReferences, + const fmi3Int32 orders[], + fmi3Float64 values[], + size_t nValues) +{ + + UNUSED(nValues); + + ASSERT_STATE(GetOutputDerivatives); + +#ifdef GET_OUTPUT_DERIVATIVE + + Status status = OK; + + for (size_t i = 0; i < nValueReferences; i++) { + const Status s = getOutputDerivative(S, (ValueReference) valueReferences[i], orders[i], &values[i]); + status = max(status, s); + if (status > Warning) { + return (fmi3Status) status; + } + } + + return (fmi3Status) status; + +#else + UNUSED(valueReferences); + UNUSED(nValueReferences); + UNUSED(orders); + UNUSED(values); + + NOT_IMPLEMENTED; +#endif +} + +fmi3Status fmi3DoStep(fmi3Instance instance, + fmi3Float64 currentCommunicationPoint, + fmi3Float64 communicationStepSize, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *eventHandlingNeeded, + fmi3Boolean *terminateSimulation, + fmi3Boolean *earlyReturn, + fmi3Float64 *lastSuccessfulTime) +{ + + UNUSED(noSetFMUStatePriorToCurrentPoint); + + ASSERT_STATE(DoStep); + + if (communicationStepSize <= 0) { + logError(S, "fmi3DoStep: communication step size must be > 0 but was %g.", communicationStepSize); + S->state = modelError; + return fmi3Error; + } + + const fmi3Float64 nextCommunicationPoint = currentCommunicationPoint + communicationStepSize + EPSILON; + + S->solverStepSize = communicationStepSize; + + fmi3Boolean nextCommunicationPointReached; + + *eventHandlingNeeded = fmi3False; + + while (true) { + + nextCommunicationPointReached = S->time + S->solverStepSize > nextCommunicationPoint; + + if (nextCommunicationPointReached) { + break; + } + + bool stateEvent, timeEvent; + + doAdaptiveStep(S, &stateEvent, &timeEvent); + +#ifdef EVENT_UPDATE + if (stateEvent || timeEvent) { + + *eventHandlingNeeded = fmi3True; + + if (S->eventModeUsed) { + break; + } + + eventUpdate(S); + + if (S->earlyReturnAllowed) { + break; + } + } +#endif + } + + *earlyReturn = !nextCommunicationPointReached; + + *terminateSimulation = fmi3False; + + *lastSuccessfulTime = S->time; + + return fmi3OK; +} + +fmi3Status fmi3ActivateModelPartition(fmi3Instance instance, + fmi3ValueReference clockReference, + fmi3Float64 activationTime) +{ + + ASSERT_STATE(ActivateModelPartition); + + return (fmi3Status) activateModelPartition(S, (ValueReference) clockReference, activationTime); +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/fmu/thirdparty/LICENSE.txt b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/thirdparty/LICENSE.txt new file mode 100644 index 000000000..d2ff5fb89 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/fmu/thirdparty/LICENSE.txt @@ -0,0 +1,148 @@ +Copyright (c) 2022, Modelica Association Project "FMI". +All rights reserved. + +The Reference FMUs and FMUSim are released under the 2-Clause BSD license: + +-------------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDi +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. +-------------------------------------------------------------------------------- + +The Reference FMUs are a fork of the Test FMUs (https://github.com/CATIA-Systems/Test-FMUs) +by Dassault Systemes, which are a fork of the FMU SDK (https://github.com/qtronic/fmusdk) +by QTronic, both released under the 2-Clause BSD License. + +FMUSim uses the following third party libraries. + +================================================================================ + +Libxml2 (https://gitlab.gnome.org/GNOME/libxml2) released under the MIT license: + +Except where otherwise noted in the source code (e.g. the files hash.c, +list.c and the trio files, which are covered by a similar licence but +with different Copyright notices) all the files are: + + Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +================================================================================ + +Zlib (http://zlib.net/) release under the zlib license: + +Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + +================================================================================ + +CSV-fast-reader (https://github.com/jandoczy/csv-fast-reader) release under the +MIT license: + +Copyright (c) 2019 Jan Doczy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +================================================================================ + +SUNDIALS: SUite of Nonlinear and DIfferential/ALgebraic equation Solvers +(https://computing.llnl.gov/projects/sundials) release under the BSD 3-Clause license: + +Copyright (c) 2002-2022, Lawrence Livermore National Security and Southern Methodist University. +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. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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 HOLDER 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. + + +The FMI header files are copyright (c) 2008-2011 MODELISAR consortium, 2012-2022 +the Modelica Association Project "FMI" and released under the 2-Clause BSD License. diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/precice-settings.json b/flow-around-controlled-moving-cylinder/controller-fmi/precice-settings.json new file mode 100644 index 000000000..b962b5fdc --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/precice-settings.json @@ -0,0 +1,9 @@ +{ + "coupling_params": { + "participant_name": "Controller", + "config_file_name": "../precice-config.xml", + "mesh_name": "Mesh-Controller", + "write_data_name": "Displacement-Spring", + "read_data_name": "Displacement-Cylinder" + } +} diff --git a/flow-around-controlled-moving-cylinder/controller-fmi/run.sh b/flow-around-controlled-moving-cylinder/controller-fmi/run.sh new file mode 100755 index 000000000..0b55398ac --- /dev/null +++ b/flow-around-controlled-moving-cylinder/controller-fmi/run.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e -u + +if [ ! -f PIDcontroller.fmu ]; then + cd fmu + rm -rf build + mkdir build + cd build + cmake -DFMI_TYPE=CS -DFMI_VERSION=3 .. + make + cp ./PIDcontroller.fmu ../.. + cd ../../ +fi + +fmiprecice ./fmi-settings.json ./precice-settings.json diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/U b/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/U new file mode 100644 index 000000000..871adb944 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/U @@ -0,0 +1,44 @@ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object U; +} + +dimensions [0 1 -1 0 0 0 0]; + +internalField uniform (0.068018 0 0); + + +boundaryField +{ + topAndBottom + { + type slip; + } + + inlet + { + type fixedValue; + value $internalField; + } + + outlet + { + type zeroGradient; + } + + frontAndBack + { + type empty; + } + + + cylinder + { + type movingWallVelocity; + value uniform (0 0 0); + } + +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/p b/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/p new file mode 100644 index 000000000..0445a8ee8 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/p @@ -0,0 +1,41 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} + +dimensions [0 2 -2 0 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + + topAndBottom + { + type zeroGradient; + } + + outlet + { + type zeroGradient; + } + + inlet + { + type zeroGradient; + } + + frontAndBack + { + type empty; + } + + cylinder + { + type zeroGradient; + } + +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/pointDisplacement b/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/pointDisplacement new file mode 100644 index 000000000..95801a57d --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/0.orig/pointDisplacement @@ -0,0 +1,44 @@ +FoamFile +{ + version 2.0; + format ascii; + class pointVectorField; + location "0.01"; + object pointDisplacement; +} + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + topAndBottom + { + type fixedValue; + value $internalField; + } + + inlet + { + type fixedValue; + value $internalField; + } + + outlet + { + type fixedValue; + value $internalField; + } + + cylinder + { + type fixedValue; + value $internalField; + } + + frontAndBack + { + type empty; + } +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/clean.sh b/flow-around-controlled-moving-cylinder/fluid-openfoam/clean.sh new file mode 100755 index 000000000..59919cb21 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/clean.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e -u + +. ../../tools/cleaning-tools.sh + +# since we work with a 0_orig folder here +rm -rf 0 + +clean_openfoam . diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/dynamicMeshDict b/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/dynamicMeshDict new file mode 100644 index 000000000..c5a915d37 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/dynamicMeshDict @@ -0,0 +1,19 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} + +motionSolverLibs ("libfvMotionSolvers.so"); + +dynamicFvMesh dynamicMotionSolverFvMesh; + +solver displacementLaplacian; +// OpenFOAM9 or newer: rename "solver" to "motionSolver" + +displacementLaplacianCoeffs +{ + diffusivity inverseDistance 1(cylinder); +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/transportProperties b/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/transportProperties new file mode 100644 index 000000000..69ccd8336 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/transportProperties @@ -0,0 +1,11 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object transportProperties; +} + +transportModel Newtonian; + +nu nu [ 0 2 -1 0 0 0 0 ] 1.0e-06; diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/turbulenceProperties b/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/turbulenceProperties new file mode 100644 index 000000000..8271e5f76 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/constant/turbulenceProperties @@ -0,0 +1,10 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object turbulenceProperties; +} + +simulationType laminar; diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/run.sh b/flow-around-controlled-moving-cylinder/fluid-openfoam/run.sh new file mode 100755 index 000000000..797f27984 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/run.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -e -u + +blockMesh +transformPoints -scale '(0.0016 0.0016 1)' +transformPoints -translate '(0.0 0.0 -0.05)' + +rm -rf 0 +cp -r 0.orig 0 + +touch fluid-openfoam.foam + +../../tools/run-openfoam.sh "$@" +. ../../tools/openfoam-remove-empty-dirs.sh && openfoam_remove_empty_dirs diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/blockMeshDict b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/blockMeshDict new file mode 100644 index 000000000..0e2ec196f --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/blockMeshDict @@ -0,0 +1,303 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} + +convertToMeters 0.1; + +vertices +( +//z=0 +//inner circle + (5 0 0) //0 + (3.535533906 3.535533906 0) //1 + (0 5 0) //2 + (-3.535533906 3.535533906 0) //3 + (-5 0 0) //4 + (-3.535533906 -3.535533906 0) //5 + (0 -5 0) //6 + (3.535533906 -3.535533906 0) //7 + +//outer circle + (30 0 0) //8 + (21.21320344 21.21320344 0) //9 + (0 30 0) //10 + (-21.21320344 21.21320344 0) //11 + (-30 0 0) //12 + (-21.21320344 -21.21320344 0) //13 + (0 -30 0) //14 + (21.21320344 -21.21320344 0) //15 + +//rectangle + (400 0 0) //16 + (400 21.21320344 0) //17 + (400 200 0) //18 + (21.21320344 200 0) //19 + (0 200 0) //20 + (-21.21320344 200 0) //21 + (-200 200 0) //22 + (-200 21.21320344 0) //23 + (-200 0 0) //24 + (-200 -21.21320344 0) //25 + (-200 -200 0) //26 + (-21.21320344 -200 0) //27 + (0 -200 0) //28 + (21.21320344 -200 0) //29 + (400 -200 0) //30 + (400 -21.21320344 0) //31 + + +//z=1 +//inner circle + (5 0 1) //32 + (3.535533906 3.535533906 1) //33 + (0 5 1) //34 + (-3.535533906 3.535533906 1) //35 + (-5 0 1) //36 + (-3.535533906 -3.535533906 1) //37 + (0 -5 1) //38 + (3.535533906 -3.535533906 1) //39 + +//outer circle + (30 0 1) //40 + (21.21320344 21.21320344 1) //41 + (0 30 1) //42 + (-21.21320344 21.21320344 1) //43 + (-30 0 1) //44 + (-21.21320344 -21.21320344 1) //45 + (0 -30 1) //46 + (21.21320344 -21.21320344 1) //47 + +//rectangle + (400 0 1) //48 + (400 21.21320344 1) //49 + (400 200 1) //50 + (21.21320344 200 1) //51 + (0 200 1) //52 + (-21.21320344 200 1) //53 + (-200 200 1) //54 + (-200 21.21320344 1) //55 + (-200 0 1) //56 + (-200 -21.21320344 1) //57 + (-200 -200 1) //58 + (-21.21320344 -200 1) //59 + (0 -200 1) //60 + (21.21320344 -200 1) //61 + (400 -200 1) //62 + (400 -21.21320344 1) //63 +); + +blocks +( + hex (1 0 8 9 33 32 40 41) (15 51 1) simpleGrading (1 8 1) //Block 0 + hex (2 1 9 10 34 33 41 42) (15 51 1) simpleGrading (1 8 1) //Block 1 + hex (3 2 10 11 35 34 42 43) (15 51 1) simpleGrading (1 8 1) //Block 2 + hex (4 3 11 12 36 35 43 44) (15 51 1) simpleGrading (1 8 1) //Block 3 + hex (5 4 12 13 37 36 44 45) (15 51 1) simpleGrading (1 8 1) //Block 4 + hex (6 5 13 14 38 37 45 46) (15 51 1) simpleGrading (1 8 1) //Block 5 + hex (7 6 14 15 39 38 46 47) (15 51 1) simpleGrading (1 8 1) //Block 6 + hex (0 7 15 8 32 39 47 40) (15 51 1) simpleGrading (1 8 1) //Block 7 + hex (8 16 17 9 40 48 49 41) (32 15 1) simpleGrading (50 1 1) //Block 8 + hex (9 17 18 19 41 49 50 51) (32 28 1) simpleGrading (50 20 1) //Block 9 + hex (10 9 19 20 42 41 51 52) (15 28 1) simpleGrading (1 20 1) //Block 10 + hex (11 10 20 21 43 42 52 53) (15 28 1) simpleGrading (1 20 1) //Block 11 + hex (23 11 21 22 55 43 53 54) (25 28 1) simpleGrading (.03 20 1) //Block 12 + hex (24 12 11 23 56 44 43 55) (25 15 1) simpleGrading (.03 1 1) //Block 13 + hex (25 13 12 24 57 45 44 56) (25 15 1) simpleGrading (.03 1 1) //Block 14 + hex (26 27 13 25 58 59 45 57) (25 28 1) simpleGrading (.03 0.05 1) //Block 15 + hex (27 28 14 13 59 60 46 45) (15 28 1) simpleGrading (1 0.05 1) //Block 16 + hex (28 29 15 14 60 61 47 46) (15 28 1) simpleGrading (1 0.05 1) //Block 17 + hex (29 30 31 15 61 62 63 47) (32 28 1) simpleGrading (50 0.05 1) //Block 18 + hex (15 31 16 8 47 63 48 40) (32 15 1) simpleGrading (50 1 1) //Block 19 +); + +edges +( + //inner cylinder surface + arc 0 1 (4 3 0) + arc 32 33 (4 3 1) + + arc 1 2 (3 4 0) + arc 33 34 (3 4 1) + + arc 2 3 (-3 4 0) + arc 34 35 (-3 4 1) + + arc 3 4 (-4 3 0) + arc 35 36 (-4 3 1) + + arc 4 5 (-4 -3 0) + arc 36 37 (-4 -3 1) + + arc 5 6 (-3 -4 0) + arc 37 38 (-3 -4 1) + + arc 6 7 (3 -4 0) + arc 38 39 (3 -4 1) + + arc 7 0 (4 -3 0) + arc 39 32 (4 -3 1) + + //outer cylinder surface + arc 8 9 (24 18 0) + arc 40 41 (24 18 1) + + arc 9 10 (18 24 0) + arc 41 42 (18 24 1) + + arc 10 11 (-18 24 0) + arc 42 43 (-18 24 1) + + arc 11 12 (-24 18 0) + arc 43 44 (-24 18 1) + + arc 12 13 (-24 -18 0) + arc 44 45 (-24 -18 1) + + arc 13 14 (-18 -24 0) + arc 45 46 (-18 -24 1) + + arc 14 15 (18 -24 0) + arc 46 47 (18 -24 1) + + arc 15 8 (24 -18 0) + arc 47 40 (24 -18 1) + +); + +boundary +( + inlet + { + type patch; + faces + ( + (22 23 55 54) + (23 24 56 55) + (24 25 57 56) + (25 26 58 57) + ); + } + + outlet + { + type patch; + faces + ( + (30 31 63 62) + (31 16 48 63) + (16 17 49 48) + (17 18 50 49) + ); + } + + topAndBottom + { + type patch; + faces + ( + (18 19 51 50) + (19 20 52 51) + (20 21 53 52) + (21 22 54 53) + + (26 27 59 58) + (27 28 60 59) + (28 29 61 60) + (29 30 62 61) + ); + } + + + cylinder + { + type wall; + faces + ( + (1 0 32 33) + (2 1 33 34) + (3 2 34 35) + (4 3 35 36) + (5 4 36 37) + (6 5 37 38) + (7 6 38 39) + (0 7 39 32) + ); + } + + frontAndBack + { + type empty; + faces + ( +//circular faces + (0 1 9 8) + (32 40 41 33) + + (1 2 10 9) + (33 41 42 34) + + (2 3 11 10) + (34 42 43 35) + + (3 4 12 11) + (35 43 44 36) + + (4 5 13 12) + (36 44 45 37) + + (5 6 14 13) + (37 45 46 38) + + (6 7 15 14) + (38 46 47 39) + + (7 0 8 15) + (39 47 40 32) + +//rectangular faces + (8 9 17 16) + (40 48 49 41) + + (9 19 18 17) + (41 49 50 51) + + (9 10 20 19) + (41 51 52 42) + + (10 11 21 20) + (42 52 53 43) + + (11 23 22 21) + (43 53 54 55) + + (11 12 24 23) + (43 55 56 44) + + (12 13 25 24) + (44 56 57 45) + + (13 27 26 25) + (45 57 58 59) + + (13 14 28 27) + (45 59 60 46) + + (14 15 29 28) + (46 60 61 47) + + (15 31 30 29) + (47 61 62 63) + + (15 8 16 31) + (47 63 48 40) + ); + } +); + +mergePatchPairs +( +); diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/controlDict b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/controlDict new file mode 100644 index 000000000..fd21869a4 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/controlDict @@ -0,0 +1,52 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} + +application pimpleFoam; + +startFrom latestTime; + +startTime 0; + +stopAt endTime; + +endTime 7; + +deltaT 0.00025; + +writeControl adjustableRunTime; + +writeInterval .5; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 6; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable no; + +adjustTimeStep no; + +maxCo 0.75; + +functions +{ + #includeFunc forces + preCICE_Adapter + { + type preciceAdapterFunctionObject; + libs ("libpreciceAdapterFunctionObject.so"); + } +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/decomposeParDict b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/decomposeParDict new file mode 100644 index 000000000..4b1bd487c --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/decomposeParDict @@ -0,0 +1,16 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object decomposeParDict; +} + +numberOfSubdomains 4; +method simple; + +simpleCoeffs +{ + n (2 2 1); + delta 0.001; +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/forces b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/forces new file mode 100644 index 000000000..ec62b36a9 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/forces @@ -0,0 +1,13 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +Description + Calculates pressure and viscous forces over specified patches for a case + where the solver is incompressible (pressure is kinematic, e.g. m^2/s^2). +\*---------------------------------------------------------------------------*/ + +#includeEtc "caseDicts/postProcessing/forces/forcesIncompressible.cfg" +log yes; +rho rhoInf; // Indicates incompressible +rhoInf 1000; // Redundant for incompressible +patches (cylinder); +CofR (0 0 0); +pitchAxis (0 0 1); diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSchemes b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSchemes new file mode 100644 index 000000000..76aabdcfe --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSchemes @@ -0,0 +1,42 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} + +ddtSchemes +{ + default backward; +} + +gradSchemes +{ + default Gauss linear; +} + +divSchemes +{ + default none; + div(phi,U) Gauss cubic; + div((nuEff*dev(T(grad(U))))) Gauss linear; + div((nuEff*dev2(T(grad(U))))) Gauss linear; +} + +laplacianSchemes +{ + default Gauss linear corrected; + laplacian(diffusivity,cellMotionU) Gauss linear uncorrected; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default corrected; +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSolution b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSolution new file mode 100644 index 000000000..d76563980 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/fvSolution @@ -0,0 +1,116 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} + +solvers +{ + pcorr + { + solver GAMG; + tolerance 0.02; + relTol 0; + smoother GaussSeidel; + nPreSweeps 0; + nPostSweeps 2; + cacheAgglomeration no; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + } + + p + { + solver GAMG; + tolerance 0; + relTol 0.01; + smoother GaussSeidel; + nPreSweeps 0; + nPostSweeps 2; + cacheAgglomeration no; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + } + + pFinal + { + $p; + tolerance 1e-06; + relTol 0; + } + + pcorrFinal + { + $pcorr; + tolerance 1e-06; + relTol 0; + } + U + { + solver smoothSolver; + smoother symGaussSeidel; + tolerance 1e-05; + relTol 0.01; + } + + UFinal + { + $U; + tolerance 1e-05; + relTol 0; + } + + cellMotionUx + { + solver PCG; + preconditioner DIC; + tolerance 1e-08; + relTol 0; + } + cellMotionUxFinal + { + solver PCG; + preconditioner DIC; + tolerance 1e-08; + relTol 0; + } + + "cellDisplacement.*" + { + solver GAMG; + tolerance 1e-5; + relTol 0; + smoother GaussSeidel; + cacheAgglomeration true; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + } + +} + +PIMPLE +{ + correctPhi yes; + nOuterCorrectors 3; + nCorrectors 1; + nNonOrthogonalCorrectors 0; + pRefCell 1001; + pRefValue 0; +} + +relaxationFactors +{ + fields + { + } + equations + { + "U.*" 1; + } +} diff --git a/flow-around-controlled-moving-cylinder/fluid-openfoam/system/preciceDict b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/preciceDict new file mode 100644 index 000000000..1185752c1 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/fluid-openfoam/system/preciceDict @@ -0,0 +1,40 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object preciceDict; +} + +preciceConfig "../precice-config.xml"; + +participant Fluid; + +modules (FSI); + +interfaces +{ + Interface1 + { + mesh Mesh-Fluid; + locations faceCenters; + patches (cylinder); + + readData + ( + Displacement-Cylinder + ); + + writeData + ( + Force + ); + }; +}; + +FSI +{ + rho rho [1 -3 0 0 0 0 0] 1000; + nu nu [ 0 2 -1 0 0 0 0 ] 1.0e-06; +} diff --git a/flow-around-controlled-moving-cylinder/images/tutorials-flow-around-controlled-moving-cylinder-setup.png b/flow-around-controlled-moving-cylinder/images/tutorials-flow-around-controlled-moving-cylinder-setup.png new file mode 100644 index 0000000000000000000000000000000000000000..4f4568310c0b43f6cbe65b4b5224d88ee9efe710 GIT binary patch literal 22535 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 WaclU-wPZI?1B0ilpUXO@geCykNr)Q& literal 0 HcmV?d00001 diff --git a/flow-around-controlled-moving-cylinder/images/tutorials-flow-around-controlled-moving-cylinder-watchpoint.png b/flow-around-controlled-moving-cylinder/images/tutorials-flow-around-controlled-moving-cylinder-watchpoint.png new file mode 100644 index 0000000000000000000000000000000000000000..9b4ddbbf2f1069a3323394a30c137d8648843472 GIT binary patch literal 123068 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

d16bKFFp!_ZcN-cTAI}|zm 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 z

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

M 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-around-controlled-moving-cylinder/solid-python/clean.sh b/flow-around-controlled-moving-cylinder/solid-python/clean.sh new file mode 100755 index 000000000..fa3b754f1 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/solid-python/clean.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +. ../../tools/cleaning-tools.sh +clean_precice_logs . diff --git a/flow-around-controlled-moving-cylinder/solid-python/run.sh b/flow-around-controlled-moving-cylinder/solid-python/run.sh new file mode 100755 index 000000000..dbf7a6708 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/solid-python/run.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e -u + + +python3 solid.py ../precice-config.xml + diff --git a/flow-around-controlled-moving-cylinder/solid-python/solid.py b/flow-around-controlled-moving-cylinder/solid-python/solid.py new file mode 100644 index 000000000..6bbfa13f3 --- /dev/null +++ b/flow-around-controlled-moving-cylinder/solid-python/solid.py @@ -0,0 +1,105 @@ +from __future__ import division + +import argparse +import numpy as np +import precice + +parser = argparse.ArgumentParser() +parser.add_argument("configurationFileName", default="../precice-config.xml", + help="Name of the xml config file.", type=str) + +try: + args = parser.parse_args() + print(args) +except SystemExit: + print("") + print("Usage: python3 ./solverdummy.py precice-config.xml") + quit() + +# mass-spring-damper system parameters +mass = 0.03575 # kg +k_spring = 69.48 # N/m +d_damper = 0.0043 # N s/m + +state_old = np.zeros(3) +state = np.zeros(3) + + +def update(m, k, d, state, dt, force, controlled_spring_displacement): + x_old, v_old, a_old = state + x = x_old + v_old * dt + 0.5 * a_old * dt**2 + a = (force - d * v_old - k * x + k * controlled_spring_displacement) / m + v = v_old + 0.5 * (a_old + a) * dt + return np.array([x, v, a]) + + +configuration_file_name = args.configurationFileName + +participant_name = "Solid" +write_data_name = "Displacement-Cylinder" +read_data_name_force = "Force" +read_data_name_displacement = "Displacement-Spring" +mesh_name = "Mesh-Solid" + +num_vertices = 1 # Number of vertices +solver_process_index = 0 +solver_process_size = 1 + +participant = precice.Participant(participant_name, configuration_file_name, + solver_process_index, solver_process_size) + +assert (not participant.requires_mesh_connectivity_for(mesh_name)) + +dimensions = participant.get_mesh_dimensions(mesh_name) + +vertices = np.zeros((num_vertices, dimensions)) +read_data_force = np.zeros((num_vertices, dimensions)) +read_data_displacement = np.zeros((num_vertices, dimensions)) +write_data = np.zeros((num_vertices, dimensions)) + +vertex_ids = participant.set_mesh_vertices(mesh_name, vertices) + +# initialize data +if participant.requires_initial_data(): + participant.write_data(mesh_name, write_data_name, vertex_ids, write_data) + +participant.initialize() +t = 0 + +while participant.is_coupling_ongoing(): + if participant.requires_writing_checkpoint(): + print("Writing checkpoint") + state_old_cp = state_old + state_cp = state + + dt = participant.get_max_time_step_size() + + read_data_force = participant.read_data(mesh_name, read_data_name_force, vertex_ids, dt) + force = read_data_force[0, 1] + read_data_displacement = participant.read_data(mesh_name, read_data_name_displacement, vertex_ids, dt) + displacement_spring = read_data_displacement[0, 1] + + # compute next time step + state = update(mass, k_spring, d_damper, state_old, dt, force, displacement_spring) + + # cylinder is fixed in x-direction + write_data[0, 0] = 0 + + # cylinder moves in y-direction according to spring-damper-mass-equation + write_data[0, 1] = state[0] + + participant.write_data(mesh_name, write_data_name, vertex_ids, write_data) + + print("Solid: Advancing in time") + participant.advance(dt) + + if participant.requires_reading_checkpoint(): + print("Reading checkpoint") + state_old = state_old_cp + state = state_cp + + else: + state_old = state + t = t + dt + +participant.finalize()