From 00bd2dd56981ad39010810801bd34d0ed0dbc75f Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Wed, 20 Feb 2019 20:29:00 +0100 Subject: [PATCH 01/16] Add initial set of Test FMUs --- .gitignore | 7 + BouncingBall/BouncingBall_ref.csv | 325 +++++ BouncingBall/BouncingBall_ref.svg | 1548 ++++++++++++++++++++++++ BouncingBall/FMI1CS.xml | 27 + BouncingBall/FMI1ME.xml | 21 + BouncingBall/FMI2.xml | 83 ++ BouncingBall/FMI3.xml | 47 + BouncingBall/config.h | 29 + BouncingBall/model.c | 122 ++ BouncingBall/readme.html | 116 ++ BouncingBall/readme.md | 25 + CMakeLists.txt | 189 +++ CONTRIBUTING.md | 150 +++ Dahlquist/Dahlquist_ref.csv | 52 + Dahlquist/Dahlquist_ref.svg | 573 +++++++++ Dahlquist/FMI1CS.xml | 24 + Dahlquist/FMI1ME.xml | 18 + Dahlquist/FMI2.xml | 55 + Dahlquist/FMI3.xml | 49 + Dahlquist/config.h | 28 + Dahlquist/model.c | 70 ++ Dahlquist/readme.html | 89 ++ Dahlquist/readme.md | 25 + Feedthrough/FMI1CS.xml | 48 + Feedthrough/FMI1ME.xml | 42 + Feedthrough/FMI2.xml | 82 ++ Feedthrough/FMI3.xml | 56 + Feedthrough/Feedthrough_in.csv | 7 + Feedthrough/Feedthrough_ref.csv | 17 + Feedthrough/Feedthrough_ref.svg | 1869 +++++++++++++++++++++++++++++ Feedthrough/config.h | 49 + Feedthrough/model.c | 136 +++ Feedthrough/readme.html | 50 + Feedthrough/readme.md | 7 + LICENSE.txt | 32 + README.md | 66 +- Resource/FMI1CS.xml | 18 + Resource/FMI1ME.xml | 12 + Resource/FMI2.xml | 43 + Resource/FMI3.xml | 41 + Resource/Resource_ref.csv | 7 + Resource/Resource_ref.svg | 517 ++++++++ Resource/config.h | 22 + Resource/model.c | 83 ++ Resource/readme.html | 52 + Resource/readme.md | 7 + Resource/resources/y.txt | 1 + Stair/FMI1CS.xml | 18 + Stair/FMI1ME.xml | 12 + Stair/FMI2.xml | 43 + Stair/FMI3.xml | 41 + Stair/Stair_ref.csv | 22 + Stair/Stair_ref.svg | 696 +++++++++++ Stair/config.h | 25 + Stair/model.c | 35 + Stair/readme.html | 52 + Stair/readme.md | 7 + VanDerPol/FMI1CS.xml | 30 + VanDerPol/FMI1ME.xml | 24 + VanDerPol/FMI2.xml | 64 + VanDerPol/FMI3.xml | 54 + VanDerPol/VanDerPol_ref.csv | 202 ++++ VanDerPol/VanDerPol_ref.svg | 1018 ++++++++++++++++ VanDerPol/config.h | 29 + VanDerPol/model.c | 86 ++ VanDerPol/readme.html | 85 ++ VanDerPol/readme.md | 20 + appveyor.yml | 9 + include/fmi2FunctionTypes.h | 243 ++++ include/fmi2Functions.h | 333 +++++ include/fmi2TypesPlatform.h | 115 ++ include/fmi3FunctionTypes.h | 473 ++++++++ include/fmi3Functions.h | 282 +++++ include/fmi3TypesPlatform.h | 87 ++ include/fmiFunctions.h | 230 ++++ include/fmiModelFunctions.h | 206 ++++ include/fmiModelTypes.h | 91 ++ include/fmiPlatformTypes.h | 73 ++ include/model.h | 132 ++ include/slave.h | 8 + include/solver.h | 13 + logo.svg | 41 + run.py | 105 ++ src/euler.c | 83 ++ src/fmi1.c | 770 ++++++++++++ src/fmi2.c | 1044 ++++++++++++++++ src/fmi3.c | 955 +++++++++++++++ src/slave.c | 81 ++ test_build.py | 141 +++ 89 files changed, 15012 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 BouncingBall/BouncingBall_ref.csv create mode 100644 BouncingBall/BouncingBall_ref.svg create mode 100644 BouncingBall/FMI1CS.xml create mode 100644 BouncingBall/FMI1ME.xml create mode 100644 BouncingBall/FMI2.xml create mode 100644 BouncingBall/FMI3.xml create mode 100644 BouncingBall/config.h create mode 100644 BouncingBall/model.c create mode 100644 BouncingBall/readme.html create mode 100644 BouncingBall/readme.md create mode 100644 CMakeLists.txt create mode 100644 CONTRIBUTING.md create mode 100644 Dahlquist/Dahlquist_ref.csv create mode 100644 Dahlquist/Dahlquist_ref.svg create mode 100644 Dahlquist/FMI1CS.xml create mode 100644 Dahlquist/FMI1ME.xml create mode 100644 Dahlquist/FMI2.xml create mode 100644 Dahlquist/FMI3.xml create mode 100644 Dahlquist/config.h create mode 100644 Dahlquist/model.c create mode 100644 Dahlquist/readme.html create mode 100644 Dahlquist/readme.md create mode 100644 Feedthrough/FMI1CS.xml create mode 100644 Feedthrough/FMI1ME.xml create mode 100644 Feedthrough/FMI2.xml create mode 100644 Feedthrough/FMI3.xml create mode 100644 Feedthrough/Feedthrough_in.csv create mode 100644 Feedthrough/Feedthrough_ref.csv create mode 100644 Feedthrough/Feedthrough_ref.svg create mode 100644 Feedthrough/config.h create mode 100644 Feedthrough/model.c create mode 100644 Feedthrough/readme.html create mode 100644 Feedthrough/readme.md create mode 100644 LICENSE.txt create mode 100644 Resource/FMI1CS.xml create mode 100644 Resource/FMI1ME.xml create mode 100644 Resource/FMI2.xml create mode 100644 Resource/FMI3.xml create mode 100644 Resource/Resource_ref.csv create mode 100644 Resource/Resource_ref.svg create mode 100644 Resource/config.h create mode 100644 Resource/model.c create mode 100644 Resource/readme.html create mode 100644 Resource/readme.md create mode 100644 Resource/resources/y.txt create mode 100644 Stair/FMI1CS.xml create mode 100644 Stair/FMI1ME.xml create mode 100644 Stair/FMI2.xml create mode 100644 Stair/FMI3.xml create mode 100644 Stair/Stair_ref.csv create mode 100644 Stair/Stair_ref.svg create mode 100644 Stair/config.h create mode 100644 Stair/model.c create mode 100644 Stair/readme.html create mode 100644 Stair/readme.md create mode 100644 VanDerPol/FMI1CS.xml create mode 100644 VanDerPol/FMI1ME.xml create mode 100644 VanDerPol/FMI2.xml create mode 100644 VanDerPol/FMI3.xml create mode 100644 VanDerPol/VanDerPol_ref.csv create mode 100644 VanDerPol/VanDerPol_ref.svg create mode 100644 VanDerPol/config.h create mode 100644 VanDerPol/model.c create mode 100644 VanDerPol/readme.html create mode 100644 VanDerPol/readme.md create mode 100644 appveyor.yml create mode 100644 include/fmi2FunctionTypes.h create mode 100644 include/fmi2Functions.h create mode 100644 include/fmi2TypesPlatform.h create mode 100644 include/fmi3FunctionTypes.h create mode 100644 include/fmi3Functions.h create mode 100644 include/fmi3TypesPlatform.h create mode 100644 include/fmiFunctions.h create mode 100644 include/fmiModelFunctions.h create mode 100644 include/fmiModelTypes.h create mode 100644 include/fmiPlatformTypes.h create mode 100644 include/model.h create mode 100644 include/slave.h create mode 100644 include/solver.h create mode 100644 logo.svg create mode 100644 run.py create mode 100644 src/euler.c create mode 100644 src/fmi1.c create mode 100644 src/fmi2.c create mode 100644 src/fmi3.c create mode 100644 src/slave.c create mode 100644 test_build.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5ed9b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# build artifacts +.idea/ +build/ +fmi1_cs/ +fmi1_me/ +fmi2/ +fmi3/ diff --git a/BouncingBall/BouncingBall_ref.csv b/BouncingBall/BouncingBall_ref.csv new file mode 100644 index 0000000..e01ca97 --- /dev/null +++ b/BouncingBall/BouncingBall_ref.csv @@ -0,0 +1,325 @@ +"time","h","v" +0,1,0 +0.01,0.999507,-0.0981 +0.02,0.998034,-0.1962 +0.03,0.995581,-0.2943 +0.04,0.992147,-0.3924 +0.05,0.987732,-0.4905 +0.06,0.982337,-0.5886 +0.07,0.97596,-0.6867 +0.08,0.968602,-0.7848 +0.09,0.960263,-0.8829 +0.1,0.950944,-0.981 +0.11,0.940643,-1.0791 +0.12,0.929361,-1.1772 +0.13,0.917099,-1.2753 +0.14,0.903855,-1.3734 +0.15,0.889631,-1.4715 +0.16,0.874425,-1.5696 +0.17,0.858239,-1.6677 +0.18,0.841071,-1.7658 +0.19,0.822922,-1.8639 +0.2,0.803793,-1.962 +0.21,0.783682,-2.0601 +0.22,0.762591,-2.1582 +0.23,0.740518,-2.2563 +0.24,0.717465,-2.3544 +0.25,0.69343,-2.4525 +0.26,0.668415,-2.5506 +0.27,0.642418,-2.6487 +0.28,0.615441,-2.7468 +0.29,0.587482,-2.8449 +0.3,0.558543,-2.943 +0.31,0.528622,-3.0411 +0.32,0.497721,-3.1392 +0.33,0.465838,-3.2373 +0.34,0.432975,-3.3354 +0.35,0.39913,-3.4335 +0.36,0.364305,-3.5316 +0.37,0.328498,-3.6297 +0.38,0.291711,-3.7278 +0.39,0.253942,-3.8259 +0.4,0.215193,-3.924 +0.41,0.175462,-4.0221 +0.42,0.134751,-4.1202 +0.43,0.0930583,-4.2183 +0.44,0.0503848,-4.3164 +0.45,0.00673031,-4.4145 +0.451522,-2.77001e-14,-4.42943 +0.451522,0,3.1006 +0.46,0.02593,3.01743 +0.47,0.0556132,2.91933 +0.48,0.0843156,2.82123 +0.49,0.112037,2.72313 +0.5,0.138778,2.62503 +0.51,0.164538,2.52693 +0.52,0.189316,2.42883 +0.53,0.213114,2.33073 +0.54,0.235931,2.23263 +0.55,0.257766,2.13453 +0.56,0.278621,2.03643 +0.57,0.298495,1.93833 +0.58,0.317388,1.84023 +0.59,0.335299,1.74213 +0.6,0.35223,1.64403 +0.61,0.36818,1.54593 +0.62,0.383149,1.44783 +0.63,0.397137,1.34973 +0.64,0.410143,1.25163 +0.65,0.422169,1.15353 +0.66,0.433214,1.05543 +0.67,0.443278,0.957333 +0.68,0.452361,0.859233 +0.69,0.460462,0.761133 +0.7,0.467583,0.663033 +0.71,0.473723,0.564933 +0.72,0.478882,0.466833 +0.73,0.48306,0.368733 +0.74,0.486257,0.270633 +0.75,0.488472,0.172533 +0.76,0.489707,0.0744327 +0.77,0.489961,-0.0236673 +0.78,0.489234,-0.121767 +0.79,0.487526,-0.219867 +0.8,0.484837,-0.317967 +0.81,0.481166,-0.416067 +0.82,0.476515,-0.514167 +0.83,0.470883,-0.612267 +0.84,0.46427,-0.710367 +0.85,0.456676,-0.808467 +0.86,0.4481,-0.906567 +0.87,0.438544,-1.00467 +0.88,0.428007,-1.10277 +0.89,0.416489,-1.20087 +0.9,0.40399,-1.29897 +0.91,0.39051,-1.39707 +0.92,0.376048,-1.49517 +0.93,0.360606,-1.59327 +0.94,0.344183,-1.69137 +0.95,0.326779,-1.78947 +0.96,0.308394,-1.88757 +0.97,0.289028,-1.98567 +0.98,0.26868,-2.08377 +0.99,0.247352,-2.18187 +1,0.225043,-2.27997 +1.01,0.201753,-2.37807 +1.02,0.177482,-2.47617 +1.03,0.15223,-2.57427 +1.04,0.125996,-2.67237 +1.05,0.0987822,-2.77047 +1.06,0.070587,-2.86857 +1.07,0.0414109,-2.96667 +1.08,0.0112537,-3.06477 +1.08365,-3.98709e-14,-3.10058 +1.08365,0,2.17041 +1.09,0.0135736,2.10812 +1.1,0.0341631,2.01002 +1.11,0.0537723,1.91192 +1.12,0.0724007,1.81382 +1.13,0.0900481,1.71572 +1.14,0.106715,1.61762 +1.15,0.1224,1.51952 +1.16,0.137105,1.42142 +1.17,0.150828,1.32332 +1.18,0.163571,1.22522 +1.19,0.175332,1.12712 +1.2,0.186113,1.02902 +1.21,0.195913,0.930919 +1.22,0.204731,0.832819 +1.23,0.212569,0.734719 +1.24,0.219426,0.636619 +1.25,0.225301,0.538519 +1.26,0.230196,0.440419 +1.27,0.23411,0.342319 +1.28,0.237042,0.244219 +1.29,0.238994,0.146119 +1.3,0.239965,0.0480186 +1.31,0.239954,-0.0500814 +1.32,0.238963,-0.148181 +1.33,0.236991,-0.246281 +1.34,0.234037,-0.344381 +1.35,0.230103,-0.442481 +1.36,0.225188,-0.540581 +1.37,0.219291,-0.638681 +1.38,0.212414,-0.736781 +1.39,0.204556,-0.834881 +1.4,0.195716,-0.932981 +1.41,0.185896,-1.03108 +1.42,0.175095,-1.12918 +1.43,0.163312,-1.22728 +1.44,0.150549,-1.32538 +1.45,0.136805,-1.42348 +1.46,0.122079,-1.52158 +1.47,0.106373,-1.61968 +1.48,0.0896859,-1.71778 +1.49,0.0720175,-1.81588 +1.5,0.0533682,-1.91398 +1.51,0.0337379,-2.01208 +1.52,0.0131266,-2.11018 +1.52613,-5.55112e-17,-2.17035 +1.52613,0,1.51924 +1.53,0.00578613,1.48131 +1.54,0.0201043,1.38321 +1.55,0.0334453,1.28511 +1.56,0.0458055,1.18701 +1.57,0.0571848,1.08891 +1.58,0.0675832,0.99081 +1.59,0.0770007,0.89271 +1.6,0.0854371,0.79461 +1.61,0.0928925,0.69651 +1.62,0.099367,0.59841 +1.63,0.104861,0.50031 +1.64,0.109373,0.40221 +1.65,0.112905,0.30411 +1.66,0.115455,0.20601 +1.67,0.117025,0.10791 +1.68,0.117613,0.00980987 +1.69,0.117221,-0.0882901 +1.7,0.115847,-0.18639 +1.71,0.113493,-0.28449 +1.72,0.110158,-0.38259 +1.73,0.105841,-0.48069 +1.74,0.100544,-0.57879 +1.75,0.0942653,-0.67689 +1.76,0.0870059,-0.77499 +1.77,0.0787655,-0.87309 +1.78,0.0695441,-0.97119 +1.79,0.0593417,-1.06929 +1.8,0.0481583,-1.16739 +1.81,0.0359939,-1.26549 +1.82,0.0228485,-1.36359 +1.83,0.00872209,-1.46169 +1.83585,-3.26544e-14,-1.5191 +1.83585,0,1.06337 +1.84,0.00431854,1.02268 +1.85,0.0140533,0.92458 +1.86,0.0228081,0.82648 +1.87,0.030582,0.72838 +1.88,0.037375,0.63028 +1.89,0.0431871,0.53218 +1.9,0.0480184,0.43408 +1.91,0.0518685,0.33598 +1.92,0.0547376,0.23788 +1.93,0.0566258,0.13978 +1.94,0.0575331,0.0416802 +1.95,0.0574593,-0.0564198 +1.96,0.0564046,-0.15452 +1.97,0.0543688,-0.25262 +1.98,0.051352,-0.35072 +1.99,0.0473543,-0.44882 +2,0.0423756,-0.54692 +2.01,0.0364159,-0.64502 +2.02,0.0294752,-0.74312 +2.03,0.0215534,-0.84122 +2.04,0.0126507,-0.93932 +2.05,0.00276702,-1.03742 +2.05263,-2.8191e-14,-1.06326 +2.05263,0,0.744284 +2.06,0.00520533,0.672028 +2.07,0.0114341,0.573928 +2.08,0.0166824,0.475828 +2.09,0.0209499,0.377728 +2.1,0.0242364,0.279628 +2.11,0.026542,0.181528 +2.12,0.0278666,0.0834277 +2.13,0.0282102,-0.0146723 +2.14,0.0275729,-0.112772 +2.15,0.0259546,-0.210872 +2.16,0.0233553,-0.308972 +2.17,0.019775,-0.407072 +2.18,0.0152137,-0.505172 +2.19,0.00967144,-0.603272 +2.2,0.00314817,-0.701372 +2.20436,-1.36471e-14,-0.744103 +2.20436,0,0.520872 +2.21,0.00277078,0.465504 +2.22,0.00693402,0.367404 +2.23,0.0101171,0.269304 +2.24,0.0123193,0.171204 +2.25,0.0135406,0.0731036 +2.26,0.0137809,-0.0249964 +2.27,0.0130404,-0.123096 +2.28,0.0113187,-0.221196 +2.29,0.00861613,-0.319296 +2.3,0.00493259,-0.417396 +2.31,0.000268093,-0.515496 +2.31052,-1.03597e-14,-0.520573 +2.31052,0,0.364401 +2.32,0.00300073,0.271378 +2.33,0.00522321,0.173278 +2.34,0.00646508,0.0751782 +2.35,0.00672614,-0.0229218 +2.36,0.00600616,-0.121022 +2.37,0.00430532,-0.219122 +2.38,0.00162345,-0.317222 +2.38477,-1.00198e-14,-0.363978 +2.38477,0,0.254785 +2.39,0.00118645,0.203441 +2.4,0.00272884,0.105341 +2.41,0.00329125,0.00724129 +2.42,0.00287287,-0.0908587 +2.43,0.00147351,-0.188959 +2.43665,-9.1073e-18,-0.254191 +2.43665,0,0.177933 +2.44,0.000530079,0.145065 +2.45,0.00148718,0.0469654 +2.46,0.00146579,-0.0511346 +2.47,0.000463562,-0.149235 +2.47284,-4.82164e-15,-0.177103 +2.47284,0,0.123972 +2.48,0.000622747,0.0537409 +2.49,0.000668661,-0.0443591 +2.498,-1.47451e-17,-0.122801 +2.498,0,0 +2.5,0,0 +2.51,0,0 +2.52,0,0 +2.53,0,0 +2.54,0,0 +2.55,0,0 +2.56,0,0 +2.57,0,0 +2.58,0,0 +2.59,0,0 +2.6,0,0 +2.61,0,0 +2.62,0,0 +2.63,0,0 +2.64,0,0 +2.65,0,0 +2.66,0,0 +2.67,0,0 +2.68,0,0 +2.69,0,0 +2.7,0,0 +2.71,0,0 +2.72,0,0 +2.73,0,0 +2.74,0,0 +2.75,0,0 +2.76,0,0 +2.77,0,0 +2.78,0,0 +2.79,0,0 +2.8,0,0 +2.81,0,0 +2.82,0,0 +2.83,0,0 +2.84,0,0 +2.85,0,0 +2.86,0,0 +2.87,0,0 +2.88,0,0 +2.89,0,0 +2.9,0,0 +2.91,0,0 +2.92,0,0 +2.93,0,0 +2.94,0,0 +2.95,0,0 +2.96,0,0 +2.97,0,0 +2.98,0,0 +2.99,0,0 +3,0,0 +3.01,0,0 diff --git a/BouncingBall/BouncingBall_ref.svg b/BouncingBall/BouncingBall_ref.svg new file mode 100644 index 0000000..40e062f --- /dev/null +++ b/BouncingBall/BouncingBall_ref.svg @@ -0,0 +1,1548 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BouncingBall/FMI1CS.xml b/BouncingBall/FMI1CS.xml new file mode 100644 index 0000000..c26d9f8 --- /dev/null +++ b/BouncingBall/FMI1CS.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BouncingBall/FMI1ME.xml b/BouncingBall/FMI1ME.xml new file mode 100644 index 0000000..f9a3f48 --- /dev/null +++ b/BouncingBall/FMI1ME.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/BouncingBall/FMI2.xml b/BouncingBall/FMI2.xml new file mode 100644 index 0000000..cea915b --- /dev/null +++ b/BouncingBall/FMI2.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BouncingBall/FMI3.xml b/BouncingBall/FMI3.xml new file mode 100644 index 0000000..230887a --- /dev/null +++ b/BouncingBall/FMI3.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BouncingBall/config.h b/BouncingBall/config.h new file mode 100644 index 0000000..6ffaeb6 --- /dev/null +++ b/BouncingBall/config.h @@ -0,0 +1,29 @@ +#ifndef config_h +#define config_h + +// define class name and unique id +#define MODEL_IDENTIFIER BouncingBall +#define MODEL_GUID "{8c4e810f-3df3-4a00-8276-176fa3c9f003}" + +// define model size +#define NUMBER_OF_STATES 2 +#define NUMBER_OF_EVENT_INDICATORS 1 + +#define GET_REAL +#define SET_REAL +#define EVENT_UPDATE + +typedef enum { + vr_h, vr_v, vr_g, vr_e, vr_v_min +} ValueReference; + +typedef struct { + + double h; + double v; + double g; + double e; + +} ModelData; + +#endif /* config_h */ diff --git a/BouncingBall/model.c b/BouncingBall/model.c new file mode 100644 index 0000000..06073f3 --- /dev/null +++ b/BouncingBall/model.c @@ -0,0 +1,122 @@ +#include // for fabs() +#include "config.h" +#include "model.h" + +// shorthand to access the variables +#define M(v) (comp->modelData->v) + +#define V_MIN (0.1) + +void setStartValues(ModelInstance *comp) { + M(h) = 1; + M(v) = 0; + M(g) = -9.81; + M(e) = 0.7; +} + +void calculateValues(ModelInstance *comp) { + // do nothing +} + +Status getReal(ModelInstance* comp, ValueReference vr, double *value) { + switch (vr) { + case vr_h: + *value = M(h); + return OK; + case vr_v: + *value = M(v); + return OK; + case vr_g: + *value = M(g); + return OK; + case vr_e: + *value = M(e); + return OK; + case vr_v_min: + *value = V_MIN; + return OK; + default: + return Error; + } +} + +Status setReal(ModelInstance* comp, ValueReference vr, double value) { + switch (vr) { + + case vr_h: + M(h) = value; + return OK; + + case vr_v: + M(v) = value; + return OK; + + case vr_g: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInstantiated && + comp->state != modelInitializationMode) { + logError(comp, "Variable g can only be set after instantiation or in initialization mode."); + return Error; + } +#endif + M(g) = value; + return OK; + + case vr_e: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInstantiated && + comp->state != modelInitializationMode && + comp->state != modelEventMode) { + logError(comp, "Variable e can only be set after instantiation, in initialization mode or event mode."); + return Error; + } +#endif + M(e) = value; + return OK; + + default: + return Error; + } +} + +void eventUpdate(ModelInstance *comp) { + + if (M(h) <= 0) { + + M(h) = 0; + M(v) = fabs(M(v) * M(e)); + + if (M(v) < V_MIN) { + // stop bouncing + M(v) = 0; + M(g) = 0; + } + + comp->valuesOfContinuousStatesChanged = true; + } + + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} + +void getContinuousStates(ModelInstance *comp, double x[], size_t nx) { + x[0] = M(h); + x[1] = M(v); +} + +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) { + M(h) = x[0]; + M(v) = x[1]; +} + +void getDerivatives(ModelInstance *comp, double dx[], size_t nx) { + dx[0] = M(v); + dx[1] = M(g); +} + +void getEventIndicators(ModelInstance *comp, double z[], size_t nz) { + z[0] = (M(h) == 0 && M(v) == 0) ? 1 : M(h); +} diff --git a/BouncingBall/readme.html b/BouncingBall/readme.html new file mode 100644 index 0000000..191434a --- /dev/null +++ b/BouncingBall/readme.html @@ -0,0 +1,116 @@ + + + + +
+

BouncingBall

+ +

The BouncingBall implements the following equation:

+ +
der(h) =  v
+der(v) = -g
+
+when h <= 0    then h := 0 and v := -e * v
+when v < v_min then h := 0 and v := 0
+
+ +

whith the variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableStartUnitCausalityVariabilityDescription
h1moutputcontinuousDistance to the ground
v0m/soutputcontinuousVelocity
g9.81m/s2parameterfixedGravity
e0.7parametertunableRebound factor
v_min0.1m/s2parameterconstantThreshold velocity to stop bouncing
+ +

The plot shows the reference result computed with FMPy.

+ +

plot

+ +
+ + diff --git a/BouncingBall/readme.md b/BouncingBall/readme.md new file mode 100644 index 0000000..b6fe2aa --- /dev/null +++ b/BouncingBall/readme.md @@ -0,0 +1,25 @@ +# BouncingBall + +The BouncingBall implements the following equation: + +``` +der(h) = v +der(v) = -g + +when h <= 0 then h := 0 and v := -e * v +when v < v_min then h := 0 and v := 0 +``` + +whith the variables + +| Variable | Start | Unit | Causality | Variability | Description +|:---------| -----:|:-----|-----------|-------------|:--------------- +| h | 1 | m | output | continuous | Distance to the ground +| v | 0 | m/s | output | continuous | Velocity +| g | 9.81 | m/s2 | parameter | fixed | Gravity +| e | 0.7 | | parameter | tunable | Rebound factor +| v_min | 0.1 | m/s2 | parameter | constant | Threshold velocity to stop bouncing + +The plot shows the [reference result](BouncingBall_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). + +![plot](BouncingBall_ref.svg) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7c13081 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,189 @@ +cmake_minimum_required (VERSION 3.2) + +FUNCTION(cat IN_FILE OUT_FILE) + file(READ ${IN_FILE} CONTENTS) + file(APPEND ${OUT_FILE} "${CONTENTS}") +ENDFUNCTION() + +project (Test-FMUs) + +set(FMI_VERSION 2 CACHE STRING "FMI Version") +set_property(CACHE FMI_VERSION PROPERTY STRINGS 1 2 3) + +set(FMI_TYPE ME CACHE STRING "FMI Type (FMI 1.0 only)") +set_property(CACHE FMI_TYPE PROPERTY STRINGS ME CS) + +if (${FMI_VERSION} GREATER 1) + set(FMI_TYPE "") +endif () + +if (WIN32) + 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 () + +if (${FMI_VERSION} GREATER 2) + + if (WIN32) + set(FMI_PLATFORM windows) + elseif (APPLE) + set(FMI_PLATFORM darwin) + else () + set(FMI_PLATFORM linux) + endif () + + if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set (FMI_PLATFORM x86_64-${FMI_PLATFORM}) + else () + set (FMI_PLATFORM i686-${FMI_PLATFORM}) + endif () + +else () + + if (WIN32) + set(FMI_PLATFORM win) + elseif (APPLE) + set(FMI_PLATFORM darwin) + else () + set(FMI_PLATFORM linux) + endif () + + if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set (FMI_PLATFORM ${FMI_PLATFORM}64) + else () + set (FMI_PLATFORM ${FMI_PLATFORM}32) + endif () + +endif () + +MESSAGE("FMI_PLATFORM: " ${FMI_PLATFORM}) + +foreach (MODEL_NAME BouncingBall Dahlquist Stair Feedthrough Resource VanDerPol) + +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 +) + +add_library(${TARGET_NAME} SHARED + ${HEADERS} + ${SOURCES} + ${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml +) + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist) + +target_compile_definitions(${TARGET_NAME} PRIVATE DISABLE_PREFIX FMI_VERSION=${FMI_VERSION}) + +if (${FMI_VERSION} EQUAL 1 AND "${FMI_TYPE}" STREQUAL CS) + message("CO_SIMULATION") + target_compile_definitions(${TARGET_NAME} PRIVATE FMI_COSIMULATION) +endif() + +target_include_directories(${TARGET_NAME} PRIVATE + "include" + "${MODEL_NAME}" +) + +set(FMU_BUILD_DIR temp/${MODEL_NAME}) + +set_target_properties(${TARGET_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + LIBRARY_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + ARCHIVE_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}" +) + +set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "") +set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${MODEL_NAME}) + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +# modelDescription.xml +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml + "${FMU_BUILD_DIR}/modelDescription.xml" +) + +# model specific header and source +foreach (SOURCE_FILE config.h model.c) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/${SOURCE_FILE}" + "${FMU_BUILD_DIR}/sources/${SOURCE_FILE}" + ) +endforeach(SOURCE_FILE) + +# documentation +if (${FMI_VERSION} EQUAL 1) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/readme.html" + "${FMU_BUILD_DIR}/documentation/_main.html" + ) +else() + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/readme.html" + "${FMU_BUILD_DIR}/documentation/index.html" + ) +endif() + +# plot +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/${MODEL_NAME}_ref.svg" + "${FMU_BUILD_DIR}/documentation/${MODEL_NAME}_ref.svg" +) + +# license +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt" + "${FMU_BUILD_DIR}/documentation/LICENSE.txt" +) + +# common headers +foreach (SOURCE_FILE model.h slave.h solver.h) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/include/${SOURCE_FILE}" + "${FMU_BUILD_DIR}/sources/${SOURCE_FILE}" + ) +endforeach(SOURCE_FILE) + +# common sources +foreach (SOURCE_FILE fmi${FMI_VERSION}.c euler.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}" + ) +endforeach(SOURCE_FILE) + +set(ARCHIVE_FILES "modelDescription.xml" "binaries" "documentation" "sources") + +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources") + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources" + "${FMU_BUILD_DIR}/resources/" + ) + set(ARCHIVE_FILES ${ARCHIVE_FILES} "resources") +endif() + +# create ZIP archive +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E tar "cfv" ${CMAKE_CURRENT_BINARY_DIR}/dist/${MODEL_NAME}.fmu --format=zip + ${ARCHIVE_FILES} + WORKING_DIRECTORY ${FMU_BUILD_DIR} +) + +endforeach(MODEL_NAME) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..916bfea --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,150 @@ +# Contributing to this project + +## Using the issue tracker + +The issue tracker is the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests). +Please **do not** use the issue tracker for personal support requests. +[Stack Overflow](http://stackoverflow.com) is a better place to get help. + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or development branch in the repository. + +3. **Isolate the problem** — create a reduced test case or example. + +A good bug report shouldn't leave others needing to chase you up for more information. +Please try to be as detailed as possible in your report. +What is your operating system, FMI version and type, importing tool? +What steps will reproduce the issue? +What model experiences the problem? +What would you expect to be the outcome? +All these details will help people to fix any potential bugs. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the platform/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> `` - a link to the reduced test case +> +> Any other information you want to share that is relevant to the issue being reported. +> This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits). + +## Feature requests + +Feature requests are welcome. +But take a moment to find out whether your idea fits with the scope and aims of the project. +It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. +Please provide as much detail and context as possible. + +## Commit messages + +Please follow [the seven rules of a great Git commit message](https://chris.beams.io/posts/git-commit/) when committing your changes: + +- Separate subject from body with a blank line +- Limit the subject line to 50 characters +- Capitalize the subject line +- Do not end the subject line with a period +- Use the imperative mood in the subject line +- Wrap the body at 72 characters +- Use the body to explain what and why vs. how + +For example: + +``` +Summarize changes in around 50 characters or less + +More detailed explanatory text, if necessary. Wrap it to about 72 +characters or so. In some contexts, the first line is treated as the +subject of the commit and the rest of the text as the body. The +blank line separating the summary from the body is critical (unless +you omit the body entirely); various tools like `log`, `shortlog` +and `rebase` can get confused if you run the two together. + +Explain the problem that this commit is solving. Focus on why you +are making this change as opposed to how (the code explains that). +Are there side effects or other unintuitive consequences of this +change? Here's the place to explain them. + +Further paragraphs come after blank lines. + + - Bullet points are okay, too + + - Typically a hyphen or asterisk is used for the bullet, preceded + by a single space, with blank lines in between, but conventions + vary here + +If you use an issue tracker, put references to them at the bottom, +like this: + +Resolves: #123 +See also: #456, #789 +``` + +## Pull requests + +Good pull requests - patches, improvements, new features - are a fantastic help. +They should remain focused in scope and avoid containing unrelated commits. + +**Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), +otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. + +Please adhere to the coding conventions used throughout a project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). + +Follow this process if you'd like your work considered for inclusion in the project: + +1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: + + ```bash + # Clone your fork of the repo into the current directory + git clone https://github.com// + # Navigate to the newly cloned directory + cd + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com// + ``` + +2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout + git pull upstream + ``` + +3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix: + + ```bash + git checkout -b + ``` + +4. Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. + Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. + +5. Locally merge (or rebase) the upstream development branch into your topic branch: + + ```bash + git pull [--rebase] upstream + ``` + +6. Push your topic branch up to your fork: + + ```bash + git push origin + ``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) + with a clear title and description. + +**IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same [license](LICENSE.txt) as that used by the project. diff --git a/Dahlquist/Dahlquist_ref.csv b/Dahlquist/Dahlquist_ref.csv new file mode 100644 index 0000000..dd7717e --- /dev/null +++ b/Dahlquist/Dahlquist_ref.csv @@ -0,0 +1,52 @@ +"time","x" +0,1 +0.2,0.818697 +0.4,0.670268 +0.6,0.548776 +0.8,0.449307 +1,0.367857 +1.2,0.301165 +1.4,0.246563 +1.6,0.201863 +1.8,0.165267 +2,0.135306 +2.2,0.110777 +2.4,0.0906989 +2.6,0.0742622 +2.8,0.0608022 +3,0.0497789 +3.2,0.0407543 +3.4,0.0333678 +3.6,0.0273202 +3.8,0.022367 +4,0.0183111 +4.2,0.0149921 +4.4,0.0122755 +4.6,0.0100503 +4.8,0.00822774 +5,0.00673565 +5.2,0.00551445 +5.4,0.0045148 +5.6,0.00369631 +5.8,0.00302613 +6,0.00247752 +6.2,0.00202847 +6.4,0.00166084 +6.6,0.00135981 +6.8,0.00111331 +7,0.000911508 +7.2,0.0007463 +7.4,0.000611038 +7.6,0.000500284 +7.8,0.000409599 +8,0.000335355 +8.2,0.000274572 +8.4,0.000224806 +8.6,0.000184058 +8.8,0.000150696 +9,0.000123381 +9.2,0.000101018 +9.4,8.27082e-05 +9.6,6.77167e-05 +9.8,5.54425e-05 +10,4.53932e-05 diff --git a/Dahlquist/Dahlquist_ref.svg b/Dahlquist/Dahlquist_ref.svg new file mode 100644 index 0000000..a0a12d7 --- /dev/null +++ b/Dahlquist/Dahlquist_ref.svg @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dahlquist/FMI1CS.xml b/Dahlquist/FMI1CS.xml new file mode 100644 index 0000000..6184a42 --- /dev/null +++ b/Dahlquist/FMI1CS.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dahlquist/FMI1ME.xml b/Dahlquist/FMI1ME.xml new file mode 100644 index 0000000..91da018 --- /dev/null +++ b/Dahlquist/FMI1ME.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Dahlquist/FMI2.xml b/Dahlquist/FMI2.xml new file mode 100644 index 0000000..4058249 --- /dev/null +++ b/Dahlquist/FMI2.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dahlquist/FMI3.xml b/Dahlquist/FMI3.xml new file mode 100644 index 0000000..4e57dd3 --- /dev/null +++ b/Dahlquist/FMI3.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dahlquist/config.h b/Dahlquist/config.h new file mode 100644 index 0000000..2b7fada --- /dev/null +++ b/Dahlquist/config.h @@ -0,0 +1,28 @@ +#ifndef config_h +#define config_h + +// define class name and unique id +#define MODEL_IDENTIFIER Dahlquist +#define MODEL_GUID "{8c4e810f-3df3-4a00-8276-176fa3c9f000}" + +// define model size +#define NUMBER_OF_STATES 1 +#define NUMBER_OF_EVENT_INDICATORS 0 + +#define GET_REAL +#define SET_REAL +#define EVENT_UPDATE + +typedef enum { + vr_x, vr_der_x, vr_k +} ValueReference; + +typedef struct { + + double x; + double der_x; + double k; + +} ModelData; + +#endif /* config_h */ diff --git a/Dahlquist/model.c b/Dahlquist/model.c new file mode 100644 index 0000000..f5b1c62 --- /dev/null +++ b/Dahlquist/model.c @@ -0,0 +1,70 @@ +#include "config.h" +#include "model.h" + + +void setStartValues(ModelInstance *comp) { + M(x) = 1; + M(k) = 1; +} + +void calculateValues(ModelInstance *comp) { + M(der_x) = -M(k) * M(x); +} + +Status getReal(ModelInstance* comp, ValueReference vr, double *value) { + calculateValues(comp); + switch (vr) { + case vr_x: + *value = M(x); + return OK; + case vr_der_x: + *value = M(der_x); + return OK; + case vr_k: + *value = M(k); + return OK; + default: + return Error; + } +} + +Status setReal(ModelInstance* comp, ValueReference vr, double value) { + switch (vr) { + case vr_x: + M(x) = value; + return OK; + case vr_k: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInstantiated && + comp->state != modelInitializationMode) { + logError(comp, "Variable k can only be set after instantiation or in initialization mode."); + return Error; + } +#endif + M(k) = value; + return OK; + default: + return Error; + } +} + +void getContinuousStates(ModelInstance *comp, double x[], size_t nx) { + x[0] = M(x); +} + +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) { + M(x) = x[0]; +} + +void getDerivatives(ModelInstance *comp, double dx[], size_t nx) { + calculateValues(comp); + dx[0] = M(der_x); +} + +void eventUpdate(ModelInstance *comp) { + comp->valuesOfContinuousStatesChanged = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} diff --git a/Dahlquist/readme.html b/Dahlquist/readme.html new file mode 100644 index 0000000..6a4f4e5 --- /dev/null +++ b/Dahlquist/readme.html @@ -0,0 +1,89 @@ + + + + +
+

