pythonfmu3 0.2.2__py3-none-any.whl → 0.2.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pythonfmu3 might be problematic. Click here for more details.
- pythonfmu3/__init__.py +8 -8
- pythonfmu3/__main__.py +52 -52
- pythonfmu3/_version.py +1 -1
- pythonfmu3/builder.py +260 -260
- pythonfmu3/default_experiment.py +7 -7
- pythonfmu3/deploy.py +118 -118
- pythonfmu3/enums.py +48 -48
- pythonfmu3/fmi3slave.py +438 -438
- pythonfmu3/logmsg.py +14 -14
- pythonfmu3/osutil.py +22 -22
- pythonfmu3/pythonfmu-export/.clang-format +35 -35
- pythonfmu3/pythonfmu-export/CMakeLists.txt +59 -59
- pythonfmu3/pythonfmu-export/build/ALL_BUILD.vcxproj +184 -0
- pythonfmu3/pythonfmu-export/build/ALL_BUILD.vcxproj.filters +8 -0
- pythonfmu3/pythonfmu-export/build/CMakeCache.txt +369 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/0ee4db0675778dfba98c7160896d5a45/generate.stamp.rule +1 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CMakeCCompiler.cmake +72 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CMakeCXXCompiler.cmake +83 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CMakeDetermineCompilerABI_C.bin +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CMakeDetermineCompilerABI_CXX.bin +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CMakeRCCompiler.cmake +6 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CMakeSystem.cmake +15 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/CMakeCCompilerId.c +838 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/CompilerIdC.exe +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/CompilerIdC.vcxproj +71 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CMakeCCompilerId.obj +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.exe.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/CL.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/CL.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/CL.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/CompilerIdC.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/link.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/link.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdC/Debug/CompilerIdC.tlog/link.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/CMakeCXXCompilerId.cpp +826 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/CompilerIdCXX.exe +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/CompilerIdCXX.vcxproj +71 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CMakeCXXCompilerId.obj +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.exe.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CompilerIdCXX.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/VCTargetsPath.txt +1 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/VCTargetsPath.vcxproj +31 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/x64/Debug/VCTargetsPath.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.24.0/x64/Debug/VCTargetsPath.tlog/VCTargetsPath.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CMakeCCompiler.cmake +81 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CMakeCXXCompiler.cmake +101 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CMakeDetermineCompilerABI_C.bin +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CMakeRCCompiler.cmake +6 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CMakeSystem.cmake +15 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/CMakeCCompilerId.c +904 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/CompilerIdC.exe +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/CompilerIdC.vcxproj +72 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CMakeCCompilerId.obj +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.exe.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/CL.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/CL.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/CL.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/CompilerIdC.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/link.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/link.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdC/Debug/CompilerIdC.tlog/link.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +919 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/CompilerIdCXX.exe +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/CompilerIdCXX.vcxproj +72 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CMakeCXXCompilerId.obj +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.exe.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CompilerIdCXX.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/VCTargetsPath.txt +1 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/VCTargetsPath.vcxproj +31 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/x64/Debug/VCTargetsPath.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/3.30.2/x64/Debug/VCTargetsPath.tlog/VCTargetsPath.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/CMakeConfigureLog.yaml +568 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/CMakeOutput.log +357 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/TargetDirectories.txt +3 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/cmake.check_cache +1 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/generate.stamp +1 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/generate.stamp.depend +28 -0
- pythonfmu3/pythonfmu-export/build/CMakeFiles/generate.stamp.list +2 -0
- pythonfmu3/pythonfmu-export/build/ZERO_CHECK.vcxproj +174 -0
- pythonfmu3/pythonfmu-export/build/ZERO_CHECK.vcxproj.filters +13 -0
- pythonfmu3/pythonfmu-export/build/cmake_install.cmake +50 -0
- pythonfmu3/pythonfmu-export/build/install_manifest.txt +0 -0
- pythonfmu3/pythonfmu-export/build/pythonfmu-export.sln +53 -0
- pythonfmu3/pythonfmu-export/build/src/CMakeFiles/generate.stamp +1 -0
- pythonfmu3/pythonfmu-export/build/src/CMakeFiles/generate.stamp.depend +2 -0
- pythonfmu3/pythonfmu-export/build/src/Debug/pythonfmu-export.pdb +0 -0
- pythonfmu3/pythonfmu-export/build/src/Release/pythonfmu-export.exp +0 -0
- pythonfmu3/pythonfmu-export/build/src/Release/pythonfmu-export.lib +0 -0
- pythonfmu3/pythonfmu-export/build/src/cmake_install.cmake +34 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/PySlaveInstance.obj +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/cppfmu_cs.obj +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/exports.def +1885 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/fmi_functions.obj +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/objects.txt +3 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/CL.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/CL.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/CL.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/CustomBuild.command.1.tlog +10 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/CustomBuild.read.1.tlog +1 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/CustomBuild.write.1.tlog +2 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/link.command.1.tlog +1 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/link.read.1.tlog +1 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/link.read.3.tlog +1 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/link.write.1.tlog +1 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/pythonfmu-export.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/pythonfmu-export.tlog/unsuccessfulbuild +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Debug/vc142.pdb +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/MinSizeRel/objects.txt +3 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/RelWithDebInfo/objects.txt +3 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/PySlaveInstance.obj +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/cppfmu_cs.obj +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/exports.def +538 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/fmi_functions.obj +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/objects.txt +3 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.dll.recipe +14 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/CL.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/CL.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/CL.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/CustomBuild.command.1.tlog +10 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/CustomBuild.read.1.tlog +1 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/CustomBuild.write.1.tlog +2 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/link.command.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/link.delete.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/link.read.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/link.write.1.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/pythonfmu-export.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.dir/Release/pythonfmu-export.tlog/pythonfmu-export.write.1u.tlog +0 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.vcxproj +414 -0
- pythonfmu3/pythonfmu-export/build/src/pythonfmu-export.vcxproj.filters +48 -0
- pythonfmu3/pythonfmu-export/build/x64/Debug/ZERO_CHECK/ZERO_CHECK.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/x64/Debug/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.command.1.tlog +10 -0
- pythonfmu3/pythonfmu-export/build/x64/Debug/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.read.1.tlog +29 -0
- pythonfmu3/pythonfmu-export/build/x64/Debug/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.write.1.tlog +3 -0
- pythonfmu3/pythonfmu-export/build/x64/Debug/ZERO_CHECK/ZERO_CHECK.tlog/ZERO_CHECK.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ALL_BUILD/ALL_BUILD.recipe +17 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/ALL_BUILD.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.command.1.tlog +10 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.read.1.tlog +27 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.write.1.tlog +2 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ZERO_CHECK/ZERO_CHECK.recipe +11 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.command.1.tlog +10 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.read.1.tlog +29 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.write.1.tlog +3 -0
- pythonfmu3/pythonfmu-export/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/ZERO_CHECK.lastbuildstate +2 -0
- pythonfmu3/pythonfmu-export/build_unix.sh +4 -4
- pythonfmu3/pythonfmu-export/build_win.sh +4 -4
- pythonfmu3/pythonfmu-export/src/CMakeLists.txt +45 -45
- pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp +161 -161
- pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp +192 -192
- pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp +185 -185
- pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp +937 -937
- pythonfmu3/pythonfmu-export/src/fmi/fmi3FunctionTypes.h +638 -638
- pythonfmu3/pythonfmu-export/src/fmi/fmi3Functions.h +343 -343
- pythonfmu3/pythonfmu-export/src/fmi/fmi3PlatformTypes.h +94 -94
- pythonfmu3/pythonfmu-export/src/pythonfmu/IPyState.hpp +17 -17
- pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp +744 -744
- pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp +111 -111
- pythonfmu3/pythonfmu-export/src/pythonfmu/PyState.hpp +84 -84
- pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so +0 -0
- pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll +0 -0
- pythonfmu3/resources/binaries/x86_64-windows1/pythonfmu-export.dll +0 -0
- pythonfmu3/tests/conftest.py +5 -5
- pythonfmu3/tests/data/csvdemo.csv +7 -7
- pythonfmu3/tests/slaves/PythonSlaveWithException.py +18 -18
- pythonfmu3/tests/slaves/localmodule.py +8 -8
- pythonfmu3/tests/slaves/pythonslave.py +52 -52
- pythonfmu3/tests/slaves/pythonslave_read_file.py +23 -23
- pythonfmu3/tests/slaves/slavewithdep.py +21 -21
- pythonfmu3/tests/test_builder.py +195 -195
- pythonfmu3/tests/test_deploy.py +48 -48
- pythonfmu3/tests/test_fmi3slave.py +152 -152
- pythonfmu3/tests/test_integration.py +350 -350
- pythonfmu3/tests/test_logger.py +180 -180
- pythonfmu3/tests/test_multiple_fmus.py +141 -141
- pythonfmu3/tests/test_variables.py +334 -334
- pythonfmu3/tests/utils.py +13 -13
- pythonfmu3/unit.py +62 -62
- pythonfmu3/variable_types.py +101 -101
- pythonfmu3/variables.py +400 -400
- pythonfmu3-0.2.2.dist-info/LICENSE → pythonfmu3-0.2.2.2.dist-info/LICENSE.txt +23 -23
- {pythonfmu3-0.2.2.dist-info → pythonfmu3-0.2.2.2.dist-info}/METADATA +9 -6
- pythonfmu3-0.2.2.2.dist-info/RECORD +200 -0
- {pythonfmu3-0.2.2.dist-info → pythonfmu3-0.2.2.2.dist-info}/WHEEL +1 -1
- {pythonfmu3-0.2.2.dist-info → pythonfmu3-0.2.2.2.dist-info}/entry_points.txt +1 -0
- pythonfmu3-0.2.2.dist-info/RECORD +0 -54
- {pythonfmu3-0.2.2.dist-info → pythonfmu3-0.2.2.2.dist-info}/top_level.txt +0 -0
|
@@ -1,744 +1,744 @@
|
|
|
1
|
-
|
|
2
|
-
#include "pythonfmu/IPyState.hpp"
|
|
3
|
-
#include "pythonfmu/PySlaveInstance.hpp"
|
|
4
|
-
|
|
5
|
-
#include "pythonfmu/PyState.hpp"
|
|
6
|
-
|
|
7
|
-
#include "cppfmu/cppfmu_cs.hpp"
|
|
8
|
-
|
|
9
|
-
#include <fstream>
|
|
10
|
-
#include <functional>
|
|
11
|
-
#include <mutex>
|
|
12
|
-
#include <regex>
|
|
13
|
-
#include <sstream>
|
|
14
|
-
#include <utility>
|
|
15
|
-
|
|
16
|
-
namespace pythonfmu
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
inline std::string getline(const std::string& fileName)
|
|
20
|
-
{
|
|
21
|
-
std::string line;
|
|
22
|
-
std::ifstream infile(fileName);
|
|
23
|
-
std::getline(infile, line);
|
|
24
|
-
return line;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
inline std::string findClassName(const std::string& fileName)
|
|
28
|
-
{
|
|
29
|
-
std::string line;
|
|
30
|
-
std::ifstream infile(fileName);
|
|
31
|
-
std::string regexStr(R"(^class (\w+)\(\s*Fmi3Slave\s*\)\s*:)");
|
|
32
|
-
while (getline(infile, line)) {
|
|
33
|
-
std::smatch m;
|
|
34
|
-
std::regex re(regexStr);
|
|
35
|
-
if (std::regex_search(line, m, re)) {
|
|
36
|
-
return m[1];
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return "";
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
inline void py_safe_run(const std::function<void(PyGILState_STATE gilState)>& f)
|
|
43
|
-
{
|
|
44
|
-
PyGILState_STATE gil_state = PyGILState_Ensure();
|
|
45
|
-
f(gil_state);
|
|
46
|
-
PyGILState_Release(gil_state);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
PySlaveInstance::PySlaveInstance(std::string instanceName, std::string resources, const cppfmu::Logger& logger, const bool visible, std::shared_ptr<IPyState> pyState)
|
|
50
|
-
: pyState_{ std::move(pyState) }
|
|
51
|
-
, instanceName_(std::move(instanceName))
|
|
52
|
-
, resources_(std::move(resources))
|
|
53
|
-
, logger_(logger)
|
|
54
|
-
, visible_(visible)
|
|
55
|
-
{
|
|
56
|
-
py_safe_run([this](PyGILState_STATE gilState) {
|
|
57
|
-
// Append resources path to python sys path
|
|
58
|
-
PyObject* sys_module = PyImport_ImportModule("sys");
|
|
59
|
-
if (sys_module == nullptr) {
|
|
60
|
-
handle_py_exception("[ctor] PyImport_ImportModule", gilState);
|
|
61
|
-
}
|
|
62
|
-
PyObject* sys_path = PyObject_GetAttrString(sys_module, "path");
|
|
63
|
-
Py_DECREF(sys_module);
|
|
64
|
-
if (sys_path == nullptr) {
|
|
65
|
-
handle_py_exception("[ctor] PyObject_GetAttrString", gilState);
|
|
66
|
-
}
|
|
67
|
-
int success = PyList_Insert(sys_path, 0, PyUnicode_FromString(resources_.c_str()));
|
|
68
|
-
Py_DECREF(sys_path);
|
|
69
|
-
if (success != 0) {
|
|
70
|
-
handle_py_exception("[ctor] PyList_Insert", gilState);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
std::string moduleName = getline(resources_ + "/slavemodule.txt");
|
|
74
|
-
PyObject* pModule = PyImport_ImportModule(moduleName.c_str());
|
|
75
|
-
if (pModule == nullptr) {
|
|
76
|
-
PyErr_Print();
|
|
77
|
-
handle_py_exception("[ctor] PyImport_ImportModule", gilState);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
std::string className = findClassName(resources_ + "/" + moduleName + ".py");
|
|
81
|
-
if (className.empty()) {
|
|
82
|
-
cleanPyObject();
|
|
83
|
-
throw cppfmu::FatalError("Unable to find class extending Fmi3Slave!");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
PyObject* pyClassName = Py_BuildValue("s", className.c_str());
|
|
87
|
-
if (pyClassName == nullptr) {
|
|
88
|
-
handle_py_exception("[ctor] Py_BuildValue", gilState);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
pClass_ = PyObject_GetAttr(pModule, pyClassName);
|
|
92
|
-
Py_DECREF(pyClassName);
|
|
93
|
-
Py_DECREF(pModule);
|
|
94
|
-
if (pClass_ == nullptr) {
|
|
95
|
-
handle_py_exception("[ctor] PyObject_GetAttr", gilState);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
initialize(gilState);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
void PySlaveInstance::clearLogBuffer() const
|
|
103
|
-
{
|
|
104
|
-
clearLogStrBuffer();
|
|
105
|
-
|
|
106
|
-
PyObject* debugField = Py_BuildValue("s", "debug");
|
|
107
|
-
PyObject* msgField = Py_BuildValue("s", "msg");
|
|
108
|
-
PyObject* categoryField = Py_BuildValue("s", "category");
|
|
109
|
-
PyObject* statusField = Py_BuildValue("s", "status");
|
|
110
|
-
|
|
111
|
-
if ( pMessages_ != NULL && PyList_Check(pMessages_) ) {
|
|
112
|
-
auto size = PyList_Size(pMessages_);
|
|
113
|
-
for (auto i = 0; i < size; i++) {
|
|
114
|
-
PyObject* msg = PyList_GetItem(pMessages_, i);
|
|
115
|
-
|
|
116
|
-
auto debugAttr = PyObject_GetAttr(msg, debugField);
|
|
117
|
-
auto msgAttr = PyObject_GetAttr(msg, msgField);
|
|
118
|
-
auto categoryAttr = PyObject_GetAttr(msg, categoryField);
|
|
119
|
-
auto statusAttr = PyObject_GetAttr(msg, statusField);
|
|
120
|
-
|
|
121
|
-
auto statusValue = static_cast<cppfmu::FMIStatus>(PyLong_AsLong(statusAttr));
|
|
122
|
-
|
|
123
|
-
PyObject* msgValue = PyUnicode_AsEncodedString(msgAttr, "utf-8", nullptr);
|
|
124
|
-
char* msgStr = PyBytes_AsString(msgValue);
|
|
125
|
-
logStrBuffer.emplace_back(msgValue);
|
|
126
|
-
|
|
127
|
-
const char* categoryStr = "";
|
|
128
|
-
if (categoryAttr != Py_None) {
|
|
129
|
-
PyObject* categoryValue = PyUnicode_AsEncodedString(categoryAttr, "utf-8", nullptr);
|
|
130
|
-
categoryStr = PyBytes_AsString(categoryValue);
|
|
131
|
-
logStrBuffer.emplace_back(categoryValue);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (PyObject_IsTrue(debugAttr)) {
|
|
135
|
-
const_cast<cppfmu::Logger&>(logger_).DebugLog(statusValue, categoryStr, msgStr);
|
|
136
|
-
} else {
|
|
137
|
-
const_cast<cppfmu::Logger&>(logger_).Log(statusValue, categoryStr, msgStr);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
PyList_SetSlice(pMessages_, 0, size, nullptr);
|
|
141
|
-
}
|
|
142
|
-
Py_DECREF(debugField);
|
|
143
|
-
Py_DECREF(msgField);
|
|
144
|
-
Py_DECREF(categoryField);
|
|
145
|
-
Py_DECREF(statusField);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
void PySlaveInstance::initialize(PyGILState_STATE gilState)
|
|
149
|
-
{
|
|
150
|
-
Py_XDECREF(pInstance_);
|
|
151
|
-
Py_XDECREF(pMessages_);
|
|
152
|
-
|
|
153
|
-
PyObject* args = PyTuple_New(0);
|
|
154
|
-
PyObject* kwargs = Py_BuildValue("{ss,ss,sn,si}",
|
|
155
|
-
"instance_name", instanceName_.c_str(),
|
|
156
|
-
"resources", resources_.c_str(),
|
|
157
|
-
"logger", &logger_,
|
|
158
|
-
"visible", visible_);
|
|
159
|
-
pInstance_ = PyObject_Call(pClass_, args, kwargs);
|
|
160
|
-
Py_DECREF(args);
|
|
161
|
-
Py_DECREF(kwargs);
|
|
162
|
-
if (pInstance_ == nullptr) {
|
|
163
|
-
handle_py_exception("[initialize] PyObject_Call", gilState);
|
|
164
|
-
}
|
|
165
|
-
pMessages_ = PyObject_CallMethod(pInstance_, "_get_log_queue", nullptr);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
void PySlaveInstance::SetupExperiment(cppfmu::FMIBoolean, cppfmu::FMIFloat64, cppfmu::FMIFloat64 startTime, cppfmu::FMIBoolean, cppfmu::FMIFloat64)
|
|
169
|
-
{
|
|
170
|
-
py_safe_run([this, startTime](PyGILState_STATE gilState) {
|
|
171
|
-
auto f = PyObject_CallMethod(pInstance_, "setup_experiment", "(d)", startTime);
|
|
172
|
-
if (f == nullptr) {
|
|
173
|
-
handle_py_exception("[setupExperiment] PyObject_CallMethod", gilState);
|
|
174
|
-
}
|
|
175
|
-
Py_DECREF(f);
|
|
176
|
-
clearLogBuffer();
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
void PySlaveInstance::EnterInitializationMode()
|
|
181
|
-
{
|
|
182
|
-
py_safe_run([this](PyGILState_STATE gilState) {
|
|
183
|
-
auto f = PyObject_CallMethod(pInstance_, "enter_initialization_mode", nullptr);
|
|
184
|
-
if (f == nullptr) {
|
|
185
|
-
handle_py_exception("[enterInitializationMode] PyObject_CallMethod", gilState);
|
|
186
|
-
}
|
|
187
|
-
Py_DECREF(f);
|
|
188
|
-
clearLogBuffer();
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
void PySlaveInstance::ExitInitializationMode()
|
|
193
|
-
{
|
|
194
|
-
py_safe_run([this](PyGILState_STATE gilState) {
|
|
195
|
-
auto f = PyObject_CallMethod(pInstance_, "exit_initialization_mode", nullptr);
|
|
196
|
-
if (f == nullptr) {
|
|
197
|
-
handle_py_exception("[exitInitializationMode] PyObject_CallMethod", gilState);
|
|
198
|
-
}
|
|
199
|
-
Py_DECREF(f);
|
|
200
|
-
clearLogBuffer();
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
cppfmu::FMIStatus PySlaveInstance::DoStep(cppfmu::FMIFloat64 currentTime,
|
|
205
|
-
cppfmu::FMIFloat64 stepSize,
|
|
206
|
-
cppfmu::FMIBoolean noSetFmuStatePriorToCurrentPoint,
|
|
207
|
-
cppfmu::FMIBoolean* eventHandlingNeeded,
|
|
208
|
-
cppfmu::FMIBoolean* terminateSimulation,
|
|
209
|
-
cppfmu::FMIBoolean* earlyReturn,
|
|
210
|
-
cppfmu::FMIFloat64& endOfStep)
|
|
211
|
-
{
|
|
212
|
-
cppfmu::FMIStatus fmuStatus = cppfmu::FMIOK;
|
|
213
|
-
py_safe_run([this, &fmuStatus, currentTime, stepSize, terminateSimulation](PyGILState_STATE gilState) {
|
|
214
|
-
auto f = PyObject_CallMethod(pInstance_, "do_step", "(dd)", currentTime, stepSize);
|
|
215
|
-
if (f == nullptr) {
|
|
216
|
-
handle_py_exception("[doStep] PyObject_CallMethod", gilState);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (PyObject_HasAttrString(f, "status")) {
|
|
220
|
-
PyObject* pyStatus = PyObject_GetAttrString(f, "status");
|
|
221
|
-
if (pyStatus) {
|
|
222
|
-
fmuStatus = static_cast<cppfmu::FMIStatus>(PyLong_AsLong(pyStatus));
|
|
223
|
-
Py_DECREF(pyStatus);
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
bool status = static_cast<bool>(PyObject_IsTrue(f));
|
|
227
|
-
if (!status) {
|
|
228
|
-
fmuStatus = cppfmu::FMIDiscard;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (PyObject_HasAttrString(f, "terminateSimulation")) {
|
|
233
|
-
PyObject* pyTerminateSimulation = PyObject_GetAttrString(f, "terminateSimulation");
|
|
234
|
-
if (pyTerminateSimulation) {
|
|
235
|
-
*terminateSimulation = static_cast<bool>(PyObject_IsTrue(pyTerminateSimulation));
|
|
236
|
-
Py_DECREF(pyTerminateSimulation);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
Py_DECREF(f);
|
|
240
|
-
clearLogBuffer();
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
return fmuStatus;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
void PySlaveInstance::Reset()
|
|
247
|
-
{
|
|
248
|
-
py_safe_run([this](PyGILState_STATE gilState) {
|
|
249
|
-
initialize(gilState);
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
void PySlaveInstance::Terminate()
|
|
254
|
-
{
|
|
255
|
-
py_safe_run([this](PyGILState_STATE gilState) {
|
|
256
|
-
auto f = PyObject_CallMethod(pInstance_, "terminate", nullptr);
|
|
257
|
-
if (f == nullptr) {
|
|
258
|
-
handle_py_exception("[terminate] PyObject_CallMethod", gilState);
|
|
259
|
-
}
|
|
260
|
-
Py_DECREF(f);
|
|
261
|
-
clearLogBuffer();
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
void PySlaveInstance::SetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIFloat64* values, std::size_t nValues)
|
|
266
|
-
{
|
|
267
|
-
py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
|
|
268
|
-
PyObject* vrs = PyList_New(nvr);
|
|
269
|
-
PyObject* refs = PyList_New(nValues);
|
|
270
|
-
for (int i = 0; i < nvr; i++) {
|
|
271
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
272
|
-
}
|
|
273
|
-
for (int i = 0; i < nValues; i++) {
|
|
274
|
-
PyList_SetItem(refs, i, Py_BuildValue("d", values[i]));
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
auto f = PyObject_CallMethod(pInstance_, "set_float64", "(OO)", vrs, refs);
|
|
278
|
-
Py_DECREF(vrs);
|
|
279
|
-
Py_DECREF(refs);
|
|
280
|
-
if (f == nullptr) {
|
|
281
|
-
handle_py_exception("[setFloat64] PyObject_CallMethod", gilState);
|
|
282
|
-
}
|
|
283
|
-
Py_DECREF(f);
|
|
284
|
-
clearLogBuffer();
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
void PySlaveInstance::SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* values)
|
|
289
|
-
{
|
|
290
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
291
|
-
PyObject* vrs = PyList_New(nvr);
|
|
292
|
-
PyObject* refs = PyList_New(nvr);
|
|
293
|
-
for (int i = 0; i < nvr; i++) {
|
|
294
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
295
|
-
PyList_SetItem(refs, i, Py_BuildValue("i", values[i]));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
auto f = PyObject_CallMethod(pInstance_, "set_int32", "(OO)", vrs, refs);
|
|
299
|
-
Py_DECREF(vrs);
|
|
300
|
-
Py_DECREF(refs);
|
|
301
|
-
if (f == nullptr) {
|
|
302
|
-
handle_py_exception("[setInt32] PyObject_CallMethod", gilState);
|
|
303
|
-
}
|
|
304
|
-
Py_DECREF(f);
|
|
305
|
-
clearLogBuffer();
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
void PySlaveInstance::SetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt64* values)
|
|
310
|
-
{
|
|
311
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
312
|
-
PyObject* vrs = PyList_New(nvr);
|
|
313
|
-
PyObject* refs = PyList_New(nvr);
|
|
314
|
-
for (int i = 0; i < nvr; i++) {
|
|
315
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
316
|
-
PyList_SetItem(refs, i, Py_BuildValue("L", values[i]));
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
auto f = PyObject_CallMethod(pInstance_, "set_int64", "(OO)", vrs, refs);
|
|
320
|
-
Py_DECREF(vrs);
|
|
321
|
-
Py_DECREF(refs);
|
|
322
|
-
if (f == nullptr) {
|
|
323
|
-
handle_py_exception("[setInt64] PyObject_CallMethod", gilState);
|
|
324
|
-
}
|
|
325
|
-
Py_DECREF(f);
|
|
326
|
-
clearLogBuffer();
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
void PySlaveInstance::SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIUInt64* values)
|
|
331
|
-
{
|
|
332
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
333
|
-
PyObject* vrs = PyList_New(nvr);
|
|
334
|
-
PyObject* refs = PyList_New(nvr);
|
|
335
|
-
for (int i = 0; i < nvr; i++) {
|
|
336
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
337
|
-
PyList_SetItem(refs, i, Py_BuildValue("K", values[i]));
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
auto f = PyObject_CallMethod(pInstance_, "set_uint64", "(OO)", vrs, refs);
|
|
341
|
-
Py_DECREF(vrs);
|
|
342
|
-
Py_DECREF(refs);
|
|
343
|
-
if (f == nullptr) {
|
|
344
|
-
handle_py_exception("[setUInt64] PyObject_CallMethod", gilState);
|
|
345
|
-
}
|
|
346
|
-
Py_DECREF(f);
|
|
347
|
-
clearLogBuffer();
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
void PySlaveInstance::SetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIBoolean* values)
|
|
352
|
-
{
|
|
353
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
354
|
-
PyObject* vrs = PyList_New(nvr);
|
|
355
|
-
PyObject* refs = PyList_New(nvr);
|
|
356
|
-
for (int i = 0; i < nvr; i++) {
|
|
357
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
358
|
-
PyList_SetItem(refs, i, PyBool_FromLong(values[i]));
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
auto f = PyObject_CallMethod(pInstance_, "set_boolean", "(OO)", vrs, refs);
|
|
362
|
-
Py_DECREF(vrs);
|
|
363
|
-
Py_DECREF(refs);
|
|
364
|
-
if (f == nullptr) {
|
|
365
|
-
handle_py_exception("[setBoolean] PyObject_CallMethod", gilState);
|
|
366
|
-
}
|
|
367
|
-
Py_DECREF(f);
|
|
368
|
-
clearLogBuffer();
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
void PySlaveInstance::SetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString const* values)
|
|
373
|
-
{
|
|
374
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
375
|
-
PyObject* vrs = PyList_New(nvr);
|
|
376
|
-
PyObject* refs = PyList_New(nvr);
|
|
377
|
-
for (int i = 0; i < nvr; i++) {
|
|
378
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
379
|
-
PyList_SetItem(refs, i, Py_BuildValue("s", values[i]));
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
auto f = PyObject_CallMethod(pInstance_, "set_string", "(OO)", vrs, refs);
|
|
383
|
-
Py_DECREF(vrs);
|
|
384
|
-
Py_DECREF(refs);
|
|
385
|
-
if (f == nullptr) {
|
|
386
|
-
handle_py_exception("[setString] PyObject_CallMethod", gilState);
|
|
387
|
-
}
|
|
388
|
-
Py_DECREF(f);
|
|
389
|
-
clearLogBuffer();
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
void PySlaveInstance::GetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIFloat64* values, std::size_t nValues) const
|
|
394
|
-
{
|
|
395
|
-
py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
|
|
396
|
-
PyObject* vrs = PyList_New(nvr);
|
|
397
|
-
for (int i = 0; i < nvr; i++) {
|
|
398
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
auto refs = PyObject_CallMethod(pInstance_, "get_float64", "O", vrs);
|
|
402
|
-
Py_DECREF(vrs);
|
|
403
|
-
if (refs == nullptr) {
|
|
404
|
-
handle_py_exception("[getFloat64] PyObject_CallMethod", gilState);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
for (int i = 0; i < nValues; i++) {
|
|
408
|
-
PyObject* value = PyList_GetItem(refs, i);
|
|
409
|
-
values[i] = PyFloat_AsDouble(value);
|
|
410
|
-
}
|
|
411
|
-
Py_DECREF(refs);
|
|
412
|
-
clearLogBuffer();
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
void PySlaveInstance::GetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt32* values) const
|
|
417
|
-
{
|
|
418
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
419
|
-
PyObject* vrs = PyList_New(nvr);
|
|
420
|
-
for (int i = 0; i < nvr; i++) {
|
|
421
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
422
|
-
}
|
|
423
|
-
auto refs = PyObject_CallMethod(pInstance_, "get_int32", "O", vrs);
|
|
424
|
-
Py_DECREF(vrs);
|
|
425
|
-
if (refs == nullptr) {
|
|
426
|
-
handle_py_exception("[getInt32] PyObject_CallMethod", gilState);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
for (int i = 0; i < nvr; i++) {
|
|
430
|
-
PyObject* value = PyList_GetItem(refs, i);
|
|
431
|
-
values[i] = static_cast<cppfmu::FMIInt32>(PyLong_AsLong(value));
|
|
432
|
-
}
|
|
433
|
-
Py_DECREF(refs);
|
|
434
|
-
clearLogBuffer();
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
void PySlaveInstance::GetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt64* values) const
|
|
439
|
-
{
|
|
440
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
441
|
-
PyObject* vrs = PyList_New(nvr);
|
|
442
|
-
for (int i = 0; i < nvr; i++) {
|
|
443
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
444
|
-
}
|
|
445
|
-
auto refs = PyObject_CallMethod(pInstance_, "get_int64", "O", vrs);
|
|
446
|
-
Py_DECREF(vrs);
|
|
447
|
-
if (refs == nullptr) {
|
|
448
|
-
handle_py_exception("[getInt64] PyObject_CallMethod", gilState);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
for (int i = 0; i < nvr; i++) {
|
|
452
|
-
PyObject* value = PyList_GetItem(refs, i);
|
|
453
|
-
values[i] = static_cast<cppfmu::FMIInt64>(PyLong_AsLongLong(value));
|
|
454
|
-
}
|
|
455
|
-
Py_DECREF(refs);
|
|
456
|
-
clearLogBuffer();
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
void PySlaveInstance::GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIUInt64* values) const
|
|
461
|
-
{
|
|
462
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
463
|
-
PyObject* vrs = PyList_New(nvr);
|
|
464
|
-
for (int i = 0; i < nvr; i++) {
|
|
465
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
466
|
-
}
|
|
467
|
-
auto refs = PyObject_CallMethod(pInstance_, "get_uint64", "O", vrs);
|
|
468
|
-
Py_DECREF(vrs);
|
|
469
|
-
if (refs == nullptr) {
|
|
470
|
-
handle_py_exception("[getUInt64] PyObject_CallMethod", gilState);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
for (int i = 0; i < nvr; i++) {
|
|
474
|
-
PyObject* item = PyList_GetItem(refs, i);
|
|
475
|
-
PyObject* value = PyObject_GetAttrString(item, "value");
|
|
476
|
-
if (value && PyLong_Check(value))
|
|
477
|
-
{
|
|
478
|
-
values[i] = static_cast<cppfmu::FMIUInt64>(PyLong_AsUnsignedLongLong(value));
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
Py_DECREF(refs);
|
|
483
|
-
clearLogBuffer();
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
void PySlaveInstance::GetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIBoolean* values) const
|
|
488
|
-
{
|
|
489
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
490
|
-
PyObject* vrs = PyList_New(nvr);
|
|
491
|
-
for (int i = 0; i < nvr; i++) {
|
|
492
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
493
|
-
}
|
|
494
|
-
auto refs = PyObject_CallMethod(pInstance_, "get_boolean", "O", vrs);
|
|
495
|
-
Py_DECREF(vrs);
|
|
496
|
-
if (refs == nullptr) {
|
|
497
|
-
handle_py_exception("[getBoolean] PyObject_CallMethod", gilState);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
for (int i = 0; i < nvr; i++) {
|
|
501
|
-
PyObject* value = PyList_GetItem(refs, i);
|
|
502
|
-
values[i] = PyObject_IsTrue(value);
|
|
503
|
-
}
|
|
504
|
-
Py_DECREF(refs);
|
|
505
|
-
clearLogBuffer();
|
|
506
|
-
});
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
void PySlaveInstance::GetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString* values) const
|
|
510
|
-
{
|
|
511
|
-
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
512
|
-
clearStrBuffer();
|
|
513
|
-
PyObject* vrs = PyList_New(nvr);
|
|
514
|
-
for (int i = 0; i < nvr; i++) {
|
|
515
|
-
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
516
|
-
}
|
|
517
|
-
auto refs = PyObject_CallMethod(pInstance_, "get_string", "O", vrs);
|
|
518
|
-
Py_DECREF(vrs);
|
|
519
|
-
if (refs == nullptr) {
|
|
520
|
-
handle_py_exception("[getString] PyObject_CallMethod", gilState);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
for (int i = 0; i < nvr; i++) {
|
|
524
|
-
PyObject* value = PyUnicode_AsEncodedString(PyList_GetItem(refs, i), "utf-8", nullptr);
|
|
525
|
-
values[i] = PyBytes_AsString(value);
|
|
526
|
-
strBuffer.emplace_back(value);
|
|
527
|
-
}
|
|
528
|
-
Py_DECREF(refs);
|
|
529
|
-
clearLogBuffer();
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
void PySlaveInstance::GetFMUstate(fmi3FMUState& state)
|
|
534
|
-
{
|
|
535
|
-
py_safe_run([this, &state](PyGILState_STATE gilState) {
|
|
536
|
-
auto f = PyObject_CallMethod(pInstance_, "_get_fmu_state", nullptr);
|
|
537
|
-
if (f == nullptr) {
|
|
538
|
-
handle_py_exception("[_get_fmu_state] PyObject_CallMethod", gilState);
|
|
539
|
-
}
|
|
540
|
-
state = reinterpret_cast<fmi3FMUState*>(f);
|
|
541
|
-
clearLogBuffer();
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
void PySlaveInstance::SetFMUstate(const fmi3FMUState& state)
|
|
546
|
-
{
|
|
547
|
-
py_safe_run([this, &state](PyGILState_STATE gilState) {
|
|
548
|
-
auto pyState = reinterpret_cast<PyObject*>(state);
|
|
549
|
-
auto f = PyObject_CallMethod(pInstance_, "_set_fmu_state", "(O)", pyState);
|
|
550
|
-
if (f == nullptr) {
|
|
551
|
-
handle_py_exception("[_set_fmu_state] PyObject_CallMethod", gilState);
|
|
552
|
-
}
|
|
553
|
-
clearLogBuffer();
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
void PySlaveInstance::FreeFMUstate(fmi3FMUState& state)
|
|
558
|
-
{
|
|
559
|
-
py_safe_run([this, &state](PyGILState_STATE gilState) {
|
|
560
|
-
auto f = reinterpret_cast<PyObject*>(state);
|
|
561
|
-
Py_XDECREF(f);
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
size_t PySlaveInstance::SerializedFMUstateSize(const fmi3FMUState& state)
|
|
566
|
-
{
|
|
567
|
-
size_t size;
|
|
568
|
-
py_safe_run([this, &state, &size](PyGILState_STATE gilState) {
|
|
569
|
-
auto pyState = reinterpret_cast<PyObject*>(state);
|
|
570
|
-
PyObject* pyStateBytes = PyObject_CallMethod(pClass_, "_fmu_state_to_bytes", "(O)", pyState);
|
|
571
|
-
if (pyStateBytes == nullptr) {
|
|
572
|
-
handle_py_exception("[SerializedFMUstateSize] PyObject_CallMethod", gilState);
|
|
573
|
-
}
|
|
574
|
-
size = PyBytes_Size(pyStateBytes);
|
|
575
|
-
Py_DECREF(pyStateBytes);
|
|
576
|
-
clearLogBuffer();
|
|
577
|
-
});
|
|
578
|
-
return size;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
void PySlaveInstance::SerializeFMUstate(const fmi3FMUState& state, fmi3Byte* bytes, size_t size)
|
|
582
|
-
{
|
|
583
|
-
py_safe_run([this, &state, &bytes, size](PyGILState_STATE gilState) {
|
|
584
|
-
auto pyState = reinterpret_cast<PyObject*>(state);
|
|
585
|
-
PyObject* pyStateBytes = PyObject_CallMethod(pClass_, "_fmu_state_to_bytes", "(O)", pyState);
|
|
586
|
-
if (pyStateBytes == nullptr) {
|
|
587
|
-
handle_py_exception("[SerializeFMUstate] PyObject_CallMethod", gilState);
|
|
588
|
-
}
|
|
589
|
-
char* c = PyBytes_AsString(pyStateBytes);
|
|
590
|
-
if (c == nullptr) {
|
|
591
|
-
handle_py_exception("[SerializeFMUstate] PyBytes_AsString", gilState);
|
|
592
|
-
}
|
|
593
|
-
for (int i = 0; i < size; i++) {
|
|
594
|
-
bytes[i] = c[i];
|
|
595
|
-
}
|
|
596
|
-
Py_DECREF(pyStateBytes);
|
|
597
|
-
clearLogBuffer();
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
void PySlaveInstance::DeSerializeFMUstate(const fmi3Byte bytes[], size_t size, fmi3FMUState& state)
|
|
602
|
-
{
|
|
603
|
-
py_safe_run([this, &bytes, size, &state](PyGILState_STATE gilState) {
|
|
604
|
-
char const * castedBytes = reinterpret_cast<char const*>(bytes);
|
|
605
|
-
PyObject* pyStateBytes = PyBytes_FromStringAndSize(castedBytes, size);
|
|
606
|
-
if (pyStateBytes == nullptr) {
|
|
607
|
-
handle_py_exception("[DeSerializeFMUstate] PyBytes_FromStringAndSize", gilState);
|
|
608
|
-
}
|
|
609
|
-
PyObject* pyState = PyObject_CallMethod(pClass_, "_fmu_state_from_bytes", "(O)", pyStateBytes);
|
|
610
|
-
if (pyState == nullptr) {
|
|
611
|
-
handle_py_exception("[DeSerializeFMUstate] PyObject_CallMethod", gilState);
|
|
612
|
-
}
|
|
613
|
-
state = reinterpret_cast<fmi3FMUState*>(pyState);
|
|
614
|
-
Py_DECREF(pyStateBytes);
|
|
615
|
-
clearLogBuffer();
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
void PySlaveInstance::handle_py_exception(const std::string& what, PyGILState_STATE gilState) const
|
|
620
|
-
{
|
|
621
|
-
auto err = PyErr_Occurred();
|
|
622
|
-
if (err != nullptr) {
|
|
623
|
-
cleanPyObject();
|
|
624
|
-
|
|
625
|
-
PyObject *pExcType, *pExcValue, *pExcTraceback;
|
|
626
|
-
PyErr_Fetch(&pExcType, &pExcValue, &pExcTraceback);
|
|
627
|
-
|
|
628
|
-
std::ostringstream oss;
|
|
629
|
-
oss << "Fatal py exception encountered: ";
|
|
630
|
-
oss << what << "\n";
|
|
631
|
-
if (pExcValue != nullptr) {
|
|
632
|
-
PyObject* pRepr = PyObject_Repr(pExcValue);
|
|
633
|
-
PyObject* pyStr = PyUnicode_AsEncodedString(pRepr, "utf-8", nullptr);
|
|
634
|
-
oss << PyBytes_AsString(pyStr);
|
|
635
|
-
Py_DECREF(pyStr);
|
|
636
|
-
Py_DECREF(pRepr);
|
|
637
|
-
} else {
|
|
638
|
-
oss << "unknown error";
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
PyErr_Clear();
|
|
642
|
-
|
|
643
|
-
Py_XDECREF(pExcType);
|
|
644
|
-
Py_XDECREF(pExcValue);
|
|
645
|
-
Py_XDECREF(pExcTraceback);
|
|
646
|
-
|
|
647
|
-
PyGILState_Release(gilState);
|
|
648
|
-
|
|
649
|
-
auto msg = oss.str();
|
|
650
|
-
throw cppfmu::FatalError(msg.c_str());
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
PySlaveInstance::~PySlaveInstance()
|
|
655
|
-
{
|
|
656
|
-
py_safe_run([this](PyGILState_STATE gilState) {
|
|
657
|
-
cleanPyObject();
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
} // namespace pythonfmu
|
|
662
|
-
|
|
663
|
-
namespace {
|
|
664
|
-
std::mutex pyStateMutex{};
|
|
665
|
-
std::shared_ptr<pythonfmu::PyState> pyState{};
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
std::unique_ptr<cppfmu::SlaveInstance> CppfmuInstantiateSlave(
|
|
669
|
-
cppfmu::FMIString instanceName,
|
|
670
|
-
cppfmu::FMIString,
|
|
671
|
-
cppfmu::FMIString fmuResourceLocation,
|
|
672
|
-
cppfmu::FMIString,
|
|
673
|
-
cppfmu::FMIFloat64,
|
|
674
|
-
cppfmu::FMIBoolean visible,
|
|
675
|
-
cppfmu::FMIBoolean,
|
|
676
|
-
const cppfmu::Logger& logger)
|
|
677
|
-
{
|
|
678
|
-
|
|
679
|
-
// Convert URI %20 to space
|
|
680
|
-
auto resources = std::regex_replace(std::string(fmuResourceLocation), std::regex("%20"), " ");
|
|
681
|
-
auto find = resources.find("file://");
|
|
682
|
-
|
|
683
|
-
if (find != std::string::npos) {
|
|
684
|
-
#ifdef _MSC_VER
|
|
685
|
-
resources.replace(find, 8, "");
|
|
686
|
-
#else
|
|
687
|
-
resources.replace(find, 7, "");
|
|
688
|
-
#endif
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
{
|
|
692
|
-
auto const ensurePyStateAlive = [&]() {
|
|
693
|
-
auto const lock = std::lock_guard{pyStateMutex};
|
|
694
|
-
if (nullptr == pyState) pyState = std::make_shared<pythonfmu::PyState>();
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
ensurePyStateAlive();
|
|
698
|
-
return std::make_unique<pythonfmu::PySlaveInstance>(
|
|
699
|
-
instanceName, resources, logger, visible, pyState);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
extern "C" {
|
|
704
|
-
|
|
705
|
-
// The PyState instance owns it's own thread for constructing and destroying the Py* from the same thread.
|
|
706
|
-
// Creation of an std::thread increments ref counter of a shared library. So, when the client unloads the library
|
|
707
|
-
// the library won't be freed, as std::thread is alive, and the std::thread itself waits for de-initialization request.
|
|
708
|
-
// Thus, use DllMain on Windows and __attribute__((destructor)) on Linux for signaling to the PyState about de-initialization.
|
|
709
|
-
void finalizePythonInterpreter()
|
|
710
|
-
{
|
|
711
|
-
pyState = nullptr;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
namespace
|
|
716
|
-
{
|
|
717
|
-
#ifdef _WIN32
|
|
718
|
-
#include <windows.h>
|
|
719
|
-
|
|
720
|
-
BOOL APIENTRY DllMain(HMODULE hModule,
|
|
721
|
-
DWORD ul_reason_for_call,
|
|
722
|
-
LPVOID lpReserved)
|
|
723
|
-
{
|
|
724
|
-
switch (ul_reason_for_call) {
|
|
725
|
-
case DLL_PROCESS_ATTACH:
|
|
726
|
-
break;
|
|
727
|
-
case DLL_THREAD_ATTACH:
|
|
728
|
-
case DLL_THREAD_DETACH:
|
|
729
|
-
break;
|
|
730
|
-
case DLL_PROCESS_DETACH:
|
|
731
|
-
finalizePythonInterpreter();
|
|
732
|
-
break;
|
|
733
|
-
}
|
|
734
|
-
return TRUE;
|
|
735
|
-
}
|
|
736
|
-
#elif defined(__linux__) || defined(__APPLE__)
|
|
737
|
-
__attribute__((destructor)) void onLibraryUnload()
|
|
738
|
-
{
|
|
739
|
-
finalizePythonInterpreter();
|
|
740
|
-
}
|
|
741
|
-
#else
|
|
742
|
-
#error port the code
|
|
743
|
-
#endif
|
|
744
|
-
}
|
|
1
|
+
|
|
2
|
+
#include "pythonfmu/IPyState.hpp"
|
|
3
|
+
#include "pythonfmu/PySlaveInstance.hpp"
|
|
4
|
+
|
|
5
|
+
#include "pythonfmu/PyState.hpp"
|
|
6
|
+
|
|
7
|
+
#include "cppfmu/cppfmu_cs.hpp"
|
|
8
|
+
|
|
9
|
+
#include <fstream>
|
|
10
|
+
#include <functional>
|
|
11
|
+
#include <mutex>
|
|
12
|
+
#include <regex>
|
|
13
|
+
#include <sstream>
|
|
14
|
+
#include <utility>
|
|
15
|
+
|
|
16
|
+
namespace pythonfmu
|
|
17
|
+
{
|
|
18
|
+
|
|
19
|
+
inline std::string getline(const std::string& fileName)
|
|
20
|
+
{
|
|
21
|
+
std::string line;
|
|
22
|
+
std::ifstream infile(fileName);
|
|
23
|
+
std::getline(infile, line);
|
|
24
|
+
return line;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
inline std::string findClassName(const std::string& fileName)
|
|
28
|
+
{
|
|
29
|
+
std::string line;
|
|
30
|
+
std::ifstream infile(fileName);
|
|
31
|
+
std::string regexStr(R"(^class (\w+)\(\s*Fmi3Slave\s*\)\s*:)");
|
|
32
|
+
while (getline(infile, line)) {
|
|
33
|
+
std::smatch m;
|
|
34
|
+
std::regex re(regexStr);
|
|
35
|
+
if (std::regex_search(line, m, re)) {
|
|
36
|
+
return m[1];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return "";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
inline void py_safe_run(const std::function<void(PyGILState_STATE gilState)>& f)
|
|
43
|
+
{
|
|
44
|
+
PyGILState_STATE gil_state = PyGILState_Ensure();
|
|
45
|
+
f(gil_state);
|
|
46
|
+
PyGILState_Release(gil_state);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
PySlaveInstance::PySlaveInstance(std::string instanceName, std::string resources, const cppfmu::Logger& logger, const bool visible, std::shared_ptr<IPyState> pyState)
|
|
50
|
+
: pyState_{ std::move(pyState) }
|
|
51
|
+
, instanceName_(std::move(instanceName))
|
|
52
|
+
, resources_(std::move(resources))
|
|
53
|
+
, logger_(logger)
|
|
54
|
+
, visible_(visible)
|
|
55
|
+
{
|
|
56
|
+
py_safe_run([this](PyGILState_STATE gilState) {
|
|
57
|
+
// Append resources path to python sys path
|
|
58
|
+
PyObject* sys_module = PyImport_ImportModule("sys");
|
|
59
|
+
if (sys_module == nullptr) {
|
|
60
|
+
handle_py_exception("[ctor] PyImport_ImportModule", gilState);
|
|
61
|
+
}
|
|
62
|
+
PyObject* sys_path = PyObject_GetAttrString(sys_module, "path");
|
|
63
|
+
Py_DECREF(sys_module);
|
|
64
|
+
if (sys_path == nullptr) {
|
|
65
|
+
handle_py_exception("[ctor] PyObject_GetAttrString", gilState);
|
|
66
|
+
}
|
|
67
|
+
int success = PyList_Insert(sys_path, 0, PyUnicode_FromString(resources_.c_str()));
|
|
68
|
+
Py_DECREF(sys_path);
|
|
69
|
+
if (success != 0) {
|
|
70
|
+
handle_py_exception("[ctor] PyList_Insert", gilState);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
std::string moduleName = getline(resources_ + "/slavemodule.txt");
|
|
74
|
+
PyObject* pModule = PyImport_ImportModule(moduleName.c_str());
|
|
75
|
+
if (pModule == nullptr) {
|
|
76
|
+
PyErr_Print();
|
|
77
|
+
handle_py_exception("[ctor] PyImport_ImportModule", gilState);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
std::string className = findClassName(resources_ + "/" + moduleName + ".py");
|
|
81
|
+
if (className.empty()) {
|
|
82
|
+
cleanPyObject();
|
|
83
|
+
throw cppfmu::FatalError("Unable to find class extending Fmi3Slave!");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
PyObject* pyClassName = Py_BuildValue("s", className.c_str());
|
|
87
|
+
if (pyClassName == nullptr) {
|
|
88
|
+
handle_py_exception("[ctor] Py_BuildValue", gilState);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pClass_ = PyObject_GetAttr(pModule, pyClassName);
|
|
92
|
+
Py_DECREF(pyClassName);
|
|
93
|
+
Py_DECREF(pModule);
|
|
94
|
+
if (pClass_ == nullptr) {
|
|
95
|
+
handle_py_exception("[ctor] PyObject_GetAttr", gilState);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
initialize(gilState);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void PySlaveInstance::clearLogBuffer() const
|
|
103
|
+
{
|
|
104
|
+
clearLogStrBuffer();
|
|
105
|
+
|
|
106
|
+
PyObject* debugField = Py_BuildValue("s", "debug");
|
|
107
|
+
PyObject* msgField = Py_BuildValue("s", "msg");
|
|
108
|
+
PyObject* categoryField = Py_BuildValue("s", "category");
|
|
109
|
+
PyObject* statusField = Py_BuildValue("s", "status");
|
|
110
|
+
|
|
111
|
+
if ( pMessages_ != NULL && PyList_Check(pMessages_) ) {
|
|
112
|
+
auto size = PyList_Size(pMessages_);
|
|
113
|
+
for (auto i = 0; i < size; i++) {
|
|
114
|
+
PyObject* msg = PyList_GetItem(pMessages_, i);
|
|
115
|
+
|
|
116
|
+
auto debugAttr = PyObject_GetAttr(msg, debugField);
|
|
117
|
+
auto msgAttr = PyObject_GetAttr(msg, msgField);
|
|
118
|
+
auto categoryAttr = PyObject_GetAttr(msg, categoryField);
|
|
119
|
+
auto statusAttr = PyObject_GetAttr(msg, statusField);
|
|
120
|
+
|
|
121
|
+
auto statusValue = static_cast<cppfmu::FMIStatus>(PyLong_AsLong(statusAttr));
|
|
122
|
+
|
|
123
|
+
PyObject* msgValue = PyUnicode_AsEncodedString(msgAttr, "utf-8", nullptr);
|
|
124
|
+
char* msgStr = PyBytes_AsString(msgValue);
|
|
125
|
+
logStrBuffer.emplace_back(msgValue);
|
|
126
|
+
|
|
127
|
+
const char* categoryStr = "";
|
|
128
|
+
if (categoryAttr != Py_None) {
|
|
129
|
+
PyObject* categoryValue = PyUnicode_AsEncodedString(categoryAttr, "utf-8", nullptr);
|
|
130
|
+
categoryStr = PyBytes_AsString(categoryValue);
|
|
131
|
+
logStrBuffer.emplace_back(categoryValue);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (PyObject_IsTrue(debugAttr)) {
|
|
135
|
+
const_cast<cppfmu::Logger&>(logger_).DebugLog(statusValue, categoryStr, msgStr);
|
|
136
|
+
} else {
|
|
137
|
+
const_cast<cppfmu::Logger&>(logger_).Log(statusValue, categoryStr, msgStr);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
PyList_SetSlice(pMessages_, 0, size, nullptr);
|
|
141
|
+
}
|
|
142
|
+
Py_DECREF(debugField);
|
|
143
|
+
Py_DECREF(msgField);
|
|
144
|
+
Py_DECREF(categoryField);
|
|
145
|
+
Py_DECREF(statusField);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void PySlaveInstance::initialize(PyGILState_STATE gilState)
|
|
149
|
+
{
|
|
150
|
+
Py_XDECREF(pInstance_);
|
|
151
|
+
Py_XDECREF(pMessages_);
|
|
152
|
+
|
|
153
|
+
PyObject* args = PyTuple_New(0);
|
|
154
|
+
PyObject* kwargs = Py_BuildValue("{ss,ss,sn,si}",
|
|
155
|
+
"instance_name", instanceName_.c_str(),
|
|
156
|
+
"resources", resources_.c_str(),
|
|
157
|
+
"logger", &logger_,
|
|
158
|
+
"visible", visible_);
|
|
159
|
+
pInstance_ = PyObject_Call(pClass_, args, kwargs);
|
|
160
|
+
Py_DECREF(args);
|
|
161
|
+
Py_DECREF(kwargs);
|
|
162
|
+
if (pInstance_ == nullptr) {
|
|
163
|
+
handle_py_exception("[initialize] PyObject_Call", gilState);
|
|
164
|
+
}
|
|
165
|
+
pMessages_ = PyObject_CallMethod(pInstance_, "_get_log_queue", nullptr);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
void PySlaveInstance::SetupExperiment(cppfmu::FMIBoolean, cppfmu::FMIFloat64, cppfmu::FMIFloat64 startTime, cppfmu::FMIBoolean, cppfmu::FMIFloat64)
|
|
169
|
+
{
|
|
170
|
+
py_safe_run([this, startTime](PyGILState_STATE gilState) {
|
|
171
|
+
auto f = PyObject_CallMethod(pInstance_, "setup_experiment", "(d)", startTime);
|
|
172
|
+
if (f == nullptr) {
|
|
173
|
+
handle_py_exception("[setupExperiment] PyObject_CallMethod", gilState);
|
|
174
|
+
}
|
|
175
|
+
Py_DECREF(f);
|
|
176
|
+
clearLogBuffer();
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
void PySlaveInstance::EnterInitializationMode()
|
|
181
|
+
{
|
|
182
|
+
py_safe_run([this](PyGILState_STATE gilState) {
|
|
183
|
+
auto f = PyObject_CallMethod(pInstance_, "enter_initialization_mode", nullptr);
|
|
184
|
+
if (f == nullptr) {
|
|
185
|
+
handle_py_exception("[enterInitializationMode] PyObject_CallMethod", gilState);
|
|
186
|
+
}
|
|
187
|
+
Py_DECREF(f);
|
|
188
|
+
clearLogBuffer();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
void PySlaveInstance::ExitInitializationMode()
|
|
193
|
+
{
|
|
194
|
+
py_safe_run([this](PyGILState_STATE gilState) {
|
|
195
|
+
auto f = PyObject_CallMethod(pInstance_, "exit_initialization_mode", nullptr);
|
|
196
|
+
if (f == nullptr) {
|
|
197
|
+
handle_py_exception("[exitInitializationMode] PyObject_CallMethod", gilState);
|
|
198
|
+
}
|
|
199
|
+
Py_DECREF(f);
|
|
200
|
+
clearLogBuffer();
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
cppfmu::FMIStatus PySlaveInstance::DoStep(cppfmu::FMIFloat64 currentTime,
|
|
205
|
+
cppfmu::FMIFloat64 stepSize,
|
|
206
|
+
cppfmu::FMIBoolean noSetFmuStatePriorToCurrentPoint,
|
|
207
|
+
cppfmu::FMIBoolean* eventHandlingNeeded,
|
|
208
|
+
cppfmu::FMIBoolean* terminateSimulation,
|
|
209
|
+
cppfmu::FMIBoolean* earlyReturn,
|
|
210
|
+
cppfmu::FMIFloat64& endOfStep)
|
|
211
|
+
{
|
|
212
|
+
cppfmu::FMIStatus fmuStatus = cppfmu::FMIOK;
|
|
213
|
+
py_safe_run([this, &fmuStatus, currentTime, stepSize, terminateSimulation](PyGILState_STATE gilState) {
|
|
214
|
+
auto f = PyObject_CallMethod(pInstance_, "do_step", "(dd)", currentTime, stepSize);
|
|
215
|
+
if (f == nullptr) {
|
|
216
|
+
handle_py_exception("[doStep] PyObject_CallMethod", gilState);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (PyObject_HasAttrString(f, "status")) {
|
|
220
|
+
PyObject* pyStatus = PyObject_GetAttrString(f, "status");
|
|
221
|
+
if (pyStatus) {
|
|
222
|
+
fmuStatus = static_cast<cppfmu::FMIStatus>(PyLong_AsLong(pyStatus));
|
|
223
|
+
Py_DECREF(pyStatus);
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
bool status = static_cast<bool>(PyObject_IsTrue(f));
|
|
227
|
+
if (!status) {
|
|
228
|
+
fmuStatus = cppfmu::FMIDiscard;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (PyObject_HasAttrString(f, "terminateSimulation")) {
|
|
233
|
+
PyObject* pyTerminateSimulation = PyObject_GetAttrString(f, "terminateSimulation");
|
|
234
|
+
if (pyTerminateSimulation) {
|
|
235
|
+
*terminateSimulation = static_cast<bool>(PyObject_IsTrue(pyTerminateSimulation));
|
|
236
|
+
Py_DECREF(pyTerminateSimulation);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
Py_DECREF(f);
|
|
240
|
+
clearLogBuffer();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return fmuStatus;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
void PySlaveInstance::Reset()
|
|
247
|
+
{
|
|
248
|
+
py_safe_run([this](PyGILState_STATE gilState) {
|
|
249
|
+
initialize(gilState);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
void PySlaveInstance::Terminate()
|
|
254
|
+
{
|
|
255
|
+
py_safe_run([this](PyGILState_STATE gilState) {
|
|
256
|
+
auto f = PyObject_CallMethod(pInstance_, "terminate", nullptr);
|
|
257
|
+
if (f == nullptr) {
|
|
258
|
+
handle_py_exception("[terminate] PyObject_CallMethod", gilState);
|
|
259
|
+
}
|
|
260
|
+
Py_DECREF(f);
|
|
261
|
+
clearLogBuffer();
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
void PySlaveInstance::SetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIFloat64* values, std::size_t nValues)
|
|
266
|
+
{
|
|
267
|
+
py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
|
|
268
|
+
PyObject* vrs = PyList_New(nvr);
|
|
269
|
+
PyObject* refs = PyList_New(nValues);
|
|
270
|
+
for (int i = 0; i < nvr; i++) {
|
|
271
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
272
|
+
}
|
|
273
|
+
for (int i = 0; i < nValues; i++) {
|
|
274
|
+
PyList_SetItem(refs, i, Py_BuildValue("d", values[i]));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
auto f = PyObject_CallMethod(pInstance_, "set_float64", "(OO)", vrs, refs);
|
|
278
|
+
Py_DECREF(vrs);
|
|
279
|
+
Py_DECREF(refs);
|
|
280
|
+
if (f == nullptr) {
|
|
281
|
+
handle_py_exception("[setFloat64] PyObject_CallMethod", gilState);
|
|
282
|
+
}
|
|
283
|
+
Py_DECREF(f);
|
|
284
|
+
clearLogBuffer();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
void PySlaveInstance::SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* values)
|
|
289
|
+
{
|
|
290
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
291
|
+
PyObject* vrs = PyList_New(nvr);
|
|
292
|
+
PyObject* refs = PyList_New(nvr);
|
|
293
|
+
for (int i = 0; i < nvr; i++) {
|
|
294
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
295
|
+
PyList_SetItem(refs, i, Py_BuildValue("i", values[i]));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
auto f = PyObject_CallMethod(pInstance_, "set_int32", "(OO)", vrs, refs);
|
|
299
|
+
Py_DECREF(vrs);
|
|
300
|
+
Py_DECREF(refs);
|
|
301
|
+
if (f == nullptr) {
|
|
302
|
+
handle_py_exception("[setInt32] PyObject_CallMethod", gilState);
|
|
303
|
+
}
|
|
304
|
+
Py_DECREF(f);
|
|
305
|
+
clearLogBuffer();
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
void PySlaveInstance::SetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt64* values)
|
|
310
|
+
{
|
|
311
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
312
|
+
PyObject* vrs = PyList_New(nvr);
|
|
313
|
+
PyObject* refs = PyList_New(nvr);
|
|
314
|
+
for (int i = 0; i < nvr; i++) {
|
|
315
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
316
|
+
PyList_SetItem(refs, i, Py_BuildValue("L", values[i]));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
auto f = PyObject_CallMethod(pInstance_, "set_int64", "(OO)", vrs, refs);
|
|
320
|
+
Py_DECREF(vrs);
|
|
321
|
+
Py_DECREF(refs);
|
|
322
|
+
if (f == nullptr) {
|
|
323
|
+
handle_py_exception("[setInt64] PyObject_CallMethod", gilState);
|
|
324
|
+
}
|
|
325
|
+
Py_DECREF(f);
|
|
326
|
+
clearLogBuffer();
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
void PySlaveInstance::SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIUInt64* values)
|
|
331
|
+
{
|
|
332
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
333
|
+
PyObject* vrs = PyList_New(nvr);
|
|
334
|
+
PyObject* refs = PyList_New(nvr);
|
|
335
|
+
for (int i = 0; i < nvr; i++) {
|
|
336
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
337
|
+
PyList_SetItem(refs, i, Py_BuildValue("K", values[i]));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
auto f = PyObject_CallMethod(pInstance_, "set_uint64", "(OO)", vrs, refs);
|
|
341
|
+
Py_DECREF(vrs);
|
|
342
|
+
Py_DECREF(refs);
|
|
343
|
+
if (f == nullptr) {
|
|
344
|
+
handle_py_exception("[setUInt64] PyObject_CallMethod", gilState);
|
|
345
|
+
}
|
|
346
|
+
Py_DECREF(f);
|
|
347
|
+
clearLogBuffer();
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
void PySlaveInstance::SetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIBoolean* values)
|
|
352
|
+
{
|
|
353
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
354
|
+
PyObject* vrs = PyList_New(nvr);
|
|
355
|
+
PyObject* refs = PyList_New(nvr);
|
|
356
|
+
for (int i = 0; i < nvr; i++) {
|
|
357
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
358
|
+
PyList_SetItem(refs, i, PyBool_FromLong(values[i]));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
auto f = PyObject_CallMethod(pInstance_, "set_boolean", "(OO)", vrs, refs);
|
|
362
|
+
Py_DECREF(vrs);
|
|
363
|
+
Py_DECREF(refs);
|
|
364
|
+
if (f == nullptr) {
|
|
365
|
+
handle_py_exception("[setBoolean] PyObject_CallMethod", gilState);
|
|
366
|
+
}
|
|
367
|
+
Py_DECREF(f);
|
|
368
|
+
clearLogBuffer();
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
void PySlaveInstance::SetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString const* values)
|
|
373
|
+
{
|
|
374
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
375
|
+
PyObject* vrs = PyList_New(nvr);
|
|
376
|
+
PyObject* refs = PyList_New(nvr);
|
|
377
|
+
for (int i = 0; i < nvr; i++) {
|
|
378
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
379
|
+
PyList_SetItem(refs, i, Py_BuildValue("s", values[i]));
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
auto f = PyObject_CallMethod(pInstance_, "set_string", "(OO)", vrs, refs);
|
|
383
|
+
Py_DECREF(vrs);
|
|
384
|
+
Py_DECREF(refs);
|
|
385
|
+
if (f == nullptr) {
|
|
386
|
+
handle_py_exception("[setString] PyObject_CallMethod", gilState);
|
|
387
|
+
}
|
|
388
|
+
Py_DECREF(f);
|
|
389
|
+
clearLogBuffer();
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
void PySlaveInstance::GetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIFloat64* values, std::size_t nValues) const
|
|
394
|
+
{
|
|
395
|
+
py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
|
|
396
|
+
PyObject* vrs = PyList_New(nvr);
|
|
397
|
+
for (int i = 0; i < nvr; i++) {
|
|
398
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
auto refs = PyObject_CallMethod(pInstance_, "get_float64", "O", vrs);
|
|
402
|
+
Py_DECREF(vrs);
|
|
403
|
+
if (refs == nullptr) {
|
|
404
|
+
handle_py_exception("[getFloat64] PyObject_CallMethod", gilState);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
for (int i = 0; i < nValues; i++) {
|
|
408
|
+
PyObject* value = PyList_GetItem(refs, i);
|
|
409
|
+
values[i] = PyFloat_AsDouble(value);
|
|
410
|
+
}
|
|
411
|
+
Py_DECREF(refs);
|
|
412
|
+
clearLogBuffer();
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
void PySlaveInstance::GetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt32* values) const
|
|
417
|
+
{
|
|
418
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
419
|
+
PyObject* vrs = PyList_New(nvr);
|
|
420
|
+
for (int i = 0; i < nvr; i++) {
|
|
421
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
422
|
+
}
|
|
423
|
+
auto refs = PyObject_CallMethod(pInstance_, "get_int32", "O", vrs);
|
|
424
|
+
Py_DECREF(vrs);
|
|
425
|
+
if (refs == nullptr) {
|
|
426
|
+
handle_py_exception("[getInt32] PyObject_CallMethod", gilState);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
for (int i = 0; i < nvr; i++) {
|
|
430
|
+
PyObject* value = PyList_GetItem(refs, i);
|
|
431
|
+
values[i] = static_cast<cppfmu::FMIInt32>(PyLong_AsLong(value));
|
|
432
|
+
}
|
|
433
|
+
Py_DECREF(refs);
|
|
434
|
+
clearLogBuffer();
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
void PySlaveInstance::GetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt64* values) const
|
|
439
|
+
{
|
|
440
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
441
|
+
PyObject* vrs = PyList_New(nvr);
|
|
442
|
+
for (int i = 0; i < nvr; i++) {
|
|
443
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
444
|
+
}
|
|
445
|
+
auto refs = PyObject_CallMethod(pInstance_, "get_int64", "O", vrs);
|
|
446
|
+
Py_DECREF(vrs);
|
|
447
|
+
if (refs == nullptr) {
|
|
448
|
+
handle_py_exception("[getInt64] PyObject_CallMethod", gilState);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
for (int i = 0; i < nvr; i++) {
|
|
452
|
+
PyObject* value = PyList_GetItem(refs, i);
|
|
453
|
+
values[i] = static_cast<cppfmu::FMIInt64>(PyLong_AsLongLong(value));
|
|
454
|
+
}
|
|
455
|
+
Py_DECREF(refs);
|
|
456
|
+
clearLogBuffer();
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
void PySlaveInstance::GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIUInt64* values) const
|
|
461
|
+
{
|
|
462
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
463
|
+
PyObject* vrs = PyList_New(nvr);
|
|
464
|
+
for (int i = 0; i < nvr; i++) {
|
|
465
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
466
|
+
}
|
|
467
|
+
auto refs = PyObject_CallMethod(pInstance_, "get_uint64", "O", vrs);
|
|
468
|
+
Py_DECREF(vrs);
|
|
469
|
+
if (refs == nullptr) {
|
|
470
|
+
handle_py_exception("[getUInt64] PyObject_CallMethod", gilState);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
for (int i = 0; i < nvr; i++) {
|
|
474
|
+
PyObject* item = PyList_GetItem(refs, i);
|
|
475
|
+
PyObject* value = PyObject_GetAttrString(item, "value");
|
|
476
|
+
if (value && PyLong_Check(value))
|
|
477
|
+
{
|
|
478
|
+
values[i] = static_cast<cppfmu::FMIUInt64>(PyLong_AsUnsignedLongLong(value));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
Py_DECREF(refs);
|
|
483
|
+
clearLogBuffer();
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
void PySlaveInstance::GetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIBoolean* values) const
|
|
488
|
+
{
|
|
489
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
490
|
+
PyObject* vrs = PyList_New(nvr);
|
|
491
|
+
for (int i = 0; i < nvr; i++) {
|
|
492
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
493
|
+
}
|
|
494
|
+
auto refs = PyObject_CallMethod(pInstance_, "get_boolean", "O", vrs);
|
|
495
|
+
Py_DECREF(vrs);
|
|
496
|
+
if (refs == nullptr) {
|
|
497
|
+
handle_py_exception("[getBoolean] PyObject_CallMethod", gilState);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
for (int i = 0; i < nvr; i++) {
|
|
501
|
+
PyObject* value = PyList_GetItem(refs, i);
|
|
502
|
+
values[i] = PyObject_IsTrue(value);
|
|
503
|
+
}
|
|
504
|
+
Py_DECREF(refs);
|
|
505
|
+
clearLogBuffer();
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
void PySlaveInstance::GetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString* values) const
|
|
510
|
+
{
|
|
511
|
+
py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
|
|
512
|
+
clearStrBuffer();
|
|
513
|
+
PyObject* vrs = PyList_New(nvr);
|
|
514
|
+
for (int i = 0; i < nvr; i++) {
|
|
515
|
+
PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
|
|
516
|
+
}
|
|
517
|
+
auto refs = PyObject_CallMethod(pInstance_, "get_string", "O", vrs);
|
|
518
|
+
Py_DECREF(vrs);
|
|
519
|
+
if (refs == nullptr) {
|
|
520
|
+
handle_py_exception("[getString] PyObject_CallMethod", gilState);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
for (int i = 0; i < nvr; i++) {
|
|
524
|
+
PyObject* value = PyUnicode_AsEncodedString(PyList_GetItem(refs, i), "utf-8", nullptr);
|
|
525
|
+
values[i] = PyBytes_AsString(value);
|
|
526
|
+
strBuffer.emplace_back(value);
|
|
527
|
+
}
|
|
528
|
+
Py_DECREF(refs);
|
|
529
|
+
clearLogBuffer();
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
void PySlaveInstance::GetFMUstate(fmi3FMUState& state)
|
|
534
|
+
{
|
|
535
|
+
py_safe_run([this, &state](PyGILState_STATE gilState) {
|
|
536
|
+
auto f = PyObject_CallMethod(pInstance_, "_get_fmu_state", nullptr);
|
|
537
|
+
if (f == nullptr) {
|
|
538
|
+
handle_py_exception("[_get_fmu_state] PyObject_CallMethod", gilState);
|
|
539
|
+
}
|
|
540
|
+
state = reinterpret_cast<fmi3FMUState*>(f);
|
|
541
|
+
clearLogBuffer();
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
void PySlaveInstance::SetFMUstate(const fmi3FMUState& state)
|
|
546
|
+
{
|
|
547
|
+
py_safe_run([this, &state](PyGILState_STATE gilState) {
|
|
548
|
+
auto pyState = reinterpret_cast<PyObject*>(state);
|
|
549
|
+
auto f = PyObject_CallMethod(pInstance_, "_set_fmu_state", "(O)", pyState);
|
|
550
|
+
if (f == nullptr) {
|
|
551
|
+
handle_py_exception("[_set_fmu_state] PyObject_CallMethod", gilState);
|
|
552
|
+
}
|
|
553
|
+
clearLogBuffer();
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
void PySlaveInstance::FreeFMUstate(fmi3FMUState& state)
|
|
558
|
+
{
|
|
559
|
+
py_safe_run([this, &state](PyGILState_STATE gilState) {
|
|
560
|
+
auto f = reinterpret_cast<PyObject*>(state);
|
|
561
|
+
Py_XDECREF(f);
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
size_t PySlaveInstance::SerializedFMUstateSize(const fmi3FMUState& state)
|
|
566
|
+
{
|
|
567
|
+
size_t size;
|
|
568
|
+
py_safe_run([this, &state, &size](PyGILState_STATE gilState) {
|
|
569
|
+
auto pyState = reinterpret_cast<PyObject*>(state);
|
|
570
|
+
PyObject* pyStateBytes = PyObject_CallMethod(pClass_, "_fmu_state_to_bytes", "(O)", pyState);
|
|
571
|
+
if (pyStateBytes == nullptr) {
|
|
572
|
+
handle_py_exception("[SerializedFMUstateSize] PyObject_CallMethod", gilState);
|
|
573
|
+
}
|
|
574
|
+
size = PyBytes_Size(pyStateBytes);
|
|
575
|
+
Py_DECREF(pyStateBytes);
|
|
576
|
+
clearLogBuffer();
|
|
577
|
+
});
|
|
578
|
+
return size;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
void PySlaveInstance::SerializeFMUstate(const fmi3FMUState& state, fmi3Byte* bytes, size_t size)
|
|
582
|
+
{
|
|
583
|
+
py_safe_run([this, &state, &bytes, size](PyGILState_STATE gilState) {
|
|
584
|
+
auto pyState = reinterpret_cast<PyObject*>(state);
|
|
585
|
+
PyObject* pyStateBytes = PyObject_CallMethod(pClass_, "_fmu_state_to_bytes", "(O)", pyState);
|
|
586
|
+
if (pyStateBytes == nullptr) {
|
|
587
|
+
handle_py_exception("[SerializeFMUstate] PyObject_CallMethod", gilState);
|
|
588
|
+
}
|
|
589
|
+
char* c = PyBytes_AsString(pyStateBytes);
|
|
590
|
+
if (c == nullptr) {
|
|
591
|
+
handle_py_exception("[SerializeFMUstate] PyBytes_AsString", gilState);
|
|
592
|
+
}
|
|
593
|
+
for (int i = 0; i < size; i++) {
|
|
594
|
+
bytes[i] = c[i];
|
|
595
|
+
}
|
|
596
|
+
Py_DECREF(pyStateBytes);
|
|
597
|
+
clearLogBuffer();
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
void PySlaveInstance::DeSerializeFMUstate(const fmi3Byte bytes[], size_t size, fmi3FMUState& state)
|
|
602
|
+
{
|
|
603
|
+
py_safe_run([this, &bytes, size, &state](PyGILState_STATE gilState) {
|
|
604
|
+
char const * castedBytes = reinterpret_cast<char const*>(bytes);
|
|
605
|
+
PyObject* pyStateBytes = PyBytes_FromStringAndSize(castedBytes, size);
|
|
606
|
+
if (pyStateBytes == nullptr) {
|
|
607
|
+
handle_py_exception("[DeSerializeFMUstate] PyBytes_FromStringAndSize", gilState);
|
|
608
|
+
}
|
|
609
|
+
PyObject* pyState = PyObject_CallMethod(pClass_, "_fmu_state_from_bytes", "(O)", pyStateBytes);
|
|
610
|
+
if (pyState == nullptr) {
|
|
611
|
+
handle_py_exception("[DeSerializeFMUstate] PyObject_CallMethod", gilState);
|
|
612
|
+
}
|
|
613
|
+
state = reinterpret_cast<fmi3FMUState*>(pyState);
|
|
614
|
+
Py_DECREF(pyStateBytes);
|
|
615
|
+
clearLogBuffer();
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
void PySlaveInstance::handle_py_exception(const std::string& what, PyGILState_STATE gilState) const
|
|
620
|
+
{
|
|
621
|
+
auto err = PyErr_Occurred();
|
|
622
|
+
if (err != nullptr) {
|
|
623
|
+
cleanPyObject();
|
|
624
|
+
|
|
625
|
+
PyObject *pExcType, *pExcValue, *pExcTraceback;
|
|
626
|
+
PyErr_Fetch(&pExcType, &pExcValue, &pExcTraceback);
|
|
627
|
+
|
|
628
|
+
std::ostringstream oss;
|
|
629
|
+
oss << "Fatal py exception encountered: ";
|
|
630
|
+
oss << what << "\n";
|
|
631
|
+
if (pExcValue != nullptr) {
|
|
632
|
+
PyObject* pRepr = PyObject_Repr(pExcValue);
|
|
633
|
+
PyObject* pyStr = PyUnicode_AsEncodedString(pRepr, "utf-8", nullptr);
|
|
634
|
+
oss << PyBytes_AsString(pyStr);
|
|
635
|
+
Py_DECREF(pyStr);
|
|
636
|
+
Py_DECREF(pRepr);
|
|
637
|
+
} else {
|
|
638
|
+
oss << "unknown error";
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
PyErr_Clear();
|
|
642
|
+
|
|
643
|
+
Py_XDECREF(pExcType);
|
|
644
|
+
Py_XDECREF(pExcValue);
|
|
645
|
+
Py_XDECREF(pExcTraceback);
|
|
646
|
+
|
|
647
|
+
PyGILState_Release(gilState);
|
|
648
|
+
|
|
649
|
+
auto msg = oss.str();
|
|
650
|
+
throw cppfmu::FatalError(msg.c_str());
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
PySlaveInstance::~PySlaveInstance()
|
|
655
|
+
{
|
|
656
|
+
py_safe_run([this](PyGILState_STATE gilState) {
|
|
657
|
+
cleanPyObject();
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
} // namespace pythonfmu
|
|
662
|
+
|
|
663
|
+
namespace {
|
|
664
|
+
std::mutex pyStateMutex{};
|
|
665
|
+
std::shared_ptr<pythonfmu::PyState> pyState{};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
std::unique_ptr<cppfmu::SlaveInstance> CppfmuInstantiateSlave(
|
|
669
|
+
cppfmu::FMIString instanceName,
|
|
670
|
+
cppfmu::FMIString,
|
|
671
|
+
cppfmu::FMIString fmuResourceLocation,
|
|
672
|
+
cppfmu::FMIString,
|
|
673
|
+
cppfmu::FMIFloat64,
|
|
674
|
+
cppfmu::FMIBoolean visible,
|
|
675
|
+
cppfmu::FMIBoolean,
|
|
676
|
+
const cppfmu::Logger& logger)
|
|
677
|
+
{
|
|
678
|
+
|
|
679
|
+
// Convert URI %20 to space
|
|
680
|
+
auto resources = std::regex_replace(std::string(fmuResourceLocation), std::regex("%20"), " ");
|
|
681
|
+
auto find = resources.find("file://");
|
|
682
|
+
|
|
683
|
+
if (find != std::string::npos) {
|
|
684
|
+
#ifdef _MSC_VER
|
|
685
|
+
resources.replace(find, 8, "");
|
|
686
|
+
#else
|
|
687
|
+
resources.replace(find, 7, "");
|
|
688
|
+
#endif
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
{
|
|
692
|
+
auto const ensurePyStateAlive = [&]() {
|
|
693
|
+
auto const lock = std::lock_guard{pyStateMutex};
|
|
694
|
+
if (nullptr == pyState) pyState = std::make_shared<pythonfmu::PyState>();
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
ensurePyStateAlive();
|
|
698
|
+
return std::make_unique<pythonfmu::PySlaveInstance>(
|
|
699
|
+
instanceName, resources, logger, visible, pyState);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
extern "C" {
|
|
704
|
+
|
|
705
|
+
// The PyState instance owns it's own thread for constructing and destroying the Py* from the same thread.
|
|
706
|
+
// Creation of an std::thread increments ref counter of a shared library. So, when the client unloads the library
|
|
707
|
+
// the library won't be freed, as std::thread is alive, and the std::thread itself waits for de-initialization request.
|
|
708
|
+
// Thus, use DllMain on Windows and __attribute__((destructor)) on Linux for signaling to the PyState about de-initialization.
|
|
709
|
+
void finalizePythonInterpreter()
|
|
710
|
+
{
|
|
711
|
+
pyState = nullptr;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
namespace
|
|
716
|
+
{
|
|
717
|
+
#ifdef _WIN32
|
|
718
|
+
#include <windows.h>
|
|
719
|
+
|
|
720
|
+
BOOL APIENTRY DllMain(HMODULE hModule,
|
|
721
|
+
DWORD ul_reason_for_call,
|
|
722
|
+
LPVOID lpReserved)
|
|
723
|
+
{
|
|
724
|
+
switch (ul_reason_for_call) {
|
|
725
|
+
case DLL_PROCESS_ATTACH:
|
|
726
|
+
break;
|
|
727
|
+
case DLL_THREAD_ATTACH:
|
|
728
|
+
case DLL_THREAD_DETACH:
|
|
729
|
+
break;
|
|
730
|
+
case DLL_PROCESS_DETACH:
|
|
731
|
+
finalizePythonInterpreter();
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
return TRUE;
|
|
735
|
+
}
|
|
736
|
+
#elif defined(__linux__) || defined(__APPLE__)
|
|
737
|
+
__attribute__((destructor)) void onLibraryUnload()
|
|
738
|
+
{
|
|
739
|
+
finalizePythonInterpreter();
|
|
740
|
+
}
|
|
741
|
+
#else
|
|
742
|
+
#error port the code
|
|
743
|
+
#endif
|
|
744
|
+
}
|