From 37716e3a2e5190602364a1c45379bb8380750a25 Mon Sep 17 00:00:00 2001 From: Henry <henry.korb@geo.uu.se> Date: Mon, 3 Oct 2022 15:09:28 +0200 Subject: [PATCH] update python installation process --- .gitignore | 1 + pyproject.toml | 10 +- pythonbindings/CMakeLists.txt | 19 +- .../src/VirtualFluidsModulesCPU.cpp | 2 +- .../src/VirtualFluidsModulesGPU.cpp | 2 +- .../src/gpu/submodules/actuator_line.cpp | 53 +++--- setup.cfg | 21 +++ setup.py | 169 +++++------------- utilities/setup_builder.py | 35 ++++ 9 files changed, 149 insertions(+), 163 deletions(-) create mode 100644 setup.cfg create mode 100644 utilities/setup_builder.py diff --git a/.gitignore b/.gitignore index f87c8efbb..1e33ea527 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ dist/ *.egg-info/ __pycache__/ .venv/ +pyfluids* # IDE .vscode/ diff --git a/pyproject.toml b/pyproject.toml index 8fcb79261..4353b0196 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,10 @@ [build-system] -requires = ["setuptools", "wheel", "scikit-build"] \ No newline at end of file +requires = [ + "wheel", + "cmake>=3.1.0", + "setuptools", + "setuptools_scm[toml]", + "cmake_build_extension" +] +build-backend = "setup_builder" +backend-path = ["utilities"] \ No newline at end of file diff --git a/pythonbindings/CMakeLists.txt b/pythonbindings/CMakeLists.txt index 5a84adef0..f56b2e89e 100644 --- a/pythonbindings/CMakeLists.txt +++ b/pythonbindings/CMakeLists.txt @@ -1,24 +1,27 @@ project(VirtualFluidsPython LANGUAGES CUDA CXX) IF(BUILD_VF_GPU) - pybind11_add_module(pyfluids src/VirtualFluidsModulesGPU.cpp) + pybind11_add_module(python_bindings MODULE src/VirtualFluidsModulesGPU.cpp) + set_target_properties(python_bindings PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/pythonbindings/pyfluids + OUTPUT_NAME "bindings") set_source_files_properties(src/VirtualFluidsModulesGPU.cpp PROPERTIES LANGUAGE CUDA) - target_link_libraries(pyfluids PRIVATE GridGenerator VirtualFluids_GPU basics lbmCuda logger) - target_include_directories(pyfluids PRIVATE ${VF_THIRD_DIR}/cuda_samples/) + target_link_libraries(python_bindings PRIVATE GridGenerator VirtualFluids_GPU basics lbmCuda logger) + target_include_directories(python_bindings PRIVATE ${VF_THIRD_DIR}/cuda_samples/) ENDIF() IF(BUILD_VF_CPU) - pybind11_add_module(pyfluids src/VirtualFluidsModulesCPU.cpp) + pybind11_add_module(python_bindings src/VirtualFluidsModulesCPU.cpp) pybind11_add_module(pymuparser src/muParser.cpp) # TODO: Move this to MuParser CMakeLists.txt set_target_properties(muparser PROPERTIES POSITION_INDEPENDENT_CODE ON) - target_compile_definitions(pyfluids PRIVATE VF_METIS VF_MPI) + target_compile_definitions(python_bindings PRIVATE VF_METIS VF_MPI) target_compile_definitions(pymuparser PRIVATE VF_METIS VF_MPI) - target_link_libraries(pyfluids PRIVATE simulationconfig VirtualFluidsCore muparser basics) + target_link_libraries(python_bindings PRIVATE simulationconfig VirtualFluidsCore muparser basics) target_link_libraries(pymuparser PRIVATE muparser) ENDIF() -target_include_directories(pyfluids PRIVATE ${CMAKE_SOURCE_DIR}/src/) -target_include_directories(pyfluids PRIVATE ${CMAKE_BINARY_DIR}) \ No newline at end of file +target_include_directories(python_bindings PRIVATE ${CMAKE_SOURCE_DIR}/src/) +target_include_directories(python_bindings PRIVATE ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/pythonbindings/src/VirtualFluidsModulesCPU.cpp b/pythonbindings/src/VirtualFluidsModulesCPU.cpp index 2fba3da49..9201a8ce9 100644 --- a/pythonbindings/src/VirtualFluidsModulesCPU.cpp +++ b/pythonbindings/src/VirtualFluidsModulesCPU.cpp @@ -5,7 +5,7 @@ namespace py_bindings { namespace py = pybind11; - PYBIND11_MODULE(pyfluids, m) + PYBIND11_MODULE(bindings, m) { cpu::makeModule(m); } diff --git a/pythonbindings/src/VirtualFluidsModulesGPU.cpp b/pythonbindings/src/VirtualFluidsModulesGPU.cpp index b96971caf..e0320115e 100644 --- a/pythonbindings/src/VirtualFluidsModulesGPU.cpp +++ b/pythonbindings/src/VirtualFluidsModulesGPU.cpp @@ -8,7 +8,7 @@ namespace py_bindings { namespace py = pybind11; - PYBIND11_MODULE(pyfluids, m) + PYBIND11_MODULE(bindings, m) { basics::makeModule(m); gpu::makeModule(m); diff --git a/pythonbindings/src/gpu/submodules/actuator_line.cpp b/pythonbindings/src/gpu/submodules/actuator_line.cpp index 3b207df2b..c489654fd 100644 --- a/pythonbindings/src/gpu/submodules/actuator_line.cpp +++ b/pythonbindings/src/gpu/submodules/actuator_line.cpp @@ -3,6 +3,8 @@ #include <pybind11/numpy.h> #include <gpu/VirtualFluids_GPU/PreCollisionInteractor/PreCollisionInteractor.h> #include <gpu/VirtualFluids_GPU/PreCollisionInteractor/ActuatorLine.h> +#include <cstdint> + class PyActuatorLine : public ActuatorLine { public: @@ -12,12 +14,14 @@ public: PYBIND11_OVERRIDE_NAME(void, ActuatorLine, "calc_blade_forces", calcBladeForces,); } }; + namespace actuator_line { namespace py = pybind11; void makeModule(py::module_ &parentModule) { + using arr = py::array_t<float, py::array::c_style>; py::class_<ActuatorLine, PreCollisionInteractor, PyActuatorLine, std::shared_ptr<ActuatorLine>>(parentModule, "ActuatorLine", py::dynamic_attr()) @@ -29,7 +33,8 @@ namespace actuator_line const real, int, const real, - const real>(), + const real, + const bool>(), "n_blades", "density", "n_blade_nodes", @@ -38,7 +43,8 @@ namespace actuator_line "diameter", "level", "delta_t", - "delta_x") + "delta_x", + "use_host_arrays") .def_property("omega", &ActuatorLine::getOmega, &ActuatorLine::setOmega) .def_property("azimuth", &ActuatorLine::getAzimuth, &ActuatorLine::setAzimuth) .def_property("yaw", &ActuatorLine::getYaw, &ActuatorLine::setYaw) @@ -63,16 +69,15 @@ namespace actuator_line .def("get_blade_forces_x", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeForcesX()); } ) .def("get_blade_forces_y", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeForcesY()); } ) .def("get_blade_forces_z", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeForcesZ()); } ) - .def("get_radii_device", [](ActuatorLine& al){ return arr(al.getNBladeNodes(), al.getBladeRadii()); } ) - .def("get_blade_coords_x_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeCoordsXD()); } ) - .def("get_blade_coords_y_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeCoordsYD()); } ) - .def("get_blade_coords_z_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeCoordsZD()); } ) - .def("get_blade_velocities_x_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeVelocitiesXD()); } ) - .def("get_blade_velocities_y_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeVelocitiesYD()); } ) - .def("get_blade_velocities_z_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeVelocitiesZD()); } ) - .def("get_blade_forces_x_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeForcesXD()); } ) - .def("get_blade_forces_y_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeForcesYD()); } ) - .def("get_blade_forces_z_device", [](ActuatorLine& al){ return arr({al.getNBlades(), al.getNBladeNodes()}, al.getBladeForcesZD()); } ) + .def("get_blade_coords_x_device", [](ActuatorLine& al) -> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeCoordsXD()); }, py::return_value_policy::reference) + .def("get_blade_coords_y_device", [](ActuatorLine& al) -> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeCoordsYD()); }, py::return_value_policy::reference) + .def("get_blade_coords_z_device", [](ActuatorLine& al) -> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeCoordsZD()); }, py::return_value_policy::reference) + .def("get_blade_velocities_x_device", [](ActuatorLine& al) -> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeVelocitiesXD()); }, py::return_value_policy::reference) + .def("get_blade_velocities_y_device", [](ActuatorLine& al) -> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeVelocitiesYD()); }, py::return_value_policy::reference) + .def("get_blade_velocities_z_device", [](ActuatorLine& al) -> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeVelocitiesZD()); }, py::return_value_policy::reference) + .def("get_blade_forces_x_device", [](ActuatorLine& al)-> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeForcesXD()); }, py::return_value_policy::reference ) + .def("get_blade_forces_y_device", [](ActuatorLine& al)-> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeForcesYD()); }, py::return_value_policy::reference ) + .def("get_blade_forces_z_device", [](ActuatorLine& al)-> intptr_t { return reinterpret_cast<intptr_t>(al.getBladeForcesZD()); }, py::return_value_policy::reference ) .def("set_preinit_blade_radii", [](ActuatorLine& al, arr radii){ al.setPreInitBladeRadii(static_cast<float *>(radii.request().ptr)); } ) .def("set_blade_coords", [](ActuatorLine& al, arr coordsX, arr coordsY, arr coordsZ) { @@ -86,18 +91,18 @@ namespace actuator_line { al.setBladeForces(static_cast<float *>(forcesX.request().ptr), static_cast<float *>(forcesY.request().ptr), static_cast<float *>(forcesZ.request().ptr)); }) - .def("set_blade_coords_device", [](ActuatorLine& al, arr coordsX, arr coordsY, arr coordsZ) - { - al.setBladeCoordsD(static_cast<float *>(coordsX.request().ptr), static_cast<float *>(coordsY.request().ptr), static_cast<float *>(coordsZ.request().ptr)); - }) - .def("set_blade_velocities_device", [](ActuatorLine& al, arr velocitiesX, arr velocitiesY, arr velocitiesZ) - { - al.setBladeVelocitiesD(static_cast<float *>(velocitiesX.request().ptr), static_cast<float *>(velocitiesY.request().ptr), static_cast<float *>(velocitiesZ.request().ptr)); - }) - .def("set_blade_forces_device", [](ActuatorLine& al, arr forcesX, arr forcesY, arr forcesZ) - { - al.setBladeForcesD(static_cast<float *>(forcesX.request().ptr), static_cast<float *>(forcesY.request().ptr), static_cast<float *>(forcesZ.request().ptr)); - }) + // .def("set_blade_coords_device", [](ActuatorLine& al, arr coordsX, arr coordsY, arr coordsZ) + // { + // al.setBladeCoordsD(static_cast<float *>(coordsX.request().ptr), static_cast<float *>(coordsY.request().ptr), static_cast<float *>(coordsZ.request().ptr)); + // }) + // .def("set_blade_velocities_device", [](ActuatorLine& al, arr velocitiesX, arr velocitiesY, arr velocitiesZ) + // { + // al.setBladeVelocitiesD(static_cast<float *>(velocitiesX.request().ptr), static_cast<float *>(velocitiesY.request().ptr), static_cast<float *>(velocitiesZ.request().ptr)); + // }) + // .def("set_blade_forces_device", [](ActuatorLine& al, arr forcesX, arr forcesY, arr forcesZ) + // { + // al.setBladeForcesD(static_cast<float *>(forcesX.request().ptr), static_cast<float *>(forcesY.request().ptr), static_cast<float *>(forcesZ.request().ptr)); + // }) .def("calc_blade_forces", &ActuatorLine::calcBladeForces); } } \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..cf060397a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,21 @@ +[metadata] +name = pyfluids +description = Python binding for VirtualFluids +long_description = file: README.md +long_description_content_type = text/markdown +platforms = any +url = https://git.rz.tu-bs.de/irmb/virtualfluids +version = 0.0.1 + +[options] +zip_safe = False +packages = find: +package_dir = + =pythonbindings +python_requires = >=3.6 +install_requires = + cmake-build-extension + +[options.packages.find] +where = pythonbindings + diff --git a/setup.py b/setup.py index b26e1c13d..52dc347f1 100644 --- a/setup.py +++ b/setup.py @@ -1,137 +1,50 @@ -import os -import re +import inspect import sys -import platform -import subprocess +from pathlib import Path -from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext -from setuptools.command.install import install -from setuptools.command.develop import develop -from distutils.version import LooseVersion +import cmake_build_extension +import setuptools """ Install python wrapper of virtual fluids -Install GPU backend with option --GPU -(pass to pip via --install-option="--GPU") +install via python setup.py install build_ext +set CMAKE Flags via -DBUILD_VF_GPU:BOOL=1 """ -vf_cmake_args = [ - "-DBUILD_VF_PYTHON_BINDINGS=ON", - "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache", - "-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache", - "-DCMAKE_C_COMPILER_LAUNCHER=ccache", - "-DBUILD_SHARED_LIBS=OFF", - "-DBUILD_WARNINGS_AS_ERRORS=OFF" -] - -vf_cpu_cmake_args = [ - "-DBUILD_VF_DOUBLE_ACCURACY=ON", - "-DBUILD_VF_CPU:BOOL=ON", - "-DBUILD_VF_UNIT_TESTS:BOOL=ON", - "-DUSE_METIS=ON", - "-DUSE_MPI=ON" -] - -vf_gpu_cmake_args = [ - "-DBUILD_VF_DOUBLE_ACCURACY=OFF", - "-DBUILD_VF_GPU:BOOL=ON", - "-DBUILD_VF_UNIT_TESTS:BOOL=OFF", -] - -GPU = False - -class CommandMixin: - user_options = [ - ('GPU', None, 'compile pyfluids with GPU backend'), - ] - - def initialize_options(self): - super().initialize_options() - self.GPU = False - - def finalize_options(self): - super().finalize_options() - - def run(self): - global GPU - GPU = GPU or self.GPU - super().run() - - -class InstallCommand(CommandMixin, install): - user_options = getattr(install, 'user_options', []) + CommandMixin.user_options - - -class DevelopCommand(CommandMixin, develop): - user_options = getattr(develop, 'user_options', []) + CommandMixin.user_options - - -class CMakeExtension(Extension): - def __init__(self, name, sourcedir=''): - Extension.__init__(self, name, sources=[]) - self.sourcedir = os.path.abspath(sourcedir) - - -class CMakeBuild(CommandMixin, build_ext): - user_options = getattr(build_ext, 'user_options', []) + CommandMixin.user_options - - def run(self): - super().run() - try: - out = subprocess.check_output(['cmake', '--version']) - except OSError: - raise RuntimeError("CMake must be installed to build the following extensions: " + - ", ".join(e.name for e in self.extensions)) - - if platform.system() == "Windows": - cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) - if cmake_version < '3.1.0': - raise RuntimeError("CMake >= 3.1.0 is required on Windows") - - for ext in self.extensions: - self.build_extension(ext) - - def build_extension(self, ext): - extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) - # required for auto-detection of auxiliary "native" libs - if not extdir.endswith(os.path.sep): - extdir += os.path.sep - - cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, - '-DPYTHON_EXECUTABLE=' + sys.executable] - - cfg = 'Debug' if self.debug else 'Release' - build_args = ['--config', cfg] - - if platform.system() == "Windows": - cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] - if sys.maxsize > 2**32: - cmake_args += ['-A', 'x64'] - build_args += ['--', '/m'] - else: - cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] - build_args += ['--', '-j2'] - - cmake_args.extend(vf_cmake_args) - cmake_args.extend(vf_gpu_cmake_args if GPU else vf_cpu_cmake_args) - - env = os.environ.copy() - env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), - self.distribution.get_version()) - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) - cmake_cache_file = self.build_temp+"/CMakeCache.txt" - if os.path.exists(cmake_cache_file): - os.remove(cmake_cache_file) - subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) - subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) - +init_py = inspect.cleandoc( + """ + import cmake_build_extension + with cmake_build_extension.build_extension_env(): + from .bindings import * + """ +) -setup( - name='pyfluids', - version='0.0.1', - ext_modules=[CMakeExtension('pyfluids')], - cmdclass={"install": InstallCommand, "develop": DevelopCommand, "build_ext": CMakeBuild}, - zip_safe=False, +extra_args = [] +if("cmake_args" in locals()): + extra_args.extend([f"{k}={v}" for k,v in locals()["cmake_args"].items()]) + +setuptools.setup( + ext_modules=[ + cmake_build_extension.CMakeExtension( + name="pyfluids", + install_prefix="pyfluids", + write_top_level_init=init_py, + source_dir=str(Path(__file__).parent.absolute()), + cmake_configure_options = [ + f"-DPython3_ROOT_DIR={Path(sys.prefix)}", + "-DCALL_FROM_SETUP_PY:BOOL=ON", + "-DBUILD_VF_PYTHON_BINDINGS=ON", + "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache", + "-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache", + "-DCMAKE_C_COMPILER_LAUNCHER=ccache", + "-DBUILD_SHARED_LIBS=OFF", + "-DBUILD_VF_DOUBLE_ACCURACY=OFF", + "-DBUILD_VF_UNIT_TESTS:BOOL=OFF", + "-DBUILD_WARNINGS_AS_ERRORS=OFF", + ] + extra_args, + ) + ], + cmdclass=dict( + build_ext=cmake_build_extension.BuildExtension, + ), ) diff --git a/utilities/setup_builder.py b/utilities/setup_builder.py new file mode 100644 index 000000000..821d72ede --- /dev/null +++ b/utilities/setup_builder.py @@ -0,0 +1,35 @@ +from setuptools import build_meta + +class builder(build_meta._BuildMetaBackend): + + def run_setup(self, setup_script='setup.py'): + # Note that we can reuse our build directory between calls + # Correctness comes first, then optimization later + __file__ = setup_script + __name__ = '__main__' + + with build_meta._open_setup_script(__file__) as f: + code = f.read().replace(r'\r\n', r'\n') + args = locals() + args["cmake_args"] = self.extra_args + exec(code, args) + + + def add_settings(self, config_settings): + self.extra_args = dict() + print(config_settings) + if config_settings: + self.extra_args = {k:v for k,v in config_settings.items() if k[:2] == "-D"} + + def build_wheel(self, wheel_directory, config_settings=None, + metadata_directory=None): + self.add_settings(config_settings) + return super().build_wheel(wheel_directory, config_settings, metadata_directory) + + def build_sdist(self, sdist_directory, config_settings=None): + self.add_settings(config_settings) + return super().build_wheel(sdist_directory, config_settings) + +build = builder() +build_wheel = build.build_wheel +build_sdist = build.build_sdist \ No newline at end of file -- GitLab