Dahlquist

+ +

The model implements the Dahlquist test equation.

+ +
der(x) = -k * x
+
+ +

whith

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableDescriptionStart
xThe only state1
der(x)The derivative0
kParameter1
+ +

The analytical solution of this system is

+ +
x(t) = exp(-k * t)
+
+ +

The plot shows the reference result computed with FMPy.

+ +

plot

+ +
+ + diff --git a/Dahlquist/readme.md b/Dahlquist/readme.md new file mode 100644 index 0000000..74f130d --- /dev/null +++ b/Dahlquist/readme.md @@ -0,0 +1,25 @@ +# Dahlquist + +The model implements the [Dahlquist](https://en.wikipedia.org/wiki/Germund_Dahlquist) test equation. + +``` +der(x) = -k * x +``` + +whith + +| Variable | Description | Start | +|:--------------|:---------------| -----:| +| x | The only state | 1 | +| der(x) | The derivative | 0 | +| k | Parameter | 1 | + +The analytical solution of this system is + +``` +x(t) = exp(-k * t) +``` + +The plot shows the [reference result](Dahlquist_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). + +![plot](Dahlquist_ref.svg) diff --git a/Feedthrough/FMI1CS.xml b/Feedthrough/FMI1CS.xml new file mode 100644 index 0000000..51ada37 --- /dev/null +++ b/Feedthrough/FMI1CS.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Feedthrough/FMI1ME.xml b/Feedthrough/FMI1ME.xml new file mode 100644 index 0000000..af3fa86 --- /dev/null +++ b/Feedthrough/FMI1ME.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Feedthrough/FMI2.xml b/Feedthrough/FMI2.xml new file mode 100644 index 0000000..81fb24f --- /dev/null +++ b/Feedthrough/FMI2.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Feedthrough/FMI3.xml b/Feedthrough/FMI3.xml new file mode 100644 index 0000000..c2a319a --- /dev/null +++ b/Feedthrough/FMI3.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Feedthrough/Feedthrough_in.csv b/Feedthrough/Feedthrough_in.csv new file mode 100644 index 0000000..a8144f2 --- /dev/null +++ b/Feedthrough/Feedthrough_in.csv @@ -0,0 +1,7 @@ +time,real_tunable_param,real_continuous_in,real_discrete_in,int_in,bool_in +0.0,0,0.0,0,0,0 +0.5,0,0.0,0,0,0 +0.5,0,2.0,0,0,0 +1.0,0,1.0,1,1,1 +1.5,-1,1.0,1,1,1 +2.0,-1,1.0,1,1,1 diff --git a/Feedthrough/Feedthrough_ref.csv b/Feedthrough/Feedthrough_ref.csv new file mode 100644 index 0000000..f15d33a --- /dev/null +++ b/Feedthrough/Feedthrough_ref.csv @@ -0,0 +1,17 @@ +"time","real_continuous_out","real_discrete_out","int_out","bool_out" +0,1,0,0,0 +0.2,1,0,0,0 +0.4,1,0,0,0 +0.5,1,0,0,0 +0.5,3,0,0,0 +0.6,2.8,0,0,0 +0.8,2.4,0,0,0 +1,2,0,0,0 +1,2,1,1,1 +1.2,2,1,1,1 +1.4,2,1,1,1 +1.5,2,1,1,1 +1.5,1,1,1,1 +1.6,1,1,1,1 +1.8,1,1,1,1 +2,1,1,1,1 diff --git a/Feedthrough/Feedthrough_ref.svg b/Feedthrough/Feedthrough_ref.svg new file mode 100644 index 0000000..54be10a --- /dev/null +++ b/Feedthrough/Feedthrough_ref.svg @@ -0,0 +1,1869 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Feedthrough/config.h b/Feedthrough/config.h new file mode 100644 index 0000000..886fa4e --- /dev/null +++ b/Feedthrough/config.h @@ -0,0 +1,49 @@ +#ifndef config_h +#define config_h + +#include // for bool + + +// define class name and unique id +#define MODEL_IDENTIFIER Feedthrough +#define MODEL_GUID "{8c4e810f-3df3-4a00-8276-176fa3c9f004}" + +// define model size +#define NUMBER_OF_STATES 0 +#define NUMBER_OF_EVENT_INDICATORS 0 + +#define GET_REAL +#define GET_INTEGER +#define GET_BOOLEAN + +#define SET_REAL +#define SET_INTEGER +#define SET_BOOLEAN + +#define EVENT_UPDATE + +typedef enum { + vr_fixed_real_parameter, + vr_tunable_real_parameter, + vr_continuous_real_in, + vr_continuous_real_out, + vr_discrete_real_in, + vr_discrete_real_out, + vr_int_in, + vr_int_out, + vr_bool_in, + vr_bool_out, + vr_string, +} ValueReference; + +typedef struct { + double real_fixed_parameter; + double real_tunable_parameter; + double real_continuous_in; + double real_discrete; + int integer; + bool boolean; + const char *string; +} ModelData; + +#endif /* config_h */ diff --git a/Feedthrough/model.c b/Feedthrough/model.c new file mode 100644 index 0000000..06791ce --- /dev/null +++ b/Feedthrough/model.c @@ -0,0 +1,136 @@ +#include "config.h" +#include "model.h" + + +void setStartValues(ModelInstance *comp) { + M(real_fixed_parameter) = 0; + M(real_tunable_parameter) = 0; + M(real_continuous_in) = 0; + M(real_discrete) = 0; + M(integer) = 0; + M(boolean) = false; + M(string) = "a"; +} + +void calculateValues(ModelInstance *comp) { + // do nothing +} + +Status getReal(ModelInstance* comp, ValueReference vr, double *value) { + calculateValues(comp); + switch (vr) { + case vr_continuous_real_in: + *value = M(real_continuous_in); + return OK; + case vr_continuous_real_out: + *value = M(real_fixed_parameter) + M(real_tunable_parameter) + M(real_continuous_in); + return OK; + case vr_discrete_real_in: + case vr_discrete_real_out: + *value = M(real_discrete); + return OK; + case vr_fixed_real_parameter: + *value = M(real_fixed_parameter); + return OK; + case vr_tunable_real_parameter: + *value = M(real_tunable_parameter); + return OK; + default: return Error; + } +} + +Status getInteger(ModelInstance* comp, ValueReference vr, int *value) { + calculateValues(comp); + switch (vr) { + case vr_int_in: + *value = M(integer); + return OK; + case vr_int_out: + *value = M(integer); + return OK; + default: return Error; + } +} + +Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value) { + calculateValues(comp); + switch (vr) { + case vr_bool_in: + *value = M(boolean); + return OK; + case vr_bool_out: + *value = M(boolean); + return OK; + default: return Error; + } +} + +Status setReal(ModelInstance* comp, ValueReference vr, double value) { + switch (vr) { + + case vr_fixed_real_parameter: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInstantiated && + comp->state != modelInitializationMode) { + logError(comp, "Variable fixed_real_parameter can only be set after instantiation or in initialization mode."); + return Error; + } +#endif + M(real_fixed_parameter) = value; + return OK; + + case vr_tunable_real_parameter: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInstantiated && + comp->state != modelInitializationMode && + comp->state != modelEventMode) { + logError(comp, "Variable tunable_real_parameter can only be set after instantiation, in initialization mode or event mode."); + return Error; + } +#endif + M(real_tunable_parameter) = value; + return OK; + + case vr_continuous_real_in: + M(real_continuous_in) = value; + return OK; + + case vr_discrete_real_in: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInitializationMode && + comp->state != modelEventMode) { + logError(comp, "Variable real_in can only be set in initialization mode or event mode."); + return Error; + } +#endif + M(real_discrete) = value; + return OK; + + default: + return Error; + } +} + +Status setInteger(ModelInstance* comp, ValueReference vr, int value) { + switch (vr) { + case vr_int_in: M(integer) = value; return OK; + default: return Error; + } +} + +Status setBoolean(ModelInstance* comp, ValueReference vr, bool value) { + switch (vr) { + case vr_bool_in: M(boolean) = value; return OK; + default: return Error; + } +} + +void eventUpdate(ModelInstance *comp) { + comp->valuesOfContinuousStatesChanged = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} diff --git a/Feedthrough/readme.html b/Feedthrough/readme.html new file mode 100644 index 0000000..de74876 --- /dev/null +++ b/Feedthrough/readme.html @@ -0,0 +1,50 @@ + + + + +
+

Feedthrough

+ +

The plot shows the reference result computed with FMPy.

+ +

Plot

+ +
+ + diff --git a/Feedthrough/readme.md b/Feedthrough/readme.md new file mode 100644 index 0000000..c4d5368 --- /dev/null +++ b/Feedthrough/readme.md @@ -0,0 +1,7 @@ +# Feedthrough + + + +The plot shows the [reference result](Feedthrough_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). + +![Plot](Feedthrough_ref.svg) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..784c6d6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,32 @@ +Copyright (c) 2019 Dassault Systemes. All rights reserved. + +The Test FMUs are released under the 2-Clause BSD license: + +-------------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDi +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- + +The Test FMUs are a fork of the FMU SDK (https://github.com/qtronic/fmusdk) by +QTronic, released under the 2-Clause BSD License. + +The FMI header files are copyright (c) 2008-2011 MODELISAR consortium, 2012-2018 +the Modelica Association Project "FMI" and released under the 2-Clause BSD License. diff --git a/README.md b/README.md index ef6e308..8923f7b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,64 @@ -# Test-FMUs -A set of FMUs for development, testing and debugging +

+ Test FMUs logo +

+ +# Test FMUs + +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 +- [Dahlquist](Dahlquist) - Dahlquist test equation +- [Feedthrough](Feedthrough) - all variable types +- [Resource](Resource) - load data from a file +- [Stair](Stair) - a counter with time events +- [VanDerPol](VanDerPol) - Van der Pol test equation + +## Repository structure + +`` +- `config.h` - model specific types and definitions +- `FMI*.xml` - model descriptions +- `model.c` - implementation of the model + +`include` +- `fmi*.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 +- `slave.c` - generic co-simulation + +## Build the FMUs + +To build the FMUs you need [CMake](https://cmake.org/) and a supported [build tool](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) e.g. Visual Studio, Xcode or make: + +- download or clone the repository + +- open the [CMakeGUI](https://cmake.org/runningcmake/) + +- click `Browse Source...` and select the cloned or downloaded and extracted repository (that contains `CMakeLists.txt`) + +- click `Browse Build...` and select the folder where you want build the FMUs + +- click `Configure` and select the generator for your IDE / build tool + +- select the `FMI_VERSION` you want to build and optionally the `FMI_TYPE` (only for FMI 1.0) + +- click `Generate` to generate the project files + +- click `Open Project` or open the project in your build tool + +- build the project + +The FMUs will be in the `dist` folder inside the selected build folder. + +## License and Attribution + +Copyright © 2019 Dassault Systemes. +All rights reserved. +The code is released under the [2-Clause BSD License](LICENSE.txt). +The Test FMUs are forked from the [FMU SDK](https://github.com/qtronic/fmusdk) by QTronic. +The stethoscope icon in the logo by [srip](https://www.flaticon.com/authors/srip) is licensed [CC-BY 3.0](http://creativecommons.org/licenses/by/3.0/). diff --git a/Resource/FMI1CS.xml b/Resource/FMI1CS.xml new file mode 100644 index 0000000..1dbba64 --- /dev/null +++ b/Resource/FMI1CS.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Resource/FMI1ME.xml b/Resource/FMI1ME.xml new file mode 100644 index 0000000..cfd4092 --- /dev/null +++ b/Resource/FMI1ME.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Resource/FMI2.xml b/Resource/FMI2.xml new file mode 100644 index 0000000..d495fe6 --- /dev/null +++ b/Resource/FMI2.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resource/FMI3.xml b/Resource/FMI3.xml new file mode 100644 index 0000000..6a54b14 --- /dev/null +++ b/Resource/FMI3.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resource/Resource_ref.csv b/Resource/Resource_ref.csv new file mode 100644 index 0000000..1ee31cd --- /dev/null +++ b/Resource/Resource_ref.csv @@ -0,0 +1,7 @@ +"time","y" +0,97 +0.2,97 +0.4,97 +0.6,97 +0.8,97 +1,97 diff --git a/Resource/Resource_ref.svg b/Resource/Resource_ref.svg new file mode 100644 index 0000000..4cce059 --- /dev/null +++ b/Resource/Resource_ref.svg @@ -0,0 +1,517 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resource/config.h b/Resource/config.h new file mode 100644 index 0000000..4c43038 --- /dev/null +++ b/Resource/config.h @@ -0,0 +1,22 @@ +#ifndef config_h +#define config_h + +// define class name and unique id +#define MODEL_IDENTIFIER Resource +#define MODEL_GUID "{7b9c2114-2ce5-4076-a138-2cbc69e069e5}" + +// define model size +#define NUMBER_OF_STATES 0 +#define NUMBER_OF_EVENT_INDICATORS 0 + +#define GET_REAL + +typedef enum { + vr_y +} ValueReference; + +typedef struct { + double y; +} ModelData; + +#endif /* config_h */ diff --git a/Resource/model.c b/Resource/model.c new file mode 100644 index 0000000..02a9a94 --- /dev/null +++ b/Resource/model.c @@ -0,0 +1,83 @@ +#include "config.h" +#include "model.h" + +#include +#include +#include + +void setStartValues(ModelInstance *comp) { + M(y) = 0; +} + +void calculateValues(ModelInstance *comp) { + // load the file + + FILE *file; + char *path; + char c; + const char *scheme1 = "file:///"; + const char *scheme2 = "file:/"; +#if FMI_VERSION < 2 + char *resourcePath = "/resources/y.txt"; +#else + char *resourcePath = "/y.txt"; +#endif + + if (!comp->resourceLocation) { + // FMI 1.0 for Model Exchange doesn't have a resource location + return; + } + + 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 { + logError(comp, "The resourceLocation must start with \"file:/\" or \"file:///\""); + return; + } + +#ifdef _WIN32 + // strip any leading slashes + while (path[0] == '/') { + strcpy(path, &path[1]); + } +#endif + + // open the resource file + file = fopen (path, "r"); + + if (!file) { + logError(comp, "Failed to open resource file %s.", path); + return; + } + + // read the first character + c = fgetc(file); + + // assign it to y + comp->modelData->y = c; + + // clost the file + fclose(file); +} + +Status getReal(ModelInstance* comp, ValueReference vr, double *value) { + switch (vr) { + case vr_y: + *value = M(y); + return OK; + default: + return Error; + } +} + +void eventUpdate(ModelInstance *comp) { + comp->valuesOfContinuousStatesChanged = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} diff --git a/Resource/readme.html b/Resource/readme.html new file mode 100644 index 0000000..9a695d7 --- /dev/null +++ b/Resource/readme.html @@ -0,0 +1,52 @@ + + + + +
+

Resource

+ +

Test model reads the first character from resources/y.txt during initialization and applies its integer value to y.

+ +

The plot shows the reference result computed with FMPy.

+ +

Plot

+ +
+ + diff --git a/Resource/readme.md b/Resource/readme.md new file mode 100644 index 0000000..f469d90 --- /dev/null +++ b/Resource/readme.md @@ -0,0 +1,7 @@ +# Resource + +Test model reads the first character from `resources/y.txt` during initialization and applies its integer value to `y`. + +The plot shows the [reference result](Resource_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). + +![Plot](Resource_ref.svg) diff --git a/Resource/resources/y.txt b/Resource/resources/y.txt new file mode 100644 index 0000000..a28397e --- /dev/null +++ b/Resource/resources/y.txt @@ -0,0 +1 @@ +a <- the value of this character (97) will be assigned to variable "y" diff --git a/Stair/FMI1CS.xml b/Stair/FMI1CS.xml new file mode 100644 index 0000000..f451379 --- /dev/null +++ b/Stair/FMI1CS.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Stair/FMI1ME.xml b/Stair/FMI1ME.xml new file mode 100644 index 0000000..484bc1e --- /dev/null +++ b/Stair/FMI1ME.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Stair/FMI2.xml b/Stair/FMI2.xml new file mode 100644 index 0000000..13afed4 --- /dev/null +++ b/Stair/FMI2.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Stair/FMI3.xml b/Stair/FMI3.xml new file mode 100644 index 0000000..d72be8c --- /dev/null +++ b/Stair/FMI3.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Stair/Stair_ref.csv b/Stair/Stair_ref.csv new file mode 100644 index 0000000..0a2dfeb --- /dev/null +++ b/Stair/Stair_ref.csv @@ -0,0 +1,22 @@ +"time","counter" +0,1 +1,1 +1,2 +2,2 +2,3 +3,3 +3,4 +4,4 +4,5 +5,5 +5,6 +6,6 +6,7 +7,7 +7,8 +8,8 +8,9 +9,9 +9,10 +10,10 +10,11 diff --git a/Stair/Stair_ref.svg b/Stair/Stair_ref.svg new file mode 100644 index 0000000..74015cf --- /dev/null +++ b/Stair/Stair_ref.svg @@ -0,0 +1,696 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Stair/config.h b/Stair/config.h new file mode 100644 index 0000000..3af04de --- /dev/null +++ b/Stair/config.h @@ -0,0 +1,25 @@ +#ifndef config_h +#define config_h + +// define class name and unique id +#define MODEL_IDENTIFIER Stair +#define MODEL_GUID "{8c4e810f-3df3-4a00-8276-176fa3c9f008}" + +// define model size +#define NUMBER_OF_STATES 0 +#define NUMBER_OF_EVENT_INDICATORS 0 + +#define GET_INTEGER +#define EVENT_UPDATE + +typedef enum { + vr_counter +} ValueReference; + +typedef struct { + + double counter; + +} ModelData; + +#endif /* config_h */ diff --git a/Stair/model.c b/Stair/model.c new file mode 100644 index 0000000..813f8f8 --- /dev/null +++ b/Stair/model.c @@ -0,0 +1,35 @@ +#include "config.h" +#include "model.h" + + +void setStartValues(ModelInstance *comp) { + M(counter) = 1; + + // TODO: move this to initialize()? + comp->nextEventTime = 1; + comp->nextEventTimeDefined = true; +} + +void calculateValues(ModelInstance *comp) { + // do nothing +} + +Status getInteger(ModelInstance* comp, ValueReference vr, int *value) { + switch (vr) { + case vr_counter: *value = M(counter); return OK; + default: return Error; + } +} + +void eventUpdate(ModelInstance *comp) { + + if (comp->nextEventTimeDefined && comp->nextEventTime == comp->time) { + M(counter)++; + comp->nextEventTime += 1; + } + + comp->valuesOfContinuousStatesChanged = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = true; +} diff --git a/Stair/readme.html b/Stair/readme.html new file mode 100644 index 0000000..7df8530 --- /dev/null +++ b/Stair/readme.html @@ -0,0 +1,52 @@ + + + + +
+

Stair

+ +

The model generates time events every second and increments the variable counter.

+ +

The plot shows the reference result computed with FMPy.

+ +

Plot

+ +
+ + diff --git a/Stair/readme.md b/Stair/readme.md new file mode 100644 index 0000000..f333ec9 --- /dev/null +++ b/Stair/readme.md @@ -0,0 +1,7 @@ +# Stair + +The model generates time events every second and increments the variable `counter`. + +The plot shows the [reference result](Stair_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). + +![Plot](Stair_ref.svg) diff --git a/VanDerPol/FMI1CS.xml b/VanDerPol/FMI1CS.xml new file mode 100644 index 0000000..c316805 --- /dev/null +++ b/VanDerPol/FMI1CS.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VanDerPol/FMI1ME.xml b/VanDerPol/FMI1ME.xml new file mode 100644 index 0000000..4cfc35c --- /dev/null +++ b/VanDerPol/FMI1ME.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VanDerPol/FMI2.xml b/VanDerPol/FMI2.xml new file mode 100644 index 0000000..4fb5005 --- /dev/null +++ b/VanDerPol/FMI2.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VanDerPol/FMI3.xml b/VanDerPol/FMI3.xml new file mode 100644 index 0000000..5ee6162 --- /dev/null +++ b/VanDerPol/FMI3.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VanDerPol/VanDerPol_ref.csv b/VanDerPol/VanDerPol_ref.csv new file mode 100644 index 0000000..ff7f7e5 --- /dev/null +++ b/VanDerPol/VanDerPol_ref.csv @@ -0,0 +1,202 @@ +"time","x0","x1" +0,2,0 +0.1,1.99095,-0.17272 +0.2,1.96695,-0.300738 +0.3,1.93182,-0.397361 +0.4,1.88816,-0.472789 +0.5,1.8377,-0.534452 +0.6,1.78153,-0.587677 +0.7,1.7203,-0.636305 +0.8,1.65432,-0.683178 +0.9,1.58364,-0.730513 +1,1.50813,-0.78017 +1.1,1.42748,-0.833837 +1.2,1.34118,-0.893187 +1.3,1.24859,-0.960008 +1.4,1.14886,-1.0363 +1.5,1.04092,-1.12433 +1.6,0.923491,-1.22665 +1.7,0.794997,-1.34607 +1.8,0.653594,-1.48549 +1.9,0.497145,-1.64747 +2,0.323332,-1.83278 +2.1,0.129925,-2.03845 +2.2,-0.084689,-2.25462 +2.3,-0.320607,-2.45981 +2.4,-0.575053,-2.61731 +2.5,-0.840844,-2.67766 +2.6,-1.10575,-2.59267 +2.7,-1.35382,-2.34103 +2.8,-1.56925,-1.94895 +2.9,-1.74115,-1.48353 +3,-1.86608,-1.02119 +3.1,-1.94732,-0.616063 +3.2,-1.99196,-0.290304 +3.3,-2.00798,-0.0420389 +3.4,-2.00251,0.142124 +3.5,-1.98116,0.278079 +3.6,-1.94803,0.379879 +3.7,-1.90596,0.458493 +3.8,-1.85686,0.521962 +3.9,-1.80191,0.576002 +4,-1.74185,0.624755 +4.1,-1.67705,0.6712 +4.2,-1.60762,0.717633 +4.3,-1.53347,0.765958 +4.4,-1.45431,0.817867 +4.5,-1.36972,0.875007 +4.6,-1.27908,0.939097 +4.7,-1.18161,1.01204 +4.8,-1.0763,1.096 +4.9,-0.961954,1.19344 +5,-0.83707,1.30715 +5.1,-0.699882,1.44005 +5.2,-0.548334,1.59477 +5.3,-0.380156,1.77284 +5.4,-0.19304,1.97286 +5.5,0.0148975,2.18746 +5.6,0.244348,2.39927 +5.7,0.493582,2.5766 +5.8,0.75695,2.67315 +5.9,1.02379,2.63788 +6,1.27901,2.43813 +6.1,1.50624,2.08412 +6.2,1.69259,1.6328 +6.3,1.83217,1.16183 +6.4,1.92644,0.734745 +6.5,1.98166,0.383436 +6.6,2.00579,0.112064 +6.7,2.00637,-0.090404 +6.8,1.98948,-0.239785 +6.9,1.95968,-0.35094 +7,1.92018,-0.435819 +7.1,1.87313,-0.503293 +7.2,1.81991,-0.559766 +7.3,1.7614,-0.609778 +7.4,1.69806,-0.656633 +7.5,1.6301,-0.702823 +7.6,1.55746,-0.750346 +7.7,1.47993,-0.800937 +7.8,1.39711,-0.856242 +7.9,1.30846,-0.917946 +8,1.21325,-0.987872 +8.1,1.11055,-1.06809 +8.2,0.999208,-1.16097 +8.3,0.877838,-1.26922 +8.4,0.744757,-1.39573 +8.5,0.597994,-1.54331 +8.6,0.435334,-1.71396 +8.7,0.254458,-1.90744 +8.8,0.0532638,-2.11876 +8.9,-0.169431,-2.33415 +9,-0.412812,-2.5268 +9.1,-0.672635,-2.6546 +9.2,-0.939849,-2.66596 +9.3,-1.20054,-2.51948 +9.4,-1.43827,-2.20995 +9.5,-1.63852,-1.78122 +9.6,-1.79303,-1.30849 +9.7,-1.90113,-0.862718 +9.8,-1.9679,-0.48598 +9.9,-2.00104,-0.189975 +10,-2.00835,0.0327633 +10.1,-1.99643,0.197292 +10.2,-1.97032,0.319131 +10.3,-1.9336,0.411224 +10.4,-1.88873,0.483397 +10.5,-1.83734,0.542787 +10.6,-1.78042,0.594437 +10.7,-1.71858,0.641968 +10.8,-1.65207,0.688101 +10.9,-1.58093,0.734988 +11,-1.50499,0.784428 +11.1,-1.4239,0.838063 +11.2,-1.33718,0.897537 +11.3,-1.24413,0.964622 +11.4,-1.14391,1.04132 +11.5,-1.03546,1.12988 +11.6,-0.917445,1.23291 +11.7,-0.788293,1.35327 +11.8,-0.646127,1.49381 +11.9,-0.488787,1.657 +12,-0.313958,1.84348 +12.1,-0.119434,2.05004 +12.2,0.0963495,2.26624 +12.3,0.33337,2.46992 +12.4,0.588661,2.62368 +12.5,0.854792,2.67764 +12.6,1.11929,2.58431 +12.7,1.36609,2.32415 +12.8,1.5795,1.92611 +12.9,1.74899,1.45891 +13,1.87153,0.998367 +13.1,1.95067,0.597036 +13.2,1.99362,0.275481 +13.3,2.00835,0.0309306 +13.4,2.00192,-0.150329 +13.5,1.97986,-0.284169 +13.6,1.9462,-0.384501 +13.7,1.90372,-0.46213 +13.8,1.85429,-0.524963 +13.9,1.79906,-0.578616 +14,1.73875,-0.62717 +14.1,1.67371,-0.673552 +14.2,1.60404,-0.720034 +14.3,1.52964,-0.768496 +14.4,1.45023,-0.820624 +14.5,1.36534,-0.878077 +14.6,1.27437,-0.942581 +14.7,1.17652,-1.01604 +14.8,1.07079,-1.10062 +14.9,0.955942,-1.1988 +15,0.830481,-1.31338 +15.1,0.692624,-1.44728 +15.2,0.540298,-1.60316 +15.3,0.371221,-1.78241 +15.4,0.183107,-1.98334 +15.5,-0.0258924,-2.19829 +15.6,-0.256386,-2.40926 +15.7,-0.506499,-2.58385 +15.8,-0.770365,-2.67495 +15.9,-1.03702,-2.63197 +16,-1.29123,-2.42373 +16.1,-1.51666,-2.06298 +16.2,-1.7007,-1.60896 +16.3,-1.83793,-1.13907 +16.4,-1.93009,-0.715353 +16.5,-1.98358,-0.368069 +16.6,-2.00638,-0.100418 +16.7,-2.00594,0.0990613 +16.8,-1.98831,0.246208 +16.9,-1.95795,0.355781 +17,-1.91801,0.439582 +17.1,-1.87061,0.506375 +17.2,-1.81712,0.562424 +17.3,-1.75836,0.612193 +17.4,-1.6948,0.658976 +17.5,-1.6266,0.70521 +17.6,-1.55372,0.752861 +17.7,-1.47592,0.803654 +17.8,-1.39283,0.859235 +17.9,-1.30386,0.921296 +18,-1.20829,0.991683 +18.1,-1.10517,1.07248 +18.2,-0.993359,1.16609 +18.3,-0.871432,1.27517 +18.4,-0.737704,1.40265 +18.5,-0.590197,1.55132 +18.6,-0.426675,1.72316 +18.7,-0.244815,1.91773 +18.8,-0.0425616,2.12963 +18.9,0.181195,2.34463 +19,0.425527,2.53522 +19.1,0.685983,2.6584 +19.2,0.953244,2.66265 +19.3,1.21319,2.50771 +19.4,1.44935,2.19071 +19.5,1.64745,1.75798 +19.6,1.7996,1.28509 +19.7,1.90548,0.841929 +19.8,1.97037,0.469058 +19.9,2.00201,0.177006 +20,2.00821,-0.0424046 diff --git a/VanDerPol/VanDerPol_ref.svg b/VanDerPol/VanDerPol_ref.svg new file mode 100644 index 0000000..22deacb --- /dev/null +++ b/VanDerPol/VanDerPol_ref.svg @@ -0,0 +1,1018 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VanDerPol/config.h b/VanDerPol/config.h new file mode 100644 index 0000000..1c02abe --- /dev/null +++ b/VanDerPol/config.h @@ -0,0 +1,29 @@ +#ifndef config_h +#define config_h + +// define class name and unique id +#define MODEL_IDENTIFIER VanDerPol +#define MODEL_GUID "{8c4e810f-3da3-4a00-8276-176fa3c9f000}" + +// define model size +#define NUMBER_OF_STATES 2 +#define NUMBER_OF_EVENT_INDICATORS 0 + +#define GET_REAL +#define SET_REAL + +typedef enum { + vr_x0, vr_der_x0, vr_x1, vr_der_x1, vr_mu +} ValueReference; + +typedef struct { + + double x0; + double der_x0; + double x1; + double der_x1; + double mu; + +} ModelData; + +#endif /* config_h */ diff --git a/VanDerPol/model.c b/VanDerPol/model.c new file mode 100644 index 0000000..8557d5f --- /dev/null +++ b/VanDerPol/model.c @@ -0,0 +1,86 @@ +#include "config.h" +#include "model.h" + + +void setStartValues(ModelInstance *comp) { + M(x0) = 2; + M(x1) = 0; + M(mu) = 1; +} + +void calculateValues(ModelInstance *comp) { + M(der_x0) = M(x1); + M(der_x1) = M(mu) * ((1.0 - M(x0) * M(x0)) * M(x1)) - M(x0); +} + +Status getReal(ModelInstance* comp, ValueReference vr, double *value) { + calculateValues(comp); + switch (vr) { + case vr_x0: + *value = M(x0); + return OK; + case vr_der_x0 : + *value = M(der_x0); + return OK; + case vr_x1: + *value = M(x1); + return OK; + case vr_der_x1: + *value = M(der_x1); + return OK; + case vr_mu: + *value = M(mu); + return OK; + default: + return Error; + } +} + +Status setReal(ModelInstance* comp, ValueReference vr, double value) { + switch (vr) { + case vr_x0: + M(x0 = value); + return OK; + case vr_x1: + M(x1 = value); + return OK; + case vr_mu: +#if FMI_VERSION > 1 + if (comp->type == ModelExchange && + comp->state != modelInstantiated && + comp->state != modelInitializationMode && + comp->state != modelEventMode) { + logError(comp, "Variable mu can only be set after instantiation, in initialization mode or event mode."); + return Error; + } +#endif + M(mu = value); + return OK; + default: + return Error; + } +} + +void getContinuousStates(ModelInstance *comp, double x[], size_t nx) { + x[0] = M(x0); + x[1] = M(x1); +} + +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) { + M(x0) = x[0]; + M(x1) = x[1]; + calculateValues(comp); +} + +void getDerivatives(ModelInstance *comp, double dx[], size_t nx) { + calculateValues(comp); + dx[0] = M(der_x0); + dx[1] = M(der_x1); +} + +void eventUpdate(ModelInstance *comp) { + comp->valuesOfContinuousStatesChanged = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} diff --git a/VanDerPol/readme.html b/VanDerPol/readme.html new file mode 100644 index 0000000..d4a1e06 --- /dev/null +++ b/VanDerPol/readme.html @@ -0,0 +1,85 @@ + + + + +
+

