diff --git a/CMakeLists.txt b/CMakeLists.txt index f9ca15fbfcf6ef1bd736edd42cd7825de03a10a4..3589391f0ea50eb2ac5308f62886a9ed04683355 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ option(DOUBLEPREC "set precision for real numbers to double precision when this option(USE_MPI "compile and link HySoP with mpi when this mode is enable. Default = on." ON) option(WITH_TESTS "Enable testing. Default = off" ON) option(BUILD_SHARED_LIBS "Enable dynamic library build, default = ON." ON) -option(WITH_LIB_CXX "Generate libhysop from fortran files in src, wrapped into hysop.cpp2hysop module. Default = ON." ON) +option(USE_CXX "Expand hysop with some new functions from a generated c++ to python interface, wrapped into hysop.cpp2hysop module. Default = ON." ON) option(WITH_SCALES "compile/create scales lib and link it with HySoP. Default = ON." ON) option(WITH_FFTW "Link with fftw library (required for some HySoP solvers), default = ON" ON) option(WITH_EXTRAS "Link with some extra fortran libraries (like arnoldi solver), default = OFF" OFF) @@ -74,26 +74,16 @@ endif() if(NOT USE_MPI) message(FATAL_ERROR "No-mpi version of hysop is broken, please enable mpi.") endif() - +set(USE_FORTRAN "ON") if(WITH_FFTW OR WITH_SCALES OR WITH_EXTRAS) set(USE_FORTRAN "ON") endif() -if(NOT WITH_LIB_CXX) +if(NOT USE_CXX) set(WITH_MAIN_CXX "OFF") set(WITH_GOOGLE_TESTS "OFF") endif() -# true if hysop used Fortran and/or c++ sources -# We can not run scales or fftw without mpi ... -if(USE_FORTRAN OR WITH_LIB_CXX) - set(WITH_COMPILED_LIB "ON") - #set(WITH_FFTW "ON") -else() - set(WITH_COMPILED_LIB "OFF") - #set(WITH_FFTW "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) @@ -117,12 +107,14 @@ set(PROJECT_LIBRARY_NAME ${PROJECT_NAME}) # Note that because of OutOfSourceBuild, binary_dir and source_dir must be different. set(LANGLIST) -if(WITH_LIB_CXX) +if(USE_CXX) set(LANGLIST ${LANGLIST} C CXX) endif() + if(USE_FORTRAN) set(LANGLIST ${LANGLIST} Fortran) endif() + include(HysopVersion) project(${PROJECT_NAME} ${LANGLIST}) @@ -154,7 +146,7 @@ if(USE_MPI) endif() # --- Wheel, required for a proper build/install process --- find_python_module(wheel REQUIRED) -if(WITH_LIB_CXX) +if(USE_CXX) find_package(SWIG 3.0.2 REQUIRED) # WARNING FP : for cmake < 3.0 UseSWIG.cmake # does not work properly (bug for swig outdir) @@ -165,7 +157,7 @@ if(WITH_LIB_CXX) endif() # Find python build dir name --> needed for tests and doc -if(WITH_COMPILED_LIB) +if(USE_CXX OR USE_FORTRAN) 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) @@ -255,6 +247,7 @@ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_D set(PYTHON_SETUP "${CMAKE_CURRENT_BINARY_DIR}/setup.py") if(USE_FORTRAN) + # if fortran is enabled, explicit setup of the compiler is required. add_custom_target(wheel ALL COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/setup.py bdist_wheel build config_fc --f90exec=${CMAKE_Fortran_COMPILER}#-d ${CMAKE_BINARY_DIR}/wheel/ COMMENT "create wheel file for ${PACKAGE_NAME} package" @@ -280,15 +273,17 @@ include(HySoPInstallSetup) # set precision for real numbers # used to generate precision.f95 file/module and constant.py if(DOUBLEPREC) - set(WORKING_PRECISION DP) + set(WORKING_PRECISION dp) set(MPI_PRECISION MPI_DOUBLE_PRECISION) set(PYTHON_PREC np.float64) set(MPI_PYTHON_PREC MPI.DOUBLE) + set(f2pymap_for_real double) else() - set(WORKING_PRECISION SP) + set(WORKING_PRECISION sp) set(MPI_PRECISION MPI_FLOAT) set(PYTHON_PREC np.float32) set(MPI_PYTHON_PREC MPI.FLOAT) + set(f2pymap_for_real float) endif() # set data layout ('fortran' order or 'C' order) @@ -304,29 +299,34 @@ if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/constants.py.in) configure_file(${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/constants.py.in ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/constants.py) endif() -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() if(USE_FORTRAN) - if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/.f2py_f2cmap) + + # Path to fortran-related generated files (.pyf, precision ...) + set(GENERATED_FORTRAN_FILES_DIR ${CMAKE_BINARY_DIR}/generated_fortran/) + + + # --- copy sort_f90 file to build --- + # Required for setup.py to handle fortran files dependencies + configure_file(${CMAKE_SOURCE_DIR}/sort_f90.py ${CMAKE_BINARY_DIR}/sort_f90.py) + + # --- Generate f2py_f2cmap file --- + if(EXISTS ${CMAKE_SOURCE_DIR}/f2py_f2cmap.in) message(STATUS "Generate f2py map file ...") - configure_file(${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/.f2py_f2cmap + configure_file(${CMAKE_SOURCE_DIR}/f2py_f2cmap.in ${CMAKE_BINARY_DIR}/.f2py_f2cmap) endif() + + # --- Create top-level pyf file --- + # -> depends on cmake config. This file + # includes the other required pyf files. + # For example, if WITH_FFTW is ON, then + # add a line 'include fftw2py.py' include(fortran_utils) - # Create f2hysop.pyf file write_main_pyf_file(f2hysop) - # ====== Create non-python (fortran) libraries (fftw and scales interfaces), if required ===== + # --- fortran libraries setup --- # Set module files directory (i.e. where .mod will be created) set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules) @@ -346,22 +346,22 @@ if(USE_FORTRAN) set(Fortran_FLAGS ${CMAKE_Fortran_FLAGS}) append_flags(Fortran_FLAGS ${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}}) - - if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/precision.conf.in) + # --- Generate precision.f95 file --- + if(EXISTS ${CMAKE_SOURCE_DIR}/precision.conf.in) message(STATUS "Generate precision.f95 file ...") - configure_file(${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/precision.conf.in - ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/utils_f/precision.f95) + configure_file(${CMAKE_SOURCE_DIR}/precision.conf.in + ${GENERATED_FORTRAN_FILES_DIR}/precision.f95) endif() endif() -if(WITH_COMPILED_LIB) - add_subdirectory(src) +if(USE_CXX OR USE_FORTRAN) + #add_subdirectory(src) #get_directory_property(FORTRAN_INCLUDE_DIRS #DIRECTORY ${CMAKE_SOURCE_DIR}/src #DEFINITION FORTRAN_INCLUDE_DIRS) endif() -if(WITH_LIB_CXX) +if(USE_CXX) #C++ variables used by setup.py.in for swig if(DEV_MODE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter") @@ -405,7 +405,7 @@ endif() # Hysop C++ library is generated in setup.py by swig # --- C++ main and tests --- -if(WITH_LIB_CXX) +if(USE_CXX) get_filename_component(CXX_DIR "${CMAKE_SOURCE_DIR}/src/hysop++" ABSOLUTE) get_filename_component(CXX_MAIN_DIR "${CXX_DIR}/main" ABSOLUTE) @@ -554,12 +554,12 @@ if(VERBOSE_MODE) if(USE_FORTRAN) message(STATUS " Fortran compiler : ${CMAKE_Fortran_COMPILER}") else() - message(WARNING "You deactivate libhysop (fortran) generation. This will disable the fortran interface, including fftw and scales fonctionnalities.") + message(WARNING "You deactivate fortran to python interface generation. This will disable the fortran interface, including fftw and scales fonctionnalities.") endif() - if(WITH_LIB_CXX) + if(USE_CXX) message(STATUS " CXX compiler : ${CMAKE_CXX_COMPILER}") else() - message(WARNING "You deactivate libhysop (cxx) generation. This will disable the Aitken-Schwarz Poisson solver.") + message(WARNING "You deactivate c++ to python interface generation. This will disable the Aitken-Schwarz Poisson solver.") endif() message(STATUS " Sources are in : ${CMAKE_SOURCE_DIR}") message(STATUS " Project uses MPI : ${USE_MPI}") diff --git a/ci/config.sh b/ci/config.sh index 5605ed2e1e0b4f2a9be0d1554af8140a9cdc3095..fd983559c56973578bda07dfe710dd198f8b9fdd 100644 --- a/ci/config.sh +++ b/ci/config.sh @@ -2,4 +2,4 @@ mkdir build cd build export FC=mpif90 CC=mpicc CXX=mpic++ F77=mpif90 -cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LIB_CXX=OFF .. +cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_CXX=OFF .. diff --git a/ci/run_tests.sh b/ci/run_tests.sh index f60cd72261aafdb06567fca7e78a79cdee041964..fc5e1a792093993de07e64f5c5a8e850416e487e 100644 --- a/ci/run_tests.sh +++ b/ci/run_tests.sh @@ -2,6 +2,6 @@ mkdir build cd build export FC=mpif90 CC=mpicc CXX=mpic++ -cmake -D CMAKE_BUILD_TYPE=Debug -DWITH_LIB_CXX=OFF .. +cmake -D CMAKE_BUILD_TYPE=Debug -DUSE_CXX=OFF .. make make test diff --git a/cmake/fortran_utils.cmake b/cmake/fortran_utils.cmake index 8f56794452975c5e23ad0aed1de74d937fb21be4..96c2f7ddb46cf1127e66efe2c5d8d01f7c9f41fa 100644 --- a/cmake/fortran_utils.cmake +++ b/cmake/fortran_utils.cmake @@ -15,7 +15,10 @@ # --> create f2hysop.pyf that will be used to generate hysop.f2hysop module. # function(write_main_pyf_file filename) - set(_file ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/${filename}.pyf.in) + + # First writes filename.pyf.in, according to cmake current config + # and then generate filename.pyf. + set(_file ${GENERATED_FORTRAN_FILES_DIR}/${filename}.pyf.in) file(WRITE ${_file} "! -*- f90 -*-\n ! Generated file - Do not edit.\n @@ -24,12 +27,12 @@ python module f2hysop ! in\n interface\n") file(APPEND ${_file} " ! Example - include '@CMAKE_SOURCE_DIR@/hysop/fortran/template.pyf'\n") + include '@CMAKE_SOURCE_DIR@/hysop/common_f/template.pyf'\n") file(APPEND ${_file} " ! precision - include '@CMAKE_SOURCE_DIR@/hysop/f2py/parameters.pyf'\n") - if(WITH_FFTW) - file(APPEND ${_file} + !! include '@CMAKE_SOURCE_DIR@/hysop/f2py/parameters.pyf'\n") + if(WITH_FFTW) + file(APPEND ${_file} " ! fftw include '@CMAKE_SOURCE_DIR@/hysop/f2py/fftw2py.pyf'\n") endif() @@ -46,7 +49,7 @@ python module f2hysop ! in\n file(APPEND ${_file} " end interface\n end python module f2hysop") -message(STATUS "Generate pyf file ...") -configure_file(${_file} ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/${filename}.pyf @ONLY) +message(STATUS "Generate f2hysop.pyf file ...") +configure_file(${_file} ${GENERATED_FORTRAN_FILES_DIR}/${filename}.pyf @ONLY) endfunction() diff --git a/f2py_f2cmap.in b/f2py_f2cmap.in new file mode 100644 index 0000000000000000000000000000000000000000..906a2f6f9c2d4208ee5eca277eb3079376035797 --- /dev/null +++ b/f2py_f2cmap.in @@ -0,0 +1,3 @@ +{'integer':{'c_int':'int'}, 'real':{'real64':'double', 'real32':'float', 'wp':'@f2pymap_for_real@'}} + + diff --git a/hysop/.f2py_f2cmap b/hysop/.f2py_f2cmap deleted file mode 100644 index 99f5f3517caf6260a22a9851a15f66443a1045d4..0000000000000000000000000000000000000000 --- a/hysop/.f2py_f2cmap +++ /dev/null @@ -1,3 +0,0 @@ -{'integer':{'c_int':'int'}, 'real':{'real64':'double', 'wp':'double'}} - - diff --git a/hysop/f2hysop.pyf.in b/hysop/f2hysop.pyf.in deleted file mode 100644 index a11194e7df7e5f7f02bb55b202ff01bf3faa85e9..0000000000000000000000000000000000000000 --- a/hysop/f2hysop.pyf.in +++ /dev/null @@ -1,20 +0,0 @@ -! -*- f90 -*- - -! Generated file - Do not edit. - -! 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 \ No newline at end of file diff --git a/hysop/fakef2py/__init__.py b/hysop/fakef2py/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/hysop/fakef2py/fftw2py/__init__.py b/hysop/fakef2py/fftw2py/__init__.py deleted file mode 100644 index 95df2255c1722b1a16cd39a6452fe5d94a7385cb..0000000000000000000000000000000000000000 --- a/hysop/fakef2py/fftw2py/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -msg = " ==== Import f2py.fftw2py warning ==== \n" -msg += "The package is empty since you disable " -msg += "fftw when installing HySoP. \n" -msg += "Whatever you'll do with this will probably failed." -print (msg) diff --git a/hysop/fakef2py/scales2py/__init__.py b/hysop/fakef2py/scales2py/__init__.py deleted file mode 100644 index 58ba76d2f7aceb911bb77628ceefced262357ce7..0000000000000000000000000000000000000000 --- a/hysop/fakef2py/scales2py/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -msg = " ==== Import f2py.scales2py warning ==== \n" -msg += "The package is empty since you disable " -msg += "scales when installing HySoP. \n" -msg += "Whatever you'll do with this will probably failed." -print (msg) diff --git a/hysop/operator/discrete/multiresolution_filter.py b/hysop/operator/discrete/multiresolution_filter.py index 157dbbb10319b251af114e3a76d474a0ac7f7a2b..0539971c36aab79f9e445a5556f7def2e82acb46 100644 --- a/hysop/operator/discrete/multiresolution_filter.py +++ b/hysop/operator/discrete/multiresolution_filter.py @@ -6,16 +6,14 @@ from hysop.operator.discrete.discrete import DiscreteOperator from hysop.tools.profiler import profile import hysop.tools.numpywrappers as npw from hysop.methods_keys import Remesh -from hysop.methods import Rmsh_Linear, L2_1 -from hysop.numerics.remeshing import RemeshFormula +from hysop.numerics.remeshing import RemeshFormula, Linear, L2_1 class FilterFineToCoarse(DiscreteOperator): - """ - Discretized operator for filtering from fine to coarse grid. + """Discretized operator for filtering from fine to coarse grid. """ - authorized_methods = [Linear, L21] + authorized_methods = [Linear, L2_1] def __init__(self, field_in, field_out, **kwds): """ diff --git a/hysop/operator/multiresolution_filter.py b/hysop/operator/multiresolution_filter.py index 01cc7d0a6b06c7e073ba8d709203e366761cc948..5be1a8d249c36822a714dacab7d97cb1f98a955b 100644 --- a/hysop/operator/multiresolution_filter.py +++ b/hysop/operator/multiresolution_filter.py @@ -25,7 +25,7 @@ class MultiresolutionFilter(Computational): """ if 'method' not in kwds: - kwds['method'] = default.MULTIRESOLUTION_FILER + kwds['method'] = default.MULTIRESOLUTION_FILTER super(MultiresolutionFilter, self).__init__(**kwds) self.d_in, self.d_out = d_in, d_out self.input = self.variables diff --git a/hysop/operator/tests/test_multiresolution_filter.py b/hysop/operator/tests/test_multiresolution_filter.py index 198d8ce4a2a4c9cb2c640dbcd0b5c98ba0948288..a66c59b0a5d39450c01a901ab63109205ce27aca 100755 --- a/hysop/operator/tests/test_multiresolution_filter.py +++ b/hysop/operator/tests/test_multiresolution_filter.py @@ -116,8 +116,9 @@ def test_L21_X(): b, e, err = filter(d_coarse=Discretization([n_middle, 5, 5], ghosts=[2, 2, 2]), d_fine=Discretization([n_large, 5, 5]), - method={Remesh: L21, }, + method={Remesh: L2_1, }, func=func_periodic_X) + print b, e, err assert b, "max(|error|)=" + str(e) + " <= " + str(err) @@ -125,7 +126,7 @@ def test_L21_Y(): b, e, err = filter(d_coarse=Discretization([5, n_middle, 5], ghosts=[2, 2, 2]), d_fine=Discretization([5, n_large, 5]), - method={Remesh: L21, }, + method={Remesh: L2_1, }, func=func_periodic_X) assert b, "max(|error|)=" + str(e) + " <= " + str(err) @@ -134,7 +135,7 @@ def test_L21_Z(): b, e, err = filter(d_coarse=Discretization([5, 5, n_middle], ghosts=[2, 2, 2]), d_fine=Discretization([5, 5, n_large]), - method={Remesh: L21, }, + method={Remesh: L2_1, }, func=func_periodic_X) assert b, "max(|error|)=" + str(e) + " <= " + str(err) @@ -181,7 +182,7 @@ def test_filter_linear(): op.setup() topo_coarse = op.discreteFields[f].topology topo_fine = [t for t in f.discreteFields.keys() - if not t is topo_coarse][0] + if t is not topo_coarse][0] f.initialize(topo=topo_fine) f_out = f.discreteFields[topo_coarse] op.apply(simu) @@ -207,7 +208,7 @@ def test_filter_l2_1(): op.setup() topo_coarse = op.discreteFields[f].topology topo_fine = [t for t in f.discreteFields.keys() - if not t is topo_coarse][0] + if t is not topo_coarse][0] f.initialize(topo=topo_fine) f_out = f.discreteFields[topo_coarse] op.apply(simu) diff --git a/setup.py.in b/setup.py.in index e92172482a497b8cc2e1b82ab574cc54a6fedd44..1676f83c012e8972431cdf026b424be01beb8cff 100644 --- a/setup.py.in +++ b/setup.py.in @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -""" -setup.py file for @PYPACKAGE_NAME@ +"""setup.py file for @PYPACKAGE_NAME@ """ from setuptools import find_packages @@ -16,26 +15,48 @@ import fnmatch # tools to deal with fortran dependencies. import sys -sys.path.append('@CMAKE_SOURCE_DIR@/') +sys.path.append('@CMAKE_BINARY_DIR@/') import sort_f90 -enable_cpp = "@WITH_LIB_CXX@" +# --- Check if c++ interface is enabled --- +enable_cpp = "@USE_CXX@" if enable_cpp: swig_executable = find_executable("@SWIG_EXECUTABLE@") def parseCMakeVar(var): + """post-process cmake list-like variable + + Example:: + + a = parseCMakeVar("var1;var2;var3;") + # --> a = ['var', 'var2', 'var3'] + """ if var != "": - return var.split(';') + res = list(set(var.split(';'))) + # list/set stuff to avoid duplicates + # remove empty strings to avoid '-I -I' things leading to bugs + if res.count(''): + res.remove('') + return res else: return [] + def parseCMakeDefines(var): + """post-process cmake variables, corresponding + to pre-processor definitions. + + Example:: + + res = parseCMakeDefines("-DVAR=VAL1:-DVAR2=VAL2:-DVAR3=VAL3") + # --> res = [('VAR', 'VAL1'), ('VAR2', 'VAL2'), ('VAR3', 'VAL3')] + """ defines = parseCMakeVar(var) - if defines == None: + if defines is None: return None - - # regex to match compiler defines like -DMACRO_NAME or -DMACRO_NAME = MACRO_VALUE + # regex to match compiler defines like -DMACRO_NAME or + # -DMACRO_NAME = MACRO_VALUE p = re.compile('\s*(?:-D)?\s*(\w+)(?:\s*=\s*(\w+))?\s*') res = list() @@ -44,26 +65,56 @@ def parseCMakeDefines(var): if m: res.append(m.group(1,2)) else: - print "\tWarning: Could extract cmake define from '",d,"'." + print "\tWarning: Could extract cmake define from '", d, "'." return res - +# --- external libraries to be linked with --- hysop_link_libraries = parseCMakeVar("@HYSOP_LINK_LIBRARIES@") -hysop_link_libraries_names = set([]) -hysop_link_libraries_dirs = set([]) +#hysop_link_libraries_names = set([]) +#hysop_link_libraries_dirs = set([]) # use set to avoid dupl. -link_list = "" -for lib in hysop_link_libraries: - hysop_link_libraries_names.add(os.path.basename(lib)) - hysop_link_libraries_dirs.add(os.path.dirname(lib)) - link_list += lib + " " -hysop_link_libraries_names = list(hysop_link_libraries_names) -hysop_link_libraries_dirs = list(hysop_link_libraries_dirs) +#link_list = "" +# for lib in hysop_link_libraries: +# hysop_link_libraries_names.add(os.path.basename(lib)) +# hysop_link_libraries_dirs.add(os.path.dirname(lib)) +# link_list += lib + " " +# hysop_link_libraries_names = list(hysop_link_libraries_names) +# hysop_link_libraries_dirs = list(hysop_link_libraries_dirs) + 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 + + Parameters + ---------- + name: string + python module name + pyf_file: string, optional + f2py interface file (absolute path) + src_dirs: list, optional + all directories containing fortran sources (absolute path) + that must be taken into account. Warning: dir. scan is not + recursive. + sources: list, optional + all fortran files that must be taken into account + libs: list of strings, optional + names of all libraries to be linked with to build f2py module + --> for -l option + libdir: list of strings, optional + list of directories, absolute path to libraries listed in libs + --> for -L... option + debug_mode: boolean, optional + if true enable f2py debug mode, default=False + + Notes + ----- + * either sources or src_dirs is required but both + can be used simultaneously. + * only .f90 and .f95 files are taken into account. """ + + # --- Collect list of fortran files --- if sources is None: sources = [] assert src_dirs is not None @@ -71,29 +122,29 @@ def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=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: + # --- set f2py options --- + f2py_options = ['--no-lower', '--no-wrap-functions'] + options = [] + 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') + + # --- set include dir --- + inc_dir = parseCMakeVar("@MPI_Fortran_INCLUDE_PATH@") + inc_dir.append('@CMAKE_Fortran_MODULE_DIRECTORY@') + # --- set compilation flags --- fortran_flags = ['@Fortran_FLAGS@'] - #includes = parseCMakeVar("@FORTRAN_INCLUDE_DIRS@") #if(includes != None): - #for exti in includes: - #inc_dir.append(exti) + # for exti in includes: + #i nc_dir.append(exti) #libs += hysop_link_libraries_names #libdir += hysop_link_libraries_dirs # we trust cmake for external libraries and @@ -114,37 +165,58 @@ def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None, def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None): """Create a python module from C++ files, using swig + + Parameters + ---------- + name: string + module name + inc_dirs: list + list of directories for includes (-I ...), absolute path + containing headers (.hpp) and swig files (.i) + sources: list, optional + all c++ files that must be taken into account + src_dirs: list, optional + all directories containing fortran sources (absolute path) + that must be taken into account. Warning: no recursive scan + in src_dirs. + + Notes + ----- + * either sources, src_dirs or inc_dirs is required but all + can be used simultaneously. + * only .cpp files are taken into account. + * main config file for swig is assumed to be + name.i in CMAKE_SOURCE_DIR/swig/ + """ - swig_dir = os.path.join('@CMAKE_SOURCE_DIR@', 'swig') - swig_config_file = os.path.join(swig_dir, name+'.i') + swig_dir = os.path.join('@CMAKE_SOURCE_DIR@', 'swig') + swig_config_file = os.path.join(swig_dir, name + '.i') include_dirs = set(inc_dirs) if sources is None: sources = [] - if(src_dirs == None): - assert(inc_dirs != None) - for idir in inc_dirs: - #sources += glob.glob(os.path.join(idir, '**/*.cpp'), recursive=True) - for root, dirnames, filenames in os.walk(idir): - for filename in fnmatch.filter(filenames, '*.cpp'): - sources.append(os.path.join(root, filename)) - else: - for sdir in src_dirs: - sources += glob.glob(os.path.join(sdir, '*.cpp')) - #else: - #for f in sources: - #include_dirs.add(os.path.dirname(f)) + assert src_dirs is not None or inc_dirs is not None + if(src_dirs is None): + assert(inc_dirs is not None) + for idir in inc_dirs: + #sources += glob.glob(os.path.join(idir, '**/*.cpp'), recursive=True) + for root, dirnames, filenames in os.walk(idir): + for filename in fnmatch.filter(filenames, '*.cpp'): + sources.append(os.path.join(root, filename)) + else: + for sdir in src_dirs: + sources += glob.glob(os.path.join(sdir, '*.cpp')) - sources.insert(0,swig_config_file) + sources.insert(0, swig_config_file) include_dirs = list(include_dirs) name = 'hysop._' + name swig_opts = ['-I' + swig_dir, '-O', '-Wextra', '-Werror', '-c++', '-extranative', '-safecstrings'] - + extern_includes = parseCMakeVar("@CXX_EXT_INCLUDES@") - if(extern_includes != None): + if(extern_includes is not None): for exti in extern_includes: include_dirs.append(exti) @@ -170,33 +242,10 @@ def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None): # List of modules (directories) to be included with_test = "@WITH_TESTS@" is "ON" if with_test: - packages = find_packages(exclude=["*fakef2py*", "*gpu*"],where="@CMAKE_SOURCE_DIR@") + packages = find_packages(exclude=["*gpu*"], where="@CMAKE_SOURCE_DIR@") else: - packages = find_packages(exclude=["*tests*","*fakef2py*", "*gpu*"],where="@CMAKE_SOURCE_DIR@") - -# packages = ['hysop', -# 'hysop.domain', -# 'hysop.fields', -# 'hysop.operator', -# 'hysop.operator.discrete', -# 'hysop.problem', -# 'hysop.tools', -# 'hysop.numerics', -# 'hysop.numerics.integrators', -# ] - -# packages_for_tests = ['hysop.domain.tests', -# 'hysop.fields.tests', -# 'hysop.operator.tests', -# 'hysop.numerics.tests', -# 'hysop.tools.tests', -# 'hysop.problem.tests', -# 'hysop.numerics.tests', -# ] - -# if "@USE_MPI@" is "ON": -# packages.append('hysop.mpi') -# packages_for_tests.append('hysop.mpi.tests') + packages = find_packages(exclude=["*tests*", "*gpu*"], + where="@CMAKE_SOURCE_DIR@") if "@WITH_GPU@" is "ON": packages.append('hysop.gpu') @@ -217,11 +266,12 @@ ext = {} if enable_fortran is "ON": fortran_root = \ '@CMAKE_SOURCE_DIR@/hysop' - hysop_libdir = ['@CMAKE_BINARY_DIR@/src'] - hysoplib = ['@HYSOP_LIBRARY_NAME@'] + hysop_libdir = [] ##### ['@CMAKE_BINARY_DIR@/src'] + #####hysoplib = ['@HYSOP_LIBRARY_NAME@'] f2py_options = ['--no-lower'] fortran_src = set([]) - fortran_src.add('f2py/parameters.f90') + + ####fortran_src.add('f2py/parameters.f90') # -- fftw fortran sources -- withfftw = "@WITH_FFTW@" if withfftw is "ON": @@ -230,16 +280,12 @@ if enable_fortran is "ON": #hysoplib.append('fftw3') #hysoplib.append('fftw3_mpi') hysop_libdir.append(fftwdir) - else: - packages.append('hysop.fakef2py') - packages.append('hysop.fakef2py.fftw2py') + # -- scales sources -- withscales = '@WITH_SCALES@' if withscales is "ON": 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)): @@ -247,14 +293,15 @@ if enable_fortran is "ON": # === Draft for future implementation of fortran interface === # -- f2py signature file -- - pyf_file = os.path.join(fortran_root, 'f2hysop.pyf') + pyf_file = os.path.join('@GENERATED_FORTRAN_FILES_DIR@', 'f2hysop.pyf') # -- list of directories which contains fortran sources -- - # those dirs must be in hysop package directory - subdirs = ['fortran',] + # path must be relative to hysop package directory + subdirs = ['common_f', ] num_dirs = [] for sd in subdirs: num_dirs.append(os.path.join(fortran_root, sd)) + num_dirs.append('@GENERATED_FORTRAN_FILES_DIR@') # create python interface to fortran sources # For the moment, it includes the 'old' interface # to scales and fftw (in sources) and the new @@ -262,8 +309,8 @@ if enable_fortran is "ON": ext['f2hysop'] = create_fortran_extension( name='hysop.f2hysop', sources=fortran_src, - libdir=hysop_libdir, - libs=hysoplib, + #libdir=hysop_libdir, + #libs=hysoplib, pyf_file=pyf_file, src_dirs=num_dirs) @@ -283,12 +330,13 @@ if enable_cpp is "ON": swig_include_dirs = [os.path.join('@CMAKE_SOURCE_DIR@','swig')] cpp_include_dirs = ['src/fftw','src/hysop++/src'] - for id in cpp_include_dirs: - swig_include_dirs.append(os.path.join('@CMAKE_SOURCE_DIR@', id)) + for d in cpp_include_dirs: + swig_include_dirs.append(os.path.join('@CMAKE_SOURCE_DIR@', d)) ext = {} cpp2hysop = "@CPP_2_HYSOP@" - ext[cpp2hysop] = create_swig_extension(name=cpp2hysop, inc_dirs=swig_include_dirs) + ext[cpp2hysop] = create_swig_extension(name=cpp2hysop, + inc_dirs=swig_include_dirs) for ex in ext: ext_modules.append(ext[ex]) diff --git a/sort_f90.py b/sort_f90.py index fb1f6a93cdb947c1fc9361561c05f842ab9bcc21..86257d4cfdbc396d6cc93c1fe1b6aefcfc9fad7a 100644 --- a/sort_f90.py +++ b/sort_f90.py @@ -1,61 +1,58 @@ """ -Dependency scanner for F90/95 modules. +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. +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 +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. +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 +import re -__all__ = ['FortranFileSorter', 'sort'] +__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 -------------------------------------- @@ -95,8 +92,8 @@ Here is a breakdown of the regex: (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 + "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(%s)" %\ + modulename """ @@ -123,7 +120,7 @@ Here is a breakdown of the regex: that make up the defined module name and save it in a group """ -def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(%s)"""%modulename +def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(%s)""" % modulename """ @@ -203,18 +200,20 @@ remove all the comments. .*$ : 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) @@ -239,11 +238,11 @@ class FortranFileSorter: 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.""" @@ -252,7 +251,7 @@ class FortranFileSorter: 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 @@ -263,28 +262,28 @@ class FortranFileSorter: self.included = {} for f in self.files: code = self.read_code(f) - code = self.uncomment(code) + 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?) + + # 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 + # 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. + + # 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: @@ -292,21 +291,20 @@ class FortranFileSorter: for f in remaining: dependencies_satisfied = self.mod_used[f].issubset(defined) if dependencies_satisfied: - ordered_list.append(f) + 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 @@ -314,13 +312,10 @@ def sort(files): """ FS = FortranFileSorter(files) FS.scan() - return FS.sort() + return FS.sort() import sys if __name__ == "__main__": print sys.argv[1:] sort(sys.argv[1:]) - - - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5eea76945fb822e3da511063aaf27f35d84576f3..a66936986a42225f07626ad70dc525877387296c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,7 +15,7 @@ if(WITH_FFTW) list(APPEND ${HYSOP_LIBRARY_NAME}_SRCDIRS fftw) endif() -if(WITH_LIB_CXX) +if(USE_CXX) list(APPEND ${HYSOP_LIBRARY_NAME}_SRCDIRS hysop++/src) endif() @@ -102,4 +102,4 @@ if(WITH_FORTRAN_TESTS) target_link_libraries(${EXE_NAME} ${HYSOP_LIBRARY_NAME}) target_link_libraries(${EXE_NAME} ${HYSOP_LINK_LIBRARIES}) endif() -endif() \ No newline at end of file +endif()