diff --git a/cmake/AkantuInstall.cmake b/cmake/AkantuInstall.cmake index 958f6405b..4a7da3a2f 100644 --- a/cmake/AkantuInstall.cmake +++ b/cmake/AkantuInstall.cmake @@ -1,160 +1,163 @@ #=============================================================================== # @file AkantuInstall.cmake # # @author Nicolas Richart # # @date creation: Wed Oct 17 2012 # @date last modification: Fri Jan 22 2016 # # @brief Create the files that allows users to link with Akantu in an other # cmake project # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== #=============================================================================== # Config gen for external packages #=============================================================================== configure_file(cmake/AkantuBuildTreeSettings.cmake.in "${PROJECT_BINARY_DIR}/AkantuBuildTreeSettings.cmake" @ONLY) file(WRITE "${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake" " #=============================================================================== # @file AkantuConfigInclude.cmake # @author Nicolas Richart # @date Fri Jun 11 09:46:59 2010 # # @section LICENSE # # Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # # @section DESCRIPTION # #=============================================================================== ") package_get_all_packages(_package_list) foreach(_pkg_name ${_package_list}) # package_pkg_name(${_option} _pkg_name) _package_is_activated(${_pkg_name} _acctivated) _package_get_real_name(${_pkg_name} _real_name) string(TOUPPER ${_real_name} _real_pkg_name) file(APPEND "${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake" " set(AKANTU_HAS_${_real_pkg_name} ${_acctivated})") _package_get_libraries(${_pkg_name} _libs) if(_libs) file(APPEND "${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake" " set(AKANTU_${_real_pkg_name}_LIBRARIES ${_libs})") endif() _package_get_include_dir(${_pkg_name} _incs) if(_incs) file(APPEND "${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake" " set(AKANTU_${_real_pkg_name}_INCLUDE_DIR ${_incs}) ") endif() _package_get_compile_flags(${_pkg_name} CXX _compile_flags) if(_compile_flags) file(APPEND "${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake" " set(AKANTU_${_real_pkg_name}_COMPILE_CXX_FLAGS ${_compile_flags}) ") endif() endforeach() file(APPEND "${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake" " set(AKANTU_EXTRA_CXX_FLAGS \"${AKANTU_EXTRA_CXX_FLAGS}\") ") # Create the AkantuConfig.cmake and AkantuConfigVersion files get_filename_component(CONF_REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}" ABSOLUTE) configure_file(cmake/AkantuConfig.cmake.in "${PROJECT_BINARY_DIR}/AkantuConfig.cmake" @ONLY) configure_file(cmake/AkantuConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/AkantuConfigVersion.cmake" @ONLY) configure_file(cmake/AkantuUse.cmake "${PROJECT_BINARY_DIR}/AkantuUse.cmake" COPYONLY) +package_is_activated(pybind11 _is_pybind11_activated) +package_is_activated(swig _is_swig_activated) + configure_file(cmake/akantu_environement.sh.in ${PROJECT_BINARY_DIR}/akantu_environement.sh @ONLY) configure_file(cmake/akantu_environement.csh.in ${PROJECT_BINARY_DIR}/akantu_environement.csh @ONLY) package_is_activated(python_interface _is_acticated) if(_is_acticated) find_package(PythonInterp ${AKANTU_PREFERRED_PYTHON_VERSION}) configure_file(cmake/akantu_install_environement.sh.in ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/akantu_environement.sh @ONLY) configure_file(cmake/akantu_install_environement.csh.in ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/akantu_environement.csh @ONLY) endif() install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/akantu_environement.sh ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/akantu_environement.csh DESTINATION share/akantu${AKANTU_VERSION}) include(CMakePackageConfigHelpers) configure_package_config_file(cmake/AkantuConfig.cmake.in "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION share/cmake/${PROJECT_NAME} ) write_basic_package_version_file(${PROJECT_BINARY_DIR}/AkantuConfigVersion.cmake VERSION ${AKANTU_VERSION} COMPATIBILITY SameMajorVersion) # Install the export set for use with the install-tree install(FILES ${PROJECT_SOURCE_DIR}/cmake/Modules/FindScaLAPACK.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindMETIS.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindParMETIS.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindPETSc.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindMumps.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindScotch.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindGMSH.cmake ${PROJECT_BINARY_DIR}/AkantuConfig.cmake ${PROJECT_BINARY_DIR}/AkantuConfigInclude.cmake ${PROJECT_BINARY_DIR}/AkantuConfigVersion.cmake ${PROJECT_SOURCE_DIR}/cmake/AkantuUse.cmake ${PROJECT_SOURCE_DIR}/cmake/AkantuSimulationMacros.cmake ${PROJECT_SOURCE_DIR}/cmake/Modules/FindGMSH.cmake DESTINATION share/cmake/${PROJECT_NAME} COMPONENT dev) diff --git a/cmake/akantu_environement.sh.in b/cmake/akantu_environement.sh.in index 762163e14..7950b97c7 100644 --- a/cmake/akantu_environement.sh.in +++ b/cmake/akantu_environement.sh.in @@ -1,2 +1,19 @@ +<<<<<<< Updated upstream export PYTHONPATH=$PYTHONPATH:"@PROJECT_BINARY_DIR@/python":"@PROJECT_SOURCE_DIR@/test":"@PROJECT_SOURCE_DIR@/test/test_fe_engine" export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:"@PROJECT_BINARY_DIR@/src" +======= +AKANTU_HAS_PYBIND11=@_is_pybind11_activated@ +AKANTU_HAS_SWIG=@_is_swig_activated@ + +if [ "${AKANTU_HAS_PYBIND11}" = "TRUE" ]; then + PYTHONPATH=$PYTHONPATH:@PROJECT_BINARY_DIR@/python/pybind11:@PROJECT_SOURCE_DIR@/python/pybind11 +fi + +if [ "${AKANTU_HAS_SWIG}" = "TRUE" ]; then + PYTHONPATH=$PYTHONPATH:@PROJECT_BINARY_DIR@/python/swig +fi + +export PYTHONPATH=$PYTHONPATH:@PROJECT_SOURCE_DIR@/test:@PROJECT_SOURCE_DIR@/test/test_fe_engine + +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:@PROJECT_BINARY_DIR@/src +>>>>>>> Stashed changes diff --git a/packages/python_interface.cmake b/packages/python_interface.cmake index bdd6535ca..0cdb0fc5e 100644 --- a/packages/python_interface.cmake +++ b/packages/python_interface.cmake @@ -1,62 +1,83 @@ #=============================================================================== # @file python_interface.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Tue Nov 29 2011 # @date last modification: Fri Jan 22 2016 # # @brief package description for the python interface # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== package_declare(python_interface DESCRIPTION "Akantu's python interface" DEPENDS PythonLibs) package_declare_sources(python_interface python/python_functor.cc python/python_functor.hh python/python_functor_inline_impl.cc model/boundary_condition_python_functor.hh model/boundary_condition_python_functor.cc model/solid_mechanics/materials/material_python/material_python.cc model/solid_mechanics/materials/material_python/material_python.hh ) +set(AKANTU_PYTHON_INTERFACE_IMPL "swig" + CACHE STRING "Specifies the implementation of the python interface") +set_property(CACHE AKANTU_PYTHON_INTERFACE_IMPL PROPERTY STRINGS + pybind11 + swig + all + ) + +if(AKANTU_PYTHON_INTERFACE_IMPL MATCHES "swig" OR AKANTU_PYTHON_INTERFACE_IMPL MATCHES "all") + package_add_dependencies(python_interface PRIVATE SWIG) +else() + package_remove_dependencies(python_interface SWIG) +endif() + +if(AKANTU_PYTHON_INTERFACE_IMPL MATCHES "swig" OR AKANTU_PYTHON_INTERFACE_IMPL MATCHES "all") + package_add_dependencies(python_interface PUBLIC pybind11) +else() + package_remove_dependencies(python_interface pybind11) +endif() + + package_set_package_system_dependency(python_interface deb-src swig3.0) package_declare_documentation(python_interface "This package enables the python interface of Akantu. It relies on swig3.0 to generate the code" "" "Under Ubuntu (14.04 LTS) the installation can be performed using the commands:" "\\begin{command}" " > sudo apt-get install swig3.0" "\\end{command}" "" ) package_declare_documentation_files(python_interface manual-python.tex ) diff --git a/packages/python_interpeter.cmake b/packages/python_interpeter.cmake new file mode 100644 index 000000000..e69de29bb diff --git a/packages/python_interpreter.cmake b/packages/python_interpreter.cmake new file mode 100644 index 000000000..455a389c4 --- /dev/null +++ b/packages/python_interpreter.cmake @@ -0,0 +1,3 @@ +package_declare(PythonInterp EXTERNAL DESCRIPTION "Akantu's python interpreter" + EXTRA_PACKAGE_OPTIONS ARGS ${AKANTU_PREFERRED_PYTHON_VERSION} + ) diff --git a/packages/pythonlibs.cmake b/packages/pythonlibs.cmake index ebb51401d..102306255 100644 --- a/packages/pythonlibs.cmake +++ b/packages/pythonlibs.cmake @@ -1,48 +1,48 @@ #=============================================================================== # @file pythonlibs.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Fri Sep 03 2010 # @date last modification: Fri Jan 22 2016 # # @brief package description for the python library # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== package_declare(PythonLibs EXTERNAL DESCRIPTION "Akantu's python interface" DEPENDS numpy - EXTRA_PACKAGE_OPTIONS PREFIX PYTHON FOUND PYTHONLIBS_FOUND + EXTRA_PACKAGE_OPTIONS ARGS ${AKANTU_PREFERRED_PYTHON_VERSION} PREFIX PYTHON FOUND PYTHONLIBS_FOUND ) package_set_package_system_dependency(PythonLibs deb libpython3) package_set_package_system_dependency(PythonLibs deb-src libpython3-dev) package_declare_documentation(PythonLibs "This package is a dependency of the python interface" "" "Under Ubuntu (14.04 LTS) the installation can be performed using the commands:" "\\begin{command}" - " > sudo apt-get install libpython2.7-dev" + " > sudo apt-get install libpython3-dev" "\\end{command}" "" ) diff --git a/packages/swig.cmake b/packages/swig.cmake new file mode 100644 index 000000000..07b7144a8 --- /dev/null +++ b/packages/swig.cmake @@ -0,0 +1,7 @@ +package_declare(SWIG EXTERNAL + EXTRA_PACKAGE_OPTIONS ARGS "3" + DESCRIPTION "Akantu's swig interface" + DEPENDS PythonInterp + ) + +mark_as_advanced(SWIG_EXECUTABLE) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 38addabc6..ce54c71be 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,292 +1,36 @@ #=============================================================================== # @file CMakeLists.txt # # @author Nicolas Richart # # @date creation: Fri Dec 12 2014 # @date last modification: Mon Jan 18 2016 # # @brief CMake file for the python wrapping of akantu # # @section LICENSE # # Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory # (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== -#=============================================================================== -# Configuration -#=============================================================================== -package_get_all_definitions(AKANTU_DEFS) -list(REMOVE_ITEM AKANTU_DEFS AKANTU_CORE_CXX11) -#message(${AKANTU_DEFS}) -set(AKA_DEFS "") -foreach (def ${AKANTU_DEFS}) - list(APPEND AKA_DEFS "-D${def}") -endforeach() - -set(AKANTU_SWIG_FLAGS -w309,325,401,317,509,503,383,384,476,362 ${AKA_DEFS}) -set(AKANTU_SWIG_OUTDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(AKANTU_SWIG_MODULES swig/akantu.i) - -#=============================================================================== -# Swig wrapper -#=============================================================================== -set(SWIG_REQURIED_VERISON 3.0) -find_package(SWIG ${SWIG_REQURIED_VERISON}) -find_package(PythonInterp ${AKANTU_PREFERRED_PYTHON_VERSION} REQUIRED) -mark_as_advanced(SWIG_EXECUTABLE) - -if(NOT PYTHON_VERSION_MAJOR LESS 3) - list(APPEND AKANTU_SWIG_FLAGS -py3) -endif() - -package_get_all_include_directories( - AKANTU_LIBRARY_INCLUDE_DIRS - ) - -package_get_all_external_informations( - INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR - ) - -set(_swig_include_dirs - ${CMAKE_CURRENT_SOURCE_DIR}/swig - ${AKANTU_LIBRARY_INCLUDE_DIRS} - ${PROJECT_BINARY_DIR}/src - ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR} - ) - -include(CMakeParseArguments) - -function(swig_generate_dependencies _module _depedencies _depedencies_out) - set(_dependencies_script - "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_generate_dependencies.cmake") - file(WRITE ${_dependencies_script} " -set(_include_directories ${_include_directories}) -list(APPEND _include_directories \"./\") - -set(_dep) -set(_files_to_process \${_module}) -while(_files_to_process) - list(GET _files_to_process 0 _file) - list(REMOVE_AT _files_to_process 0) - file(STRINGS \${_file} _file_content REGEX \"^%include *\\\"(.*)\\\"\") - - set(_includes) - foreach(_line \${_file_content}) - string(REGEX REPLACE \"^%include *\\\"(.*)\\\"\" \"\\\\1\" _inc \${_line}) - if(_inc) - list(APPEND _includes \${_inc}) - endif() - endforeach() - - foreach(_include \${_includes}) - unset(_found) - foreach(_inc_dir \${_include_directories}) - if(EXISTS \${_inc_dir}/\${_include}) - set(_found \${_inc_dir}/\${_include}) - break() - endif() - endforeach() - - if(_found) - list(APPEND _files_to_process \${_found}) - list(APPEND _dep \${_found}) - endif() - endforeach() -endwhile() - -get_filename_component(_module_we \"\${_module}\" NAME_WE) -set(_dependencies_file - \${CMAKE_CURRENT_BINARY_DIR}\${CMAKE_FILES_DIRECTORY}/_swig_\${_module_we}_depends.cmake) -file(WRITE \"\${_dependencies_file}\" - \"set(_swig_\${_module_we}_depends\") -foreach(_d \${_dep}) - file(APPEND \"\${_dependencies_file}\" \" - \${_d}\") -endforeach() -file(APPEND \"\${_dependencies_file}\" \" - )\") -") - - get_filename_component(_module_absolute "${_module}" ABSOLUTE) - get_filename_component(_module_we "${_module}" NAME_WE) - - set(_dependencies_file - ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) - - if(EXISTS ${_dependencies_file}) - include(${_dependencies_file}) - else() - execute_process(COMMAND ${CMAKE_COMMAND} - -D_module=${_module_absolute} - -P ${_dependencies_script} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - include(${_dependencies_file}) - endif() - - set(${_depedencies_out} ${_swig_${_module_we}_depends} PARENT_SCOPE) - - add_custom_command(OUTPUT ${_dependencies_file} - COMMAND ${CMAKE_COMMAND} - -D_module=${_module_absolute} - -P ${_dependencies_script} - COMMENT "Scanning dependencies for swig module ${_module_we}" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - MAIN_DEPENDENCY ${_module_absolute} - DEPENDS ${_swig_${_module_we}_depends} - ) - - set(${_depedencies} ${_dependencies_file} PARENT_SCOPE) -endfunction() - -function(swig_generate_wrappers project _wrappers_cpp _wrappers_py) - cmake_parse_arguments(_swig_opt - "" - "OUTPUT_DIR;DEPENDENCIES" - "EXTRA_FLAGS;INCLUDE_DIRECTORIES" - ${ARGN}) - - if(_swig_opt_OUTPUT_DIR) - set(_output_dir ${_swig_opt_OUTPUT_DIR}) - else() - set(_output_dir ${CMAKE_CURRENT_BINARY_DIR}) - endif() - - set(_swig_wrappers) - get_directory_property(_include_directories INCLUDE_DIRECTORIES) - list(APPEND _include_directories ${_swig_opt_INCLUDE_DIRECTORIES}) - if(_include_directories) - string(REPLACE ";" ";-I" _swig_include_directories "${_include_directories}") +foreach(_pkg swig pybind11) + package_is_activated(${_pkg} _pkg_act) + if(_pkg_act) + add_subdirectory(${_pkg}) endif() - - foreach(_module ${_swig_opt_UNPARSED_ARGUMENTS}) - swig_generate_dependencies(${_module} _module_dependencies _depends_out) - if(_swig_opt_DEPENDENCIES) - set(${_swig_opt_DEPENDENCIES} ${_depends_out} PARENT_SCOPE) - endif() - - get_filename_component(_module_absolute "${_module}" ABSOLUTE) - get_filename_component(_module_path "${_module_absolute}" PATH) - get_filename_component(_module_name "${_module}" NAME) - get_filename_component(_module_we "${_module}" NAME_WE) - set(_wrapper "${_output_dir}/${_module_we}_wrapper.cpp") - set(_extra_wrapper "${_output_dir}/${_module_we}.py") - set(_extra_wrapper_bin "${CMAKE_CURRENT_BINARY_DIR}/${_module_we}.py") - - if(SWIG_FOUND) - set_source_files_properties("${_wrapper}" PROPERTIES GENERATED 1) - set_source_files_properties("${_extra_wrapper}" PROPERTIES GENERATED 1) - - set(_dependencies_file - ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) - - set(_ouput "${_wrapper}" "${_extra_wrapper}") - add_custom_command( - OUTPUT ${_ouput} - COMMAND "${SWIG_EXECUTABLE}" - ARGS -python -c++ - ${_swig_opt_EXTRA_FLAGS} - -outdir ${_output_dir} - -I${_swig_include_directories} -I${_module_path} - -o "${_wrapper}" - "${_module_absolute}" - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_extra_wrapper} ${_extra_wrapper_bin} - # MAIN_DEPENDENCY "${_module_absolute}" - DEPENDS ${_module_dependencies} - COMMENT "Generating swig wrapper ${_module} -> ${_wrapper}" - ) - - list(APPEND _swig_wrappers ${_wrapper}) - list(APPEND _swig_wrappers_py "${_extra_wrapper_bin}") - else() - if(NOT EXISTS ${_wrapper} OR NOT EXISTS "${_extra_wrapper}") - message(FATAL_ERROR "The file ${_wrapper} and/or ${_extra_wrapper} does " - "not exists and they cannot be generated. Install swig ${SWIG_REQURIED_VERISON} " - " in order to generate them. Or get them from a different machine, " - "in order to be able to compile the python interface") - else() - list(APPEND _swig_wrappers "${_wrapper}") - list(APPEND _swig_wrappers_py "${_extra_wrapper_bin}") - endif() - endif() - endforeach() - - add_custom_target(${project}_generate_swig_wrappers DEPENDS ${_swig_wrappers}) - - set(${_wrappers_cpp} ${_swig_wrappers} PARENT_SCOPE) - set(${_wrappers_py} ${_swig_wrappers_py} PARENT_SCOPE) -endfunction() - - -swig_generate_wrappers(akantu AKANTU_SWIG_WRAPPERS_CPP AKANTU_WRAPPERS_PYTHON - ${AKANTU_SWIG_MODULES} - EXTRA_FLAGS ${AKANTU_SWIG_FLAGS} - DEPENDENCIES _deps - INCLUDE_DIRECTORIES ${_swig_include_dirs}) - -if(AKANTU_SWIG_WRAPPERS_CPP) - set(_ext_files "${AKANTU_SWIG_WRAPPERS_CPP}") - set(_inc_dirs "${_swig_include_dirs}") - set(_lib_dirs "${Akantu_BINARY_DIR}/src") - - string(TOUPPER "${CMAKE_BUILD_TYPE}" _config) - set(_akantu_lib_name "akantu${CMAKE_${_config}_POSTFIX}") - - get_property(_compile_flags TARGET akantu PROPERTY COMPILE_FLAGS) - set(_compile_flags "${_compile_flags} ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${_config}}") - separate_arguments(_compile_flags) - get_property(_cxx_standard TARGET akantu PROPERTY CXX_STANDARD) - - set(_flags ${_compile_flags} -std=c++${_cxx_standard} - -Wno-unused-parameter -Wno-uninitialized) - - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - list(APPEND -Wno-unused-command-line-argument) - elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - list(APPEND -Wno-maybe-uninitialized) - endif() - - set(_quiet) - if(NOT CMAKE_VERBOSE_MAKEFILE) - set(_quiet --quiet) - endif() - - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in - ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY) - - add_custom_target(_akantu ALL - COMMAND ${PYTHON_EXECUTABLE} ./setup.py ${_quiet} --no-user-cfg build_ext --inplace - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${AKANTU_SWIG_WRAPPERS_CPP} akantu - COMMENT "Building akantu's python interface" - ) - - set_directory_properties(PROPERTIES - ADDITIONAL_MAKE_CLEAN_FILES - ${CMAKE_CURRENT_BINARY_DIR}/_akantu${CMAKE_SHARED_MODULE_SUFFIX}) - - install(CODE "execute_process( - COMMAND ${PYTHON_EXECUTABLE} ./setup.py ${_quiet} install --prefix=${AKANTU_PYTHON_INSTALL_PREFIX} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" - ) - - package_declare_extra_files_to_package(python_interface - ${_deps} - ${PROJECT_SOURCE_DIR}/python/${AKANTU_SWIG_MODULES}) -endif() +endforeach() diff --git a/python/pybind11/CMakeLists.txt b/python/pybind11/CMakeLists.txt new file mode 100644 index 000000000..2588e2e23 --- /dev/null +++ b/python/pybind11/CMakeLists.txt @@ -0,0 +1,4 @@ +pybind11_add_module(py11_akantu py_akantu.cc) +target_link_libraries(py11_akantu PRIVATE akantu) + +set_property(TARGET py11_akantu PROPERTY DEBUG_POSTFIX "") diff --git a/python/pybind11/akantu/__init__.py b/python/pybind11/akantu/__init__.py new file mode 100644 index 000000000..4d938f662 --- /dev/null +++ b/python/pybind11/akantu/__init__.py @@ -0,0 +1 @@ +from py11_akantu import * # noqa: F401, F403 diff --git a/python/pybind11/akantu/__init__.pyc b/python/pybind11/akantu/__init__.pyc new file mode 100644 index 000000000..0f21f01eb Binary files /dev/null and b/python/pybind11/akantu/__init__.pyc differ diff --git a/python/pybind11/py_aka_array.cc b/python/pybind11/py_aka_array.cc new file mode 100644 index 000000000..d664116b7 --- /dev/null +++ b/python/pybind11/py_aka_array.cc @@ -0,0 +1,154 @@ +/* -------------------------------------------------------------------------- */ +#include "aka_array.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +/* -------------------------------------------------------------------------- */ + +namespace py = pybind11; +namespace _aka = akantu; + +namespace akantu { +template class ArrayProxy : public Array { +protected: + // deallocate the memory + void deallocate() override final {} + + // allocate the memory + void allocate(UInt size, UInt nb_component) override final {} + + // allocate and initialize the memory + void allocate(UInt size, UInt nb_component, const T & value) override final {} + +public: + ArrayProxy(T * data, UInt size, UInt nb_component) { + this->values = data; + this->size_ = size; + this->nb_component = nb_component; + } + + ArrayProxy(const Array & src) { + this->values = src.storage(); + this->size_ = src.size(); + this->nb_component = src.getNbComponent(); + } + + void resize(UInt size, const T & val) override final { + AKANTU_EXCEPTION("cannot resize a temporary array"); + } + + void resize(UInt new_size) override final { + AKANTU_EXCEPTION("cannot resize a temporary array"); + } + + void reserve(UInt new_size) override final { + AKANTU_EXCEPTION("cannot resize a temporary array"); + } +}; + +} // namespace akantu + +namespace pybind11 { +namespace detail { + /* ------------------------------------------------------------------------ */ + template + py::handle aka_array_cast(const _aka::Array & src, + py::handle base = handle(), bool writeable = true) { + constexpr ssize_t elem_size = sizeof(T); + array a; + a = array({src.size(), src.getNbComponent()}, + {elem_size * src.getNbComponent(), elem_size}, src.storage(), + base); + + if (not writeable) + array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; + + return a.release(); + } + + template struct type_caster<_aka::Array> { + protected: + using py_array = array_t; + + public: + static constexpr auto name = + _("numpy.ndarray[") + npy_format_descriptor::name + + _(", flags.writeable") + _(", flags.c_contiguous") + _("]"); + + /** + * Conversion part 1 (Python->C++) + */ + bool load(handle src, bool convert) { + bool need_copy = not isinstance(src); + + auto && fits = [&](auto && a) { + auto && dims = copy_or_ref.ndim(); + if (dims < 1 || dims > 2) + return false; + + return true; + }; + + if (not need_copy) { + // We don't need a converting copy, but we also need to check whether + // the strides are compatible with the Ref's stride requirements + py_array aref = reinterpret_borrow(src); + + if (not fits(aref)) { + return false; + } + + copy_or_ref = std::move(aref); + } else { + if (not convert) { + return false; + } + + auto copy = py_array::ensure(src); + if (not copy) { + return false; + } + + if (not fits(copy)) { + return false; + } + copy_or_ref = std::move(py_array::ensure(src)); + loader_life_support::add_patient(copy_or_ref); + } + + array_proxy.reset(new _aka::ArrayProxy> (copy_or_ref.mutable_data(), + copy_or_ref.shape(0), + copy_or_ref.shape(1))); + return true; + } + + operator _aka::Array *() { return array_proxy.get(); } + operator _aka::Array &() { return *array_proxy; } + template + using cast_op_type = pybind11::detail::cast_op_type<_T>; + + /** + * Conversion part 2 (C++ -> Python) + */ + static handle cast(const _aka::Array & src, return_value_policy policy, + handle parent) { + switch (policy) { + case return_value_policy::copy: + return aka_array_cast(src); + case return_value_policy::reference_internal: + return aka_array_cast(src, parent); + case return_value_policy::reference: + case return_value_policy::automatic: + case return_value_policy::automatic_reference: + return aka_array_cast(src, none()); + default: + pybind11_fail("Invalid return_value_policy for ArrayProxy type"); + } + } + + protected: + std::unique_ptr<_aka::Array> array_proxy; + py_array copy_or_ref; + }; +} // namespace detail +} // namespace pybind11 diff --git a/python/pybind11/py_aka_common.cc b/python/pybind11/py_aka_common.cc new file mode 100644 index 000000000..6b223902d --- /dev/null +++ b/python/pybind11/py_aka_common.cc @@ -0,0 +1,69 @@ +/* -------------------------------------------------------------------------- */ +#include "aka_common.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +/* -------------------------------------------------------------------------- */ + +namespace py = pybind11; +namespace _aka = akantu; + +namespace { + +py::module & register_enums(py::module & mod) { + py::enum_<_aka::SpatialDirection>(mod, "SpatialDirection") + .value("_x", _aka::_x) + .value("_y", _aka::_y) + .value("_z", _aka::_z); + + py::enum_<_aka::AnalysisMethod>(mod, "AnalysisMethod") + .value("_static", _aka::_static) + .value("_implicit_dynamic", _aka::_implicit_dynamic) + .value("_explicit_lumped_mass", _aka::_explicit_lumped_mass) + .value("_explicit_lumped_capacity", _aka::_explicit_lumped_capacity) + .value("_explicit_consistent_mass", _aka::_explicit_consistent_mass); + + py::enum_<_aka::NonLinearSolverType>(mod, "NonLinearSolverType") + .value("_nls_linear", _aka::_nls_linear) + .value("_nls_newton_raphson", _aka::_nls_newton_raphson) + .value("_nls_newton_raphson_modified", _aka::_nls_newton_raphson_modified) + .value("_nls_lumped", _aka::_nls_lumped) + .value("_nls_auto", _aka::_nls_auto); + + py::enum_<_aka::TimeStepSolverType>(mod, "TimeStepSolverType") + .value("_tsst_static", _aka::_tsst_static) + .value("_tsst_dynamic", _aka::_tsst_dynamic) + .value("_tsst_dynamic_lumped", _aka::_tsst_dynamic_lumped) + .value("_tsst_not_defined", _aka::_tsst_not_defined); + + py::enum_<_aka::IntegrationSchemeType>(mod, "IntegrationSchemeType") + .value("_ist_pseudo_time", _aka::_ist_pseudo_time) + .value("_ist_forward_euler", _aka::_ist_forward_euler) + .value("_ist_trapezoidal_rule_1", _aka::_ist_trapezoidal_rule_1) + .value("_ist_backward_euler", _aka::_ist_backward_euler) + .value("_ist_central_difference", _aka::_ist_central_difference) + .value("_ist_fox_goodwin", _aka::_ist_fox_goodwin) + .value("_ist_trapezoidal_rule_2", _aka::_ist_trapezoidal_rule_2) + .value("_ist_linear_acceleration", _aka::_ist_linear_acceleration) + .value("_ist_newmark_beta", _aka::_ist_newmark_beta) + .value("_ist_generalized_trapezoidal", + _aka::_ist_generalized_trapezoidal); + + py::enum_<_aka::SolveConvergenceCriteria>(mod, "SolveConvergenceCriteria") + .value("_scc_residual", _aka::_scc_residual) + .value("_scc_solution", _aka::_scc_solution) + .value("_scc_residual_mass_wgh", _aka::_scc_residual_mass_wgh); + + py::enum_<_aka::CohesiveMethod>(mod, "CohesiveMethod") + .value("_intrinsic", _aka::_intrinsic) + .value("_extrinsic", _aka::_extrinsic); + + py::enum_<_aka::GhostType>(mod, "GhostType") + .value("_not_ghost", _aka::_not_ghost) + .value("_ghost", _aka::_ghost) + .value("_casper", _aka::_casper); + + return mod; +} + +} // namespace diff --git a/python/pybind11/py_akantu.cc b/python/pybind11/py_akantu.cc new file mode 100644 index 000000000..39c06c0e7 --- /dev/null +++ b/python/pybind11/py_akantu.cc @@ -0,0 +1,12 @@ +#include + +namespace py = pybind11; + +#include "py_aka_common.cc" +#include "py_aka_array.cc" + +PYBIND11_MODULE(py11_akantu, mod) { + mod.doc() = "Akantu python interface"; + + register_enums(mod); +} // Module akantu diff --git a/python/CMakeLists.txt b/python/swig/CMakeLists.txt similarity index 70% copy from python/CMakeLists.txt copy to python/swig/CMakeLists.txt index 38addabc6..a35aa7ed5 100644 --- a/python/CMakeLists.txt +++ b/python/swig/CMakeLists.txt @@ -1,292 +1,246 @@ -#=============================================================================== -# @file CMakeLists.txt -# -# @author Nicolas Richart -# -# @date creation: Fri Dec 12 2014 -# @date last modification: Mon Jan 18 2016 -# -# @brief CMake file for the python wrapping of akantu -# -# @section LICENSE -# -# Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory -# (LSMS - Laboratoire de Simulation en Mécanique des Solides) -# -# Akantu is free software: you can redistribute it and/or modify it under the -# terms of the GNU Lesser General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) any -# later version. -# -# Akantu is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -# details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Akantu. If not, see . -# -#=============================================================================== - #=============================================================================== # Configuration #=============================================================================== package_get_all_definitions(AKANTU_DEFS) list(REMOVE_ITEM AKANTU_DEFS AKANTU_CORE_CXX11) #message(${AKANTU_DEFS}) set(AKA_DEFS "") foreach (def ${AKANTU_DEFS}) list(APPEND AKA_DEFS "-D${def}") endforeach() set(AKANTU_SWIG_FLAGS -w309,325,401,317,509,503,383,384,476,362 ${AKA_DEFS}) set(AKANTU_SWIG_OUTDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(AKANTU_SWIG_MODULES swig/akantu.i) +set(AKANTU_SWIG_MODULES akantu.i) #=============================================================================== # Swig wrapper #=============================================================================== -set(SWIG_REQURIED_VERISON 3.0) -find_package(SWIG ${SWIG_REQURIED_VERISON}) -find_package(PythonInterp ${AKANTU_PREFERRED_PYTHON_VERSION} REQUIRED) -mark_as_advanced(SWIG_EXECUTABLE) - if(NOT PYTHON_VERSION_MAJOR LESS 3) list(APPEND AKANTU_SWIG_FLAGS -py3) endif() package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) package_get_all_external_informations( INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR ) set(_swig_include_dirs - ${CMAKE_CURRENT_SOURCE_DIR}/swig + ${CMAKE_CURRENT_SOURCE_DIR} ${AKANTU_LIBRARY_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/src ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR} ) include(CMakeParseArguments) function(swig_generate_dependencies _module _depedencies _depedencies_out) set(_dependencies_script "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_generate_dependencies.cmake") file(WRITE ${_dependencies_script} " set(_include_directories ${_include_directories}) list(APPEND _include_directories \"./\") set(_dep) set(_files_to_process \${_module}) while(_files_to_process) list(GET _files_to_process 0 _file) list(REMOVE_AT _files_to_process 0) file(STRINGS \${_file} _file_content REGEX \"^%include *\\\"(.*)\\\"\") set(_includes) foreach(_line \${_file_content}) string(REGEX REPLACE \"^%include *\\\"(.*)\\\"\" \"\\\\1\" _inc \${_line}) if(_inc) list(APPEND _includes \${_inc}) endif() endforeach() foreach(_include \${_includes}) unset(_found) foreach(_inc_dir \${_include_directories}) if(EXISTS \${_inc_dir}/\${_include}) set(_found \${_inc_dir}/\${_include}) break() endif() endforeach() if(_found) list(APPEND _files_to_process \${_found}) list(APPEND _dep \${_found}) endif() endforeach() endwhile() get_filename_component(_module_we \"\${_module}\" NAME_WE) set(_dependencies_file \${CMAKE_CURRENT_BINARY_DIR}\${CMAKE_FILES_DIRECTORY}/_swig_\${_module_we}_depends.cmake) file(WRITE \"\${_dependencies_file}\" \"set(_swig_\${_module_we}_depends\") foreach(_d \${_dep}) file(APPEND \"\${_dependencies_file}\" \" \${_d}\") endforeach() file(APPEND \"\${_dependencies_file}\" \" )\") ") get_filename_component(_module_absolute "${_module}" ABSOLUTE) get_filename_component(_module_we "${_module}" NAME_WE) set(_dependencies_file ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) if(EXISTS ${_dependencies_file}) include(${_dependencies_file}) else() execute_process(COMMAND ${CMAKE_COMMAND} -D_module=${_module_absolute} -P ${_dependencies_script} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) include(${_dependencies_file}) endif() set(${_depedencies_out} ${_swig_${_module_we}_depends} PARENT_SCOPE) add_custom_command(OUTPUT ${_dependencies_file} COMMAND ${CMAKE_COMMAND} -D_module=${_module_absolute} -P ${_dependencies_script} COMMENT "Scanning dependencies for swig module ${_module_we}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} MAIN_DEPENDENCY ${_module_absolute} DEPENDS ${_swig_${_module_we}_depends} ) set(${_depedencies} ${_dependencies_file} PARENT_SCOPE) endfunction() function(swig_generate_wrappers project _wrappers_cpp _wrappers_py) cmake_parse_arguments(_swig_opt "" "OUTPUT_DIR;DEPENDENCIES" "EXTRA_FLAGS;INCLUDE_DIRECTORIES" ${ARGN}) if(_swig_opt_OUTPUT_DIR) set(_output_dir ${_swig_opt_OUTPUT_DIR}) else() set(_output_dir ${CMAKE_CURRENT_BINARY_DIR}) endif() set(_swig_wrappers) get_directory_property(_include_directories INCLUDE_DIRECTORIES) list(APPEND _include_directories ${_swig_opt_INCLUDE_DIRECTORIES}) if(_include_directories) string(REPLACE ";" ";-I" _swig_include_directories "${_include_directories}") endif() foreach(_module ${_swig_opt_UNPARSED_ARGUMENTS}) swig_generate_dependencies(${_module} _module_dependencies _depends_out) if(_swig_opt_DEPENDENCIES) set(${_swig_opt_DEPENDENCIES} ${_depends_out} PARENT_SCOPE) endif() get_filename_component(_module_absolute "${_module}" ABSOLUTE) get_filename_component(_module_path "${_module_absolute}" PATH) get_filename_component(_module_name "${_module}" NAME) get_filename_component(_module_we "${_module}" NAME_WE) set(_wrapper "${_output_dir}/${_module_we}_wrapper.cpp") set(_extra_wrapper "${_output_dir}/${_module_we}.py") set(_extra_wrapper_bin "${CMAKE_CURRENT_BINARY_DIR}/${_module_we}.py") - if(SWIG_FOUND) - set_source_files_properties("${_wrapper}" PROPERTIES GENERATED 1) - set_source_files_properties("${_extra_wrapper}" PROPERTIES GENERATED 1) - - set(_dependencies_file - ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) - - set(_ouput "${_wrapper}" "${_extra_wrapper}") - add_custom_command( - OUTPUT ${_ouput} - COMMAND "${SWIG_EXECUTABLE}" - ARGS -python -c++ - ${_swig_opt_EXTRA_FLAGS} - -outdir ${_output_dir} - -I${_swig_include_directories} -I${_module_path} - -o "${_wrapper}" - "${_module_absolute}" - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_extra_wrapper} ${_extra_wrapper_bin} - # MAIN_DEPENDENCY "${_module_absolute}" - DEPENDS ${_module_dependencies} - COMMENT "Generating swig wrapper ${_module} -> ${_wrapper}" - ) - - list(APPEND _swig_wrappers ${_wrapper}) - list(APPEND _swig_wrappers_py "${_extra_wrapper_bin}") - else() - if(NOT EXISTS ${_wrapper} OR NOT EXISTS "${_extra_wrapper}") - message(FATAL_ERROR "The file ${_wrapper} and/or ${_extra_wrapper} does " - "not exists and they cannot be generated. Install swig ${SWIG_REQURIED_VERISON} " - " in order to generate them. Or get them from a different machine, " - "in order to be able to compile the python interface") - else() - list(APPEND _swig_wrappers "${_wrapper}") - list(APPEND _swig_wrappers_py "${_extra_wrapper_bin}") - endif() - endif() + + set_source_files_properties("${_wrapper}" PROPERTIES GENERATED 1) + set_source_files_properties("${_extra_wrapper}" PROPERTIES GENERATED 1) + + set(_dependencies_file + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) + + set(_ouput "${_wrapper}" "${_extra_wrapper}") + add_custom_command( + OUTPUT ${_ouput} + COMMAND "${SWIG_EXECUTABLE}" + ARGS -python -c++ + ${_swig_opt_EXTRA_FLAGS} + -outdir ${_output_dir} + -I${_swig_include_directories} -I${_module_path} + -o "${_wrapper}" + "${_module_absolute}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_extra_wrapper} ${_extra_wrapper_bin} + # MAIN_DEPENDENCY "${_module_absolute}" + DEPENDS ${_module_dependencies} + COMMENT "Generating swig wrapper ${_module} -> ${_wrapper}" + ) + + list(APPEND _swig_wrappers ${_wrapper}) + list(APPEND _swig_wrappers_py "${_extra_wrapper_bin}") endforeach() add_custom_target(${project}_generate_swig_wrappers DEPENDS ${_swig_wrappers}) set(${_wrappers_cpp} ${_swig_wrappers} PARENT_SCOPE) set(${_wrappers_py} ${_swig_wrappers_py} PARENT_SCOPE) endfunction() swig_generate_wrappers(akantu AKANTU_SWIG_WRAPPERS_CPP AKANTU_WRAPPERS_PYTHON ${AKANTU_SWIG_MODULES} EXTRA_FLAGS ${AKANTU_SWIG_FLAGS} DEPENDENCIES _deps INCLUDE_DIRECTORIES ${_swig_include_dirs}) if(AKANTU_SWIG_WRAPPERS_CPP) set(_ext_files "${AKANTU_SWIG_WRAPPERS_CPP}") set(_inc_dirs "${_swig_include_dirs}") set(_lib_dirs "${Akantu_BINARY_DIR}/src") string(TOUPPER "${CMAKE_BUILD_TYPE}" _config) set(_akantu_lib_name "akantu${CMAKE_${_config}_POSTFIX}") get_property(_compile_flags TARGET akantu PROPERTY COMPILE_FLAGS) set(_compile_flags "${_compile_flags} ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${_config}}") separate_arguments(_compile_flags) get_property(_cxx_standard TARGET akantu PROPERTY CXX_STANDARD) set(_flags ${_compile_flags} -std=c++${_cxx_standard} -Wno-unused-parameter -Wno-uninitialized) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") list(APPEND -Wno-unused-command-line-argument) elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") list(APPEND -Wno-maybe-uninitialized) endif() set(_quiet) if(NOT CMAKE_VERBOSE_MAKEFILE) set(_quiet --quiet) endif() configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY) add_custom_target(_akantu ALL COMMAND ${PYTHON_EXECUTABLE} ./setup.py ${_quiet} --no-user-cfg build_ext --inplace WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${AKANTU_SWIG_WRAPPERS_CPP} akantu COMMENT "Building akantu's python interface" ) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/_akantu${CMAKE_SHARED_MODULE_SUFFIX}) install(CODE "execute_process( COMMAND ${PYTHON_EXECUTABLE} ./setup.py ${_quiet} install --prefix=${AKANTU_PYTHON_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" ) package_declare_extra_files_to_package(python_interface ${_deps} ${PROJECT_SOURCE_DIR}/python/${AKANTU_SWIG_MODULES}) endif() diff --git a/python/swig/setup.py.in b/python/swig/setup.py.in new file mode 100644 index 000000000..6ff905995 --- /dev/null +++ b/python/swig/setup.py.in @@ -0,0 +1,42 @@ +from distutils.core import setup +from distutils.core import setup, Extension +from distutils.command.build_ext import build_ext +from distutils.sysconfig import customize_compiler + +import os +import sys + +os.environ['CC'] = '@CMAKE_CXX_COMPILER@' +os.environ['CXX'] = '@CMAKE_CXX_COMPILER@' + +def cmake_to_list(cmake_list): + if cmake_list == '': + return [] + return cmake_list.split(';') + + +class cpp_build_ext(build_ext): + def build_extensions(self): + customize_compiler(self.compiler) + try: + self.compiler.compiler_so.remove("-Wstrict-prototypes") + except (AttributeError, ValueError): + pass + build_ext.build_extensions(self) + +setup( + name='akantu', + license='LGPLv3', + version='@AKANTU_VERSION@', + py_modules=['akantu'], + cmdclass={'build_ext': cpp_build_ext}, + ext_modules=[Extension( + '_akantu', + cmake_to_list('@_ext_files@'), + include_dirs=cmake_to_list('@_inc_dirs@'), + language='c++', + libraries=cmake_to_list('@_akantu_lib_name@'), + library_dirs=cmake_to_list('@_lib_dirs@'), + extra_compile_args=cmake_to_list('@_flags@') + )] +) diff --git a/test/test_fe_engine/py_engine/py_engine.py b/test/test_fe_engine/py_engine/py_engine.py index 37bd98ac5..0bd2c7f84 100644 --- a/test/test_fe_engine/py_engine/py_engine.py +++ b/test/test_fe_engine/py_engine/py_engine.py @@ -1,355 +1,355 @@ #!/usr/bin/env python3 - +# -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016-2018, EPFL (Ecole Polytechnique Fédérale" \ " de Lausanne) Laboratory (LSMS - Laboratoire de Simulation" \ " en Mécanique des Solides)" __credits__ = ["Nicolas Richart"] __license__ = "L-GPLv3" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" # ------------------------------------------------------------------------------ __all__ = ['Shapes'] import numpy as np import numpy.polynomial.polynomial as poly import aka_test class Shapes(object): NATURAL_COORDS = { (1, 'quadrangle'): np.array([[-1.], [1.], [0.]]), (2, 'quadrangle'): np.array([[-1., -1.], [ 1., -1.], [ 1., 1.], [-1., 1.], [ 0., -1.], [ 1., 0.], [ 0., 1.], [-1., 0.]]), (3, 'quadrangle'): np.array([[-1., -1., -1.], [ 1., -1., -1.], [ 1., 1., -1.], [-1., 1., -1.], [-1., -1., 1.], [ 1., -1., 1.], [ 1., 1., 1.], [-1., 1., 1.], [ 0., -1., -1.], [ 1., 0., -1.], [ 0., 1., -1.], [-1., 0., -1.], [-1., -1., 0.], [ 1., -1., 0.], [ 1., 1., 0.], [-1., 1., 0.], [ 0., -1., 1.], [ 1., 0., 1.], [ 0., 1., 1.], [-1., 0., 1.]]), (2, 'triangle'): np.array([[0., 0.], [1., 0.], [0., 1,], [.5, 0.], [.5, .5], [0., .5]]), (3, 'triangle'): np.array([[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.], [.5, 0., 0.], [.5, .5, 0.], [0., .5, 0.], [0., 0., .5], [.5, 0., .5], [0., .5, .5]]), (3, 'pentahedron'): np.array([[-1., 1., 0.], [-1., 0., 1.], [-1., 0., 0.], [ 1., 1., 0.], [ 1., 0., 1.], [ 1., 0., 0.], [-1., .5, .5], [-1., 0., .5], [-1., .5, 0.], [ 0., 1., 0.], [ 0., 0., 1.], [ 0., 0., 0.], [ 1., .5, .5], [ 1., 0., .5], [ 1., .5, 0.], [ 0., .5, .5], [ 0., 0., .5], [ 0., .5, 0.]]), } QUADRATURE_W = { (1, 'quadrangle', 1): np.array([2.]), (1, 'quadrangle', 2): np.array([1., 1.]), (2, 'triangle', 1): np.array([1./2.]), (2, 'triangle', 2): np.array([1., 1., 1.])/6., (3, 'triangle', 1): np.array([1./6.]), (3, 'triangle', 2): np.array([1., 1., 1., 1.])/24., (2, 'quadrangle', 1): np.array([1., 1., 1., 1.]), (2, 'quadrangle', 2): np.array([1., 1., 1., 1.]), (3, 'quadrangle', 1): np.array([1., 1., 1., 1., 1., 1., 1., 1.]), (3, 'quadrangle', 2): np.array([1., 1., 1., 1., 1., 1., 1., 1.]), (3, 'pentahedron', 1): np.array([1., 1., 1., 1., 1., 1.])/6., (3, 'pentahedron', 2): np.array([1., 1., 1., 1., 1., 1.])/6., } _tet_a = (5. - np.sqrt(5.))/20. _tet_b = (5. + 3.*np.sqrt(5.))/20. QUADRATURE_G = { (1, 'quadrangle', 1): np.array([[0.]]), (1, 'quadrangle', 2): np.array([[-1.], [1.]])/np.sqrt(3.), (2, 'triangle', 1): np.array([[1., 1.]])/3., (2, 'triangle', 2): np.array([[1./6., 1./6.], [2./3, 1./6], [1./6., 2./3.]]), (3, 'triangle', 1): np.array([[1., 1., 1.]])/4., (3, 'triangle', 2): np.array([[_tet_a, _tet_a, _tet_a], [_tet_b, _tet_a, _tet_a], [_tet_a, _tet_b, _tet_a], [_tet_a, _tet_a, _tet_b]]), (2, 'quadrangle', 1): np.array([[-1., -1.], [ 1., -1.], [-1., 1.], [ 1., 1.]])/np.sqrt(3.), (2, 'quadrangle', 2): np.array([[-1., -1.], [ 1., -1.], [-1., 1.], [ 1., 1.]])/np.sqrt(3.), (3, 'quadrangle', 1): np.array([[-1., -1., -1.], [ 1., -1., -1.], [-1., 1., -1.], [ 1., 1., -1.], [-1., -1., 1.], [ 1., -1., 1.], [-1., 1., 1.], [ 1., 1., 1.]])/np.sqrt(3.), (3, 'quadrangle', 2): np.array([[-1., -1., -1.], [ 1., -1., -1.], [-1., 1., -1.], [ 1., 1., -1.], [-1., -1., 1.], [ 1., -1., 1.], [-1., 1., 1.], [ 1., 1., 1.]])/np.sqrt(3.), # (3, 'pentahedron', 1): np.array([[-1./np.sqrt(3.), 0.5, 0.5], # [-1./np.sqrt(3.), 0. , 0.5], # [-1./np.sqrt(3.), 0.5, 0. ], # [ 1./np.sqrt(3.), 0.5, 0.5], # [ 1./np.sqrt(3.), 0. , 0.5], # [ 1./np.sqrt(3.), 0.5 ,0. ]]), (3, 'pentahedron', 1): np.array([[-1./np.sqrt(3.), 1./6., 1./6.], [-1./np.sqrt(3.), 2./3., 1./6.], [-1./np.sqrt(3.), 1./6., 2./3.], [ 1./np.sqrt(3.), 1./6., 1./6.], [ 1./np.sqrt(3.), 2./3., 1./6.], [ 1./np.sqrt(3.), 1./6., 2./3.]]), (3, 'pentahedron', 2): np.array([[-1./np.sqrt(3.), 1./6., 1./6.], [-1./np.sqrt(3.), 2./3., 1./6.], [-1./np.sqrt(3.), 1./6., 2./3.], [ 1./np.sqrt(3.), 1./6., 1./6.], [ 1./np.sqrt(3.), 2./3., 1./6.], [ 1./np.sqrt(3.), 1./6., 2./3.]]), } ELEMENT_TYPES = { '_segment_2': ('quadrangle', 1, 'lagrange', 1, 2), '_segment_3': ('quadrangle', 2, 'lagrange', 1, 3), '_triangle_3': ('triangle', 1, 'lagrange', 2, 3), '_triangle_6': ('triangle', 2, 'lagrange', 2, 6), '_quadrangle_4': ('quadrangle', 1, 'serendip', 2, 4), '_quadrangle_8': ('quadrangle', 2, 'serendip', 2, 8), '_tetrahedron_4': ('triangle', 1, 'lagrange', 3, 4), '_tetrahedron_10': ('triangle', 2, 'lagrange', 3, 10), '_pentahedron_6': ('pentahedron', 1, 'lagrange', 3, 6), '_pentahedron_15': ('pentahedron', 2, 'lagrange', 3, 15), '_hexahedron_8': ('quadrangle', 1, 'serendip', 3, 8), '_hexahedron_20': ('quadrangle', 2, 'serendip', 3, 20), } MONOMES = {(1, 'quadrangle'): np.array([[0], [1], [2], [3], [4], [5]]), (2, 'triangle'): np.array([[0, 0], # 1 [1, 0], [0, 1], # x y [2, 0], [1, 1], [0, 2]]), # x^2 x.y y^2 (2, 'quadrangle'): np.array([[0, 0], [1, 0], [1, 1], [0, 1], [2, 0], [2, 1], [1, 2], [0, 2]]), (3, 'triangle'): np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [2, 0, 0], [1, 1, 0], [0, 2, 0], [0, 1, 1], [0, 0, 2], [1, 0, 1]]), (3, 'quadrangle'): np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1], [1, 1, 1], [2, 0, 0], [0, 2, 0], [0, 0, 2], [2, 1, 0], [2, 0, 1], [2, 1, 1], [1, 2, 0], [0, 2, 1], [1, 2, 1], [1, 0, 2], [0, 1, 2], [1, 1, 2]]), } SHAPES = { (3, 'pentahedron', 1): np.array([ [[[ 0., 0.], [ 1., 0.]], [[ 0., 0.], [-1., 0.]]], [[[ 0., 1.], [ 0., 0.]], [[ 0., -1.], [ 0., 0.]]], [[[ 1., -1.], [-1., 0.]], [[-1., 1.], [ 1., 0.]]], [[[ 0., 0.], [ 1., 0.]], [[ 0., 0.], [ 1., 0.]]], [[[ 0., 1.], [ 0., 0.]], [[ 0., 1.], [ 0., 0.]]], [[[ 1., -1.], [-1., 0.]], [[ 1., -1.], [-1., 0.]]] ])/2., (3, 'pentahedron', 2): np.array([ # 0 [[[ 0. , 0. , 0. ], [-1. , 0. , 0. ], [ 1. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0.5, 0. , 0. ], [-1. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0.5, 0. , 0. ], [ 0. , 0. , 0. ]]], # 1 [[[ 0. , -1. , 1. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0.5, -1. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0.5, 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 2 [[[ 0. , -1. , 1. ], [-1. , 2. , 0. ], [ 1. , 0. , 0. ]], [[-0.5, 1.5, -1. ], [ 1.5, -2. , 0. ], [-1. , 0. , 0. ]], [[ 0.5, -0.5, 0. ], [-0.5, 0. , 0. ], [ 0. , 0. , 0. ]]], # 3 [[[ 0. , 0. , 0. ], [-1. , 0. , 0. ], [ 1. , 0. , 0. ]], [[ 0. , 0. , 0. ], [-0.5, 0. , 0. ], [ 1. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0.5, 0. , 0. ], [ 0. , 0. , 0. ]]], # 4 [[[ 0. , -1. , 1. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , -0.5, 1. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0.5, 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 5 [[[ 0. , -1. , 1. ], [-1. , 2. , 0. ], [ 1. , 0. , 0. ]], [[ 0.5, -1.5, 1. ], [-1.5, 2. , 0. ], [ 1. , 0. , 0. ]], [[ 0.5, -0.5, 0. ], [-0.5, 0. , 0. ], [ 0. , 0. , 0. ]]], # 6 [[[ 0. , 0. , 0. ], [ 0. , 2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , -2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 7 [[[ 0. , 2. , -2. ], [ 0. , -2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , -2. , 2. ], [ 0. , 2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 8 [[[ 0. , 0. , 0. ], [ 2. , -2. , 0. ], [-2. , 0. , 0. ]], [[ 0. , 0. , 0. ], [-2. , 2. , 0. ], [ 2. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 9 [[[ 0. , 0. , 0. ], [ 1. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [-1. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 10 [[[ 0. , 1. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , -1. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 11 [[[ 1. , -1. , 0. ], [-1. , 0. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]], [[-1. , 1. , 0. ], [ 1. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 12 [[[ 0. , 0. , 0. ], [ 0. , 2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 13 [[[ 0. , 2. , -2. ], [ 0. , -2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 2. , -2. ], [ 0. , -2. , 0. ], [ 0. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], # 14 [[[ 0. , 0. , 0. ], [ 2. , -2. , 0. ], [-2. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 2. , -2. , 0. ], [-2. , 0. , 0. ]], [[ 0. , 0. , 0. ], [ 0. , 0. , 0. ], [ 0. , 0. , 0. ]]], ])} def __init__(self, element): self._shape, self._order, self._inter_poly, self._dim, self._nnodes = self.ELEMENT_TYPES[element] self._ksi = self.NATURAL_COORDS[(self._dim, self._shape)][:self._nnodes] self._g = self.QUADRATURE_G[(self._dim, self._shape, self._order)] self._w = self.QUADRATURE_W[(self._dim, self._shape, self._order)] def polyval(self, x, p): if 1 == self._dim: return poly.polyval(x[0], p) if 2 == self._dim: return poly.polyval2d(x[0], x[1], p) if 3 == self._dim: return poly.polyval3d(x[0], x[1], x[2], p) def shape_from_monomes(self): momo = self.MONOMES[(self._dim, self._shape)][:self._nnodes] _shape = list(momo[0]) for s in range(len(_shape)): _shape[s] = max(momo[:,s])+1 self._poly_shape = tuple(_shape) self._monome = [] for m in momo: p = np.zeros(self._poly_shape) p[tuple(m)] = 1 self._monome.append(p) # evaluate polynomial constant for shapes _x = self._ksi _xe = np.zeros((self._nnodes, self._nnodes)) for n in range(self._nnodes): _xe[:,n] = [self.polyval(_x[n], m) for m in self._monome] _a = np.linalg.inv(_xe) _n = np.zeros((self._nnodes,) + self._monome[0].shape) # set shapes polynomials for n in range(self._nnodes): for m in range(len(self._monome)): _n[n] += _a[n, m] * self._monome[m] return _n def compute_shapes(self): if (self._dim, self._shape) in self.MONOMES: return self.shape_from_monomes() else: _n = self.SHAPES[(self._dim, self._shape, self._order)] self._poly_shape = _n[0].shape return _n def precompute(self, **kwargs): X = np.array(kwargs["X"], copy=False) nb_element = X.shape[0] X = X.reshape(nb_element, self._nnodes, self._dim) _x = self._ksi _n = self.compute_shapes() # sanity check on shapes for n in range(self._nnodes): for m in range(self._nnodes): v = self.polyval(_x[n], _n[m]) ve = 1. if n == m else 0. test = np.isclose(v, ve) if not test: raise Exception("Most probably an error in the shapes evaluation") # compute shapes derivatives _b = np.zeros((self._dim, self._nnodes,) + self._poly_shape) for d in range(self._dim): for n in range(self._nnodes): _der = poly.polyder(_n[n], axis=d) _mshape = np.array(self._poly_shape) _mshape[d] = _mshape[d] - _der.shape[d] _mshape = tuple(_mshape) _comp = np.zeros(_mshape) if 1 == self._dim: _bt = np.hstack((_der, _comp)) else: if 0 == d: _bt = np.vstack((_der, _comp)) if 1 == d: _bt = np.hstack((_der, _comp)) if 2 == d: _bt = np.dstack((_der, _comp)) _b[d, n] = _bt _nb_quads = len(self._g) _nq = np.zeros((_nb_quads, self._nnodes)) _bq = np.zeros((_nb_quads, self._dim, self._nnodes)) # evaluate shapes and shapes derivatives on gauss points for q in range(_nb_quads): _g = self._g[q] for n in range(self._nnodes): _nq[q, n] = self.polyval(_g, _n[n]) for d in range(self._dim): _bq[q, d, n] = self.polyval(_g, _b[d, n]) _j = np.array(kwargs['j'], copy=False).reshape((nb_element, _nb_quads)) _B = np.array(kwargs['B'], copy=False).reshape((nb_element, _nb_quads, self._nnodes, self._dim)) _N = np.array(kwargs['N'], copy=False).reshape((nb_element, _nb_quads, self._nnodes)) _Q = np.array(kwargs['Q'], copy=False) if np.linalg.norm(_Q - self._g.T) > 1e-15: raise Exception('Not using the same quadrature points') for e in range(nb_element): for q in range(_nb_quads): _J = np.matmul(_bq[q], X[e]) if(np.linalg.norm(_N[e, q] - _nq[q]) > 1e-10): print(f"{e},{q}") print(_N[e, q]) print(_nq[q]) _N[e, q] = _nq[q] _tmp = np.matmul(np.linalg.inv(_J), _bq[q]) _B[e, q] = _tmp.T _j[e, q] = np.linalg.det(_J) * self._w[q] diff --git a/test/test_python_interface/CMakeLists.txt b/test/test_python_interface/CMakeLists.txt index 4cace506e..06118ae4c 100644 --- a/test/test_python_interface/CMakeLists.txt +++ b/test/test_python_interface/CMakeLists.txt @@ -1,46 +1,48 @@ #=============================================================================== # @file CMakeLists.txt # # @author Fabian Barras # @author Lucas Frerot # # @date creation: Fri Sep 03 2010 # @date last modification: Mon Feb 05 2018 # # @brief Python Interface tests # # @section LICENSE # # Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along with Akantu. If not, see . # #=============================================================================== +add_akantu_test(pybind11 "Test the pybind11 interface") + add_mesh(mesh_python mesh_dcb_2d.geo ORDER 2 DIM 2) register_test(test_multiple_init SCRIPT test_multiple_init.py PYTHON DEPENDS mesh_python PACKAGE python_interface FILES_TO_COPY input_test.dat ) register_test(test_mesh_interface SCRIPT test_mesh_interface.py PYTHON DEPENDS mesh_python PACKAGE python_interface ) register_test(test_boundary_condition_functors SCRIPT test_boundary_condition_functors.py PYTHON DEPENDS mesh_python PACKAGE python_interface FILES_TO_COPY input_test.dat) diff --git a/test/test_python_interface/pybind11/CMakeLists.txt b/test/test_python_interface/pybind11/CMakeLists.txt new file mode 100644 index 000000000..334aef6ce --- /dev/null +++ b/test/test_python_interface/pybind11/CMakeLists.txt @@ -0,0 +1,10 @@ +pybind11_add_module(py11_akantu_test_common test_common.cc) +target_link_libraries(py11_akantu_test_common PRIVATE akantu) +set_property(TARGET py11_akantu_test_common PROPERTY DEBUG_POSTFIX "") + +register_test(test_pybind11_common + SCRIPT test_common.py + DEPENDS py11_akantu + PACKAGE pybind11 python_interface + PYTHON + ) diff --git a/test/test_python_interface/pybind11/test_common.cc b/test/test_python_interface/pybind11/test_common.cc new file mode 100644 index 000000000..13c20dd1e --- /dev/null +++ b/test/test_python_interface/pybind11/test_common.cc @@ -0,0 +1,13 @@ +#include +#include + +namespace py = pybind11; +using namespace akantu; + +PYBIND11_MODULE(py11_akantu_test_common, mod) { + mod.doc() = "Akantu Test function for common "; + + Array data{1000, 3}; + + mod.def("getData", [&data]() -> Array& { return data; }); +} // Module akantu_test_common diff --git a/test/test_python_interface/pybind11/test_common.py b/test/test_python_interface/pybind11/test_common.py new file mode 100644 index 000000000..3f253b395 --- /dev/null +++ b/test/test_python_interface/pybind11/test_common.py @@ -0,0 +1,8 @@ +# import pybind11 +import py11_akantu as pyaka +import py11_akantu_test_common as pyaka_test + + +def test_array(): + array = pyaka_test.getData() + assert array.shape == (1000, 3)