diff --git a/CMake/FindFFTW.cmake b/CMake/FindFFTW.cmake index eb00a98025d4657b63b4b7041118fdcfb5717a0f..7a48c8e21b1b6752fada4cdd4914ef02ede952cc 100644 --- a/CMake/FindFFTW.cmake +++ b/CMake/FindFFTW.cmake @@ -80,11 +80,11 @@ find_library(FFTWFloat_MPI_LIBRARY #other types for the CXX library -find_library (FFTWD_LIB "fftw3") -find_library (FFTWL_LIB "fftw3l") -find_library (FFTWQ_LIB "fftw3q") -set(FFTW_OTHER_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB} ${FFTWL_LIB} ${FFTWQ_LIB}) +#find_library (FFTWD_LIB "fftw3") +#find_library (FFTWL_LIB "fftw3l") +#find_library (FFTWQ_LIB "fftw3q") +set(FFTW_OTHER_LIBRARIES) # ${FFTW_LIB} ${FFTWF_LIB} ${FFTWL_LIB} ${FFTWQ_LIB}) set(FFTW_PROCESS_INCLUDES FFTW_INCLUDE_DIR) -set(FFTW_PROCESS_LIBS FFTW_LIBRARY FFTWFloat_LIBRARY FFTW_MPI_LIBRARY FFTWFloat_MPI_LIBRARY FFTW_OTHER_LIBRARIES) +set(FFTW_PROCESS_LIBS FFTW_LIBRARY FFTWFloat_LIBRARY FFTW_MPI_LIBRARY FFTWFloat_MPI_LIBRARY)# FFTW_OTHER_LIBRARIES) libfind_process(FFTW) diff --git a/CMake/FindPythonFull.cmake b/CMake/FindPythonFull.cmake index 6447a4af8fc9fbe0be05d74b08e49f33afe9b477..646611606ac36dbb90f17eab561856ce8a195189 100644 --- a/CMake/FindPythonFull.cmake +++ b/CMake/FindPythonFull.cmake @@ -16,7 +16,7 @@ # PYTHON_EXECUTABLE - python interpreter (full path) # PYTHON_VERSION_STRING - Python version found e.g. 2.5.2 # PYTHON_LIBRARIES - full path to the python library -# PYTHON_INCLUDE_DIR - full path to Python.h +# PYTHON_INCLUDE_DIRS - full path to Python.h # PYTHONLIBS_VERSION_STRING - version of the Python libs found # # By default, we search for the current active python version first. @@ -27,7 +27,7 @@ set(PYTHON_FOUND FALSE) # Does nothing if vars are already in cache -if(EXISTS "${PYTHON_INCLUDE_DIR}" AND EXISTS "${PYTHON_LIBRARY}" AND EXISTS "${PYTHON_SITE_PACKAGES_DIR}") +if(EXISTS "${PYTHON_INCLUDE_DIRS}" AND EXISTS "${PYTHON_LIBRARY}" AND EXISTS "${PYTHON_SITE_PACKAGES_DIR}") set(PYTHON_FOUND TRUE) else() set(PYTHON_FOUND FALSE) @@ -47,11 +47,12 @@ else() if(python_config) string(REGEX REPLACE ".*exec_prefix:([^\n]+).*$" "\\1" PYTHON_PREFIX ${python_config}) string(REGEX REPLACE ".*\nversion:([^\n]+).*$" "\\1" PYTHON_VERSION ${python_config}) - string(REGEX REPLACE ".*\npy_inc_dir:([^\n]+).*$" "\\1" PYTHON_INCLUDE_DIR ${python_config}) + string(REGEX REPLACE ".*\npy_inc_dir:([^\n]+).*$" "\\1" PYTHON_INCLUDE_DIRS ${python_config}) string(REGEX REPLACE ".*\nsite_packages_dir:([^\n]+).*$" "\\1" PYTHON_SITE_PACKAGES_DIR ${python_config}) string(REGEX REPLACE "([0-9]+).([0-9]+)" "\\1\\2" PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) if(WIN32) string(REPLACE "\\" "/" PYTHON_SITE_PACKAGES_DIR ${PYTHON_SITE_PACKAGES_DIR}) + string(REPLACE "\\" "/" PYTHON_PREFIX ${PYTHON_PREFIX}) endif(WIN32) # --- Search python library corresponding to python exec. @@ -59,25 +60,17 @@ else() NAMES python${PYTHON_VERSION_NO_DOTS} python${PYTHON_VERSION} NO_DEFAULT_PATH - HINTS - ${PYTHON_PREFIX} - ${PYTHON_PREFIX}/lib/python${PYTHON_VERSION}/config - ${PYTHON_PREFIX}/lib/python${PYTHON_VERSION}/config-x86_64-linux-gnu - PATH_SUFFIXES lib + HINTS ${PYTHON_PREFIX} ${PYTHON_PREFIX}/lib/python${PYTHON_VERSION}/config ${PYTHON_PREFIX}/lib/python${PYTHON_VERSION}/config-${CMAKE_LIBRARY_ARCHITECTURE} + PATH_SUFFIXES lib libs ) - # find_library(PYTHON_LIBRARY - # NAMES - # python${PYTHON_VERSION_NO_DOTS} python${PYTHON_VERSION} - # NO_DEFAULT_PATH - # HINTS ${PYTHON_PREFIX}/lib/python${PYTHON_VERSION}/config - # ) + set(PYTHON_LIBRARIES ${PYTHON_LIBRARY} CACHE FILEPATH "Python libraries" FORCE) - set(PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR} CACHE FILEPATH "Path to Python.h" FORCE) + set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE FILEPATH "Path to Python.h" FORCE) # --- Extract python library version for further checks. - if(PYTHON_INCLUDE_DIR AND EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h") - file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str + if(PYTHON_INCLUDE_DIRS AND EXISTS "${PYTHON_INCLUDE_DIRS}/patchlevel.h") + file(STRINGS "${PYTHON_INCLUDE_DIRS}/patchlevel.h" python_version_str REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" PYTHONLIBS_VERSION_STRING "${python_version_str}") @@ -89,15 +82,15 @@ else() unset(PYTHON_FOUND) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Python - REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIR PYTHON_EXECUTABLE + REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS PYTHON_EXECUTABLE VERSION_VAR PYTHONLIBS_VERSION_STRING) - if(PYTHON_FOUND) + set(PYTHONFULL_FOUND TRUE) if(NOT PythonFull_FIND_QUIETLY) message("-- Found Python executable: ${PYTHON_EXECUTABLE}") message("-- Found Python library: ${PYTHON_LIBRARIES}") message("-- Python version is : ${PYTHON_VERSION_STRING}") - message("-- Python include dir is : ${PYTHON_INCLUDE_DIR}") + message("-- Python include dir is : ${PYTHON_INCLUDE_DIRS}") message("-- Python Site package dir is : ${PYTHON_SITE_PACKAGES_DIR}\n") endif() else() @@ -111,5 +104,5 @@ endif() if(NOT PYTHONLIBS_VERSION_STRING VERSION_EQUAL PYTHON_VERSION_STRING) display(PYTHONLIBS_VERSION_STRING) display(PYTHON_VERSION_STRING) - message(FATAL_ERROR "Python library and executable versions do not match.") + message(FATAL_ERROR "Python library and executable versions do not match. Please check your python installation.") endif() diff --git a/CMake/FindPythonModule.cmake b/CMake/FindPythonModule.cmake index 660533df8669e4671e4562f767588263a3525fd5..dd356effbb06122a682e11bc977c8bf4f7ca7990 100644 --- a/CMake/FindPythonModule.cmake +++ b/CMake/FindPythonModule.cmake @@ -11,16 +11,24 @@ function(find_python_module module) # A module's location is usually a directory, but for binary modules # it's a .so file. execute_process(COMMAND ${PYTHON_EXECUTABLE} -c - "import re, ${module}; print re.compile('/__init__.py.*').sub('',${module}.__file__)" + "import re, ${module}; print(re.compile('/__init__.py.*').sub('',${module}.__file__))" RESULT_VARIABLE _${module}_status OUTPUT_VARIABLE _${module}_location ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - + if(_${module}_location) + # Sometimes the output of the command above is multi-lines. + # We need to keep only the last one. + string(FIND ${_${module}_location} "\n" matches REVERSE) + if(${matches} GREATER 0) + MATH(EXPR matches "${matches}+1") + string(SUBSTRING ${_${module}_location} ${matches} -1 _${module}_location) + endif() + endif() if(NOT _${module}_status) set(python_${module_upper} ${_${module}_location} CACHE STRING "Location of Python module ${module}") endif(NOT _${module}_status) - + display(_${module}_location) find_package_handle_standard_args(${module} DEFAULT_MSG _${module}_location) set(${module}_FOUND ${${module_upper}_FOUND} PARENT_SCOPE) endfunction(find_python_module) diff --git a/CMake/MyTools.cmake b/CMake/MyTools.cmake index f0c4ad54c40a01dba44c761e2fc6eca3f928638a..018c8d5ba2315f44bd8a4d25bffeb746501acbfa 100644 --- a/CMake/MyTools.cmake +++ b/CMake/MyTools.cmake @@ -1,10 +1,12 @@ include(LibFindMacros) -# Basic list manipulation +# -- Basic list manipulation -- +# Get first element of list var macro(CAR var) set(${var} ${ARGV1}) endmacro(CAR) +# get elements in list var minus the first one. macro(CDR var junk) set(${var} ${ARGN}) endmacro(CDR) @@ -16,48 +18,6 @@ macro(APPEND_FLAGS) set(${_V} "${${_V}} ${_F}") endmacro(APPEND_FLAGS) - -# Add all dirs in _DIRS into the searched directories for include files -# Set, for dir in _DIRS: -# - ${PROJECT_NAME}_INCLUDE_DIRECTORIES -# - ${PROJECT_NAME}_REMEMBER_INC_${dir} (to avoid multiple sets) -macro(REMEMBER_INCLUDE_DIRECTORIES _DIRS) - foreach(_D ${_DIRS}) - if(NOT ${PROJECT_NAME}_REMEMBER_INC_${_D}) - set(${PROJECT_NAME}_REMEMBER_INC_${_D} TRUE) - list(APPEND ${PROJECT_NAME}_INCLUDE_DIRECTORIES ${_D}) - include_directories(${_DIRS}) - endif(NOT ${PROJECT_NAME}_REMEMBER_INC_${_D}) - endforeach(_D ${_DIRS}) -endmacro(REMEMBER_INCLUDE_DIRECTORIES _DIRS) - -# Add all dirs in _DIRS into the searched directories for linked libraries -# Set, for dir in _DIRS: -# - ${PROJECT_NAME}_LINK_DIRECTORIES -# - ${PROJECT_NAME}_REMEMBER_LINK_${dir} (to avoid multiple sets) -macro(REMEMBER_LINK_DIRECTORIES _DIRS) - foreach(_D ${_DIRS}) - if(NOT ${PROJECT_NAME}_REMEMBER_LINK_${_D}) - set(${PROJECT_NAME}_REMEMBER_LINK_${_D} TRUE) - list(APPEND ${PROJECT_NAME}_LINK_DIRECTORIES ${_D}) - link_directories(${_D}) - endif(NOT ${PROJECT_NAME}_REMEMBER_LINK_${_D}) - endforeach(_D ${_DIRS}) -endmacro(REMEMBER_LINK_DIRECTORIES _DIRS) - -# Add all libraries in _LIBS into the searched directories for linked libraries -# Set, for lib in _LIBS: -# - ${PROJECT_NAME}_LINK_LIBRARIES -# - ${PROJECT_NAME}_REMEMBER_LINK_LIBRARIES_${lib} (to avoid multiple sets) -macro(REMEMBER_LINK_LIBRARIES _LIBS) - foreach(_LIB ${_LIBS}) - if(NOT ${PROJECT_NAME}_REMEMBER_LINK_LIBRARIES_${_LIB}) - set(${PROJECT_NAME}_REMEMBER_LINK_LIBRARIES_${_LIB} TRUE) - list(APPEND ${PROJECT_NAME}_LINK_LIBRARIES ${_LIB}) - endif(NOT ${PROJECT_NAME}_REMEMBER_LINK_LIBRARIES_${_LIB}) - endforeach(_LIB ${_LIBS}) -endmacro(REMEMBER_LINK_LIBRARIES _LIBS) - # The use of ADD_DEFINITION results in a warning with Fortran compiler macro(APPEND_C_FLAGS) APPEND_FLAGS(CMAKE_C_FLAGS ${ARGV}) @@ -71,48 +31,201 @@ macro(APPEND_Fortran_FLAGS) APPEND_FLAGS(CMAKE_Fortran_FLAGS ${ARGV}) endmacro(APPEND_Fortran_FLAGS) +# Scans DIRS (list of directories) and returns a list of all files in those dirs +# matching extensions defined in SRC_EXTS list. +# Results are saved in SOURCES_FILES +# +# Usage: +# set(src_dirs dir1 dir2) +# get_sources(src_dirs) +macro(get_sources) + set(SOURCES_FILES) + foreach(DIR ${ARGV}) + foreach(_EXT ${SRC_EXTS}) + file(GLOB FILES_LIST ${DIR}/*.${_EXT}) + if(FILES_LIST) + list(APPEND SOURCES_FILES ${FILES_LIST}) + endif() + endforeach() + endforeach() + if(SOURCES_FILES) + list(REMOVE_DUPLICATES SOURCES_FILES) + endif() +endmacro() + +# Scans DIRS (list of directories) and returns a list of all files in those dirs +# matching extensions defined in HDR_EXTS list. +# Results are saved in HDRS_FILES +# +# Usage: +# set(src_dirs dir1 dir2) +# get_headers(src_dirs) +macro(get_headers DIRS) + set(HDRS_FILES) + foreach(DIR ${ARGV}) + foreach(_EXT ${HDR_EXTS}) + file(GLOB FILES_LIST ${DIR}/*.${_EXT}) + if(FILES_LIST) + list(APPEND HDRS_FILES ${FILES_LIST}) + endif() + endforeach() + endforeach() + if(HDRS_FILES) + list(REMOVE_DUPLICATES HDRS_FILES) + endif() +endmacro() + + +# Return all files matching ext in directories of list dirs +function(get_files ext dirs) + set(files_list) + foreach(_dir IN LISTS ${dirs}) + file(GLOB files ${_DIR}/*.${ext}) + endforeach() + list(APPEND files_list ${files}) + if(files_list) + list(REMOVE_DUPLICATES files_list) + endif() + set(files_list ${files_list} PARENT_SCOPE) +endfunction() + +# -- returns a list of source files extension -- +# Results in var ALL_EXTS +macro(get_standard_ext) + set(ALL_EXTS) + foreach(_EXT + ${CMAKE_CXX_SOURCE_FILE_EXTENSIONS} + ${CMAKE_C_SOURCE_FILE_EXTENSIONS} + ${CMAKE_Fortran_SOURCE_FILE_EXTENSIONS} + ${CMAKE_Java_SOURCE_FILE_EXTENSIONS} + ${CMAKE_RC_SOURCE_FILE_EXTENSIONS}) + list(APPEND ALL_EXTS ${_EXT}) + endforeach() + list(REMOVE_DUPLICATES ALL_EXTS) +endmacro() + # debug macro(display V) message(STATUS "${V} = ${${V}}") endmacro(display V) -# Tests -macro(begin_test _D) - set(_CURRENT_TEST_DIRECTORY ${_D}) - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_D}) +# ======================================= +# For a given package name, try to find +# corresponding headers and libraries and +# add them to the include directories +# and list of linked libraries. +# +# It sets (if found): +# - HYSOP_INCLUDE_DIRECTORIES with the list +# of directories of headers required for hysop to work with +# - HYSOP_LINK_LIBRARIES with the list of external libraries +# (full path!) needed by hysop project. +# +# Usage : +# compile_with(Packagename options) +# +# with the same 'options' as find_package +# (see http://www.cmake.org/cmake/help/v3.0/command/find_package.html?highlight=find_package) +macro(COMPILE_WITH) + # Get package name and extra args ... + CAR(_NAME ${ARGV}) + CDR(_REST ${ARGV}) + CAR(_REQ ${_REST}) + if(_REST) + CDR(_RREST ${_REST}) + CAR(_COMP ${_RREST}) + endif(_REST) + string(TOUPPER ${_NAME} _UNAME) + list(APPEND _NAMES ${_NAME}) + list(APPEND _NAMES ${_UNAME}) + set(_FOUND) + find_package(${ARGV}) - # create a CMakeLists.txt for the current test in build_dir/test-name - # Source = file CMakeListsForTests.cmake. - configure_file(${CMAKE_SOURCE_DIR}/CMake/CMakeListsForTests.cmake - ${CMAKE_CURRENT_BINARY_DIR}/${_CURRENT_TEST_DIRECTORY}/CMakeLists.txt @ONLY) - - # init the list of test executables - set(_EXE_LIST_${_CURRENT_TEST_DIRECTORY}) -endmacro(begin_test _D) - -macro(end_test) - # add the subdir corresponding to the current test (i.e. take the new CMakeLists.txt into account) - add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/${_CURRENT_TEST_DIRECTORY} ${CMAKE_CURRENT_BINARY_DIR}/${_CURRENT_TEST_DIRECTORY}) -endmacro(end_test) - - -# Declare a new test -macro(new_test) - car(_EXE ${ARGV}) - cdr(_SOURCES ${ARGV}) - # Add the current test to the list of all executables - list(APPEND _EXE_LIST_${_CURRENT_TEST_DIRECTORY} ${_EXE}) - # Get the list of sources for the current executable - set(${_EXE}_FSOURCES) - foreach(_F ${_SOURCES}) - list(APPEND ${_EXE}_FSOURCES ${CMAKE_CURRENT_SOURCE_DIR}/${_CURRENT_TEST_DIRECTORY}/${_F}) - endforeach(_F ${_SOURCES}) -endmacro(new_test) + foreach(_N ${_NAMES}) + if(${_N}_FOUND) + set(_FOUND TRUE) + # add headers dirs into 'include' path + # INCLUDE_DIR var name depends on FindNAME + # We try to check the standard var names. + if(DEFINED ${_N}_INCLUDE_DIRS) + remember_include_directories("${${_N}_INCLUDE_DIRS}") + endif() + if(DEFINED ${_N}_INCLUDE_DIR) + remember_include_directories("${${_N}_INCLUDE_DIR}") + endif() + if(DEFINED ${_N}_INCLUDE_PATH) + remember_include_directories("${${_N}_INCLUDE_DIR}") + endif() + # Now we set list of libs that must be linked with. + if(DEFINED ${_N}_LIBRARIES) + set(HYSOP_LINK_LIBRARIES ${HYSOP_LINK_LIBRARIES} + ${${_N}_LIBRARIES}) + endif() + # And the compiler flags + if(DEFINED ${_N}_DEFINITIONS) + foreach(_DEF ${${_N}_DEFINITIONS}) + append_c_flags(${_DEF}) + append_cxx_flags(${_DEF}) + endforeach() + endif() + endif() + endforeach() + list(REMOVE_DUPLICATES HYSOP_LINK_LIBRARIES) + set(HYSOP_LINK_LIBRARIES ${HYSOP_LINK_LIBRARIES} + ${${_N}_LIBRARIES} CACHE INTERNAL "List of external libraries.") + set(_N) + set(_NAME) + set(_UNAME) + set(_NAMES) +endmacro(COMPILE_WITH) + +# ==== Save directories required for include_directory === +# +# Set variable HYSOP_INCLUDE_DIRECTORIES with the list +# of directories of headers required for hysop to work with +# its dependencies. +# Usage : +# set(dirs d1 d2 d3) +# remember_include_directories(${dirs}) +# --> save d1, d2, d3 into HYSOP_INCLUDE_DIRECTORIES +# +macro(REMEMBER_INCLUDE_DIRECTORIES _DIRS) + foreach(_D ${_DIRS}) + list(APPEND HYSOP_INCLUDE_DIRECTORIES ${_D}) + endforeach() + list(REMOVE_DUPLICATES HYSOP_INCLUDE_DIRECTORIES) + set(HYSOP_INCLUDE_DIRECTORIES ${HYSOP_INCLUDE_DIRECTORIES} + CACHE INTERNAL "Include directories for external dependencies.") + +endmacro() + +# ==== Save directories required for include_directory === +# +# Set variable ${PROJECT_NAME}_LOCAL_INCLUDE_DIRECTORIES with the list +# of directories of headers for hysop +# +# Usage : +# set(dirs d1 d2 d3) +# remember_local_include(${dirs}) +# --> save d1, d2, d3 into ${PROJECT_NAME}_LOCAL_INCLUDE_DIRECTORIES +# +# mind the ${CMAKE_CURRENT_SOURCE_DIR} below! +macro(remember_local_include_directories _DIRS) + foreach(_D ${_DIRS}) + list(APPEND ${PROJECT_NAME}_LOCAL_INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_SOURCE_DIR}/${_D}) + endforeach() + list(REMOVE_DUPLICATES ${PROJECT_NAME}_LOCAL_INCLUDE_DIRECTORIES) + set(${PROJECT_NAME}_LOCAL_INCLUDE_DIRECTORIES + ${${PROJECT_NAME}_LOCAL_INCLUDE_DIRECTORIES} + CACHE INTERNAL "Include directories for external dependencies.") +endmacro() + # Usage: list_subdirectories(the_list_is_returned_here dir 1) # 1 if you want relative directories as output. macro(list_subdirectories retval curdir return_relative) - file(GLOB_RECURSE subdir RELATIVE ${curdir} *) + file(GLOB subdir RELATIVE ${curdir} *) display(subdir) set(list_of_dirs "") foreach(dir ${subdir}) @@ -155,4 +268,20 @@ macro(get_python_builddir where result) get_filename_component(builddir ${hysopfile} PATH) get_filename_component(builddir ${builddir} PATH) set(${result} ${builddir}) -endmacro() \ No newline at end of file +endmacro() + + +# ------------------------------------ +# Get the list of subdirectories +# of a given dir +# ------------------------------------ +macro(get_subdirectories result current_dir) + file(GLOB subdirs RELATIVE ${current_dir} ${current_dir}/*) + set(dirs "") + foreach(_dir ${subdirs}) + if(IS_DIRECTORY ${current_dir}/${_dir}) + list(APPEND dirs ${_dir}) + endif() + endforeach() + set(${result} ${dirs}) +endmacro() diff --git a/HySoP/CMakeLists.txt b/HySoP/CMakeLists.txt index 0491bc9e14ff56558989704ad09f3f78e624a357..9e414eaad7706c9fcaaa589f0dd02ebe8cc41fe0 100644 --- a/HySoP/CMakeLists.txt +++ b/HySoP/CMakeLists.txt @@ -43,9 +43,17 @@ option(FULL_TEST "Enable all test options (pep8, mpi ...) - Default = OFF" OFF) option(PROFILE "Enable profiling mode for HySoP. 0:disabled, 1: enabled. Default = 0" 0) option(OPTIM "To allow python -OO run, some packages must be deactivated. Set this option to 'ON' to do so. Default = OFF" OFF) option(WITH_MPI_TESTS "Enable mpi tests. Default = ON if USE_MPI is ON." ON) +option(FORTRAN_LAYOUT "Choose default data layout ('fortran', column-major or 'C' order, row-major) for arrays. Default = column-major." ON) +option(WITH_DOCUMENTATION "Build Documentation. Default = OFF" ON) + +# Set python install mode: +# - user --> behave as 'python setup.py install --user' +# - standard --> install in python site-package (ie behave as python setup.py install) +# - prefix --> install in python CMAKE_INSTALL_PREFIX (ie behave as python setup.py install --prefix=CMAKE_INSTALL_PREFIX) +set(hysop_python_install "user" CACHE STRING "Install mode for hysop python package") if(NOT WITH_LIB_FORTRAN) - message(WARNING "You deactivate libhysop (fortran) generation. This will disable fftw and scales fonctionnalities.") + message(WARNING "You deactivate libhysop (fortran) generation. This will disable the fortran interface, including fftw and scales fonctionnalities.") set(WITH_FFTW "OFF") set(WITH_SCALES "OFF") set(WITH_MAIN_FORTRAN "OFF") @@ -56,6 +64,20 @@ if(NOT WITH_LIB_CXX) set(WITH_MAIN_CXX "OFF") endif() +# Force a default build type if not provided by user +# CMAKE_BUILD_TYPE = empty, Debug, Release, RelWithDebInfo or MinSizeRel. +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RELEASE CACHE STRING + "Choose the type of build, options are: None Debug Release." + FORCE) +endif() + + +# true if hysop used Fortran and/or c++ sources +if(${WITH_LIB_FORTRAN} OR ${WITH_LIB_CXX}) + set(WITH_COMPILED_LIB) +endif() + # We can not run scales or fftw without mpi ... if(WITH_FFTW OR WITH_SCALES OR WITH_HYSOP_PLUS_PLUS) set(USE_MPI "ON") @@ -77,27 +99,24 @@ set(PROJECT_LIBRARY_NAME ${PROJECT_NAME}) # - ${PROJECT_NAME}_BINARY_DIR : where you have run cmake, i.e. the place for compilation # - ${PROJECT_NAME}_SOURCE_DIR : where sources (.f and .h and this CMakeLists.txt) are located # Note that because of OutOfSourceBuild, binary_dir and source_dir must be different. -project(${PROJECT_NAME}) -# ============= Search for libraries ============= -# We search for libraries HySoP depends on and -# set the compile/link conf (-I and -L opt) +set(LANGLIST) +if(WITH_LIB_CXX) + set(LANGLIST ${LANGLIST} CXX) +endif() +if(WITH_LIB_FORTRAN) + set(LANGLIST ${LANGLIST} Fortran) +endif() + +project(${PROJECT_NAME} ${LANGLIST}) set(HYSOP_LIBRARY_NAME hysop) set(PACKAGE_NAME HySoP) -# --- Python --- +# ============= Python and its packages ============= # - Global setup (interp and lib) - find_package(PythonFull REQUIRED) include(FindPythonModule) -find_package(SWIG 2.0.7 REQUIRED) -# WARNING FP : for cmake < 3.0 UseSWIG.cmake -# does not work properly (bug for swig outdir) -if(CMAKE_VERSION VERSION_LESS 3.0.0) - set(SWIG_USE_FILE ${CMAKE_SOURCE_DIR}/cmake/UseSWIG.cmake) -endif() -include(${SWIG_USE_FILE}) - # - python packages - find_python_module(numpy REQUIRED) find_python_module(scipy) @@ -115,6 +134,47 @@ if(USE_MPI) find_python_module(mpi4py REQUIRED) endif() +if(WITH_LIB_CXX) + find_package(SWIG 2.0.7 REQUIRED) + # WARNING FP : for cmake < 3.0 UseSWIG.cmake + # does not work properly (bug for swig outdir) + if(CMAKE_VERSION VERSION_LESS 3.0.0) + set(SWIG_USE_FILE ${CMAKE_SOURCE_DIR}/cmake/UseSWIG.cmake) + endif() + include(${SWIG_USE_FILE}) +endif() + +# Find python build dir name --> needed for tests and doc +if(WITH_COMPILED_LIB) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.util as ut ; import distutils.sysconfig as sy; print 'lib.'+ut.get_platform()+'-'+sy.get_python_version()" + OUTPUT_VARIABLE ${PROJECT_NAME}_PYTHON_BUILD_DIR) + string(STRIP ${${PROJECT_NAME}_PYTHON_BUILD_DIR} ${PROJECT_NAME}_PYTHON_BUILD_DIR) + set(HYSOP_BUILD_PYTHONPATH ${CMAKE_BINARY_DIR}/build/${${PROJECT_NAME}_PYTHON_BUILD_DIR} CACHE INTERNAL "Python package build path") +else() + set(HYSOP_BUILD_PYTHONPATH ${CMAKE_BINARY_DIR}/build/lib CACHE INTERNAL "Python package build path") +endif() + +# ============= Other dependencies ============= + +# --- FFTW --- +if(WITH_FFTW) + compile_with(FFTW REQUIRED) + set(dirlist) + foreach(_file ${FFTW_LIBRARIES}) + if(CMAKE_PATCH_VERSION LESS 12) + get_filename_component(_name ${_file} PATH) + else() + get_filename_component(_name ${_file} DIRECTORY) + endif() + list(FIND dirlist ${_name} isin) + if(isin EQUAL -1) + list(APPEND dirlist ${_name}) + endif() + endforeach() + set(FFTWLIB ${dirlist} CACHE PATH "fftw libraries dir") +endif() + # ========= Check which opencl devices are available on the system ========= if(WITH_GPU) execute_process( @@ -141,13 +201,44 @@ display(OPENCL_DEFAULT_OPENCL_DEVICE_ID) # --> set installation dir # --> set options for python install # --> create install/uninstall targets - include(HySoPInstallSetup) # Remark : this must be done before add_subdir below, since install process in src needs CMAKE_INSTALL_PREFIX # to be properly set. -# ====== Create non-python (fortran, cxx) libraries (fftw and scales interfaces), if required ===== -if(WITH_LIB_FORTRAN OR WITH_LIB_CXX) +if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/.f2py_f2cmap) + message(STATUS "Generate f2py map file ...") + configure_file(${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/.f2py_f2cmap + ${CMAKE_BINARY_DIR}/.f2py_f2cmap) +endif() +if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/f2hysop.pyf.in) + message(STATUS "Generate f2hysop.pyf (f2py main signature file) ...") + configure_file(${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/f2hysop.pyf.in + ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/f2hysop.pyf) +endif() + +# ====== Create non-python (fortran) libraries (fftw and scales interfaces), if required ===== +if(WITH_LIB_FORTRAN) + # Set module files directory (i.e. where .mod will be created) + set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules) + # Add compilation flags: + #append_Fortran_FLAGS("-Wall -fPIC -ffree-line-length-none -DBLOCKING_SEND_PLUS -DBLOCKING_SEND") + append_Fortran_FLAGS("-Wall -fPIC -ffree-line-length-none -cpp") + + if(USE_MPI) + # Find MPI for fortran. + find_package(MPI REQUIRED) + # -I + include_directories(${MPI_Fortran_INCLUDE_PATH}) + # Add compilation/link flags + set(${HYSOP_LIBRARY_NAME}_LINK_FLAGS ${${HYSOP_LIBRARY_NAME}_LINK_FLAGS} ${MPI_Fortran_LINK_FLAGS}) + append_Fortran_flags(${MPI_Fortran_COMPILE_FLAGS}) + # Append mpi libraries to the list of libraries linked with libhysop. + set(LIBS ${LIBS} ${MPI_Fortran_LIBRARIES} ) + endif(USE_MPI) + + set(Fortran_FLAGS ${CMAKE_Fortran_FLAGS}) + append_flags(Fortran_FLAGS ${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}}) + add_subdirectory(src) endif() @@ -207,6 +298,7 @@ endif() # ============= Tests ============= if(WITH_TESTS) + include(CTest) # Number of mpi processes used to run tests. set(NBPROCS_FOR_TESTS 8) if(NOT USE_MPI) @@ -219,16 +311,19 @@ endif(WITH_TESTS) # ============= Summary ============= if(VERBOSE_MODE) message(STATUS "====================== Summary ======================") - message(STATUS " Python libs found : ${PYTHONLIBS_FOUND}") message(STATUS " Python libraries : ${PYTHON_LIBRARIES}") message(STATUS " Python include : ${PYTHON_INCLUDE_DIRS}") message(STATUS " Python version : ${PYTHON_VERSION_STRING}") message(STATUS " Python executable : ${PYTHON_EXECUTABLE}") message(STATUS " Python user lib : ${PYTHON_LIBRARY}") - message(STATUS " Python user include : ${PYTHON_INCLUDE_DIR}") - message(STATUS " Install directory : ${CMAKE_INSTALL_PREFIX}") - message(STATUS " Fortran compiler : ${CMAKE_Fortran_COMPILER}") - message(STATUS " C++ compiler : ${CMAKE_CXX_COMPILER}") + message(STATUS " ${PACKAGE_NAME} will be installed in : ${HYSOP_PYTHON_INSTALL_DIR}") + message(STATUS " ${PACKAGE_NAME} will be built in ${HYSOP_BUILD_PYTHONPATH}") + if(WITH_LIB_FORTRAN) + message(STATUS " Fortran compiler : ${CMAKE_Fortran_COMPILER}") + endif() + if(WITH_LIB_CXX) + message(STATUS " CXX compiler : ${CMAKE_CXX_COMPILER}") + endif() message(STATUS " Sources are in : ${CMAKE_SOURCE_DIR}") message(STATUS " Project uses MPI : ${USE_MPI}") message(STATUS " Project uses Scales : ${WITH_SCALES}") @@ -246,7 +341,7 @@ if(VERBOSE_MODE) message(STATUS " 'make clean' to clean build directory.") message(STATUS " 'make uninstall' to clean install directory. Dry-run (make -n uninstall) is advisable to check what will really be deleted.") message(STATUS "\n\n/!\\ Warning /!\\ : depending on your python environment configuration, you may need to set PYTHONPATH.") - message("Try to run python -c 'import hysop'. If it fails, add ${${PROJECT_NAME}_PYTHONPATH} to PYTHONPATH environment variable.") - message("Example : \n export PYTHONPATH=${${PROJECT_NAME}_PYTHONPATH}:\${PYTHONPATH}\n") + message("Try to run python -c 'import hysop'. If it fails, add ${HYSOP_PYTHON_INSTALL_DIR} to PYTHONPATH environment variable.") + message("Example : \n export PYTHONPATH=${HYSOP_PYTHON_INSTALL_DIR}:\${PYTHONPATH}\n") endif() diff --git a/HySoP/hysop/.f2py_f2cmap b/HySoP/hysop/.f2py_f2cmap new file mode 100644 index 0000000000000000000000000000000000000000..99f5f3517caf6260a22a9851a15f66443a1045d4 --- /dev/null +++ b/HySoP/hysop/.f2py_f2cmap @@ -0,0 +1,3 @@ +{'integer':{'c_int':'int'}, 'real':{'real64':'double', 'wp':'double'}} + + diff --git a/HySoP/hysop/domain/tests/test_box.py b/HySoP/hysop/domain/tests/test_box.py index ca231e8ceec97c9634942eda24e8d32ad2fed1e3..f23e357d3558f4ffb5e6abce6164fe5ef25b3dde 100644 --- a/HySoP/hysop/domain/tests/test_box.py +++ b/HySoP/hysop/domain/tests/test_box.py @@ -124,7 +124,7 @@ def test_topo_plane(): def test_topo_from_mesh(): # e.g. for fftw dom = Box(proc_tasks=proc_tasks) - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py if dom.is_on_task(CPU): localres, global_start = fftw2py.init_fftw_solver( r3D.resolution, dom.length, comm=comm_s.py2f()) diff --git a/HySoP/hysop/f2hysop.pyf.in b/HySoP/hysop/f2hysop.pyf.in new file mode 100644 index 0000000000000000000000000000000000000000..16fc16b58562b4e0ad0c89503c837ca78e130baf --- /dev/null +++ b/HySoP/hysop/f2hysop.pyf.in @@ -0,0 +1,16 @@ + ! -*- f90 -*- + ! Note: the context of this file is case sensitive. + + python module f2hysop ! in + interface + ! Example + include '@CMAKE_SOURCE_DIR@/hysop/fortran/template.pyf' + ! precision + include '@CMAKE_SOURCE_DIR@/hysop/f2py/parameters.pyf' + ! fftw + include '@CMAKE_SOURCE_DIR@/hysop/f2py/fftw2py.pyf' + ! scales + include '@CMAKE_SOURCE_DIR@/hysop/f2py/scales2py.pyf' + + end interface +end python module f2hysop diff --git a/HySoP/hysop/f2py/fftw2py.pyf b/HySoP/hysop/f2py/fftw2py.pyf new file mode 100644 index 0000000000000000000000000000000000000000..3153e51b9c80f7ba98960bebb9378050867e2e50 --- /dev/null +++ b/HySoP/hysop/f2py/fftw2py.pyf @@ -0,0 +1,130 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +module fftw2py ! in fftw2py.f90 + use fft3d + use mpi + use client_data + use hysopparam + use fft2d + subroutine init_fftw_solver(resolution,lengths,comm,datashape,offset,dim,fftw_type_real) ! in fftw2py.f90:fftw2py + integer dimension(dim),intent(in) :: resolution + real(kind=pk) dimension(dim),intent(in),depend(dim) :: lengths + integer intent(in) :: comm + integer(kind=ik) dimension(dim),intent(out),depend(dim) :: datashape + integer(kind=ik) dimension(dim),intent(out),depend(dim) :: offset + integer, optional,intent(hide),check(len(resolution)>=dim),depend(resolution) :: dim=len(resolution) + logical, optional,intent(in) :: fftw_type_real=1 + end subroutine init_fftw_solver + subroutine init_fftw_solver_scalar(resolution,lengths,comm,datashape,offset,dim,fftw_type_real) ! in fftw2py.f90:fftw2py + integer dimension(dim),intent(in) :: resolution + real(kind=pk) dimension(dim),intent(in),depend(dim) :: lengths + integer intent(in) :: comm + integer(kind=ik) dimension(dim),intent(out),depend(dim) :: datashape + integer(kind=ik) dimension(dim),intent(out),depend(dim) :: offset + integer, optional,intent(hide),check(len(resolution)>=dim),depend(resolution) :: dim=len(resolution) + logical, optional,intent(in) :: fftw_type_real=1 + end subroutine init_fftw_solver_scalar + subroutine clean_fftw_solver(dim) ! in fftw2py.f90:fftw2py + integer intent(in) :: dim + end subroutine clean_fftw_solver + subroutine solve_poisson_2d(omega,velocity_x,velocity_y,ghosts_vort,ghosts_velo) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:),intent(in) :: omega + real(kind=pk) dimension(size(omega,1),size(omega,2)),intent(in,out),depend(omega,omega) :: velocity_x + real(kind=pk) dimension(size(omega,1),size(omega,2)),intent(in,out),depend(omega,omega) :: velocity_y + integer dimension(2),intent(in) :: ghosts_vort + integer dimension(2),intent(in) :: ghosts_velo + end subroutine solve_poisson_2d + subroutine solve_diffusion_2d(nudt,omega,ghosts_vort) ! in fftw2py.f90:fftw2py + real(kind=pk) intent(in) :: nudt + real(kind=pk) dimension(:,:),intent(in,out) :: omega + integer dimension(2),intent(in) :: ghosts_vort + end subroutine solve_diffusion_2d + subroutine solve_poisson_3d(omega_x,omega_y,omega_z,velocity_x,velocity_y,velocity_z,ghosts_vort,ghosts_velo) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:,:),intent(in) :: omega_x + real(kind=pk) dimension(:,:,:),intent(in) :: omega_y + real(kind=pk) dimension(:,:,:),intent(in) :: omega_z + real(kind=pk) dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(in,out),depend(omega_x,omega_y,omega_z) :: velocity_x + real(kind=pk) dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(in,out),depend(omega_x,omega_y,omega_z) :: velocity_y + real(kind=pk) dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(in,out),depend(omega_x,omega_y,omega_z) :: velocity_z + integer dimension(3),intent(in) :: ghosts_vort + integer dimension(3),intent(in) :: ghosts_velo + end subroutine solve_poisson_3d + subroutine solve_poisson_2d_c(omega,velocity_x,velocity_y) ! in fftw2py.f90:fftw2py + complex(kind=pk) dimension(:,:),intent(in) :: omega + complex(kind=pk) dimension(size(omega,1),size(omega,2)),intent(in,out),depend(omega,omega) :: velocity_x + complex(kind=pk) dimension(size(omega,1),size(omega,2)),intent(in,out),depend(omega,omega) :: velocity_y + end subroutine solve_poisson_2d_c + subroutine solve_poisson_3d_c(omega_x,omega_y,omega_z,velocity_x,velocity_y,velocity_z) ! in fftw2py.f90:fftw2py + complex(kind=pk) dimension(:,:,:),intent(in) :: omega_x + complex(kind=pk) dimension(:,:,:),intent(in) :: omega_y + complex(kind=pk) dimension(:,:,:),intent(in) :: omega_z + complex(kind=pk) dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(in,out),depend(omega_x,omega_y,omega_z) :: velocity_x + complex(kind=pk) dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(in,out),depend(omega_x,omega_y,omega_z) :: velocity_y + complex(kind=pk) dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(in,out),depend(omega_x,omega_y,omega_z) :: velocity_z + end subroutine solve_poisson_3d_c + subroutine solve_curl_diffusion_3d(nudt,velocity_x,velocity_y,velocity_z,omega_x,omega_y,omega_z,ghosts_velo,ghosts_vort) ! in fftw2py.f90:fftw2py + real(kind=pk) intent(in) :: nudt + real(kind=pk) dimension(:,:,:),intent(in) :: velocity_x + real(kind=pk) dimension(:,:,:),intent(in) :: velocity_y + real(kind=pk) dimension(:,:,:),intent(in) :: velocity_z + real(kind=pk) dimension(size(velocity_x,1),size(velocity_y,2),size(velocity_z,3)),intent(in,out),depend(velocity_x,velocity_y,velocity_z) :: omega_x + real(kind=pk) dimension(size(velocity_x,1),size(velocity_y,2),size(velocity_z,3)),intent(in,out),depend(velocity_x,velocity_y,velocity_z) :: omega_y + real(kind=pk) dimension(size(velocity_x,1),size(velocity_y,2),size(velocity_z,3)),intent(in,out),depend(velocity_x,velocity_y,velocity_z) :: omega_z + integer dimension(3),intent(in) :: ghosts_velo + integer dimension(3),intent(in) :: ghosts_vort + end subroutine solve_curl_diffusion_3d + subroutine solve_diffusion_3d(nudt,omega_x,omega_y,omega_z,ghosts) ! in fftw2py.f90:fftw2py + real(kind=pk) intent(in) :: nudt + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_x + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_y + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_z + integer dimension(3),intent(in) :: ghosts + end subroutine solve_diffusion_3d + subroutine projection_om_3d(omega_x,omega_y,omega_z,ghosts) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_x + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_y + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_z + integer dimension(3),intent(in) :: ghosts + end subroutine projection_om_3d + subroutine multires_om_3d(dxf,dyf,dzf,omega_x,omega_y,omega_z,ghosts) ! in fftw2py.f90:fftw2py + real(kind=pk) intent(in) :: dxf + real(kind=pk) intent(in) :: dyf + real(kind=pk) intent(in) :: dzf + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_x + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_y + real(kind=pk) dimension(:,:,:),intent(in,out) :: omega_z + integer dimension(3),intent(in) :: ghosts + end subroutine multires_om_3d + subroutine pressure_3d(pressure,ghosts) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:,:),intent(in,out) :: pressure + integer dimension(3),intent(in) :: ghosts + end subroutine pressure_3d + subroutine solve_curl_3d(velocity_x,velocity_y,velocity_z,omega_x,omega_y,omega_z,ghosts_velo,ghosts_vort) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:,:),intent(in) :: velocity_x + real(kind=pk) dimension(:,:,:),intent(in) :: velocity_y + real(kind=pk) dimension(:,:,:),intent(in) :: velocity_z + real(kind=pk) dimension(size(velocity_x,1),size(velocity_y,2),size(velocity_z,3)),intent(in,out),depend(velocity_x,velocity_y,velocity_z) :: omega_x + real(kind=pk) dimension(size(velocity_x,1),size(velocity_y,2),size(velocity_z,3)),intent(in,out),depend(velocity_x,velocity_y,velocity_z) :: omega_y + real(kind=pk) dimension(size(velocity_x,1),size(velocity_y,2),size(velocity_z,3)),intent(in,out),depend(velocity_x,velocity_y,velocity_z) :: omega_z + integer dimension(3),intent(in) :: ghosts_velo + integer dimension(3),intent(in) :: ghosts_vort + end subroutine solve_curl_3d + subroutine solve_curl_2d(velocity_x,velocity_y,omega_z,ghosts_velo,ghosts_vort) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:),intent(in) :: velocity_x + real(kind=pk) dimension(:,:),intent(in) :: velocity_y + real(kind=pk) dimension(size(velocity_x,1),size(velocity_x,2)),intent(in,out),depend(velocity_x,velocity_x) :: omega_z + integer dimension(2),intent(in) :: ghosts_velo + integer dimension(2),intent(in) :: ghosts_vort + end subroutine solve_curl_2d + subroutine spectrum_3d(field,spectrum,wavelengths,ghosts,length) ! in fftw2py.f90:fftw2py + real(kind=pk) dimension(:,:,:),intent(in) :: field + real(kind=pk) dimension(:),intent(inout) :: spectrum + real(kind=pk) dimension(:),intent(inout) :: wavelengths + integer dimension(3),intent(in) :: ghosts + real(kind=pk) intent(in) :: length + end subroutine spectrum_3d +end module fftw2py + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/HySoP/hysop/f2py/parameters.pyf b/HySoP/hysop/f2py/parameters.pyf new file mode 100644 index 0000000000000000000000000000000000000000..caefb2e4fd8de7978f125e0bd76d227072b60866 --- /dev/null +++ b/HySoP/hysop/f2py/parameters.pyf @@ -0,0 +1,14 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +module hysopparam ! in parameters.f90 + integer, parameter,optional :: pk=8 + integer, parameter,optional :: ik=8 +end module hysopparam +module hysopparam_sp ! in parameters.f90 + integer, parameter,optional :: pk=4 + integer, parameter,optional :: ik=8 +end module hysopparam_sp + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/HySoP/hysop/f2py/scales2py.pyf b/HySoP/hysop/f2py/scales2py.pyf new file mode 100644 index 0000000000000000000000000000000000000000..584336cfac437a80667dccfa9dcc3cf15bcf2e87 --- /dev/null +++ b/HySoP/hysop/f2py/scales2py.pyf @@ -0,0 +1,63 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +module scales2py ! in scales2py.f90 + use advec, only: advec_step_inter_two,advec_step_inter_basic,advec_step,advec_init + use interpolation_velo, only: interpol_init + use cart_topology, only: cart_rank,coord,n_proc,discretisation_set_mesh_velo,cart_create,set_group_size,discretisation_create + use advec_vect, only: advec_step_vect,advec_step_inter_basic_vect + use mpi + use hysopparam + subroutine init_advection_solver(ncells,lengths,topodims,main_comm,datashape,offset,dim,order,dim_split) ! in scales2py.f90:scales2py + integer dimension(dim),intent(in) :: ncells + real(kind=pk) dimension(dim),intent(in),depend(dim) :: lengths + integer dimension(dim),intent(in),depend(dim) :: topodims + integer intent(in) :: main_comm + integer(kind=ik) dimension(dim),intent(out),depend(dim) :: datashape + integer(kind=ik) dimension(dim),intent(out),depend(dim) :: offset + integer, optional,intent(hide),depend(ncells) :: dim=len(ncells) + character*(*), optional,intent(in) :: order='p_o2' + character*(*), optional,intent(in) :: dim_split + end subroutine init_advection_solver + subroutine init_multiscale(nx,ny,nz,formula) ! in scales2py.f90:scales2py + integer intent(in) :: nx + integer intent(in) :: ny + integer intent(in) :: nz + character*(*), optional,intent(in) :: formula + end subroutine init_multiscale + subroutine solve_advection(dt,vx,vy,vz,scal) ! in scales2py.f90:scales2py + real(kind=pk) intent(in) :: dt + real(kind=pk) dimension(:,:,:),intent(in) :: vx + real(kind=pk) dimension(:,:,:),intent(in) :: vy + real(kind=pk) dimension(:,:,:),intent(in) :: vz + real(kind=pk) dimension(size(vx,1),size(vx,2),size(vx,3)),intent(in,out),depend(size(vx,1)) :: scal + end subroutine solve_advection + subroutine solve_advection_vect(dt,vx,vy,vz,cx,cy,cz) ! in scales2py.f90:scales2py + real(kind=pk) intent(in) :: dt + real(kind=pk) dimension(:,:,:),intent(in) :: vx + real(kind=pk) dimension(:,:,:),intent(in) :: vy + real(kind=pk) dimension(:,:,:),intent(in) :: vz + real(kind=pk) dimension(size(vx,1),size(vx,2),size(vx,3)),intent(in,out),depend(size(vx,1)) :: cx + real(kind=pk) dimension(size(vx,1),size(vx,2),size(vx,3)),intent(in,out),depend(size(vx,1)) :: cy + real(kind=pk) dimension(size(vx,1),size(vx,2),size(vx,3)),intent(in,out),depend(size(vx,1)) :: cz + end subroutine solve_advection_vect + subroutine solve_advection_inter_basic(dt,vx,vy,vz,scal) ! in scales2py.f90:scales2py + real(kind=pk) intent(in) :: dt + real(kind=pk) dimension(:,:,:),intent(in) :: vx + real(kind=pk) dimension(:,:,:),intent(in) :: vy + real(kind=pk) dimension(:,:,:),intent(in) :: vz + real(kind=pk) dimension(:,:,:),intent(in,out) :: scal + end subroutine solve_advection_inter_basic + subroutine solve_advection_inter_basic_vec(dt,vx,vy,vz,cx,cy,cz) ! in scales2py.f90:scales2py + real(kind=pk) intent(in) :: dt + real(kind=pk) dimension(:,:,:),intent(in) :: vx + real(kind=pk) dimension(:,:,:),intent(in) :: vy + real(kind=pk) dimension(:,:,:),intent(in) :: vz + real(kind=pk) dimension(:,:,:),intent(in,out) :: cx + real(kind=pk) dimension(:,:,:),intent(in,out) :: cy + real(kind=pk) dimension(:,:,:),intent(in,out) :: cz + end subroutine solve_advection_inter_basic_vec +end module scales2py + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/HySoP/hysop/fakef2py/__init__.py b/HySoP/hysop/fakef2py/__init__.py index 58da6ae35dd3554bf354e34a5f0878ee4a7c427c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/HySoP/hysop/fakef2py/__init__.py +++ b/HySoP/hysop/fakef2py/__init__.py @@ -1,24 +0,0 @@ -## @package hysop.f2py -# f2py interfaces to fortran files. -# -# Driver routines to generate python functions -# from fortran routines using f2py. -# -# Available interfaces : -# - fftw : driver for fftw-mpi (fortran) routines. -# Poisson and Diffusion solvers. -# - scales : advection solver (only 3D). -# -# Usage : -# \code -# import hysop.f2py -# ppfft = hysop.f2py.fftw2py -# scales = hysop.f2py.scales2py -# ... -# ppfft.init_fftw_solver(...) -# scales.init_advection_solver(...) -# # List of functionnalities and help : -# dir(scales) -# dir(ppfft) -# print ppfft.init_fftw_solver.__doc__ -# \endcode diff --git a/HySoP/hysop/fortran/template.f95 b/HySoP/hysop/fortran/template.f95 new file mode 100644 index 0000000000000000000000000000000000000000..77685fb293e3c9d23968b5f00494b6a35bde7c2b --- /dev/null +++ b/HySoP/hysop/fortran/template.f95 @@ -0,0 +1,27 @@ + !! Template file - Provide an example + !! to write f2py interface between fortran and python + + +module template_f2py + + implicit none + + !> a global var + integer, parameter :: var1 = 12 + +contains + + !> do something ... + subroutine check_f2py(input, output) + + !> input array + real(kind=8), dimension(:,:), intent(in) :: input + !> output array + real(kind=8), dimension(:,:), intent(inout) :: output + + print *, 'template f2py for tab' + output(:,:) = 2 * input(:,:) + print *, 'aha hah', output(1,1) + end subroutine check_f2py + +end module template_f2py diff --git a/HySoP/hysop/fortran/template.pyf b/HySoP/hysop/fortran/template.pyf new file mode 100644 index 0000000000000000000000000000000000000000..1564dabe01205ce1ca54ef2de8c54484b2eb47fc --- /dev/null +++ b/HySoP/hysop/fortran/template.pyf @@ -0,0 +1,13 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +module template_f2py ! in template.f95 + integer, parameter,optional :: var1=12 + subroutine check_f2py(input,output) ! in template.f95:template_f2py + real(kind=8), dimension(:, :), intent(in) :: input + real(kind=8), dimension(size(input,1), size(input,2)), intent(in,out), depend(input,input) :: output + end subroutine check_f2py +end module template_f2py + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/HySoP/hysop/operator/advection.py b/HySoP/hysop/operator/advection.py index 130785a895cdd956f1bdb8fa9dc182de2f89a1f0..fd5abc420271d1b99a0bfd825aea36bb23196683 100644 --- a/HySoP/hysop/operator/advection.py +++ b/HySoP/hysop/operator/advection.py @@ -215,7 +215,7 @@ class Advection(Computational): # Check if topos need to be created build_topos = self._check_variables() - from hysop.f2py import scales2py as scales + from hysop.f2hysop import scales2py as scales # Scales, single resolution if self._single_topo: @@ -281,7 +281,7 @@ class Advection(Computational): self._discretize_vars() def _create_scales_topo(self, d3d, order, splitting): - from hysop.f2py import scales2py as scales + from hysop.f2hysop import scales2py as scales comm = self._mpis.comm topodims = [1, 1, comm.Get_size()] msg = 'Wrong type for parameter discretization (at init).' + str(self._discretization) @@ -300,7 +300,7 @@ class Advection(Computational): discretization=d3d, cdir=ZDIR) def _check_scales_topo(self, toporef, order, splitting): - from hysop.f2py import scales2py as scales + from hysop.f2hysop import scales2py as scales # In that case, self._discretization must be # a Cartesian object, used for all fields. # We use it to initialize scales solver diff --git a/HySoP/hysop/operator/computational.py b/HySoP/hysop/operator/computational.py index d5992a9add91cced0f67c2765411c6d263dfa6fd..31ecca3eb47ea209d05235adb12966703427b9c9 100644 --- a/HySoP/hysop/operator/computational.py +++ b/HySoP/hysop/operator/computational.py @@ -246,7 +246,7 @@ class Computational(Operator): assert self._single_topo, 'All fields must use the same topology.' # Get local mesh parameters from fftw comm = self._mpis.comm - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py if build_topos: # In that case, self._discretization must be # a Discretization object, used for all fields. diff --git a/HySoP/hysop/operator/curlAndDiffusion.py b/HySoP/hysop/operator/curlAndDiffusion.py index e8958501cad35ec1cbcf02ddee1b48ba54c83712..b171bd647382fd83b57f56e79cbc81d69e9b9c69 100644 --- a/HySoP/hysop/operator/curlAndDiffusion.py +++ b/HySoP/hysop/operator/curlAndDiffusion.py @@ -7,7 +7,7 @@ Operator for diffusion problem. """ from hysop.operator.continuous import Operator try: - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py except ImportError: from hysop.fakef2py import fftw2py from hysop.operator.discrete.diffusion_fft import DiffusionFFT diff --git a/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py b/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py index 73c6500618f4b9506f1db2121fa8435fbbd4f453..d8828c7fd1e5c6769737938358f7c09c5a3352f4 100644 --- a/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py +++ b/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py @@ -4,7 +4,7 @@ Discrete Diffusion operator using FFTW (fortran) """ try: - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py except ImportError: from hysop.fakef2py import fftw2py from hysop.operator.discrete.discrete import DiscreteOperator diff --git a/HySoP/hysop/operator/discrete/differential.py b/HySoP/hysop/operator/discrete/differential.py index abd6e7ded1e3cbbc574e600002e632d6ebbe8cf2..6c9360a518c7a5b9ec798d7bc782259d535a6baa 100644 --- a/HySoP/hysop/operator/discrete/differential.py +++ b/HySoP/hysop/operator/discrete/differential.py @@ -18,7 +18,7 @@ from abc import ABCMeta, abstractmethod from hysop.numerics.update_ghosts import UpdateGhosts from hysop.methods_keys import SpaceDiscretisation try: - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py except ImportError: from hysop.fakef2py import fftw2py import hysop.default_methods as default diff --git a/HySoP/hysop/operator/discrete/diffusion_fft.py b/HySoP/hysop/operator/discrete/diffusion_fft.py index fe7a3822b86b986deebf6684fe2019bef2cc6004..21401ea3aca6de152d10d11fde0d72a2f5816af5 100644 --- a/HySoP/hysop/operator/discrete/diffusion_fft.py +++ b/HySoP/hysop/operator/discrete/diffusion_fft.py @@ -4,7 +4,7 @@ Discrete Diffusion operator using FFTW (fortran) """ try: - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py except ImportError: from hysop.fakef2py import fftw2py from hysop.operator.discrete.discrete import DiscreteOperator diff --git a/HySoP/hysop/operator/discrete/poisson_fft.py b/HySoP/hysop/operator/discrete/poisson_fft.py index 379b63244976337c3c76b4452cca134101e0e048..7aeb18b223097e80bdf64c13f300a5b023a3e553 100644 --- a/HySoP/hysop/operator/discrete/poisson_fft.py +++ b/HySoP/hysop/operator/discrete/poisson_fft.py @@ -5,7 +5,7 @@ Discrete operator for Poisson problem (fftw based) """ import hysop.tools.numpywrappers as npw try: - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py except ImportError: from hysop.fakef2py import fftw2py diff --git a/HySoP/hysop/operator/discrete/reprojection.py b/HySoP/hysop/operator/discrete/reprojection.py index 57ce89f6afde6c0034a800e05dd784562402c945..76a1ba3e4796e00adc926606b8f8aaa9a1073e21 100644 --- a/HySoP/hysop/operator/discrete/reprojection.py +++ b/HySoP/hysop/operator/discrete/reprojection.py @@ -104,7 +104,7 @@ class Reprojection(DiscreteOperator): # computation of the reprojection criterion and mpi-reduction criterion = d1 / d2 criterion = self.vorticity.topology.comm.allreduce( - criterion, HYSOP_MPI_REAL, op=MPI.MAX) + criterion, op=MPI.MAX) # is reprojection of vorticity needed for the next time step ? if criterion > self.threshold: self.frequency = 1 diff --git a/HySoP/hysop/operator/discrete/scales_advection.py b/HySoP/hysop/operator/discrete/scales_advection.py index 8c035f677fa68d7c083be4930a18a1996449cd32..04b47c09de4ac93930d3778ded4f74a2397822e8 100644 --- a/HySoP/hysop/operator/discrete/scales_advection.py +++ b/HySoP/hysop/operator/discrete/scales_advection.py @@ -5,7 +5,7 @@ Discrete Advection operator based on scales library (Jean-Baptiste) """ try: - from hysop.f2py import scales2py + from hysop.f2hysop import scales2py except ImportError: from hysop.fakef2py import scales2py from hysop.operator.discrete.discrete import DiscreteOperator diff --git a/HySoP/hysop/operator/discrete/spectrum.py b/HySoP/hysop/operator/discrete/spectrum.py index 72502d24b0947355138e15a1df68004a1046a45d..9b1bdb0560fd808a3db431f61a9db97b28124118 100644 --- a/HySoP/hysop/operator/discrete/spectrum.py +++ b/HySoP/hysop/operator/discrete/spectrum.py @@ -4,7 +4,7 @@ Discrete Spectrum operator using FFTW (fortran) """ try: - from hysop.f2py import fftw2py + from hysop.f2hysop import fftw2py except ImportError: from hysop.fakef2py import fftw2py from hysop.operator.discrete.discrete import DiscreteOperator diff --git a/HySoP/setup.py.in b/HySoP/setup.py.in index 6c8cd130ba9342a2d1802ddbe59140e6adafa6fc..6a08d5f70a8d4bcecd0843ab07abacadadcfb94f 100644 --- a/HySoP/setup.py.in +++ b/HySoP/setup.py.in @@ -9,6 +9,52 @@ from numpy.distutils.misc_util import Configuration import os import glob +# tools to deal with fortran dependencies. +import sys +sys.path.append('@CMAKE_SOURCE_DIR@/') +import sort_f90 + + +def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None, + libdir=None, libs=None, debug_mode=0): + """Create a new f2py module from fortran files + """ + if sources is None: + sources = [] + assert src_dirs is not None + + for sdir in src_dirs: + sources += glob.glob(os.path.join(sdir, '*.f95')) + sources += glob.glob(os.path.join(sdir, '*.f90')) + f2py_options = ['--no-lower', '--no-wrap-functions'] + options = [] + # Reorder source list with fortran modules + # dependencies. It seems that this is not taken into + # account in f2py or distutils. + if pyf_file is not None: + sources.append(pyf_file) + sources = sort_f90.sort(sources) + if debug_mode == 0: + options.append(('F2PY_REPORT_ON_ARRAY_COPY', '1')) + if os.uname()[0] == 'Linux': + options.append(('F2PY_REPORT_ATEXIT', '1')) + inc_dir = '@MPI_Fortran_INCLUDE_PATH@'.split(';') + # To avoid -I -I in compiler call, which results in a bug: + while inc_dir.count('') > 0: + inc_dir.remove('') + inc_dir.append('@CMAKE_BINARY_DIR@/Modules') + fortran_flags = ['@Fortran_FLAGS@'] + ext_fort = Extension(name=name, + sources=sources, + f2py_options=f2py_options, + include_dirs=inc_dir, + define_macros=options, + library_dirs=libdir, + libraries=libs, + extra_f90_compile_args=fortran_flags + ) + return ext_fort + def create_swig_extension(name, src_dirs=None, sources=None): """Create a python module from C++ files, using swig @@ -44,6 +90,7 @@ def create_swig_extension(name, src_dirs=None, sources=None): return swig_ext +# ------------ Set list of packages required to build the module ------------- # Full package name name = '@PYPACKAGE_NAME@' # List of modules (directories) to be included @@ -81,30 +128,26 @@ if "@WITH_TESTS@" is "ON": # Enable this to get debug info DISTUTILS_DEBUG = 1 +# ------------ Extensions (f2py, cython, ...) setup ------------ + ext_modules = [] -# Check if libhysop was created +# Check if fortran interface is enabled enable_fortran = "@WITH_LIB_FORTRAN@" - +ext = {} if enable_fortran is "ON": - inc_dir = '@MPI_Fortran_INCLUDE_PATH@'.split(';') - # To avoid -I -I in compiler call. Result in a bug: - while inc_dir.count('') > 0: - inc_dir.remove('') - - hysop_dir = '@CMAKE_BINARY_DIR@/Modules' - inc_dir.append(hysop_dir) - fortran_dir = \ - '@CMAKE_SOURCE_DIR@/hysop/f2py/' + fortran_root = \ + '@CMAKE_SOURCE_DIR@/hysop' hysop_libdir = ['@CMAKE_BINARY_DIR@/src'] hysoplib = ['@HYSOP_LIBRARY_NAME@'] f2py_options = ['--no-lower'] - fortran_src = [] + fortran_src = set([]) + # -- fftw fortran sources -- withfftw = "@WITH_FFTW@" if withfftw is "ON": - fortran_src.append(fortran_dir + 'parameters.f90') - fortran_src.append(fortran_dir + 'fftw2py.f90') + fortran_src.add('f2py/parameters.f90') + fortran_src.add('f2py/fftw2py.f90') fftwdir = '@FFTWLIB@' hysoplib.append('fftw3') hysoplib.append('fftw3_mpi') @@ -112,28 +155,45 @@ if enable_fortran is "ON": else: packages.append('hysop.fakef2py') packages.append('hysop.fakef2py.fftw2py') + # -- scales sources -- withscales = '@WITH_SCALES@' if withscales is "ON": - if withfftw is "OFF": - fortran_src.append(fortran_dir + 'parameters.f90') - fortran_src.append(fortran_dir + 'scales2py.f90') + fortran_src.add('f2py/parameters.f90') + fortran_src.add('f2py/scales2py.f90') else: packages.append('hysop.fakef2py') packages.append('hysop.fakef2py.scales2py') + # -- set full path to fortran sources -- + fortran_src = list(fortran_src) + for i in xrange(len(fortran_src)): + fortran_src[i] = os.path.join(fortran_root, fortran_src[i]) + + # === Draft for future implementation of fortran interface === + # -- f2py signature file -- + pyf_file = os.path.join(fortran_root, 'f2hysop.pyf') + # -- list of directories which contains fortran sources -- + # those dirs must be in hysop package directory + subdirs = ['fortran', + ] + num_dirs = [] + for sd in subdirs: + num_dirs.append(os.path.join(fortran_root, sd)) + + # create python interface to fortran sources + # For the moment, it includes the 'old' interface + # to scales and fftw (in sources) and the new + # interface, in src_dirs + ext['f2hysop'] = create_fortran_extension( + name='hysop.f2hysop', + sources=fortran_src, + libdir=hysop_libdir, + libs=hysoplib, + pyf_file=pyf_file, + src_dirs=num_dirs) + + for ex in ext: + ext_modules.append(ext[ex]) - options = [('F2PY_REPORT_ON_ARRAY_COPY', '1')] - if os.uname()[0] == 'Linux': - options.append(('F2PY_REPORT_ATEXIT', '1')) - - parpyModule = Extension(name='hysop.f2py', - f2py_options=f2py_options, - sources=fortran_src, - include_dirs=inc_dir, - library_dirs=hysop_libdir, - libraries=hysoplib, - define_macros=options - ) - ext_modules.append(parpyModule) else: packages.append('hysop.fakef2py') packages.append('hysop.fakef2py.scales2py') @@ -142,18 +202,21 @@ else: data_files = [] # --- C++ files and swig interface -- -# path to .i files -swig_dirs = [os.path.join('@CMAKE_SOURCE_DIR@','swig')] - -# C++ files and swig interface -cpp_src_dirs = ['src/fftw','src/hysop++'] -for sd in cpp_src_dirs: - swig_dirs.append(os.path.join('@CMAKE_SOURCE_DIR@', sd)) -ext = {} -ext['cpp2hysop'] = create_swig_extension( - name='cpp2hysop', src_dirs=swig_dirs) -for ex in ext: - ext_modules.append(ext[ex]) +enable_cpp = "@WITH_LIB_CPP@" + +if enable_cpp: + # path to .i files + swig_dirs = [os.path.join('@CMAKE_SOURCE_DIR@','swig')] + + # C++ files and swig interface + cpp_src_dirs = ['src/fftw','src/hysop++'] + for sd in cpp_src_dirs: + swig_dirs.append(os.path.join('@CMAKE_SOURCE_DIR@', sd)) + ext = {} + ext['cpp2hysop'] = create_swig_extension( + name='cpp2hysop', src_dirs=swig_dirs) + for ex in ext: + ext_modules.append(ext[ex]) if "@WITH_GPU@" is "ON": diff --git a/HySoP/sort_f90.py b/HySoP/sort_f90.py new file mode 100644 index 0000000000000000000000000000000000000000..fb1f6a93cdb947c1fc9361561c05f842ab9bcc21 --- /dev/null +++ b/HySoP/sort_f90.py @@ -0,0 +1,326 @@ +""" +Dependency scanner for F90/95 modules. + +The sort function provided below sorts fortran source files in order of +increasing dependency. That is, the sorting order makes sure that modules are +compiled before they are USE'd. + +See: + http://scipy.org/scipy/numpy/ticket/752 + +The regular expressions are modified versions from the SCons.Scanner.Fortran +module. The copyright notice for Scons is included below. + +:Author: David Huard, Pearu Peterson +:Date: May, 2008 +""" + +""" +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +import re, copy, os +import warnings + +__all__ = ['FortranFileSorter', 'sort'] + +""" +Regular expression for a module name +------------------------------------ + +An alphanumeric word not beginning with a numeric character. + + [a-z_] : a letter or an underscore + \w* : any number of alphanumeric characters +""" +modulename = """[a-z_]\w*""" + + + +""" +Regular expression for a USE statement +-------------------------------------- + +Matches the following statements: + +USE module_name +USE :: module_name +USE, INTRINSIC :: module_name +USE, NON_INTRINSIC :: module_name +USE module_name, only :: [list of procedures] + + +Here is a breakdown of the regex: + + (?i) : regex is case insensitive + (?: : group a collection of regex symbols without saving the match as a "group" + ^|; : matches either the start of the line or a semicolon - semicolon + ) : end the unsaved grouping + \s* : any amount of white space + USE : match the string USE, case insensitive + (?: : group a collection of regex symbols without saving the match as a "group" + \s+| : match one or more whitespace OR .... (the next entire grouped set of regex symbols) + (?: : group a collection of regex symbols without saving the match as a "group" + (?: : establish another unsaved grouping of regex symbols + \s* : any amount of white space + , : match a comma + \s* : any amount of white space + (?:NON_)? : optionally match the prefix NON_, case insensitive + INTRINSIC : match the string INTRINSIC, case insensitive + )? : optionally match the ", INTRINSIC/NON_INTRINSIC" grouped expression + \s* : any amount of white space + :: : match a double colon that must appear after the INTRINSIC/NON_INTRINSIC attribute + ) : end the unsaved grouping + ) : end the unsaved grouping + \s* : match any amount of white space + (modulename_regex) : match the module name that is being USE'd, see above. +""" +use_regex = \ +"(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(%s)"%\ +modulename + + +""" +Regular expression for a MODULE statement +----------------------------------------- + +This regex finds module definitions by matching the following: + +MODULE module_name + +but *not* the following: + +MODULE PROCEDURE procedure_name + +Here is a breakdown of the regex: + (?i) : regex is case insensitive + ^\s* : any amount of white space + MODULE : match the string MODULE, case insensitive + \s+ : match one or more white space characters + (?!PROCEDURE) : but *don't* match if the next word matches + PROCEDURE (negative lookahead assertion), + case insensitive + ([a-z_]\w*) : match one or more alphanumeric characters + that make up the defined module name and + save it in a group +""" +def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(%s)"""%modulename + + +""" +Regular expression for an INCLUDE statement +------------------------------------------- +The INCLUDE statement regex matches the following: + + INCLUDE 'some_Text' + INCLUDE "some_Text" + INCLUDE "some_Text" ; INCLUDE "some_Text" + INCLUDE kind_"some_Text" + INCLUDE kind_'some_Text" + +where some_Text can include any alphanumeric and/or special character +as defined by the Fortran 2003 standard. + +Here is a breakdown of the regex: + + (?i) : regex is case insensitive + (?: : begin a non-saving group that matches the following: + ^ : either the start of the line + | : or + ['">]\s*; : a semicolon that follows a single quote, + double quote or greater than symbol (with any + amount of whitespace in between). This will + allow the regex to match multiple INCLUDE + statements per line (although it also requires + the positive lookahead assertion that is + used below). It will even properly deal with + (i.e. ignore) cases in which the additional + INCLUDES are part of an in-line comment, ala + " INCLUDE 'someFile' ! ; INCLUDE 'someFile2' " + ) : end of non-saving group + \s* : any amount of white space + INCLUDE : match the string INCLUDE, case insensitive + \s+ : match one or more white space characters + (?\w+_)? : match the optional "kind-param _" prefix allowed by the standard + [<"'] : match the include delimiter - an apostrophe, double quote, or less than symbol + (.+?) : match one or more characters that make up + the included path and file name and save it + in a group. The Fortran standard allows for + any non-control character to be used. The dot + operator will pick up any character, including + control codes, but I can't conceive of anyone + putting control codes in their file names. + The question mark indicates it is non-greedy so + that regex will match only up to the next quote, + double quote, or greater than symbol + (?=["'>]) : positive lookahead assertion to match the include + delimiter - an apostrophe, double quote, or + greater than symbol. This level of complexity + is required so that the include delimiter is + not consumed by the match, thus allowing the + sub-regex discussed above to uniquely match a + set of semicolon-separated INCLUDE statements + (as allowed by the F2003 standard) +""" +include_regex = \ + """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" + + +""" +Regular expression for a comment +-------------------------------- + +One limitation of the original Scons scanner is that it cannot properly USE +statements if they are commented out. In either of the following cases: + + ! USE mod_a ; USE mod_b [entire line is commented out] + USE mod_a ! ; USE mod_b [in-line comment of second USE statement] + +the second module name (mod_b) will be picked up as a dependency even though +it should be ignored. The proposed solution is to first parse the file to +remove all the comments. + +(^.*)!? : match everything on a line before an optional comment +.*$ : ignore the rest of the line +""" +comment_regex = r'(^.*)!?.*$' + +class FortranFileSorter: + """Given a list of fortran 90/95 files, return a file list sorted by module + dependency. If a file depends on a parent through a USE MODULE statement, + this parent file will occur earlier in the list. + + Parameters + ---------- + files : sequence + The sequence of file names to be sorted. + + """ + def __init__(self, files): + self.files = files + self.use_regex = re.compile(use_regex, re.MULTILINE) + self.def_regex = re.compile(def_regex, re.MULTILINE) + self.comment_regex = re.compile(comment_regex, re.MULTILINE) + self.include_regex = re.compile(include_regex, re.MULTILINE) + + def read_code(self, file): + """Open the file and return the code as one string.""" + if not hasattr(file, 'readlines'): + file = open(file, 'r') + return file.read() + + def uncomment(self, code): + """Return an uncommented version of a code string.""" + return '\n'.join(self.comment_regex.findall(code)) + + def match_used(self, code): + """Return the set of used module in a code string.""" + return set(map(str.lower, self.use_regex.findall(code))) + + def match_defined(self, code): + """Return the set of defined module in a code string.""" + return set(map(str.lower, self.def_regex.findall(code))) + + def match_included(self, code): + """Return the set of included files in a code string.""" + return set(self.include_regex.findall(code)) + + def externals(self): + """Return the modules that are used but not defined in the list of + files.""" + if not hasattr(self, 'mod_defined'): + self.scan() + all_used = reduce(set.union, self.mod_used.values()) + all_defined = reduce(set.union, self.mod_defined.values()) + return all_used.difference(all_defined) + + def scan(self): + """For each file, identify the set of modules that are + defined, used but not defined in the same file, and the set of + included files. + """ + self.mod_defined = {} + self.mod_used = {} + self.included = {} + for f in self.files: + code = self.read_code(f) + code = self.uncomment(code) + self.mod_defined[f] = self.match_defined(code) + self.mod_used[f] = self.match_used(code) + self.included[f] = self.match_included(code) + + # Remove from used the modules defined internally. + # That is, keep elements in used but not in defined. + self.mod_used[f].difference_update(self.mod_defined[f]) + + # TODO : Deal with include (do we have too?) + def sort(self): + """Sort the files in order of dependency. + """ + ordered_list = [] + + # Take care of modules not defined anywhere in the files. eg. + # an intrinsic module by assuming them known from the + # start. + defined = self.externals() + + # This cycles through the files, and appends those whose dependencies + # are already satisfied by the files in the ordered list. + remaining = set(self.files) + goon = True + while goon: + goon = False + for f in remaining: + dependencies_satisfied = self.mod_used[f].issubset(defined) + if dependencies_satisfied: + ordered_list.append(f) + defined.update(self.mod_defined[f]) + goon = True + remaining.difference_update(set(ordered_list)) + + ordered_list.extend(list(remaining)) + return ordered_list + + + +def sort(files): + """Given a list of fortran 90/95 files, return a file list sorted by module + dependency. If a file depends on a parent through a USE MODULE statement, + this parent file will occur earlier in the list. + + Parameters + ---------- + files : sequence + The sequence of file names to be sorted. + """ + FS = FortranFileSorter(files) + FS.scan() + return FS.sort() + + +import sys +if __name__ == "__main__": + print sys.argv[1:] + sort(sys.argv[1:]) + + + diff --git a/HySoP/src/hysop++/tests/CMakeLists.txt b/HySoP/src/hysop++/tests/CMakeLists.txt index e16d2d63c31dfb62856c04ea233266894d40cdd3..cd300769e9ca3ffd1f1b7d67a595c8676ced83e2 100644 --- a/HySoP/src/hysop++/tests/CMakeLists.txt +++ b/HySoP/src/hysop++/tests/CMakeLists.txt @@ -1,7 +1,7 @@ -include("${CMAKE_SOURCE_DIR}/CMake/GoogleTestHelper.cmake") +#include("${CMAKE_SOURCE_DIR}/CMake/GoogleTestHelper.cmake") -add_subdirectory("testPolynoms") -add_subdirectory("testPlanner") -add_subdirectory("testDiffSolver") -add_subdirectory("testPoissonSolver") +#add_subdirectory("testPolynoms") +#add_subdirectory("testPlanner") +#add_subdirectory("testDiffSolver") +#add_subdirectory("testPoissonSolver")