VanDerPol

+ +

The model implements the Van der Pol oscillator.

+ +
der(x0) = x1
+der(x1) = mu * ((1 - x0 * x0) * x1) - x0
+
+ +

whith

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableDescriptionStart
xThe only state1
der(x)The derivative0
kParameter1
+ +

The plot shows the reference result computed with FMPy.

+ +

plot

+ +
+ + diff --git a/VanDerPol/readme.md b/VanDerPol/readme.md new file mode 100644 index 0000000..b6e3bb8 --- /dev/null +++ b/VanDerPol/readme.md @@ -0,0 +1,20 @@ +# VanDerPol + +The model implements the [Van der Pol oscillator](https://en.wikipedia.org/wiki/Van_der_Pol_oscillator). + +``` +der(x0) = x1 +der(x1) = mu * ((1 - x0 * x0) * x1) - x0 +``` + +whith + +| Variable | Description | Start | +|:--------------|:---------------| -----:| +| x | The only state | 1 | +| der(x) | The derivative | 0 | +| k | Parameter | 1 | + +The plot shows the [reference result](VanDerPol_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). + +![plot](VanDerPol_ref.svg) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..73cba9d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,9 @@ +image: Visual Studio 2015 + +build: false + +install: + - pip install fmpy + +test_script: + - python test_build.py diff --git a/include/fmi2FunctionTypes.h b/include/fmi2FunctionTypes.h new file mode 100644 index 0000000..348c76e --- /dev/null +++ b/include/fmi2FunctionTypes.h @@ -0,0 +1,243 @@ +#ifndef fmi2FunctionTypes_h +#define fmi2FunctionTypes_h + +#include "fmi2TypesPlatform.h" + +/* This header file must be utilized when compiling an FMU or an FMI master. + It declares data and function types for FMI 2.0 + + Revisions: + - Apr. 9, 2014: all prefixes "fmi" renamed to "fmi2" (decision from April 8) + - Apr. 3, 2014: Added #include for size_t definition + - Mar. 27, 2014: Added #include "fmiTypesPlatform.h" (#179) + - Mar. 26, 2014: Introduced function argument "void" for the functions (#171) + fmiGetTypesPlatformTYPE and fmiGetVersionTYPE + - Oct. 11, 2013: Functions of ModelExchange and CoSimulation merged: + fmiInstantiateModelTYPE , fmiInstantiateSlaveTYPE -> fmiInstantiateTYPE + fmiFreeModelInstanceTYPE, fmiFreeSlaveInstanceTYPE -> fmiFreeInstanceTYPE + fmiEnterModelInitializationModeTYPE, fmiEnterSlaveInitializationModeTYPE -> fmiEnterInitializationModeTYPE + fmiExitModelInitializationModeTYPE , fmiExitSlaveInitializationModeTYPE -> fmiExitInitializationModeTYPE + fmiTerminateModelTYPE , fmiTerminateSlaveTYPE -> fmiTerminate + fmiResetSlave -> fmiReset (now also for ModelExchange and not only for CoSimulation) + Functions renamed + fmiUpdateDiscreteStatesTYPE -> fmiNewDiscreteStatesTYPE + Renamed elements of the enumeration fmiEventInfo + upcomingTimeEvent -> nextEventTimeDefined // due to generic naming scheme: varDefined + var + newUpdateDiscreteStatesNeeded -> newDiscreteStatesNeeded; + - June 13, 2013: Changed type fmiEventInfo + Functions removed: + fmiInitializeModelTYPE + fmiEventUpdateTYPE + fmiCompletedEventIterationTYPE + fmiInitializeSlaveTYPE + Functions added: + fmiEnterModelInitializationModeTYPE + fmiExitModelInitializationModeTYPE + fmiEnterEventModeTYPE + fmiUpdateDiscreteStatesTYPE + fmiEnterContinuousTimeModeTYPE + fmiEnterSlaveInitializationModeTYPE; + fmiExitSlaveInitializationModeTYPE; + - Feb. 17, 2013: Added third argument to fmiCompletedIntegratorStepTYPE + Changed function name "fmiTerminateType" to "fmiTerminateModelType" (due to #113) + Changed function name "fmiGetNominalContinuousStateTYPE" to + "fmiGetNominalsOfContinuousStatesTYPE" + Removed fmiGetStateValueReferencesTYPE. + - Nov. 14, 2011: First public Version + + + Copyright © 2011 MODELISAR consortium, + 2012-2013 Modelica Association Project "FMI" + All rights reserved. + This file is licensed by the copyright holders under the BSD 2-Clause License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. + (Note, this means that if you distribute a modified file, + the modified file must also be provided under this license). +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* make sure all compiler use the same alignment policies for structures */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(push,8) +#endif + +/* Include stddef.h, in order that size_t etc. is defined */ +#include + + +/* Type definitions */ +typedef enum { + fmi2OK, + fmi2Warning, + fmi2Discard, + fmi2Error, + fmi2Fatal, + fmi2Pending +} fmi2Status; + +typedef enum { + fmi2ModelExchange, + fmi2CoSimulation +} fmi2Type; + +typedef enum { + fmi2DoStepStatus, + fmi2PendingStatus, + fmi2LastSuccessfulTime, + fmi2Terminated +} fmi2StatusKind; + +typedef void (*fmi2CallbackLogger) (fmi2ComponentEnvironment, fmi2String, fmi2Status, fmi2String, fmi2String, ...); +typedef void* (*fmi2CallbackAllocateMemory)(size_t, size_t); +typedef void (*fmi2CallbackFreeMemory) (void*); +typedef void (*fmi2StepFinished) (fmi2ComponentEnvironment, fmi2Status); + +typedef struct { + const fmi2CallbackLogger logger; + const fmi2CallbackAllocateMemory allocateMemory; + const fmi2CallbackFreeMemory freeMemory; + const fmi2StepFinished stepFinished; + const fmi2ComponentEnvironment componentEnvironment; +} fmi2CallbackFunctions; + +typedef struct { + fmi2Boolean newDiscreteStatesNeeded; + fmi2Boolean terminateSimulation; + fmi2Boolean nominalsOfContinuousStatesChanged; + fmi2Boolean valuesOfContinuousStatesChanged; + fmi2Boolean nextEventTimeDefined; + fmi2Real nextEventTime; +} fmi2EventInfo; + + +/* reset alignment policy to the one set before reading this file */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(pop) +#endif + + +/* Define fmi2 function pointer types to simplify dynamic loading */ + +/*************************************************** +Types for Common Functions +****************************************************/ + +/* Inquire version numbers of header files and setting logging status */ + typedef const char* fmi2GetTypesPlatformTYPE(void); + typedef const char* fmi2GetVersionTYPE(void); + typedef fmi2Status fmi2SetDebugLoggingTYPE(fmi2Component, fmi2Boolean, size_t, const fmi2String[]); + +/* Creation and destruction of FMU instances and setting debug status */ + typedef fmi2Component fmi2InstantiateTYPE (fmi2String, fmi2Type, fmi2String, fmi2String, const fmi2CallbackFunctions*, fmi2Boolean, fmi2Boolean); + typedef void fmi2FreeInstanceTYPE(fmi2Component); + +/* Enter and exit initialization mode, terminate and reset */ + typedef fmi2Status fmi2SetupExperimentTYPE (fmi2Component, fmi2Boolean, fmi2Real, fmi2Real, fmi2Boolean, fmi2Real); + typedef fmi2Status fmi2EnterInitializationModeTYPE(fmi2Component); + typedef fmi2Status fmi2ExitInitializationModeTYPE (fmi2Component); + typedef fmi2Status fmi2TerminateTYPE (fmi2Component); + typedef fmi2Status fmi2ResetTYPE (fmi2Component); + +/* Getting and setting variable values */ + typedef fmi2Status fmi2GetRealTYPE (fmi2Component, const fmi2ValueReference[], size_t, fmi2Real []); + typedef fmi2Status fmi2GetIntegerTYPE(fmi2Component, const fmi2ValueReference[], size_t, fmi2Integer[]); + typedef fmi2Status fmi2GetBooleanTYPE(fmi2Component, const fmi2ValueReference[], size_t, fmi2Boolean[]); + typedef fmi2Status fmi2GetStringTYPE (fmi2Component, const fmi2ValueReference[], size_t, fmi2String []); + + typedef fmi2Status fmi2SetRealTYPE (fmi2Component, const fmi2ValueReference[], size_t, const fmi2Real []); + typedef fmi2Status fmi2SetIntegerTYPE(fmi2Component, const fmi2ValueReference[], size_t, const fmi2Integer[]); + typedef fmi2Status fmi2SetBooleanTYPE(fmi2Component, const fmi2ValueReference[], size_t, const fmi2Boolean[]); + typedef fmi2Status fmi2SetStringTYPE (fmi2Component, const fmi2ValueReference[], size_t, const fmi2String []); + +/* Getting and setting the internal FMU state */ + typedef fmi2Status fmi2GetFMUstateTYPE (fmi2Component, fmi2FMUstate*); + typedef fmi2Status fmi2SetFMUstateTYPE (fmi2Component, fmi2FMUstate); + typedef fmi2Status fmi2FreeFMUstateTYPE (fmi2Component, fmi2FMUstate*); + typedef fmi2Status fmi2SerializedFMUstateSizeTYPE(fmi2Component, fmi2FMUstate, size_t*); + typedef fmi2Status fmi2SerializeFMUstateTYPE (fmi2Component, fmi2FMUstate, fmi2Byte[], size_t); + typedef fmi2Status fmi2DeSerializeFMUstateTYPE (fmi2Component, const fmi2Byte[], size_t, fmi2FMUstate*); + +/* Getting partial derivatives */ + typedef fmi2Status fmi2GetDirectionalDerivativeTYPE(fmi2Component, const fmi2ValueReference[], size_t, + const fmi2ValueReference[], size_t, + const fmi2Real[], fmi2Real[]); + +/*************************************************** +Types for Functions for FMI2 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ + typedef fmi2Status fmi2EnterEventModeTYPE (fmi2Component); + typedef fmi2Status fmi2NewDiscreteStatesTYPE (fmi2Component, fmi2EventInfo*); + typedef fmi2Status fmi2EnterContinuousTimeModeTYPE(fmi2Component); + typedef fmi2Status fmi2CompletedIntegratorStepTYPE(fmi2Component, fmi2Boolean, fmi2Boolean*, fmi2Boolean*); + +/* Providing independent variables and re-initialization of caching */ + typedef fmi2Status fmi2SetTimeTYPE (fmi2Component, fmi2Real); + typedef fmi2Status fmi2SetContinuousStatesTYPE(fmi2Component, const fmi2Real[], size_t); + +/* Evaluation of the model equations */ + typedef fmi2Status fmi2GetDerivativesTYPE (fmi2Component, fmi2Real[], size_t); + typedef fmi2Status fmi2GetEventIndicatorsTYPE (fmi2Component, fmi2Real[], size_t); + typedef fmi2Status fmi2GetContinuousStatesTYPE (fmi2Component, fmi2Real[], size_t); + typedef fmi2Status fmi2GetNominalsOfContinuousStatesTYPE(fmi2Component, fmi2Real[], size_t); + + +/*************************************************** +Types for Functions for FMI2 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ + typedef fmi2Status fmi2SetRealInputDerivativesTYPE (fmi2Component, const fmi2ValueReference [], size_t, const fmi2Integer [], const fmi2Real []); + typedef fmi2Status fmi2GetRealOutputDerivativesTYPE(fmi2Component, const fmi2ValueReference [], size_t, const fmi2Integer [], fmi2Real []); + + typedef fmi2Status fmi2DoStepTYPE (fmi2Component, fmi2Real, fmi2Real, fmi2Boolean); + typedef fmi2Status fmi2CancelStepTYPE (fmi2Component); + +/* Inquire slave status */ + typedef fmi2Status fmi2GetStatusTYPE (fmi2Component, const fmi2StatusKind, fmi2Status* ); + typedef fmi2Status fmi2GetRealStatusTYPE (fmi2Component, const fmi2StatusKind, fmi2Real* ); + typedef fmi2Status fmi2GetIntegerStatusTYPE(fmi2Component, const fmi2StatusKind, fmi2Integer*); + typedef fmi2Status fmi2GetBooleanStatusTYPE(fmi2Component, const fmi2StatusKind, fmi2Boolean*); + typedef fmi2Status fmi2GetStringStatusTYPE (fmi2Component, const fmi2StatusKind, fmi2String* ); + + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi2FunctionTypes_h */ diff --git a/include/fmi2Functions.h b/include/fmi2Functions.h new file mode 100644 index 0000000..a23697f --- /dev/null +++ b/include/fmi2Functions.h @@ -0,0 +1,333 @@ +#ifndef fmi2Functions_h +#define fmi2Functions_h + +/* This header file must be utilized when compiling a FMU. + It defines all functions of the + FMI 2.0 Model Exchange and Co-Simulation Interface. + + In order to have unique function names even if several FMUs + are compiled together (e.g. for embedded systems), every "real" function name + is constructed by prepending the function name by "FMI2_FUNCTION_PREFIX". + Therefore, the typical usage is: + + #define FMI2_FUNCTION_PREFIX MyModel_ + #include "fmi2Functions.h" + + As a result, a function that is defined as "fmi2GetDerivatives" in this header file, + is actually getting the name "MyModel_fmi2GetDerivatives". + + This only holds if the FMU is shipped in C source code, or is compiled in a + static link library. For FMUs compiled in a DLL/sharedObject, the "actual" function + names are used and "FMI2_FUNCTION_PREFIX" must not be defined. + + Revisions: + - Apr. 9, 2014: all prefixes "fmi" renamed to "fmi2" (decision from April 8) + - Mar. 26, 2014: FMI_Export set to empty value if FMI_Export and FMI_FUNCTION_PREFIX + are not defined (#173) + - Oct. 11, 2013: Functions of ModelExchange and CoSimulation merged: + fmiInstantiateModel , fmiInstantiateSlave -> fmiInstantiate + fmiFreeModelInstance, fmiFreeSlaveInstance -> fmiFreeInstance + fmiEnterModelInitializationMode, fmiEnterSlaveInitializationMode -> fmiEnterInitializationMode + fmiExitModelInitializationMode , fmiExitSlaveInitializationMode -> fmiExitInitializationMode + fmiTerminateModel, fmiTerminateSlave -> fmiTerminate + fmiResetSlave -> fmiReset (now also for ModelExchange and not only for CoSimulation) + Functions renamed: + fmiUpdateDiscreteStates -> fmiNewDiscreteStates + - June 13, 2013: Functions removed: + fmiInitializeModel + fmiEventUpdate + fmiCompletedEventIteration + fmiInitializeSlave + Functions added: + fmiEnterModelInitializationMode + fmiExitModelInitializationMode + fmiEnterEventMode + fmiUpdateDiscreteStates + fmiEnterContinuousTimeMode + fmiEnterSlaveInitializationMode; + fmiExitSlaveInitializationMode; + - Feb. 17, 2013: Portability improvements: + o DllExport changed to FMI_Export + o FUNCTION_PREFIX changed to FMI_FUNCTION_PREFIX + o Allow undefined FMI_FUNCTION_PREFIX (meaning no prefix is used) + Changed function name "fmiTerminate" to "fmiTerminateModel" (due to #113) + Changed function name "fmiGetNominalContinuousState" to + "fmiGetNominalsOfContinuousStates" + Removed fmiGetStateValueReferences. + - Nov. 14, 2011: Adapted to FMI 2.0: + o Split into two files (fmiFunctions.h, fmiTypes.h) in order + that code that dynamically loads an FMU can directly + utilize the header files). + o Added C++ encapsulation of C-part, in order that the header + file can be directly utilized in C++ code. + o fmiCallbackFunctions is passed as pointer to fmiInstantiateXXX + o stepFinished within fmiCallbackFunctions has as first + argument "fmiComponentEnvironment" and not "fmiComponent". + o New functions to get and set the complete FMU state + and to compute partial derivatives. + - Nov. 4, 2010: Adapted to specification text: + o fmiGetModelTypesPlatform renamed to fmiGetTypesPlatform + o fmiInstantiateSlave: Argument GUID replaced by fmuGUID + Argument mimetype replaced by mimeType + o tabs replaced by spaces + - Oct. 16, 2010: Functions for FMI for Co-simulation added + - Jan. 20, 2010: stateValueReferencesChanged added to struct fmiEventInfo (ticket #27) + (by M. Otter, DLR) + Added WIN32 pragma to define the struct layout (ticket #34) + (by J. Mauss, QTronic) + - Jan. 4, 2010: Removed argument intermediateResults from fmiInitialize + Renamed macro fmiGetModelFunctionsVersion to fmiGetVersion + Renamed macro fmiModelFunctionsVersion to fmiVersion + Replaced fmiModel by fmiComponent in decl of fmiInstantiateModel + (by J. Mauss, QTronic) + - Dec. 17, 2009: Changed extension "me" to "fmi" (by Martin Otter, DLR). + - Dez. 14, 2009: Added eventInfo to meInitialize and added + meGetNominalContinuousStates (by Martin Otter, DLR) + - Sept. 9, 2009: Added DllExport (according to Peter Nilsson's suggestion) + (by A. Junghanns, QTronic) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + meInquireModelTypesVersion -> meGetModelTypesPlatform + meInquireModelFunctionsVersion -> meGetModelFunctionsVersion + meSetStates -> meSetContinuousStates + meGetStates -> meGetContinuousStates + removal of meInitializeModelClass + removal of meGetTime + change of arguments of meInstantiateModel + change of arguments of meCompletedIntegratorStep + (by Martin Otter, DLR): + - July 19, 2009: Added "me" as prefix to file names (by Martin Otter, DLR). + - March 2, 2009: Changed function definitions according to the last design + meeting with additional improvements (by Martin Otter, DLR). + - Dec. 3 , 2008: First version by Martin Otter (DLR) and Hans Olsson (Dynasim). + + Copyright © 2008-2011 MODELISAR consortium, + 2012-2013 Modelica Association Project "FMI" + All rights reserved. + This file is licensed by the copyright holders under the BSD 2-Clause License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. + (Note, this means that if you distribute a modified file, + the modified file must also be provided under this license). +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "fmi2TypesPlatform.h" +#include "fmi2FunctionTypes.h" +#include + + +/* + Export FMI2 API functions on Windows and under GCC. + If custom linking is desired then the FMI2_Export must be + defined before including this file. For instance, + it may be set to __declspec(dllimport). +*/ +#if !defined(FMI2_Export) + #if !defined(FMI2_FUNCTION_PREFIX) + #if defined _WIN32 || defined __CYGWIN__ + /* Note: both gcc & MSVC on Windows support this syntax. */ + #define FMI2_Export __declspec(dllexport) + #else + #if __GNUC__ >= 4 + #define FMI2_Export __attribute__ ((visibility ("default"))) + #else + #define FMI2_Export + #endif + #endif + #else + #define FMI2_Export + #endif +#endif + +/* Macros to construct the real function name + (prepend function name by FMI2_FUNCTION_PREFIX) */ +#if defined(FMI2_FUNCTION_PREFIX) + #define fmi2Paste(a,b) a ## b + #define fmi2PasteB(a,b) fmi2Paste(a,b) + #define fmi2FullName(name) fmi2PasteB(FMI2_FUNCTION_PREFIX, name) +#else + #define fmi2FullName(name) name +#endif + +/*************************************************** +Common Functions +****************************************************/ +#define fmi2GetTypesPlatform fmi2FullName(fmi2GetTypesPlatform) +#define fmi2GetVersion fmi2FullName(fmi2GetVersion) +#define fmi2SetDebugLogging fmi2FullName(fmi2SetDebugLogging) +#define fmi2Instantiate fmi2FullName(fmi2Instantiate) +#define fmi2FreeInstance fmi2FullName(fmi2FreeInstance) +#define fmi2SetupExperiment fmi2FullName(fmi2SetupExperiment) +#define fmi2EnterInitializationMode fmi2FullName(fmi2EnterInitializationMode) +#define fmi2ExitInitializationMode fmi2FullName(fmi2ExitInitializationMode) +#define fmi2Terminate fmi2FullName(fmi2Terminate) +#define fmi2Reset fmi2FullName(fmi2Reset) +#define fmi2GetReal fmi2FullName(fmi2GetReal) +#define fmi2GetInteger fmi2FullName(fmi2GetInteger) +#define fmi2GetBoolean fmi2FullName(fmi2GetBoolean) +#define fmi2GetString fmi2FullName(fmi2GetString) +#define fmi2SetReal fmi2FullName(fmi2SetReal) +#define fmi2SetInteger fmi2FullName(fmi2SetInteger) +#define fmi2SetBoolean fmi2FullName(fmi2SetBoolean) +#define fmi2SetString fmi2FullName(fmi2SetString) +#define fmi2GetFMUstate fmi2FullName(fmi2GetFMUstate) +#define fmi2SetFMUstate fmi2FullName(fmi2SetFMUstate) +#define fmi2FreeFMUstate fmi2FullName(fmi2FreeFMUstate) +#define fmi2SerializedFMUstateSize fmi2FullName(fmi2SerializedFMUstateSize) +#define fmi2SerializeFMUstate fmi2FullName(fmi2SerializeFMUstate) +#define fmi2DeSerializeFMUstate fmi2FullName(fmi2DeSerializeFMUstate) +#define fmi2GetDirectionalDerivative fmi2FullName(fmi2GetDirectionalDerivative) + + +/*************************************************** +Functions for FMI2 for Model Exchange +****************************************************/ +#define fmi2EnterEventMode fmi2FullName(fmi2EnterEventMode) +#define fmi2NewDiscreteStates fmi2FullName(fmi2NewDiscreteStates) +#define fmi2EnterContinuousTimeMode fmi2FullName(fmi2EnterContinuousTimeMode) +#define fmi2CompletedIntegratorStep fmi2FullName(fmi2CompletedIntegratorStep) +#define fmi2SetTime fmi2FullName(fmi2SetTime) +#define fmi2SetContinuousStates fmi2FullName(fmi2SetContinuousStates) +#define fmi2GetDerivatives fmi2FullName(fmi2GetDerivatives) +#define fmi2GetEventIndicators fmi2FullName(fmi2GetEventIndicators) +#define fmi2GetContinuousStates fmi2FullName(fmi2GetContinuousStates) +#define fmi2GetNominalsOfContinuousStates fmi2FullName(fmi2GetNominalsOfContinuousStates) + + +/*************************************************** +Functions for FMI2 for Co-Simulation +****************************************************/ +#define fmi2SetRealInputDerivatives fmi2FullName(fmi2SetRealInputDerivatives) +#define fmi2GetRealOutputDerivatives fmi2FullName(fmi2GetRealOutputDerivatives) +#define fmi2DoStep fmi2FullName(fmi2DoStep) +#define fmi2CancelStep fmi2FullName(fmi2CancelStep) +#define fmi2GetStatus fmi2FullName(fmi2GetStatus) +#define fmi2GetRealStatus fmi2FullName(fmi2GetRealStatus) +#define fmi2GetIntegerStatus fmi2FullName(fmi2GetIntegerStatus) +#define fmi2GetBooleanStatus fmi2FullName(fmi2GetBooleanStatus) +#define fmi2GetStringStatus fmi2FullName(fmi2GetStringStatus) + +/* Version number */ +#define fmi2Version "2.0" + + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers of header files */ + FMI2_Export fmi2GetTypesPlatformTYPE fmi2GetTypesPlatform; + FMI2_Export fmi2GetVersionTYPE fmi2GetVersion; + FMI2_Export fmi2SetDebugLoggingTYPE fmi2SetDebugLogging; + +/* Creation and destruction of FMU instances */ + FMI2_Export fmi2InstantiateTYPE fmi2Instantiate; + FMI2_Export fmi2FreeInstanceTYPE fmi2FreeInstance; + +/* Enter and exit initialization mode, terminate and reset */ + FMI2_Export fmi2SetupExperimentTYPE fmi2SetupExperiment; + FMI2_Export fmi2EnterInitializationModeTYPE fmi2EnterInitializationMode; + FMI2_Export fmi2ExitInitializationModeTYPE fmi2ExitInitializationMode; + FMI2_Export fmi2TerminateTYPE fmi2Terminate; + FMI2_Export fmi2ResetTYPE fmi2Reset; + +/* Getting and setting variables values */ + FMI2_Export fmi2GetRealTYPE fmi2GetReal; + FMI2_Export fmi2GetIntegerTYPE fmi2GetInteger; + FMI2_Export fmi2GetBooleanTYPE fmi2GetBoolean; + FMI2_Export fmi2GetStringTYPE fmi2GetString; + + FMI2_Export fmi2SetRealTYPE fmi2SetReal; + FMI2_Export fmi2SetIntegerTYPE fmi2SetInteger; + FMI2_Export fmi2SetBooleanTYPE fmi2SetBoolean; + FMI2_Export fmi2SetStringTYPE fmi2SetString; + +/* Getting and setting the internal FMU state */ + FMI2_Export fmi2GetFMUstateTYPE fmi2GetFMUstate; + FMI2_Export fmi2SetFMUstateTYPE fmi2SetFMUstate; + FMI2_Export fmi2FreeFMUstateTYPE fmi2FreeFMUstate; + FMI2_Export fmi2SerializedFMUstateSizeTYPE fmi2SerializedFMUstateSize; + FMI2_Export fmi2SerializeFMUstateTYPE fmi2SerializeFMUstate; + FMI2_Export fmi2DeSerializeFMUstateTYPE fmi2DeSerializeFMUstate; + +/* Getting partial derivatives */ + FMI2_Export fmi2GetDirectionalDerivativeTYPE fmi2GetDirectionalDerivative; + + +/*************************************************** +Functions for FMI2 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ + FMI2_Export fmi2EnterEventModeTYPE fmi2EnterEventMode; + FMI2_Export fmi2NewDiscreteStatesTYPE fmi2NewDiscreteStates; + FMI2_Export fmi2EnterContinuousTimeModeTYPE fmi2EnterContinuousTimeMode; + FMI2_Export fmi2CompletedIntegratorStepTYPE fmi2CompletedIntegratorStep; + +/* Providing independent variables and re-initialization of caching */ + FMI2_Export fmi2SetTimeTYPE fmi2SetTime; + FMI2_Export fmi2SetContinuousStatesTYPE fmi2SetContinuousStates; + +/* Evaluation of the model equations */ + FMI2_Export fmi2GetDerivativesTYPE fmi2GetDerivatives; + FMI2_Export fmi2GetEventIndicatorsTYPE fmi2GetEventIndicators; + FMI2_Export fmi2GetContinuousStatesTYPE fmi2GetContinuousStates; + FMI2_Export fmi2GetNominalsOfContinuousStatesTYPE fmi2GetNominalsOfContinuousStates; + + +/*************************************************** +Functions for FMI2 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ + FMI2_Export fmi2SetRealInputDerivativesTYPE fmi2SetRealInputDerivatives; + FMI2_Export fmi2GetRealOutputDerivativesTYPE fmi2GetRealOutputDerivatives; + + FMI2_Export fmi2DoStepTYPE fmi2DoStep; + FMI2_Export fmi2CancelStepTYPE fmi2CancelStep; + +/* Inquire slave status */ + FMI2_Export fmi2GetStatusTYPE fmi2GetStatus; + FMI2_Export fmi2GetRealStatusTYPE fmi2GetRealStatus; + FMI2_Export fmi2GetIntegerStatusTYPE fmi2GetIntegerStatus; + FMI2_Export fmi2GetBooleanStatusTYPE fmi2GetBooleanStatus; + FMI2_Export fmi2GetStringStatusTYPE fmi2GetStringStatus; + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi2Functions_h */ \ No newline at end of file diff --git a/include/fmi2TypesPlatform.h b/include/fmi2TypesPlatform.h new file mode 100644 index 0000000..03c7339 --- /dev/null +++ b/include/fmi2TypesPlatform.h @@ -0,0 +1,115 @@ +#ifndef fmi2TypesPlatform_h +#define fmi2TypesPlatform_h + +/* Standard header file to define the argument types of the + functions of the Functional Mock-up Interface 2.0. + This header file must be utilized both by the model and + by the simulation engine. + + Revisions: + - Apr. 9, 2014: all prefixes "fmi" renamed to "fmi2" (decision from April 8) + - Mar 31, 2014: New datatype fmiChar introduced. + - Feb. 17, 2013: Changed fmiTypesPlatform from "standard32" to "default". + Removed fmiUndefinedValueReference since no longer needed + (because every state is defined in ScalarVariables). + - March 20, 2012: Renamed from fmiPlatformTypes.h to fmiTypesPlatform.h + - Nov. 14, 2011: Use the header file "fmiPlatformTypes.h" for FMI 2.0 + both for "FMI for model exchange" and for "FMI for co-simulation" + New types "fmiComponentEnvironment", "fmiState", and "fmiByte". + The implementation of "fmiBoolean" is change from "char" to "int". + The #define "fmiPlatform" changed to "fmiTypesPlatform" + (in order that #define and function call are consistent) + - Oct. 4, 2010: Renamed header file from "fmiModelTypes.h" to fmiPlatformTypes.h" + for the co-simulation interface + - Jan. 4, 2010: Renamed meModelTypes_h to fmiModelTypes_h (by Mauss, QTronic) + - Dec. 21, 2009: Changed "me" to "fmi" and "meModel" to "fmiComponent" + according to meeting on Dec. 18 (by Martin Otter, DLR) + - Dec. 6, 2009: Added meUndefinedValueReference (by Martin Otter, DLR) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + Changed "version" to "platform", "standard" to "standard32", + Added a precise definition of "standard32" as comment + (by Martin Otter, DLR) + - July 19, 2009: Added "me" as prefix to file names, added meTrue/meFalse, + and changed meValueReferenced from int to unsigned int + (by Martin Otter, DLR). + - March 2, 2009: Moved enums and function pointer definitions to + ModelFunctions.h (by Martin Otter, DLR). + - Dec. 3, 2008 : First version by Martin Otter (DLR) and + Hans Olsson (Dynasim). + + + Copyright © 2008-2011 MODELISAR consortium, + 2012-2013 Modelica Association Project "FMI" + All rights reserved. + This file is licensed by the copyright holders under the BSD 2-Clause License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. + (Note, this means that if you distribute a modified file, + the modified file must also be provided under this license). +*/ + +/* Platform (unique identification of this header file) */ +#define fmi2TypesPlatform "default" + +/* Type definitions of variables passed as arguments + Version "default" means: + + fmi2Component : an opaque object pointer + fmi2ComponentEnvironment: an opaque object pointer + fmi2FMUstate : an opaque object pointer + fmi2ValueReference : handle to the value of a variable + fmi2Real : double precision floating-point data type + fmi2Integer : basic signed integer data type + fmi2Boolean : basic signed integer data type + fmi2Char : character data type + fmi2String : a pointer to a vector of fmi2Char characters + ('\0' terminated, UTF8 encoded) + fmi2Byte : smallest addressable unit of the machine, typically one byte. +*/ + typedef void* fmi2Component; /* Pointer to FMU instance */ + typedef void* fmi2ComponentEnvironment; /* Pointer to FMU environment */ + typedef void* fmi2FMUstate; /* Pointer to internal FMU state */ + typedef unsigned int fmi2ValueReference; + typedef double fmi2Real ; + typedef int fmi2Integer; + typedef int fmi2Boolean; + typedef char fmi2Char; + typedef const fmi2Char* fmi2String; + typedef char fmi2Byte; + +/* Values for fmi2Boolean */ +#define fmi2True 1 +#define fmi2False 0 + + +#endif /* fmi2TypesPlatform_h */ diff --git a/include/fmi3FunctionTypes.h b/include/fmi3FunctionTypes.h new file mode 100644 index 0000000..814e08a --- /dev/null +++ b/include/fmi3FunctionTypes.h @@ -0,0 +1,473 @@ +#ifndef fmi3FunctionTypes_h +#define fmi3FunctionTypes_h + +#include "fmi3TypesPlatform.h" + +/* +This header file must be utilized when compiling an FMU or an FMI master. +It declares data and function types for FMI 3.0-wg003.3 + +Copyright (C) 2011 MODELISAR consortium, + 2012-2018 Modelica Association Project "FMI" + All rights reserved. + +This file is licensed by the copyright holders under the 2-Clause BSD License +(https://opensource.org/licenses/BSD-2-Clause): + +---------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +---------------------------------------------------------------------------- +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* make sure all compiler use the same alignment policies for structures */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(push,8) +#endif + +/* Include stddef.h, in order that size_t etc. is defined */ +#include + + +/* Type definitions */ + +/* tag::Status[] */ +typedef enum { + fmi3OK, + fmi3Warning, + fmi3Discard, + fmi3Error, + fmi3Fatal, + fmi3Pending +} fmi3Status; +/* end::Status[] */ + +/* tag::Type[] */ +typedef enum { + fmi3ModelExchange, + fmi3CoSimulation +} fmi3Type; +/* end::Type[] */ + +/* tag::DependencyKind[] */ +typedef enum { + /* fmi3Independent = 0, not needed but reserved for future use */ + fmi3Constant = 1, + fmi3Fixed = 2, + fmi3Tunable = 3, + fmi3Discrete = 4, + fmi3Dependent = 5 +} fmi3DependencyKind; +/* end::DependencyKind[] */ + +/* tag::CallbackFunctions[] */ +typedef void (*fmi3CallbackLogger) (fmi3ComponentEnvironment componentEnvironment, + fmi3String instanceName, + fmi3Status status, + fmi3String category, + fmi3String message); +typedef void* (*fmi3CallbackAllocateMemory) (fmi3ComponentEnvironment componentEnvironment, + size_t nobj, + size_t size); +typedef void (*fmi3CallbackFreeMemory) (fmi3ComponentEnvironment componentEnvironment, + void* obj); +typedef void (*fmi3StepFinished) (fmi3ComponentEnvironment componentEnvironment, + fmi3Status status); + +typedef struct { + fmi3CallbackLogger logger; + fmi3CallbackAllocateMemory allocateMemory; + fmi3CallbackFreeMemory freeMemory; + fmi3StepFinished stepFinished; + fmi3ComponentEnvironment componentEnvironment; +} fmi3CallbackFunctions; +/* end::CallbackFunctions[] */ + +/* tag::EventInfo[] */ +typedef struct { + fmi3Boolean newDiscreteStatesNeeded; + fmi3Boolean terminateSimulation; + fmi3Boolean nominalsOfContinuousStatesChanged; + fmi3Boolean valuesOfContinuousStatesChanged; + fmi3Boolean nextEventTimeDefined; + fmi3Float64 nextEventTime; /* next event if nextEventTimeDefined=fmi3True */ +} fmi3EventInfo; +/* end::EventInfo[] */ + +/* reset alignment policy to the one set before reading this file */ +#if defined _MSC_VER || defined __GNUC__ +#pragma pack(pop) +#endif + +/* Define fmi3 function pointer types to simplify dynamic loading */ + +/*************************************************** +Types for Common Functions +****************************************************/ + +/* Inquire version numbers and setting logging status */ + +/* tag::GetVersion[] */ +typedef const char* fmi3GetVersionTYPE(void); +/* end::GetVersion[] */ + +/* tag::SetDebugLogging[] */ +typedef fmi3Status fmi3SetDebugLoggingTYPE(fmi3Component c, + fmi3Boolean loggingOn, + size_t nCategories, + const fmi3String categories[]); +/* end::SetDebugLogging[] */ + +/* Creation and destruction of FMU instances and setting debug status */ +/* tag::Instantiate[] */ +typedef fmi3Component fmi3InstantiateTYPE(fmi3String instanceName, + fmi3Type fmuType, + fmi3String fmuGUID, + fmi3String fmuResourceLocation, + const fmi3CallbackFunctions* functions, + fmi3Boolean visible, + fmi3Boolean loggingOn); +/* end::Instantiate[] */ + +/* tag::FreeInstance[] */ +typedef void fmi3FreeInstanceTYPE(fmi3Component c); +/* end::FreeInstance[] */ + +/* Enter and exit initialization mode, terminate and reset */ +/* tag::SetupExperiment[] */ +typedef fmi3Status fmi3SetupExperimentTYPE(fmi3Component c, + fmi3Boolean toleranceDefined, + fmi3Float64 tolerance, + fmi3Float64 startTime, + fmi3Boolean stopTimeDefined, + fmi3Float64 stopTime); +/* end::SetupExperiment[] */ + +/* tag::EnterInitializationMode[] */ +typedef fmi3Status fmi3EnterInitializationModeTYPE(fmi3Component c); +/* end::EnterInitializationMode[] */ + +/* tag::ExitInitializationMode[] */ +typedef fmi3Status fmi3ExitInitializationModeTYPE(fmi3Component c); +/* end::ExitInitializationMode[] */ + +/* tag::Terminate[] */ +typedef fmi3Status fmi3TerminateTYPE(fmi3Component c); +/* end::Terminate[] */ + +/* tag::Reset[] */ +typedef fmi3Status fmi3ResetTYPE(fmi3Component c); +/* end::Reset[] */ + +/* Getting and setting variable values */ +/* tag::Getters[] */ +typedef fmi3Status fmi3GetFloat32TYPE(fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Float32 value[], size_t nValues); + +typedef fmi3Status fmi3GetFloat64TYPE(fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Float64 value[], size_t nValues); + +typedef fmi3Status fmi3GetInt8TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Int8 value[], size_t nValues); + +typedef fmi3Status fmi3GetUInt8TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3UInt8 value[], size_t nValues); + +typedef fmi3Status fmi3GetInt16TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Int16 value[], size_t nValues); + +typedef fmi3Status fmi3GetUInt16TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3UInt16 value[], size_t nValues); + +typedef fmi3Status fmi3GetInt32TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Int32 value[], size_t nValues); + +typedef fmi3Status fmi3GetUInt32TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3UInt32 value[], size_t nValues); + +typedef fmi3Status fmi3GetInt64TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Int64 value[], size_t nValues); + +typedef fmi3Status fmi3GetUInt64TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3UInt64 value[], size_t nValues); + +typedef fmi3Status fmi3GetBooleanTYPE(fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3Boolean value[], size_t nValues); + +typedef fmi3Status fmi3GetStringTYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + fmi3String value[], size_t nValues); + +typedef fmi3Status fmi3GetBinaryTYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + size_t size[], fmi3Binary value[], size_t nValues); +/* end::Getters[] */ + +/* tag::Setters[] */ +typedef fmi3Status fmi3SetFloat32TYPE(fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Float32 value[], size_t nValues); + +typedef fmi3Status fmi3SetFloat64TYPE(fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Float64 value[], size_t nValues); + +typedef fmi3Status fmi3SetInt8TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Int8 value[], size_t nValues); + +typedef fmi3Status fmi3SetUInt8TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3UInt8 value[], size_t nValues); + +typedef fmi3Status fmi3SetInt16TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Int16 value[], size_t nValues); + +typedef fmi3Status fmi3SetUInt16TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3UInt16 value[], size_t nValues); + +typedef fmi3Status fmi3SetInt32TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Int32 value[], size_t nValues); + +typedef fmi3Status fmi3SetUInt32TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3UInt32 value[], size_t nValues); + +typedef fmi3Status fmi3SetInt64TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Int64 value[], size_t nValues); + +typedef fmi3Status fmi3SetUInt64TYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3UInt64 value[], size_t nValues); + +typedef fmi3Status fmi3SetBooleanTYPE(fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3Boolean value[], size_t nValues); + +typedef fmi3Status fmi3SetStringTYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const fmi3String value[], size_t nValues); + +typedef fmi3Status fmi3SetBinaryTYPE (fmi3Component c, + const fmi3ValueReference vr[], size_t nvr, + const size_t size[], const fmi3Binary value[], size_t nValues); +/* end::Setters[] */ + +/* Getting Variable Dependency Information */ + +/* tag::GetNumberOfVariableDependencies[] */ +typedef fmi3Status fmi3GetNumberOfVariableDependenciesTYPE(fmi3Component c, + fmi3ValueReference vr, + size_t* nDependencies); +/* end::GetNumberOfVariableDependencies[] */ + +/* tag::GetVariableDependencies[] */ +typedef fmi3Status fmi3GetVariableDependenciesTYPE(fmi3Component c, + fmi3ValueReference vrDependent, + size_t elementIndexDependent[], + fmi3ValueReference vrIndependent[], + size_t elementIndexIndependent[], + fmi3DependencyKind dependencyType[], + size_t nDependencies); +/* end::GetVariableDependencies[] */ + +/* Getting and setting the internal FMU state */ + +/* tag::GetSetFreeFMUstate[] */ +typedef fmi3Status fmi3GetFMUstateTYPE (fmi3Component c, fmi3FMUstate* FMUstate); +typedef fmi3Status fmi3SetFMUstateTYPE (fmi3Component c, fmi3FMUstate FMUstate); +typedef fmi3Status fmi3FreeFMUstateTYPE(fmi3Component c, fmi3FMUstate* FMUstate); +/* end::GetSetFreeFMUstate[] */ + +/* tag::SerializedFMUstate[] */ +typedef fmi3Status fmi3SerializedFMUstateSizeTYPE(fmi3Component c, + fmi3FMUstate FMUstate, + size_t* size); + +typedef fmi3Status fmi3SerializeFMUstateTYPE (fmi3Component c, + fmi3FMUstate FMUstate, + fmi3Byte serializedState[], + size_t size); + +typedef fmi3Status fmi3DeSerializeFMUstateTYPE (fmi3Component c, + const fmi3Byte serializedState[], + size_t size, + fmi3FMUstate* FMUstate); +/* end::SerializedFMUstate[] */ + +/* Getting partial derivatives */ + +/* tag::GetDirectionalDerivative[] */ +typedef fmi3Status fmi3GetDirectionalDerivativeTYPE(fmi3Component c, + const fmi3ValueReference vrUnknown[], + size_t nUnknown, + const fmi3ValueReference vrKnown[], + size_t nKnown, + const fmi3Float64 dvKnown[], + size_t nDvKnown, + fmi3Float64 dvUnknown[], + size_t nDvUnknown); +/* end::GetDirectionalDerivative[] */ + +/*************************************************** +Types for Functions for FMI3 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ + +/* tag::EnterEventMode[] */ +typedef fmi3Status fmi3EnterEventModeTYPE(fmi3Component c); +/* end::EnterEventMode[] */ + +/* tag::NewDiscreteStates[] */ +typedef fmi3Status fmi3NewDiscreteStatesTYPE(fmi3Component c, + fmi3EventInfo* fmi3eventInfo); +/* end::NewDiscreteStates[] */ + +/* tag::EnterContinuousTimeMode[] */ +typedef fmi3Status fmi3EnterContinuousTimeModeTYPE(fmi3Component c); +/* end::EnterContinuousTimeMode[] */ + +/* tag::CompletedIntegratorStep[] */ +typedef fmi3Status fmi3CompletedIntegratorStepTYPE(fmi3Component c, + fmi3Boolean noSetFMUStatePriorToCurrentPoint, + fmi3Boolean* enterEventMode, + fmi3Boolean* terminateSimulation); +/* end::CompletedIntegratorStep[] */ + +/* Providing independent variables and re-initialization of caching */ + +/* tag::SetTime[] */ +typedef fmi3Status fmi3SetTimeTYPE(fmi3Component c, fmi3Float64 time); +/* end::SetTime[] */ + +/* tag::SetContinuousStates[] */ +typedef fmi3Status fmi3SetContinuousStatesTYPE(fmi3Component c, + const fmi3Float64 x[], + size_t nx); +/* end::SetContinuousStates[] */ + +/* Evaluation of the model equations */ + +/* tag::GetDerivatives[] */ +typedef fmi3Status fmi3GetDerivativesTYPE(fmi3Component c, + fmi3Float64 derivatives[], + size_t nx); +/* end::GetDerivatives[] */ + +/* tag::GetEventIndicators[] */ +typedef fmi3Status fmi3GetEventIndicatorsTYPE(fmi3Component c, + fmi3Float64 eventIndicators[], + size_t ni); +/* end::GetEventIndicators[] */ + +/* tag::GetContinuousStates[] */ +typedef fmi3Status fmi3GetContinuousStatesTYPE(fmi3Component c, fmi3Float64 x[], size_t nx); +/* end::GetContinuousStates[] */ + +/* tag::GetNominalsOfContinuousStates[] */ +typedef fmi3Status fmi3GetNominalsOfContinuousStatesTYPE(fmi3Component c, + fmi3Float64 x_nominal[], + size_t nx); +/* end::GetNominalsOfContinuousStates[] */ + +/* tag::GetNumberOfEventIndicators[] */ +typedef fmi3Status fmi3GetNumberOfEventIndicatorsTYPE(fmi3Component c, size_t* nz); +/* end::GetNumberOfEventIndicators[] */ + +/* tag::GetNumberOfContinuousStates[] */ +typedef fmi3Status fmi3GetNumberOfContinuousStatesTYPE(fmi3Component c, size_t* nx); +/* end::GetNumberOfContinuousStates[] */ + +/*************************************************** +Types for Functions for FMI3 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ + +/* tag::SetInputDerivatives[] */ +typedef fmi3Status fmi3SetInputDerivativesTYPE(fmi3Component c, + const fmi3ValueReference vr[], + size_t nvr, + const fmi3Int32 order[], + const fmi3Float64 value[], + size_t nValues); +/* end::SetInputDerivatives[] */ + +/* tag::GetOutputDerivatives[] */ +typedef fmi3Status fmi3GetOutputDerivativesTYPE(fmi3Component c, + const fmi3ValueReference vr[], + size_t nvr, + const fmi3Int32 order[], + fmi3Float64 value[], + size_t nValues); +/* end::GetOutputDerivatives[] */ + +/* tag::DoStep[] */ +typedef fmi3Status fmi3DoStepTYPE(fmi3Component c, + fmi3Float64 currentCommunicationPoint, + fmi3Float64 communicationStepSize, + fmi3Boolean noSetFMUStatePriorToCurrentPoint); +/* end::DoStep[] */ + +/* tag::CancelStep[] */ +typedef fmi3Status fmi3CancelStepTYPE(fmi3Component c); +/* end::CancelStep[] */ + +/* Inquire slave status */ + +/* tag::GetDoStepPendingStatus[] */ +typedef fmi3Status fmi3GetDoStepPendingStatusTYPE(fmi3Component c, + fmi3Status* status, + fmi3String* message); +/* end::GetDoStepPendingStatus[] */ + +/* tag::GetDoStepDiscardedStatus[] */ +typedef fmi3Status fmi3GetDoStepDiscardedStatusTYPE(fmi3Component c, + fmi3Boolean* terminate, + fmi3Float64* lastSuccessfulTime); +/* end::GetDoStepDiscardedStatus[] */ + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi3FunctionTypes_h */ diff --git a/include/fmi3Functions.h b/include/fmi3Functions.h new file mode 100644 index 0000000..6ac257c --- /dev/null +++ b/include/fmi3Functions.h @@ -0,0 +1,282 @@ +#ifndef fmi3Functions_h +#define fmi3Functions_h + +/* +This header file must be utilized when compiling a FMU. +It defines all functions of the + FMI 3.0-wg003.3 Model Exchange and Co-Simulation Interface. + +In order to have unique function names even if several FMUs +are compiled together (e.g. for embedded systems), every "real" function name +is constructed by prepending the function name by "FMI3_FUNCTION_PREFIX". +Therefore, the typical usage is: + + #define FMI3_FUNCTION_PREFIX MyModel_ + #include "fmi3Functions.h" + +As a result, a function that is defined as "fmi3GetDerivatives" in this header file, +is actually getting the name "MyModel_fmi3GetDerivatives". + +This only holds if the FMU is shipped in C source code, or is compiled in a +static link library. For FMUs compiled in a DLL/sharedObject, the "actual" function +names are used and "FMI3_FUNCTION_PREFIX" must not be defined. + +Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2018 Modelica Association Project "FMI" + All rights reserved. + +This file is licensed by the copyright holders under the 2-Clause BSD License +(https://opensource.org/licenses/BSD-2-Clause): + +---------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +---------------------------------------------------------------------------- +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "fmi3TypesPlatform.h" +#include "fmi3FunctionTypes.h" +#include + +/* +Export FMI3 API functions on Windows and under GCC. +If custom linking is desired then the FMI3_Export must be +defined before including this file. For instance, +it may be set to __declspec(dllimport). +*/ +#if !defined(FMI3_Export) + #if !defined(FMI3_FUNCTION_PREFIX) + #if defined _WIN32 || defined __CYGWIN__ + /* Note: both gcc & MSVC on Windows support this syntax. */ + #define FMI3_Export __declspec(dllexport) + #else + #if __GNUC__ >= 4 + #define FMI3_Export __attribute__ ((visibility ("default"))) + #else + #define FMI3_Export + #endif + #endif + #else + #define FMI3_Export + #endif +#endif + +/* +Macros to construct the real function name (prepend function name by FMI3_FUNCTION_PREFIX) +*/ +#if defined(FMI3_FUNCTION_PREFIX) + #define fmi3Paste(a,b) a ## b + #define fmi3PasteB(a,b) fmi3Paste(a,b) + #define fmi3FullName(name) fmi3PasteB(FMI3_FUNCTION_PREFIX, name) +#else + #define fmi3FullName(name) name +#endif + +/*************************************************** +Common Functions +****************************************************/ +#define fmi3GetVersion fmi3FullName(fmi3GetVersion) +#define fmi3SetDebugLogging fmi3FullName(fmi3SetDebugLogging) +#define fmi3Instantiate fmi3FullName(fmi3Instantiate) +#define fmi3FreeInstance fmi3FullName(fmi3FreeInstance) +#define fmi3SetupExperiment fmi3FullName(fmi3SetupExperiment) +#define fmi3EnterInitializationMode fmi3FullName(fmi3EnterInitializationMode) +#define fmi3ExitInitializationMode fmi3FullName(fmi3ExitInitializationMode) +#define fmi3Terminate fmi3FullName(fmi3Terminate) +#define fmi3Reset fmi3FullName(fmi3Reset) +#define fmi3GetFloat32 fmi3FullName(fmi3GetFloat32) +#define fmi3GetFloat64 fmi3FullName(fmi3GetFloat64) +#define fmi3GetInt8 fmi3FullName(fmi3GetInt8) +#define fmi3GetUInt8 fmi3FullName(fmi3GetUInt8) +#define fmi3GetInt16 fmi3FullName(fmi3GetInt16) +#define fmi3GetUInt16 fmi3FullName(fmi3GetUInt16) +#define fmi3GetInt32 fmi3FullName(fmi3GetInt32) +#define fmi3GetUInt32 fmi3FullName(fmi3GetUInt32) +#define fmi3GetInt64 fmi3FullName(fmi3GetInt64) +#define fmi3GetUInt64 fmi3FullName(fmi3GetUInt64) +#define fmi3GetBoolean fmi3FullName(fmi3GetBoolean) +#define fmi3GetString fmi3FullName(fmi3GetString) +#define fmi3GetBinary fmi3FullName(fmi3GetBinary) +#define fmi3SetFloat32 fmi3FullName(fmi3SetFloat32) +#define fmi3SetFloat64 fmi3FullName(fmi3SetFloat64) +#define fmi3SetInt8 fmi3FullName(fmi3SetInt8) +#define fmi3SetUInt8 fmi3FullName(fmi3SetUInt8) +#define fmi3SetInt16 fmi3FullName(fmi3SetInt16) +#define fmi3SetUInt16 fmi3FullName(fmi3SetUInt16) +#define fmi3SetInt32 fmi3FullName(fmi3SetInt32) +#define fmi3SetUInt32 fmi3FullName(fmi3SetUInt32) +#define fmi3SetInt64 fmi3FullName(fmi3SetInt64) +#define fmi3SetUInt64 fmi3FullName(fmi3SetUInt64) +#define fmi3SetBoolean fmi3FullName(fmi3SetBoolean) +#define fmi3SetString fmi3FullName(fmi3SetString) +#define fmi3SetBinary fmi3FullName(fmi3SetBinary) +#define fmi3GetNumberOfVariableDependencies fmi3FullName(fmi3GetNumberOfVariableDependencies) +#define fmi3GetVariableDependencies fmi3FullName(fmi3GetVariableDependencies) +#define fmi3GetFMUstate fmi3FullName(fmi3GetFMUstate) +#define fmi3SetFMUstate fmi3FullName(fmi3SetFMUstate) +#define fmi3FreeFMUstate fmi3FullName(fmi3FreeFMUstate) +#define fmi3SerializedFMUstateSize fmi3FullName(fmi3SerializedFMUstateSize) +#define fmi3SerializeFMUstate fmi3FullName(fmi3SerializeFMUstate) +#define fmi3DeSerializeFMUstate fmi3FullName(fmi3DeSerializeFMUstate) +#define fmi3GetDirectionalDerivative fmi3FullName(fmi3GetDirectionalDerivative) + +/*************************************************** +Functions for FMI3 for Model Exchange +****************************************************/ + +#define fmi3EnterEventMode fmi3FullName(fmi3EnterEventMode) +#define fmi3NewDiscreteStates fmi3FullName(fmi3NewDiscreteStates) +#define fmi3EnterContinuousTimeMode fmi3FullName(fmi3EnterContinuousTimeMode) +#define fmi3CompletedIntegratorStep fmi3FullName(fmi3CompletedIntegratorStep) +#define fmi3SetTime fmi3FullName(fmi3SetTime) +#define fmi3SetContinuousStates fmi3FullName(fmi3SetContinuousStates) +#define fmi3GetDerivatives fmi3FullName(fmi3GetDerivatives) +#define fmi3GetEventIndicators fmi3FullName(fmi3GetEventIndicators) +#define fmi3GetContinuousStates fmi3FullName(fmi3GetContinuousStates) +#define fmi3GetNominalsOfContinuousStates fmi3FullName(fmi3GetNominalsOfContinuousStates) +#define fmi3GetNumberOfEventIndicators fmi3FullName(fmi3GetNumberOfEventIndicators) +#define fmi3GetNumberOfContinuousStates fmi3FullName(fmi3GetNumberOfContinuousStates) + +/*************************************************** +Functions for FMI3 for Co-Simulation +****************************************************/ + +#define fmi3SetInputDerivatives fmi3FullName(fmi3SetInputDerivatives) +#define fmi3GetOutputDerivatives fmi3FullName(fmi3GetOutputDerivatives) +#define fmi3DoStep fmi3FullName(fmi3DoStep) +#define fmi3CancelStep fmi3FullName(fmi3CancelStep) +#define fmi3GetDoStepPendingStatus fmi3FullName(fmi3GetDoStepPendingStatus) +#define fmi3GetDoStepDiscardedStatus fmi3FullName(fmi3GetDoStepDiscardedStatus) + +/* Version number */ +#define fmi3Version "3.0-wg003.3" + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers and set debug logging */ +FMI3_Export fmi3GetVersionTYPE fmi3GetVersion; +FMI3_Export fmi3SetDebugLoggingTYPE fmi3SetDebugLogging; + +/* Creation and destruction of FMU instances */ +FMI3_Export fmi3InstantiateTYPE fmi3Instantiate; +FMI3_Export fmi3FreeInstanceTYPE fmi3FreeInstance; + +/* Enter and exit initialization mode, terminate and reset */ +FMI3_Export fmi3SetupExperimentTYPE fmi3SetupExperiment; +FMI3_Export fmi3EnterInitializationModeTYPE fmi3EnterInitializationMode; +FMI3_Export fmi3ExitInitializationModeTYPE fmi3ExitInitializationMode; +FMI3_Export fmi3TerminateTYPE fmi3Terminate; +FMI3_Export fmi3ResetTYPE fmi3Reset; + +/* Getting and setting variables values */ +FMI3_Export fmi3GetFloat32TYPE fmi3GetFloat32; +FMI3_Export fmi3GetFloat64TYPE fmi3GetFloat64; +FMI3_Export fmi3GetInt8TYPE fmi3GetInt8; +FMI3_Export fmi3GetUInt8TYPE fmi3GetUInt8; +FMI3_Export fmi3GetInt16TYPE fmi3GetInt16; +FMI3_Export fmi3GetUInt16TYPE fmi3GetUInt16; +FMI3_Export fmi3GetInt32TYPE fmi3GetInt32; +FMI3_Export fmi3GetUInt32TYPE fmi3GetUInt32; +FMI3_Export fmi3GetInt64TYPE fmi3GetInt64; +FMI3_Export fmi3GetUInt64TYPE fmi3GetUInt64; +FMI3_Export fmi3GetBooleanTYPE fmi3GetBoolean; +FMI3_Export fmi3GetStringTYPE fmi3GetString; +FMI3_Export fmi3GetBinaryTYPE fmi3GetBinary; +FMI3_Export fmi3SetFloat32TYPE fmi3SetFloat32; +FMI3_Export fmi3SetFloat64TYPE fmi3SetFloat64; +FMI3_Export fmi3SetInt8TYPE fmi3SetInt8; +FMI3_Export fmi3SetUInt8TYPE fmi3SetUInt8; +FMI3_Export fmi3SetInt16TYPE fmi3SetInt16; +FMI3_Export fmi3SetUInt16TYPE fmi3SetUInt16; +FMI3_Export fmi3SetInt32TYPE fmi3SetInt32; +FMI3_Export fmi3SetUInt32TYPE fmi3SetUInt32; +FMI3_Export fmi3SetInt64TYPE fmi3SetInt64; +FMI3_Export fmi3SetUInt64TYPE fmi3SetUInt64; +FMI3_Export fmi3SetBooleanTYPE fmi3SetBoolean; +FMI3_Export fmi3SetStringTYPE fmi3SetString; +FMI3_Export fmi3SetBinaryTYPE fmi3SetBinary; +FMI3_Export fmi3SetStringTYPE fmi3SetString; +FMI3_Export fmi3SetBinaryTYPE fmi3SetBinary; + +/* Getting Variable Dependency Information */ +FMI3_Export fmi3GetNumberOfVariableDependenciesTYPE fmi3GetNumberOfVariableDependencies; +FMI3_Export fmi3GetVariableDependenciesTYPE fmi3GetVariableDependencies; + +/* Getting and setting the internal FMU state */ +FMI3_Export fmi3GetFMUstateTYPE fmi3GetFMUstate; +FMI3_Export fmi3SetFMUstateTYPE fmi3SetFMUstate; +FMI3_Export fmi3FreeFMUstateTYPE fmi3FreeFMUstate; +FMI3_Export fmi3SerializedFMUstateSizeTYPE fmi3SerializedFMUstateSize; +FMI3_Export fmi3SerializeFMUstateTYPE fmi3SerializeFMUstate; +FMI3_Export fmi3DeSerializeFMUstateTYPE fmi3DeSerializeFMUstate; + +/* Getting partial derivatives */ +FMI3_Export fmi3GetDirectionalDerivativeTYPE fmi3GetDirectionalDerivative; + +/*************************************************** +Functions for FMI3 for Model Exchange +****************************************************/ + +/* Enter and exit the different modes */ +FMI3_Export fmi3EnterEventModeTYPE fmi3EnterEventMode; +FMI3_Export fmi3NewDiscreteStatesTYPE fmi3NewDiscreteStates; +FMI3_Export fmi3EnterContinuousTimeModeTYPE fmi3EnterContinuousTimeMode; +FMI3_Export fmi3CompletedIntegratorStepTYPE fmi3CompletedIntegratorStep; + +/* Providing independent variables and re-initialization of caching */ +FMI3_Export fmi3SetTimeTYPE fmi3SetTime; +FMI3_Export fmi3SetContinuousStatesTYPE fmi3SetContinuousStates; + +/* Evaluation of the model equations */ +FMI3_Export fmi3GetDerivativesTYPE fmi3GetDerivatives; +FMI3_Export fmi3GetEventIndicatorsTYPE fmi3GetEventIndicators; +FMI3_Export fmi3GetContinuousStatesTYPE fmi3GetContinuousStates; +FMI3_Export fmi3GetNominalsOfContinuousStatesTYPE fmi3GetNominalsOfContinuousStates; +FMI3_Export fmi3GetNumberOfEventIndicatorsTYPE fmi3GetNumberOfEventIndicators; +FMI3_Export fmi3GetNumberOfContinuousStatesTYPE fmi3GetNumberOfContinuousStates; + +/*************************************************** +Functions for FMI3 for Co-Simulation +****************************************************/ + +/* Simulating the slave */ +FMI3_Export fmi3SetInputDerivativesTYPE fmi3SetInputDerivatives; +FMI3_Export fmi3GetOutputDerivativesTYPE fmi3GetOutputDerivatives; + +FMI3_Export fmi3DoStepTYPE fmi3DoStep; +FMI3_Export fmi3CancelStepTYPE fmi3CancelStep; + +/* Inquire slave status */ +FMI3_Export fmi3GetDoStepPendingStatusTYPE fmi3GetDoStepPendingStatus; +FMI3_Export fmi3GetDoStepDiscardedStatusTYPE fmi3GetDoStepDiscardedStatus; + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif /* fmi3Functions_h */ diff --git a/include/fmi3TypesPlatform.h b/include/fmi3TypesPlatform.h new file mode 100644 index 0000000..d44d50a --- /dev/null +++ b/include/fmi3TypesPlatform.h @@ -0,0 +1,87 @@ +#ifndef fmi3TypesPlatform_h +#define fmi3TypesPlatform_h + +/* +Standard header file to define the argument types of the +functions of the Functional Mock-up Interface 3.0-wg003.3. +This header file must be utilized both by the model and +by the simulation engine. + +Copyright (C) 2008-2011 MODELISAR consortium, + 2012-2018 Modelica Association Project "FMI" + All rights reserved. + +This file is licensed by the copyright holders under the 2-Clause BSD License +(https://opensource.org/licenses/BSD-2-Clause): + +---------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +---------------------------------------------------------------------------- +*/ + +/* Include the integer type definitions */ +#include + + +/* tag::Component[] */ +typedef void* fmi3Component; /* Pointer to FMU instance */ +/* end::Component[] */ + +/* tag::ComponentEnvironment[] */ +typedef void* fmi3ComponentEnvironment; /* Pointer to FMU environment */ +/* end::ComponentEnvironment[] */ + +/* tag::FMUstate[] */ +typedef void* fmi3FMUstate; /* Pointer to internal FMU state */ +/* end::FMUstate[] */ + +/* tag::ValueReference[] */ +typedef unsigned int fmi3ValueReference; /* Handle to the value of a variable */ +/* end::ValueReference[] */ + +/* tag::VariableTypes[] */ +typedef float fmi3Float32; /* Single precision floating point (32-bit) */ +typedef double fmi3Float64; /* Double precision floating point (64-bit) */ +typedef int8_t fmi3Int8; /* 8-bit signed integer */ +typedef uint8_t fmi3UInt8; /* 8-bit unsigned integer */ +typedef int16_t fmi3Int16; /* 16-bit signed integer */ +typedef uint16_t fmi3UInt16; /* 16-bit unsigned integer */ +typedef int16_t fmi3Int32; /* 32-bit signed integer */ +typedef uint16_t fmi3UInt32; /* 32-bit unsigned integer */ +typedef int16_t fmi3Int64; /* 64-bit signed integer */ +typedef uint16_t fmi3UInt64; /* 64-bit unsigned integer */ +typedef int fmi3Boolean; /* Data type to be used with fmi3True and fmi3False */ +typedef char fmi3Char; /* Data type for one character */ +typedef const fmi3Char* fmi3String; /* Data type for character strings + ('\0' terminated, UTF8 encoded) */ +typedef char fmi3Byte; /* Smallest addressable unit of the machine + (typically one byte) */ +typedef const fmi3Byte* fmi3Binary; /* Data type for binary data + (out-of-band length terminated) */ + +/* Values for fmi3Boolean */ +#define fmi3True 1 +#define fmi3False 0 +/* end::VariableTypes[] */ + +#endif /* fmi3TypesPlatform_h */ diff --git a/include/fmiFunctions.h b/include/fmiFunctions.h new file mode 100644 index 0000000..bc08c36 --- /dev/null +++ b/include/fmiFunctions.h @@ -0,0 +1,230 @@ +#ifndef fmiFunctions_h +#define fmiFunctions_h + +/* This header file must be utilized when compiling a FMU. + It defines all functions of Co-Simulation Interface. + In order to have unique function names even if several FMUs + are compiled together (e.g. for embedded systems), every "real" function name + is constructed by prepending the function name by + "MODEL_IDENTIFIER" + "_" where "MODEL_IDENTIFIER" is the short name + of the model used as the name of the zip-file where the model is stored. + Therefore, the typical usage is: + + #define MODEL_IDENTIFIER MyModel + #include "fmiFunctions.h" + + As a result, a function that is defined as "fmiGetDerivatives" in this header file, + is actually getting the name "MyModel_fmiGetDerivatives". + + Revisions: + - November 4, 2010: Adapted to specification text: + o fmiGetModelTypesPlatform renamed to fmiGetTypesPlatform + o fmiInstantiateSlave: Argument GUID replaced by fmuGUID + Argument mimetype replaced by mimeType + o tabs replaced by spaces + - October 16, 2010: First public Version + + + Copyright © 2008-2010, MODELISAR consortium. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- +*/ + +#include "fmiPlatformTypes.h" +#include + +/* Export fmi functions on Windows */ +#ifdef _MSC_VER +#define DllExport __declspec( dllexport ) +#else +#define DllExport +#endif + +/* Macros to construct the real function name + (prepend function name by MODEL_IDENTIFIER + "_") */ + +#define fmiPaste(a,b) a ## b +#define fmiPasteB(a,b) fmiPaste(a,b) +#define fmiFullName(name) fmiPasteB(MODEL_IDENTIFIER, name) + +/*************************************************** +Common Functions +****************************************************/ +#define fmiGetTypesPlatform fmiFullName(_fmiGetTypesPlatform) +#define fmiGetVersion fmiFullName(_fmiGetVersion) +#define fmiSetDebugLogging fmiFullName(_fmiSetDebugLogging) + +/*Data Exchange*/ +#define fmiSetReal fmiFullName(_fmiSetReal) +#define fmiSetInteger fmiFullName(_fmiSetInteger) +#define fmiSetBoolean fmiFullName(_fmiSetBoolean) +#define fmiSetString fmiFullName(_fmiSetString) + +#define fmiGetReal fmiFullName(_fmiGetReal) +#define fmiGetInteger fmiFullName(_fmiGetInteger) +#define fmiGetBoolean fmiFullName(_fmiGetBoolean) +#define fmiGetString fmiFullName(_fmiGetString) + +/*************************************************** +Functions for FMI for Co-Simulation +****************************************************/ +#define fmiInstantiateSlave fmiFullName(_fmiInstantiateSlave) +#define fmiInitializeSlave fmiFullName(_fmiInitializeSlave) +#define fmiTerminateSlave fmiFullName(_fmiTerminateSlave) +#define fmiResetSlave fmiFullName(_fmiResetSlave) +#define fmiFreeSlaveInstance fmiFullName(_fmiFreeSlaveInstance) +#define fmiSetRealInputDerivatives fmiFullName(_fmiSetRealInputDerivatives) +#define fmiGetRealOutputDerivatives fmiFullName(_fmiGetRealOutputDerivatives) +#define fmiDoStep fmiFullName(_fmiDoStep) +#define fmiCancelStep fmiFullName(_fmiCancelStep) +#define fmiGetStatus fmiFullName(_fmiGetStatus) +#define fmiGetRealStatus fmiFullName(_fmiGetRealStatus) +#define fmiGetIntegerStatus fmiFullName(_fmiGetIntegerStatus) +#define fmiGetBooleanStatus fmiFullName(_fmiGetBooleanStatus) +#define fmiGetStringStatus fmiFullName(_fmiGetStringStatus) + +/* Version number */ +#define fmiVersion "1.0" + +/* make sure all compiler use the same alignment policies for structures */ +#ifdef _MSC_VER +#pragma pack(push,8) +#endif + +/* Type definitions */ + typedef enum {fmiOK, + fmiWarning, + fmiDiscard, + fmiError, + fmiFatal, + fmiPending} fmiStatus; + + typedef void (*fmiCallbackLogger) (fmiComponent c, fmiString instanceName, fmiStatus status, + fmiString category, fmiString message, ...); + typedef void* (*fmiCallbackAllocateMemory)(size_t nobj, size_t size); + typedef void (*fmiCallbackFreeMemory) (void* obj); + typedef void (*fmiStepFinished) (fmiComponent c, fmiStatus status); + + typedef struct { + fmiCallbackLogger logger; + fmiCallbackAllocateMemory allocateMemory; + fmiCallbackFreeMemory freeMemory; + fmiStepFinished stepFinished; + } fmiCallbackFunctions; + + typedef struct { + fmiBoolean iterationConverged; + fmiBoolean stateValueReferencesChanged; + fmiBoolean stateValuesChanged; + fmiBoolean terminateSimulation; + fmiBoolean upcomingTimeEvent; + fmiReal nextEventTime; + } fmiEventInfo; + +/* reset alignment policy to the one set before reading this file */ +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +/*************************************************** +Common Functions +****************************************************/ + +/* Inquire version numbers of header files */ + DllExport const char* fmiGetTypesPlatform(); + DllExport const char* fmiGetVersion(); + + DllExport fmiStatus fmiSetDebugLogging (fmiComponent c, fmiBoolean loggingOn); + +/* Data Exchange Functions*/ + DllExport fmiStatus fmiGetReal (fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]); + DllExport fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]); + DllExport fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]); + DllExport fmiStatus fmiGetString (fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]); + + DllExport fmiStatus fmiSetReal (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]); + DllExport fmiStatus fmiSetInteger (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]); + DllExport fmiStatus fmiSetBoolean (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]); + DllExport fmiStatus fmiSetString (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]); + +/*************************************************** +Functions for FMI for Co-Simulation +****************************************************/ + +/* Creation and destruction of slave instances and setting debug status */ + DllExport fmiComponent fmiInstantiateSlave(fmiString instanceName, + fmiString fmuGUID, + fmiString fmuLocation, + fmiString mimeType, + fmiReal timeout, + fmiBoolean visible, + fmiBoolean interactive, + fmiCallbackFunctions functions, + fmiBoolean loggingOn); + + DllExport fmiStatus fmiInitializeSlave(fmiComponent c, + fmiReal tStart, + fmiBoolean StopTimeDefined, + fmiReal tStop); + + DllExport fmiStatus fmiTerminateSlave (fmiComponent c); + DllExport fmiStatus fmiResetSlave (fmiComponent c); + DllExport void fmiFreeSlaveInstance(fmiComponent c); + + DllExport fmiStatus fmiSetRealInputDerivatives(fmiComponent c, + const fmiValueReference vr[], + size_t nvr, + const fmiInteger order[], + const fmiReal value[]); + + DllExport fmiStatus fmiGetRealOutputDerivatives(fmiComponent c, + const fmiValueReference vr[], + size_t nvr, + const fmiInteger order[], + fmiReal value[]); + + DllExport fmiStatus fmiCancelStep(fmiComponent c); + DllExport fmiStatus fmiDoStep (fmiComponent c, + fmiReal currentCommunicationPoint, + fmiReal communicationStepSize, + fmiBoolean newStep); + + + typedef enum {fmiDoStepStatus, + fmiPendingStatus, + fmiLastSuccessfulTime} fmiStatusKind; + + DllExport fmiStatus fmiGetStatus (fmiComponent c, const fmiStatusKind s, fmiStatus* value); + DllExport fmiStatus fmiGetRealStatus (fmiComponent c, const fmiStatusKind s, fmiReal* value); + DllExport fmiStatus fmiGetIntegerStatus(fmiComponent c, const fmiStatusKind s, fmiInteger* value); + DllExport fmiStatus fmiGetBooleanStatus(fmiComponent c, const fmiStatusKind s, fmiBoolean* value); + DllExport fmiStatus fmiGetStringStatus (fmiComponent c, const fmiStatusKind s, fmiString* value); + + +#endif // fmiFunctions_h diff --git a/include/fmiModelFunctions.h b/include/fmiModelFunctions.h new file mode 100644 index 0000000..695f4c6 --- /dev/null +++ b/include/fmiModelFunctions.h @@ -0,0 +1,206 @@ +#ifndef fmiModelFunctions_h +#define fmiModelFunctions_h + +/* This header file must be utilized when compiling a model. + It defines all functions of the Model Execution Interface. + In order to have unique function names even if several models + are compiled together (e.g. for embedded systems), every "real" function name + is constructed by prepending the function name by + "MODEL_IDENTIFIER" + "_" where "MODEL_IDENTIFIER" is the short name + of the model used as the name of the zip-file where the model is stored. + Therefore, the typical usage is: + + #define MODEL_IDENTIFIER MyModel + #include "fmiModelFunctions.h" + + As a result, a function that is defined as "fmiGetDerivatives" in this header file, + is actually getting the name "MyModel_fmiGetDerivatives". + + Revisions: + - Jan. 20, 2010: stateValueReferencesChanged added to struct fmiEventInfo (ticket #27) + (by M. Otter, DLR) + Added WIN32 pragma to define the struct layout (ticket #34) + (by J. Mauss, QTronic) + - Jan. 4, 2010: Removed argument intermediateResults from fmiInitialize + Renamed macro fmiGetModelFunctionsVersion to fmiGetVersion + Renamed macro fmiModelFunctionsVersion to fmiVersion + Replaced fmiModel by fmiComponent in decl of fmiInstantiateModel + (by J. Mauss, QTronic) + - Dec. 17, 2009: Changed extension "me" to "fmi" (by Martin Otter, DLR). + - Dez. 14, 2009: Added eventInfo to meInitialize and added + meGetNominalContinuousStates (by Martin Otter, DLR) + - Sept. 9, 2009: Added DllExport (according to Peter Nilsson's suggestion) + (by A. Junghanns, QTronic) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + meInquireModelTypesVersion -> meGetModelTypesPlatform + meInquireModelFunctionsVersion -> meGetModelFunctionsVersion + meSetStates -> meSetContinuousStates + meGetStates -> meGetContinuousStates + removal of meInitializeModelClass + removal of meGetTime + change of arguments of meInstantiateModel + change of arguments of meCompletedIntegratorStep + (by Martin Otter, DLR): + - July 19, 2009: Added "me" as prefix to file names (by Martin Otter, DLR). + - March 2, 2009: Changed function definitions according to the last design + meeting with additional improvements (by Martin Otter, DLR). + - Dec. 3 , 2008: First version by Martin Otter (DLR) and Hans Olsson (Dynasim). + + + Copyright © 2008-2009, MODELISAR consortium. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html): + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. +*/ + +#include "fmiModelTypes.h" +#include + +/* Export fmi functions on Windows */ +#ifdef _MSC_VER +#define DllExport __declspec( dllexport ) +#else +#define DllExport +#endif + +/* Macros to construct the real function name + (prepend function name by MODEL_IDENTIFIER + "_") */ + +#define fmiPaste(a,b) a ## b +#define fmiPasteB(a,b) fmiPaste(a,b) +#define fmiFullName(name) fmiPasteB(MODEL_IDENTIFIER, name) + +#define fmiGetModelTypesPlatform fmiFullName(_fmiGetModelTypesPlatform) +#define fmiGetVersion fmiFullName(_fmiGetVersion) +#define fmiInstantiateModel fmiFullName(_fmiInstantiateModel) +#define fmiFreeModelInstance fmiFullName(_fmiFreeModelInstance) +#define fmiSetDebugLogging fmiFullName(_fmiSetDebugLogging) +#define fmiSetTime fmiFullName(_fmiSetTime) +#define fmiSetContinuousStates fmiFullName(_fmiSetContinuousStates) +#define fmiCompletedIntegratorStep fmiFullName(_fmiCompletedIntegratorStep) +#define fmiSetReal fmiFullName(_fmiSetReal) +#define fmiSetInteger fmiFullName(_fmiSetInteger) +#define fmiSetBoolean fmiFullName(_fmiSetBoolean) +#define fmiSetString fmiFullName(_fmiSetString) +#define fmiInitialize fmiFullName(_fmiInitialize) +#define fmiGetDerivatives fmiFullName(_fmiGetDerivatives) +#define fmiGetEventIndicators fmiFullName(_fmiGetEventIndicators) +#define fmiGetReal fmiFullName(_fmiGetReal) +#define fmiGetInteger fmiFullName(_fmiGetInteger) +#define fmiGetBoolean fmiFullName(_fmiGetBoolean) +#define fmiGetString fmiFullName(_fmiGetString) +#define fmiEventUpdate fmiFullName(_fmiEventUpdate) +#define fmiGetContinuousStates fmiFullName(_fmiGetContinuousStates) +#define fmiGetNominalContinuousStates fmiFullName(_fmiGetNominalContinuousStates) +#define fmiGetStateValueReferences fmiFullName(_fmiGetStateValueReferences) +#define fmiTerminate fmiFullName(_fmiTerminate) + + +/* Version number */ +#define fmiVersion "1.0" + +/* Inquire version numbers of header files */ + DllExport const char* fmiGetModelTypesPlatform(); + DllExport const char* fmiGetVersion(); + +/* make sure all compiler use the same alignment policies for structures */ +#pragma pack(push,8) + +/* Type definitions */ + typedef enum {fmiOK, + fmiWarning, + fmiDiscard, + fmiError, + fmiFatal} fmiStatus; + + typedef void (*fmiCallbackLogger) (fmiComponent c, fmiString instanceName, fmiStatus status, + fmiString category, fmiString message, ...); + typedef void* (*fmiCallbackAllocateMemory)(size_t nobj, size_t size); + typedef void (*fmiCallbackFreeMemory) (void* obj); + + typedef struct { + fmiCallbackLogger logger; + fmiCallbackAllocateMemory allocateMemory; + fmiCallbackFreeMemory freeMemory; + } fmiCallbackFunctions; + + typedef struct { + fmiBoolean iterationConverged; + fmiBoolean stateValueReferencesChanged; + fmiBoolean stateValuesChanged; + fmiBoolean terminateSimulation; + fmiBoolean upcomingTimeEvent; + fmiReal nextEventTime; + } fmiEventInfo; + +/* reset alignment policy to the one set before reading this file */ +#pragma pack(pop) + +/* Creation and destruction of model instances and setting debug status */ + DllExport fmiComponent fmiInstantiateModel (fmiString instanceName, + fmiString GUID, + fmiCallbackFunctions functions, + fmiBoolean loggingOn); + DllExport void fmiFreeModelInstance(fmiComponent c); + DllExport fmiStatus fmiSetDebugLogging (fmiComponent c, fmiBoolean loggingOn); + + +/* Providing independent variables and re-initialization of caching */ + DllExport fmiStatus fmiSetTime (fmiComponent c, fmiReal time); + DllExport fmiStatus fmiSetContinuousStates (fmiComponent c, const fmiReal x[], size_t nx); + DllExport fmiStatus fmiCompletedIntegratorStep(fmiComponent c, fmiBoolean* callEventUpdate); + DllExport fmiStatus fmiSetReal (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]); + DllExport fmiStatus fmiSetInteger (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]); + DllExport fmiStatus fmiSetBoolean (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]); + DllExport fmiStatus fmiSetString (fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]); + + +/* Evaluation of the model equations */ + DllExport fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, + fmiReal relativeTolerance, fmiEventInfo* eventInfo); + + DllExport fmiStatus fmiGetDerivatives (fmiComponent c, fmiReal derivatives[] , size_t nx); + DllExport fmiStatus fmiGetEventIndicators(fmiComponent c, fmiReal eventIndicators[], size_t ni); + + DllExport fmiStatus fmiGetReal (fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]); + DllExport fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]); + DllExport fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]); + DllExport fmiStatus fmiGetString (fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]); + + DllExport fmiStatus fmiEventUpdate (fmiComponent c, fmiBoolean intermediateResults, fmiEventInfo* eventInfo); + DllExport fmiStatus fmiGetContinuousStates (fmiComponent c, fmiReal states[], size_t nx); + DllExport fmiStatus fmiGetNominalContinuousStates(fmiComponent c, fmiReal x_nominal[], size_t nx); + DllExport fmiStatus fmiGetStateValueReferences (fmiComponent c, fmiValueReference vrx[], size_t nx); + DllExport fmiStatus fmiTerminate (fmiComponent c); + +#endif // fmiModelFunctions_h diff --git a/include/fmiModelTypes.h b/include/fmiModelTypes.h new file mode 100644 index 0000000..41db809 --- /dev/null +++ b/include/fmiModelTypes.h @@ -0,0 +1,91 @@ +#ifndef fmiModelTypes_h +#define fmiModelTypes_h + +/* Standard header file to define the argument types of the + functions of the Model Execution Interface. + This header file must be utilized both by the model and + by the simulation engine. + + Revisions: + - Jan. 4, 2010: Renamed meModelTypes_h to fmiModelTypes_h (by Mauss, QTronic) + - Dec. 21, 2009: Changed "me" to "fmi" and "meModel" to "fmiComponent" + according to meeting on Dec. 18 (by Martin Otter, DLR) + - Dec. 6, 2009: Added meUndefinedValueReference (by Martin Otter, DLR) + - Sept. 9, 2009: Changes according to FMI-meeting on July 21: + Changed "version" to "platform", "standard" to "standard32", + Added a precise definition of "standard32" as comment + (by Martin Otter, DLR) + - July 19, 2009: Added "me" as prefix to file names, added meTrue/meFalse, + and changed meValueReferenced from int to unsigned int + (by Martin Otter, DLR). + - March 2, 2009: Moved enums and function pointer definitions to + ModelFunctions.h (by Martin Otter, DLR). + - Dec. 3, 2008 : First version by Martin Otter (DLR) and + Hans Olsson (Dynasim). + + + Copyright © 2008-2010, MODELISAR consortium. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html) + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- + + with the extension: + + You may distribute or publicly perform any modification only under the + terms of this license. +*/ + +/* Platform (combination of machine, compiler, operating system) */ +#define fmiModelTypesPlatform "standard32" + +/* Type definitions of variables passed as arguments + Version "standard32" means: + + fmiComponent : 32 bit pointer + fmiValueReference: 32 bit + fmiReal : 64 bit + fmiInteger : 32 bit + fmiBoolean : 8 bit + fmiString : 32 bit pointer + +*/ + typedef void* fmiComponent; + typedef unsigned int fmiValueReference; + typedef double fmiReal ; + typedef int fmiInteger; + typedef char fmiBoolean; + typedef const char* fmiString ; + +/* Values for fmiBoolean */ +#define fmiTrue 1 +#define fmiFalse 0 + +/* Undefined value for fmiValueReference (largest unsigned int value) */ +#define fmiUndefinedValueReference (fmiValueReference)(-1) + +#endif diff --git a/include/fmiPlatformTypes.h b/include/fmiPlatformTypes.h new file mode 100644 index 0000000..e714496 --- /dev/null +++ b/include/fmiPlatformTypes.h @@ -0,0 +1,73 @@ +#ifndef fmiPlatformTypes_h +#define fmiPlatformTypes_h + +/* Standard header file to define the argument types of the + functions of the Model Execution Interface. + This header file must be utilized both by the model and + by the simulation engine. + + Revisions: + - October 2010: First public Version + + + Copyright © 2008-2010, MODELISAR consortium. All rights reserved. + This file is licensed by the copyright holders under the BSD License + (http://www.opensource.org/licenses/bsd-license.html): + + + ---------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------- +*/ + +/* Platform (combination of machine, compiler, operating system) */ +#define fmiPlatform "standard32" + +/* Type definitions of variables passed as arguments + Version "standard32" means: + + fmiComponent : 32 bit pointer + fmiValueReference: 32 bit + fmiReal : 64 bit + fmiInteger : 32 bit + fmiBoolean : 8 bit + fmiString : 32 bit pointer + +*/ + typedef void* fmiComponent; + typedef unsigned int fmiValueReference; + typedef double fmiReal ; + typedef int fmiInteger; + typedef char fmiBoolean; + typedef const char* fmiString ; + +/* Values for fmiBoolean */ +#define fmiTrue 1 +#define fmiFalse 0 + +/* Undefined value for fmiValueReference (largest unsigned int value) */ +#define fmiUndefinedValueReference (fmiValueReference)(-1) + +#endif diff --git a/include/model.h b/include/model.h new file mode 100644 index 0000000..5835b9a --- /dev/null +++ b/include/model.h @@ -0,0 +1,132 @@ +#ifndef model_h +#define model_h + +#include // for size_t +#include // for bool + +#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) + +typedef enum { + modelInstantiated = 1<<0, + modelInitialized = 1<<1, + modelTerminated = 1<<2, + modelError = 1<<3 +} ModelState; + +#else + +typedef enum { + modelStartAndEnd = 1<<0, + modelInstantiated = 1<<1, + modelInitializationMode = 1<<2, + + // ME states + modelEventMode = 1<<3, + modelContinuousTimeMode = 1<<4, + + // CS states + modelStepComplete = 1<<5, + modelStepInProgress = 1<<6, + modelStepFailed = 1<<7, + modelStepCanceled = 1<<8, + + modelTerminated = 1<<9, + modelError = 1<<10, + modelFatal = 1<<11, +} ModelState; + +#endif + +typedef enum { + ModelExchange, + CoSimulation +} InterfaceType; + +typedef enum { + OK, + Warning, + Discard, + Error, + Fatal, + Pending +} Status; + + +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 + bool loggingOn; + bool logCategories[NUMBER_OF_CATEGORIES]; + + void *componentEnvironment; + ModelState state; + + // event info + bool newDiscreteStatesNeeded; + bool terminateSimulation; + bool nominalsOfContinuousStatesChanged; + bool valuesOfContinuousStatesChanged; + bool nextEventTimeDefined; + double nextEventTime; + + bool isDirtyValues; + bool isNewEventIteration; + + ModelData *modelData; + void *solverData; + +} ModelInstance; + +// shorthand to access the variables +#define M(v) (comp->modelData->v) + +void setStartValues(ModelInstance *comp); +void calculateValues(ModelInstance *comp); + +Status getReal(ModelInstance* comp, ValueReference vr, double *value); +Status getInteger(ModelInstance* comp, ValueReference vr, int *value); +Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value); + +Status setReal(ModelInstance* comp, ValueReference vr, double value); +Status setInteger(ModelInstance* comp, ValueReference vr, int value); +Status setBoolean(ModelInstance* comp, ValueReference vr, bool value); + +void getContinuousStates(ModelInstance *comp, double x[], size_t nx); +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx); +void getDerivatives(ModelInstance *comp, double dx[], size_t nx); +void getEventIndicators(ModelInstance *comp, double z[], size_t nz); +void eventUpdate(ModelInstance *comp); + +void logError(ModelInstance *comp, const char *message, ...); + +#endif /* model_h */ diff --git a/include/slave.h b/include/slave.h new file mode 100644 index 0000000..83cdd40 --- /dev/null +++ b/include/slave.h @@ -0,0 +1,8 @@ +#ifndef slave_h +#define slave_h + +#include "model.h" + +Status doStep(ModelInstance *comp, double t, double tNext); + +#endif /* slave_h */ diff --git a/include/solver.h b/include/solver.h new file mode 100644 index 0000000..3740f36 --- /dev/null +++ b/include/solver.h @@ -0,0 +1,13 @@ +#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/logo.svg b/logo.svg new file mode 100644 index 0000000..1082344 --- /dev/null +++ b/logo.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/run.py b/run.py new file mode 100644 index 0000000..aba3539 --- /dev/null +++ b/run.py @@ -0,0 +1,105 @@ +""" Simulate the FMUs, generate the reference results and plots and convert the readme.md files to HTML """ + +from fmpy import simulate_fmu +from fmpy.util import plot_result, write_csv, read_csv +import os +import markdown2 + + +header = """ + + + +
+""" + +footer = """ +
+ + +""" + +dist_dir = os.path.dirname(__file__) +dist_dir = os.path.join(dist_dir, 'build', 'dist') + +src_dir = os.path.dirname(__file__) + +info = [ + ('BouncingBall', {}, 0.01), + ('Dahlquist', {}, 0.2), + ('Feedthrough', {'real_fixed_param': 1}, 0.2), + ('Resource', {}, 0.2), + ('Stair', {}, 10), + ('VanDerPol', {}, 0.1), +] + +for model_name, start_values, output_interval in info: + print(model_name) + fmu = os.path.join(dist_dir, model_name + '.fmu') + + ref_csv = os.path.join(src_dir, model_name, model_name + '_ref.csv') + ref_png = os.path.join(src_dir, model_name, model_name + '_ref.svg') + in_csv = os.path.join(src_dir, model_name, model_name + '_in.csv') + + if os.path.isfile(in_csv): + input = read_csv(in_csv) + else: + input = None + + result = simulate_fmu(fmu, + fmi_type='ModelExchange', + # solver='Euler', + start_values=start_values, + input=input, + output_interval=output_interval + ) + + write_csv(ref_csv, result) + ref = read_csv(ref_csv) + plot_result(ref, events=True, filename=ref_png) + + md_file = os.path.join(src_dir, model_name, 'readme.md') + html_file = os.path.join(src_dir, model_name, 'readme.html') + + md = markdown2.markdown_path(md_file, extras=['tables', 'fenced-code-blocks']) + + with open(html_file, 'w') as html: + html.write(header) + html.write(md) + html.write(footer) diff --git a/src/euler.c b/src/euler.c new file mode 100644 index 0000000..d5b3bc5 --- /dev/null +++ b/src/euler.c @@ -0,0 +1,83 @@ +/**************************************************************** + * 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/fmi1.c b/src/fmi1.c new file mode 100644 index 0000000..a128caf --- /dev/null +++ b/src/fmi1.c @@ -0,0 +1,770 @@ +/**************************************************************** + * 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 "solver.h" +#include "slave.h" + + +#ifdef FMI_COSIMULATION +#include "fmiFunctions.h" +#else +#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 + +#ifndef DT_EVENT_DETECT +#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); +} + +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); + 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; + comp->logger(comp, comp->instanceName, fmiError, "error", + "%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; + comp->logger(comp, comp->instanceName, fmiError, "error", + "%s: Invalid argument %s = NULL.", f, arg); + return fmiTrue; + } + return fmiFalse; +} + +// --------------------------------------------------------------------------- +// Private helpers used below to implement functions +// --------------------------------------------------------------------------- + +fmiStatus setString(fmiComponent comp, fmiValueReference vr, fmiString value){ + return fmiSetString(comp, &vr, 1, &value); +} + +// 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; + 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; + if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", fname); + comp->state = modelTerminated; + 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 +// --------------------------------------------------------------------------- + +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; + if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", + "fmiSetDebugLogging: loggingOn=%d", loggingOn); + comp->loggingOn = loggingOn; + return fmiOK; +} + +fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) { +#ifdef SET_REAL + int i; + Status status = OK; + + 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; + + if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", + "fmiSetReal: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + status = max(status, setReal(comp, vr[i], value[i])); + if (status > Warning) return status; + } + + return status; +#else + return fmiError; // not implemented +#endif +} + +fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]) { +#ifdef SET_INTEGER + int i; + Status status = OK; + + 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; + + if (comp->loggingOn) + comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetInteger: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + status = max(status, setInteger(comp, vr[i], value[i])); + if (status > Warning) return status; + } + + return status; +#else + return fmiError; // not implemented +#endif +} + +fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]){ +#ifdef SET_BOOLEAN + int i; + Status status = OK; + + 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; + + if (comp->loggingOn) + comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetBoolean: nvr = %d", nvr); + + for (i = 0; i < nvr; i++) { + status = max(status, setBoolean(comp, vr[i], value[i] != fmiFalse)); + if (status > Warning) return status; + } + + return status; +#else + return fmiError; // not implemented +#endif +} + +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[]) { + int i; + + 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; + + for (i=0; i 0 && nullPointer(comp, "fmiGetInteger", "vr[]", vr)) + return fmiError; + + if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "value[]", value)) + return fmiError; + + + for (i = 0; i < nvr; i++) { + getInteger(comp, vr[i], &value[i]); + } + + return fmiOK; +} + +fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) { + + int i; + + 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; + + for (i=0; i < nvr; i++) { + getBoolean(comp, vr[i], &value[i]); + } + + return fmiOK; +} + +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 instantiateModel("fmiInstantiateSlave", instanceName, GUID, fmuLocation, functions, loggingOn); +} + +fmiStatus fmiInitializeSlave(fmiComponent c, fmiReal tStart, fmiBoolean StopTimeDefined, fmiReal tStop) { + init(c); + return fmiOK; +} + +fmiStatus fmiTerminateSlave(fmiComponent c) { + return terminate("fmiTerminateSlave", c); +} + +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; +} + +void fmiFreeSlaveInstance(fmiComponent c) { +// ModelInstance* comp = (ModelInstance *)c; +// if (invalidState(comp, "fmiFreeSlaveInstance", modelTerminated)) +// return; +// freeInstance("fmiFreeSlaveInstance", 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; + 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; +} + +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 instantiateModel("fmiInstantiateModel", instanceName, GUID, NULL, functions, loggingOn); +} + +fmiStatus fmiInitialize(fmiComponent c, fmiBoolean toleranceControlled, fmiReal relativeTolerance, fmiEventInfo* eventInfo) { + return init(c); +} + +fmiStatus fmiSetTime(fmiComponent c, fmiReal time) { + + ModelInstance* comp = (ModelInstance *)c; + + 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; +} + +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; + + if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", + "fmiEventUpdate: intermediateResults = %d", intermediateResults); + + 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; + + if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiCompletedIntegratorStep"); + + 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 "solver.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" + + +// 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 +#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 +// --------------------------------------------------------------------------- + +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 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) + 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; + FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "%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; + FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "%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; + //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) + return fmi2Error; +} + +static void notImplemented(ModelInstance* comp, const char *f) { + comp->state = modelError; + FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "Function %s is not implemented", f) +} + +fmi2Status setString(fmi2Component comp, fmi2ValueReference vr, fmi2String value) { + return fmi2SetString(comp, &vr, 1, &value); +} + +// --------------------------------------------------------------------------- +// 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) { + // 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 = fmi2True; // because we just called setStartValues + + comp->solverData = solver_create(comp); + + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2Instantiate: GUID=%s", fmuGUID) + + return comp; +} + +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; + + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetupExperiment: toleranceDefined=%d tolerance=%g", + toleranceDefined, tolerance) + + comp->time = startTime; + + return fmi2OK; +} + +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; +} + +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 + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2Terminate") + + comp->state = modelTerminated; + return fmi2OK; +} + +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 = fmi2True; // 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; + + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2FreeInstance") + + 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 +// --------------------------------------------------------------------------- + +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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetDebugLogging") + + // 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; + +#ifdef GET_REAL + int i; + Status status = OK; + 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 = fmi2False; + } + + for (i = 0; i < nvr; i++) { + status = max(status, getReal(comp, vr[i], &value[i])); + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetReal: #r%u# = %.16g", vr[i], value[i]) + if (status > Warning) return status; + } + + return status; +#else + notImplemented(comp, "getReal"); + return fmi2Error; // not implemented +#endif +} + +fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) { + + int i; + Status status = OK; + + 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 = fmi2False; + } + +#ifdef GET_INTEGER + for (i = 0; i < nvr; i++) { + status = max(status, getInteger(comp, vr[i], &value[i])); + if (status > Warning) return status; + } + + return status; +#else + return fmi2Error; // not implemented +#endif +} + +fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) { + int i; + Status status = OK; + + 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 = fmi2False; + } + +#ifdef GET_BOOLEAN + for (i = 0; i < nvr; i++) { + status = max(status, getBoolean(comp, vr[i], &value[i])); + if (status > Warning) return status; + } + + return status; +#else + return fmi2Error; // not implemented +#endif +} + +fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { + int i; + 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 = fmi2False; + } + +#ifdef SET_STRING + for (i=0; is[vr[i]]; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetString: #s%u# = '%s'", vr[i], value[i]) + } +#else + return fmi2Error; +#endif + return fmi2OK; +} + +fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) { +#ifdef SET_REAL + int i; + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: nvr = %d", nvr) + + // no check whether setting the value is allowed in the current state + for (i = 0; i < nvr; i++) { + if (setReal(comp, vr[i], value[i]) > Warning) return fmi2Error; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: #r%d# = %.16g", vr[i], value[i]) + } + + if (nvr > 0) comp->isDirtyValues = fmi2True; + return fmi2OK; +#else + return fmi2Error; +#endif +} + +fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) { + int i; + Status status = OK; + + 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; + + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetInteger: nvr = %d", nvr) + +#ifdef SET_INTEGER + for (i = 0; i < nvr; i++) { + status = max(status, setInteger(comp, vr[i], value[i])); + if (status > Warning) return status; + } + if (nvr > 0) comp->isDirtyValues = fmi2True; + return status; +#else + return fmi2Error; // not implemented +#endif +} + +fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) { + int i; + + 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; + + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetBoolean: nvr = %d", nvr) + +#ifdef SET_BOOLEAN + for (i = 0; i < nvr; i++) { + if (setBoolean(comp, vr[i], value[i]) > Warning) return fmi2Error; + } + + if (nvr > 0) comp->isDirtyValues = fmi2True; + + return fmi2OK; +#else + return fmi2Error; // not implemented +#endif +} + +fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { + int i; + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetString: nvr = %d", nvr) + +#ifdef SET_STRING + for (i = 0; i < nvr; i++) { + char *string = (char *)comp->s[vr[i]]; + if (vrOutOfRange(comp, "fmi2SetString", vr[i], NUMBER_OF_STRINGS)) + return fmi2Error; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetString: #s%d# = '%s'", vr[i], value[i]) + + if (value[i] == NULL) { + if (string) comp->functions->freeMemory(string); + comp->s[vr[i]] = NULL; + FILTERED_LOG(comp, fmi2Warning, LOG_ERROR, "fmi2SetString: 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; + FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "fmi2SetString: Out of memory.") + return fmi2Error; + } + } + strcpy((char *)comp->s[vr[i]], (char *)value[i]); + } + } + if (nvr > 0) comp->isDirtyValues = fmi2True; +#else + return fmi2Error; +#endif + + return fmi2OK; +} + +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; + } + 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\"") + 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; + 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\"") + 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; + } + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2CancelStep") + FILTERED_LOG(comp, fmi2Error, LOG_ERROR,"fmi2CancelStep: Can be called when fmi2DoStep returned fmi2Pending." + " This is not the case."); + // comp->state = modelStepCanceled; + return fmi2Error; +} + +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) + 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; + 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; + } + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2EnterEventMode") + + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2NewDiscreteStates") + + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL,"fmi2EnterContinuousTimeMode") + + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL,"fmi2CompletedIntegratorStep") + *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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetTime: time=%.16g", time) + comp->time = time; + return fmi2OK; +} + +fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t nx){ + ModelInstance *comp = (ModelInstance *)c; + int i; + 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); + +//#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; +} + +/* Evaluation of the model equations */ +fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx) { + int i; + + 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; + 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 new file mode 100644 index 0000000..a214373 --- /dev/null +++ b/src/fmi3.c @@ -0,0 +1,955 @@ +/**************************************************************** + * 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 "solver.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" + + +// 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 +#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 +// --------------------------------------------------------------------------- + +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 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) + 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; + FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "%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; + FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "%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; + //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) + return fmi3Error; +} + +static void notImplemented(ModelInstance* comp, const char *f) { + comp->state = modelError; + FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "Function %s is not implemented", f) +} + +fmi3Status setString(fmi3Component comp, fmi3ValueReference vr, fmi3String value) { + //return fmi3SetString(comp, &vr, 1, &value); + 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) { + // 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); // to be implemented by the includer of this file + comp->isDirtyValues = fmi3True; // because we just called setStartValues + + comp->solverData = solver_create(comp); + + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3Instantiate: GUID=%s", fmuGUID) + + return comp; +} + +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; + + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetupExperiment: toleranceDefined=%d tolerance=%g", + toleranceDefined, tolerance) + + comp->time = startTime; + + return fmi3OK; +} + +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; +} + +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 + if (comp->isDirtyValues) { + calculateValues(comp); + comp->isDirtyValues = fmi3False; + } + + 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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3Terminate") + + comp->state = modelTerminated; + return fmi3OK; +} + +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); // to be implemented by the includer of this file + comp->isDirtyValues = fmi3True; // because we just called setStartValues + return fmi3OK; +} + +void fmi3FreeInstance(fmi3Component c) { + + ModelInstance *comp = (ModelInstance *)c; + + if (!comp) return; + + if (invalidState(comp, "fmi3FreeInstance", MASK_fmi3FreeInstance)) + return; + + 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); +} + +// --------------------------------------------------------------------------- +// 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; + 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]); + } + } + } + return fmi3OK; +} + +fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 value[], size_t nValues) { + + ModelInstance *comp = (ModelInstance *)c; + +#ifdef GET_REAL + int i; + Status status = OK; + 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 = fmi3False; + } + + for (i = 0; i < nvr; i++) { + status = max(status, getReal(comp, vr[i], &value[i])); + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetReal: #r%u# = %.16g", vr[i], value[i]) + if (status > Warning) return status; + } + + return status; +#else + notImplemented(comp, "getReal"); + return fmi3Error; // not implemented +#endif +} + +fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Int32 value[], size_t nValues) { + + int i; + Status status = OK; + + 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 = fmi3False; + } + +#ifdef GET_INTEGER + for (i = 0; i < nvr; i++) { + status = max(status, getInteger(comp, vr[i], &value[i])); + if (status > Warning) return status; + } + + return status; +#else + return fmi3Error; // not implemented +#endif +} + +fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) { + int i; + Status status = OK; + + 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 = fmi3False; + } + +#ifdef GET_BOOLEAN + for (i = 0; i < nvr; i++) { + status = max(status, getBoolean(comp, vr[i], &value[i])); + if (status > Warning) return status; + } + + return status; +#else + return fmi3Error; // not implemented +#endif +} + +fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { + int i; + 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 = fmi3False; + } + +#ifdef SET_STRING + for (i=0; is[vr[i]]; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetString: #s%u# = '%s'", vr[i], value[i]) + } +#else + return fmi3Error; +#endif + return fmi3OK; +} + +fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { +#ifdef SET_REAL + int i; + 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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: nvr = %d", nvr) + + // no check whether setting the value is allowed in the current state + for (i = 0; i < nvr; i++) { + if (setReal(comp, vr[i], value[i]) > Warning) return fmi3Error; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: #r%d# = %.16g", vr[i], value[i]) + } + + if (nvr > 0) comp->isDirtyValues = fmi3True; + return fmi3OK; +#else + return fmi3Error; +#endif +} + +fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Int32 value[], size_t nValues) { + int i; + Status status = OK; + + 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; + + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetInteger: nvr = %d", nvr) + +#ifdef SET_INTEGER + for (i = 0; i < nvr; i++) { + status = max(status, setInteger(comp, vr[i], value[i])); + if (status > Warning) return status; + } + if (nvr > 0) comp->isDirtyValues = fmi3True; + return status; +#else + return fmi3Error; // not implemented +#endif +} + +fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) { + int i; + + 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; + + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetBoolean: nvr = %d", nvr) + +#ifdef SET_BOOLEAN + for (i = 0; i < nvr; i++) { + if (setBoolean(comp, vr[i], value[i]) > Warning) return fmi3Error; + } + + if (nvr > 0) comp->isDirtyValues = fmi3True; + + return fmi3OK; +#else + return fmi3Error; // not implemented +#endif +} + +fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { + int i; + 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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetString: nvr = %d", nvr) + +#ifdef SET_STRING + for (i = 0; i < nvr; i++) { + char *string = (char *)comp->s[vr[i]]; + if (vrOutOfRange(comp, "fmi3SetString", vr[i], NUMBER_OF_STRINGS)) + return fmi3Error; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetString: #s%d# = '%s'", vr[i], value[i]) + + if (value[i] == NULL) { + if (string) comp->functions->freeMemory(string); + comp->s[vr[i]] = NULL; + FILTERED_LOG(comp, fmi3Warning, LOG_ERROR, "fmi3SetString: 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; + FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "fmi3SetString: Out of memory.") + return fmi3Error; + } + } + strcpy((char *)comp->s[vr[i]], (char *)value[i]); + } + } + if (nvr > 0) comp->isDirtyValues = fmi3True; +#else + return fmi3Error; +#endif + + return fmi3OK; +} + +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); +} + +//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; + 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." + " This is not the case."); + // comp->state = modelStepCanceled; + 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") + + if (communicationStepSize <= 0) { + FILTERED_LOG(comp, fmi3Error, LOG_ERROR, + "fmi3DoStep: communication step size must be > 0. Fount %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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3EnterEventMode") + + 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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3NewDiscreteStates") + + 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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL,"fmi3EnterContinuousTimeMode") + + 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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL,"fmi3CompletedIntegratorStep") + *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; + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetTime: time=%.16g", time) + comp->time = time; + return fmi3OK; +} + +fmi3Status fmi3SetContinuousStates(fmi3Component c, const fmi3Float64 x[], size_t nx){ + ModelInstance *comp = (ModelInstance *)c; + int i; + 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); + +//#if NUMBER_OF_STATES>0 +// for (i = 0; i < nx; i++) { +// fmi3ValueReference vr = vrStates[i]; +// FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetContinuousStates: #r%d#=%.16g", vr, x[i]) +// assert(vr < NUMBER_OF_REALS); +// comp->r[vr] = x[i]; +// } +//#endif + return fmi3OK; +} + +/* Evaluation of the model equations */ +fmi3Status fmi3GetDerivatives(fmi3Component c, fmi3Float64 derivatives[], size_t nx) { + int i; + + 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; + 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 new file mode 100644 index 0000000..272573b --- /dev/null +++ b/src/slave.c @@ -0,0 +1,81 @@ +/**************************************************************** + * 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 "config.h" +#include "slave.h" +#include "solver.h" + + +// default implementations +#if NUMBER_OF_EVENT_INDICATORS < 1 +void getEventIndicators(ModelInstance *comp, double z[], size_t nz) { + // do nothing +} +#endif + +#ifndef GET_REAL +Status getReal(ModelInstance* comp, ValueReference vr, double *value) { + return Error; +} +#endif + +#ifndef GET_INTEGER +Status getInteger(ModelInstance* comp, ValueReference vr, int *value) { + return Error; +} +#endif + +#ifndef GET_BOOLEAN +Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value) { + return Error; +} +#endif + +#if NUMBER_OF_STATES < 1 +void getContinuousStates(ModelInstance *comp, double x[], size_t nx) {} +void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) {} +void getDerivatives(ModelInstance *comp, double dx[], size_t nx) {} +#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); + } + + // check for time event + if (comp->nextEventTimeDefined && (comp->time - comp->nextEventTime > -1e-5)) { + timeEvent = true; + } + + if (stateEvent || timeEvent) { + eventUpdate(comp); + timeEvent = 0; + stateEvent = 0; + } + + // terminate simulation, if requested by the model in the previous step + if (comp->terminateSimulation) { +#if FMI_VERSION > 1 + comp->state = modelStepFailed; +#endif + return Discard; // enforce termination of the simulation loop + } + + } + + return OK; +} diff --git a/test_build.py b/test_build.py new file mode 100644 index 0000000..d2fd464 --- /dev/null +++ b/test_build.py @@ -0,0 +1,141 @@ +import unittest +import subprocess +import os +import shutil + +try: + from fmpy import simulate_fmu + fmpy_available = True +except: + print("FMPy not available. Skipping simulation.") + fmpy_available = False + + +fmi3_available = False + +try: + import fmpy + fmi3_available = 'fmi3' in dir(fmpy) +except: + pass + +if not fmi3_available: + print("FMI 3.0 support in FMPy not available. Skipping FMI 3.0 simulation.") + + +test_fmus_dir = os.path.dirname(__file__) + +models = ['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol', 'Feedthrough'] + +if os.name == 'nt': + generator = 'Visual Studio 14 2015 Win64' +else: + generator = 'Unix Makefiles' + + +class BuildTest(unittest.TestCase): + """ Build all variants of the Test FMUs and simulate the default experiment """ + + @classmethod + def setUpClass(cls): + # clean up + for name in ['fmi1_me', 'fmi1_cs', 'fmi2', 'fmi3']: + build_dir = os.path.join(test_fmus_dir, name) + if os.path.isdir(build_dir): + print("Removing " + build_dir) + shutil.rmtree(build_dir) + + def validate(self, build_dir, fmi_types=['ModelExchange', 'CoSimulation'], models=models): + + from fmpy.util import read_csv, validate_result + + for model in models: + + print(model) + + fmu_filename = os.path.join(build_dir, 'dist', model + '.fmu') + + if model == 'Feedthrough': + start_values = {'real_fixed_param': 1} + in_csv = os.path.join(test_fmus_dir, model, model + '_in.csv') + input = read_csv(in_csv) + else: + start_values = {} + input = None + + ref_csv = os.path.join(test_fmus_dir, model, model + '_ref.csv') + + for fmi_type in fmi_types: + ref = read_csv(ref_csv) + + result = simulate_fmu(fmu_filename, + fmi_type=fmi_type, + start_values=start_values, + input=input) + + dev = validate_result(result, ref) + + self.assertLess(dev, 0.2, "Failed to validate " + model) + + def test_fmi1_me(self): + + build_dir = os.path.join(test_fmus_dir, 'fmi1_me') + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + subprocess.call(['cmake', '-G', generator, '-DFMI_VERSION=1', '-DFMI_TYPE=ME', '..'], cwd=build_dir) + subprocess.call(['cmake', '--build', '.', '--config', 'Release'], cwd=build_dir) + + if fmpy_available: + self.validate(build_dir, + fmi_types=['ModelExchange'], + models=['BouncingBall', 'Dahlquist', 'Stair', 'VanDerPol'] #, 'Feedthrough' +) + + def test_fmi1_cs(self): + + build_dir = os.path.join(test_fmus_dir, 'fmi1_cs') + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + subprocess.call(['cmake', '-G', generator, '-DFMI_VERSION=1', '-DFMI_TYPE=CS', '..'], cwd=build_dir) + subprocess.call(['cmake', '--build', '.', '--config', 'Release'], cwd=build_dir) + + if fmpy_available: + self.validate(build_dir, + fmi_types=['CoSimulation'], + models=['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol']) # , 'Feedthrough' + + def test_fmi2(self): + + build_dir = os.path.join(test_fmus_dir, 'fmi2') + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + subprocess.call(['cmake', '-G', generator, '-DFMI_VERSION=2', '..'], cwd=build_dir) + subprocess.call(['cmake', '--build', '.', '--config', 'Release'], cwd=build_dir) + + if fmpy_available: + self.validate(build_dir) + + def test_fmi3(self): + + print('FMI 3.0') + + build_dir = os.path.join(test_fmus_dir, 'fmi3') + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + subprocess.call(['cmake', '-G', 'Unix Makefiles', '-DFMI_VERSION=3', '..'], cwd=build_dir) + subprocess.call(['cmake', '--build', '.'], cwd=build_dir) + + if fmi3_available: + self.validate(build_dir, models=['BouncingBall', 'Dahlquist', 'Feedthrough', 'Resource', 'Stair', 'VanDerPol']) + + +if __name__ == '__main__': + unittest.main() From 52a0735ba014d3affc38253bbbd8e17b891a1be6 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 21 Feb 2019 17:14:50 +0100 Subject: [PATCH 02/16] Add prototype of LinearTransform FMU --- CMakeLists.txt | 2 +- LinearTransform/FMI3.xml | 64 +++ LinearTransform/LinearTransform_ref.svg | 573 ++++++++++++++++++++++++ LinearTransform/config.h | 30 ++ LinearTransform/model.c | 81 ++++ LinearTransform/readme.html | 45 ++ LinearTransform/readme.md | 7 + include/model.h | 4 +- src/fmi3.c | 14 +- 9 files changed, 815 insertions(+), 5 deletions(-) create mode 100644 LinearTransform/FMI3.xml create mode 100644 LinearTransform/LinearTransform_ref.svg create mode 100644 LinearTransform/config.h create mode 100644 LinearTransform/model.c create mode 100644 LinearTransform/readme.html create mode 100644 LinearTransform/readme.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c13081..2bba3dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ endif () MESSAGE("FMI_PLATFORM: " ${FMI_PLATFORM}) -foreach (MODEL_NAME BouncingBall Dahlquist Stair Feedthrough Resource VanDerPol) +foreach (MODEL_NAME LinearTransform) #BouncingBall Dahlquist Stair Feedthrough Resource VanDerPol) set(TARGET_NAME ${MODEL_NAME}) diff --git a/LinearTransform/FMI3.xml b/LinearTransform/FMI3.xml new file mode 100644 index 0000000..810a08f --- /dev/null +++ b/LinearTransform/FMI3.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LinearTransform/LinearTransform_ref.svg b/LinearTransform/LinearTransform_ref.svg new file mode 100644 index 0000000..a0a12d7 --- /dev/null +++ b/LinearTransform/LinearTransform_ref.svg @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LinearTransform/config.h b/LinearTransform/config.h new file mode 100644 index 0000000..0863d40 --- /dev/null +++ b/LinearTransform/config.h @@ -0,0 +1,30 @@ +#ifndef config_h +#define config_h + +// define class name and unique id +#define MODEL_IDENTIFIER LinearTransform +#define MODEL_GUID "{8c4e810f-3df3-4a00-8276-176fa3c9f000}" + +// define model size +#define NUMBER_OF_STATES 0 +#define NUMBER_OF_EVENT_INDICATORS 0 + +#define GET_REAL +#define SET_REAL +#define EVENT_UPDATE + +typedef enum { + vr_m, vr_n, vr_u, vr_A, vr_y +} ValueReference; + +typedef struct { + + int m; + int n; + double u[3]; + double A[2][3]; + double y[2]; + +} ModelData; + +#endif /* config_h */ diff --git a/LinearTransform/model.c b/LinearTransform/model.c new file mode 100644 index 0000000..59f1eab --- /dev/null +++ b/LinearTransform/model.c @@ -0,0 +1,81 @@ +#include "config.h" +#include "model.h" + + +void setStartValues(ModelInstance *comp) { + + M(m) = 2; + + M(n) = 3; + + M(A)[0][0] = 1; M(A)[0][1] = 1; M(A)[0][2] = 0; + M(A)[1][0] = 0; M(A)[1][1] = 1; M(A)[1][2] = 1; + + M(u)[0] = 0; + M(u)[1] = 1; + M(u)[2] = 2; + + M(y)[0] = 0; + M(y)[1] = 0; +} + +void calculateValues(ModelInstance *comp) { + + M(y)[0] = M(A)[0][0] * M(u)[0] + M(A)[0][1] * M(u)[1] + M(A)[0][2] * M(u)[2]; + M(y)[1] = M(A)[1][0] * M(u)[0] + M(A)[1][1] * M(u)[1] + M(A)[1][2] * M(u)[2]; + +} + +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { + + //calculateValues(comp); + +// size_t i = *index; +// size_t *ii = &i; +// *index = 0; + + logError(comp, "getReal(vr=%d)", vr); + + switch (vr) { + case vr_m: + value[(*index)++] = M(m); + return OK; + case vr_n: + value[(*index)++] = M(n); + return OK; + case vr_u: + value[(*index)++] = M(u)[0]; + value[(*index)++] = M(u)[1]; + value[(*index)++] = M(u)[2]; + return OK; + case vr_A: + value[(*index)++] = M(A)[0][0]; + value[(*index)++] = M(A)[0][1]; + value[(*index)++] = M(A)[0][2]; + value[(*index)++] = M(A)[1][0]; + value[(*index)++] = M(A)[1][1]; + value[(*index)++] = M(A)[1][2]; + return OK; + case vr_y: + value[0] = (*index)++; + //(*index) += 1; //M(y)[0]; + value[1] = (*index)++; //M(y)[1]; + return OK; + default: + return Error; + } +} + +Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { + switch (vr) { + default: + return Error; + } +} + +void eventUpdate(ModelInstance *comp) { + comp->valuesOfContinuousStatesChanged = false; + comp->nominalsOfContinuousStatesChanged = false; + comp->terminateSimulation = false; + comp->nextEventTimeDefined = false; +} diff --git a/LinearTransform/readme.html b/LinearTransform/readme.html new file mode 100644 index 0000000..bdf6ae6 --- /dev/null +++ b/LinearTransform/readme.html @@ -0,0 +1,45 @@ + + + + +
+

LinearTransform

+
+ + diff --git a/LinearTransform/readme.md b/LinearTransform/readme.md new file mode 100644 index 0000000..3b8619c --- /dev/null +++ b/LinearTransform/readme.md @@ -0,0 +1,7 @@ +# LinearTransform + +Implements the equation + +``` +y = u * A +``` diff --git a/include/model.h b/include/model.h index 5835b9a..9f1eb78 100644 --- a/include/model.h +++ b/include/model.h @@ -113,11 +113,11 @@ typedef struct { void setStartValues(ModelInstance *comp); void calculateValues(ModelInstance *comp); -Status getReal(ModelInstance* comp, ValueReference vr, double *value); +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index); Status getInteger(ModelInstance* comp, ValueReference vr, int *value); Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value); -Status setReal(ModelInstance* comp, ValueReference vr, double value); +Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index); Status setInteger(ModelInstance* comp, ValueReference vr, int value); Status setBoolean(ModelInstance* comp, ValueReference vr, bool value); diff --git a/src/fmi3.c b/src/fmi3.c index a214373..8515cf6 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -459,9 +459,16 @@ fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ calculateValues(comp); comp->isDirtyValues = fmi3False; } + + size_t index = 0; + + logError(comp, "nvr=%d", nvr); for (i = 0; i < nvr; i++) { - status = max(status, getReal(comp, vr[i], &value[i])); + + logError(comp, "i=%d", i); + + status = max(status, getReal(comp, vr[i], value, &index)); FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetReal: #r%u# = %.16g", vr[i], value[i]) if (status > Warning) return status; } @@ -568,6 +575,8 @@ fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { #ifdef SET_REAL int i; + size_t index = 0; + fmi3Status status = fmi3OK; ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3SetReal", MASK_fmi3SetReal)) return fmi3Error; @@ -579,7 +588,8 @@ fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ // no check whether setting the value is allowed in the current state for (i = 0; i < nvr; i++) { - if (setReal(comp, vr[i], value[i]) > Warning) return fmi3Error; + status = max(status, setReal(comp, vr[i], value, &index)); + if (status > Warning) return status; FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: #r%d# = %.16g", vr[i], value[i]) } From b34de2a06cebed46730f50ed6d5804d60c1575b5 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 21 Feb 2019 21:56:54 +0100 Subject: [PATCH 03/16] Fix get / set Real and add index pointer --- LinearTransform/model.c | 21 ++++++++++----------- src/fmi3.c | 11 ++++------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/LinearTransform/model.c b/LinearTransform/model.c index 59f1eab..9080805 100644 --- a/LinearTransform/model.c +++ b/LinearTransform/model.c @@ -28,14 +28,8 @@ void calculateValues(ModelInstance *comp) { Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { - //calculateValues(comp); - -// size_t i = *index; -// size_t *ii = &i; -// *index = 0; - - logError(comp, "getReal(vr=%d)", vr); - + calculateValues(comp); + switch (vr) { case vr_m: value[(*index)++] = M(m); @@ -57,9 +51,8 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in value[(*index)++] = M(A)[1][2]; return OK; case vr_y: - value[0] = (*index)++; - //(*index) += 1; //M(y)[0]; - value[1] = (*index)++; //M(y)[1]; + value[(*index)++] = M(y)[0]; + value[(*index)++] = M(y)[1]; return OK; default: return Error; @@ -68,6 +61,12 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { + case vr_u: + M(u)[0] = value[(*index)++]; + M(u)[1] = value[(*index)++]; + M(u)[2] = value[(*index)++]; + calculateValues(comp); + return OK; default: return Error; } diff --git a/src/fmi3.c b/src/fmi3.c index 8515cf6..f06d2cd 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -462,13 +462,9 @@ fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ size_t index = 0; - logError(comp, "nvr=%d", nvr); - for (i = 0; i < nvr; i++) { - - logError(comp, "i=%d", i); - - status = max(status, getReal(comp, vr[i], value, &index)); + Status s = getReal(comp, vr[i], value, &index); + status = max(status, s); FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetReal: #r%u# = %.16g", vr[i], value[i]) if (status > Warning) return status; } @@ -588,7 +584,8 @@ fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ // no check whether setting the value is allowed in the current state for (i = 0; i < nvr; i++) { - status = max(status, setReal(comp, vr[i], value, &index)); + Status s = setReal(comp, vr[i], value, &index); + status = max(status, s); if (status > Warning) return status; FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: #r%d# = %.16g", vr[i], value[i]) } From b06debb398469824813d1d186f9bcc59c50346e1 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 21 Feb 2019 22:36:48 +0100 Subject: [PATCH 04/16] Adapt getters and setters to arrays --- BouncingBall/model.c | 22 ++++++++--------- CMakeLists.txt | 8 ++++++- Dahlquist/model.c | 14 +++++------ Feedthrough/model.c | 56 ++++++++++++++++++++++---------------------- Resource/model.c | 16 ++++++------- Stair/model.c | 9 ++++--- VanDerPol/model.c | 22 ++++++++--------- include/model.h | 8 +++---- src/fmi2.c | 32 +++++++++++++++++++------ src/slave.c | 6 ++--- 10 files changed, 110 insertions(+), 83 deletions(-) diff --git a/BouncingBall/model.c b/BouncingBall/model.c index 06073f3..bb6223b 100644 --- a/BouncingBall/model.c +++ b/BouncingBall/model.c @@ -18,37 +18,37 @@ void calculateValues(ModelInstance *comp) { // do nothing } -Status getReal(ModelInstance* comp, ValueReference vr, double *value) { +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { switch (vr) { case vr_h: - *value = M(h); + value[(*index)++] = M(h); return OK; case vr_v: - *value = M(v); + value[(*index)++] = M(v); return OK; case vr_g: - *value = M(g); + value[(*index)++] = M(g); return OK; case vr_e: - *value = M(e); + value[(*index)++] = M(e); return OK; case vr_v_min: - *value = V_MIN; + value[(*index)++] = V_MIN; return OK; default: return Error; } } -Status setReal(ModelInstance* comp, ValueReference vr, double value) { +Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_h: - M(h) = value; + M(h) = value[(*index)++]; return OK; case vr_v: - M(v) = value; + M(v) = value[(*index)++]; return OK; case vr_g: @@ -60,7 +60,7 @@ Status setReal(ModelInstance* comp, ValueReference vr, double value) { return Error; } #endif - M(g) = value; + M(g) = value[(*index)++]; return OK; case vr_e: @@ -73,7 +73,7 @@ Status setReal(ModelInstance* comp, ValueReference vr, double value) { return Error; } #endif - M(e) = value; + M(e) = value[(*index)++]; return OK; default: diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bba3dd..74192cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,13 @@ endif () MESSAGE("FMI_PLATFORM: " ${FMI_PLATFORM}) -foreach (MODEL_NAME LinearTransform) #BouncingBall Dahlquist Stair Feedthrough Resource VanDerPol) +set (MODEL_NAMES BouncingBall Dahlquist Stair Feedthrough Resource VanDerPol) + +if (${FMI_VERSION} GREATER 2) + set (MODEL_NAMES ${MODEL_NAMES} LinearTransform) +endif () + +foreach (MODEL_NAME ${MODEL_NAMES}) # Dahlquist Stair Feedthrough Resource VanDerPol) set(TARGET_NAME ${MODEL_NAME}) diff --git a/Dahlquist/model.c b/Dahlquist/model.c index f5b1c62..dd00844 100644 --- a/Dahlquist/model.c +++ b/Dahlquist/model.c @@ -11,27 +11,27 @@ void calculateValues(ModelInstance *comp) { M(der_x) = -M(k) * M(x); } -Status getReal(ModelInstance* comp, ValueReference vr, double *value) { +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_x: - *value = M(x); + value[(*index)++] = M(x); return OK; case vr_der_x: - *value = M(der_x); + value[(*index)++] = M(der_x); return OK; case vr_k: - *value = M(k); + value[(*index)++] = M(k); return OK; default: return Error; } } -Status setReal(ModelInstance* comp, ValueReference vr, double value) { +Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_x: - M(x) = value; + M(x) = value[(*index)++]; return OK; case vr_k: #if FMI_VERSION > 1 @@ -42,7 +42,7 @@ Status setReal(ModelInstance* comp, ValueReference vr, double value) { return Error; } #endif - M(k) = value; + M(k) = value[(*index)++]; return OK; default: return Error; diff --git a/Feedthrough/model.c b/Feedthrough/model.c index 06791ce..9d46aa2 100644 --- a/Feedthrough/model.c +++ b/Feedthrough/model.c @@ -16,73 +16,73 @@ void calculateValues(ModelInstance *comp) { // do nothing } -Status getReal(ModelInstance* comp, ValueReference vr, double *value) { +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_continuous_real_in: - *value = M(real_continuous_in); + value[(*index)++] = M(real_continuous_in); return OK; case vr_continuous_real_out: - *value = M(real_fixed_parameter) + M(real_tunable_parameter) + M(real_continuous_in); + value[(*index)++] = M(real_fixed_parameter) + M(real_tunable_parameter) + M(real_continuous_in); return OK; case vr_discrete_real_in: case vr_discrete_real_out: - *value = M(real_discrete); + value[(*index)++] = M(real_discrete); return OK; case vr_fixed_real_parameter: - *value = M(real_fixed_parameter); + value[(*index)++] = M(real_fixed_parameter); return OK; case vr_tunable_real_parameter: - *value = M(real_tunable_parameter); + value[(*index)++] = M(real_tunable_parameter); return OK; default: return Error; } } -Status getInteger(ModelInstance* comp, ValueReference vr, int *value) { +Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_int_in: - *value = M(integer); + value[(*index)++] = M(integer); return OK; case vr_int_out: - *value = M(integer); + value[(*index)++] = M(integer); return OK; default: return Error; } } -Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value) { +Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_bool_in: - *value = M(boolean); + value[(*index)++] = M(boolean); return OK; case vr_bool_out: - *value = M(boolean); + value[(*index)++] = M(boolean); return OK; default: return Error; } } -Status setReal(ModelInstance* comp, ValueReference vr, double value) { +Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { - + case vr_fixed_real_parameter: #if FMI_VERSION > 1 - if (comp->type == ModelExchange && + if (comp->type == ModelExchange && comp->state != modelInstantiated && comp->state != modelInitializationMode) { logError(comp, "Variable fixed_real_parameter can only be set after instantiation or in initialization mode."); return Error; } #endif - M(real_fixed_parameter) = value; + M(real_fixed_parameter) = value[(*index)++]; return OK; - + case vr_tunable_real_parameter: #if FMI_VERSION > 1 - if (comp->type == ModelExchange && + if (comp->type == ModelExchange && comp->state != modelInstantiated && comp->state != modelInitializationMode && comp->state != modelEventMode) { @@ -90,13 +90,13 @@ Status setReal(ModelInstance* comp, ValueReference vr, double value) { return Error; } #endif - M(real_tunable_parameter) = value; + M(real_tunable_parameter) = value[(*index)++]; return OK; - + case vr_continuous_real_in: - M(real_continuous_in) = value; + M(real_continuous_in) = value[(*index)++]; return OK; - + case vr_discrete_real_in: #if FMI_VERSION > 1 if (comp->type == ModelExchange && @@ -106,24 +106,24 @@ Status setReal(ModelInstance* comp, ValueReference vr, double value) { return Error; } #endif - M(real_discrete) = value; + M(real_discrete) = value[(*index)++]; return OK; - + default: return Error; } } -Status setInteger(ModelInstance* comp, ValueReference vr, int value) { +Status setInteger(ModelInstance* comp, ValueReference vr, const int *value, size_t *index) { switch (vr) { - case vr_int_in: M(integer) = value; return OK; + case vr_int_in: M(integer) = value[(*index)++]; return OK; default: return Error; } } -Status setBoolean(ModelInstance* comp, ValueReference vr, bool value) { +Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, size_t *index) { switch (vr) { - case vr_bool_in: M(boolean) = value; return OK; + case vr_bool_in: M(boolean) = value[(*index)++]; return OK; default: return Error; } } diff --git a/Resource/model.c b/Resource/model.c index 02a9a94..de86d8e 100644 --- a/Resource/model.c +++ b/Resource/model.c @@ -11,7 +11,7 @@ void setStartValues(ModelInstance *comp) { void calculateValues(ModelInstance *comp) { // load the file - + FILE *file; char *path; char c; @@ -27,7 +27,7 @@ void calculateValues(ModelInstance *comp) { // FMI 1.0 for Model Exchange doesn't have a resource location return; } - + if (strncmp(comp->resourceLocation, scheme1, strlen(scheme1)) == 0) { path = malloc(strlen(comp->resourceLocation) + strlen(resourcePath) + 1); strcpy(path, &comp->resourceLocation[strlen(scheme1)] - 1); @@ -46,26 +46,26 @@ void calculateValues(ModelInstance *comp) { strcpy(path, &path[1]); } #endif - + // open the resource file file = fopen (path, "r"); - + if (!file) { logError(comp, "Failed to open resource file %s.", path); return; } - + // read the first character c = fgetc(file); - + // assign it to y comp->modelData->y = c; - + // clost the file fclose(file); } -Status getReal(ModelInstance* comp, ValueReference vr, double *value) { +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { switch (vr) { case vr_y: *value = M(y); diff --git a/Stair/model.c b/Stair/model.c index 813f8f8..e648912 100644 --- a/Stair/model.c +++ b/Stair/model.c @@ -14,10 +14,13 @@ void calculateValues(ModelInstance *comp) { // do nothing } -Status getInteger(ModelInstance* comp, ValueReference vr, int *value) { +Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { switch (vr) { - case vr_counter: *value = M(counter); return OK; - default: return Error; + case vr_counter: + value[(*index)++] = M(counter); + return OK; + default: + return Error; } } diff --git a/VanDerPol/model.c b/VanDerPol/model.c index 8557d5f..07427f4 100644 --- a/VanDerPol/model.c +++ b/VanDerPol/model.c @@ -13,36 +13,36 @@ void calculateValues(ModelInstance *comp) { M(der_x1) = M(mu) * ((1.0 - M(x0) * M(x0)) * M(x1)) - M(x0); } -Status getReal(ModelInstance* comp, ValueReference vr, double *value) { +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_x0: - *value = M(x0); + value[(*index)++] = M(x0); return OK; case vr_der_x0 : - *value = M(der_x0); + value[(*index)++] = M(der_x0); return OK; case vr_x1: - *value = M(x1); + value[(*index)++] = M(x1); return OK; - case vr_der_x1: - *value = M(der_x1); + case vr_der_x1: + value[(*index)++] = M(der_x1); return OK; case vr_mu: - *value = M(mu); + value[(*index)++] = M(mu); return OK; default: return Error; } } -Status setReal(ModelInstance* comp, ValueReference vr, double value) { +Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_x0: - M(x0 = value); + M(x0) = value[(*index)++]; return OK; case vr_x1: - M(x1 = value); + M(x1) = value[(*index)++]; return OK; case vr_mu: #if FMI_VERSION > 1 @@ -54,7 +54,7 @@ Status setReal(ModelInstance* comp, ValueReference vr, double value) { return Error; } #endif - M(mu = value); + M(mu) = value[(*index)++]; return OK; default: return Error; diff --git a/include/model.h b/include/model.h index 9f1eb78..88d6796 100644 --- a/include/model.h +++ b/include/model.h @@ -114,12 +114,12 @@ void setStartValues(ModelInstance *comp); void calculateValues(ModelInstance *comp); Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index); -Status getInteger(ModelInstance* comp, ValueReference vr, int *value); -Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value); +Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index); +Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *index); Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index); -Status setInteger(ModelInstance* comp, ValueReference vr, int value); -Status setBoolean(ModelInstance* comp, ValueReference vr, bool value); +Status setInteger(ModelInstance* comp, ValueReference vr, const int *value, size_t *index); +Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, size_t *index); void getContinuousStates(ModelInstance *comp, double x[], size_t nx); void setContinuousStates(ModelInstance *comp, const double x[], size_t nx); diff --git a/src/fmi2.c b/src/fmi2.c index 67b3ea3..6769061 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -456,8 +456,11 @@ fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n comp->isDirtyValues = fmi2False; } + size_t index = 0; + for (i = 0; i < nvr; i++) { - status = max(status, getReal(comp, vr[i], &value[i])); + Status s = getReal(comp, vr[i], value, &index); + status = max(status, s); FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetReal: #r%u# = %.16g", vr[i], value[i]) if (status > Warning) return status; } @@ -491,8 +494,11 @@ fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t } #ifdef GET_INTEGER + size_t index = 0; + for (i = 0; i < nvr; i++) { - status = max(status, getInteger(comp, vr[i], &value[i])); + Status s = getInteger(comp, vr[i], value, &index); + status = max(status, s); if (status > Warning) return status; } @@ -523,11 +529,15 @@ fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t } #ifdef GET_BOOLEAN + size_t index = 0; + for (i = 0; i < nvr; i++) { - status = max(status, getBoolean(comp, vr[i], &value[i])); + bool v = value[i]; + Status s = getBoolean(comp, vr[i], &v, &index); + status = max(status, s); if (status > Warning) return status; } - + return status; #else return fmi2Error; // not implemented @@ -573,9 +583,12 @@ fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n return fmi2Error; FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: nvr = %d", nvr) + size_t index = 0; + // no check whether setting the value is allowed in the current state for (i = 0; i < nvr; i++) { - if (setReal(comp, vr[i], value[i]) > Warning) return fmi2Error; + Status s = setReal(comp, vr[i], value, &index); + if (s > Warning) return fmi2Error; FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: #r%d# = %.16g", vr[i], value[i]) } @@ -604,8 +617,10 @@ fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetInteger: nvr = %d", nvr) #ifdef SET_INTEGER + size_t index = 0; for (i = 0; i < nvr; i++) { - status = max(status, setInteger(comp, vr[i], value[i])); + Status s = setInteger(comp, vr[i], value, &index); + status = max(status, s); if (status > Warning) return status; } if (nvr > 0) comp->isDirtyValues = fmi2True; @@ -632,8 +647,11 @@ fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetBoolean: nvr = %d", nvr) #ifdef SET_BOOLEAN + for (i = 0; i < nvr; i++) { - if (setBoolean(comp, vr[i], value[i]) > Warning) return fmi2Error; + bool v = value[i]; + size_t index = 0; + if (setBoolean(comp, vr[i], &v, &index) > Warning) return fmi2Error; } if (nvr > 0) comp->isDirtyValues = fmi2True; diff --git a/src/slave.c b/src/slave.c index 272573b..f5889b0 100644 --- a/src/slave.c +++ b/src/slave.c @@ -17,19 +17,19 @@ void getEventIndicators(ModelInstance *comp, double z[], size_t nz) { #endif #ifndef GET_REAL -Status getReal(ModelInstance* comp, ValueReference vr, double *value) { +Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { return Error; } #endif #ifndef GET_INTEGER -Status getInteger(ModelInstance* comp, ValueReference vr, int *value) { +Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { return Error; } #endif #ifndef GET_BOOLEAN -Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value) { +Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *index) { return Error; } #endif From db8a808c76b49c3a0928f1cddbab9b61242d006b Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 22 Feb 2019 09:56:01 +0100 Subject: [PATCH 05/16] Fix integer typedefs for FMI 3.0 --- include/fmi3TypesPlatform.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fmi3TypesPlatform.h b/include/fmi3TypesPlatform.h index d44d50a..6218863 100644 --- a/include/fmi3TypesPlatform.h +++ b/include/fmi3TypesPlatform.h @@ -66,10 +66,10 @@ typedef int8_t fmi3Int8; /* 8-bit signed integer */ typedef uint8_t fmi3UInt8; /* 8-bit unsigned integer */ typedef int16_t fmi3Int16; /* 16-bit signed integer */ typedef uint16_t fmi3UInt16; /* 16-bit unsigned integer */ -typedef int16_t fmi3Int32; /* 32-bit signed integer */ -typedef uint16_t fmi3UInt32; /* 32-bit unsigned integer */ -typedef int16_t fmi3Int64; /* 64-bit signed integer */ -typedef uint16_t fmi3UInt64; /* 64-bit unsigned integer */ +typedef int32_t fmi3Int32; /* 32-bit signed integer */ +typedef uint32_t fmi3UInt32; /* 32-bit unsigned integer */ +typedef int64_t fmi3Int64; /* 64-bit signed integer */ +typedef uint64_t fmi3UInt64; /* 64-bit unsigned integer */ typedef int fmi3Boolean; /* Data type to be used with fmi3True and fmi3False */ typedef char fmi3Char; /* Data type for one character */ typedef const fmi3Char* fmi3String; /* Data type for character strings From af990813f0bafba5004b2334c29965436e27aeec Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 22 Feb 2019 14:40:25 +0100 Subject: [PATCH 06/16] Add arrays to getters / setters for all FMI versions --- src/fmi1.c | 67 ++++++++++++++++++++++++++++++++++++++++-------------- src/fmi2.c | 3 ++- src/fmi3.c | 55 ++++++++++++++++++++++++++++---------------- 3 files changed, 87 insertions(+), 38 deletions(-) diff --git a/src/fmi1.c b/src/fmi1.c index a128caf..5f8210a 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -233,8 +233,6 @@ fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn) { fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) { #ifdef SET_REAL - int i; - Status status = OK; ModelInstance* comp = (ModelInstance *)c; @@ -249,9 +247,14 @@ fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, c if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetReal: nvr = %d", nvr); - + + int i; + Status status = OK; + size_t index = 0; + for (i = 0; i < nvr; i++) { - status = max(status, setReal(comp, vr[i], value[i])); + Status s = setReal(comp, vr[i], value, &index); + status = max(status, s); if (status > Warning) return status; } @@ -263,8 +266,6 @@ fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, c fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiInteger value[]) { #ifdef SET_INTEGER - int i; - Status status = OK; ModelInstance* comp = (ModelInstance *)c; @@ -280,11 +281,18 @@ fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetInteger: nvr = %d", nvr); + int i; + Status status = OK; + size_t index = 0; + for (i = 0; i < nvr; i++) { - status = max(status, setInteger(comp, vr[i], value[i])); + Status s = setInteger(comp, vr[i], value, &index); + status = max(status, s); if (status > Warning) return status; } + if (nvr > 0) comp->isDirtyValues = true; + return status; #else return fmiError; // not implemented @@ -311,11 +319,15 @@ fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetBoolean: nvr = %d", nvr); for (i = 0; i < nvr; i++) { - status = max(status, setBoolean(comp, vr[i], value[i] != fmiFalse)); - if (status > Warning) return status; + bool v = value[i]; + size_t index = 0; + if (setBoolean(comp, vr[i], &v, &index) > Warning) return fmiError; } + + if (nvr > 0) comp->isDirtyValues = true; + + return fmiOK; - return status; #else return fmiError; // not implemented #endif @@ -373,9 +385,16 @@ fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, f if (nvr > 0 && nullPointer(comp, "fmiGetReal", "value[]", value)) return fmiError; - for (i=0; i Warning) return status; } + + return status; return fmiOK; } @@ -394,18 +413,22 @@ fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "value[]", value)) return fmiError; + size_t index = 0; + Status status = OK; for (i = 0; i < nvr; i++) { - getInteger(comp, vr[i], &value[i]); + Status s = getInteger(comp, vr[i], value, &index); + status = max(status, s); + if (status > Warning) return status; } + + return status; return fmiOK; } fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) { - int i; - ModelInstance* comp = (ModelInstance *)c; if (invalidState(comp, "fmiGetBoolean", not_modelError)) @@ -417,9 +440,19 @@ fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "value[]", value)) return fmiError; - for (i=0; i < nvr; i++) { - getBoolean(comp, vr[i], &value[i]); + int i; + size_t index = 0; + Status status = OK; + + for (i = 0; i < nvr; i++) { + bool v = false; + Status s = getBoolean(comp, vr[i], &v, &index); + value[i] = v; + status = max(status, s); + if (status > Warning) return status; } + + return status; return fmiOK; } diff --git a/src/fmi2.c b/src/fmi2.c index 6769061..65d0a57 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -532,8 +532,9 @@ fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t size_t index = 0; for (i = 0; i < nvr; i++) { - bool v = value[i]; + bool v = false; Status s = getBoolean(comp, vr[i], &v, &index); + value[i] = v; status = max(status, s); if (status > Warning) return status; } diff --git a/src/fmi3.c b/src/fmi3.c index f06d2cd..7a748a3 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -478,9 +478,6 @@ fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Int32 value[], size_t nValues) { - int i; - Status status = OK; - ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi3GetInteger", MASK_fmi3GetInteger)) @@ -498,8 +495,11 @@ fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n } #ifdef GET_INTEGER - for (i = 0; i < nvr; i++) { - status = max(status, getInteger(comp, vr[i], &value[i])); + Status status = OK; + size_t index = 0; + + for (int i = 0; i < nvr; i++) { + status = max(status, getInteger(comp, vr[i], value, &index)); if (status > Warning) return status; } @@ -510,8 +510,6 @@ fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n } fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) { - int i; - Status status = OK; ModelInstance *comp = (ModelInstance *)c; @@ -530,11 +528,17 @@ fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t } #ifdef GET_BOOLEAN - for (i = 0; i < nvr; i++) { - status = max(status, getBoolean(comp, vr[i], &value[i])); + Status status = OK; + + for (int i = 0; i < nvr; i++) { + size_t index = 0; + bool v = false; + Status s = getBoolean(comp, vr[i], &v, &index); + value[i] = v; + status = max(status, s); if (status > Warning) return status; } - + return status; #else return fmi3Error; // not implemented @@ -598,8 +602,6 @@ fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ } fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Int32 value[], size_t nValues) { - int i; - Status status = OK; ModelInstance *comp = (ModelInstance *)c; @@ -615,11 +617,18 @@ fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetInteger: nvr = %d", nvr) #ifdef SET_INTEGER + int i; + Status status = OK; + size_t index = 0; + for (i = 0; i < nvr; i++) { - status = max(status, setInteger(comp, vr[i], value[i])); + Status s = setInteger(comp, vr[i], value, &index); + status = max(status, s); if (status > Warning) return status; } - if (nvr > 0) comp->isDirtyValues = fmi3True; + + if (nvr > 0) comp->isDirtyValues = true; + return status; #else return fmi3Error; // not implemented @@ -627,7 +636,6 @@ fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n } fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) { - int i; ModelInstance *comp = (ModelInstance *)c; @@ -643,13 +651,20 @@ fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetBoolean: nvr = %d", nvr) #ifdef SET_BOOLEAN + int i; + Status status = OK; + for (i = 0; i < nvr; i++) { - if (setBoolean(comp, vr[i], value[i]) > Warning) return fmi3Error; + bool v = value[i]; + size_t index = 0; + Status s = setBoolean(comp, vr[i], &v, &index); + status = max(status, s); + if (status > Warning) return status; } - - if (nvr > 0) comp->isDirtyValues = fmi3True; - - return fmi3OK; + + if (nvr > 0) comp->isDirtyValues = true; + + return status; #else return fmi3Error; // not implemented #endif From f830397045d6506655d00a5992c0fed075e47470 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 22 Feb 2019 15:50:26 +0100 Subject: [PATCH 07/16] Add GET / SET_VARIABLES macros --- BouncingBall/config.h | 4 +- BouncingBall/model.c | 4 +- Dahlquist/config.h | 4 +- Dahlquist/model.c | 4 +- Feedthrough/config.h | 8 ++-- Feedthrough/model.c | 8 ++-- LinearTransform/config.h | 4 +- LinearTransform/model.c | 4 +- Resource/config.h | 2 +- Resource/model.c | 2 +- Stair/config.h | 2 +- Stair/model.c | 2 +- VanDerPol/config.h | 4 +- VanDerPol/model.c | 4 +- include/model.h | 35 +++++++++++++---- src/fmi1.c | 66 +++++++------------------------ src/fmi2.c | 85 ++++++++++++---------------------------- src/fmi3.c | 70 ++++++++------------------------- src/slave.c | 8 ++-- 19 files changed, 117 insertions(+), 203 deletions(-) diff --git a/BouncingBall/config.h b/BouncingBall/config.h index 6ffaeb6..c5bd308 100644 --- a/BouncingBall/config.h +++ b/BouncingBall/config.h @@ -9,8 +9,8 @@ #define NUMBER_OF_STATES 2 #define NUMBER_OF_EVENT_INDICATORS 1 -#define GET_REAL -#define SET_REAL +#define GET_FLOAT64 +#define SET_FLOAT64 #define EVENT_UPDATE typedef enum { diff --git a/BouncingBall/model.c b/BouncingBall/model.c index bb6223b..9656b36 100644 --- a/BouncingBall/model.c +++ b/BouncingBall/model.c @@ -18,7 +18,7 @@ void calculateValues(ModelInstance *comp) { // do nothing } -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { switch (vr) { case vr_h: value[(*index)++] = M(h); @@ -40,7 +40,7 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in } } -Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_h: diff --git a/Dahlquist/config.h b/Dahlquist/config.h index 2b7fada..43c4bbf 100644 --- a/Dahlquist/config.h +++ b/Dahlquist/config.h @@ -9,8 +9,8 @@ #define NUMBER_OF_STATES 1 #define NUMBER_OF_EVENT_INDICATORS 0 -#define GET_REAL -#define SET_REAL +#define GET_FLOAT64 +#define SET_FLOAT64 #define EVENT_UPDATE typedef enum { diff --git a/Dahlquist/model.c b/Dahlquist/model.c index dd00844..167b912 100644 --- a/Dahlquist/model.c +++ b/Dahlquist/model.c @@ -11,7 +11,7 @@ void calculateValues(ModelInstance *comp) { M(der_x) = -M(k) * M(x); } -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_x: @@ -28,7 +28,7 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in } } -Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_x: M(x) = value[(*index)++]; diff --git a/Feedthrough/config.h b/Feedthrough/config.h index 886fa4e..29621d5 100644 --- a/Feedthrough/config.h +++ b/Feedthrough/config.h @@ -12,12 +12,12 @@ #define NUMBER_OF_STATES 0 #define NUMBER_OF_EVENT_INDICATORS 0 -#define GET_REAL -#define GET_INTEGER +#define GET_FLOAT64 +#define GET_INT32 #define GET_BOOLEAN -#define SET_REAL -#define SET_INTEGER +#define SET_FLOAT64 +#define SET_INT32 #define SET_BOOLEAN #define EVENT_UPDATE diff --git a/Feedthrough/model.c b/Feedthrough/model.c index 9d46aa2..2f3e651 100644 --- a/Feedthrough/model.c +++ b/Feedthrough/model.c @@ -16,7 +16,7 @@ void calculateValues(ModelInstance *comp) { // do nothing } -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_continuous_real_in: @@ -39,7 +39,7 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in } } -Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { +Status getInt32(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_int_in: @@ -65,7 +65,7 @@ Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *i } } -Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_fixed_real_parameter: @@ -114,7 +114,7 @@ Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size } } -Status setInteger(ModelInstance* comp, ValueReference vr, const int *value, size_t *index) { +Status setInt32(ModelInstance* comp, ValueReference vr, const int *value, size_t *index) { switch (vr) { case vr_int_in: M(integer) = value[(*index)++]; return OK; default: return Error; diff --git a/LinearTransform/config.h b/LinearTransform/config.h index 0863d40..2b359de 100644 --- a/LinearTransform/config.h +++ b/LinearTransform/config.h @@ -9,8 +9,8 @@ #define NUMBER_OF_STATES 0 #define NUMBER_OF_EVENT_INDICATORS 0 -#define GET_REAL -#define SET_REAL +#define GET_FLOAT64 +#define SET_FLOAT64 #define EVENT_UPDATE typedef enum { diff --git a/LinearTransform/model.c b/LinearTransform/model.c index 9080805..5da2e04 100644 --- a/LinearTransform/model.c +++ b/LinearTransform/model.c @@ -26,7 +26,7 @@ void calculateValues(ModelInstance *comp) { } -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); @@ -59,7 +59,7 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in } } -Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_u: M(u)[0] = value[(*index)++]; diff --git a/Resource/config.h b/Resource/config.h index 4c43038..1e52d53 100644 --- a/Resource/config.h +++ b/Resource/config.h @@ -9,7 +9,7 @@ #define NUMBER_OF_STATES 0 #define NUMBER_OF_EVENT_INDICATORS 0 -#define GET_REAL +#define GET_FLOAT64 typedef enum { vr_y diff --git a/Resource/model.c b/Resource/model.c index de86d8e..222ef3f 100644 --- a/Resource/model.c +++ b/Resource/model.c @@ -65,7 +65,7 @@ void calculateValues(ModelInstance *comp) { fclose(file); } -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { switch (vr) { case vr_y: *value = M(y); diff --git a/Stair/config.h b/Stair/config.h index 3af04de..f5aafa5 100644 --- a/Stair/config.h +++ b/Stair/config.h @@ -9,7 +9,7 @@ #define NUMBER_OF_STATES 0 #define NUMBER_OF_EVENT_INDICATORS 0 -#define GET_INTEGER +#define GET_INT32 #define EVENT_UPDATE typedef enum { diff --git a/Stair/model.c b/Stair/model.c index e648912..6b9fca0 100644 --- a/Stair/model.c +++ b/Stair/model.c @@ -14,7 +14,7 @@ void calculateValues(ModelInstance *comp) { // do nothing } -Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { +Status getInt32(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { switch (vr) { case vr_counter: value[(*index)++] = M(counter); diff --git a/VanDerPol/config.h b/VanDerPol/config.h index 1c02abe..636bca8 100644 --- a/VanDerPol/config.h +++ b/VanDerPol/config.h @@ -9,8 +9,8 @@ #define NUMBER_OF_STATES 2 #define NUMBER_OF_EVENT_INDICATORS 0 -#define GET_REAL -#define SET_REAL +#define GET_FLOAT64 +#define SET_FLOAT64 typedef enum { vr_x0, vr_der_x0, vr_x1, vr_der_x1, vr_mu diff --git a/VanDerPol/model.c b/VanDerPol/model.c index 07427f4..8d3f1e1 100644 --- a/VanDerPol/model.c +++ b/VanDerPol/model.c @@ -13,7 +13,7 @@ void calculateValues(ModelInstance *comp) { M(der_x1) = M(mu) * ((1.0 - M(x0) * M(x0)) * M(x1)) - M(x0); } -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { calculateValues(comp); switch (vr) { case vr_x0: @@ -36,7 +36,7 @@ Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *in } } -Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { switch (vr) { case vr_x0: M(x0) = value[(*index)++]; diff --git a/include/model.h b/include/model.h index 88d6796..2e5b2da 100644 --- a/include/model.h +++ b/include/model.h @@ -107,18 +107,15 @@ typedef struct { } ModelInstance; -// shorthand to access the variables -#define M(v) (comp->modelData->v) - void setStartValues(ModelInstance *comp); void calculateValues(ModelInstance *comp); -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index); -Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index); +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index); +Status getInt32(ModelInstance* comp, ValueReference vr, int *value, size_t *index); Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *index); -Status setReal(ModelInstance* comp, ValueReference vr, const double *value, size_t *index); -Status setInteger(ModelInstance* comp, ValueReference vr, const int *value, size_t *index); +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index); +Status setInt32(ModelInstance* comp, ValueReference vr, const int *value, size_t *index); Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, size_t *index); void getContinuousStates(ModelInstance *comp, double x[], size_t nx); @@ -129,4 +126,28 @@ void eventUpdate(ModelInstance *comp); void logError(ModelInstance *comp, const char *message, ...); +// shorthand to access the variables +#define M(v) (comp->modelData->v) + +#define GET_VARIABLES(T) \ +size_t index = 0; \ +Status status = OK; \ +for (int i = 0; i < nvr; i++) { \ + Status s = get ## T(comp, vr[i], value, &index); \ + status = max(status, s); \ + if (status > Warning) return status; \ +} \ +return status; + +#define SET_VARIABLES(T) \ +size_t index = 0; \ +Status status = OK; \ +for (int i = 0; i < nvr; i++) { \ + Status s = set ## T(comp, vr[i], value, &index); \ + status = max(status, s); \ + if (status > Warning) return status; \ +} \ +if (nvr > 0) comp->isDirtyValues = true; \ +return status; + #endif /* model_h */ diff --git a/src/fmi1.c b/src/fmi1.c index 5f8210a..bf6268e 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -232,7 +232,6 @@ fmiStatus fmiSetDebugLogging(fmiComponent c, fmiBoolean loggingOn) { } fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiReal value[]) { -#ifdef SET_REAL ModelInstance* comp = (ModelInstance *)c; @@ -248,24 +247,14 @@ fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, c if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetReal: nvr = %d", nvr); - int i; - Status status = OK; - size_t index = 0; - - for (i = 0; i < nvr; i++) { - Status s = setReal(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - - return status; +#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[]) { -#ifdef SET_INTEGER ModelInstance* comp = (ModelInstance *)c; @@ -281,19 +270,8 @@ fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetInteger: nvr = %d", nvr); - int i; - Status status = OK; - size_t index = 0; - - for (i = 0; i < nvr; i++) { - Status s = setInteger(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - - if (nvr > 0) comp->isDirtyValues = true; - - return status; +#ifdef SET_INT32 + SET_VARIABLES(Int32) #else return fmiError; // not implemented #endif @@ -372,7 +350,6 @@ fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, } fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiReal value[]) { - int i; ModelInstance* comp = (ModelInstance *)c; @@ -384,23 +361,15 @@ fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, f if (nvr > 0 && nullPointer(comp, "fmiGetReal", "value[]", value)) return fmiError; - - size_t index = 0; - Status status = OK; - for (i = 0; i < nvr; i++) { - Status s = getReal(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - - return status; - - return fmiOK; +#ifdef GET_FLOAT64 + GET_VARIABLES(Float64) +#else + return fmiError; // not implemented +#endif } fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]) { - int i; ModelInstance* comp = (ModelInstance *)c; @@ -413,18 +382,11 @@ fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "value[]", value)) return fmiError; - size_t index = 0; - Status status = OK; - - for (i = 0; i < nvr; i++) { - Status s = getInteger(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - - return status; - - return fmiOK; +#ifdef GET_INT32 + GET_VARIABLES(Int32) +#else + return fmiError; // not implemented +#endif } fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) { diff --git a/src/fmi2.c b/src/fmi2.c index 65d0a57..d6f4c59 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -442,30 +442,22 @@ fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n ModelInstance *comp = (ModelInstance *)c; -#ifdef GET_REAL - int i; - Status status = OK; 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 = fmi2False; } - size_t index = 0; - - for (i = 0; i < nvr; i++) { - Status s = getReal(comp, vr[i], value, &index); - status = max(status, s); - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetReal: #r%u# = %.16g", vr[i], value[i]) - if (status > Warning) return status; - } - - return status; +#ifdef GET_FLOAT64 + GET_VARIABLES(Float64) #else notImplemented(comp, "getReal"); return fmi2Error; // not implemented @@ -474,9 +466,6 @@ fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) { - int i; - Status status = OK; - ModelInstance *comp = (ModelInstance *)c; if (invalidState(comp, "fmi2GetInteger", MASK_fmi2GetInteger)) @@ -493,24 +482,14 @@ fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t comp->isDirtyValues = fmi2False; } -#ifdef GET_INTEGER - size_t index = 0; - - for (i = 0; i < nvr; i++) { - Status s = getInteger(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - - return status; +#ifdef GET_INT32 + GET_VARIABLES(Int32) #else return fmi2Error; // not implemented #endif } fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) { - int i; - Status status = OK; ModelInstance *comp = (ModelInstance *)c; @@ -530,8 +509,9 @@ fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t #ifdef GET_BOOLEAN size_t index = 0; - - for (i = 0; i < nvr; i++) { + Status status = OK; + + for (int i = 0; i < nvr; i++) { bool v = false; Status s = getBoolean(comp, vr[i], &v, &index); value[i] = v; @@ -573,36 +553,28 @@ fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t } fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) { -#ifdef SET_REAL - int i; + 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; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: nvr = %d", nvr) - size_t index = 0; - - // no check whether setting the value is allowed in the current state - for (i = 0; i < nvr; i++) { - Status s = setReal(comp, vr[i], value, &index); - if (s > Warning) return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: #r%d# = %.16g", vr[i], value[i]) - } + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: nvr = %d", nvr) - if (nvr > 0) comp->isDirtyValues = fmi2True; - return fmi2OK; +#ifdef SET_FLOAT64 + SET_VARIABLES(Float64) #else return fmi2Error; #endif } fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) { - int i; - Status status = OK; ModelInstance *comp = (ModelInstance *)c; @@ -617,22 +589,14 @@ fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetInteger: nvr = %d", nvr) -#ifdef SET_INTEGER - size_t index = 0; - for (i = 0; i < nvr; i++) { - Status s = setInteger(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - if (nvr > 0) comp->isDirtyValues = fmi2True; - return status; +#ifdef SET_INT32 + SET_VARIABLES(Int32) #else return fmi2Error; // not implemented #endif } fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) { - int i; ModelInstance *comp = (ModelInstance *)c; @@ -648,8 +612,7 @@ fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetBoolean: nvr = %d", nvr) #ifdef SET_BOOLEAN - - for (i = 0; i < nvr; i++) { + for (int i = 0; i < nvr; i++) { bool v = value[i]; size_t index = 0; if (setBoolean(comp, vr[i], &v, &index) > Warning) return fmi2Error; @@ -664,18 +627,22 @@ fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t } fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { - int i; + 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; + FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetString: nvr = %d", nvr) #ifdef SET_STRING - for (i = 0; i < nvr; i++) { + for (int i = 0; i < nvr; i++) { char *string = (char *)comp->s[vr[i]]; if (vrOutOfRange(comp, "fmi2SetString", vr[i], NUMBER_OF_STRINGS)) return fmi2Error; diff --git a/src/fmi3.c b/src/fmi3.c index 7a748a3..ff86805 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -446,33 +446,24 @@ fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ ModelInstance *comp = (ModelInstance *)c; -#ifdef GET_REAL - int i; - Status status = OK; 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 = fmi3False; } - size_t index = 0; - - for (i = 0; i < nvr; i++) { - Status s = getReal(comp, vr[i], value, &index); - status = max(status, s); - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetReal: #r%u# = %.16g", vr[i], value[i]) - if (status > Warning) return status; - } - - return status; +#ifdef GET_FLOAT64 + GET_VARIABLES(Float64) #else - notImplemented(comp, "getReal"); - return fmi3Error; // not implemented + return fmi3Error; #endif } @@ -494,16 +485,8 @@ fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n comp->isDirtyValues = fmi3False; } -#ifdef GET_INTEGER - Status status = OK; - size_t index = 0; - - for (int i = 0; i < nvr; i++) { - status = max(status, getInteger(comp, vr[i], value, &index)); - if (status > Warning) return status; - } - - return status; +#ifdef GET_INT32 + GET_VARIABLES(Int32) #else return fmi3Error; // not implemented #endif @@ -573,29 +556,22 @@ fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t } fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { -#ifdef SET_REAL - int i; - size_t index = 0; - fmi3Status status = fmi3OK; + 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; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: nvr = %d", nvr) - // no check whether setting the value is allowed in the current state - for (i = 0; i < nvr; i++) { - Status s = setReal(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: #r%d# = %.16g", vr[i], value[i]) - } + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: nvr = %d", nvr) - if (nvr > 0) comp->isDirtyValues = fmi3True; - return fmi3OK; +#ifdef SET_FLOAT64 + SET_VARIABLES(Float64) #else return fmi3Error; #endif @@ -616,20 +592,8 @@ fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetInteger: nvr = %d", nvr) -#ifdef SET_INTEGER - int i; - Status status = OK; - size_t index = 0; - - for (i = 0; i < nvr; i++) { - Status s = setInteger(comp, vr[i], value, &index); - status = max(status, s); - if (status > Warning) return status; - } - - if (nvr > 0) comp->isDirtyValues = true; - - return status; +#ifdef SET_INT32 + SET_VARIABLES(Int32) #else return fmi3Error; // not implemented #endif diff --git a/src/slave.c b/src/slave.c index f5889b0..fade5bc 100644 --- a/src/slave.c +++ b/src/slave.c @@ -16,14 +16,14 @@ void getEventIndicators(ModelInstance *comp, double z[], size_t nz) { } #endif -#ifndef GET_REAL -Status getReal(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { +#ifndef GET_FLOAT64 +Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index) { return Error; } #endif -#ifndef GET_INTEGER -Status getInteger(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { +#ifndef GET_INT32 +Status getInt32(ModelInstance* comp, ValueReference vr, int *value, size_t *index) { return Error; } #endif From feae8f3d9dcb6c5823272276e20826a24464ea99 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 22 Feb 2019 15:54:35 +0100 Subject: [PATCH 08/16] =?UTF-8?q?Fix=20isDirtyValues=20=3D=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fmi3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fmi3.c b/src/fmi3.c index ff86805..6dc2738 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -482,7 +482,7 @@ fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n if (nvr > 0 && comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi3False; + comp->isDirtyValues = false; } #ifdef GET_INT32 @@ -507,7 +507,7 @@ fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t if (nvr > 0 && comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi3False; + comp->isDirtyValues = false; } #ifdef GET_BOOLEAN @@ -539,7 +539,7 @@ fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t return fmi3Error; if (nvr > 0 && comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi3False; + comp->isDirtyValues = false; } #ifdef SET_STRING From a491e3382f6d306fb0ef46e65b31cfeed1b97d72 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 22 Feb 2019 17:12:27 +0100 Subject: [PATCH 09/16] Add GET / SET_BOOLEAN_VARIABLES macros --- include/model.h | 25 ++++++++++++++++++++++++ src/fmi1.c | 41 ++------------------------------------ src/fmi2.c | 48 ++------------------------------------------- src/fmi3.c | 52 ++----------------------------------------------- src/slave.c | 18 +++++++++++++++++ test_build.py | 4 ++-- 6 files changed, 51 insertions(+), 137 deletions(-) diff --git a/include/model.h b/include/model.h index 2e5b2da..e28197b 100644 --- a/include/model.h +++ b/include/model.h @@ -150,4 +150,29 @@ for (int i = 0; i < nvr; i++) { \ if (nvr > 0) comp->isDirtyValues = true; \ return status; +// TODO: make this work with arrays +#define GET_BOOLEAN_VARIABLES \ +Status status = OK; \ +for (int i = 0; i < nvr; i++) { \ + bool v = false; \ + size_t index = 0; \ + Status s = getBoolean(comp, vr[i], &v, &index); \ + value[i] = v; \ + status = max(status, s); \ + if (status > Warning) return status; \ +} \ +return status; + +// TODO: make this work with arrays +#define SET_BOOLEAN_VARIABLES \ +Status status = OK; \ +for (int i = 0; i < nvr; i++) { \ + bool v = value[i]; \ + size_t index = 0; \ + Status s = setBoolean(comp, vr[i], &v, &index); \ + status = max(status, s); \ + if (status > Warning) return status; \ +} \ +return status; + #endif /* model_h */ diff --git a/src/fmi1.c b/src/fmi1.c index bf6268e..db15ae4 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -278,9 +278,6 @@ fmiStatus fmiSetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr } fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiBoolean value[]){ -#ifdef SET_BOOLEAN - int i; - Status status = OK; ModelInstance* comp = (ModelInstance *)c; @@ -296,19 +293,7 @@ fmiStatus fmiSetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetBoolean: nvr = %d", nvr); - for (i = 0; i < nvr; i++) { - bool v = value[i]; - size_t index = 0; - if (setBoolean(comp, vr[i], &v, &index) > Warning) return fmiError; - } - - if (nvr > 0) comp->isDirtyValues = true; - - return fmiOK; - -#else - return fmiError; // not implemented -#endif + SET_BOOLEAN_VARIABLES } fmiStatus fmiSetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, const fmiString value[]){ @@ -362,11 +347,7 @@ fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, f if (nvr > 0 && nullPointer(comp, "fmiGetReal", "value[]", value)) return fmiError; -#ifdef GET_FLOAT64 GET_VARIABLES(Float64) -#else - return fmiError; // not implemented -#endif } fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiInteger value[]) { @@ -382,11 +363,7 @@ fmiStatus fmiGetInteger(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr > 0 && nullPointer(comp, "fmiGetInteger", "value[]", value)) return fmiError; -#ifdef GET_INT32 GET_VARIABLES(Int32) -#else - return fmiError; // not implemented -#endif } fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiBoolean value[]) { @@ -402,21 +379,7 @@ fmiStatus fmiGetBoolean(fmiComponent c, const fmiValueReference vr[], size_t nvr if (nvr>0 && nullPointer(comp, "fmiGetBoolean", "value[]", value)) return fmiError; - int i; - size_t index = 0; - Status status = OK; - - for (i = 0; i < nvr; i++) { - bool v = false; - Status s = getBoolean(comp, vr[i], &v, &index); - value[i] = v; - status = max(status, s); - if (status > Warning) return status; - } - - return status; - - return fmiOK; + GET_BOOLEAN_VARIABLES } fmiStatus fmiGetString(fmiComponent c, const fmiValueReference vr[], size_t nvr, fmiString value[]) { diff --git a/src/fmi2.c b/src/fmi2.c index d6f4c59..af5ef5a 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -456,12 +456,7 @@ fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n comp->isDirtyValues = fmi2False; } -#ifdef GET_FLOAT64 GET_VARIABLES(Float64) -#else - notImplemented(comp, "getReal"); - return fmi2Error; // not implemented -#endif } fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Integer value[]) { @@ -482,11 +477,7 @@ fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t comp->isDirtyValues = fmi2False; } -#ifdef GET_INT32 GET_VARIABLES(Int32) -#else - return fmi2Error; // not implemented -#endif } fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2Boolean value[]) { @@ -506,23 +497,8 @@ fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t calculateValues(comp); comp->isDirtyValues = fmi2False; } - -#ifdef GET_BOOLEAN - size_t index = 0; - Status status = OK; - - for (int i = 0; i < nvr; i++) { - bool v = false; - Status s = getBoolean(comp, vr[i], &v, &index); - value[i] = v; - status = max(status, s); - if (status > Warning) return status; - } - return status; -#else - return fmi2Error; // not implemented -#endif + GET_BOOLEAN_VARIABLES } fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { @@ -567,11 +543,7 @@ fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetReal: nvr = %d", nvr) -#ifdef SET_FLOAT64 SET_VARIABLES(Float64) -#else - return fmi2Error; -#endif } fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Integer value[]) { @@ -589,11 +561,7 @@ fmi2Status fmi2SetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetInteger: nvr = %d", nvr) -#ifdef SET_INT32 SET_VARIABLES(Int32) -#else - return fmi2Error; // not implemented -#endif } fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Boolean value[]) { @@ -611,19 +579,7 @@ fmi2Status fmi2SetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetBoolean: nvr = %d", nvr) -#ifdef SET_BOOLEAN - for (int i = 0; i < nvr; i++) { - bool v = value[i]; - size_t index = 0; - if (setBoolean(comp, vr[i], &v, &index) > Warning) return fmi2Error; - } - - if (nvr > 0) comp->isDirtyValues = fmi2True; - - return fmi2OK; -#else - return fmi2Error; // not implemented -#endif + SET_BOOLEAN_VARIABLES } fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2String value[]) { diff --git a/src/fmi3.c b/src/fmi3.c index 6dc2738..9adc8f4 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -460,11 +460,7 @@ fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ comp->isDirtyValues = fmi3False; } -#ifdef GET_FLOAT64 GET_VARIABLES(Float64) -#else - return fmi3Error; -#endif } fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Int32 value[], size_t nValues) { @@ -485,11 +481,7 @@ fmi3Status fmi3GetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n comp->isDirtyValues = false; } -#ifdef GET_INT32 GET_VARIABLES(Int32) -#else - return fmi3Error; // not implemented -#endif } fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) { @@ -510,22 +502,7 @@ fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t comp->isDirtyValues = false; } -#ifdef GET_BOOLEAN - Status status = OK; - - for (int i = 0; i < nvr; i++) { - size_t index = 0; - bool v = false; - Status s = getBoolean(comp, vr[i], &v, &index); - value[i] = v; - status = max(status, s); - if (status > Warning) return status; - } - - return status; -#else - return fmi3Error; // not implemented -#endif + GET_BOOLEAN_VARIABLES } fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { @@ -570,11 +547,7 @@ fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetReal: nvr = %d", nvr) -#ifdef SET_FLOAT64 SET_VARIABLES(Float64) -#else - return fmi3Error; -#endif } fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Int32 value[], size_t nValues) { @@ -592,11 +565,7 @@ fmi3Status fmi3SetInt32(fmi3Component c, const fmi3ValueReference vr[], size_t n FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetInteger: nvr = %d", nvr) -#ifdef SET_INT32 SET_VARIABLES(Int32) -#else - return fmi3Error; // not implemented -#endif } fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) { @@ -614,24 +583,7 @@ fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetBoolean: nvr = %d", nvr) -#ifdef SET_BOOLEAN - int i; - Status status = OK; - - for (i = 0; i < nvr; i++) { - bool v = value[i]; - size_t index = 0; - Status s = setBoolean(comp, vr[i], &v, &index); - status = max(status, s); - if (status > Warning) return status; - } - - if (nvr > 0) comp->isDirtyValues = true; - - return status; -#else - return fmi3Error; // not implemented -#endif + SET_BOOLEAN_VARIABLES } fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { diff --git a/src/slave.c b/src/slave.c index fade5bc..e3f1043 100644 --- a/src/slave.c +++ b/src/slave.c @@ -34,6 +34,24 @@ Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *i } #endif +#ifndef SET_FLOAT64 +Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { + return Error; +} +#endif + +#ifndef SET_INT32 +Status setInt32(ModelInstance* comp, ValueReference vr, const int *value, size_t *index) { + return Error; +} +#endif + +#ifndef SET_BOOLEAN +Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, size_t *index) { + return Error; +} +#endif + #if NUMBER_OF_STATES < 1 void getContinuousStates(ModelInstance *comp, double x[], size_t nx) {} void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) {} diff --git a/test_build.py b/test_build.py index d2fd464..9ca7144 100644 --- a/test_build.py +++ b/test_build.py @@ -90,7 +90,7 @@ def test_fmi1_me(self): if fmpy_available: self.validate(build_dir, fmi_types=['ModelExchange'], - models=['BouncingBall', 'Dahlquist', 'Stair', 'VanDerPol'] #, 'Feedthrough' + models=['BouncingBall', 'Dahlquist', 'Stair', 'VanDerPol'] ) def test_fmi1_cs(self): @@ -106,7 +106,7 @@ def test_fmi1_cs(self): if fmpy_available: self.validate(build_dir, fmi_types=['CoSimulation'], - models=['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol']) # , 'Feedthrough' + models=['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol']) def test_fmi2(self): From 15bff55a461da90219c7e8365d2784a84aa2c5b4 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 22 Feb 2019 22:47:59 +0100 Subject: [PATCH 10/16] Add get / setString() functions and clean up --- include/model.h | 2 + src/fmi1.c | 4 -- src/fmi2.c | 84 +++++++++--------------------------- src/fmi3.c | 111 ++++++++++++++---------------------------------- src/slave.c | 12 ++++++ 5 files changed, 68 insertions(+), 145 deletions(-) diff --git a/include/model.h b/include/model.h index e28197b..c40c1ce 100644 --- a/include/model.h +++ b/include/model.h @@ -113,10 +113,12 @@ void calculateValues(ModelInstance *comp); Status getFloat64(ModelInstance* comp, ValueReference vr, double *value, size_t *index); Status getInt32(ModelInstance* comp, ValueReference vr, int *value, size_t *index); Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *index); +Status getString(ModelInstance* comp, ValueReference vr, const char **value, size_t *index); Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index); Status setInt32(ModelInstance* comp, ValueReference vr, const int *value, size_t *index); Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, size_t *index); +Status setString(ModelInstance* comp, ValueReference vr, const char *const *value, size_t *index); void getContinuousStates(ModelInstance *comp, double x[], size_t nx); void setContinuousStates(ModelInstance *comp, const double x[], size_t nx); diff --git a/src/fmi1.c b/src/fmi1.c index db15ae4..729db4a 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -95,10 +95,6 @@ static fmiBoolean nullPointer(ModelInstance* comp, const char* f, const char* ar // Private helpers used below to implement functions // --------------------------------------------------------------------------- -fmiStatus setString(fmiComponent comp, fmiValueReference vr, fmiString value){ - return fmiSetString(comp, &vr, 1, &value); -} - // fname is fmiInstantiateModel or fmiInstantiateSlave static fmiComponent instantiateModel(char* fname, fmiString instanceName, fmiString GUID, fmiString fmuLocation, fmiCallbackFunctions functions, fmiBoolean loggingOn) { diff --git a/src/fmi2.c b/src/fmi2.c index af5ef5a..96aa61a 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -191,15 +191,6 @@ static fmi2Status unsupportedFunction(fmi2Component c, const char *fName, int st return fmi2Error; } -static void notImplemented(ModelInstance* comp, const char *f) { - comp->state = modelError; - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "Function %s is not implemented", f) -} - -fmi2Status setString(fmi2Component comp, fmi2ValueReference vr, fmi2String value) { - return fmi2SetString(comp, &vr, 1, &value); -} - // --------------------------------------------------------------------------- // Private helpers logger // --------------------------------------------------------------------------- @@ -287,7 +278,7 @@ fmi2Component fmi2Instantiate(fmi2String instanceName, fmi2Type fmuType, fmi2Str comp->nextEventTime = 0; setStartValues(comp); // to be implemented by the includer of this file - comp->isDirtyValues = fmi2True; // because we just called setStartValues + comp->isDirtyValues = true; // because we just called setStartValues comp->solverData = solver_create(comp); @@ -362,7 +353,7 @@ fmi2Status fmi2Reset(fmi2Component c) { comp->state = modelInstantiated; setStartValues(comp); // to be implemented by the includer of this file - comp->isDirtyValues = fmi2True; // because we just called setStartValues + comp->isDirtyValues = true; // because we just called setStartValues return fmi2OK; } @@ -444,16 +435,16 @@ fmi2Status fmi2GetReal (fmi2Component c, const fmi2ValueReference vr[], size_t n 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 = fmi2False; + comp->isDirtyValues = false; } GET_VARIABLES(Float64) @@ -474,7 +465,7 @@ fmi2Status fmi2GetInteger(fmi2Component c, const fmi2ValueReference vr[], size_t if (nvr > 0 && comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi2False; + comp->isDirtyValues = false; } GET_VARIABLES(Int32) @@ -495,37 +486,31 @@ fmi2Status fmi2GetBoolean(fmi2Component c, const fmi2ValueReference vr[], size_t if (nvr > 0 && comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi2False; + comp->isDirtyValues = false; } - + GET_BOOLEAN_VARIABLES } fmi2Status fmi2GetString (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, fmi2String value[]) { - int i; + 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 = fmi2False; + comp->isDirtyValues = false; } -#ifdef SET_STRING - for (i=0; is[vr[i]]; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2GetString: #s%u# = '%s'", vr[i], value[i]) - } -#else - return fmi2Error; -#endif - return fmi2OK; + GET_VARIABLES(String) } fmi2Status fmi2SetReal (fmi2Component c, const fmi2ValueReference vr[], size_t nvr, const fmi2Real value[]) { @@ -597,36 +582,7 @@ fmi2Status fmi2SetString (fmi2Component c, const fmi2ValueReference vr[], size_t FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetString: nvr = %d", nvr) -#ifdef SET_STRING - for (int i = 0; i < nvr; i++) { - char *string = (char *)comp->s[vr[i]]; - if (vrOutOfRange(comp, "fmi2SetString", vr[i], NUMBER_OF_STRINGS)) - return fmi2Error; - FILTERED_LOG(comp, fmi2OK, LOG_FMI_CALL, "fmi2SetString: #s%d# = '%s'", vr[i], value[i]) - - if (value[i] == NULL) { - if (string) comp->functions->freeMemory(string); - comp->s[vr[i]] = NULL; - FILTERED_LOG(comp, fmi2Warning, LOG_ERROR, "fmi2SetString: 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; - FILTERED_LOG(comp, fmi2Error, LOG_ERROR, "fmi2SetString: Out of memory.") - return fmi2Error; - } - } - strcpy((char *)comp->s[vr[i]], (char *)value[i]); - } - } - if (nvr > 0) comp->isDirtyValues = fmi2True; -#else - return fmi2Error; -#endif - - return fmi2OK; + SET_VARIABLES(String) } fmi2Status fmi2GetFMUstate (fmi2Component c, fmi2FMUstate* FMUstate) { @@ -892,12 +848,15 @@ fmi2Status fmi2SetTime(fmi2Component c, fmi2Real time) { } fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t nx){ + ModelInstance *comp = (ModelInstance *)c; - int i; + 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; @@ -916,7 +875,6 @@ fmi2Status fmi2SetContinuousStates(fmi2Component c, const fmi2Real x[], size_t n /* Evaluation of the model equations */ fmi2Status fmi2GetDerivatives(fmi2Component c, fmi2Real derivatives[], size_t nx) { - int i; ModelInstance* comp = (ModelInstance *)c; diff --git a/src/fmi3.c b/src/fmi3.c index 9adc8f4..8f0cf5f 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -130,23 +130,23 @@ static const char *logCategoriesNames[] = {"logAll", "logError", "logFmiCall", " // --------------------------------------------------------------------------- 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); } @@ -191,16 +191,6 @@ static fmi3Status unsupportedFunction(fmi3Component c, const char *fName, int st return fmi3Error; } -static void notImplemented(ModelInstance* comp, const char *f) { - comp->state = modelError; - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "Function %s is not implemented", f) -} - -fmi3Status setString(fmi3Component comp, fmi3ValueReference vr, fmi3String value) { - //return fmi3SetString(comp, &vr, 1, &value); - return fmi3Error; -} - // --------------------------------------------------------------------------- // Private helpers logger // --------------------------------------------------------------------------- @@ -258,7 +248,7 @@ fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3Str 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. @@ -294,8 +284,8 @@ fmi3Component fmi3Instantiate(fmi3String instanceName, fmi3Type fmuType, fmi3Str comp->nextEventTimeDefined = fmi3False; comp->nextEventTime = 0; - setStartValues(comp); // to be implemented by the includer of this file - comp->isDirtyValues = fmi3True; // because we just called setStartValues + setStartValues(comp); + comp->isDirtyValues = true; comp->solverData = solver_create(comp); @@ -341,14 +331,16 @@ fmi3Status fmi3ExitInitializationMode(fmi3Component c) { // ensure calculated values are updated now if (comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi3False; + comp->isDirtyValues = false; } if (comp->type == fmi3ModelExchange) { comp->state = modelEventMode; comp->isNewEventIteration = fmi3True; + } else { + comp->state = modelStepComplete; } - else comp->state = modelStepComplete; + return fmi3OK; } @@ -369,8 +361,8 @@ fmi3Status fmi3Reset(fmi3Component c) { FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3Reset") comp->state = modelInstantiated; - setStartValues(comp); // to be implemented by the includer of this file - comp->isDirtyValues = fmi3True; // because we just called setStartValues + setStartValues(comp); + comp->isDirtyValues = true; return fmi3OK; } @@ -457,9 +449,9 @@ fmi3Status fmi3GetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_ if (nvr > 0 && comp->isDirtyValues) { calculateValues(comp); - comp->isDirtyValues = fmi3False; + comp->isDirtyValues = false; } - + GET_VARIABLES(Float64) } @@ -506,30 +498,24 @@ fmi3Status fmi3GetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t } fmi3Status fmi3GetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) { - int i; + 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; } -#ifdef SET_STRING - for (i=0; is[vr[i]]; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3GetString: #s%u# = '%s'", vr[i], value[i]) - } -#else - return fmi3Error; -#endif - return fmi3OK; + GET_VARIABLES(String) } fmi3Status fmi3SetFloat64 (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) { @@ -587,46 +573,21 @@ fmi3Status fmi3SetBoolean(fmi3Component c, const fmi3ValueReference vr[], size_t } fmi3Status fmi3SetString (fmi3Component c, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) { - int i; + 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; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetString: nvr = %d", nvr) -#ifdef SET_STRING - for (i = 0; i < nvr; i++) { - char *string = (char *)comp->s[vr[i]]; - if (vrOutOfRange(comp, "fmi3SetString", vr[i], NUMBER_OF_STRINGS)) - return fmi3Error; - FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetString: #s%d# = '%s'", vr[i], value[i]) - - if (value[i] == NULL) { - if (string) comp->functions->freeMemory(string); - comp->s[vr[i]] = NULL; - FILTERED_LOG(comp, fmi3Warning, LOG_ERROR, "fmi3SetString: 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; - FILTERED_LOG(comp, fmi3Error, LOG_ERROR, "fmi3SetString: Out of memory.") - return fmi3Error; - } - } - strcpy((char *)comp->s[vr[i]], (char *)value[i]); - } - } - if (nvr > 0) comp->isDirtyValues = fmi3True; -#else - return fmi3Error; -#endif + FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetString: nvr = %d", nvr) - return fmi3OK; + SET_VARIABLES(String) } fmi3Status fmi3GetFMUstate (fmi3Component c, fmi3FMUstate* FMUstate) { @@ -799,31 +760,25 @@ fmi3Status fmi3SetTime(fmi3Component c, fmi3Float64 time) { } fmi3Status fmi3SetContinuousStates(fmi3Component c, const fmi3Float64 x[], size_t nx){ + ModelInstance *comp = (ModelInstance *)c; - int i; + 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); -//#if NUMBER_OF_STATES>0 -// for (i = 0; i < nx; i++) { -// fmi3ValueReference vr = vrStates[i]; -// FILTERED_LOG(comp, fmi3OK, LOG_FMI_CALL, "fmi3SetContinuousStates: #r%d#=%.16g", vr, x[i]) -// assert(vr < NUMBER_OF_REALS); -// comp->r[vr] = x[i]; -// } -//#endif return fmi3OK; } /* Evaluation of the model equations */ fmi3Status fmi3GetDerivatives(fmi3Component c, fmi3Float64 derivatives[], size_t nx) { - int i; ModelInstance* comp = (ModelInstance *)c; diff --git a/src/slave.c b/src/slave.c index e3f1043..4053821 100644 --- a/src/slave.c +++ b/src/slave.c @@ -34,6 +34,12 @@ Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *i } #endif +#ifndef GET_STRING +Status getString(ModelInstance* comp, ValueReference vr, const char **value, size_t *index) { + return Error; +} +#endif + #ifndef SET_FLOAT64 Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, size_t *index) { return Error; @@ -52,6 +58,12 @@ Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, siz } #endif +#ifndef SET_STRING +Status setString(ModelInstance* comp, ValueReference vr, const char *const *value, size_t *index) { + return Error; +} +#endif + #if NUMBER_OF_STATES < 1 void getContinuousStates(ModelInstance *comp, double x[], size_t nx) {} void setContinuousStates(ModelInstance *comp, const double x[], size_t nx) {} From cf8f482d9cb7dcf68a82005137626a640c17883e Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 23 Feb 2019 15:01:14 +0100 Subject: [PATCH 11/16] =?UTF-8?q?Don=E2=80=99t=20build=20=E2=80=9CResource?= =?UTF-8?q?=E2=80=9D=20for=20FMI=201.0=20ME?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74192cf..8cecbe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,13 +58,17 @@ endif () MESSAGE("FMI_PLATFORM: " ${FMI_PLATFORM}) -set (MODEL_NAMES BouncingBall Dahlquist Stair Feedthrough Resource VanDerPol) +set (MODEL_NAMES BouncingBall Dahlquist Stair Feedthrough VanDerPol) + +if (${FMI_VERSION} GREATER 1 OR "${FMI_TYPE}" STREQUAL "CS") + set (MODEL_NAMES ${MODEL_NAMES} Resource) +endif () if (${FMI_VERSION} GREATER 2) set (MODEL_NAMES ${MODEL_NAMES} LinearTransform) endif () -foreach (MODEL_NAME ${MODEL_NAMES}) # Dahlquist Stair Feedthrough Resource VanDerPol) +foreach (MODEL_NAME ${MODEL_NAMES}) set(TARGET_NAME ${MODEL_NAME}) @@ -92,7 +96,6 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist) target_compile_definitions(${TARGET_NAME} PRIVATE DISABLE_PREFIX FMI_VERSION=${FMI_VERSION}) if (${FMI_VERSION} EQUAL 1 AND "${FMI_TYPE}" STREQUAL CS) - message("CO_SIMULATION") target_compile_definitions(${TARGET_NAME} PRIVATE FMI_COSIMULATION) endif() From aac4ac774fe20fd4c2060d59d7dbc9d00d143f0b Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sat, 23 Feb 2019 15:58:40 +0100 Subject: [PATCH 12/16] Fix FMI 3.0 test for Windows --- test_build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_build.py b/test_build.py index 9ca7144..af6ddaa 100644 --- a/test_build.py +++ b/test_build.py @@ -130,8 +130,8 @@ def test_fmi3(self): if not os.path.exists(build_dir): os.makedirs(build_dir) - subprocess.call(['cmake', '-G', 'Unix Makefiles', '-DFMI_VERSION=3', '..'], cwd=build_dir) - subprocess.call(['cmake', '--build', '.'], cwd=build_dir) + subprocess.call(['cmake', '-G', generator, '-DFMI_VERSION=3', '..'], cwd=build_dir) + subprocess.call(['cmake', '--build', '.', '--config', 'Release'], cwd=build_dir) if fmi3_available: self.validate(build_dir, models=['BouncingBall', 'Dahlquist', 'Feedthrough', 'Resource', 'Stair', 'VanDerPol']) From 70e69551d79ae81c16eb5a73252cbce42599a7b5 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sun, 24 Feb 2019 16:48:28 +0100 Subject: [PATCH 13/16] Implement get / setString() --- Feedthrough/FMI2.xml | 4 ++-- Feedthrough/FMI3.xml | 4 ++-- Feedthrough/config.h | 4 ++++ Feedthrough/model.c | 42 ++++++++++++++++++++++++++++++++++++------ Feedthrough/readme.md | 12 ++++++++++++ include/model.h | 3 +++ src/fmi1.c | 19 +++++++++++++++++-- src/fmi2.c | 15 +++++++++++++++ src/fmi3.c | 15 +++++++++++++++ test_build.py | 2 +- 10 files changed, 107 insertions(+), 13 deletions(-) diff --git a/Feedthrough/FMI2.xml b/Feedthrough/FMI2.xml index 81fb24f..1148851 100644 --- a/Feedthrough/FMI2.xml +++ b/Feedthrough/FMI2.xml @@ -59,8 +59,8 @@ - - + + diff --git a/Feedthrough/FMI3.xml b/Feedthrough/FMI3.xml index c2a319a..57a999f 100644 --- a/Feedthrough/FMI3.xml +++ b/Feedthrough/FMI3.xml @@ -39,8 +39,8 @@ - - + + diff --git a/Feedthrough/config.h b/Feedthrough/config.h index 29621d5..a54f8a1 100644 --- a/Feedthrough/config.h +++ b/Feedthrough/config.h @@ -15,10 +15,12 @@ #define GET_FLOAT64 #define GET_INT32 #define GET_BOOLEAN +#define GET_STRING #define SET_FLOAT64 #define SET_INT32 #define SET_BOOLEAN +#define SET_STRING #define EVENT_UPDATE @@ -46,4 +48,6 @@ typedef struct { const char *string; } ModelData; +extern const char *STRING_START; + #endif /* config_h */ diff --git a/Feedthrough/model.c b/Feedthrough/model.c index 2f3e651..dfec767 100644 --- a/Feedthrough/model.c +++ b/Feedthrough/model.c @@ -1,6 +1,8 @@ #include "config.h" #include "model.h" +#include // for strcmp() +const char *STRING_START = "Set me!"; void setStartValues(ModelInstance *comp) { M(real_fixed_parameter) = 0; @@ -9,7 +11,7 @@ void setStartValues(ModelInstance *comp) { M(real_discrete) = 0; M(integer) = 0; M(boolean) = false; - M(string) = "a"; + M(string) = STRING_START; } void calculateValues(ModelInstance *comp) { @@ -59,7 +61,16 @@ Status getBoolean(ModelInstance* comp, ValueReference vr, bool *value, size_t *i value[(*index)++] = M(boolean); return OK; case vr_bool_out: - value[(*index)++] = M(boolean); + value[(*index)++] = M(boolean) && (strcmp(M(string), "FMI is awesome!") == 0); + return OK; + default: return Error; + } +} + +Status getString(ModelInstance* comp, ValueReference vr, const char **value, size_t *index) { + switch (vr) { + case vr_string: + value[(*index)++] = M(string); return OK; default: return Error; } @@ -116,15 +127,34 @@ Status setFloat64(ModelInstance* comp, ValueReference vr, const double *value, s Status setInt32(ModelInstance* comp, ValueReference vr, const int *value, size_t *index) { switch (vr) { - case vr_int_in: M(integer) = value[(*index)++]; return OK; - default: return Error; + case vr_int_in: + M(integer) = value[(*index)++]; + return OK; + default: + return Error; } } Status setBoolean(ModelInstance* comp, ValueReference vr, const bool *value, size_t *index) { switch (vr) { - case vr_bool_in: M(boolean) = value[(*index)++]; return OK; - default: return Error; + case vr_bool_in: + M(boolean) = value[(*index)++]; + return OK; + default: + return Error; + } +} + +Status setString(ModelInstance* comp, ValueReference vr, const char *const *value, size_t *index) { + switch (vr) { + case vr_string: + if (M(string) != STRING_START) { + freeMemory(comp, (void *)M(string)); + } + M(string) = duplicateString(comp, value[(*index)++]); + return OK; + default: + return Error; } } diff --git a/Feedthrough/readme.md b/Feedthrough/readme.md index c4d5368..219b538 100644 --- a/Feedthrough/readme.md +++ b/Feedthrough/readme.md @@ -1,6 +1,18 @@ # Feedthrough +| Variable | Start | Causality | Variability | Description +|:-----------------| ----------|-----------|-------------|:--------------- +| real_fixed_param | 0 | parameter | fixed | Fixed parameter +| string_param | "Set me!" | parameter | fixed | String parameter +In order to reproduce the reference results the following parameters need to be set + +``` +real_fixed_param: 1 +string_param: "FMI is awesome!" +``` + +and the [input signals](Feedthrough_in.csv) must be applied. The plot shows the [reference result](Feedthrough_ref.csv) computed with [FMPy](https://github.com/CATIA-Systems/FMPy). diff --git a/include/model.h b/include/model.h index c40c1ce..82b033c 100644 --- a/include/model.h +++ b/include/model.h @@ -127,6 +127,9 @@ 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 freeMemory(ModelInstance *comp, void *obj); +const char *duplicateString(ModelInstance *comp, const char *str1); // shorthand to access the variables #define M(v) (comp->modelData->v) diff --git a/src/fmi1.c b/src/fmi1.c index 729db4a..96dd423 100644 --- a/src/fmi1.c +++ b/src/fmi1.c @@ -59,6 +59,21 @@ 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; @@ -242,7 +257,7 @@ fmiStatus fmiSetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, c if (comp->loggingOn) comp->logger(c, comp->instanceName, fmiOK, "log", "fmiSetReal: nvr = %d", nvr); - + #ifdef SET_FLOAT64 SET_VARIABLES(Float64) #else @@ -342,7 +357,7 @@ fmiStatus fmiGetReal(fmiComponent c, const fmiValueReference vr[], size_t nvr, f if (nvr > 0 && nullPointer(comp, "fmiGetReal", "value[]", value)) return fmiError; - + GET_VARIABLES(Float64) } diff --git a/src/fmi2.c b/src/fmi2.c index 96aa61a..478586b 100644 --- a/src/fmi2.c +++ b/src/fmi2.c @@ -150,6 +150,21 @@ 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) { diff --git a/src/fmi3.c b/src/fmi3.c index 8f0cf5f..e40f686 100644 --- a/src/fmi3.c +++ b/src/fmi3.c @@ -150,6 +150,21 @@ 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) { diff --git a/test_build.py b/test_build.py index af6ddaa..b8c8093 100644 --- a/test_build.py +++ b/test_build.py @@ -56,7 +56,7 @@ def validate(self, build_dir, fmi_types=['ModelExchange', 'CoSimulation'], model fmu_filename = os.path.join(build_dir, 'dist', model + '.fmu') if model == 'Feedthrough': - start_values = {'real_fixed_param': 1} + start_values = {'real_fixed_param': 1, 'string_param': "FMI is awesome!"} in_csv = os.path.join(test_fmus_dir, model, model + '_in.csv') input = read_csv(in_csv) else: From e4dee6562c60f51e3b512a031ea9addf8d000d50 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sun, 24 Feb 2019 17:02:29 +0100 Subject: [PATCH 14/16] Fix XML for FMI 1.0 Feedthrough --- Feedthrough/FMI1CS.xml | 4 ++-- Feedthrough/FMI1ME.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Feedthrough/FMI1CS.xml b/Feedthrough/FMI1CS.xml index 51ada37..7ad2fdc 100644 --- a/Feedthrough/FMI1CS.xml +++ b/Feedthrough/FMI1CS.xml @@ -34,8 +34,8 @@ - - + + diff --git a/Feedthrough/FMI1ME.xml b/Feedthrough/FMI1ME.xml index af3fa86..67d8cbd 100644 --- a/Feedthrough/FMI1ME.xml +++ b/Feedthrough/FMI1ME.xml @@ -34,8 +34,8 @@ - - + + From ce4060486049ba05add6d623c5270e7b0ffa661f Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Sun, 24 Feb 2019 20:10:00 +0100 Subject: [PATCH 15/16] Add *_ref.opt files and copy FMUs to cross-check --- BouncingBall/BouncingBall_ref.opt | 4 +++ Dahlquist/Dahlquist_ref.opt | 4 +++ Feedthrough/Feedthrough_ref.opt | 4 +++ LinearTransform/LinearTransform_ref.opt | 4 +++ Resource/Resource_ref.opt | 4 +++ Stair/Stair_ref.opt | 4 +++ VanDerPol/VanDerPol_ref.opt | 4 +++ test_build.py | 33 ++++++++++++++++++++++--- 8 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 BouncingBall/BouncingBall_ref.opt create mode 100644 Dahlquist/Dahlquist_ref.opt create mode 100644 Feedthrough/Feedthrough_ref.opt create mode 100644 LinearTransform/LinearTransform_ref.opt create mode 100644 Resource/Resource_ref.opt create mode 100644 Stair/Stair_ref.opt create mode 100644 VanDerPol/VanDerPol_ref.opt diff --git a/BouncingBall/BouncingBall_ref.opt b/BouncingBall/BouncingBall_ref.opt new file mode 100644 index 0000000..0f5b42f --- /dev/null +++ b/BouncingBall/BouncingBall_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 3 +StepSize, 0 +RelTol, 1e-5 diff --git a/Dahlquist/Dahlquist_ref.opt b/Dahlquist/Dahlquist_ref.opt new file mode 100644 index 0000000..5de8a30 --- /dev/null +++ b/Dahlquist/Dahlquist_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 10 +StepSize, 0 +RelTol, 1e-5 diff --git a/Feedthrough/Feedthrough_ref.opt b/Feedthrough/Feedthrough_ref.opt new file mode 100644 index 0000000..d5ed5ee --- /dev/null +++ b/Feedthrough/Feedthrough_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 2 +StepSize, 0 +RelTol, 1e-5 diff --git a/LinearTransform/LinearTransform_ref.opt b/LinearTransform/LinearTransform_ref.opt new file mode 100644 index 0000000..5de8a30 --- /dev/null +++ b/LinearTransform/LinearTransform_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 10 +StepSize, 0 +RelTol, 1e-5 diff --git a/Resource/Resource_ref.opt b/Resource/Resource_ref.opt new file mode 100644 index 0000000..0ad2110 --- /dev/null +++ b/Resource/Resource_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 1 +StepSize, 0 +RelTol, 1e-5 diff --git a/Stair/Stair_ref.opt b/Stair/Stair_ref.opt new file mode 100644 index 0000000..5de8a30 --- /dev/null +++ b/Stair/Stair_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 10 +StepSize, 0 +RelTol, 1e-5 diff --git a/VanDerPol/VanDerPol_ref.opt b/VanDerPol/VanDerPol_ref.opt new file mode 100644 index 0000000..be04cd6 --- /dev/null +++ b/VanDerPol/VanDerPol_ref.opt @@ -0,0 +1,4 @@ +StartTime, 0 +StopTime, 20 +StepSize, 0 +RelTol, 1e-5 diff --git a/test_build.py b/test_build.py index b8c8093..393742e 100644 --- a/test_build.py +++ b/test_build.py @@ -3,6 +3,9 @@ import os import shutil + +fmus_dir = None # /path/to/fmi-cross-check/fmus + try: from fmpy import simulate_fmu fmpy_available = True @@ -33,6 +36,21 @@ generator = 'Unix Makefiles' +def copy_to_cross_check(build_dir, model_names, fmi_version, fmi_types): + + if fmus_dir is None: + return + + for fmi_type in fmi_types: + for model in model_names: + target_dir = os.path.join(fmus_dir, fmi_version, fmi_type, fmpy.platform, 'Test-FMUs', '0.0.0', model) + if not os.path.exists(target_dir): + os.makedirs(target_dir) + shutil.copy(os.path.join(build_dir, 'dist', model + '.fmu'), target_dir) + shutil.copy(os.path.join(test_fmus_dir, model, model + '_ref.csv'), target_dir) + shutil.copy(os.path.join(test_fmus_dir, model, model + '_ref.opt'), target_dir) + + class BuildTest(unittest.TestCase): """ Build all variants of the Test FMUs and simulate the default experiment """ @@ -87,11 +105,14 @@ def test_fmi1_me(self): subprocess.call(['cmake', '-G', generator, '-DFMI_VERSION=1', '-DFMI_TYPE=ME', '..'], cwd=build_dir) subprocess.call(['cmake', '--build', '.', '--config', 'Release'], cwd=build_dir) + model_names = ['BouncingBall', 'Dahlquist', 'Stair', 'VanDerPol'] + if fmpy_available: self.validate(build_dir, fmi_types=['ModelExchange'], - models=['BouncingBall', 'Dahlquist', 'Stair', 'VanDerPol'] -) + models=model_names) + + copy_to_cross_check(build_dir=build_dir, model_names=model_names, fmi_version='1.0', fmi_types=['me']) def test_fmi1_cs(self): @@ -103,10 +124,14 @@ def test_fmi1_cs(self): subprocess.call(['cmake', '-G', generator, '-DFMI_VERSION=1', '-DFMI_TYPE=CS', '..'], cwd=build_dir) subprocess.call(['cmake', '--build', '.', '--config', 'Release'], cwd=build_dir) + model_names = ['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol'] + if fmpy_available: self.validate(build_dir, fmi_types=['CoSimulation'], - models=['BouncingBall', 'Dahlquist', 'Resource', 'Stair', 'VanDerPol']) + models=model_names) + + copy_to_cross_check(build_dir=build_dir, model_names=model_names, fmi_version='1.0', fmi_types=['cs']) def test_fmi2(self): @@ -121,6 +146,8 @@ def test_fmi2(self): if fmpy_available: self.validate(build_dir) + copy_to_cross_check(build_dir=build_dir, model_names=models, fmi_version='2.0', fmi_types=['cs', 'me']) + def test_fmi3(self): print('FMI 3.0') From 8eae22aa9cc4e261a5a50ed47a0047506da8c5bf Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Thu, 28 Feb 2019 14:59:46 +0100 Subject: [PATCH 16/16] Bump version in build script to 0.0.1 --- test_build.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_build.py b/test_build.py index 393742e..b2830e1 100644 --- a/test_build.py +++ b/test_build.py @@ -5,6 +5,7 @@ fmus_dir = None # /path/to/fmi-cross-check/fmus +test_fmus_version = '0.0.1' try: from fmpy import simulate_fmu @@ -43,7 +44,7 @@ def copy_to_cross_check(build_dir, model_names, fmi_version, fmi_types): for fmi_type in fmi_types: for model in model_names: - target_dir = os.path.join(fmus_dir, fmi_version, fmi_type, fmpy.platform, 'Test-FMUs', '0.0.0', model) + target_dir = os.path.join(fmus_dir, fmi_version, fmi_type, fmpy.platform, 'Test-FMUs', test_fmus_version, model) if not os.path.exists(target_dir): os.makedirs(target_dir) shutil.copy(os.path.join(build_dir, 'dist', model + '.fmu'), target_dir)