From 6aea220b1f268e658072e8a0a9bfd58aaf8b25af Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 6 Apr 2019 14:05:39 +0200 Subject: [PATCH 01/28] Fix causality of v_min in BouncingBall (fixes #2) --- BouncingBall/FMI2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index cea915b..85ddac3 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -60,7 +60,7 @@ - + From 25abcff55dfce9e24381af20816eb055ff8d2330 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sun, 7 Apr 2019 13:06:16 +0200 Subject: [PATCH 02/28] Set /MT flag only for Visual Studio --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cecbe6..a1e7ec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ if (${FMI_VERSION} GREATER 1) set(FMI_TYPE "") endif () -if (WIN32) +if (MSVC) string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "/MDd" "/MTd" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") endif () From 904bc97870d0d58e2a4ea105bdddd4fbec9ca27a Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Mon, 27 May 2019 21:50:11 +0200 Subject: [PATCH 03/28] Fix resource path for URI scheme2 as suggested by @StefanOltean see #4 --- Resource/model.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Resource/model.c b/Resource/model.c index 222ef3f..21c22d5 100644 --- a/Resource/model.c +++ b/Resource/model.c @@ -31,15 +31,16 @@ void calculateValues(ModelInstance *comp) { if (strncmp(comp->resourceLocation, scheme1, strlen(scheme1)) == 0) { path = malloc(strlen(comp->resourceLocation) + strlen(resourcePath) + 1); strcpy(path, &comp->resourceLocation[strlen(scheme1)] - 1); - strcat(path, resourcePath); } else if (strncmp(comp->resourceLocation, scheme2, strlen(scheme2)) == 0) { path = malloc(strlen(comp->resourceLocation) + strlen(resourcePath) + 1); strcpy(path, &comp->resourceLocation[strlen(scheme2) - 1]); - } else { + } else { logError(comp, "The resourceLocation must start with \"file:/\" or \"file:///\""); return; } + strcat(path, resourcePath); + #ifdef _WIN32 // strip any leading slashes while (path[0] == '/') { From b41b343c2e4748dc146ea0e2b0f8b0f62fa3dc56 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Mon, 27 May 2019 21:58:54 +0200 Subject: [PATCH 04/28] Update eventInfo in fmiInitialize() as suggested by @StefanOltean see #4 --- src/fmi1.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/fmi1.c b/src/fmi1.c index 96dd423..aa891a4 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -555,7 +555,16 @@ fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID, fmiCal } fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance, fmiEventInfo* eventInfo) { - return init(c); + ModelInstance *comp = (ModelInstance *)c; + + eventInfo->iterationConverged = fmiTrue; + eventInfo->stateValueReferencesChanged = fmiFalse; + eventInfo->stateValuesChanged = fmiFalse; + eventInfo->terminateSimulation = fmiFalse; + eventInfo->upcomingTimeEvent = comp->nextEventTimeDefined; + eventInfo->nextEventTime = comp->nextEventTime; + + return init(c); } fmiStatus fmiSetTime(fmiComponent c, fmiReal time) { From 0fb1f65f7938b745efedf78ced68d45d05e52ec0 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Mon, 27 May 2019 21:59:29 +0200 Subject: [PATCH 05/28] Use return value of init() in fmiInitializeSlave() as suggested by @StefanOltean see #4 --- src/fmi1.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fmi1.c b/src/fmi1.c index aa891a4..eab117b 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -429,8 +429,7 @@ fmiComponent fmiInstantiateSlave(fmiString instanceName, fmiString GUID, } fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) { - init(c); - return fmiOK; + return init(c); } fmiStatus fmiTerminateSlave(fmiComponent c) { From 32775ec2b62f103af3292ad8501189d337be1e12 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Wed, 29 May 2019 10:24:08 +0200 Subject: [PATCH 06/28] Add description attributes --- BouncingBall/FMI1CS.xml | 9 ++++++++- BouncingBall/FMI1ME.xml | 17 ++++++++++++----- BouncingBall/FMI2.xml | 19 +++++++++++-------- Dahlquist/FMI1CS.xml | 9 ++++++++- Dahlquist/FMI1ME.xml | 9 ++++++++- Dahlquist/FMI2.xml | 7 ++++++- Feedthrough/FMI1CS.xml | 9 ++++++++- Feedthrough/FMI1ME.xml | 9 ++++++++- Feedthrough/FMI2.xml | 7 ++++++- Resource/FMI1CS.xml | 9 ++++++++- Resource/FMI1ME.xml | 9 ++++++++- Resource/FMI2.xml | 7 ++++++- Stair/FMI1CS.xml | 9 ++++++++- Stair/FMI1ME.xml | 9 ++++++++- Stair/FMI2.xml | 7 ++++++- VanDerPol/FMI1CS.xml | 9 ++++++++- VanDerPol/FMI1ME.xml | 9 ++++++++- VanDerPol/FMI2.xml | 7 ++++++- 18 files changed, 141 insertions(+), 29 deletions(-) diff --git a/BouncingBall/FMI1CS.xml b/BouncingBall/FMI1CS.xml index c26d9f8..ae512ad 100644 --- a/BouncingBall/FMI1CS.xml +++ b/BouncingBall/FMI1CS.xml @@ -1,5 +1,12 @@ - + diff --git a/BouncingBall/FMI1ME.xml b/BouncingBall/FMI1ME.xml index f9a3f48..3cacebb 100644 --- a/BouncingBall/FMI1ME.xml +++ b/BouncingBall/FMI1ME.xml @@ -1,19 +1,26 @@ - + - + - + - + - + diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index 85ddac3..d28dbc9 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -1,5 +1,10 @@ - + @@ -19,8 +24,6 @@ - - @@ -48,19 +51,19 @@ - + - + - + - + - + diff --git a/Dahlquist/FMI1CS.xml b/Dahlquist/FMI1CS.xml index 6184a42..806a349 100644 --- a/Dahlquist/FMI1CS.xml +++ b/Dahlquist/FMI1CS.xml @@ -1,5 +1,12 @@ - + diff --git a/Dahlquist/FMI1ME.xml b/Dahlquist/FMI1ME.xml index 91da018..8be2932 100644 --- a/Dahlquist/FMI1ME.xml +++ b/Dahlquist/FMI1ME.xml @@ -1,5 +1,12 @@ - + diff --git a/Dahlquist/FMI2.xml b/Dahlquist/FMI2.xml index 4058249..4d5d8e5 100644 --- a/Dahlquist/FMI2.xml +++ b/Dahlquist/FMI2.xml @@ -1,5 +1,10 @@ - + diff --git a/Feedthrough/FMI1CS.xml b/Feedthrough/FMI1CS.xml index 7ad2fdc..e23eb2e 100644 --- a/Feedthrough/FMI1CS.xml +++ b/Feedthrough/FMI1CS.xml @@ -1,5 +1,12 @@ - + diff --git a/Feedthrough/FMI1ME.xml b/Feedthrough/FMI1ME.xml index 67d8cbd..445784e 100644 --- a/Feedthrough/FMI1ME.xml +++ b/Feedthrough/FMI1ME.xml @@ -1,5 +1,12 @@ - + diff --git a/Feedthrough/FMI2.xml b/Feedthrough/FMI2.xml index 1148851..9cedd2e 100644 --- a/Feedthrough/FMI2.xml +++ b/Feedthrough/FMI2.xml @@ -1,5 +1,10 @@ - + diff --git a/Resource/FMI1CS.xml b/Resource/FMI1CS.xml index 1dbba64..538eef7 100644 --- a/Resource/FMI1CS.xml +++ b/Resource/FMI1CS.xml @@ -1,5 +1,12 @@ - + diff --git a/Resource/FMI1ME.xml b/Resource/FMI1ME.xml index cfd4092..8bacb67 100644 --- a/Resource/FMI1ME.xml +++ b/Resource/FMI1ME.xml @@ -1,5 +1,12 @@ - + diff --git a/Resource/FMI2.xml b/Resource/FMI2.xml index d495fe6..9b8601a 100644 --- a/Resource/FMI2.xml +++ b/Resource/FMI2.xml @@ -1,5 +1,10 @@ - + diff --git a/Stair/FMI1CS.xml b/Stair/FMI1CS.xml index f451379..27cff66 100644 --- a/Stair/FMI1CS.xml +++ b/Stair/FMI1CS.xml @@ -1,5 +1,12 @@ - + diff --git a/Stair/FMI1ME.xml b/Stair/FMI1ME.xml index 484bc1e..1a938c9 100644 --- a/Stair/FMI1ME.xml +++ b/Stair/FMI1ME.xml @@ -1,5 +1,12 @@ - + diff --git a/Stair/FMI2.xml b/Stair/FMI2.xml index 13afed4..515baec 100644 --- a/Stair/FMI2.xml +++ b/Stair/FMI2.xml @@ -1,5 +1,10 @@ - + diff --git a/VanDerPol/FMI1CS.xml b/VanDerPol/FMI1CS.xml index c316805..aa5f005 100644 --- a/VanDerPol/FMI1CS.xml +++ b/VanDerPol/FMI1CS.xml @@ -1,5 +1,12 @@ - + diff --git a/VanDerPol/FMI1ME.xml b/VanDerPol/FMI1ME.xml index 4cfc35c..305e170 100644 --- a/VanDerPol/FMI1ME.xml +++ b/VanDerPol/FMI1ME.xml @@ -1,5 +1,12 @@ - + diff --git a/VanDerPol/FMI2.xml b/VanDerPol/FMI2.xml index 4fb5005..0c61f7d 100644 --- a/VanDerPol/FMI2.xml +++ b/VanDerPol/FMI2.xml @@ -1,5 +1,10 @@ - + From 68472c713e0b6cfb363ba88af581f360144f5d38 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 1 Jun 2019 14:59:32 +0200 Subject: [PATCH 07/28] Set up CI with Azure Pipelines - remove AppVeyor configuration - build FMUs with Visual Studio 2017 on Windows - add build status badge --- README.md | 2 + appveyor.yml | 9 --- azure-pipelines.yml | 151 ++++++++++++++++++++++++++++++++++++++++++++ test_build.py | 2 +- 4 files changed, 154 insertions(+), 10 deletions(-) delete mode 100644 appveyor.yml create mode 100644 azure-pipelines.yml diff --git a/README.md b/README.md index 8923f7b..b2f737b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ # Test FMUs +[![Build Status](https://dev.azure.com/CATIA-Systems/Test-FMUs/_apis/build/status/CATIA-Systems.Test-FMUs?branchName=develop)](https://dev.azure.com/CATIA-Systems/Test-FMUs/_build/latest?definitionId=2&branchName=develop) + A set of test models for development, testing and debugging of the [Functional Mock-up Interface](https://fmi-standard.org/). - [BouncingBall](BouncingBall) - a bouncing ball model with state events diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 73cba9d..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,9 +0,0 @@ -image: Visual Studio 2015 - -build: false - -install: - - pip install fmpy - -test_script: - - python test_build.py diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..f611af3 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,151 @@ +jobs: + +- job: + displayName: 'Ubuntu 16.04' + pool: + vmImage: 'ubuntu-16.04' + steps: + - bash: echo "##vso[task.prependpath]$CONDA/bin" + displayName: Add conda to PATH + + - bash: conda create --yes --quiet --name myEnvironment + displayName: Create Anaconda environment + + - bash: | + source activate myEnvironment + conda install --yes --quiet --name myEnvironment -c conda-forge python=3.7 fmpy pytest scipy + displayName: Install Anaconda packages + + - bash: | + source activate myEnvironment + pytest --junitxml=junit/test-results.xml + displayName: Build and run tests + + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testResultsFiles: '**/test-*.xml' + testRunTitle: 'Publish test results' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi1_cs/dist' + artifactName: 'linux64-fmi1_cs' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi1_me/dist' + artifactName: 'linux64-fmi1_me' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi2/dist' + artifactName: 'linux64-fmi2' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi3/dist' + artifactName: 'linux64-fmi3' + +- job: + displayName: 'macOS 10.13' + pool: + vmImage: 'macos-10.13' + + steps: + + - bash: echo "##vso[task.prependpath]$CONDA/bin" + displayName: Add conda to PATH + + # On Hosted macOS, the agent user doesn't have ownership of Miniconda's installation directory/ + # We need to take ownership if we want to update conda or install packages globally + - bash: sudo chown -R $USER $CONDA + displayName: Take ownership of conda installation + + - bash: conda create --yes --quiet --name myEnvironment + displayName: Create Anaconda environment + + - bash: | + source activate myEnvironment + conda install --yes --quiet --name myEnvironment -c conda-forge python=3.7 fmpy pytest scipy + displayName: Install Anaconda packages + + - bash: | + source activate myEnvironment + pytest --junitxml=junit/test-results.xml + displayName: Build and run tests + + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testResultsFiles: '**/test-*.xml' + testRunTitle: 'Publish test results' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi1_cs/dist' + artifactName: 'darwin64-fmi1_cs' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi1_me/dist' + artifactName: 'darwin64-fmi1_me' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi2/dist' + artifactName: 'darwin64-fmi2' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi3/dist' + artifactName: 'darwin64-fmi3' + +- job: + displayName: 'Windows 2016' + pool: + vmImage: 'vs2017-win2016' + + steps: + + - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" + displayName: Add conda to PATH + + - script: conda create --yes --quiet --name myEnvironment + displayName: Create Anaconda environment + + - script: | + call activate myEnvironment + conda install --yes --quiet --name myEnvironment -c conda-forge python=3.7 cmake fmpy pytest scipy + displayName: Install Anaconda packages + + - script: | + call activate myEnvironment + pytest --junitxml=junit/test-results.xml + displayName: Build, install and run tests + + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testResultsFiles: '**/test-*.xml' + testRunTitle: 'Publish test results' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi1_cs/dist' + artifactName: 'win64-fmi1_cs' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi1_me/dist' + artifactName: 'win64-fmi1_me' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi2/dist' + artifactName: 'win64-fmi2' + + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: 'fmi3/dist' + artifactName: 'win64-fmi3' diff --git a/test_build.py b/test_build.py index b2830e1..f091d15 100644 --- a/test_build.py +++ b/test_build.py @@ -32,7 +32,7 @@ models = ['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol', 'Feedthrough'] if os.name == 'nt': - generator = 'Visual Studio 14 2015 Win64' + generator = 'Visual Studio 15 2017 Win64' else: generator = 'Unix Makefiles' From df7b0443befd17db26a144a63ff1819ed29c3c07 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Tue, 4 Jun 2019 10:49:49 +0200 Subject: [PATCH 08/28] Free path in Resource model --- Resource/model.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Resource/model.c b/Resource/model.c index 21c22d5..f695e19 100644 --- a/Resource/model.c +++ b/Resource/model.c @@ -12,15 +12,15 @@ void setStartValues(ModelInstance *comp) { void calculateValues(ModelInstance *comp) { // load the file - FILE *file; - char *path; - char c; + FILE *file = NULL; + char *path = NULL; + char c = '\0'; const char *scheme1 = "file:///"; const char *scheme2 = "file:/"; #if FMI_VERSION < 2 - char *resourcePath = "/resources/y.txt"; + const char *resourcePath = "/resources/y.txt"; #else - char *resourcePath = "/y.txt"; + const char *resourcePath = "/y.txt"; #endif if (!comp->resourceLocation) { @@ -62,8 +62,11 @@ void calculateValues(ModelInstance *comp) { // assign it to y comp->modelData->y = c; - // clost the file + // close the file fclose(file); + + // clean up + free(path); } Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { From c29f1602e0c3a59f360f6d9aa22817cf7ada3d0f Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Tue, 4 Jun 2019 10:39:43 +0200 Subject: [PATCH 09/28] Use fixed solver step for co-simulation --- BouncingBall/FMI2.xml | 2 +- BouncingBall/FMI3.xml | 2 +- BouncingBall/config.h | 2 ++ Dahlquist/FMI2.xml | 2 +- Dahlquist/FMI3.xml | 2 +- Dahlquist/config.h | 2 ++ Feedthrough/config.h | 2 ++ LinearTransform/config.h | 2 ++ Resource/config.h | 2 ++ Stair/FMI2.xml | 2 +- Stair/FMI3.xml | 2 +- Stair/config.h | 2 ++ Stair/model.c | 2 +- VanDerPol/FMI2.xml | 2 +- VanDerPol/FMI3.xml | 2 +- VanDerPol/config.h | 2 ++ src/slave.c | 17 +++++------------ 17 files changed, 28 insertions(+), 21 deletions(-) diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index d28dbc9..83ae546 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -48,7 +48,7 @@ - + diff --git a/BouncingBall/FMI3.xml b/BouncingBall/FMI3.xml index 230887a..f2bae32 100644 --- a/BouncingBall/FMI3.xml +++ b/BouncingBall/FMI3.xml @@ -20,7 +20,7 @@ - + diff --git a/BouncingBall/config.h b/BouncingBall/config.h index c5bd308..c51b22c 100644 --- a/BouncingBall/config.h +++ b/BouncingBall/config.h @@ -13,6 +13,8 @@ #define SET_FLOAT64 #define EVENT_UPDATE +#define FIXED_SOLVER_STEP 1e-2 + typedef enum { vr_h, vr_v, vr_g, vr_e, vr_v_min } ValueReference; diff --git a/Dahlquist/FMI2.xml b/Dahlquist/FMI2.xml index 4d5d8e5..d492573 100644 --- a/Dahlquist/FMI2.xml +++ b/Dahlquist/FMI2.xml @@ -31,7 +31,7 @@ - + diff --git a/Dahlquist/FMI3.xml b/Dahlquist/FMI3.xml index 4e57dd3..12379cf 100644 --- a/Dahlquist/FMI3.xml +++ b/Dahlquist/FMI3.xml @@ -26,7 +26,7 @@ - + diff --git a/Dahlquist/config.h b/Dahlquist/config.h index 43c4bbf..52bb1da 100644 --- a/Dahlquist/config.h +++ b/Dahlquist/config.h @@ -13,6 +13,8 @@ #define SET_FLOAT64 #define EVENT_UPDATE +#define FIXED_SOLVER_STEP 0.1 + typedef enum { vr_x, vr_der_x, vr_k } ValueReference; diff --git a/Feedthrough/config.h b/Feedthrough/config.h index a54f8a1..01d8fb3 100644 --- a/Feedthrough/config.h +++ b/Feedthrough/config.h @@ -24,6 +24,8 @@ #define EVENT_UPDATE +#define FIXED_SOLVER_STEP 1 + typedef enum { vr_fixed_real_parameter, vr_tunable_real_parameter, diff --git a/LinearTransform/config.h b/LinearTransform/config.h index 2b359de..057fc5d 100644 --- a/LinearTransform/config.h +++ b/LinearTransform/config.h @@ -13,6 +13,8 @@ #define SET_FLOAT64 #define EVENT_UPDATE +#define FIXED_SOLVER_STEP 1 + typedef enum { vr_m, vr_n, vr_u, vr_A, vr_y } ValueReference; diff --git a/Resource/config.h b/Resource/config.h index 1e52d53..4e509a7 100644 --- a/Resource/config.h +++ b/Resource/config.h @@ -11,6 +11,8 @@ #define GET_FLOAT64 +#define FIXED_SOLVER_STEP 1 + typedef enum { vr_y } ValueReference; diff --git a/Stair/FMI2.xml b/Stair/FMI2.xml index 515baec..61dca10 100644 --- a/Stair/FMI2.xml +++ b/Stair/FMI2.xml @@ -31,7 +31,7 @@ - + diff --git a/Stair/FMI3.xml b/Stair/FMI3.xml index d72be8c..c9598c9 100644 --- a/Stair/FMI3.xml +++ b/Stair/FMI3.xml @@ -26,7 +26,7 @@ - + diff --git a/Stair/config.h b/Stair/config.h index f5aafa5..6aed4be 100644 --- a/Stair/config.h +++ b/Stair/config.h @@ -12,6 +12,8 @@ #define GET_INT32 #define EVENT_UPDATE +#define FIXED_SOLVER_STEP 0.2 + typedef enum { vr_counter } ValueReference; diff --git a/Stair/model.c b/Stair/model.c index 6b9fca0..03dddc5 100644 --- a/Stair/model.c +++ b/Stair/model.c @@ -26,7 +26,7 @@ Status getInt32(ModelInstance* comp, ValueReference vr, int *value, size_t *inde void eventUpdate(ModelInstance *comp) { - if (comp->nextEventTimeDefined && comp->nextEventTime == comp->time) { + if (comp->nextEventTimeDefined && comp->time >= comp->nextEventTime) { M(counter)++; comp->nextEventTime += 1; } diff --git a/VanDerPol/FMI2.xml b/VanDerPol/FMI2.xml index 0c61f7d..c2d25ee 100644 --- a/VanDerPol/FMI2.xml +++ b/VanDerPol/FMI2.xml @@ -31,7 +31,7 @@ - + diff --git a/VanDerPol/FMI3.xml b/VanDerPol/FMI3.xml index 5ee6162..61c6ef2 100644 --- a/VanDerPol/FMI3.xml +++ b/VanDerPol/FMI3.xml @@ -26,7 +26,7 @@ - + diff --git a/VanDerPol/config.h b/VanDerPol/config.h index 636bca8..fa16b17 100644 --- a/VanDerPol/config.h +++ b/VanDerPol/config.h @@ -12,6 +12,8 @@ #define GET_FLOAT64 #define SET_FLOAT64 +#define FIXED_SOLVER_STEP 1e-2 + typedef enum { vr_x0, vr_der_x0, vr_x1, vr_der_x1, vr_mu } ValueReference; diff --git a/src/slave.c b/src/slave.c index 4053821..50713e0 100644 --- a/src/slave.c +++ b/src/slave.c @@ -70,25 +70,18 @@ void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) {} void getDerivatives(ModelInstance *comp, double dx[], size_t nx) {} #endif - Status doStep(ModelInstance *comp, double t, double tNext) { int stateEvent = 0; int timeEvent = 0; - comp->time = t; - - while (comp->time < tNext) { - - if (comp->nextEventTimeDefined && comp->nextEventTime < tNext) { - solver_step(comp, comp->time, comp->nextEventTime, &comp->time, &stateEvent); - } else { - solver_step(comp, comp->time, tNext, &comp->time, &stateEvent); - } + while (comp->time + FIXED_SOLVER_STEP < tNext) { + + solver_step(comp, comp->time, comp->time + FIXED_SOLVER_STEP, &comp->time, &stateEvent); // check for time event - if (comp->nextEventTimeDefined && (comp->time - comp->nextEventTime > -1e-5)) { - timeEvent = true; + if (comp->nextEventTimeDefined && (comp->time >= comp->nextEventTime)) { + timeEvent = 1; } if (stateEvent || timeEvent) { From 3ea4d9a717ee7924b104f57274d518a5bd6dfd14 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Wed, 12 Jun 2019 19:41:01 +0200 Subject: [PATCH 10/28] Reduce step size for BouncingBall Fix stepSize for BouncingBall --- BouncingBall/FMI2.xml | 2 +- BouncingBall/FMI3.xml | 2 +- BouncingBall/config.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index 83ae546..c036df6 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -48,7 +48,7 @@ - + diff --git a/BouncingBall/FMI3.xml b/BouncingBall/FMI3.xml index f2bae32..45d4892 100644 --- a/BouncingBall/FMI3.xml +++ b/BouncingBall/FMI3.xml @@ -20,7 +20,7 @@ - + diff --git a/BouncingBall/config.h b/BouncingBall/config.h index c51b22c..82b382b 100644 --- a/BouncingBall/config.h +++ b/BouncingBall/config.h @@ -13,7 +13,7 @@ #define SET_FLOAT64 #define EVENT_UPDATE -#define FIXED_SOLVER_STEP 1e-2 +#define FIXED_SOLVER_STEP 1e-3 typedef enum { vr_h, vr_v, vr_g, vr_e, vr_v_min From bdc71292df0391761714e1c4ed965fa58dc673bf Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Wed, 12 Jun 2019 20:02:19 +0200 Subject: [PATCH 11/28] Use fixed step size and move solver to slave.c --- CMakeLists.txt | 6 ++-- include/model.h | 5 ++- include/solver.h | 13 -------- src/euler.c | 83 ------------------------------------------------ src/fmi2.c | 14 ++++++-- src/slave.c | 38 ++++++++++++++++++++-- 6 files changed, 52 insertions(+), 107 deletions(-) delete mode 100644 include/solver.h delete mode 100644 src/euler.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a1e7ec4..fff2590 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,13 +75,11 @@ set(TARGET_NAME ${MODEL_NAME}) SET(HEADERS ${MODEL_NAME}/config.h include/model.h - include/solver.h ) SET(SOURCES ${MODEL_NAME}/model.c src/fmi${FMI_VERSION}.c - src/euler.c src/slave.c ) @@ -163,7 +161,7 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E ) # common headers -foreach (SOURCE_FILE model.h slave.h solver.h) +foreach (SOURCE_FILE model.h slave.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}" @@ -171,7 +169,7 @@ foreach (SOURCE_FILE model.h slave.h solver.h) endforeach(SOURCE_FILE) # common sources -foreach (SOURCE_FILE fmi${FMI_VERSION}.c euler.c slave.c) +foreach (SOURCE_FILE fmi${FMI_VERSION}.c slave.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}" diff --git a/include/model.h b/include/model.h index 82b033c..d584551 100644 --- a/include/model.h +++ b/include/model.h @@ -103,7 +103,10 @@ typedef struct { bool isNewEventIteration; ModelData *modelData; - void *solverData; + + // event indicators + double *z; + double *prez; } ModelInstance; diff --git a/include/solver.h b/include/solver.h deleted file mode 100644 index 3740f36..0000000 --- a/include/solver.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef solver_h -#define solver_h - -#include "config.h" -#include "model.h" - - -void *solver_create(ModelInstance *comp); -void solver_step(ModelInstance *comp, double t, double tNext, double *tRet, int *stateEvent); -void solver_reset(ModelInstance *comp); - - -#endif /* solver_h */ diff --git a/src/euler.c b/src/euler.c deleted file mode 100644 index d5b3bc5..0000000 --- a/src/euler.c +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************** - * Copyright (c) Dassault Systemes. All rights reserved. * - * This file is part of the Test-FMUs. See LICENSE.txt in the * - * project root for license information. * - ****************************************************************/ - -#include "solver.h" -#include - - -typedef struct { - int nx; - int nz; - double *x; - double *dx; - double *z; - double *prez; -} SolverData; - -void *solver_create(ModelInstance *comp) { - SolverData *s = (SolverData *)calloc(1, sizeof(SolverData)); - s->nx = NUMBER_OF_STATES; - s->nz = NUMBER_OF_EVENT_INDICATORS; - s->x = (double *)calloc(s->nx, sizeof(double)); - s->dx = (double *)calloc(s->nx, sizeof(double)); - s->z = (double *)calloc(s->nz, sizeof(double)); - s->prez = (double *)calloc(s->nz, sizeof(double)); - return s; -} - -void solver_step(ModelInstance *comp, double t, double tNext, double *tRet, int *stateEvent) { - - SolverData *s = (SolverData *)comp->solverData; - - // step size - const double h = tNext - t; - - double *temp; - - // set continuous states - getContinuousStates(comp, s->x, s->nx); - - // get derivatives - getDerivatives(comp, s->dx, s->nx); - - // forward Euler step - for (int i = 0; i < s->nx; i++) { - s->x[i] += h * s->dx[i]; - } - - // tNext has been reached - *tRet = tNext; - - // set continuous states - setContinuousStates(comp, s->x, s->nx); - - // get event indicators - getEventIndicators(comp, s->z, s->nz); - - *stateEvent = false; - - // check for zero-crossing - for (int i = 0; i < s->nz; i++) { - *stateEvent |= (s->prez[i] * s->z[i]) <= 0; - } - - // remember the current event indicators - temp = s->z; - s->z = s->prez; - s->prez = temp; -} - -void solver_reset(ModelInstance *comp) { - - SolverData *s = (SolverData *)comp->solverData; - - // set continuous states - setContinuousStates(comp, s->x, s->nx); - - // get event indicators - getEventIndicators(comp, s->z, s->nz); - -} diff --git a/src/fmi2.c b/src/fmi2.c index 478586b..a154c0e 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -11,7 +11,6 @@ #include "config.h" #include "model.h" -#include "solver.h" #include "slave.h" @@ -295,7 +294,13 @@ fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2Str setStartValues(comp); // to be implemented by the includer of this file comp->isDirtyValues = true; // because we just called setStartValues - comp->solverData = solver_create(comp); +#if NUMBER_OF_EVENT_INDICATORS > 0 + comp->z = functions->allocateMemory(sizeof(double), NUMBER_OF_EVENT_INDICATORS); + comp->prez = functions->allocateMemory(sizeof(double), NUMBER_OF_EVENT_INDICATORS); +#else + comp->z = NULL; + comp->prez = NULL; +#endif FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2Instantiate: GUID=%s", fmuGUID) @@ -384,7 +389,10 @@ void fmi2FreeInstance(fmi2Component c) { FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2FreeInstance") if (comp->instanceName) comp->freeMemory((void *)comp->instanceName); - if (comp->GUID) comp->freeMemory((void *)comp->GUID); + if (comp->GUID) comp->freeMemory((void *)comp->GUID); + if (comp->z) comp->freeMemory((void *)comp->z); + if (comp->prez) comp->freeMemory((void *)comp->prez); + comp->freeMemory(comp); } diff --git a/src/slave.c b/src/slave.c index 50713e0..dd77023 100644 --- a/src/slave.c +++ b/src/slave.c @@ -6,7 +6,6 @@ #include "config.h" #include "slave.h" -#include "solver.h" // default implementations @@ -74,10 +73,42 @@ Status doStep(ModelInstance *comp, double t, double tNext) { int stateEvent = 0; int timeEvent = 0; + double *temp = NULL; - while (comp->time + FIXED_SOLVER_STEP < tNext) { +#if NUMBER_OF_STATES > 0 + double x[NUMBER_OF_STATES] = { 0 }; + double dx[NUMBER_OF_STATES] = { 0 }; +#endif + + while (comp->time + FIXED_SOLVER_STEP < tNext + 0.1 * FIXED_SOLVER_STEP) { - solver_step(comp, comp->time, comp->time + FIXED_SOLVER_STEP, &comp->time, &stateEvent); +#if NUMBER_OF_STATES > 0 + getContinuousStates(comp, x, NUMBER_OF_STATES); + getDerivatives(comp, dx, NUMBER_OF_STATES); + + // forward Euler step + for (int i = 0; i < NUMBER_OF_STATES; i++) { + x[i] += FIXED_SOLVER_STEP * dx[i]; + } + + setContinuousStates(comp, x, NUMBER_OF_STATES); +#endif + + stateEvent = 0; + +#if NUMBER_OF_EVENT_INDICATORS > 0 + getEventIndicators(comp, comp->z, NUMBER_OF_EVENT_INDICATORS); + + // check for zero-crossing + for (int i = 0; i < NUMBER_OF_EVENT_INDICATORS; i++) { + stateEvent |= (comp->prez[i] * comp->z[i]) <= 0; + } + + // remember the current event indicators + temp = comp->z; + comp->z = comp->prez; + comp->prez = temp; +#endif // check for time event if (comp->nextEventTimeDefined && (comp->time >= comp->nextEventTime)) { @@ -98,6 +129,7 @@ Status doStep(ModelInstance *comp, double t, double tNext) { return Discard; // enforce termination of the simulation loop } + comp->time += FIXED_SOLVER_STEP; } return OK; From fcb9de577b6c61075d1c70099d39df83926e9415 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 15:28:38 +0200 Subject: [PATCH 12/28] Add create/freeModelInstance() --- include/model.h | 41 +++++++++----- src/fmi1.c | 147 +++++++++--------------------------------------- src/fmi2.c | 115 +++++-------------------------------- src/fmi3.c | 143 ++++------------------------------------------ src/slave.c | 133 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 367 deletions(-) diff --git a/include/model.h b/include/model.h index d584551..3db4ad6 100644 --- a/include/model.h +++ b/include/model.h @@ -64,27 +64,28 @@ typedef enum { Pending } Status; +#if FMI_VERSION < 3 +typedef void (*loggerType) (void *componentEnvironment, const char *instanceName, int status, const char *category, const char *message, ...); +typedef void* (*allocateMemoryType)(size_t nobj, size_t size); +typedef void (*freeMemoryType) (void *obj); +#else +typedef void (*loggerType) (void *componentEnvironment, const char *instanceName, int status, const char *category, const char *message); +typedef void* (*allocateMemoryType)(void *componentEnvironment, size_t nobj, size_t size); +typedef void (*freeMemoryType) (void *componentEnvironment, void *obj); +#endif typedef struct { double time; const char *instanceName; InterfaceType type; - const char *GUID; const char *resourceLocation; - // callback functions -#if FMI_VERSION < 3 - void (*logger)(void *, const char *, int, const char *, const char *, ...); - void* (*allocateMemory)(size_t, size_t); - void (*freeMemory)(void *); - void (*stepFinished)(void *, int); -#else - void (*logger)(void *, const char *, int, const char *, const char *, ...); - void* (*allocateMemory)(void *, size_t, size_t); - void (*freeMemory)(void *, void *); - void (*stepFinished)(void *, void *, int); -#endif + // callback functions + loggerType logger; + allocateMemoryType allocateMemory; + freeMemoryType freeMemory; + bool loggingOn; bool logCategories[NUMBER_OF_CATEGORIES]; @@ -110,6 +111,18 @@ typedef struct { } ModelInstance; +ModelInstance *createModelInstance( + loggerType logger, + allocateMemoryType allocateMemory, + freeMemoryType freeMemory, + void *componentEnvironment, + const char *instanceName, + const char *GUID, + const char *resourceLocation, + bool loggingOn, + InterfaceType interfaceType); +void freeModelInstance(ModelInstance *comp); + void setStartValues(ModelInstance *comp); void calculateValues(ModelInstance *comp); @@ -130,7 +143,7 @@ void getEventIndicators(ModelInstance *comp, double z[], size_t nz); void eventUpdate(ModelInstance *comp); void logError(ModelInstance *comp, const char *message, ...); -void *allocateMemory(ModelInstance *comp, size_t size); +void *allocateMemory(ModelInstance *comp, size_t num, size_t size); void freeMemory(ModelInstance *comp, void *obj); const char *duplicateString(ModelInstance *comp, const char *str1); diff --git a/src/fmi1.c b/src/fmi1.c index eab117b..736b14e 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -11,7 +11,6 @@ #include "config.h" #include "model.h" -#include "solver.h" #include "slave.h" @@ -21,11 +20,6 @@ #include "fmiModelFunctions.h" #endif -//// array of value references of states -//#if NUMBER_OF_STATES>0 -//fmiValueReference vrStates[NUMBER_OF_STATES] = STATES; -//#endif - #ifndef max #define max(a,b) ((a)>(b) ? (a) : (b)) #endif @@ -59,21 +53,6 @@ void logError(ModelInstance *comp, const char *message, ...) { free(buf); } -void *allocateMemory(ModelInstance *comp, size_t size) { - return comp->allocateMemory(size, 1); -} - -void freeMemory(ModelInstance *comp, void *obj) { - comp->freeMemory(obj); -} - -const char *duplicateString(ModelInstance *comp, const char *str1) { - size_t len = strlen(str1); - char *str2 = allocateMemory(comp, len + 1); - strncpy(str2, str1, len + 1); - return str2; -} - static fmiBoolean invalidNumber(ModelInstance* comp, const char* f, const char* arg, int n, int nExpected){ if (n != nExpected) { comp->state = modelError; @@ -110,87 +89,6 @@ static fmiBoolean nullPointer(ModelInstance* comp, const char* f, const char* ar // Private helpers used below to implement functions // --------------------------------------------------------------------------- -// fname is fmiInstantiateModel or fmiInstantiateSlave -static fmiComponent instantiateModel(char* fname, fmiString instanceName, fmiString GUID, - fmiString fmuLocation, fmiCallbackFunctions functions, fmiBoolean loggingOn) { - - ModelInstance* comp; - - if (!functions.logger) - return NULL; // we cannot even log this problem - - if (!instanceName || strlen(instanceName) == 0) { - functions.logger(NULL, "?", fmiError, "error", - "%s: Missing instance name.", fname); - return NULL; - } - - if (!GUID || strlen(GUID) == 0) { - functions.logger(NULL, instanceName, fmiError, "error", - "%s: Missing GUID.", fname); - return NULL; - } - -#if CO_SIMULATION - if (!fmuLocation || strlen(fmuLocation) == 0) { - functions.logger(NULL, instanceName, fmiError, "error", - "%s: Missing fmuLocation.", fname); - return NULL; - } -#endif - - if (!functions.allocateMemory || !functions.freeMemory){ - functions.logger(NULL, instanceName, fmiError, "error", - "%s: Missing callback function.", fname); - return NULL; - } - - if (strcmp(GUID, MODEL_GUID)) { - functions.logger(NULL, instanceName, fmiError, "error", - "%s: Wrong GUID %s. Expected %s.", fname, GUID, MODEL_GUID); - return NULL; - } - - comp = (ModelInstance *)functions.allocateMemory(1, sizeof(ModelInstance)); - - if (comp) { - comp->instanceName = (char *)functions.allocateMemory(1 + strlen(instanceName), sizeof(char)); - comp->GUID = (char *)functions.allocateMemory(1 + strlen(GUID), sizeof(char)); -#ifdef FMI_COSIMULATION - comp->resourceLocation = (char *)functions.allocateMemory(1 + strlen(fmuLocation), sizeof(char)); -#else - comp->resourceLocation = NULL; -#endif - comp->modelData = (ModelData *)functions.allocateMemory(1, sizeof(ModelData)); - } - - if (!comp || !comp->instanceName || !comp->GUID) { - functions.logger(NULL, instanceName, fmiError, "error", - "%s: Out of memory.", fname); - return NULL; - } - - if (loggingOn) functions.logger(NULL, instanceName, fmiOK, "log", - "%s: GUID=%s", fname, GUID); - - strcpy((char *)comp->instanceName, (char *)instanceName); - strcpy((char *)comp->GUID, (char *)GUID); -#ifdef FMI_COSIMULATION - strcpy((char *)comp->resourceLocation, (char *)fmuLocation); -#endif - comp->logger = functions.logger; - comp->allocateMemory = functions.allocateMemory; - comp->freeMemory = functions.freeMemory; - comp->loggingOn = loggingOn; - comp->state = modelInstantiated; - - setStartValues(comp); // to be implemented by the includer of this file - - comp->solverData = solver_create(comp); - - return comp; -} - // fname is fmiInitialize or fmiInitializeSlave static fmiStatus init(fmiComponent c) { ModelInstance* comp = (ModelInstance *)c; @@ -209,16 +107,6 @@ static fmiStatus terminate(char* fname, fmiComponent c) { return fmiOK; } -// fname is freeModelInstance of freeSlaveInstance -void freeInstance(char* fname, fmiComponent c) { - ModelInstance* comp = (ModelInstance *)c; - if (!comp) return; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", fname); - if (comp->instanceName) comp->freeMemory((void *)comp->instanceName); - if (comp->GUID) comp->freeMemory((void *)comp->GUID); - comp->freeMemory(comp); -} - // --------------------------------------------------------------------------- // FMI functions: class methods not depending of a specific model instance // --------------------------------------------------------------------------- @@ -424,8 +312,18 @@ const char* fmiGetTypesPlatform() { fmiComponent fmiInstantiateSlave(fmiString instanceName, fmiString GUID, fmiString fmuLocation, fmiString mimeType, fmiReal timeout, fmiBoolean visible, fmiBoolean interactive, fmiCallbackFunctions functions, fmiBoolean loggingOn) { - // ignoring arguments: mimeType, timeout, visible, interactive - return instantiateModel("fmiInstantiateSlave", instanceName, GUID, fmuLocation, functions, loggingOn); + + // ignoring arguments: mimeType, timeout, visible, interactive + return createModelInstance( + functions.logger, + functions.allocateMemory, + functions.freeMemory, + NULL, + instanceName, + GUID, + fmuLocation, + loggingOn, + CoSimulation); } fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) { @@ -447,10 +345,8 @@ fmiStatus fmiResetSlave(fmiComponent c) { } void fmiFreeSlaveInstance(fmiComponent c) { -// ModelInstance* comp = (ModelInstance *)c; -// if (invalidState(comp, "fmiFreeSlaveInstance", modelTerminated)) -// return; -// freeInstance("fmiFreeSlaveInstance", c); + ModelInstance *comp = (ModelInstance *)c; + freeModelInstance(comp); } fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, @@ -550,7 +446,17 @@ const char* fmiGetModelTypesPlatform() { } fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID, fmiCallbackFunctions functions, fmiBoolean loggingOn) { - return instantiateModel("fmiInstantiateModel", instanceName, GUID, NULL, functions, loggingOn); + //return instantiateModel("fmiInstantiateModel", instanceName, GUID, NULL, functions, loggingOn); + return createModelInstance( + functions.logger, + functions.allocateMemory, + functions.freeMemory, + NULL, + instanceName, + GUID, + NULL, + loggingOn, + ModelExchange); } fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance, fmiEventInfo* eventInfo) { @@ -741,7 +647,8 @@ fmiStatus fmiTerminate(fmiComponent c){ } void fmiFreeModelInstance(fmiComponent c) { - freeInstance("fmiFreeModelInstance", c); + ModelInstance *comp = (ModelInstance *)c; + freeModelInstance(comp); } #endif // Model Exchange 1.0 diff --git a/src/fmi2.c b/src/fmi2.c index a154c0e..0d85bce 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -149,21 +149,6 @@ void logError(ModelInstance *comp, const char *message, ...) { free(buf); } -void *allocateMemory(ModelInstance *comp, size_t size) { - return comp->allocateMemory(size, 1); -} - -void freeMemory(ModelInstance *comp, void *obj) { - comp->freeMemory(obj); -} - -const char *duplicateString(ModelInstance *comp, const char *str1) { - size_t len = strlen(str1); - char *str2 = allocateMemory(comp, len + 1); - strncpy(str2, str1, len + 1); - return str2; -} - fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); static bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { @@ -224,87 +209,18 @@ fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID, fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions, fmi2Boolean visible, fmi2Boolean loggingOn) { - // ignoring arguments: fmuResourceLocation, visible - ModelInstance *comp; - if (!functions->logger) { - return NULL; - } - - if (!functions->allocateMemory || !functions->freeMemory) { - functions->logger(functions->componentEnvironment, instanceName, fmi2Error, "error", - "fmi2Instantiate: Missing callback function."); - return NULL; - } - if (!instanceName || strlen(instanceName) == 0) { - functions->logger(functions->componentEnvironment, "?", fmi2Error, "error", - "fmi2Instantiate: Missing instance name."); - return NULL; - } - if (!fmuGUID || strlen(fmuGUID) == 0) { - functions->logger(functions->componentEnvironment, instanceName, fmi2Error, "error", - "fmi2Instantiate: Missing GUID."); - return NULL; - } - if (strcmp(fmuGUID, MODEL_GUID)) { - functions->logger(functions->componentEnvironment, instanceName, fmi2Error, "error", - "fmi2Instantiate: Wrong GUID %s. Expected %s.", fmuGUID, MODEL_GUID); - return NULL; - } - comp = (ModelInstance *)functions->allocateMemory(1, sizeof(ModelInstance)); - if (comp) { - int i; - comp->instanceName = (char *)functions->allocateMemory(1 + strlen(instanceName), sizeof(char)); - comp->GUID = (char *)functions->allocateMemory(1 + strlen(fmuGUID), sizeof(char)); - comp->resourceLocation = (char *)functions->allocateMemory(1 + strlen(fmuResourceLocation), sizeof(char)); - - comp->modelData = (ModelData *)functions->allocateMemory(1, sizeof(ModelData)); - - // set all categories to on or off. fmi2SetDebugLogging should be called to choose specific categories. - for (i = 0; i < NUMBER_OF_CATEGORIES; i++) { - comp->logCategories[i] = loggingOn; - } - } - if (!comp || !comp->modelData || !comp->instanceName || !comp->GUID) { - - functions->logger(functions->componentEnvironment, instanceName, fmi2Error, "error", - "fmi2Instantiate: Out of memory."); - return NULL; - } - comp->time = 0; // overwrite in fmi2SetupExperiment, fmi2SetTime - strcpy((char *)comp->instanceName, (char *)instanceName); - comp->type = fmuType; - strcpy((char *)comp->GUID, (char *)fmuGUID); - strcpy((char *)comp->resourceLocation, (char *)fmuResourceLocation); - comp->logger = functions->logger; - comp->allocateMemory = functions->allocateMemory; - comp->freeMemory = functions->freeMemory; - comp->stepFinished = functions->stepFinished; - comp->componentEnvironment = functions->componentEnvironment; - comp->loggingOn = loggingOn; - comp->state = modelInstantiated; - comp->isNewEventIteration = fmi2False; - - comp->newDiscreteStatesNeeded = fmi2False; - comp->terminateSimulation = fmi2False; - comp->nominalsOfContinuousStatesChanged = fmi2False; - comp->valuesOfContinuousStatesChanged = fmi2False; - comp->nextEventTimeDefined = fmi2False; - comp->nextEventTime = 0; - - setStartValues(comp); // to be implemented by the includer of this file - comp->isDirtyValues = true; // because we just called setStartValues - -#if NUMBER_OF_EVENT_INDICATORS > 0 - comp->z = functions->allocateMemory(sizeof(double), NUMBER_OF_EVENT_INDICATORS); - comp->prez = functions->allocateMemory(sizeof(double), NUMBER_OF_EVENT_INDICATORS); -#else - comp->z = NULL; - comp->prez = NULL; -#endif - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2Instantiate: GUID=%s", fmuGUID) - - return comp; + return createModelInstance( + functions->logger, + functions->allocateMemory, + functions->freeMemory, + functions->componentEnvironment, + instanceName, + fmuGUID, + fmuResourceLocation, + loggingOn, + fmuType + ); } fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance, @@ -386,14 +302,9 @@ void fmi2FreeInstance(fmi2Component c) { if (invalidState(comp, "fmi2FreeInstance", MASK_fmi2FreeInstance)) return; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2FreeInstance") - - if (comp->instanceName) comp->freeMemory((void *)comp->instanceName); - if (comp->GUID) comp->freeMemory((void *)comp->GUID); - if (comp->z) comp->freeMemory((void *)comp->z); - if (comp->prez) comp->freeMemory((void *)comp->prez); + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2FreeInstance") - comp->freeMemory(comp); + freeModelInstance(comp); } // --------------------------------------------------------------------------- diff --git a/src/fmi3.c b/src/fmi3.c index e40f686..42d54e0 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -11,7 +11,6 @@ #include "config.h" #include "model.h" -#include "solver.h" #include "slave.h" @@ -150,21 +149,6 @@ void logError(ModelInstance *comp, const char *message, ...) { free(buf); } -void *allocateMemory(ModelInstance *comp, size_t size) { - return comp->allocateMemory(comp->componentEnvironment, size, 1); -} - -void freeMemory(ModelInstance *comp, void *obj) { - comp->freeMemory(comp->componentEnvironment, obj); -} - -const char *duplicateString(ModelInstance *comp, const char *str1) { - size_t len = strlen(str1); - char *str2 = allocateMemory(comp, len + 1); - strncpy(str2, str1, len + 1); - return str2; -} - fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); static bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { @@ -225,88 +209,18 @@ fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3String fmuGUID, fmi3String fmuResourceLocation, const fmi3CallbackFunctions *functions, fmi3Boolean visible, fmi3Boolean loggingOn) { - // ignoring arguments: fmuResourceLocation, visible - ModelInstance *comp; - - if (!functions->logger) { - return NULL; - } - - if (!functions->allocateMemory || !functions->freeMemory) { - functions->logger(functions->componentEnvironment, instanceName, fmi3Error, "error", - "fmi3Instantiate: Missing callback function."); - return NULL; - } - - if (!instanceName || strlen(instanceName) == 0) { - functions->logger(functions->componentEnvironment, "?", fmi3Error, "error", - "fmi3Instantiate: Missing instance name."); - return NULL; - } - - if (!fmuGUID || strlen(fmuGUID) == 0) { - functions->logger(functions->componentEnvironment, instanceName, fmi3Error, "error", - "fmi3Instantiate: Missing GUID."); - return NULL; - } - - if (strcmp(fmuGUID, MODEL_GUID)) { -// functions->logger(functions->componentEnvironment, instanceName, fmi3Error, "error", -// "fmi3Instantiate: Wrong GUID %s. Expected %s.", fmuGUID, MODEL_GUID); - return NULL; - } - - comp = (ModelInstance *)functions->allocateMemory(NULL, 1, sizeof(ModelInstance)); - - if (comp) { - int i; - comp->instanceName = (char *)functions->allocateMemory(NULL, 1 + strlen(instanceName), sizeof(char)); - comp->GUID = (char *)functions->allocateMemory(NULL, 1 + strlen(fmuGUID), sizeof(char)); - comp->resourceLocation = (char *)functions->allocateMemory(NULL, 1 + strlen(fmuResourceLocation), sizeof(char)); - - comp->modelData = (ModelData *)functions->allocateMemory(NULL, 1, sizeof(ModelData)); - // set all categories to on or off. fmi3SetDebugLogging should be called to choose specific categories. - for (i = 0; i < NUMBER_OF_CATEGORIES; i++) { - comp->logCategories[i] = loggingOn; - } - } - - if (!comp || !comp->modelData || !comp->instanceName || !comp->GUID) { - functions->logger(functions->componentEnvironment, instanceName, fmi3Error, "error", - "fmi3Instantiate: Out of memory."); - return NULL; - } - - comp->time = 0; // overwrite in fmi3SetupExperiment, fmi3SetTime - strcpy((char *)comp->instanceName, (char *)instanceName); - comp->type = fmuType; - strcpy((char *)comp->GUID, (char *)fmuGUID); - strcpy((char *)comp->resourceLocation, (char *)fmuResourceLocation); - comp->logger = functions->logger; - comp->allocateMemory = functions->allocateMemory; - comp->freeMemory = functions->freeMemory; - comp->stepFinished = functions->stepFinished; - comp->componentEnvironment = functions->componentEnvironment; - comp->loggingOn = loggingOn; - comp->state = modelInstantiated; - comp->isNewEventIteration = fmi3False; - - comp->newDiscreteStatesNeeded = fmi3False; - comp->terminateSimulation = fmi3False; - comp->nominalsOfContinuousStatesChanged = fmi3False; - comp->valuesOfContinuousStatesChanged = fmi3False; - comp->nextEventTimeDefined = fmi3False; - comp->nextEventTime = 0; - - setStartValues(comp); - comp->isDirtyValues = true; - - comp->solverData = solver_create(comp); - - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3Instantiate: GUID=%s", fmuGUID) - - return comp; + return createModelInstance( + functions->logger, + functions->allocateMemory, + functions->freeMemory, + functions->componentEnvironment, + instanceName, + fmuGUID, + fmuResourceLocation, + loggingOn, + fmuType + ); } fmi3Status fmi3SetupExperiment(fmi3Component c, fmi3Boolean toleranceDefined, fmi3Float64 tolerance, @@ -392,9 +306,7 @@ void fmi3FreeInstance(fmi3Component c) { FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3FreeInstance") - if (comp->instanceName) comp->freeMemory(comp, (void *)comp->instanceName); - if (comp->GUID) comp->freeMemory(comp, (void *)comp->GUID); - comp->freeMemory(comp, comp); + freeModelInstance(comp); } // --------------------------------------------------------------------------- @@ -625,40 +537,9 @@ fmi3Status fmi3DeSerializeFMUstate (fmi3Component c, const fmi3Byte serializedSt return unsupportedFunction(c, "fmi3DeSerializeFMUstate", MASK_fmi3DeSerializeFMUstate); } -//fmi3Status fmi3GetDirectionalDerivative(fmi3Component c, const fmi3ValueReference vUnknown_ref[], size_t nUnknown, -// const fmi3ValueReference vKnown_ref[] , size_t nKnown, -// const fmi3Float64 dvKnown[], fmi3Float64 dvUnknown[]) { -// return unsupportedFunction(c, "fmi3GetDirectionalDerivative", MASK_fmi3GetDirectionalDerivative); -//} - // --------------------------------------------------------------------------- // Functions for FMI for Co-Simulation // --------------------------------------------------------------------------- -/* Simulating the slave */ -//fmi3Status fmi3SetRealInputDerivatives(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, -// const fmi3Integer order[], const fmi3Float64 value[]) { -// ModelInstance *comp = (ModelInstance *)c; -// if (invalidState(comp, "fmi3SetRealInputDerivatives", MASK_fmi3SetRealInputDerivatives)) { -// return fmi3Error; -// } -// FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetRealInputDerivatives: nvr= %d", nvr) -// FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "fmi3SetRealInputDerivatives: ignoring function call." -// " This model cannot interpolate inputs: canInterpolateInputs=\"fmi3False\"") -// return fmi3Error; -//} - -//fmi3Status fmi3GetRealOutputDerivatives(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, -// const fmi3Integer order[], fmi3Float64 value[]) { -// int i; -// ModelInstance *comp = (ModelInstance *)c; -// if (invalidState(comp, "fmi3GetRealOutputDerivatives", MASK_fmi3GetRealOutputDerivatives)) -// return fmi3Error; -// FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetRealOutputDerivatives: nvr= %d", nvr) -// FILTERED_LOG(comp, fmi3Error, LOG_ERROR,"fmi3GetRealOutputDerivatives: ignoring function call." -// " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\"") -// for (i = 0; i < nvr; i++) value[i] = 0; -// return fmi3Error; -//} fmi3Status fmi3CancelStep(fmi3Component c) { ModelInstance *comp = (ModelInstance *)c; diff --git a/src/slave.c b/src/slave.c index dd77023..d44f0de 100644 --- a/src/slave.c +++ b/src/slave.c @@ -7,6 +7,139 @@ #include "config.h" #include "slave.h" +ModelInstance *createModelInstance( + loggerType cbLogger, + allocateMemoryType cbAllocateMemory, + freeMemoryType cbFreeMemory, + void *componentEnvironment, + const char *instanceName, + const char *GUID, + const char *resourceLocation, + bool loggingOn, + InterfaceType interfaceType) { + + ModelInstance *comp = NULL; + + if (!cbLogger) { + return NULL; + } + + if (!cbAllocateMemory || !cbFreeMemory) { + cbLogger(componentEnvironment, instanceName, Error, "error", "Missing callback function."); + return NULL; + } + + if (!instanceName || strlen(instanceName) == 0) { + cbLogger(componentEnvironment, "?", Error, "error", "Missing instance name."); + return NULL; + } + + if (!GUID || strlen(GUID) == 0) { + cbLogger(componentEnvironment, instanceName, Error, "error", "Missing GUID."); + return NULL; + } + + if (strcmp(GUID, MODEL_GUID)) { + cbLogger(componentEnvironment, instanceName, Error, "error", "Wrong GUID."); + return NULL; + } + +#if FMI_VERSION < 3 + comp = (ModelInstance *)cbAllocateMemory(1, sizeof(ModelInstance)); +#else + comp = (ModelInstance *)cbAllocateMemory(componentEnvironment, 1, sizeof(ModelInstance)); +#endif + + if (comp) { + + // set the callbacks + comp->componentEnvironment = componentEnvironment; + comp->logger = cbLogger; + comp->allocateMemory = cbAllocateMemory; + comp->freeMemory = cbFreeMemory; + + int i; + comp->instanceName = (char *)allocateMemory(comp, 1 + strlen(instanceName), sizeof(char)); + + // resourceLocation is NULL for FMI 1.0 ME + if (resourceLocation) { + comp->resourceLocation = (char *)allocateMemory(comp, 1 + strlen(resourceLocation), sizeof(char)); + strcpy((char *)comp->resourceLocation, (char *)resourceLocation); + } else { + comp->resourceLocation = NULL; + } + + comp->modelData = (ModelData *)allocateMemory(comp, 1, sizeof(ModelData)); + + // set all categories to on or off. fmi2SetDebugLogging should be called to choose specific categories. + for (i = 0; i < NUMBER_OF_CATEGORIES; i++) { + comp->logCategories[i] = loggingOn; + } + } + + if (!comp || !comp->modelData || !comp->instanceName) { + logError(comp, "Out of memory."); + return NULL; + } + + comp->time = 0; // overwrite in fmi*SetupExperiment, fmi*SetTime + strcpy((char *)comp->instanceName, (char *)instanceName); + comp->type = interfaceType; + + comp->loggingOn = loggingOn; + comp->state = modelInstantiated; + comp->isNewEventIteration = false; + + comp->newDiscreteStatesNeeded = false; + comp->terminateSimulation = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->valuesOfContinuousStatesChanged = false; + comp->nextEventTimeDefined = false; + comp->nextEventTime = 0; + + setStartValues(comp); // to be implemented by the includer of this file + comp->isDirtyValues = true; // because we just called setStartValues + +#if NUMBER_OF_EVENT_INDICATORS > 0 + comp->z = allocateMemory(comp, sizeof(double), NUMBER_OF_EVENT_INDICATORS); + comp->prez = allocateMemory(comp, sizeof(double), NUMBER_OF_EVENT_INDICATORS); +#else + comp->z = NULL; + comp->prez = NULL; +#endif + + return comp; +} + +void freeModelInstance(ModelInstance *comp) { + freeMemory(comp, (void *)comp->instanceName); + freeMemory(comp, (void *)comp->z); + freeMemory(comp, (void *)comp->prez); + freeMemory(comp, comp); +} + +void *allocateMemory(ModelInstance *comp, size_t num, size_t size) { +#if FMI_VERSION > 2 + return comp->allocateMemory(comp->componentEnvironment, num, size); +#else + return comp->allocateMemory(num, size); +#endif +} + +void freeMemory(ModelInstance *comp, void *obj) { +#if FMI_VERSION > 2 + comp->freeMemory(comp->componentEnvironment, obj); +#else + comp->freeMemory(obj); +#endif +} + +const char *duplicateString(ModelInstance *comp, const char *str1) { + size_t len = strlen(str1); + char *str2 = allocateMemory(comp, len + 1, sizeof(char)); + strncpy(str2, str1, len + 1); + return str2; +} // default implementations #if NUMBER_OF_EVENT_INDICATORS < 1 From 73930ca449965dac2a640a9302d0adee8bb08f11 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 17:23:15 +0200 Subject: [PATCH 13/28] Remove "OK" log messages --- src/fmi1.c | 30 ++--------- src/fmi2.c | 117 +++++++++++-------------------------------- src/fmi3.c | 142 ++++++++++++++++++---------------------------------- src/slave.c | 1 + 4 files changed, 83 insertions(+), 207 deletions(-) diff --git a/src/fmi1.c b/src/fmi1.c index 736b14e..c6db3ba 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -56,8 +56,7 @@ void logError(ModelInstance *comp, const char *message, ...) { static fmiBoolean invalidNumber(ModelInstance* comp, const char* f, const char* arg, int n, int nExpected){ if (n != nExpected) { comp->state = modelError; - comp->logger(comp, comp->instanceName, fmiError, "error", - "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); + logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); return fmiTrue; } return fmiFalse; @@ -68,8 +67,7 @@ static fmiBoolean invalidState(ModelInstance* comp, const char* f, int statesExp return fmiTrue; if (!(comp->state & statesExpected)) { comp->state = modelError; - comp->logger(comp, comp->instanceName, fmiError, "error", - "%s: Illegal call sequence.", f); + logError(comp, "%s: Illegal call sequence.", f); return fmiTrue; } return fmiFalse; @@ -78,8 +76,7 @@ static fmiBoolean invalidState(ModelInstance* comp, const char* f, int statesExp static fmiBoolean nullPointer(ModelInstance* comp, const char* f, const char* arg, const void* p){ if (!p) { comp->state = modelError; - comp->logger(comp, comp->instanceName, fmiError, "error", - "%s: Invalid argument %s = NULL.", f, arg); + logError(comp, "%s: Invalid argument %s = NULL.", f, arg); return fmiTrue; } return fmiFalse; @@ -102,7 +99,6 @@ static fmiStatus terminate(char* fname, fmiComponent c) { ModelInstance* comp = (ModelInstance *)c; if (invalidState(comp, fname, modelInitialized)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", fname); comp->state = modelTerminated; return fmiOK; } @@ -124,8 +120,6 @@ fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn) { ModelInstance* comp = (ModelInstance *)c; if (invalidState(comp, "fmiSetDebugLogging", not_modelError)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", - "fmiSetDebugLogging: loggingOn=%d", loggingOn); comp->loggingOn = loggingOn; return fmiOK; } @@ -143,9 +137,6 @@ fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, c if (nvr>0 && nullPointer(comp, "fmiSetReal", "value[]", value)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", - "fmiSetReal: nvr = %d", nvr); - #ifdef SET_FLOAT64 SET_VARIABLES(Float64) #else @@ -166,9 +157,6 @@ fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr>0 && nullPointer(comp, "fmiSetInteger", "value[]", value)) return fmiError; - if (comp->loggingOn) - comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetInteger: nvr = %d", nvr); - #ifdef SET_INT32 SET_VARIABLES(Int32) #else @@ -189,9 +177,6 @@ fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "value[]", value)) return fmiError; - if (comp->loggingOn) - comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetBoolean: nvr = %d", nvr); - SET_BOOLEAN_VARIABLES } @@ -338,7 +323,6 @@ fmiStatus fmiResetSlave(fmiComponent c) { ModelInstance* comp = (ModelInstance *)c; if (invalidState(comp, "fmiResetSlave", modelInitialized)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiResetSlave"); comp->state = modelInstantiated; setStartValues(comp); // to be implemented by the includer of this file return fmiOK; @@ -355,7 +339,6 @@ fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[ fmiCallbackLogger log = comp->logger; if (invalidState(comp, "fmiSetRealInputDerivatives", modelInitialized)) return fmiError; - if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiSetRealInputDerivatives: nvr= %d", nvr); log(c, comp->instanceName, fmiError, "warning", "fmiSetRealInputDerivatives: ignoring function call." " This model cannot interpolate inputs: canInterpolateInputs=\"fmiFalse\""); return fmiWarning; @@ -479,8 +462,6 @@ fmiStatus fmiSetTime(fmiComponent c, fmiReal time) { if (invalidState(comp, "fmiSetTime", modelInstantiated|modelInitialized)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetTime: time=%.16g", time); - comp->time = time; return fmiOK; @@ -516,9 +497,6 @@ fmiStatus fmiEventUpdate(fmiComponent c, fmiBoolean intermediateResults, fmiEven if (nullPointer(comp, "fmiEventUpdate", "eventInfo", eventInfo)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", - "fmiEventUpdate: intermediateResults = %d", intermediateResults); - comp->newDiscreteStatesNeeded = false; comp->terminateSimulation = false; comp->nominalsOfContinuousStatesChanged = false; @@ -551,8 +529,6 @@ fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean* callEventUpdate if (nullPointer(comp, "fmiCompletedIntegratorStep", "callEventUpdate", callEventUpdate)) return fmiError; - if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiCompletedIntegratorStep"); - return fmiOK; } diff --git a/src/fmi2.c b/src/fmi2.c index 0d85bce..bc3d723 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -23,13 +23,6 @@ #endif #include "fmi2Functions.h" - -// macro to be used to log messages. The macro check if current -// log category is valid and, if true, call the logger provided by simulator. -#define FILTERED_LOG(instance, status, categoryIndex, message, ...) if (status == fmi2Error || status == fmi2Fatal || isCategoryLogged(instance, categoryIndex)) \ - instance->logger(instance->componentEnvironment, instance->instanceName, status, \ - logCategoriesNames[categoryIndex], message, ##__VA_ARGS__); - static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; #ifndef max @@ -154,7 +147,7 @@ fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); static bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { if (n != nExpected) { comp->state = modelError; - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected) + logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); return fmi2True; } return fmi2False; @@ -165,7 +158,7 @@ static fmi2Boolean invalidState(ModelInstance *comp, const char *f, int statesEx return fmi2True; if (!(comp->state & statesExpected)) { comp->state = modelError; - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "%s: Illegal call sequence.", f) + logError(comp, "%s: Illegal call sequence.", f); return fmi2True; } return fmi2False; @@ -174,7 +167,7 @@ static fmi2Boolean invalidState(ModelInstance *comp, const char *f, int statesEx static fmi2Boolean nullPointer(ModelInstance* comp, const char *f, const char *arg, const void *p) { if (!p) { comp->state = modelError; - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "%s: Invalid argument %s = NULL.", f, arg) + logError(comp, "%s: Invalid argument %s = NULL.", f, arg); return fmi2True; } return fmi2False; @@ -182,11 +175,9 @@ static fmi2Boolean nullPointer(ModelInstance* comp, const char *f, const char *a static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int statesExpected) { ModelInstance *comp = (ModelInstance *)c; - //fmi2CallbackLogger log = comp->functions->logger; if (invalidState(comp, fName, statesExpected)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, fName); - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "%s: Function not implemented.", fName) + logError(comp, "%s: Function not implemented.", fName); return fmi2Error; } @@ -211,9 +202,9 @@ fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2Str fmi2Boolean visible, fmi2Boolean loggingOn) { return createModelInstance( - functions->logger, - functions->allocateMemory, - functions->freeMemory, + (loggerType)functions->logger, + (allocateMemoryType)functions->allocateMemory, + (freeMemoryType)functions->freeMemory, functions->componentEnvironment, instanceName, fmuGUID, @@ -232,9 +223,6 @@ fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fm if (invalidState(comp, "fmi2SetupExperiment", MASK_fmi2SetupExperiment)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetupExperiment: toleranceDefined=%d tolerance=%g", - toleranceDefined, tolerance) - comp->time = startTime; return fmi2OK; @@ -244,8 +232,6 @@ fmi2Status fmi2EnterInitializationMode(fmi2Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2EnterInitializationMode", MASK_fmi2EnterInitializationMode)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2EnterInitializationMode") - comp->state = modelInitializationMode; return fmi2OK; } @@ -254,7 +240,6 @@ fmi2Status fmi2ExitInitializationMode(fmi2Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2ExitInitializationMode", MASK_fmi2ExitInitializationMode)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2ExitInitializationMode") // if values were set and no fmi2GetXXX triggered update before, // ensure calculated values are updated now @@ -275,8 +260,6 @@ fmi2Status fmi2Terminate(fmi2Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2Terminate", MASK_fmi2Terminate)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2Terminate") - comp->state = modelTerminated; return fmi2OK; } @@ -285,8 +268,6 @@ fmi2Status fmi2Reset(fmi2Component c) { ModelInstance* comp = (ModelInstance *)c; if (invalidState(comp, "fmi2Reset", MASK_fmi2Reset)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2Reset") - comp->state = modelInstantiated; setStartValues(comp); // to be implemented by the includer of this file comp->isDirtyValues = true; // because we just called setStartValues @@ -302,8 +283,6 @@ void fmi2FreeInstance(fmi2Component c) { if (invalidState(comp, "fmi2FreeInstance", MASK_fmi2FreeInstance)) return; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2FreeInstance") - freeModelInstance(comp); } @@ -330,7 +309,6 @@ fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nC if (invalidState(comp, "fmi2SetDebugLogging", MASK_fmi2SetDebugLogging)) return fmi2Error; comp->loggingOn = loggingOn; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetDebugLogging") // reset all categories for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { @@ -460,8 +438,6 @@ fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n if (nvr > 0 && nullPointer(comp, "fmi2SetReal", "value[]", value)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: nvr = %d", nvr) - SET_VARIABLES(Float64) } @@ -478,8 +454,6 @@ fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t if (nvr > 0 && nullPointer(comp, "fmi2SetInteger", "value[]", value)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetInteger: nvr = %d", nvr) - SET_VARIABLES(Int32) } @@ -496,8 +470,6 @@ fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t if (nvr>0 && nullPointer(comp, "fmi2SetBoolean", "value[]", value)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetBoolean: nvr = %d", nvr) - SET_BOOLEAN_VARIABLES } @@ -514,8 +486,6 @@ fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t if (nvr>0 && nullPointer(comp, "fmi2SetString", "value[]", value)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetString: nvr = %d", nvr) - SET_VARIABLES(String) } @@ -585,9 +555,8 @@ fmi2Status fmi2SetRealInputDerivatives(fmi2Component c, const fmi2ValueReference if (invalidState(comp, "fmi2SetRealInputDerivatives", MASK_fmi2SetRealInputDerivatives)) { return fmi2Error; } - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetRealInputDerivatives: nvr= %d", nvr) - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "fmi2SetRealInputDerivatives: ignoring function call." - " This model cannot interpolate inputs: canInterpolateInputs=\"fmi2False\"") + logError(comp, "fmi2SetRealInputDerivatives: ignoring function call." + " This model cannot interpolate inputs: canInterpolateInputs=\"fmi2False\""); return fmi2Error; } @@ -597,9 +566,8 @@ fmi2Status fmi2GetRealOutputDerivatives(fmi2Component c, const fmi2ValueReferenc ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2GetRealOutputDerivatives", MASK_fmi2GetRealOutputDerivatives)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetRealOutputDerivatives: nvr= %d", nvr) - FILTERED_LOG(comp, fmi2Error, LOG_ERROR,"fmi2GetRealOutputDerivatives: ignoring function call." - " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\"") + logError(comp, "fmi2GetRealOutputDerivatives: ignoring function call." + " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); for (i = 0; i < nvr; i++) value[i] = 0; return fmi2Error; } @@ -610,10 +578,8 @@ fmi2Status fmi2CancelStep(fmi2Component c) { // always fmi2CancelStep is invalid, because model is never in modelStepInProgress state. return fmi2Error; } - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2CancelStep") - FILTERED_LOG(comp, fmi2Error, LOG_ERROR,"fmi2CancelStep: Can be called when fmi2DoStep returned fmi2Pending." + logError(comp, "fmi2CancelStep: Can be called when fmi2DoStep returned fmi2Pending." " This is not the case."); - // comp->state = modelStepCanceled; return fmi2Error; } @@ -621,15 +587,8 @@ fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint, fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint) { ModelInstance *comp = (ModelInstance *)c; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2DoStep: " - "currentCommunicationPoint = %g, " - "communicationStepSize = %g, " - "noSetFMUStatePriorToCurrentPoint = fmi2%s", - currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint ? "True" : "False") - if (communicationStepSize <= 0) { - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, - "fmi2DoStep: communication step size must be > 0. Fount %g.", communicationStepSize) + logError(comp, "fmi2DoStep: communication step size must be > 0. Fount %g.", communicationStepSize); comp->state = modelError; return fmi2Error; } @@ -643,25 +602,24 @@ static fmi2Status getStatus(char* fname, fmi2Component c, const fmi2StatusKind s ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, fname, MASK_fmi2GetStatus)) // all get status have the same MASK_fmi2GetStatus return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "$s: fmi2StatusKind = %s", fname, statusKind[s]) switch(s) { - case fmi2DoStepStatus: FILTERED_LOG(comp, fmi2Error, LOG_ERROR, - "%s: Can be called with fmi2DoStepStatus when fmi2DoStep returned fmi2Pending." - " This is not the case.", fname) - break; - case fmi2PendingStatus: FILTERED_LOG(comp, fmi2Error, LOG_ERROR, - "%s: Can be called with fmi2PendingStatus when fmi2DoStep returned fmi2Pending." - " This is not the case.", fname) - break; - case fmi2LastSuccessfulTime: FILTERED_LOG(comp, fmi2Error, LOG_ERROR, - "%s: Can be called with fmi2LastSuccessfulTime when fmi2DoStep returned fmi2Discard." - " This is not the case.", fname) - break; - case fmi2Terminated: FILTERED_LOG(comp, fmi2Error, LOG_ERROR, - "%s: Can be called with fmi2Terminated when fmi2DoStep returned fmi2Discard." - " This is not the case.", fname) - break; + case fmi2DoStepStatus: logError(comp, + "%s: Can be called with fmi2DoStepStatus when fmi2DoStep returned fmi2Pending." + " This is not the case.", fname); + break; + case fmi2PendingStatus: logError(comp, + "%s: Can be called with fmi2PendingStatus when fmi2DoStep returned fmi2Pending." + " This is not the case.", fname); + break; + case fmi2LastSuccessfulTime: logError(comp, + "%s: Can be called with fmi2LastSuccessfulTime when fmi2DoStep returned fmi2Discard." + " This is not the case.", fname); + break; + case fmi2Terminated: logError(comp, + "%s: Can be called with fmi2Terminated when fmi2DoStep returned fmi2Discard." + " This is not the case.", fname); + break; } return fmi2Discard; } @@ -708,8 +666,6 @@ fmi2Status fmi2EnterEventMode(fmi2Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2EnterEventMode", MASK_fmi2EnterEventMode)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2EnterEventMode") - comp->state = modelEventMode; comp->isNewEventIteration = fmi2True; return fmi2OK; @@ -720,8 +676,6 @@ fmi2Status fmi2NewDiscreteStates(fmi2Component c, fmi2EventInfo *eventInfo) { int timeEvent = 0; if (invalidState(comp, "fmi2NewDiscreteStates", MASK_fmi2NewDiscreteStates)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2NewDiscreteStates") - comp->newDiscreteStatesNeeded = fmi2False; comp->terminateSimulation = fmi2False; comp->nominalsOfContinuousStatesChanged = fmi2False; @@ -750,8 +704,6 @@ fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2EnterContinuousTimeMode", MASK_fmi2EnterContinuousTimeMode)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL,"fmi2EnterContinuousTimeMode") - comp->state = modelContinuousTimeMode; return fmi2OK; } @@ -765,7 +717,6 @@ fmi2Status fmi2CompletedIntegratorStep(fmi2Component c, fmi2Boolean noSetFMUStat return fmi2Error; if (nullPointer(comp, "fmi2CompletedIntegratorStep", "terminateSimulation", terminateSimulation)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL,"fmi2CompletedIntegratorStep") *enterEventMode = fmi2False; *terminateSimulation = fmi2False; return fmi2OK; @@ -776,7 +727,6 @@ fmi2Status fmi2SetTime(fmi2Component c, fmi2Real time) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2SetTime", MASK_fmi2SetTime)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetTime: time=%.16g", time) comp->time = time; return fmi2OK; } @@ -796,14 +746,6 @@ fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t n setContinuousStates(comp, x, nx); -//#if NUMBER_OF_STATES>0 -// for (i = 0; i < nx; i++) { -// fmi2ValueReference vr = vrStates[i]; -// FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetContinuousStates: #r%d#=%.16g", vr, x[i]) -// assert(vr < NUMBER_OF_REALS); -// comp->r[vr] = x[i]; -// } -//#endif return fmi2OK; } @@ -871,7 +813,6 @@ fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c, fmi2Real x_nominal return fmi2Error; if (nullPointer(comp, "fmi2GetNominalContinuousStates", "x_nominal[]", x_nominal)) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetNominalContinuousStates: x_nominal[0..%d] = 1.0", nx-1) for (i = 0; i < nx; i++) x_nominal[i] = 1; return fmi2OK; diff --git a/src/fmi3.c b/src/fmi3.c index 42d54e0..39939bc 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -23,13 +23,6 @@ #endif #include "fmi3Functions.h" - -// macro to be used to log messages. The macro check if current -// log category is valid and, if true, call the logger provided by simulator. -#define FILTERED_LOG(instance, status, categoryIndex, message, ...) if (status == fmi3Error || status == fmi3Fatal || isCategoryLogged(instance, categoryIndex)) \ - instance->logger(instance->componentEnvironment, instance->instanceName, status, \ - logCategoriesNames[categoryIndex], message, ##__VA_ARGS__); - static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; #ifndef max @@ -154,7 +147,7 @@ fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); static bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { if (n != nExpected) { comp->state = modelError; - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected) + logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); return fmi3True; } return fmi3False; @@ -165,7 +158,7 @@ static fmi3Boolean invalidState(ModelInstance *comp, const char *f, int statesEx return fmi3True; if (!(comp->state & statesExpected)) { comp->state = modelError; - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "%s: Illegal call sequence.", f) + logError(comp, "%s: Illegal call sequence.", f); return fmi3True; } return fmi3False; @@ -174,7 +167,7 @@ static fmi3Boolean invalidState(ModelInstance *comp, const char *f, int statesEx static fmi3Boolean nullPointer(ModelInstance* comp, const char *f, const char *arg, const void *p) { if (!p) { comp->state = modelError; - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "%s: Invalid argument %s = NULL.", f, arg) + logError(comp, "%s: Invalid argument %s = NULL.", f, arg); return fmi3True; } return fmi3False; @@ -182,11 +175,9 @@ static fmi3Boolean nullPointer(ModelInstance* comp, const char *f, const char *a static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int statesExpected) { ModelInstance *comp = (ModelInstance *)c; - //fmi3CallbackLogger log = comp->functions->logger; if (invalidState(comp, fName, statesExpected)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, fName); - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "%s: Function not implemented.", fName) + logError(comp, "%s: Function not implemented.", fName); return fmi3Error; } @@ -211,9 +202,9 @@ fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3Str fmi3Boolean visible, fmi3Boolean loggingOn) { return createModelInstance( - functions->logger, - functions->allocateMemory, - functions->freeMemory, + (loggerType)functions->logger, + (allocateMemoryType)functions->allocateMemory, + (freeMemoryType)functions->freeMemory, functions->componentEnvironment, instanceName, fmuGUID, @@ -232,9 +223,6 @@ fmi3Status fmi3SetupExperiment(fmi3Component c, fmi3Boolean toleranceDefined, fm if (invalidState(comp, "fmi3SetupExperiment", MASK_fmi3SetupExperiment)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetupExperiment: toleranceDefined=%d tolerance=%g", - toleranceDefined, tolerance) - comp->time = startTime; return fmi3OK; @@ -244,8 +232,6 @@ fmi3Status fmi3EnterInitializationMode(fmi3Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3EnterInitializationMode", MASK_fmi3EnterInitializationMode)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3EnterInitializationMode") - comp->state = modelInitializationMode; return fmi3OK; } @@ -254,7 +240,6 @@ fmi3Status fmi3ExitInitializationMode(fmi3Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3ExitInitializationMode", MASK_fmi3ExitInitializationMode)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3ExitInitializationMode") // if values were set and no fmi3GetXXX triggered update before, // ensure calculated values are updated now @@ -277,8 +262,6 @@ fmi3Status fmi3Terminate(fmi3Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3Terminate", MASK_fmi3Terminate)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3Terminate") - comp->state = modelTerminated; return fmi3OK; } @@ -287,8 +270,6 @@ fmi3Status fmi3Reset(fmi3Component c) { ModelInstance* comp = (ModelInstance *)c; if (invalidState(comp, "fmi3Reset", MASK_fmi3Reset)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3Reset") - comp->state = modelInstantiated; setStartValues(comp); comp->isDirtyValues = true; @@ -304,8 +285,6 @@ void fmi3FreeInstance(fmi3Component c) { if (invalidState(comp, "fmi3FreeInstance", MASK_fmi3FreeInstance)) return; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3FreeInstance") - freeModelInstance(comp); } @@ -323,41 +302,40 @@ const char* fmi3GetVersion() { // --------------------------------------------------------------------------- fmi3Status fmi3SetDebugLogging(fmi3Component c, fmi3Boolean loggingOn, size_t nCategories, const fmi3String categories[]) { - int i, j; - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3SetDebugLogging", MASK_fmi3SetDebugLogging)) - return fmi3Error; - comp->loggingOn = loggingOn; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetDebugLogging") - - // reset all categories - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - comp->logCategories[j] = fmi3False; - } - - if (nCategories == 0) { - // no category specified, set all categories to have loggingOn value - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - comp->logCategories[j] = loggingOn; - } - } else { - // set specific categories on - for (i = 0; i < nCategories; i++) { - fmi3Boolean categoryFound = fmi3False; - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - if (strcmp(logCategoriesNames[j], categories[i]) == 0) { - comp->logCategories[j] = loggingOn; - categoryFound = fmi3True; - break; - } - } - if (!categoryFound) { - comp->logger(comp->componentEnvironment, comp->instanceName, fmi3Warning, - logCategoriesNames[LOG_ERROR], - "logging category '%s' is not supported by model", categories[i]); - } - } - } + //int i, j; + //ModelInstance *comp = (ModelInstance *)c; + //if (invalidState(comp, "fmi3SetDebugLogging", MASK_fmi3SetDebugLogging)) + // return fmi3Error; + //comp->loggingOn = loggingOn; + + //// reset all categories + //for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + // comp->logCategories[j] = fmi3False; + //} + + //if (nCategories == 0) { + // // no category specified, set all categories to have loggingOn value + // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + // comp->logCategories[j] = loggingOn; + // } + //} else { + // // set specific categories on + // for (i = 0; i < nCategories; i++) { + // fmi3Boolean categoryFound = fmi3False; + // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + // if (strcmp(logCategoriesNames[j], categories[i]) == 0) { + // comp->logCategories[j] = loggingOn; + // categoryFound = fmi3True; + // break; + // } + // } + // if (!categoryFound) { + // comp->logger(comp->componentEnvironment, comp->instanceName, fmi3Warning, + // logCategoriesNames[LOG_ERROR], + // "logging category '%s' is not supported by model", categories[i]); + // } + // } + //} return fmi3OK; } @@ -458,8 +436,6 @@ fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ if (nvr > 0 && nullPointer(comp, "fmi3SetReal", "value[]", value)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: nvr = %d", nvr) - SET_VARIABLES(Float64) } @@ -476,8 +452,6 @@ fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n if (nvr > 0 && nullPointer(comp, "fmi3SetInteger", "value[]", value)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetInteger: nvr = %d", nvr) - SET_VARIABLES(Int32) } @@ -494,8 +468,6 @@ fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t if (nvr>0 && nullPointer(comp, "fmi3SetBoolean", "value[]", value)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetBoolean: nvr = %d", nvr) - SET_BOOLEAN_VARIABLES } @@ -512,8 +484,6 @@ fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t if (nvr>0 && nullPointer(comp, "fmi3SetString", "value[]", value)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetString: nvr = %d", nvr) - SET_VARIABLES(String) } @@ -542,31 +512,27 @@ fmi3Status fmi3DeSerializeFMUstate (fmi3Component c, const fmi3Byte serializedSt // --------------------------------------------------------------------------- fmi3Status fmi3CancelStep(fmi3Component c) { + ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3CancelStep", MASK_fmi3CancelStep)) { + + if (invalidState(comp, "fmi3CancelStep", MASK_fmi3CancelStep)) { // always fmi3CancelStep is invalid, because model is never in modelStepInProgress state. return fmi3Error; } - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3CancelStep") - FILTERED_LOG(comp, fmi3Error, LOG_ERROR,"fmi3CancelStep: Can be called when fmi3DoStep returned fmi3Pending." + + logError(comp, "fmi3CancelStep: Can be called when fmi3DoStep returned fmi3Pending." " This is not the case."); - // comp->state = modelStepCanceled; - return fmi3Error; + + return fmi3Error; } fmi3Status fmi3DoStep(fmi3Component c, fmi3Float64 currentCommunicationPoint, fmi3Float64 communicationStepSize, fmi3Boolean noSetFMUStatePriorToCurrentPoint) { - ModelInstance *comp = (ModelInstance *)c; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3DoStep: " - "currentCommunicationPoint = %g, " - "communicationStepSize = %g, " - "noSetFMUStatePriorToCurrentPoint = fmi3%s", - currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint ? "True" : "False") + ModelInstance *comp = (ModelInstance *)c; if (communicationStepSize <= 0) { - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, - "fmi3DoStep: communication step size must be > 0. Fount %g.", communicationStepSize) + logError(comp, "fmi3DoStep: communication step size must be > 0 but was %g.", communicationStepSize); comp->state = modelError; return fmi3Error; } @@ -582,8 +548,6 @@ fmi3Status fmi3EnterEventMode(fmi3Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3EnterEventMode", MASK_fmi3EnterEventMode)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3EnterEventMode") - comp->state = modelEventMode; comp->isNewEventIteration = fmi3True; return fmi3OK; @@ -594,7 +558,6 @@ fmi3Status fmi3NewDiscreteStates(fmi3Component c, fmi3EventInfo *eventInfo) { int timeEvent = 0; if (invalidState(comp, "fmi3NewDiscreteStates", MASK_fmi3NewDiscreteStates)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3NewDiscreteStates") comp->newDiscreteStatesNeeded = fmi3False; comp->terminateSimulation = fmi3False; @@ -624,8 +587,6 @@ fmi3Status fmi3EnterContinuousTimeMode(fmi3Component c) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3EnterContinuousTimeMode", MASK_fmi3EnterContinuousTimeMode)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL,"fmi3EnterContinuousTimeMode") - comp->state = modelContinuousTimeMode; return fmi3OK; } @@ -639,7 +600,6 @@ fmi3Status fmi3CompletedIntegratorStep(fmi3Component c, fmi3Boolean noSetFMUStat return fmi3Error; if (nullPointer(comp, "fmi3CompletedIntegratorStep", "terminateSimulation", terminateSimulation)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL,"fmi3CompletedIntegratorStep") *enterEventMode = fmi3False; *terminateSimulation = fmi3False; return fmi3OK; @@ -650,7 +610,6 @@ fmi3Status fmi3SetTime(fmi3Component c, fmi3Float64 time) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3SetTime", MASK_fmi3SetTime)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetTime: time=%.16g", time) comp->time = time; return fmi3OK; } @@ -737,7 +696,6 @@ fmi3Status fmi3GetNominalsOfContinuousStates(fmi3Component c, fmi3Float64 x_nomi return fmi3Error; if (nullPointer(comp, "fmi3GetNominalContinuousStates", "x_nominal[]", x_nominal)) return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetNominalContinuousStates: x_nominal[0..%d] = 1.0", nx-1) for (i = 0; i < nx; i++) x_nominal[i] = 1; return fmi3OK; diff --git a/src/slave.c b/src/slave.c index d44f0de..6fcae4a 100644 --- a/src/slave.c +++ b/src/slave.c @@ -4,6 +4,7 @@ * project root for license information. * ****************************************************************/ +#include #include "config.h" #include "slave.h" From f001de65f21d04e972a8ce62c688129afd94cfb5 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 17:37:58 +0200 Subject: [PATCH 14/28] Move helper functions to slave.c --- include/model.h | 3 +++ src/fmi1.c | 29 ----------------------------- src/fmi2.c | 29 ----------------------------- src/fmi3.c | 29 ----------------------------- src/slave.c | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 40 insertions(+), 87 deletions(-) diff --git a/include/model.h b/include/model.h index 3db4ad6..e1cab2e 100644 --- a/include/model.h +++ b/include/model.h @@ -146,6 +146,9 @@ void logError(ModelInstance *comp, const char *message, ...); void *allocateMemory(ModelInstance *comp, size_t num, size_t size); void freeMemory(ModelInstance *comp, void *obj); const char *duplicateString(ModelInstance *comp, const char *str1); +bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected); +bool invalidState(ModelInstance *comp, const char *f, int statesExpected); +bool nullPointer(ModelInstance* comp, const char *f, const char *arg, const void *p); // shorthand to access the variables #define M(v) (comp->modelData->v) diff --git a/src/fmi1.c b/src/fmi1.c index c6db3ba..ea11c38 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -53,35 +53,6 @@ void logError(ModelInstance *comp, const char *message, ...) { free(buf); } -static fmiBoolean invalidNumber(ModelInstance* comp, const char* f, const char* arg, int n, int nExpected){ - if (n != nExpected) { - comp->state = modelError; - logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); - return fmiTrue; - } - return fmiFalse; -} - -static fmiBoolean invalidState(ModelInstance* comp, const char* f, int statesExpected){ - if (!comp) - return fmiTrue; - if (!(comp->state & statesExpected)) { - comp->state = modelError; - logError(comp, "%s: Illegal call sequence.", f); - return fmiTrue; - } - return fmiFalse; -} - -static fmiBoolean 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 fmiTrue; - } - return fmiFalse; -} - // --------------------------------------------------------------------------- // Private helpers used below to implement functions // --------------------------------------------------------------------------- diff --git a/src/fmi2.c b/src/fmi2.c index bc3d723..6205e58 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -144,35 +144,6 @@ void logError(ModelInstance *comp, const char *message, ...) { fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); -static bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { - if (n != nExpected) { - comp->state = modelError; - logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); - return fmi2True; - } - return fmi2False; -} - -static fmi2Boolean invalidState(ModelInstance *comp, const char *f, int statesExpected) { - if (!comp) - return fmi2True; - if (!(comp->state & statesExpected)) { - comp->state = modelError; - logError(comp, "%s: Illegal call sequence.", f); - return fmi2True; - } - return fmi2False; -} - -static fmi2Boolean 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 fmi2True; - } - return fmi2False; -} - static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int statesExpected) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, fName, statesExpected)) diff --git a/src/fmi3.c b/src/fmi3.c index 39939bc..962478d 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -144,35 +144,6 @@ void logError(ModelInstance *comp, const char *message, ...) { fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); -static bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { - if (n != nExpected) { - comp->state = modelError; - logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); - return fmi3True; - } - return fmi3False; -} - -static fmi3Boolean invalidState(ModelInstance *comp, const char *f, int statesExpected) { - if (!comp) - return fmi3True; - if (!(comp->state & statesExpected)) { - comp->state = modelError; - logError(comp, "%s: Illegal call sequence.", f); - return fmi3True; - } - return fmi3False; -} - -static fmi3Boolean 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 fmi3True; - } - return fmi3False; -} - static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int statesExpected) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, fName, statesExpected)) diff --git a/src/slave.c b/src/slave.c index 6fcae4a..5bf7093 100644 --- a/src/slave.c +++ b/src/slave.c @@ -142,6 +142,43 @@ const char *duplicateString(ModelInstance *comp, const char *str1) { return str2; } +bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { + + if (n != nExpected) { + comp->state = modelError; + logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); + return true; + } + + return false; +} + +bool invalidState(ModelInstance *comp, const char *f, int statesExpected) { + + if (!comp) { + return true; + } + + 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; +} + // default implementations #if NUMBER_OF_EVENT_INDICATORS < 1 void getEventIndicators(ModelInstance *comp, double z[], size_t nz) { From 85cb2436c9d5befb21102689daadc810e88df1af Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 18:04:03 +0200 Subject: [PATCH 15/28] Fix variable type in Stair model --- Stair/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stair/config.h b/Stair/config.h index 6aed4be..ed1ceae 100644 --- a/Stair/config.h +++ b/Stair/config.h @@ -20,7 +20,7 @@ typedef enum { typedef struct { - double counter; + int counter; } ModelData; From 2e069cf1fcfb1c6033330adc0a1468a617cd5321 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 18:05:17 +0200 Subject: [PATCH 16/28] Disable CRT warnings --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fff2590..a9b133b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,11 @@ add_library(${TARGET_NAME} SHARED file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist) -target_compile_definitions(${TARGET_NAME} PRIVATE DISABLE_PREFIX FMI_VERSION=${FMI_VERSION}) +target_compile_definitions(${TARGET_NAME} PRIVATE + _CRT_SECURE_NO_WARNINGS + DISABLE_PREFIX + FMI_VERSION=${FMI_VERSION} +) if (${FMI_VERSION} EQUAL 1 AND "${FMI_TYPE}" STREQUAL CS) target_compile_definitions(${TARGET_NAME} PRIVATE FMI_COSIMULATION) From 7dbf9c052877a24fd7688515a3013da9f8d3eee3 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 18:07:08 +0200 Subject: [PATCH 17/28] Fix parameter types in invalidNumber() --- include/model.h | 2 +- src/slave.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/model.h b/include/model.h index e1cab2e..f15ced1 100644 --- a/include/model.h +++ b/include/model.h @@ -146,7 +146,7 @@ void logError(ModelInstance *comp, const char *message, ...); void *allocateMemory(ModelInstance *comp, size_t num, size_t size); void freeMemory(ModelInstance *comp, void *obj); const char *duplicateString(ModelInstance *comp, const char *str1); -bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected); +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); diff --git a/src/slave.c b/src/slave.c index 5bf7093..e149772 100644 --- a/src/slave.c +++ b/src/slave.c @@ -142,11 +142,11 @@ const char *duplicateString(ModelInstance *comp, const char *str1) { return str2; } -bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, int n, int nExpected) { +bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, size_t actual, size_t expected) { - if (n != nExpected) { + if (actual != expected) { comp->state = modelError; - logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, n, nExpected); + logError(comp, "%s: Invalid argument %s = %d. Expected %d.", f, arg, actual, expected); return true; } From f2b3b225d27bc878aee29c3ba5491fc311387c99 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 18:21:54 +0200 Subject: [PATCH 18/28] Move logError() to slave.c and use FMI memory management --- include/model.h | 2 +- src/fmi1.c | 25 ------------------------- src/fmi2.c | 21 --------------------- src/fmi3.c | 21 --------------------- src/slave.c | 24 ++++++++++++++++++++++++ 5 files changed, 25 insertions(+), 68 deletions(-) diff --git a/include/model.h b/include/model.h index f15ced1..65a0f65 100644 --- a/include/model.h +++ b/include/model.h @@ -142,13 +142,13 @@ void getDerivatives(ModelInstance *comp, double dx[], size_t nx); void getEventIndicators(ModelInstance *comp, double z[], size_t nz); void eventUpdate(ModelInstance *comp); -void logError(ModelInstance *comp, const char *message, ...); void *allocateMemory(ModelInstance *comp, size_t num, size_t size); void freeMemory(ModelInstance *comp, void *obj); const char *duplicateString(ModelInstance *comp, const char *str1); 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, ...); // shorthand to access the variables #define M(v) (comp->modelData->v) diff --git a/src/fmi1.c b/src/fmi1.c index ea11c38..ae4593a 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -28,31 +28,6 @@ #define DT_EVENT_DETECT 1e-10 #endif -// --------------------------------------------------------------------------- -// Private helpers used below to validate function arguments -// --------------------------------------------------------------------------- - -void logError(ModelInstance *comp, const char *message, ...) { - - va_list args; - size_t len = 0; - char *buf = ""; - - va_start(args, message); - len = vsnprintf(buf, len, message, args); - va_end(args); - - buf = malloc(len + 1); - - va_start(args, message); - len = vsnprintf(buf, len + 1, message, args); - va_end(args); - - comp->logger(comp->componentEnvironment, comp->instanceName, fmiError, "logError", buf); - - free(buf); -} - // --------------------------------------------------------------------------- // Private helpers used below to implement functions // --------------------------------------------------------------------------- diff --git a/src/fmi2.c b/src/fmi2.c index 6205e58..d1addab 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -121,27 +121,6 @@ static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", " // Private helpers used below to validate function arguments // --------------------------------------------------------------------------- -void logError(ModelInstance *comp, const char *message, ...) { - - va_list args; - size_t len = 0; - char *buf = ""; - - va_start(args, message); - len = vsnprintf(buf, len, message, args); - va_end(args); - - buf = malloc(len + 1); - - va_start(args, message); - len = vsnprintf(buf, len + 1, message, args); - va_end(args); - - comp->logger(comp->componentEnvironment, comp->instanceName, fmi2Error, "logError", buf); - - free(buf); -} - fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int statesExpected) { diff --git a/src/fmi3.c b/src/fmi3.c index 962478d..0719140 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -121,27 +121,6 @@ static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", " // Private helpers used below to validate function arguments // --------------------------------------------------------------------------- -void logError(ModelInstance *comp, const char *message, ...) { - - va_list args; - size_t len = 0; - char *buf = ""; - - va_start(args, message); - len = vsnprintf(buf, len, message, args); - va_end(args); - - buf = malloc(len + 1); - - va_start(args, message); - len = vsnprintf(buf, len + 1, message, args); - va_end(args); - - comp->logger(comp->componentEnvironment, comp->instanceName, fmi3Error, "logError", buf); - - free(buf); -} - fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int statesExpected) { diff --git a/src/slave.c b/src/slave.c index e149772..113a28d 100644 --- a/src/slave.c +++ b/src/slave.c @@ -4,6 +4,8 @@ * project root for license information. * ****************************************************************/ +#include +#include #include #include "config.h" #include "slave.h" @@ -179,6 +181,28 @@ bool nullPointer(ModelInstance* comp, const char *f, const char *arg, const void return false; } +void logError(ModelInstance *comp, const char *message, ...) { + + va_list args; + size_t len = 0; + char *buf = ""; + + va_start(args, message); + len = vsnprintf(buf, len, message, args); + va_end(args); + + buf = allocateMemory(comp, len + 1, sizeof(char)); + + va_start(args, message); + len = vsnprintf(buf, len + 1, message, args); + va_end(args); + + // no need to distinguish between FMI versions since we're not using variadic arguments + comp->logger(comp->componentEnvironment, comp->instanceName, Error, "error", buf); + + freeMemory(comp, buf); +} + // default implementations #if NUMBER_OF_EVENT_INDICATORS < 1 void getEventIndicators(ModelInstance *comp, double z[], size_t nz) { From dd1f85721727b86f345498fddae83ce75f1d2838 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 13 Jun 2019 18:26:59 +0200 Subject: [PATCH 19/28] Add const cast for FMI 1 callbacks --- src/fmi1.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/fmi1.c b/src/fmi1.c index ae4593a..815353a 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -246,9 +246,9 @@ fmiComponent fmiInstantiateSlave(fmiString instanceName, fmiString GUID, // ignoring arguments: mimeType, timeout, visible, interactive return createModelInstance( - functions.logger, - functions.allocateMemory, - functions.freeMemory, + (loggerType)functions.logger, + (allocateMemoryType)functions.allocateMemory, + (freeMemoryType)functions.freeMemory, NULL, instanceName, GUID, @@ -375,11 +375,10 @@ const char* fmiGetModelTypesPlatform() { } fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID, fmiCallbackFunctions functions, fmiBoolean loggingOn) { - //return instantiateModel("fmiInstantiateModel", instanceName, GUID, NULL, functions, loggingOn); return createModelInstance( - functions.logger, - functions.allocateMemory, - functions.freeMemory, + (loggerType)functions.logger, + (allocateMemoryType)functions.allocateMemory, + (freeMemoryType)functions.freeMemory, NULL, instanceName, GUID, From 75399167511ed5a06319ae643068818de42f0214 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 14 Jun 2019 11:49:26 +0200 Subject: [PATCH 20/28] Rename fmi*.c to fmi*Functions.c and fix --- BouncingBall/FMI2.xml | 6 +- BouncingBall/FMI3.xml | 4 + CMakeLists.txt | 4 +- Dahlquist/FMI2.xml | 6 +- Dahlquist/FMI3.xml | 6 +- Feedthrough/FMI2.xml | 6 +- Feedthrough/FMI3.xml | 6 +- LinearTransform/FMI3.xml | 6 +- Resource/FMI2.xml | 6 +- Resource/FMI3.xml | 6 +- Stair/FMI2.xml | 6 +- Stair/FMI3.xml | 6 +- VanDerPol/FMI2.xml | 6 +- VanDerPol/FMI3.xml | 6 +- src/{fmi1.c => fmi1Functions.c} | 1150 +++++++++++------------ src/{fmi2.c => fmi2Functions.c} | 1538 +++++++++++++++---------------- src/{fmi3.c => fmi3Functions.c} | 1304 +++++++++++++------------- 17 files changed, 2026 insertions(+), 2046 deletions(-) rename src/{fmi1.c => fmi1Functions.c} (97%) rename src/{fmi2.c => fmi2Functions.c} (97%) rename src/{fmi3.c => fmi3Functions.c} (97%) diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index c036df6..bfdb231 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -8,8 +8,7 @@ - - + @@ -17,8 +16,7 @@ - - + diff --git a/BouncingBall/FMI3.xml b/BouncingBall/FMI3.xml index 45d4892..aadd9bd 100644 --- a/BouncingBall/FMI3.xml +++ b/BouncingBall/FMI3.xml @@ -4,12 +4,16 @@ + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index a9b133b..888643d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,7 @@ SET(HEADERS SET(SOURCES ${MODEL_NAME}/model.c - src/fmi${FMI_VERSION}.c + src/fmi${FMI_VERSION}Functions.c src/slave.c ) @@ -173,7 +173,7 @@ foreach (SOURCE_FILE model.h slave.h) endforeach(SOURCE_FILE) # common sources -foreach (SOURCE_FILE fmi${FMI_VERSION}.c slave.c) +foreach (SOURCE_FILE fmi${FMI_VERSION}Functions.c slave.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}" diff --git a/Dahlquist/FMI2.xml b/Dahlquist/FMI2.xml index d492573..f88a586 100644 --- a/Dahlquist/FMI2.xml +++ b/Dahlquist/FMI2.xml @@ -8,8 +8,7 @@ - - + @@ -17,8 +16,7 @@ - - + diff --git a/Dahlquist/FMI3.xml b/Dahlquist/FMI3.xml index 12379cf..c51908b 100644 --- a/Dahlquist/FMI3.xml +++ b/Dahlquist/FMI3.xml @@ -3,8 +3,7 @@ - - + @@ -12,8 +11,7 @@ - - + diff --git a/Feedthrough/FMI2.xml b/Feedthrough/FMI2.xml index 9cedd2e..4f7cb7c 100644 --- a/Feedthrough/FMI2.xml +++ b/Feedthrough/FMI2.xml @@ -8,8 +8,7 @@ - - + @@ -17,8 +16,7 @@ - - + diff --git a/Feedthrough/FMI3.xml b/Feedthrough/FMI3.xml index 57a999f..48efc48 100644 --- a/Feedthrough/FMI3.xml +++ b/Feedthrough/FMI3.xml @@ -3,8 +3,7 @@ - - + @@ -12,8 +11,7 @@ - - + diff --git a/LinearTransform/FMI3.xml b/LinearTransform/FMI3.xml index 810a08f..e5424c2 100644 --- a/LinearTransform/FMI3.xml +++ b/LinearTransform/FMI3.xml @@ -3,8 +3,7 @@ - - + @@ -12,8 +11,7 @@ - - + diff --git a/Resource/FMI2.xml b/Resource/FMI2.xml index 9b8601a..7ca09f3 100644 --- a/Resource/FMI2.xml +++ b/Resource/FMI2.xml @@ -8,8 +8,7 @@ - - + @@ -17,8 +16,7 @@ - - + diff --git a/Resource/FMI3.xml b/Resource/FMI3.xml index 6a54b14..ede802f 100644 --- a/Resource/FMI3.xml +++ b/Resource/FMI3.xml @@ -3,8 +3,7 @@ - - + @@ -12,8 +11,7 @@ - - + diff --git a/Stair/FMI2.xml b/Stair/FMI2.xml index 61dca10..7775e5f 100644 --- a/Stair/FMI2.xml +++ b/Stair/FMI2.xml @@ -8,8 +8,7 @@ - - + @@ -17,8 +16,7 @@ - - + diff --git a/Stair/FMI3.xml b/Stair/FMI3.xml index c9598c9..6bfcfe0 100644 --- a/Stair/FMI3.xml +++ b/Stair/FMI3.xml @@ -3,8 +3,7 @@ - - + @@ -12,8 +11,7 @@ - - + diff --git a/VanDerPol/FMI2.xml b/VanDerPol/FMI2.xml index c2d25ee..a167c77 100644 --- a/VanDerPol/FMI2.xml +++ b/VanDerPol/FMI2.xml @@ -8,8 +8,7 @@ - - + @@ -17,8 +16,7 @@ - - + diff --git a/VanDerPol/FMI3.xml b/VanDerPol/FMI3.xml index 61c6ef2..5610205 100644 --- a/VanDerPol/FMI3.xml +++ b/VanDerPol/FMI3.xml @@ -3,8 +3,7 @@ - - + @@ -12,8 +11,7 @@ - - + diff --git a/src/fmi1.c b/src/fmi1Functions.c similarity index 97% rename from src/fmi1.c rename to src/fmi1Functions.c index 815353a..f33aea4 100644 --- a/src/fmi1.c +++ b/src/fmi1Functions.c @@ -1,575 +1,575 @@ -/**************************************************************** - * Copyright (c) Dassault Systemes. All rights reserved. * - * This file is part of the Test-FMUs. See LICENSE.txt in the * - * project root for license information. * - ****************************************************************/ - -#include -#include -#include -#include - -#include "config.h" -#include "model.h" -#include "slave.h" - - -#ifdef FMI_COSIMULATION -#include "fmiFunctions.h" -#else -#include "fmiModelFunctions.h" -#endif - -#ifndef max -#define max(a,b) ((a)>(b) ? (a) : (b)) -#endif - -#ifndef DT_EVENT_DETECT -#define DT_EVENT_DETECT 1e-10 -#endif - -// --------------------------------------------------------------------------- -// Private helpers used below to implement functions -// --------------------------------------------------------------------------- - -// fname is fmiInitialize or fmiInitializeSlave -static fmiStatus init(fmiComponent c) { - ModelInstance* comp = (ModelInstance *)c; - comp->state = modelInitialized; - calculateValues(comp); - return fmiOK; -} - -// fname is fmiTerminate or fmiTerminateSlave -static fmiStatus terminate(char* fname, fmiComponent c) { - ModelInstance* comp = (ModelInstance *)c; - if (invalidState(comp, fname, modelInitialized)) - return fmiError; - comp->state = modelTerminated; - 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) { - ModelInstance* comp = (ModelInstance *)c; - if (invalidState(comp, "fmiSetDebugLogging", not_modelError)) - return fmiError; - comp->loggingOn = loggingOn; - return fmiOK; -} - -fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiSetReal", modelInstantiated|modelInitialized)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiSetReal", "vr[]", vr)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiSetReal", "value[]", value)) - return fmiError; - -#ifdef SET_FLOAT64 - SET_VARIABLES(Float64) -#else - return fmiError; // not implemented -#endif -} - -fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiSetInteger", modelInstantiated|modelInitialized)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiSetInteger", "vr[]", vr)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiSetInteger", "value[]", value)) - return fmiError; - -#ifdef SET_INT32 - SET_VARIABLES(Int32) -#else - return fmiError; // not implemented -#endif -} - -fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]){ - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiSetBoolean", modelInstantiated|modelInitialized)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "vr[]", vr)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "value[]", value)) - return fmiError; - - SET_BOOLEAN_VARIABLES -} - -fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]){ -// int i; -// ModelInstance* comp = (ModelInstance *)c; -// if (invalidState(comp, "fmiSetString", modelInstantiated|modelInitialized)) -// return fmiError; -// if (nvr>0 && nullPointer(comp, "fmiSetString", "vr[]", vr)) -// return fmiError; -// if (nvr>0 && nullPointer(comp, "fmiSetString", "value[]", value)) -// return fmiError; -// if (comp->loggingOn) -// comp->functions.logger(c, comp->instanceName, fmiOK, "log", "fmiSetString: nvr = %d", nvr); -// for (i=0; is[vr[i]]; -// if (vrOutOfRange(comp, "fmiSetString", vr[i], NUMBER_OF_STRINGS)) -// return fmiError; -// if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", -// "fmiSetString: #s%d# = '%s'", vr[i], value[i]); -// if (value[i] == NULL) { -// if (string) comp->functions.freeMemory(string); -// comp->s[vr[i]] = NULL; -// comp->functions.logger(comp, comp->instanceName, fmiWarning, "warning", -// "fmiSetString: string argument value[%d] = NULL.", i); -// } else { -// if (string==NULL || strlen(string) < strlen(value[i])) { -// if (string) comp->functions.freeMemory(string); -// comp->s[vr[i]] = (char *)comp->functions.allocateMemory(1+strlen(value[i]), sizeof(char)); -// if (!comp->s[vr[i]]) { -// comp->state = modelError; -// comp->functions.logger(NULL, comp->instanceName, fmiError, "error", "fmiSetString: Out of memory."); -// return fmiError; -// } -// } -// strcpy((char *)comp->s[vr[i]], (char *)value[i]); -// } -// } - return fmiOK; -} - -fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiGetReal", not_modelError)) - return fmiError; - - if (nvr > 0 && nullPointer(comp, "fmiGetReal", "vr[]", vr)) - return fmiError; - - if (nvr > 0 && nullPointer(comp, "fmiGetReal", "value[]", value)) - return fmiError; - - GET_VARIABLES(Float64) -} - -fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiGetInteger", not_modelError)) - return fmiError; - - if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "vr[]", vr)) - return fmiError; - - if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "value[]", value)) - return fmiError; - - GET_VARIABLES(Int32) -} - -fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiGetBoolean", not_modelError)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "vr[]", vr)) - return fmiError; - - if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "value[]", value)) - return fmiError; - - GET_BOOLEAN_VARIABLES -} - -fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]) { -// int i; -// ModelInstance* comp = (ModelInstance *)c; -// if (invalidState(comp, "fmiGetString", not_modelError)) -// return fmiError; -// if (nvr>0 && nullPointer(comp, "fmiGetString", "vr[]", vr)) -// return fmiError; -// if (nvr>0 && nullPointer(comp, "fmiGetString", "value[]", value)) -// return fmiError; -// for (i=0; is[vr[i]]; -// if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", -// "fmiGetString: #s%u# = '%s'", vr[i], value[i]); -// } - return fmiOK; -} - -#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) { - - // ignoring arguments: mimeType, timeout, visible, interactive - return createModelInstance( - (loggerType)functions.logger, - (allocateMemoryType)functions.allocateMemory, - (freeMemoryType)functions.freeMemory, - NULL, - instanceName, - GUID, - fmuLocation, - loggingOn, - CoSimulation); -} - -fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) { - return init(c); -} - -fmiStatus fmiTerminateSlave(fmiComponent c) { - return terminate("fmiTerminateSlave", c); -} - -fmiStatus fmiResetSlave(fmiComponent c) { - ModelInstance* comp = (ModelInstance *)c; - if (invalidState(comp, "fmiResetSlave", modelInitialized)) - return fmiError; - comp->state = modelInstantiated; - setStartValues(comp); // to be implemented by the includer of this file - return fmiOK; -} - -void fmiFreeSlaveInstance(fmiComponent c) { - ModelInstance *comp = (ModelInstance *)c; - freeModelInstance(comp); -} - -fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, - const fmiInteger order[], const fmiReal value[]) { - ModelInstance* comp = (ModelInstance *)c; - fmiCallbackLogger log = comp->logger; - if (invalidState(comp, "fmiSetRealInputDerivatives", modelInitialized)) - return fmiError; - log(c, comp->instanceName, fmiError, "warning", "fmiSetRealInputDerivatives: ignoring function call." - " This model cannot interpolate inputs: canInterpolateInputs=\"fmiFalse\""); - return fmiWarning; -} - -fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, - const fmiInteger order[], fmiReal value[]) { - int i; - ModelInstance* comp = (ModelInstance *)c; - fmiCallbackLogger log = comp->logger; - if (invalidState(comp, "fmiGetRealOutputDerivatives", modelInitialized)) - return fmiError; - if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiGetRealOutputDerivatives: nvr= %d", nvr); - log(c, comp->instanceName, fmiError, "warning", "fmiGetRealOutputDerivatives: ignoring function call." - " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); - for (i=0; ilogger; - if (invalidState(comp, "fmiCancelStep", modelInitialized)) - return fmiError; - if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiCancelStep"); - log(c, comp->instanceName, fmiError, "error", - "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) { - ModelInstance* comp = (ModelInstance *)c; - return doStep(comp, currentCommunicationPoint, currentCommunicationPoint + communicationStepSize); -} - -static fmiStatus getStatus(char* fname, fmiComponent c, const fmiStatusKind s) { -// const char* statusKind[3] = {"fmiDoStepStatus","fmiPendingStatus","fmiLastSuccessfulTime"}; -// ModelInstance* comp = (ModelInstance *)c; -// fmiCallbackLogger log = comp->functions.logger; -// if (invalidState(comp, fname, modelInstantiated|modelInitialized)) -// return fmiError; -// if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "$s: fmiStatusKind = %s", fname, statusKind[s]); -// switch(s) { -// case fmiDoStepStatus: log(c, comp->instanceName, fmiError, "error", -// "%s: Can be called with fmiDoStepStatus when fmiDoStep returned fmiPending." -// " This is not the case.", fname); -// break; -// case fmiPendingStatus: log(c, comp->instanceName, fmiError, "error", -// "%s: Can be called with fmiPendingStatus when fmiDoStep returned fmiPending." -// " This is not the case.", fname); -// break; -// case fmiLastSuccessfulTime: log(c, comp->instanceName, fmiError, "error", -// "%s: Can be called with fmiLastSuccessfulTime when fmiDoStep returned fmiDiscard." -// " This is not the case.", fname); -// break; -// } - return fmiError; -} - -fmiStatus fmiGetStatus(fmiComponent c, const fmiStatusKind s, fmiStatus* value) { - return getStatus("fmiGetStatus", c, s); -} - -fmiStatus fmiGetRealStatus(fmiComponent c, const fmiStatusKind s, fmiReal* value){ - return getStatus("fmiGetRealStatus", c, s); -} - -fmiStatus fmiGetIntegerStatus(fmiComponent c, const fmiStatusKind s, fmiInteger* value){ - return getStatus("fmiGetIntegerStatus", c, s); -} - -fmiStatus fmiGetBooleanStatus(fmiComponent c, const fmiStatusKind s, fmiBoolean* value){ - return getStatus("fmiGetBooleanStatus", c, s); -} - -fmiStatus fmiGetStringStatus(fmiComponent c, const fmiStatusKind s, fmiString* value){ - return getStatus("fmiGetStringStatus", c, s); -} - -#else -// --------------------------------------------------------------------------- -// FMI functions: only for Model Exchange 1.0 -// --------------------------------------------------------------------------- - -const char* fmiGetModelTypesPlatform() { - return fmiModelTypesPlatform; -} - -fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID, fmiCallbackFunctions functions, fmiBoolean loggingOn) { - return createModelInstance( - (loggerType)functions.logger, - (allocateMemoryType)functions.allocateMemory, - (freeMemoryType)functions.freeMemory, - NULL, - instanceName, - GUID, - NULL, - loggingOn, - ModelExchange); -} - -fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance, fmiEventInfo* eventInfo) { - ModelInstance *comp = (ModelInstance *)c; - - eventInfo->iterationConverged = fmiTrue; - eventInfo->stateValueReferencesChanged = fmiFalse; - eventInfo->stateValuesChanged = fmiFalse; - eventInfo->terminateSimulation = fmiFalse; - eventInfo->upcomingTimeEvent = comp->nextEventTimeDefined; - eventInfo->nextEventTime = comp->nextEventTime; - - return init(c); -} - -fmiStatus fmiSetTime(fmiComponent c, fmiReal time) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiSetTime", modelInstantiated|modelInitialized)) - return fmiError; - - comp->time = time; - - return fmiOK; -} - -fmiStatus fmiSetContinuousStates(fmiComponent c, const fmiReal x[], size_t nx) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiSetContinuousStates", modelInitialized)) - return fmiError; - - if (invalidNumber(comp, "fmiSetContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmiError; - - if (nullPointer(comp, "fmiSetContinuousStates", "x[]", x)) - return fmiError; - - setContinuousStates(comp, x, nx); - - return fmiOK; -} - -fmiStatus fmiEventUpdate(fmiComponent c, fmiBoolean intermediateResults, fmiEventInfo* eventInfo) { - - ModelInstance* comp = (ModelInstance *)c; - - int timeEvent = 0; - - if (invalidState(comp, "fmiEventUpdate", modelInitialized)) - return fmiError; - - if (nullPointer(comp, "fmiEventUpdate", "eventInfo", eventInfo)) - return fmiError; - - comp->newDiscreteStatesNeeded = false; - comp->terminateSimulation = false; - comp->nominalsOfContinuousStatesChanged = false; - comp->valuesOfContinuousStatesChanged = false; - - if (comp->nextEventTimeDefined && comp->nextEventTime <= comp->time) { - timeEvent = 1; - } - - eventUpdate(comp); - - // copy internal eventInfo of component to output eventInfo - eventInfo->iterationConverged = fmiTrue; - eventInfo->stateValueReferencesChanged = fmiFalse; - eventInfo->stateValuesChanged = comp->valuesOfContinuousStatesChanged; - eventInfo->terminateSimulation = comp->terminateSimulation; - eventInfo->upcomingTimeEvent = comp->nextEventTimeDefined; - eventInfo->nextEventTime = comp->nextEventTime; - - return fmiOK; -} - -fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean* callEventUpdate) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiCompletedIntegratorStep", modelInitialized)) - return fmiError; - - if (nullPointer(comp, "fmiCompletedIntegratorStep", "callEventUpdate", callEventUpdate)) - return fmiError; - - return fmiOK; -} - -fmiStatus fmiGetStateValueReferences(fmiComponent c, fmiValueReference vrx[], size_t nx) { -// int i; -// ModelInstance* comp = (ModelInstance *)c; -// if (invalidState(comp, "fmiGetStateValueReferences", not_modelError)) -// return fmiError; -// if (invalidNumber(comp, "fmiGetStateValueReferences", "nx", nx, NUMBER_OF_STATES)) -// return fmiError; -// if (nullPointer(comp, "fmiGetStateValueReferences", "vrx[]", vrx)) -// return fmiError; -//#if NUMBER_OF_STATES>0 -// for (i=0; iloggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", -// "fmiGetStateValueReferences: vrx[%d] = %d", i, vrx[i]); -// } -//#endif - return fmiOK; -} - -fmiStatus fmiGetContinuousStates(fmiComponent c, fmiReal states[], size_t nx){ - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmiGetContinuousStates", not_modelError)) - return fmiError; - - if (invalidNumber(comp, "fmiGetContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmiError; - - if (nullPointer(comp, "fmiGetContinuousStates", "states[]", states)) - return fmiError; - - getContinuousStates(comp, states, nx); - - return fmiOK; -} - -fmiStatus fmiGetNominalContinuousStates(fmiComponent c, fmiReal x_nominal[], size_t nx) { -// int i; -// ModelInstance* comp = (ModelInstance *)c; -// if (invalidState(comp, "fmiGetNominalContinuousStates", not_modelError)) -// return fmiError; -// if (invalidNumber(comp, "fmiGetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES)) -// return fmiError; -// if (nullPointer(comp, "fmiGetNominalContinuousStates", "x_nominal[]", x_nominal)) -// return fmiError; -// if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", -// "fmiGetNominalContinuousStates: x_nominal[0..%d] = 1.0", nx-1); -// for (i=0; i +#include +#include +#include + +#include "config.h" +#include "model.h" +#include "slave.h" + + +#ifdef FMI_COSIMULATION +#include "fmiFunctions.h" +#else +#include "fmiModelFunctions.h" +#endif + +#ifndef max +#define max(a,b) ((a)>(b) ? (a) : (b)) +#endif + +#ifndef DT_EVENT_DETECT +#define DT_EVENT_DETECT 1e-10 +#endif + +// --------------------------------------------------------------------------- +// Private helpers used below to implement functions +// --------------------------------------------------------------------------- + +// fname is fmiInitialize or fmiInitializeSlave +static fmiStatus init(fmiComponent c) { + ModelInstance* comp = (ModelInstance *)c; + comp->state = modelInitialized; + calculateValues(comp); + return fmiOK; +} + +// fname is fmiTerminate or fmiTerminateSlave +static fmiStatus terminate(char* fname, fmiComponent c) { + ModelInstance* comp = (ModelInstance *)c; + if (invalidState(comp, fname, modelInitialized)) + return fmiError; + comp->state = modelTerminated; + 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) { + ModelInstance* comp = (ModelInstance *)c; + if (invalidState(comp, "fmiSetDebugLogging", not_modelError)) + return fmiError; + comp->loggingOn = loggingOn; + return fmiOK; +} + +fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiSetReal", modelInstantiated|modelInitialized)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiSetReal", "vr[]", vr)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiSetReal", "value[]", value)) + return fmiError; + +#ifdef SET_FLOAT64 + SET_VARIABLES(Float64) +#else + return fmiError; // not implemented +#endif +} + +fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiSetInteger", modelInstantiated|modelInitialized)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiSetInteger", "vr[]", vr)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiSetInteger", "value[]", value)) + return fmiError; + +#ifdef SET_INT32 + SET_VARIABLES(Int32) +#else + return fmiError; // not implemented +#endif +} + +fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]){ + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiSetBoolean", modelInstantiated|modelInitialized)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "vr[]", vr)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiSetBoolean", "value[]", value)) + return fmiError; + + SET_BOOLEAN_VARIABLES +} + +fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]){ +// int i; +// ModelInstance* comp = (ModelInstance *)c; +// if (invalidState(comp, "fmiSetString", modelInstantiated|modelInitialized)) +// return fmiError; +// if (nvr>0 && nullPointer(comp, "fmiSetString", "vr[]", vr)) +// return fmiError; +// if (nvr>0 && nullPointer(comp, "fmiSetString", "value[]", value)) +// return fmiError; +// if (comp->loggingOn) +// comp->functions.logger(c, comp->instanceName, fmiOK, "log", "fmiSetString: nvr = %d", nvr); +// for (i=0; is[vr[i]]; +// if (vrOutOfRange(comp, "fmiSetString", vr[i], NUMBER_OF_STRINGS)) +// return fmiError; +// if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", +// "fmiSetString: #s%d# = '%s'", vr[i], value[i]); +// if (value[i] == NULL) { +// if (string) comp->functions.freeMemory(string); +// comp->s[vr[i]] = NULL; +// comp->functions.logger(comp, comp->instanceName, fmiWarning, "warning", +// "fmiSetString: string argument value[%d] = NULL.", i); +// } else { +// if (string==NULL || strlen(string) < strlen(value[i])) { +// if (string) comp->functions.freeMemory(string); +// comp->s[vr[i]] = (char *)comp->functions.allocateMemory(1+strlen(value[i]), sizeof(char)); +// if (!comp->s[vr[i]]) { +// comp->state = modelError; +// comp->functions.logger(NULL, comp->instanceName, fmiError, "error", "fmiSetString: Out of memory."); +// return fmiError; +// } +// } +// strcpy((char *)comp->s[vr[i]], (char *)value[i]); +// } +// } + return fmiOK; +} + +fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiGetReal", not_modelError)) + return fmiError; + + if (nvr > 0 && nullPointer(comp, "fmiGetReal", "vr[]", vr)) + return fmiError; + + if (nvr > 0 && nullPointer(comp, "fmiGetReal", "value[]", value)) + return fmiError; + + GET_VARIABLES(Float64) +} + +fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiGetInteger", not_modelError)) + return fmiError; + + if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "vr[]", vr)) + return fmiError; + + if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "value[]", value)) + return fmiError; + + GET_VARIABLES(Int32) +} + +fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiGetBoolean", not_modelError)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "vr[]", vr)) + return fmiError; + + if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "value[]", value)) + return fmiError; + + GET_BOOLEAN_VARIABLES +} + +fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]) { +// int i; +// ModelInstance* comp = (ModelInstance *)c; +// if (invalidState(comp, "fmiGetString", not_modelError)) +// return fmiError; +// if (nvr>0 && nullPointer(comp, "fmiGetString", "vr[]", vr)) +// return fmiError; +// if (nvr>0 && nullPointer(comp, "fmiGetString", "value[]", value)) +// return fmiError; +// for (i=0; is[vr[i]]; +// if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", +// "fmiGetString: #s%u# = '%s'", vr[i], value[i]); +// } + return fmiOK; +} + +#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) { + + // ignoring arguments: mimeType, timeout, visible, interactive + return createModelInstance( + (loggerType)functions.logger, + (allocateMemoryType)functions.allocateMemory, + (freeMemoryType)functions.freeMemory, + NULL, + instanceName, + GUID, + fmuLocation, + loggingOn, + CoSimulation); +} + +fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) { + return init(c); +} + +fmiStatus fmiTerminateSlave(fmiComponent c) { + return terminate("fmiTerminateSlave", c); +} + +fmiStatus fmiResetSlave(fmiComponent c) { + ModelInstance* comp = (ModelInstance *)c; + if (invalidState(comp, "fmiResetSlave", modelInitialized)) + return fmiError; + comp->state = modelInstantiated; + setStartValues(comp); // to be implemented by the includer of this file + return fmiOK; +} + +void fmiFreeSlaveInstance(fmiComponent c) { + ModelInstance *comp = (ModelInstance *)c; + freeModelInstance(comp); +} + +fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, + const fmiInteger order[], const fmiReal value[]) { + ModelInstance* comp = (ModelInstance *)c; + fmiCallbackLogger log = comp->logger; + if (invalidState(comp, "fmiSetRealInputDerivatives", modelInitialized)) + return fmiError; + log(c, comp->instanceName, fmiError, "warning", "fmiSetRealInputDerivatives: ignoring function call." + " This model cannot interpolate inputs: canInterpolateInputs=\"fmiFalse\""); + return fmiWarning; +} + +fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, + const fmiInteger order[], fmiReal value[]) { + int i; + ModelInstance* comp = (ModelInstance *)c; + fmiCallbackLogger log = comp->logger; + if (invalidState(comp, "fmiGetRealOutputDerivatives", modelInitialized)) + return fmiError; + if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiGetRealOutputDerivatives: nvr= %d", nvr); + log(c, comp->instanceName, fmiError, "warning", "fmiGetRealOutputDerivatives: ignoring function call." + " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); + for (i=0; ilogger; + if (invalidState(comp, "fmiCancelStep", modelInitialized)) + return fmiError; + if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiCancelStep"); + log(c, comp->instanceName, fmiError, "error", + "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) { + ModelInstance* comp = (ModelInstance *)c; + return doStep(comp, currentCommunicationPoint, currentCommunicationPoint + communicationStepSize); +} + +static fmiStatus getStatus(char* fname, fmiComponent c, const fmiStatusKind s) { +// const char* statusKind[3] = {"fmiDoStepStatus","fmiPendingStatus","fmiLastSuccessfulTime"}; +// ModelInstance* comp = (ModelInstance *)c; +// fmiCallbackLogger log = comp->functions.logger; +// if (invalidState(comp, fname, modelInstantiated|modelInitialized)) +// return fmiError; +// if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "$s: fmiStatusKind = %s", fname, statusKind[s]); +// switch(s) { +// case fmiDoStepStatus: log(c, comp->instanceName, fmiError, "error", +// "%s: Can be called with fmiDoStepStatus when fmiDoStep returned fmiPending." +// " This is not the case.", fname); +// break; +// case fmiPendingStatus: log(c, comp->instanceName, fmiError, "error", +// "%s: Can be called with fmiPendingStatus when fmiDoStep returned fmiPending." +// " This is not the case.", fname); +// break; +// case fmiLastSuccessfulTime: log(c, comp->instanceName, fmiError, "error", +// "%s: Can be called with fmiLastSuccessfulTime when fmiDoStep returned fmiDiscard." +// " This is not the case.", fname); +// break; +// } + return fmiError; +} + +fmiStatus fmiGetStatus(fmiComponent c, const fmiStatusKind s, fmiStatus* value) { + return getStatus("fmiGetStatus", c, s); +} + +fmiStatus fmiGetRealStatus(fmiComponent c, const fmiStatusKind s, fmiReal* value){ + return getStatus("fmiGetRealStatus", c, s); +} + +fmiStatus fmiGetIntegerStatus(fmiComponent c, const fmiStatusKind s, fmiInteger* value){ + return getStatus("fmiGetIntegerStatus", c, s); +} + +fmiStatus fmiGetBooleanStatus(fmiComponent c, const fmiStatusKind s, fmiBoolean* value){ + return getStatus("fmiGetBooleanStatus", c, s); +} + +fmiStatus fmiGetStringStatus(fmiComponent c, const fmiStatusKind s, fmiString* value){ + return getStatus("fmiGetStringStatus", c, s); +} + +#else +// --------------------------------------------------------------------------- +// FMI functions: only for Model Exchange 1.0 +// --------------------------------------------------------------------------- + +const char* fmiGetModelTypesPlatform() { + return fmiModelTypesPlatform; +} + +fmiComponent fmiInstantiateModel(fmiString instanceName, fmiString GUID, fmiCallbackFunctions functions, fmiBoolean loggingOn) { + return createModelInstance( + (loggerType)functions.logger, + (allocateMemoryType)functions.allocateMemory, + (freeMemoryType)functions.freeMemory, + NULL, + instanceName, + GUID, + NULL, + loggingOn, + ModelExchange); +} + +fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance, fmiEventInfo* eventInfo) { + ModelInstance *comp = (ModelInstance *)c; + + eventInfo->iterationConverged = fmiTrue; + eventInfo->stateValueReferencesChanged = fmiFalse; + eventInfo->stateValuesChanged = fmiFalse; + eventInfo->terminateSimulation = fmiFalse; + eventInfo->upcomingTimeEvent = comp->nextEventTimeDefined; + eventInfo->nextEventTime = comp->nextEventTime; + + return init(c); +} + +fmiStatus fmiSetTime(fmiComponent c, fmiReal time) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiSetTime", modelInstantiated|modelInitialized)) + return fmiError; + + comp->time = time; + + return fmiOK; +} + +fmiStatus fmiSetContinuousStates(fmiComponent c, const fmiReal x[], size_t nx) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiSetContinuousStates", modelInitialized)) + return fmiError; + + if (invalidNumber(comp, "fmiSetContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmiError; + + if (nullPointer(comp, "fmiSetContinuousStates", "x[]", x)) + return fmiError; + + setContinuousStates(comp, x, nx); + + return fmiOK; +} + +fmiStatus fmiEventUpdate(fmiComponent c, fmiBoolean intermediateResults, fmiEventInfo* eventInfo) { + + ModelInstance* comp = (ModelInstance *)c; + + int timeEvent = 0; + + if (invalidState(comp, "fmiEventUpdate", modelInitialized)) + return fmiError; + + if (nullPointer(comp, "fmiEventUpdate", "eventInfo", eventInfo)) + return fmiError; + + comp->newDiscreteStatesNeeded = false; + comp->terminateSimulation = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->valuesOfContinuousStatesChanged = false; + + if (comp->nextEventTimeDefined && comp->nextEventTime <= comp->time) { + timeEvent = 1; + } + + eventUpdate(comp); + + // copy internal eventInfo of component to output eventInfo + eventInfo->iterationConverged = fmiTrue; + eventInfo->stateValueReferencesChanged = fmiFalse; + eventInfo->stateValuesChanged = comp->valuesOfContinuousStatesChanged; + eventInfo->terminateSimulation = comp->terminateSimulation; + eventInfo->upcomingTimeEvent = comp->nextEventTimeDefined; + eventInfo->nextEventTime = comp->nextEventTime; + + return fmiOK; +} + +fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean* callEventUpdate) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiCompletedIntegratorStep", modelInitialized)) + return fmiError; + + if (nullPointer(comp, "fmiCompletedIntegratorStep", "callEventUpdate", callEventUpdate)) + return fmiError; + + return fmiOK; +} + +fmiStatus fmiGetStateValueReferences(fmiComponent c, fmiValueReference vrx[], size_t nx) { +// int i; +// ModelInstance* comp = (ModelInstance *)c; +// if (invalidState(comp, "fmiGetStateValueReferences", not_modelError)) +// return fmiError; +// if (invalidNumber(comp, "fmiGetStateValueReferences", "nx", nx, NUMBER_OF_STATES)) +// return fmiError; +// if (nullPointer(comp, "fmiGetStateValueReferences", "vrx[]", vrx)) +// return fmiError; +//#if NUMBER_OF_STATES>0 +// for (i=0; iloggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", +// "fmiGetStateValueReferences: vrx[%d] = %d", i, vrx[i]); +// } +//#endif + return fmiOK; +} + +fmiStatus fmiGetContinuousStates(fmiComponent c, fmiReal states[], size_t nx){ + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmiGetContinuousStates", not_modelError)) + return fmiError; + + if (invalidNumber(comp, "fmiGetContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmiError; + + if (nullPointer(comp, "fmiGetContinuousStates", "states[]", states)) + return fmiError; + + getContinuousStates(comp, states, nx); + + return fmiOK; +} + +fmiStatus fmiGetNominalContinuousStates(fmiComponent c, fmiReal x_nominal[], size_t nx) { +// int i; +// ModelInstance* comp = (ModelInstance *)c; +// if (invalidState(comp, "fmiGetNominalContinuousStates", not_modelError)) +// return fmiError; +// if (invalidNumber(comp, "fmiGetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES)) +// return fmiError; +// if (nullPointer(comp, "fmiGetNominalContinuousStates", "x_nominal[]", x_nominal)) +// return fmiError; +// if (comp->loggingOn) comp->functions.logger(c, comp->instanceName, fmiOK, "log", +// "fmiGetNominalContinuousStates: x_nominal[0..%d] = 1.0", nx-1); +// for (i=0; i -#include -#include -#include - -#include "config.h" -#include "model.h" -#include "slave.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" - -static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; - -#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 (modelStartAndEnd | modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi2GetVersion MASK_fmi2GetTypesPlatform -#define MASK_fmi2SetDebugLogging (modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi2Instantiate (modelStartAndEnd) -#define MASK_fmi2FreeInstance (modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi2SetupExperiment modelInstantiated -#define MASK_fmi2EnterInitializationMode modelInstantiated -#define MASK_fmi2ExitInitializationMode modelInitializationMode -#define MASK_fmi2Terminate (modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed) -#define MASK_fmi2Reset MASK_fmi2FreeInstance -#define MASK_fmi2GetReal (modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi2GetInteger MASK_fmi2GetReal -#define MASK_fmi2GetBoolean MASK_fmi2GetReal -#define MASK_fmi2GetString MASK_fmi2GetReal -#define MASK_fmi2SetReal (modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete) -#define MASK_fmi2SetInteger (modelInstantiated | modelInitializationMode \ -| modelEventMode \ -| modelStepComplete) -#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 (modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) - -// --------------------------------------------------------------------------- -// Function calls allowed state masks for Model-exchange -// --------------------------------------------------------------------------- -#define MASK_fmi2EnterEventMode (modelEventMode | modelContinuousTimeMode) -#define MASK_fmi2NewDiscreteStates modelEventMode -#define MASK_fmi2EnterContinuousTimeMode modelEventMode -#define MASK_fmi2CompletedIntegratorStep modelContinuousTimeMode -#define MASK_fmi2SetTime (modelEventMode | modelContinuousTimeMode) -#define MASK_fmi2SetContinuousStates modelContinuousTimeMode -#define MASK_fmi2GetEventIndicators (modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelTerminated | modelError) -#define MASK_fmi2GetContinuousStates MASK_fmi2GetEventIndicators -#define MASK_fmi2GetDerivatives (modelEventMode | modelContinuousTimeMode \ -| modelTerminated | modelError) -#define MASK_fmi2GetNominalsOfContinuousStates ( modelInstantiated \ -| modelEventMode | modelContinuousTimeMode \ -| modelTerminated | modelError) - -// --------------------------------------------------------------------------- -// Function calls allowed state masks for Co-simulation -// --------------------------------------------------------------------------- -#define MASK_fmi2SetRealInputDerivatives (modelInstantiated | modelInitializationMode \ -| modelStepComplete) -#define MASK_fmi2GetRealOutputDerivatives (modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi2DoStep modelStepComplete -#define MASK_fmi2CancelStep modelStepInProgress -#define MASK_fmi2GetStatus (modelStepComplete | modelStepInProgress | modelStepFailed \ -| modelTerminated) -#define MASK_fmi2GetRealStatus MASK_fmi2GetStatus -#define MASK_fmi2GetIntegerStatus MASK_fmi2GetStatus -#define MASK_fmi2GetBooleanStatus MASK_fmi2GetStatus -#define MASK_fmi2GetStringStatus MASK_fmi2GetStatus - -// --------------------------------------------------------------------------- -// Private helpers used below to validate function arguments -// --------------------------------------------------------------------------- - -fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); - -static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int statesExpected) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, fName, statesExpected)) - return fmi2Error; - logError(comp, "%s: Function not implemented.", fName); - return fmi2Error; -} - -// --------------------------------------------------------------------------- -// Private helpers logger -// --------------------------------------------------------------------------- - -// return fmi2True if logging category is on. Else return fmi2False. -fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { - if (categoryIndex < NUMBER_OF_CATEGORIES - && (comp->logCategories[categoryIndex] || comp->logCategories[LOG_ALL])) { - return fmi2True; - } - return fmi2False; -} - -// --------------------------------------------------------------------------- -// FMI functions -// --------------------------------------------------------------------------- -fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID, - fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions, - fmi2Boolean visible, fmi2Boolean loggingOn) { - - return createModelInstance( - (loggerType)functions->logger, - (allocateMemoryType)functions->allocateMemory, - (freeMemoryType)functions->freeMemory, - functions->componentEnvironment, - instanceName, - fmuGUID, - fmuResourceLocation, - loggingOn, - fmuType - ); -} - -fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance, - fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime) { - - // ignore arguments: stopTimeDefined, stopTime - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2SetupExperiment", MASK_fmi2SetupExperiment)) - return fmi2Error; - - comp->time = startTime; - - return fmi2OK; -} - -fmi2Status fmi2EnterInitializationMode(fmi2Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2EnterInitializationMode", MASK_fmi2EnterInitializationMode)) - return fmi2Error; - comp->state = modelInitializationMode; - return fmi2OK; -} - -fmi2Status fmi2ExitInitializationMode(fmi2Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2ExitInitializationMode", MASK_fmi2ExitInitializationMode)) - return fmi2Error; - - // if values were set and no fmi2GetXXX triggered update before, - // ensure calculated values are updated now - if (comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - if (comp->type == ModelExchange) { - comp->state = modelEventMode; - comp->isNewEventIteration = false; - } - else comp->state = modelStepComplete; - return fmi2OK; -} - -fmi2Status fmi2Terminate(fmi2Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2Terminate", MASK_fmi2Terminate)) - return fmi2Error; - comp->state = modelTerminated; - return fmi2OK; -} - -fmi2Status fmi2Reset(fmi2Component c) { - ModelInstance* comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2Reset", MASK_fmi2Reset)) - return fmi2Error; - comp->state = modelInstantiated; - setStartValues(comp); // to be implemented by the includer of this file - comp->isDirtyValues = true; // because we just called setStartValues - return fmi2OK; -} - -void fmi2FreeInstance(fmi2Component c) { - - ModelInstance *comp = (ModelInstance *)c; - - if (!comp) return; - - if (invalidState(comp, "fmi2FreeInstance", MASK_fmi2FreeInstance)) - return; - - freeModelInstance(comp); -} - -// --------------------------------------------------------------------------- -// 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[]) { - int i, j; - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2SetDebugLogging", MASK_fmi2SetDebugLogging)) - return fmi2Error; - comp->loggingOn = loggingOn; - - // reset all categories - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - comp->logCategories[j] = fmi2False; - } - - if (nCategories == 0) { - // no category specified, set all categories to have loggingOn value - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - comp->logCategories[j] = loggingOn; - } - } else { - // set specific categories on - for (i = 0; i < nCategories; i++) { - fmi2Boolean categoryFound = fmi2False; - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - if (strcmp(logCategoriesNames[j], categories[i]) == 0) { - comp->logCategories[j] = loggingOn; - categoryFound = fmi2True; - break; - } - } - if (!categoryFound) { - comp->logger(comp->componentEnvironment, comp->instanceName, fmi2Warning, - logCategoriesNames[LOG_ERROR], - "logging category '%s' is not supported by model", categories[i]); - } - } - } - return fmi2OK; -} - -fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetReal", MASK_fmi2GetReal)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2GetReal", "vr[]", vr)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2GetReal", "value[]", value)) - return fmi2Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_VARIABLES(Float64) -} - -fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetInteger", MASK_fmi2GetInteger)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2GetInteger", "vr[]", vr)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2GetInteger", "value[]", value)) - return fmi2Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_VARIABLES(Int32) -} - -fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetBoolean", MASK_fmi2GetBoolean)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2GetBoolean", "vr[]", vr)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2GetBoolean", "value[]", value)) - return fmi2Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_BOOLEAN_VARIABLES -} - -fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetString", MASK_fmi2GetString)) - return fmi2Error; - - if (nvr>0 && nullPointer(comp, "fmi2GetString", "vr[]", vr)) - return fmi2Error; - - if (nvr>0 && nullPointer(comp, "fmi2GetString", "value[]", value)) - return fmi2Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_VARIABLES(String) -} - -fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2SetReal", MASK_fmi2SetReal)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2SetReal", "vr[]", vr)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2SetReal", "value[]", value)) - return fmi2Error; - - SET_VARIABLES(Float64) -} - -fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2SetInteger", MASK_fmi2SetInteger)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2SetInteger", "vr[]", vr)) - return fmi2Error; - - if (nvr > 0 && nullPointer(comp, "fmi2SetInteger", "value[]", value)) - return fmi2Error; - - SET_VARIABLES(Int32) -} - -fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2SetBoolean", MASK_fmi2SetBoolean)) - return fmi2Error; - - if (nvr>0 && nullPointer(comp, "fmi2SetBoolean", "vr[]", vr)) - return fmi2Error; - - if (nvr>0 && nullPointer(comp, "fmi2SetBoolean", "value[]", value)) - return fmi2Error; - - SET_BOOLEAN_VARIABLES -} - -fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2SetString", MASK_fmi2SetString)) - return fmi2Error; - - if (nvr>0 && nullPointer(comp, "fmi2SetString", "vr[]", vr)) - return fmi2Error; - - if (nvr>0 && nullPointer(comp, "fmi2SetString", "value[]", value)) - return fmi2Error; - - SET_VARIABLES(String) -} - -fmi2Status fmi2GetFMUstate (fmi2Component c, fmi2FMUstate* FMUstate) { - ModelInstance *comp = (ModelInstance *)c; - ModelData *modelData = comp->allocateMemory(1, sizeof(ModelData)); - memcpy(modelData, comp->modelData, sizeof(ModelData)); - *FMUstate = modelData; - return fmi2OK; -} - -fmi2Status fmi2SetFMUstate (fmi2Component c, fmi2FMUstate FMUstate) { - ModelInstance *comp = (ModelInstance *)c; - ModelData *modelData = FMUstate; - memcpy(comp->modelData, modelData, sizeof(ModelData)); - return fmi2OK; -} - -fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate* FMUstate) { - ModelInstance *comp = (ModelInstance *)c; - ModelData *modelData = *FMUstate; - comp->freeMemory(modelData); - *FMUstate = NULL; - return fmi2OK; -} - -fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate FMUstate, size_t *size) { - *size = sizeof(ModelData); - return fmi2OK; -} - -fmi2Status fmi2SerializeFMUstate (fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte serializedState[], size_t size) { - ModelInstance *comp = (ModelInstance *)c; - // TODO: check size - memcpy(serializedState, comp->modelData, sizeof(ModelData)); - return fmi2OK; -} - -fmi2Status fmi2DeSerializeFMUstate (fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate* FMUstate) { - - ModelInstance *comp = (ModelInstance *)c; - - if (*FMUstate == NULL) { - *FMUstate = comp->allocateMemory(1, sizeof(ModelData)); - } - - // TODO: check size - - memcpy(*FMUstate, serializedState, sizeof(ModelData)); - - 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[]) { - return unsupportedFunction(c, "fmi2GetDirectionalDerivative", MASK_fmi2GetDirectionalDerivative); -} - -// --------------------------------------------------------------------------- -// 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[]) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2SetRealInputDerivatives", MASK_fmi2SetRealInputDerivatives)) { - return fmi2Error; - } - logError(comp, "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[]) { - int i; - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2GetRealOutputDerivatives", MASK_fmi2GetRealOutputDerivatives)) - return fmi2Error; - logError(comp, "fmi2GetRealOutputDerivatives: ignoring function call." - " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); - for (i = 0; i < nvr; i++) value[i] = 0; - return fmi2Error; -} - -fmi2Status fmi2CancelStep(fmi2Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2CancelStep", MASK_fmi2CancelStep)) { - // always fmi2CancelStep is invalid, because model is never in modelStepInProgress state. - return fmi2Error; - } - logError(comp, "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) { - ModelInstance *comp = (ModelInstance *)c; - - if (communicationStepSize <= 0) { - logError(comp, "fmi2DoStep: communication step size must be > 0. Fount %g.", communicationStepSize); - comp->state = modelError; - return fmi2Error; - } - - return doStep(comp, currentCommunicationPoint, currentCommunicationPoint + communicationStepSize); -} - -/* Inquire slave status */ -static fmi2Status getStatus(char* fname, fmi2Component c, const fmi2StatusKind s) { - const char *statusKind[3] = {"fmi2DoStepStatus","fmi2PendingStatus","fmi2LastSuccessfulTime"}; - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, fname, MASK_fmi2GetStatus)) // all get status have the same MASK_fmi2GetStatus - return fmi2Error; - - switch(s) { - case fmi2DoStepStatus: logError(comp, - "%s: Can be called with fmi2DoStepStatus when fmi2DoStep returned fmi2Pending." - " This is not the case.", fname); - break; - case fmi2PendingStatus: logError(comp, - "%s: Can be called with fmi2PendingStatus when fmi2DoStep returned fmi2Pending." - " This is not the case.", fname); - break; - case fmi2LastSuccessfulTime: logError(comp, - "%s: Can be called with fmi2LastSuccessfulTime when fmi2DoStep returned fmi2Discard." - " This is not the case.", fname); - break; - case fmi2Terminated: logError(comp, - "%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) { - return getStatus("fmi2GetStatus", c, s); -} - -fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real *value) { - if (s == fmi2LastSuccessfulTime) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2GetRealStatus", MASK_fmi2GetRealStatus)) - return fmi2Error; - *value = comp->time; - return fmi2OK; - } - return getStatus("fmi2GetRealStatus", c, s); -} - -fmi2Status fmi2GetIntegerStatus(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value) { - return getStatus("fmi2GetIntegerStatus", c, s); -} - -fmi2Status fmi2GetBooleanStatus(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value) { - if (s == fmi2Terminated) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2GetBooleanStatus", MASK_fmi2GetBooleanStatus)) - return fmi2Error; - *value = comp->terminateSimulation; - return fmi2OK; - } - return getStatus("fmi2GetBooleanStatus", c, s); -} - -fmi2Status fmi2GetStringStatus(fmi2Component c, const fmi2StatusKind s, fmi2String *value) { - return getStatus("fmi2GetStringStatus", c, s); -} - -// --------------------------------------------------------------------------- -// Functions for FMI2 for Model Exchange -// --------------------------------------------------------------------------- -/* Enter and exit the different modes */ -fmi2Status fmi2EnterEventMode(fmi2Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2EnterEventMode", MASK_fmi2EnterEventMode)) - return fmi2Error; - comp->state = modelEventMode; - comp->isNewEventIteration = fmi2True; - return fmi2OK; -} - -fmi2Status fmi2NewDiscreteStates(fmi2Component c, fmi2EventInfo *eventInfo) { - ModelInstance *comp = (ModelInstance *)c; - int timeEvent = 0; - if (invalidState(comp, "fmi2NewDiscreteStates", MASK_fmi2NewDiscreteStates)) - return fmi2Error; - comp->newDiscreteStatesNeeded = fmi2False; - comp->terminateSimulation = fmi2False; - comp->nominalsOfContinuousStatesChanged = fmi2False; - comp->valuesOfContinuousStatesChanged = fmi2False; - - if (comp->nextEventTimeDefined && comp->nextEventTime <= comp->time) { - timeEvent = 1; - } - - eventUpdate(comp); - - comp->isNewEventIteration = false; - - // copy internal eventInfo of component to output eventInfo - eventInfo->newDiscreteStatesNeeded = comp->newDiscreteStatesNeeded; - eventInfo->terminateSimulation = comp->terminateSimulation; - eventInfo->nominalsOfContinuousStatesChanged = comp->nominalsOfContinuousStatesChanged; - eventInfo->valuesOfContinuousStatesChanged = comp->valuesOfContinuousStatesChanged; - eventInfo->nextEventTimeDefined = comp->nextEventTimeDefined; - eventInfo->nextEventTime = comp->nextEventTime; - - return fmi2OK; -} - -fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2EnterContinuousTimeMode", MASK_fmi2EnterContinuousTimeMode)) - return fmi2Error; - comp->state = modelContinuousTimeMode; - return fmi2OK; -} - -fmi2Status fmi2CompletedIntegratorStep(fmi2Component c, fmi2Boolean noSetFMUStatePriorToCurrentPoint, - fmi2Boolean *enterEventMode, fmi2Boolean *terminateSimulation) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2CompletedIntegratorStep", MASK_fmi2CompletedIntegratorStep)) - return fmi2Error; - if (nullPointer(comp, "fmi2CompletedIntegratorStep", "enterEventMode", enterEventMode)) - return fmi2Error; - if (nullPointer(comp, "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) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2SetTime", MASK_fmi2SetTime)) - return fmi2Error; - comp->time = time; - return fmi2OK; -} - -fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t nx){ - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2SetContinuousStates", MASK_fmi2SetContinuousStates)) - return fmi2Error; - - if (invalidNumber(comp, "fmi2SetContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmi2Error; - - if (nullPointer(comp, "fmi2SetContinuousStates", "x[]", x)) - return fmi2Error; - - setContinuousStates(comp, x, nx); - - return fmi2OK; -} - -/* Evaluation of the model equations */ -fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetDerivatives", MASK_fmi2GetDerivatives)) - return fmi2Error; - - if (invalidNumber(comp, "fmi2GetDerivatives", "nx", nx, NUMBER_OF_STATES)) - return fmi2Error; - - if (nullPointer(comp, "fmi2GetDerivatives", "derivatives[]", derivatives)) - return fmi2Error; - - getDerivatives(comp, derivatives, nx); - - return fmi2OK; -} - -fmi2Status fmi2GetEventIndicators(fmi2Component c, fmi2Real eventIndicators[], size_t ni) { - -#if NUMBER_OF_EVENT_INDICATORS > 0 - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetEventIndicators", MASK_fmi2GetEventIndicators)) - return fmi2Error; - - if (invalidNumber(comp, "fmi2GetEventIndicators", "ni", ni, NUMBER_OF_EVENT_INDICATORS)) - return fmi2Error; - - getEventIndicators(comp, eventIndicators, ni); -#else - if (ni > 0) return fmi2Error; -#endif - return fmi2OK; -} - -fmi2Status fmi2GetContinuousStates(fmi2Component c, fmi2Real states[], size_t nx) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi2GetContinuousStates", MASK_fmi2GetContinuousStates)) - return fmi2Error; - - if (invalidNumber(comp, "fmi2GetContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmi2Error; - - if (nullPointer(comp, "fmi2GetContinuousStates", "states[]", states)) - return fmi2Error; - - getContinuousStates(comp, states, nx); - - return fmi2OK; -} - -fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c, fmi2Real x_nominal[], size_t nx) { - int i; - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2GetNominalsOfContinuousStates", MASK_fmi2GetNominalsOfContinuousStates)) - return fmi2Error; - if (invalidNumber(comp, "fmi2GetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmi2Error; - if (nullPointer(comp, "fmi2GetNominalContinuousStates", "x_nominal[]", x_nominal)) - return fmi2Error; - for (i = 0; i < nx; i++) - x_nominal[i] = 1; - return fmi2OK; -} +/**************************************************************** + * Copyright (c) Dassault Systemes. All rights reserved. * + * This file is part of the Test-FMUs. See LICENSE.txt in the * + * project root for license information. * + ****************************************************************/ + +#include +#include +#include +#include + +#include "config.h" +#include "model.h" +#include "slave.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" + +static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; + +#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 (modelStartAndEnd | modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi2GetVersion MASK_fmi2GetTypesPlatform +#define MASK_fmi2SetDebugLogging (modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi2Instantiate (modelStartAndEnd) +#define MASK_fmi2FreeInstance (modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi2SetupExperiment modelInstantiated +#define MASK_fmi2EnterInitializationMode modelInstantiated +#define MASK_fmi2ExitInitializationMode modelInitializationMode +#define MASK_fmi2Terminate (modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed) +#define MASK_fmi2Reset MASK_fmi2FreeInstance +#define MASK_fmi2GetReal (modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi2GetInteger MASK_fmi2GetReal +#define MASK_fmi2GetBoolean MASK_fmi2GetReal +#define MASK_fmi2GetString MASK_fmi2GetReal +#define MASK_fmi2SetReal (modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete) +#define MASK_fmi2SetInteger (modelInstantiated | modelInitializationMode \ +| modelEventMode \ +| modelStepComplete) +#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 (modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for Model-exchange +// --------------------------------------------------------------------------- +#define MASK_fmi2EnterEventMode (modelEventMode | modelContinuousTimeMode) +#define MASK_fmi2NewDiscreteStates modelEventMode +#define MASK_fmi2EnterContinuousTimeMode modelEventMode +#define MASK_fmi2CompletedIntegratorStep modelContinuousTimeMode +#define MASK_fmi2SetTime (modelEventMode | modelContinuousTimeMode) +#define MASK_fmi2SetContinuousStates modelContinuousTimeMode +#define MASK_fmi2GetEventIndicators (modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelTerminated | modelError) +#define MASK_fmi2GetContinuousStates MASK_fmi2GetEventIndicators +#define MASK_fmi2GetDerivatives (modelEventMode | modelContinuousTimeMode \ +| modelTerminated | modelError) +#define MASK_fmi2GetNominalsOfContinuousStates ( modelInstantiated \ +| modelEventMode | modelContinuousTimeMode \ +| modelTerminated | modelError) + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for Co-simulation +// --------------------------------------------------------------------------- +#define MASK_fmi2SetRealInputDerivatives (modelInstantiated | modelInitializationMode \ +| modelStepComplete) +#define MASK_fmi2GetRealOutputDerivatives (modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi2DoStep modelStepComplete +#define MASK_fmi2CancelStep modelStepInProgress +#define MASK_fmi2GetStatus (modelStepComplete | modelStepInProgress | modelStepFailed \ +| modelTerminated) +#define MASK_fmi2GetRealStatus MASK_fmi2GetStatus +#define MASK_fmi2GetIntegerStatus MASK_fmi2GetStatus +#define MASK_fmi2GetBooleanStatus MASK_fmi2GetStatus +#define MASK_fmi2GetStringStatus MASK_fmi2GetStatus + +// --------------------------------------------------------------------------- +// Private helpers used below to validate function arguments +// --------------------------------------------------------------------------- + +fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); + +static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int statesExpected) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, fName, statesExpected)) + return fmi2Error; + logError(comp, "%s: Function not implemented.", fName); + return fmi2Error; +} + +// --------------------------------------------------------------------------- +// Private helpers logger +// --------------------------------------------------------------------------- + +// return fmi2True if logging category is on. Else return fmi2False. +fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { + if (categoryIndex < NUMBER_OF_CATEGORIES + && (comp->logCategories[categoryIndex] || comp->logCategories[LOG_ALL])) { + return fmi2True; + } + return fmi2False; +} + +// --------------------------------------------------------------------------- +// FMI functions +// --------------------------------------------------------------------------- +fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID, + fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions, + fmi2Boolean visible, fmi2Boolean loggingOn) { + + return createModelInstance( + (loggerType)functions->logger, + (allocateMemoryType)functions->allocateMemory, + (freeMemoryType)functions->freeMemory, + functions->componentEnvironment, + instanceName, + fmuGUID, + fmuResourceLocation, + loggingOn, + fmuType + ); +} + +fmi2Status fmi2SetupExperiment(fmi2Component c, fmi2Boolean toleranceDefined, fmi2Real tolerance, + fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime) { + + // ignore arguments: stopTimeDefined, stopTime + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2SetupExperiment", MASK_fmi2SetupExperiment)) + return fmi2Error; + + comp->time = startTime; + + return fmi2OK; +} + +fmi2Status fmi2EnterInitializationMode(fmi2Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2EnterInitializationMode", MASK_fmi2EnterInitializationMode)) + return fmi2Error; + comp->state = modelInitializationMode; + return fmi2OK; +} + +fmi2Status fmi2ExitInitializationMode(fmi2Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2ExitInitializationMode", MASK_fmi2ExitInitializationMode)) + return fmi2Error; + + // if values were set and no fmi2GetXXX triggered update before, + // ensure calculated values are updated now + if (comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + if (comp->type == ModelExchange) { + comp->state = modelEventMode; + comp->isNewEventIteration = false; + } + else comp->state = modelStepComplete; + return fmi2OK; +} + +fmi2Status fmi2Terminate(fmi2Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2Terminate", MASK_fmi2Terminate)) + return fmi2Error; + comp->state = modelTerminated; + return fmi2OK; +} + +fmi2Status fmi2Reset(fmi2Component c) { + ModelInstance* comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2Reset", MASK_fmi2Reset)) + return fmi2Error; + comp->state = modelInstantiated; + setStartValues(comp); // to be implemented by the includer of this file + comp->isDirtyValues = true; // because we just called setStartValues + return fmi2OK; +} + +void fmi2FreeInstance(fmi2Component c) { + + ModelInstance *comp = (ModelInstance *)c; + + if (!comp) return; + + if (invalidState(comp, "fmi2FreeInstance", MASK_fmi2FreeInstance)) + return; + + freeModelInstance(comp); +} + +// --------------------------------------------------------------------------- +// 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[]) { + int i, j; + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2SetDebugLogging", MASK_fmi2SetDebugLogging)) + return fmi2Error; + comp->loggingOn = loggingOn; + + // reset all categories + for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + comp->logCategories[j] = fmi2False; + } + + if (nCategories == 0) { + // no category specified, set all categories to have loggingOn value + for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + comp->logCategories[j] = loggingOn; + } + } else { + // set specific categories on + for (i = 0; i < nCategories; i++) { + fmi2Boolean categoryFound = fmi2False; + for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + if (strcmp(logCategoriesNames[j], categories[i]) == 0) { + comp->logCategories[j] = loggingOn; + categoryFound = fmi2True; + break; + } + } + if (!categoryFound) { + comp->logger(comp->componentEnvironment, comp->instanceName, fmi2Warning, + logCategoriesNames[LOG_ERROR], + "logging category '%s' is not supported by model", categories[i]); + } + } + } + return fmi2OK; +} + +fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetReal", MASK_fmi2GetReal)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2GetReal", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2GetReal", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_VARIABLES(Float64) +} + +fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetInteger", MASK_fmi2GetInteger)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2GetInteger", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2GetInteger", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_VARIABLES(Int32) +} + +fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetBoolean", MASK_fmi2GetBoolean)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2GetBoolean", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2GetBoolean", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_BOOLEAN_VARIABLES +} + +fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetString", MASK_fmi2GetString)) + return fmi2Error; + + if (nvr>0 && nullPointer(comp, "fmi2GetString", "vr[]", vr)) + return fmi2Error; + + if (nvr>0 && nullPointer(comp, "fmi2GetString", "value[]", value)) + return fmi2Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_VARIABLES(String) +} + +fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2SetReal", MASK_fmi2SetReal)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2SetReal", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2SetReal", "value[]", value)) + return fmi2Error; + + SET_VARIABLES(Float64) +} + +fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2SetInteger", MASK_fmi2SetInteger)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2SetInteger", "vr[]", vr)) + return fmi2Error; + + if (nvr > 0 && nullPointer(comp, "fmi2SetInteger", "value[]", value)) + return fmi2Error; + + SET_VARIABLES(Int32) +} + +fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2SetBoolean", MASK_fmi2SetBoolean)) + return fmi2Error; + + if (nvr>0 && nullPointer(comp, "fmi2SetBoolean", "vr[]", vr)) + return fmi2Error; + + if (nvr>0 && nullPointer(comp, "fmi2SetBoolean", "value[]", value)) + return fmi2Error; + + SET_BOOLEAN_VARIABLES +} + +fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2SetString", MASK_fmi2SetString)) + return fmi2Error; + + if (nvr>0 && nullPointer(comp, "fmi2SetString", "vr[]", vr)) + return fmi2Error; + + if (nvr>0 && nullPointer(comp, "fmi2SetString", "value[]", value)) + return fmi2Error; + + SET_VARIABLES(String) +} + +fmi2Status fmi2GetFMUstate (fmi2Component c, fmi2FMUstate* FMUstate) { + ModelInstance *comp = (ModelInstance *)c; + ModelData *modelData = comp->allocateMemory(1, sizeof(ModelData)); + memcpy(modelData, comp->modelData, sizeof(ModelData)); + *FMUstate = modelData; + return fmi2OK; +} + +fmi2Status fmi2SetFMUstate (fmi2Component c, fmi2FMUstate FMUstate) { + ModelInstance *comp = (ModelInstance *)c; + ModelData *modelData = FMUstate; + memcpy(comp->modelData, modelData, sizeof(ModelData)); + return fmi2OK; +} + +fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate* FMUstate) { + ModelInstance *comp = (ModelInstance *)c; + ModelData *modelData = *FMUstate; + comp->freeMemory(modelData); + *FMUstate = NULL; + return fmi2OK; +} + +fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate FMUstate, size_t *size) { + *size = sizeof(ModelData); + return fmi2OK; +} + +fmi2Status fmi2SerializeFMUstate (fmi2Component c, fmi2FMUstate FMUstate, fmi2Byte serializedState[], size_t size) { + ModelInstance *comp = (ModelInstance *)c; + // TODO: check size + memcpy(serializedState, comp->modelData, sizeof(ModelData)); + return fmi2OK; +} + +fmi2Status fmi2DeSerializeFMUstate (fmi2Component c, const fmi2Byte serializedState[], size_t size, fmi2FMUstate* FMUstate) { + + ModelInstance *comp = (ModelInstance *)c; + + if (*FMUstate == NULL) { + *FMUstate = comp->allocateMemory(1, sizeof(ModelData)); + } + + // TODO: check size + + memcpy(*FMUstate, serializedState, sizeof(ModelData)); + + 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[]) { + return unsupportedFunction(c, "fmi2GetDirectionalDerivative", MASK_fmi2GetDirectionalDerivative); +} + +// --------------------------------------------------------------------------- +// 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[]) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2SetRealInputDerivatives", MASK_fmi2SetRealInputDerivatives)) { + return fmi2Error; + } + logError(comp, "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[]) { + int i; + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2GetRealOutputDerivatives", MASK_fmi2GetRealOutputDerivatives)) + return fmi2Error; + logError(comp, "fmi2GetRealOutputDerivatives: ignoring function call." + " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); + for (i = 0; i < nvr; i++) value[i] = 0; + return fmi2Error; +} + +fmi2Status fmi2CancelStep(fmi2Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2CancelStep", MASK_fmi2CancelStep)) { + // always fmi2CancelStep is invalid, because model is never in modelStepInProgress state. + return fmi2Error; + } + logError(comp, "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) { + ModelInstance *comp = (ModelInstance *)c; + + if (communicationStepSize <= 0) { + logError(comp, "fmi2DoStep: communication step size must be > 0. Fount %g.", communicationStepSize); + comp->state = modelError; + return fmi2Error; + } + + return doStep(comp, currentCommunicationPoint, currentCommunicationPoint + communicationStepSize); +} + +/* Inquire slave status */ +static fmi2Status getStatus(char* fname, fmi2Component c, const fmi2StatusKind s) { + const char *statusKind[3] = {"fmi2DoStepStatus","fmi2PendingStatus","fmi2LastSuccessfulTime"}; + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, fname, MASK_fmi2GetStatus)) // all get status have the same MASK_fmi2GetStatus + return fmi2Error; + + switch(s) { + case fmi2DoStepStatus: logError(comp, + "%s: Can be called with fmi2DoStepStatus when fmi2DoStep returned fmi2Pending." + " This is not the case.", fname); + break; + case fmi2PendingStatus: logError(comp, + "%s: Can be called with fmi2PendingStatus when fmi2DoStep returned fmi2Pending." + " This is not the case.", fname); + break; + case fmi2LastSuccessfulTime: logError(comp, + "%s: Can be called with fmi2LastSuccessfulTime when fmi2DoStep returned fmi2Discard." + " This is not the case.", fname); + break; + case fmi2Terminated: logError(comp, + "%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) { + return getStatus("fmi2GetStatus", c, s); +} + +fmi2Status fmi2GetRealStatus(fmi2Component c, const fmi2StatusKind s, fmi2Real *value) { + if (s == fmi2LastSuccessfulTime) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2GetRealStatus", MASK_fmi2GetRealStatus)) + return fmi2Error; + *value = comp->time; + return fmi2OK; + } + return getStatus("fmi2GetRealStatus", c, s); +} + +fmi2Status fmi2GetIntegerStatus(fmi2Component c, const fmi2StatusKind s, fmi2Integer *value) { + return getStatus("fmi2GetIntegerStatus", c, s); +} + +fmi2Status fmi2GetBooleanStatus(fmi2Component c, const fmi2StatusKind s, fmi2Boolean *value) { + if (s == fmi2Terminated) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2GetBooleanStatus", MASK_fmi2GetBooleanStatus)) + return fmi2Error; + *value = comp->terminateSimulation; + return fmi2OK; + } + return getStatus("fmi2GetBooleanStatus", c, s); +} + +fmi2Status fmi2GetStringStatus(fmi2Component c, const fmi2StatusKind s, fmi2String *value) { + return getStatus("fmi2GetStringStatus", c, s); +} + +// --------------------------------------------------------------------------- +// Functions for FMI2 for Model Exchange +// --------------------------------------------------------------------------- +/* Enter and exit the different modes */ +fmi2Status fmi2EnterEventMode(fmi2Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2EnterEventMode", MASK_fmi2EnterEventMode)) + return fmi2Error; + comp->state = modelEventMode; + comp->isNewEventIteration = fmi2True; + return fmi2OK; +} + +fmi2Status fmi2NewDiscreteStates(fmi2Component c, fmi2EventInfo *eventInfo) { + ModelInstance *comp = (ModelInstance *)c; + int timeEvent = 0; + if (invalidState(comp, "fmi2NewDiscreteStates", MASK_fmi2NewDiscreteStates)) + return fmi2Error; + comp->newDiscreteStatesNeeded = fmi2False; + comp->terminateSimulation = fmi2False; + comp->nominalsOfContinuousStatesChanged = fmi2False; + comp->valuesOfContinuousStatesChanged = fmi2False; + + if (comp->nextEventTimeDefined && comp->nextEventTime <= comp->time) { + timeEvent = 1; + } + + eventUpdate(comp); + + comp->isNewEventIteration = false; + + // copy internal eventInfo of component to output eventInfo + eventInfo->newDiscreteStatesNeeded = comp->newDiscreteStatesNeeded; + eventInfo->terminateSimulation = comp->terminateSimulation; + eventInfo->nominalsOfContinuousStatesChanged = comp->nominalsOfContinuousStatesChanged; + eventInfo->valuesOfContinuousStatesChanged = comp->valuesOfContinuousStatesChanged; + eventInfo->nextEventTimeDefined = comp->nextEventTimeDefined; + eventInfo->nextEventTime = comp->nextEventTime; + + return fmi2OK; +} + +fmi2Status fmi2EnterContinuousTimeMode(fmi2Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2EnterContinuousTimeMode", MASK_fmi2EnterContinuousTimeMode)) + return fmi2Error; + comp->state = modelContinuousTimeMode; + return fmi2OK; +} + +fmi2Status fmi2CompletedIntegratorStep(fmi2Component c, fmi2Boolean noSetFMUStatePriorToCurrentPoint, + fmi2Boolean *enterEventMode, fmi2Boolean *terminateSimulation) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2CompletedIntegratorStep", MASK_fmi2CompletedIntegratorStep)) + return fmi2Error; + if (nullPointer(comp, "fmi2CompletedIntegratorStep", "enterEventMode", enterEventMode)) + return fmi2Error; + if (nullPointer(comp, "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) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2SetTime", MASK_fmi2SetTime)) + return fmi2Error; + comp->time = time; + return fmi2OK; +} + +fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t nx){ + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2SetContinuousStates", MASK_fmi2SetContinuousStates)) + return fmi2Error; + + if (invalidNumber(comp, "fmi2SetContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmi2Error; + + if (nullPointer(comp, "fmi2SetContinuousStates", "x[]", x)) + return fmi2Error; + + setContinuousStates(comp, x, nx); + + return fmi2OK; +} + +/* Evaluation of the model equations */ +fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetDerivatives", MASK_fmi2GetDerivatives)) + return fmi2Error; + + if (invalidNumber(comp, "fmi2GetDerivatives", "nx", nx, NUMBER_OF_STATES)) + return fmi2Error; + + if (nullPointer(comp, "fmi2GetDerivatives", "derivatives[]", derivatives)) + return fmi2Error; + + getDerivatives(comp, derivatives, nx); + + return fmi2OK; +} + +fmi2Status fmi2GetEventIndicators(fmi2Component c, fmi2Real eventIndicators[], size_t ni) { + +#if NUMBER_OF_EVENT_INDICATORS > 0 + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetEventIndicators", MASK_fmi2GetEventIndicators)) + return fmi2Error; + + if (invalidNumber(comp, "fmi2GetEventIndicators", "ni", ni, NUMBER_OF_EVENT_INDICATORS)) + return fmi2Error; + + getEventIndicators(comp, eventIndicators, ni); +#else + if (ni > 0) return fmi2Error; +#endif + return fmi2OK; +} + +fmi2Status fmi2GetContinuousStates(fmi2Component c, fmi2Real states[], size_t nx) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi2GetContinuousStates", MASK_fmi2GetContinuousStates)) + return fmi2Error; + + if (invalidNumber(comp, "fmi2GetContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmi2Error; + + if (nullPointer(comp, "fmi2GetContinuousStates", "states[]", states)) + return fmi2Error; + + getContinuousStates(comp, states, nx); + + return fmi2OK; +} + +fmi2Status fmi2GetNominalsOfContinuousStates(fmi2Component c, fmi2Real x_nominal[], size_t nx) { + int i; + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi2GetNominalsOfContinuousStates", MASK_fmi2GetNominalsOfContinuousStates)) + return fmi2Error; + if (invalidNumber(comp, "fmi2GetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmi2Error; + if (nullPointer(comp, "fmi2GetNominalContinuousStates", "x_nominal[]", x_nominal)) + return fmi2Error; + for (i = 0; i < nx; i++) + x_nominal[i] = 1; + return fmi2OK; +} diff --git a/src/fmi3.c b/src/fmi3Functions.c similarity index 97% rename from src/fmi3.c rename to src/fmi3Functions.c index 0719140..d13204b 100644 --- a/src/fmi3.c +++ b/src/fmi3Functions.c @@ -1,652 +1,652 @@ -/**************************************************************** - * Copyright (c) Dassault Systemes. All rights reserved. * - * This file is part of the Test-FMUs. See LICENSE.txt in the * - * project root for license information. * - ****************************************************************/ - -#include -#include -#include -#include - -#include "config.h" -#include "model.h" -#include "slave.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 fmi3_FUNCTION_PREFIX pasteB(MODEL_IDENTIFIER, _) -#endif -#include "fmi3Functions.h" - -static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; - -#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_fmi3GetTypesPlatform (modelStartAndEnd | modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi3GetVersion MASK_fmi3GetTypesPlatform -#define MASK_fmi3SetDebugLogging (modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi3Instantiate (modelStartAndEnd) -#define MASK_fmi3FreeInstance (modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi3SetupExperiment modelInstantiated -#define MASK_fmi3EnterInitializationMode modelInstantiated -#define MASK_fmi3ExitInitializationMode modelInitializationMode -#define MASK_fmi3Terminate (modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed) -#define MASK_fmi3Reset MASK_fmi3FreeInstance -#define MASK_fmi3GetReal (modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi3GetInteger MASK_fmi3GetReal -#define MASK_fmi3GetBoolean MASK_fmi3GetReal -#define MASK_fmi3GetString MASK_fmi3GetReal -#define MASK_fmi3SetReal (modelInstantiated | modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete) -#define MASK_fmi3SetInteger (modelInstantiated | modelInitializationMode \ -| modelEventMode \ -| modelStepComplete) -#define MASK_fmi3SetBoolean MASK_fmi3SetInteger -#define MASK_fmi3SetString MASK_fmi3SetInteger -#define MASK_fmi3GetFMUstate MASK_fmi3FreeInstance -#define MASK_fmi3SetFMUstate MASK_fmi3FreeInstance -#define MASK_fmi3FreeFMUstate MASK_fmi3FreeInstance -#define MASK_fmi3SerializedFMUstateSize MASK_fmi3FreeInstance -#define MASK_fmi3SerializeFMUstate MASK_fmi3FreeInstance -#define MASK_fmi3DeSerializeFMUstate MASK_fmi3FreeInstance -#define MASK_fmi3GetDirectionalDerivative (modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) - -// --------------------------------------------------------------------------- -// Function calls allowed state masks for Model-exchange -// --------------------------------------------------------------------------- -#define MASK_fmi3EnterEventMode (modelEventMode | modelContinuousTimeMode) -#define MASK_fmi3NewDiscreteStates modelEventMode -#define MASK_fmi3EnterContinuousTimeMode modelEventMode -#define MASK_fmi3CompletedIntegratorStep modelContinuousTimeMode -#define MASK_fmi3SetTime (modelEventMode | modelContinuousTimeMode) -#define MASK_fmi3SetContinuousStates modelContinuousTimeMode -#define MASK_fmi3GetEventIndicators (modelInitializationMode \ -| modelEventMode | modelContinuousTimeMode \ -| modelTerminated | modelError) -#define MASK_fmi3GetContinuousStates MASK_fmi3GetEventIndicators -#define MASK_fmi3GetDerivatives (modelEventMode | modelContinuousTimeMode \ -| modelTerminated | modelError) -#define MASK_fmi3GetNominalsOfContinuousStates ( modelInstantiated \ -| modelEventMode | modelContinuousTimeMode \ -| modelTerminated | modelError) - -// --------------------------------------------------------------------------- -// Function calls allowed state masks for Co-simulation -// --------------------------------------------------------------------------- -#define MASK_fmi3SetRealInputDerivatives (modelInstantiated | modelInitializationMode \ -| modelStepComplete) -#define MASK_fmi3GetRealOutputDerivatives (modelStepComplete | modelStepFailed | modelStepCanceled \ -| modelTerminated | modelError) -#define MASK_fmi3DoStep modelStepComplete -#define MASK_fmi3CancelStep modelStepInProgress -#define MASK_fmi3GetStatus (modelStepComplete | modelStepInProgress | modelStepFailed \ -| modelTerminated) -#define MASK_fmi3GetRealStatus MASK_fmi3GetStatus -#define MASK_fmi3GetIntegerStatus MASK_fmi3GetStatus -#define MASK_fmi3GetBooleanStatus MASK_fmi3GetStatus -#define MASK_fmi3GetStringStatus MASK_fmi3GetStatus - -// --------------------------------------------------------------------------- -// Private helpers used below to validate function arguments -// --------------------------------------------------------------------------- - -fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); - -static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int statesExpected) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, fName, statesExpected)) - return fmi3Error; - logError(comp, "%s: Function not implemented.", fName); - return fmi3Error; -} - -// --------------------------------------------------------------------------- -// Private helpers logger -// --------------------------------------------------------------------------- - -// return fmi3True if logging category is on. Else return fmi3False. -fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { - if (categoryIndex < NUMBER_OF_CATEGORIES - && (comp->logCategories[categoryIndex] || comp->logCategories[LOG_ALL])) { - return fmi3True; - } - return fmi3False; -} - -// --------------------------------------------------------------------------- -// FMI functions -// --------------------------------------------------------------------------- -fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3String fmuGUID, - fmi3String fmuResourceLocation, const fmi3CallbackFunctions *functions, - fmi3Boolean visible, fmi3Boolean loggingOn) { - - return createModelInstance( - (loggerType)functions->logger, - (allocateMemoryType)functions->allocateMemory, - (freeMemoryType)functions->freeMemory, - functions->componentEnvironment, - instanceName, - fmuGUID, - fmuResourceLocation, - loggingOn, - fmuType - ); -} - -fmi3Status fmi3SetupExperiment(fmi3Component c, fmi3Boolean toleranceDefined, fmi3Float64 tolerance, - fmi3Float64 startTime, fmi3Boolean stopTimeDefined, fmi3Float64 stopTime) { - - // ignore arguments: stopTimeDefined, stopTime - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3SetupExperiment", MASK_fmi3SetupExperiment)) - return fmi3Error; - - comp->time = startTime; - - return fmi3OK; -} - -fmi3Status fmi3EnterInitializationMode(fmi3Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3EnterInitializationMode", MASK_fmi3EnterInitializationMode)) - return fmi3Error; - comp->state = modelInitializationMode; - return fmi3OK; -} - -fmi3Status fmi3ExitInitializationMode(fmi3Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3ExitInitializationMode", MASK_fmi3ExitInitializationMode)) - return fmi3Error; - - // if values were set and no fmi3GetXXX triggered update before, - // ensure calculated values are updated now - if (comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - if (comp->type == fmi3ModelExchange) { - comp->state = modelEventMode; - comp->isNewEventIteration = fmi3True; - } else { - comp->state = modelStepComplete; - } - - return fmi3OK; -} - -fmi3Status fmi3Terminate(fmi3Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3Terminate", MASK_fmi3Terminate)) - return fmi3Error; - comp->state = modelTerminated; - return fmi3OK; -} - -fmi3Status fmi3Reset(fmi3Component c) { - ModelInstance* comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3Reset", MASK_fmi3Reset)) - return fmi3Error; - comp->state = modelInstantiated; - setStartValues(comp); - comp->isDirtyValues = true; - return fmi3OK; -} - -void fmi3FreeInstance(fmi3Component c) { - - ModelInstance *comp = (ModelInstance *)c; - - if (!comp) return; - - if (invalidState(comp, "fmi3FreeInstance", MASK_fmi3FreeInstance)) - return; - - freeModelInstance(comp); -} - -// --------------------------------------------------------------------------- -// FMI functions: class methods not depending of a specific model instance -// --------------------------------------------------------------------------- - -const char* fmi3GetVersion() { - return fmi3Version; -} - -// --------------------------------------------------------------------------- -// FMI functions: logging control, setters and getters for Real, Integer, -// Boolean, String -// --------------------------------------------------------------------------- - -fmi3Status fmi3SetDebugLogging(fmi3Component c, fmi3Boolean loggingOn, size_t nCategories, const fmi3String categories[]) { - //int i, j; - //ModelInstance *comp = (ModelInstance *)c; - //if (invalidState(comp, "fmi3SetDebugLogging", MASK_fmi3SetDebugLogging)) - // return fmi3Error; - //comp->loggingOn = loggingOn; - - //// reset all categories - //for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - // comp->logCategories[j] = fmi3False; - //} - - //if (nCategories == 0) { - // // no category specified, set all categories to have loggingOn value - // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - // comp->logCategories[j] = loggingOn; - // } - //} else { - // // set specific categories on - // for (i = 0; i < nCategories; i++) { - // fmi3Boolean categoryFound = fmi3False; - // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - // if (strcmp(logCategoriesNames[j], categories[i]) == 0) { - // comp->logCategories[j] = loggingOn; - // categoryFound = fmi3True; - // break; - // } - // } - // if (!categoryFound) { - // comp->logger(comp->componentEnvironment, comp->instanceName, fmi3Warning, - // logCategoriesNames[LOG_ERROR], - // "logging category '%s' is not supported by model", categories[i]); - // } - // } - //} - return fmi3OK; -} - -fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetReal", MASK_fmi3GetReal)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3GetReal", "vr[]", vr)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3GetReal", "value[]", value)) - return fmi3Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_VARIABLES(Float64) -} - -fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Int32 value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetInteger", MASK_fmi3GetInteger)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3GetInteger", "vr[]", vr)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3GetInteger", "value[]", value)) - return fmi3Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_VARIABLES(Int32) -} - -fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetBoolean", MASK_fmi3GetBoolean)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3GetBoolean", "vr[]", vr)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3GetBoolean", "value[]", value)) - return fmi3Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_BOOLEAN_VARIABLES -} - -fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetString", MASK_fmi3GetString)) - return fmi3Error; - - if (nvr>0 && nullPointer(comp, "fmi3GetString", "vr[]", vr)) - return fmi3Error; - - if (nvr>0 && nullPointer(comp, "fmi3GetString", "value[]", value)) - return fmi3Error; - - if (nvr > 0 && comp->isDirtyValues) { - calculateValues(comp); - comp->isDirtyValues = false; - } - - GET_VARIABLES(String) -} - -fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3SetReal", MASK_fmi3SetReal)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3SetReal", "vr[]", vr)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3SetReal", "value[]", value)) - return fmi3Error; - - SET_VARIABLES(Float64) -} - -fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Int32 value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3SetInteger", MASK_fmi3SetInteger)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3SetInteger", "vr[]", vr)) - return fmi3Error; - - if (nvr > 0 && nullPointer(comp, "fmi3SetInteger", "value[]", value)) - return fmi3Error; - - SET_VARIABLES(Int32) -} - -fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3SetBoolean", MASK_fmi3SetBoolean)) - return fmi3Error; - - if (nvr>0 && nullPointer(comp, "fmi3SetBoolean", "vr[]", vr)) - return fmi3Error; - - if (nvr>0 && nullPointer(comp, "fmi3SetBoolean", "value[]", value)) - return fmi3Error; - - SET_BOOLEAN_VARIABLES -} - -fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3SetString", MASK_fmi3SetString)) - return fmi3Error; - - if (nvr>0 && nullPointer(comp, "fmi3SetString", "vr[]", vr)) - return fmi3Error; - - if (nvr>0 && nullPointer(comp, "fmi3SetString", "value[]", value)) - return fmi3Error; - - SET_VARIABLES(String) -} - -fmi3Status fmi3GetFMUstate (fmi3Component c, fmi3FMUstate* FMUstate) { - return unsupportedFunction(c, "fmi3GetFMUstate", MASK_fmi3GetFMUstate); -} -fmi3Status fmi3SetFMUstate (fmi3Component c, fmi3FMUstate FMUstate) { - return unsupportedFunction(c, "fmi3SetFMUstate", MASK_fmi3SetFMUstate); -} -fmi3Status fmi3FreeFMUstate(fmi3Component c, fmi3FMUstate* FMUstate) { - return unsupportedFunction(c, "fmi3FreeFMUstate", MASK_fmi3FreeFMUstate); -} -fmi3Status fmi3SerializedFMUstateSize(fmi3Component c, fmi3FMUstate FMUstate, size_t *size) { - return unsupportedFunction(c, "fmi3SerializedFMUstateSize", MASK_fmi3SerializedFMUstateSize); -} -fmi3Status fmi3SerializeFMUstate (fmi3Component c, fmi3FMUstate FMUstate, fmi3Byte serializedState[], size_t size) { - return unsupportedFunction(c, "fmi3SerializeFMUstate", MASK_fmi3SerializeFMUstate); -} -fmi3Status fmi3DeSerializeFMUstate (fmi3Component c, const fmi3Byte serializedState[], size_t size, - fmi3FMUstate* FMUstate) { - return unsupportedFunction(c, "fmi3DeSerializeFMUstate", MASK_fmi3DeSerializeFMUstate); -} - -// --------------------------------------------------------------------------- -// Functions for FMI for Co-Simulation -// --------------------------------------------------------------------------- - -fmi3Status fmi3CancelStep(fmi3Component c) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3CancelStep", MASK_fmi3CancelStep)) { - // always fmi3CancelStep is invalid, because model is never in modelStepInProgress state. - return fmi3Error; - } - - logError(comp, "fmi3CancelStep: Can be called when fmi3DoStep returned fmi3Pending." - " This is not the case."); - - return fmi3Error; -} - -fmi3Status fmi3DoStep(fmi3Component c, fmi3Float64 currentCommunicationPoint, - fmi3Float64 communicationStepSize, fmi3Boolean noSetFMUStatePriorToCurrentPoint) { - - ModelInstance *comp = (ModelInstance *)c; - - if (communicationStepSize <= 0) { - logError(comp, "fmi3DoStep: communication step size must be > 0 but was %g.", communicationStepSize); - comp->state = modelError; - return fmi3Error; - } - - return doStep(comp, currentCommunicationPoint, currentCommunicationPoint + communicationStepSize); -} - -// --------------------------------------------------------------------------- -// Functions for fmi3 for Model Exchange -// --------------------------------------------------------------------------- -/* Enter and exit the different modes */ -fmi3Status fmi3EnterEventMode(fmi3Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3EnterEventMode", MASK_fmi3EnterEventMode)) - return fmi3Error; - comp->state = modelEventMode; - comp->isNewEventIteration = fmi3True; - return fmi3OK; -} - -fmi3Status fmi3NewDiscreteStates(fmi3Component c, fmi3EventInfo *eventInfo) { - ModelInstance *comp = (ModelInstance *)c; - int timeEvent = 0; - if (invalidState(comp, "fmi3NewDiscreteStates", MASK_fmi3NewDiscreteStates)) - return fmi3Error; - - comp->newDiscreteStatesNeeded = fmi3False; - comp->terminateSimulation = fmi3False; - comp->nominalsOfContinuousStatesChanged = fmi3False; - comp->valuesOfContinuousStatesChanged = fmi3False; - - if (comp->nextEventTimeDefined && comp->nextEventTime <= comp->time) { - timeEvent = 1; - } - - eventUpdate(comp); - - comp->isNewEventIteration = false; - - // copy internal eventInfo of component to output eventInfo - eventInfo->newDiscreteStatesNeeded = comp->newDiscreteStatesNeeded; - eventInfo->terminateSimulation = comp->terminateSimulation; - eventInfo->nominalsOfContinuousStatesChanged = comp->nominalsOfContinuousStatesChanged; - eventInfo->valuesOfContinuousStatesChanged = comp->valuesOfContinuousStatesChanged; - eventInfo->nextEventTimeDefined = comp->nextEventTimeDefined; - eventInfo->nextEventTime = comp->nextEventTime; - - return fmi3OK; -} - -fmi3Status fmi3EnterContinuousTimeMode(fmi3Component c) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3EnterContinuousTimeMode", MASK_fmi3EnterContinuousTimeMode)) - return fmi3Error; - comp->state = modelContinuousTimeMode; - return fmi3OK; -} - -fmi3Status fmi3CompletedIntegratorStep(fmi3Component c, fmi3Boolean noSetFMUStatePriorToCurrentPoint, - fmi3Boolean *enterEventMode, fmi3Boolean *terminateSimulation) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3CompletedIntegratorStep", MASK_fmi3CompletedIntegratorStep)) - return fmi3Error; - if (nullPointer(comp, "fmi3CompletedIntegratorStep", "enterEventMode", enterEventMode)) - return fmi3Error; - if (nullPointer(comp, "fmi3CompletedIntegratorStep", "terminateSimulation", terminateSimulation)) - return fmi3Error; - *enterEventMode = fmi3False; - *terminateSimulation = fmi3False; - return fmi3OK; -} - -/* Providing independent variables and re-initialization of caching */ -fmi3Status fmi3SetTime(fmi3Component c, fmi3Float64 time) { - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3SetTime", MASK_fmi3SetTime)) - return fmi3Error; - comp->time = time; - return fmi3OK; -} - -fmi3Status fmi3SetContinuousStates(fmi3Component c, const fmi3Float64 x[], size_t nx){ - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3SetContinuousStates", MASK_fmi3SetContinuousStates)) - return fmi3Error; - - if (invalidNumber(comp, "fmi3SetContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmi3Error; - - if (nullPointer(comp, "fmi3SetContinuousStates", "x[]", x)) - return fmi3Error; - - setContinuousStates(comp, x, nx); - - return fmi3OK; -} - -/* Evaluation of the model equations */ -fmi3Status fmi3GetDerivatives(fmi3Component c, fmi3Float64 derivatives[], size_t nx) { - - ModelInstance* comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetDerivatives", MASK_fmi3GetDerivatives)) - return fmi3Error; - - if (invalidNumber(comp, "fmi3GetDerivatives", "nx", nx, NUMBER_OF_STATES)) - return fmi3Error; - - if (nullPointer(comp, "fmi3GetDerivatives", "derivatives[]", derivatives)) - return fmi3Error; - - getDerivatives(comp, derivatives, nx); - - return fmi3OK; -} - -fmi3Status fmi3GetEventIndicators(fmi3Component c, fmi3Float64 eventIndicators[], size_t ni) { - -#if NUMBER_OF_EVENT_INDICATORS > 0 - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetEventIndicators", MASK_fmi3GetEventIndicators)) - return fmi3Error; - - if (invalidNumber(comp, "fmi3GetEventIndicators", "ni", ni, NUMBER_OF_EVENT_INDICATORS)) - return fmi3Error; - - getEventIndicators(comp, eventIndicators, ni); -#else - if (ni > 0) return fmi3Error; -#endif - return fmi3OK; -} - -fmi3Status fmi3GetContinuousStates(fmi3Component c, fmi3Float64 states[], size_t nx) { - - ModelInstance *comp = (ModelInstance *)c; - - if (invalidState(comp, "fmi3GetContinuousStates", MASK_fmi3GetContinuousStates)) - return fmi3Error; - - if (invalidNumber(comp, "fmi3GetContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmi3Error; - - if (nullPointer(comp, "fmi3GetContinuousStates", "states[]", states)) - return fmi3Error; - - getContinuousStates(comp, states, nx); - - return fmi3OK; -} - -fmi3Status fmi3GetNominalsOfContinuousStates(fmi3Component c, fmi3Float64 x_nominal[], size_t nx) { - int i; - ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi3GetNominalsOfContinuousStates", MASK_fmi3GetNominalsOfContinuousStates)) - return fmi3Error; - if (invalidNumber(comp, "fmi3GetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES)) - return fmi3Error; - if (nullPointer(comp, "fmi3GetNominalContinuousStates", "x_nominal[]", x_nominal)) - return fmi3Error; - for (i = 0; i < nx; i++) - x_nominal[i] = 1; - return fmi3OK; -} +/**************************************************************** + * Copyright (c) Dassault Systemes. All rights reserved. * + * This file is part of the Test-FMUs. See LICENSE.txt in the * + * project root for license information. * + ****************************************************************/ + +#include +#include +#include +#include + +#include "config.h" +#include "model.h" +#include "slave.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 fmi3_FUNCTION_PREFIX pasteB(MODEL_IDENTIFIER, _) +#endif +#include "fmi3Functions.h" + +static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; + +#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_fmi3GetTypesPlatform (modelStartAndEnd | modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi3GetVersion MASK_fmi3GetTypesPlatform +#define MASK_fmi3SetDebugLogging (modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepInProgress | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi3Instantiate (modelStartAndEnd) +#define MASK_fmi3FreeInstance (modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi3SetupExperiment modelInstantiated +#define MASK_fmi3EnterInitializationMode modelInstantiated +#define MASK_fmi3ExitInitializationMode modelInitializationMode +#define MASK_fmi3Terminate (modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed) +#define MASK_fmi3Reset MASK_fmi3FreeInstance +#define MASK_fmi3GetReal (modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi3GetInteger MASK_fmi3GetReal +#define MASK_fmi3GetBoolean MASK_fmi3GetReal +#define MASK_fmi3GetString MASK_fmi3GetReal +#define MASK_fmi3SetReal (modelInstantiated | modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete) +#define MASK_fmi3SetInteger (modelInstantiated | modelInitializationMode \ +| modelEventMode \ +| modelStepComplete) +#define MASK_fmi3SetBoolean MASK_fmi3SetInteger +#define MASK_fmi3SetString MASK_fmi3SetInteger +#define MASK_fmi3GetFMUstate MASK_fmi3FreeInstance +#define MASK_fmi3SetFMUstate MASK_fmi3FreeInstance +#define MASK_fmi3FreeFMUstate MASK_fmi3FreeInstance +#define MASK_fmi3SerializedFMUstateSize MASK_fmi3FreeInstance +#define MASK_fmi3SerializeFMUstate MASK_fmi3FreeInstance +#define MASK_fmi3DeSerializeFMUstate MASK_fmi3FreeInstance +#define MASK_fmi3GetDirectionalDerivative (modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for Model-exchange +// --------------------------------------------------------------------------- +#define MASK_fmi3EnterEventMode (modelEventMode | modelContinuousTimeMode) +#define MASK_fmi3NewDiscreteStates modelEventMode +#define MASK_fmi3EnterContinuousTimeMode modelEventMode +#define MASK_fmi3CompletedIntegratorStep modelContinuousTimeMode +#define MASK_fmi3SetTime (modelEventMode | modelContinuousTimeMode) +#define MASK_fmi3SetContinuousStates modelContinuousTimeMode +#define MASK_fmi3GetEventIndicators (modelInitializationMode \ +| modelEventMode | modelContinuousTimeMode \ +| modelTerminated | modelError) +#define MASK_fmi3GetContinuousStates MASK_fmi3GetEventIndicators +#define MASK_fmi3GetDerivatives (modelEventMode | modelContinuousTimeMode \ +| modelTerminated | modelError) +#define MASK_fmi3GetNominalsOfContinuousStates ( modelInstantiated \ +| modelEventMode | modelContinuousTimeMode \ +| modelTerminated | modelError) + +// --------------------------------------------------------------------------- +// Function calls allowed state masks for Co-simulation +// --------------------------------------------------------------------------- +#define MASK_fmi3SetRealInputDerivatives (modelInstantiated | modelInitializationMode \ +| modelStepComplete) +#define MASK_fmi3GetRealOutputDerivatives (modelStepComplete | modelStepFailed | modelStepCanceled \ +| modelTerminated | modelError) +#define MASK_fmi3DoStep modelStepComplete +#define MASK_fmi3CancelStep modelStepInProgress +#define MASK_fmi3GetStatus (modelStepComplete | modelStepInProgress | modelStepFailed \ +| modelTerminated) +#define MASK_fmi3GetRealStatus MASK_fmi3GetStatus +#define MASK_fmi3GetIntegerStatus MASK_fmi3GetStatus +#define MASK_fmi3GetBooleanStatus MASK_fmi3GetStatus +#define MASK_fmi3GetStringStatus MASK_fmi3GetStatus + +// --------------------------------------------------------------------------- +// Private helpers used below to validate function arguments +// --------------------------------------------------------------------------- + +fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); + +static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int statesExpected) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, fName, statesExpected)) + return fmi3Error; + logError(comp, "%s: Function not implemented.", fName); + return fmi3Error; +} + +// --------------------------------------------------------------------------- +// Private helpers logger +// --------------------------------------------------------------------------- + +// return fmi3True if logging category is on. Else return fmi3False. +fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { + if (categoryIndex < NUMBER_OF_CATEGORIES + && (comp->logCategories[categoryIndex] || comp->logCategories[LOG_ALL])) { + return fmi3True; + } + return fmi3False; +} + +// --------------------------------------------------------------------------- +// FMI functions +// --------------------------------------------------------------------------- +fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3String fmuGUID, + fmi3String fmuResourceLocation, const fmi3CallbackFunctions *functions, + fmi3Boolean visible, fmi3Boolean loggingOn) { + + return createModelInstance( + (loggerType)functions->logger, + (allocateMemoryType)functions->allocateMemory, + (freeMemoryType)functions->freeMemory, + functions->componentEnvironment, + instanceName, + fmuGUID, + fmuResourceLocation, + loggingOn, + fmuType + ); +} + +fmi3Status fmi3SetupExperiment(fmi3Component c, fmi3Boolean toleranceDefined, fmi3Float64 tolerance, + fmi3Float64 startTime, fmi3Boolean stopTimeDefined, fmi3Float64 stopTime) { + + // ignore arguments: stopTimeDefined, stopTime + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetupExperiment", MASK_fmi3SetupExperiment)) + return fmi3Error; + + comp->time = startTime; + + return fmi3OK; +} + +fmi3Status fmi3EnterInitializationMode(fmi3Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3EnterInitializationMode", MASK_fmi3EnterInitializationMode)) + return fmi3Error; + comp->state = modelInitializationMode; + return fmi3OK; +} + +fmi3Status fmi3ExitInitializationMode(fmi3Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3ExitInitializationMode", MASK_fmi3ExitInitializationMode)) + return fmi3Error; + + // if values were set and no fmi3GetXXX triggered update before, + // ensure calculated values are updated now + if (comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + if (comp->type == fmi3ModelExchange) { + comp->state = modelEventMode; + comp->isNewEventIteration = fmi3True; + } else { + comp->state = modelStepComplete; + } + + return fmi3OK; +} + +fmi3Status fmi3Terminate(fmi3Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3Terminate", MASK_fmi3Terminate)) + return fmi3Error; + comp->state = modelTerminated; + return fmi3OK; +} + +fmi3Status fmi3Reset(fmi3Component c) { + ModelInstance* comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3Reset", MASK_fmi3Reset)) + return fmi3Error; + comp->state = modelInstantiated; + setStartValues(comp); + comp->isDirtyValues = true; + return fmi3OK; +} + +void fmi3FreeInstance(fmi3Component c) { + + ModelInstance *comp = (ModelInstance *)c; + + if (!comp) return; + + if (invalidState(comp, "fmi3FreeInstance", MASK_fmi3FreeInstance)) + return; + + freeModelInstance(comp); +} + +// --------------------------------------------------------------------------- +// FMI functions: class methods not depending of a specific model instance +// --------------------------------------------------------------------------- + +const char* fmi3GetVersion() { + return fmi3Version; +} + +// --------------------------------------------------------------------------- +// FMI functions: logging control, setters and getters for Real, Integer, +// Boolean, String +// --------------------------------------------------------------------------- + +fmi3Status fmi3SetDebugLogging(fmi3Component c, fmi3Boolean loggingOn, size_t nCategories, const fmi3String categories[]) { + //int i, j; + //ModelInstance *comp = (ModelInstance *)c; + //if (invalidState(comp, "fmi3SetDebugLogging", MASK_fmi3SetDebugLogging)) + // return fmi3Error; + //comp->loggingOn = loggingOn; + + //// reset all categories + //for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + // comp->logCategories[j] = fmi3False; + //} + + //if (nCategories == 0) { + // // no category specified, set all categories to have loggingOn value + // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + // comp->logCategories[j] = loggingOn; + // } + //} else { + // // set specific categories on + // for (i = 0; i < nCategories; i++) { + // fmi3Boolean categoryFound = fmi3False; + // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { + // if (strcmp(logCategoriesNames[j], categories[i]) == 0) { + // comp->logCategories[j] = loggingOn; + // categoryFound = fmi3True; + // break; + // } + // } + // if (!categoryFound) { + // comp->logger(comp->componentEnvironment, comp->instanceName, fmi3Warning, + // logCategoriesNames[LOG_ERROR], + // "logging category '%s' is not supported by model", categories[i]); + // } + // } + //} + return fmi3OK; +} + +fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetReal", MASK_fmi3GetReal)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3GetReal", "vr[]", vr)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3GetReal", "value[]", value)) + return fmi3Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_VARIABLES(Float64) +} + +fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Int32 value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetInteger", MASK_fmi3GetInteger)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3GetInteger", "vr[]", vr)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3GetInteger", "value[]", value)) + return fmi3Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_VARIABLES(Int32) +} + +fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetBoolean", MASK_fmi3GetBoolean)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3GetBoolean", "vr[]", vr)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3GetBoolean", "value[]", value)) + return fmi3Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_BOOLEAN_VARIABLES +} + +fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetString", MASK_fmi3GetString)) + return fmi3Error; + + if (nvr>0 && nullPointer(comp, "fmi3GetString", "vr[]", vr)) + return fmi3Error; + + if (nvr>0 && nullPointer(comp, "fmi3GetString", "value[]", value)) + return fmi3Error; + + if (nvr > 0 && comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = false; + } + + GET_VARIABLES(String) +} + +fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetReal", MASK_fmi3SetReal)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3SetReal", "vr[]", vr)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3SetReal", "value[]", value)) + return fmi3Error; + + SET_VARIABLES(Float64) +} + +fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Int32 value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetInteger", MASK_fmi3SetInteger)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3SetInteger", "vr[]", vr)) + return fmi3Error; + + if (nvr > 0 && nullPointer(comp, "fmi3SetInteger", "value[]", value)) + return fmi3Error; + + SET_VARIABLES(Int32) +} + +fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetBoolean", MASK_fmi3SetBoolean)) + return fmi3Error; + + if (nvr>0 && nullPointer(comp, "fmi3SetBoolean", "vr[]", vr)) + return fmi3Error; + + if (nvr>0 && nullPointer(comp, "fmi3SetBoolean", "value[]", value)) + return fmi3Error; + + SET_BOOLEAN_VARIABLES +} + +fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetString", MASK_fmi3SetString)) + return fmi3Error; + + if (nvr>0 && nullPointer(comp, "fmi3SetString", "vr[]", vr)) + return fmi3Error; + + if (nvr>0 && nullPointer(comp, "fmi3SetString", "value[]", value)) + return fmi3Error; + + SET_VARIABLES(String) +} + +fmi3Status fmi3GetFMUstate (fmi3Component c, fmi3FMUstate* FMUstate) { + return unsupportedFunction(c, "fmi3GetFMUstate", MASK_fmi3GetFMUstate); +} +fmi3Status fmi3SetFMUstate (fmi3Component c, fmi3FMUstate FMUstate) { + return unsupportedFunction(c, "fmi3SetFMUstate", MASK_fmi3SetFMUstate); +} +fmi3Status fmi3FreeFMUstate(fmi3Component c, fmi3FMUstate* FMUstate) { + return unsupportedFunction(c, "fmi3FreeFMUstate", MASK_fmi3FreeFMUstate); +} +fmi3Status fmi3SerializedFMUstateSize(fmi3Component c, fmi3FMUstate FMUstate, size_t *size) { + return unsupportedFunction(c, "fmi3SerializedFMUstateSize", MASK_fmi3SerializedFMUstateSize); +} +fmi3Status fmi3SerializeFMUstate (fmi3Component c, fmi3FMUstate FMUstate, fmi3Byte serializedState[], size_t size) { + return unsupportedFunction(c, "fmi3SerializeFMUstate", MASK_fmi3SerializeFMUstate); +} +fmi3Status fmi3DeSerializeFMUstate (fmi3Component c, const fmi3Byte serializedState[], size_t size, + fmi3FMUstate* FMUstate) { + return unsupportedFunction(c, "fmi3DeSerializeFMUstate", MASK_fmi3DeSerializeFMUstate); +} + +// --------------------------------------------------------------------------- +// Functions for FMI for Co-Simulation +// --------------------------------------------------------------------------- + +fmi3Status fmi3CancelStep(fmi3Component c) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3CancelStep", MASK_fmi3CancelStep)) { + // always fmi3CancelStep is invalid, because model is never in modelStepInProgress state. + return fmi3Error; + } + + logError(comp, "fmi3CancelStep: Can be called when fmi3DoStep returned fmi3Pending." + " This is not the case."); + + return fmi3Error; +} + +fmi3Status fmi3DoStep(fmi3Component c, fmi3Float64 currentCommunicationPoint, + fmi3Float64 communicationStepSize, fmi3Boolean noSetFMUStatePriorToCurrentPoint) { + + ModelInstance *comp = (ModelInstance *)c; + + if (communicationStepSize <= 0) { + logError(comp, "fmi3DoStep: communication step size must be > 0 but was %g.", communicationStepSize); + comp->state = modelError; + return fmi3Error; + } + + return doStep(comp, currentCommunicationPoint, currentCommunicationPoint + communicationStepSize); +} + +// --------------------------------------------------------------------------- +// Functions for fmi3 for Model Exchange +// --------------------------------------------------------------------------- +/* Enter and exit the different modes */ +fmi3Status fmi3EnterEventMode(fmi3Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3EnterEventMode", MASK_fmi3EnterEventMode)) + return fmi3Error; + comp->state = modelEventMode; + comp->isNewEventIteration = fmi3True; + return fmi3OK; +} + +fmi3Status fmi3NewDiscreteStates(fmi3Component c, fmi3EventInfo *eventInfo) { + ModelInstance *comp = (ModelInstance *)c; + int timeEvent = 0; + if (invalidState(comp, "fmi3NewDiscreteStates", MASK_fmi3NewDiscreteStates)) + return fmi3Error; + + comp->newDiscreteStatesNeeded = fmi3False; + comp->terminateSimulation = fmi3False; + comp->nominalsOfContinuousStatesChanged = fmi3False; + comp->valuesOfContinuousStatesChanged = fmi3False; + + if (comp->nextEventTimeDefined && comp->nextEventTime <= comp->time) { + timeEvent = 1; + } + + eventUpdate(comp); + + comp->isNewEventIteration = false; + + // copy internal eventInfo of component to output eventInfo + eventInfo->newDiscreteStatesNeeded = comp->newDiscreteStatesNeeded; + eventInfo->terminateSimulation = comp->terminateSimulation; + eventInfo->nominalsOfContinuousStatesChanged = comp->nominalsOfContinuousStatesChanged; + eventInfo->valuesOfContinuousStatesChanged = comp->valuesOfContinuousStatesChanged; + eventInfo->nextEventTimeDefined = comp->nextEventTimeDefined; + eventInfo->nextEventTime = comp->nextEventTime; + + return fmi3OK; +} + +fmi3Status fmi3EnterContinuousTimeMode(fmi3Component c) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3EnterContinuousTimeMode", MASK_fmi3EnterContinuousTimeMode)) + return fmi3Error; + comp->state = modelContinuousTimeMode; + return fmi3OK; +} + +fmi3Status fmi3CompletedIntegratorStep(fmi3Component c, fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean *enterEventMode, fmi3Boolean *terminateSimulation) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3CompletedIntegratorStep", MASK_fmi3CompletedIntegratorStep)) + return fmi3Error; + if (nullPointer(comp, "fmi3CompletedIntegratorStep", "enterEventMode", enterEventMode)) + return fmi3Error; + if (nullPointer(comp, "fmi3CompletedIntegratorStep", "terminateSimulation", terminateSimulation)) + return fmi3Error; + *enterEventMode = fmi3False; + *terminateSimulation = fmi3False; + return fmi3OK; +} + +/* Providing independent variables and re-initialization of caching */ +fmi3Status fmi3SetTime(fmi3Component c, fmi3Float64 time) { + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3SetTime", MASK_fmi3SetTime)) + return fmi3Error; + comp->time = time; + return fmi3OK; +} + +fmi3Status fmi3SetContinuousStates(fmi3Component c, const fmi3Float64 x[], size_t nx){ + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetContinuousStates", MASK_fmi3SetContinuousStates)) + return fmi3Error; + + if (invalidNumber(comp, "fmi3SetContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmi3Error; + + if (nullPointer(comp, "fmi3SetContinuousStates", "x[]", x)) + return fmi3Error; + + setContinuousStates(comp, x, nx); + + return fmi3OK; +} + +/* Evaluation of the model equations */ +fmi3Status fmi3GetDerivatives(fmi3Component c, fmi3Float64 derivatives[], size_t nx) { + + ModelInstance* comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetDerivatives", MASK_fmi3GetDerivatives)) + return fmi3Error; + + if (invalidNumber(comp, "fmi3GetDerivatives", "nx", nx, NUMBER_OF_STATES)) + return fmi3Error; + + if (nullPointer(comp, "fmi3GetDerivatives", "derivatives[]", derivatives)) + return fmi3Error; + + getDerivatives(comp, derivatives, nx); + + return fmi3OK; +} + +fmi3Status fmi3GetEventIndicators(fmi3Component c, fmi3Float64 eventIndicators[], size_t ni) { + +#if NUMBER_OF_EVENT_INDICATORS > 0 + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetEventIndicators", MASK_fmi3GetEventIndicators)) + return fmi3Error; + + if (invalidNumber(comp, "fmi3GetEventIndicators", "ni", ni, NUMBER_OF_EVENT_INDICATORS)) + return fmi3Error; + + getEventIndicators(comp, eventIndicators, ni); +#else + if (ni > 0) return fmi3Error; +#endif + return fmi3OK; +} + +fmi3Status fmi3GetContinuousStates(fmi3Component c, fmi3Float64 states[], size_t nx) { + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3GetContinuousStates", MASK_fmi3GetContinuousStates)) + return fmi3Error; + + if (invalidNumber(comp, "fmi3GetContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmi3Error; + + if (nullPointer(comp, "fmi3GetContinuousStates", "states[]", states)) + return fmi3Error; + + getContinuousStates(comp, states, nx); + + return fmi3OK; +} + +fmi3Status fmi3GetNominalsOfContinuousStates(fmi3Component c, fmi3Float64 x_nominal[], size_t nx) { + int i; + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, "fmi3GetNominalsOfContinuousStates", MASK_fmi3GetNominalsOfContinuousStates)) + return fmi3Error; + if (invalidNumber(comp, "fmi3GetNominalContinuousStates", "nx", nx, NUMBER_OF_STATES)) + return fmi3Error; + if (nullPointer(comp, "fmi3GetNominalContinuousStates", "x_nominal[]", x_nominal)) + return fmi3Error; + for (i = 0; i < nx; i++) + x_nominal[i] = 1; + return fmi3OK; +} From 9726f525130e6a7f1d0849b52d6187bb770dc96a Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 14 Jun 2019 15:56:36 +0200 Subject: [PATCH 21/28] Add all.c to use definitions in source code FMUs --- BouncingBall/FMI2.xml | 8 ++------ BouncingBall/FMI3.xml | 8 ++------ CMakeLists.txt | 13 +++++++++++++ Dahlquist/FMI2.xml | 8 ++------ Dahlquist/FMI3.xml | 8 ++------ Feedthrough/FMI2.xml | 8 ++------ Feedthrough/FMI3.xml | 8 ++------ LinearTransform/FMI3.xml | 8 ++------ Resource/FMI2.xml | 8 ++------ Resource/FMI3.xml | 8 ++------ Stair/FMI2.xml | 8 ++------ Stair/FMI3.xml | 8 ++------ VanDerPol/FMI2.xml | 8 ++------ VanDerPol/FMI3.xml | 8 ++------ 14 files changed, 39 insertions(+), 78 deletions(-) diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index bfdb231..e079bed 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -8,17 +8,13 @@ - - - + - - - + diff --git a/BouncingBall/FMI3.xml b/BouncingBall/FMI3.xml index aadd9bd..1f86b97 100644 --- a/BouncingBall/FMI3.xml +++ b/BouncingBall/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + diff --git a/CMakeLists.txt b/CMakeLists.txt index 888643d..f57f764 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,13 @@ endif () MESSAGE("FMI_PLATFORM: " ${FMI_PLATFORM}) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/all.c" "#define FMI_VERSION ${FMI_VERSION} + +#include \"fmi${FMI_VERSION}Functions.c\" +#include \"model.c\" +#include \"slave.c\" +") + set (MODEL_NAMES BouncingBall Dahlquist Stair Feedthrough VanDerPol) if (${FMI_VERSION} GREATER 1 OR "${FMI_TYPE}" STREQUAL "CS") @@ -180,6 +187,12 @@ foreach (SOURCE_FILE fmi${FMI_VERSION}Functions.c slave.c) ) endforeach(SOURCE_FILE) +# all.c +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" +) + set(ARCHIVE_FILES "modelDescription.xml" "binaries" "documentation" "sources") if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources") diff --git a/Dahlquist/FMI2.xml b/Dahlquist/FMI2.xml index f88a586..a43037b 100644 --- a/Dahlquist/FMI2.xml +++ b/Dahlquist/FMI2.xml @@ -8,17 +8,13 @@ - - - + - - - + diff --git a/Dahlquist/FMI3.xml b/Dahlquist/FMI3.xml index c51908b..fca1898 100644 --- a/Dahlquist/FMI3.xml +++ b/Dahlquist/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + diff --git a/Feedthrough/FMI2.xml b/Feedthrough/FMI2.xml index 4f7cb7c..67409f6 100644 --- a/Feedthrough/FMI2.xml +++ b/Feedthrough/FMI2.xml @@ -8,17 +8,13 @@ - - - + - - - + diff --git a/Feedthrough/FMI3.xml b/Feedthrough/FMI3.xml index 48efc48..a6db29b 100644 --- a/Feedthrough/FMI3.xml +++ b/Feedthrough/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + diff --git a/LinearTransform/FMI3.xml b/LinearTransform/FMI3.xml index e5424c2..6ace561 100644 --- a/LinearTransform/FMI3.xml +++ b/LinearTransform/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + diff --git a/Resource/FMI2.xml b/Resource/FMI2.xml index 7ca09f3..e02a12f 100644 --- a/Resource/FMI2.xml +++ b/Resource/FMI2.xml @@ -8,17 +8,13 @@ - - - + - - - + diff --git a/Resource/FMI3.xml b/Resource/FMI3.xml index ede802f..147fa19 100644 --- a/Resource/FMI3.xml +++ b/Resource/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + diff --git a/Stair/FMI2.xml b/Stair/FMI2.xml index 7775e5f..2d92976 100644 --- a/Stair/FMI2.xml +++ b/Stair/FMI2.xml @@ -8,17 +8,13 @@ - - - + - - - + diff --git a/Stair/FMI3.xml b/Stair/FMI3.xml index 6bfcfe0..ffc8bdc 100644 --- a/Stair/FMI3.xml +++ b/Stair/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + diff --git a/VanDerPol/FMI2.xml b/VanDerPol/FMI2.xml index a167c77..b605ebb 100644 --- a/VanDerPol/FMI2.xml +++ b/VanDerPol/FMI2.xml @@ -8,17 +8,13 @@ - - - + - - - + diff --git a/VanDerPol/FMI3.xml b/VanDerPol/FMI3.xml index 5610205..c19f733 100644 --- a/VanDerPol/FMI3.xml +++ b/VanDerPol/FMI3.xml @@ -3,17 +3,13 @@ - - - + - - - + From 17b38ac378c002c8cc8aa580a7815e535e0119fb Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 14 Jun 2019 16:17:51 +0200 Subject: [PATCH 22/28] Compile FMI 2.0 models in test --- test_build.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test_build.py b/test_build.py index f091d15..9ab64c6 100644 --- a/test_build.py +++ b/test_build.py @@ -9,6 +9,8 @@ try: from fmpy import simulate_fmu + from fmpy.util import compile_platform_binary + fmpy_available = True except: print("FMPy not available. Skipping simulation.") @@ -19,6 +21,7 @@ try: import fmpy + fmi3_available = 'fmi3' in dir(fmpy) except: pass @@ -38,7 +41,6 @@ def copy_to_cross_check(build_dir, model_names, fmi_version, fmi_types): - if fmus_dir is None: return @@ -64,7 +66,7 @@ def setUpClass(cls): print("Removing " + build_dir) shutil.rmtree(build_dir) - def validate(self, build_dir, fmi_types=['ModelExchange', 'CoSimulation'], models=models): + def validate(self, build_dir, fmi_types=['ModelExchange', 'CoSimulation'], models=models, compile=False): from fmpy.util import read_csv, validate_result @@ -85,8 +87,12 @@ def validate(self, build_dir, fmi_types=['ModelExchange', 'CoSimulation'], model ref_csv = os.path.join(test_fmus_dir, model, model + '_ref.csv') for fmi_type in fmi_types: + ref = read_csv(ref_csv) + if compile: + compile_platform_binary(fmu_filename) + result = simulate_fmu(fmu_filename, fmi_type=fmi_type, start_values=start_values, @@ -146,6 +152,7 @@ def test_fmi2(self): if fmpy_available: self.validate(build_dir) + self.validate(build_dir, compile=True) copy_to_cross_check(build_dir=build_dir, model_names=models, fmi_version='2.0', fmi_types=['cs', 'me']) From 77c921f8e5096e33c3c10b621ce4188824f9b8fb Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 15 Jun 2019 14:40:25 +0200 Subject: [PATCH 23/28] Remove unnecessary assignments --- src/slave.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/slave.c b/src/slave.c index 113a28d..0b98dfb 100644 --- a/src/slave.c +++ b/src/slave.c @@ -194,7 +194,7 @@ void logError(ModelInstance *comp, const char *message, ...) { buf = allocateMemory(comp, len + 1, sizeof(char)); va_start(args, message); - len = vsnprintf(buf, len + 1, message, args); + vsnprintf(buf, len + 1, message, args); va_end(args); // no need to distinguish between FMI versions since we're not using variadic arguments @@ -266,10 +266,12 @@ void getDerivatives(ModelInstance *comp, double dx[], size_t nx) {} Status doStep(ModelInstance *comp, double t, double tNext) { - int stateEvent = 0; - int timeEvent = 0; + bool stateEvent, timeEvent; + +#if NUMBER_OF_EVENT_INDICATORS > 0 double *temp = NULL; - +#endif + #if NUMBER_OF_STATES > 0 double x[NUMBER_OF_STATES] = { 0 }; double dx[NUMBER_OF_STATES] = { 0 }; @@ -289,12 +291,12 @@ Status doStep(ModelInstance *comp, double t, double tNext) { setContinuousStates(comp, x, NUMBER_OF_STATES); #endif - stateEvent = 0; + stateEvent = false; #if NUMBER_OF_EVENT_INDICATORS > 0 getEventIndicators(comp, comp->z, NUMBER_OF_EVENT_INDICATORS); - // check for zero-crossing + // check for zero-crossing for (int i = 0; i < NUMBER_OF_EVENT_INDICATORS; i++) { stateEvent |= (comp->prez[i] * comp->z[i]) <= 0; } @@ -304,16 +306,12 @@ Status doStep(ModelInstance *comp, double t, double tNext) { comp->z = comp->prez; comp->prez = temp; #endif - + // check for time event - if (comp->nextEventTimeDefined && (comp->time >= comp->nextEventTime)) { - timeEvent = 1; - } + timeEvent = comp->nextEventTimeDefined && (comp->time >= comp->nextEventTime); if (stateEvent || timeEvent) { eventUpdate(comp); - timeEvent = 0; - stateEvent = 0; } // terminate simulation, if requested by the model in the previous step From 56ff93f5c51048ed6f9369536da4aff2b83933f1 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 15 Jun 2019 18:27:46 +0200 Subject: [PATCH 24/28] Add logEvent() and logError() --- BouncingBall/FMI2.xml | 5 +++ BouncingBall/FMI3.xml | 6 +-- BouncingBall/model.c | 15 ++++--- Dahlquist/FMI2.xml | 6 +-- Dahlquist/FMI3.xml | 6 +-- Feedthrough/FMI2.xml | 6 +-- Feedthrough/FMI3.xml | 6 +-- LinearTransform/FMI3.xml | 6 +-- Resource/FMI2.xml | 6 +-- Resource/FMI3.xml | 6 +-- Stair/FMI2.xml | 6 +-- Stair/FMI3.xml | 6 +-- VanDerPol/FMI2.xml | 6 +-- VanDerPol/FMI3.xml | 6 +-- include/model.h | 16 +++---- src/fmi1Functions.c | 41 +++++++++--------- src/fmi2Functions.c | 59 ++++---------------------- src/fmi3Functions.c | 74 +++++++------------------------- src/slave.c | 92 +++++++++++++++++++++++++++++----------- 19 files changed, 157 insertions(+), 217 deletions(-) diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml index e079bed..8bc3c79 100644 --- a/BouncingBall/FMI2.xml +++ b/BouncingBall/FMI2.xml @@ -42,6 +42,11 @@ + + + + + diff --git a/BouncingBall/FMI3.xml b/BouncingBall/FMI3.xml index 1f86b97..8a7273f 100644 --- a/BouncingBall/FMI3.xml +++ b/BouncingBall/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/BouncingBall/model.c b/BouncingBall/model.c index 9656b36..4c5046e 100644 --- a/BouncingBall/model.c +++ b/BouncingBall/model.c @@ -42,15 +42,15 @@ Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { - + case vr_h: M(h) = value[(*index)++]; return OK; - + case vr_v: M(v) = value[(*index)++]; return OK; - + case vr_g: #if FMI_VERSION > 1 if (comp->type == ModelExchange && @@ -62,7 +62,7 @@ Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, s #endif M(g) = value[(*index)++]; return OK; - + case vr_e: #if FMI_VERSION > 1 if (comp->type == ModelExchange && @@ -75,8 +75,13 @@ Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, s #endif M(e) = value[(*index)++]; return OK; - + + case vr_v_min: + logError(comp, "Variable v_min (value reference %d) is constant and cannot be set.", vr_v_min); + return Error; + default: + logError(comp, "Unexpected value reference: %.", vr); return Error; } } diff --git a/Dahlquist/FMI2.xml b/Dahlquist/FMI2.xml index a43037b..2182179 100644 --- a/Dahlquist/FMI2.xml +++ b/Dahlquist/FMI2.xml @@ -19,10 +19,8 @@ - - - - + + diff --git a/Dahlquist/FMI3.xml b/Dahlquist/FMI3.xml index fca1898..1b42106 100644 --- a/Dahlquist/FMI3.xml +++ b/Dahlquist/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/Feedthrough/FMI2.xml b/Feedthrough/FMI2.xml index 67409f6..2c0979c 100644 --- a/Feedthrough/FMI2.xml +++ b/Feedthrough/FMI2.xml @@ -19,10 +19,8 @@ - - - - + + diff --git a/Feedthrough/FMI3.xml b/Feedthrough/FMI3.xml index a6db29b..341685b 100644 --- a/Feedthrough/FMI3.xml +++ b/Feedthrough/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/LinearTransform/FMI3.xml b/LinearTransform/FMI3.xml index 6ace561..df348d2 100644 --- a/LinearTransform/FMI3.xml +++ b/LinearTransform/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/Resource/FMI2.xml b/Resource/FMI2.xml index e02a12f..5f3dc9c 100644 --- a/Resource/FMI2.xml +++ b/Resource/FMI2.xml @@ -19,10 +19,8 @@ - - - - + + diff --git a/Resource/FMI3.xml b/Resource/FMI3.xml index 147fa19..dbcfb2f 100644 --- a/Resource/FMI3.xml +++ b/Resource/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/Stair/FMI2.xml b/Stair/FMI2.xml index 2d92976..a5ff4a4 100644 --- a/Stair/FMI2.xml +++ b/Stair/FMI2.xml @@ -19,10 +19,8 @@ - - - - + + diff --git a/Stair/FMI3.xml b/Stair/FMI3.xml index ffc8bdc..bc439d6 100644 --- a/Stair/FMI3.xml +++ b/Stair/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/VanDerPol/FMI2.xml b/VanDerPol/FMI2.xml index b605ebb..eb8e77a 100644 --- a/VanDerPol/FMI2.xml +++ b/VanDerPol/FMI2.xml @@ -19,10 +19,8 @@ - - - - + + diff --git a/VanDerPol/FMI3.xml b/VanDerPol/FMI3.xml index c19f733..b55eb36 100644 --- a/VanDerPol/FMI3.xml +++ b/VanDerPol/FMI3.xml @@ -14,10 +14,8 @@ - - - - + + diff --git a/include/model.h b/include/model.h index 65a0f65..787ad54 100644 --- a/include/model.h +++ b/include/model.h @@ -6,15 +6,6 @@ #include "config.h" -// categories of logging supported by model. -// Value is the index in logCategories of a ModelInstance. -#define LOG_ALL 0 -#define LOG_ERROR 1 -#define LOG_FMI_CALL 2 -#define LOG_EVENT 3 - -#define NUMBER_OF_CATEGORIES 4 - #if FMI_VERSION == 1 #define not_modelError (modelInstantiated|modelInitialized|modelTerminated) @@ -86,8 +77,8 @@ typedef struct { allocateMemoryType allocateMemory; freeMemoryType freeMemory; - bool loggingOn; - bool logCategories[NUMBER_OF_CATEGORIES]; + bool logEvents; + bool logErrors; void *componentEnvironment; ModelState state; @@ -149,6 +140,9 @@ bool invalidNumber(ModelInstance *comp, const char *f, const char *arg, size_t a 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, ...); // shorthand to access the variables #define M(v) (comp->modelData->v) diff --git a/src/fmi1Functions.c b/src/fmi1Functions.c index f33aea4..916016c 100644 --- a/src/fmi1Functions.c +++ b/src/fmi1Functions.c @@ -63,11 +63,13 @@ const char* fmiGetVersion() { // --------------------------------------------------------------------------- fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn) { + ModelInstance* comp = (ModelInstance *)c; + if (invalidState(comp, "fmiSetDebugLogging", not_modelError)) return fmiError; - comp->loggingOn = loggingOn; - return fmiOK; + + return setDebugLogging(comp, loggingOn, 0, NULL); } fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) { @@ -281,38 +283,39 @@ void fmiFreeSlaveInstance(fmiComponent c) { fmiStatus fmiSetRealInputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger order[], const fmiReal value[]) { + ModelInstance* comp = (ModelInstance *)c; - fmiCallbackLogger log = comp->logger; + if (invalidState(comp, "fmiSetRealInputDerivatives", modelInitialized)) return fmiError; - log(c, comp->instanceName, fmiError, "warning", "fmiSetRealInputDerivatives: ignoring function call." - " This model cannot interpolate inputs: canInterpolateInputs=\"fmiFalse\""); - return fmiWarning; + + logError(comp, "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[]) { - int i; +fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger order[], fmiReal value[]) { + ModelInstance* comp = (ModelInstance *)c; - fmiCallbackLogger log = comp->logger; + if (invalidState(comp, "fmiGetRealOutputDerivatives", modelInitialized)) return fmiError; - if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiGetRealOutputDerivatives: nvr= %d", nvr); - log(c, comp->instanceName, fmiError, "warning", "fmiGetRealOutputDerivatives: ignoring function call." - " This model cannot compute derivatives of outputs: MaxOutputDerivativeOrder=\"0\""); - for (i=0; ilogger; + if (invalidState(comp, "fmiCancelStep", modelInitialized)) return fmiError; - if (comp->loggingOn) log(c, comp->instanceName, fmiOK, "log", "fmiCancelStep"); - log(c, comp->instanceName, fmiError, "error", - "fmiCancelStep: Can be called when fmiDoStep returned fmiPending." + + logError(comp, "fmiCancelStep: Can be called when fmiDoStep returned fmiPending." " This is not the case."); + return fmiError; } diff --git a/src/fmi2Functions.c b/src/fmi2Functions.c index 26e8f6c..09d0bdb 100644 --- a/src/fmi2Functions.c +++ b/src/fmi2Functions.c @@ -23,8 +23,6 @@ #endif #include "fmi2Functions.h" -static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; - #ifndef max #define max(a,b) ((a)>(b) ? (a) : (b)) #endif @@ -121,8 +119,6 @@ static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", " // Private helpers used below to validate function arguments // --------------------------------------------------------------------------- -fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); - static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int statesExpected) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, fName, statesExpected)) @@ -131,22 +127,10 @@ static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int st return fmi2Error; } -// --------------------------------------------------------------------------- -// Private helpers logger -// --------------------------------------------------------------------------- - -// return fmi2True if logging category is on. Else return fmi2False. -fmi2Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { - if (categoryIndex < NUMBER_OF_CATEGORIES - && (comp->logCategories[categoryIndex] || comp->logCategories[LOG_ALL])) { - return fmi2True; - } - return fmi2False; -} - // --------------------------------------------------------------------------- // FMI functions // --------------------------------------------------------------------------- + fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2String fmuGUID, fmi2String fmuResourceLocation, const fmi2CallbackFunctions *functions, fmi2Boolean visible, fmi2Boolean loggingOn) { @@ -254,41 +238,12 @@ const char* fmi2GetTypesPlatform() { // --------------------------------------------------------------------------- fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) { - int i, j; + ModelInstance *comp = (ModelInstance *)c; - if (invalidState(comp, "fmi2SetDebugLogging", MASK_fmi2SetDebugLogging)) - return fmi2Error; - comp->loggingOn = loggingOn; - // reset all categories - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - comp->logCategories[j] = fmi2False; - } + if (invalidState(comp, "fmi2SetDebugLogging", MASK_fmi2SetDebugLogging)) return fmi2Error; - if (nCategories == 0) { - // no category specified, set all categories to have loggingOn value - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - comp->logCategories[j] = loggingOn; - } - } else { - // set specific categories on - for (i = 0; i < nCategories; i++) { - fmi2Boolean categoryFound = fmi2False; - for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - if (strcmp(logCategoriesNames[j], categories[i]) == 0) { - comp->logCategories[j] = loggingOn; - categoryFound = fmi2True; - break; - } - } - if (!categoryFound) { - comp->logger(comp->componentEnvironment, comp->instanceName, fmi2Warning, - logCategoriesNames[LOG_ERROR], - "logging category '%s' is not supported by model", categories[i]); - } - } - } - return fmi2OK; + return setDebugLogging(comp, loggingOn, nCategories, categories); } fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Real value[]) { @@ -548,10 +503,11 @@ fmi2Status fmi2DoStep(fmi2Component c, fmi2Real currentCommunicationPoint, /* Inquire slave status */ static fmi2Status getStatus(char* fname, fmi2Component c, const fmi2StatusKind s) { - const char *statusKind[3] = {"fmi2DoStepStatus","fmi2PendingStatus","fmi2LastSuccessfulTime"}; + ModelInstance *comp = (ModelInstance *)c; + if (invalidState(comp, fname, MASK_fmi2GetStatus)) // all get status have the same MASK_fmi2GetStatus - return fmi2Error; + return fmi2Error; switch(s) { case fmi2DoStepStatus: logError(comp, @@ -571,6 +527,7 @@ static fmi2Status getStatus(char* fname, fmi2Component c, const fmi2StatusKind s " This is not the case.", fname); break; } + return fmi2Discard; } diff --git a/src/fmi3Functions.c b/src/fmi3Functions.c index d13204b..b1b3e7e 100644 --- a/src/fmi3Functions.c +++ b/src/fmi3Functions.c @@ -23,8 +23,6 @@ #endif #include "fmi3Functions.h" -static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", "logEvent"}; - #ifndef max #define max(a,b) ((a)>(b) ? (a) : (b)) #endif @@ -121,8 +119,6 @@ static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", " // Private helpers used below to validate function arguments // --------------------------------------------------------------------------- -fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex); - static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int statesExpected) { ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, fName, statesExpected)) @@ -131,22 +127,10 @@ static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int st return fmi3Error; } -// --------------------------------------------------------------------------- -// Private helpers logger -// --------------------------------------------------------------------------- - -// return fmi3True if logging category is on. Else return fmi3False. -fmi3Boolean isCategoryLogged(ModelInstance *comp, int categoryIndex) { - if (categoryIndex < NUMBER_OF_CATEGORIES - && (comp->logCategories[categoryIndex] || comp->logCategories[LOG_ALL])) { - return fmi3True; - } - return fmi3False; -} - // --------------------------------------------------------------------------- // FMI functions // --------------------------------------------------------------------------- + fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3String fmuGUID, fmi3String fmuResourceLocation, const fmi3CallbackFunctions *functions, fmi3Boolean visible, fmi3Boolean loggingOn) { @@ -252,44 +236,16 @@ const char* fmi3GetVersion() { // --------------------------------------------------------------------------- fmi3Status fmi3SetDebugLogging(fmi3Component c, fmi3Boolean loggingOn, size_t nCategories, const fmi3String categories[]) { - //int i, j; - //ModelInstance *comp = (ModelInstance *)c; - //if (invalidState(comp, "fmi3SetDebugLogging", MASK_fmi3SetDebugLogging)) - // return fmi3Error; - //comp->loggingOn = loggingOn; - - //// reset all categories - //for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - // comp->logCategories[j] = fmi3False; - //} - - //if (nCategories == 0) { - // // no category specified, set all categories to have loggingOn value - // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - // comp->logCategories[j] = loggingOn; - // } - //} else { - // // set specific categories on - // for (i = 0; i < nCategories; i++) { - // fmi3Boolean categoryFound = fmi3False; - // for (j = 0; j < NUMBER_OF_CATEGORIES; j++) { - // if (strcmp(logCategoriesNames[j], categories[i]) == 0) { - // comp->logCategories[j] = loggingOn; - // categoryFound = fmi3True; - // break; - // } - // } - // if (!categoryFound) { - // comp->logger(comp->componentEnvironment, comp->instanceName, fmi3Warning, - // logCategoriesNames[LOG_ERROR], - // "logging category '%s' is not supported by model", categories[i]); - // } - // } - //} - return fmi3OK; + + ModelInstance *comp = (ModelInstance *)c; + + if (invalidState(comp, "fmi3SetDebugLogging", MASK_fmi3SetDebugLogging)) + return fmi3Error; + + return setDebugLogging(comp, loggingOn, nCategories, categories); } -fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 value[], size_t nValues) { +fmi3Status fmi3GetFloat64(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 value[], size_t nValues) { ModelInstance *comp = (ModelInstance *)c; @@ -352,7 +308,7 @@ fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t GET_BOOLEAN_VARIABLES } -fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { +fmi3Status fmi3GetString(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { ModelInstance *comp = (ModelInstance *)c; @@ -373,7 +329,7 @@ fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t GET_VARIABLES(String) } -fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { +fmi3Status fmi3SetFloat64(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { ModelInstance *comp = (ModelInstance *)c; @@ -421,7 +377,7 @@ fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t SET_BOOLEAN_VARIABLES } -fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { +fmi3Status fmi3SetString(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { ModelInstance *comp = (ModelInstance *)c; @@ -437,10 +393,10 @@ fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t SET_VARIABLES(String) } -fmi3Status fmi3GetFMUstate (fmi3Component c, fmi3FMUstate* FMUstate) { +fmi3Status fmi3GetFMUstate(fmi3Component c, fmi3FMUstate* FMUstate) { return unsupportedFunction(c, "fmi3GetFMUstate", MASK_fmi3GetFMUstate); } -fmi3Status fmi3SetFMUstate (fmi3Component c, fmi3FMUstate FMUstate) { +fmi3Status fmi3SetFMUstate(fmi3Component c, fmi3FMUstate FMUstate) { return unsupportedFunction(c, "fmi3SetFMUstate", MASK_fmi3SetFMUstate); } fmi3Status fmi3FreeFMUstate(fmi3Component c, fmi3FMUstate* FMUstate) { @@ -449,7 +405,7 @@ fmi3Status fmi3FreeFMUstate(fmi3Component c, fmi3FMUstate* FMUstate) { fmi3Status fmi3SerializedFMUstateSize(fmi3Component c, fmi3FMUstate FMUstate, size_t *size) { return unsupportedFunction(c, "fmi3SerializedFMUstateSize", MASK_fmi3SerializedFMUstateSize); } -fmi3Status fmi3SerializeFMUstate (fmi3Component c, fmi3FMUstate FMUstate, fmi3Byte serializedState[], size_t size) { +fmi3Status fmi3SerializeFMUstate(fmi3Component c, fmi3FMUstate FMUstate, fmi3Byte serializedState[], size_t size) { return unsupportedFunction(c, "fmi3SerializeFMUstate", MASK_fmi3SerializeFMUstate); } fmi3Status fmi3DeSerializeFMUstate (fmi3Component c, const fmi3Byte serializedState[], size_t size, diff --git a/src/slave.c b/src/slave.c index 0b98dfb..7519468 100644 --- a/src/slave.c +++ b/src/slave.c @@ -61,7 +61,6 @@ ModelInstance *createModelInstance( comp->allocateMemory = cbAllocateMemory; comp->freeMemory = cbFreeMemory; - int i; comp->instanceName = (char *)allocateMemory(comp, 1 + strlen(instanceName), sizeof(char)); // resourceLocation is NULL for FMI 1.0 ME @@ -73,11 +72,9 @@ ModelInstance *createModelInstance( } comp->modelData = (ModelData *)allocateMemory(comp, 1, sizeof(ModelData)); - - // set all categories to on or off. fmi2SetDebugLogging should be called to choose specific categories. - for (i = 0; i < NUMBER_OF_CATEGORIES; i++) { - comp->logCategories[i] = loggingOn; - } + + comp->logEvents = loggingOn; + comp->logErrors = true; // always log errors } if (!comp || !comp->modelData || !comp->instanceName) { @@ -89,7 +86,6 @@ ModelInstance *createModelInstance( strcpy((char *)comp->instanceName, (char *)instanceName); comp->type = interfaceType; - comp->loggingOn = loggingOn; comp->state = modelInstantiated; comp->isNewEventIteration = false; @@ -181,26 +177,70 @@ bool nullPointer(ModelInstance* comp, const char *f, const char *arg, const void return false; } -void logError(ModelInstance *comp, const char *message, ...) { - - va_list args; - size_t len = 0; - char *buf = ""; - - va_start(args, message); - len = vsnprintf(buf, len, message, args); - va_end(args); +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; +} - buf = allocateMemory(comp, len + 1, sizeof(char)); +static void logMessage(ModelInstance *comp, int status, const char *category, const char *message, va_list args) { + + 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 = allocateMemory(comp, 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 + comp->logger(comp->componentEnvironment, comp->instanceName, status, category, buf); + + freeMemory(comp, buf); +} - va_start(args, message); - vsnprintf(buf, len + 1, message, args); - va_end(args); +void logEvent(ModelInstance *comp, const char *message, ...) { + + if (!comp->logEvents) return; + + va_list args; + va_start(args, message); + logMessage(comp, OK, "logEvents", message, args); + va_end(args); +} - // no need to distinguish between FMI versions since we're not using variadic arguments - comp->logger(comp->componentEnvironment, comp->instanceName, Error, "error", buf); +void logError(ModelInstance *comp, const char *message, ...) { + + if (!comp->logErrors) return; - freeMemory(comp, buf); + va_list args; + va_start(args, message); + logMessage(comp, Error, "logStatusError", message, args); + va_end(args); } // default implementations @@ -308,7 +348,11 @@ Status doStep(ModelInstance *comp, double t, double tNext) { #endif // check for time event - timeEvent = comp->nextEventTimeDefined && (comp->time >= comp->nextEventTime); + timeEvent = comp->nextEventTimeDefined && comp->time >= comp->nextEventTime; + + // log events + if (timeEvent) logEvent(comp, "Time event detected at t=%g s.", comp->time); + if (stateEvent) logEvent(comp, "State event detected at t=%g s.", comp->time); if (stateEvent || timeEvent) { eventUpdate(comp); From 4f1317f25ccf1fa72d0abd71c117820db48259c8 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 21 Jun 2019 11:26:51 +0200 Subject: [PATCH 25/28] Merge platform binaries in CI [skip ci] --- .gitignore | 3 ++ azure-pipelines.yml | 94 ++++++++++++++++++-------------------- merge_platform_binaries.py | 56 +++++++++++++++++++++++ test_build.py | 3 +- 4 files changed, 105 insertions(+), 51 deletions(-) create mode 100644 merge_platform_binaries.py diff --git a/.gitignore b/.gitignore index b5ed9b2..7775be0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ fmi1_cs/ fmi1_me/ fmi2/ fmi3/ +fmus/ +*.fmu +*.zip diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f611af3..918d4a9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,10 +1,12 @@ jobs: -- job: +- job: linux64 displayName: 'Ubuntu 16.04' pool: vmImage: 'ubuntu-16.04' + steps: + - bash: echo "##vso[task.prependpath]$CONDA/bin" displayName: Add conda to PATH @@ -27,27 +29,12 @@ jobs: testResultsFiles: '**/test-*.xml' testRunTitle: 'Publish test results' - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'fmi1_cs/dist' - artifactName: 'linux64-fmi1_cs' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'fmi1_me/dist' - artifactName: 'linux64-fmi1_me' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'fmi2/dist' - artifactName: 'linux64-fmi2' - - - task: PublishBuildArtifacts@1 + - task: PublishPipelineArtifact@1 inputs: - pathtoPublish: 'fmi3/dist' - artifactName: 'linux64-fmi3' + path: fmus + artifact: linux64 -- job: +- job: darwin64 displayName: 'macOS 10.13' pool: vmImage: 'macos-10.13' @@ -81,27 +68,12 @@ jobs: testResultsFiles: '**/test-*.xml' testRunTitle: 'Publish test results' - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'fmi1_cs/dist' - artifactName: 'darwin64-fmi1_cs' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'fmi1_me/dist' - artifactName: 'darwin64-fmi1_me' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: 'fmi2/dist' - artifactName: 'darwin64-fmi2' - - - task: PublishBuildArtifacts@1 + - task: PublishPipelineArtifact@1 inputs: - pathtoPublish: 'fmi3/dist' - artifactName: 'darwin64-fmi3' + path: fmus + artifact: darwin64 -- job: +- job: win64 displayName: 'Windows 2016' pool: vmImage: 'vs2017-win2016' @@ -130,22 +102,44 @@ jobs: testResultsFiles: '**/test-*.xml' testRunTitle: 'Publish test results' - - task: PublishBuildArtifacts@1 + - task: PublishPipelineArtifact@1 + inputs: + path: fmus + artifact: win64 + +- job: merge + dependsOn: + - linux64 + - darwin64 + - win64 + displayName: 'Merge platform binaries' + pool: + vmImage: 'ubuntu-16.04' + + steps: + + - bash: mkdir fmus + displayName: Create fmus directory + + - task: DownloadPipelineArtifact@2 inputs: - pathtoPublish: 'fmi1_cs/dist' - artifactName: 'win64-fmi1_cs' + artifact: linux64 + downloadPath: fmus - - task: PublishBuildArtifacts@1 + - task: DownloadPipelineArtifact@2 inputs: - pathtoPublish: 'fmi1_me/dist' - artifactName: 'win64-fmi1_me' + artifact: darwin64 + downloadPath: fmus - - task: PublishBuildArtifacts@1 + - task: DownloadPipelineArtifact@2 inputs: - pathtoPublish: 'fmi2/dist' - artifactName: 'win64-fmi2' + artifact: win64 + downloadPath: fmus + + - bash: python3 merge_platform_binaries.py + displayName: Merge FMUs - task: PublishBuildArtifacts@1 inputs: - pathtoPublish: 'fmi3/dist' - artifactName: 'win64-fmi3' + pathtoPublish: merged_fmus.zip + artifactName: merged_fmus diff --git a/merge_platform_binaries.py b/merge_platform_binaries.py new file mode 100644 index 0000000..75de3c7 --- /dev/null +++ b/merge_platform_binaries.py @@ -0,0 +1,56 @@ +import zipfile +from tempfile import mkdtemp +from shutil import rmtree +import shutil +import os + +repo_dir = os.path.dirname(__file__) + +test_fmus_version = '0.0.1' + + +def merge(fmi_version, fmi_types): + + for fmi_type in fmi_types: + + platforms_dir = os.path.join(repo_dir, 'fmus', fmi_version, fmi_type) + + _, platforms, _ = next(os.walk(platforms_dir)) + + version_dir = os.path.join(repo_dir, 'fmus', fmi_version, fmi_type, platforms[0], 'Test-FMUs', test_fmus_version) + + _, model_names, _ = next(os.walk(version_dir)) + + for model_name in model_names: + + tempdir = mkdtemp() + + for platform in platforms: + + platform_fmu = os.path.join(repo_dir, 'fmus', fmi_version, fmi_type, platform, 'Test-FMUs', test_fmus_version, model_name, model_name + '.fmu') + + if not os.path.isfile(platform_fmu): + continue + + with zipfile.ZipFile(platform_fmu, 'r') as archive: + archive.extractall(path=tempdir) + + if len(fmi_types) > 1: + merged_fmu = os.path.join(repo_dir, 'merged', fmi_version, fmi_type, model_name + '.fmu') + else: + merged_fmu = os.path.join(repo_dir, 'merged', fmi_version, model_name + '.fmu') + + os.makedirs(os.path.dirname(merged_fmu), exist_ok=True) + + shutil.make_archive(merged_fmu, 'zip', tempdir) + + os.rename(merged_fmu + '.zip', merged_fmu) + + rmtree(tempdir, ignore_errors=True) + + +merge('1.0', ['cs', 'me']) +merge('2.0', ['cs']) +merge('3.0', ['cs']) + +shutil.make_archive(os.path.join(repo_dir, 'merged_fmus'), 'zip', os.path.join(repo_dir, 'merged')) diff --git a/test_build.py b/test_build.py index 9ab64c6..1df12a1 100644 --- a/test_build.py +++ b/test_build.py @@ -4,7 +4,7 @@ import shutil -fmus_dir = None # /path/to/fmi-cross-check/fmus +fmus_dir = os.path.join(os.path.dirname(__file__), 'fmus') # /path/to/fmi-cross-check/fmus test_fmus_version = '0.0.1' try: @@ -171,6 +171,7 @@ def test_fmi3(self): if fmi3_available: self.validate(build_dir, models=['BouncingBall', 'Dahlquist', 'Feedthrough', 'Resource', 'Stair', 'VanDerPol']) + copy_to_cross_check(build_dir=build_dir, model_names=models, fmi_version='3.0', fmi_types=['cs', 'me']) if __name__ == '__main__': unittest.main() From e1925c95cf9416b0c8426b81b7fcb0e1d438818d Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 22 Jun 2019 23:24:55 +0200 Subject: [PATCH 26/28] Update repository structure documentation [skip ci] --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b2f737b..d17b3e6 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,16 @@ A set of test models for development, testing and debugging of the [Functional M `` - `config.h` - model specific types and definitions -- `FMI*.xml` - model descriptions +- `FMI{1CS|1ME|2|3}.xml` - model descriptions - `model.c` - implementation of the model `include` -- `fmi*.h` - FMI header files +- `fmi{|2|3}Functions.h` - FMI header files - `model.h` - generic model interface - `slave.h` - generic co-simulation interface -- `solver.h` - solver interface `src` -- `euler.c` - forward Euler solver -- `fmi[1,2,3].c` - FMI implementation +- `fmi{1|2|3}Functions.c` - FMI implementations - `slave.c` - generic co-simulation ## Build the FMUs From b67809e42841ddef44500597551a3189d05e818e Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 22 Jun 2019 23:35:30 +0200 Subject: [PATCH 27/28] Fix description of variable y in Resource model --- Resource/FMI1CS.xml | 2 +- Resource/FMI1ME.xml | 2 +- Resource/FMI2.xml | 2 +- Resource/FMI3.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resource/FMI1CS.xml b/Resource/FMI1CS.xml index 538eef7..48ded3c 100644 --- a/Resource/FMI1CS.xml +++ b/Resource/FMI1CS.xml @@ -11,7 +11,7 @@ - + diff --git a/Resource/FMI1ME.xml b/Resource/FMI1ME.xml index 8bacb67..4605c0b 100644 --- a/Resource/FMI1ME.xml +++ b/Resource/FMI1ME.xml @@ -11,7 +11,7 @@ - + diff --git a/Resource/FMI2.xml b/Resource/FMI2.xml index 5f3dc9c..85601d7 100644 --- a/Resource/FMI2.xml +++ b/Resource/FMI2.xml @@ -26,7 +26,7 @@ - + diff --git a/Resource/FMI3.xml b/Resource/FMI3.xml index dbcfb2f..ab0ff16 100644 --- a/Resource/FMI3.xml +++ b/Resource/FMI3.xml @@ -21,7 +21,7 @@ - + From 810f3699076b1a42632e01faeb1a2f115eaed4f8 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sun, 23 Jun 2019 13:21:07 +0200 Subject: [PATCH 28/28] Bump version to 0.0.2 --- merge_platform_binaries.py | 2 +- test_build.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/merge_platform_binaries.py b/merge_platform_binaries.py index 75de3c7..830057a 100644 --- a/merge_platform_binaries.py +++ b/merge_platform_binaries.py @@ -6,7 +6,7 @@ repo_dir = os.path.dirname(__file__) -test_fmus_version = '0.0.1' +test_fmus_version = '0.0.2' def merge(fmi_version, fmi_types): diff --git a/test_build.py b/test_build.py index 1df12a1..b553c28 100644 --- a/test_build.py +++ b/test_build.py @@ -5,7 +5,7 @@ fmus_dir = os.path.join(os.path.dirname(__file__), 'fmus') # /path/to/fmi-cross-check/fmus -test_fmus_version = '0.0.1' +test_fmus_version = '0.0.2' try: from fmpy import simulate_fmu