Skip to content
Snippets Groups Projects
Commit 38996304 authored by Franck Pérignon's avatar Franck Pérignon
Browse files

Fortran/f2Py things

parent 0b858c0d
No related branches found
No related tags found
No related merge requests found
...@@ -33,7 +33,7 @@ option(DOUBLEPREC "set precision for real numbers to double precision when this ...@@ -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(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(WITH_TESTS "Enable testing. Default = off" ON)
option(BUILD_SHARED_LIBS "Enable dynamic library build, default = ON." 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_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_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) option(WITH_EXTRAS "Link with some extra fortran libraries (like arnoldi solver), default = OFF" OFF)
...@@ -74,26 +74,16 @@ endif() ...@@ -74,26 +74,16 @@ endif()
if(NOT USE_MPI) if(NOT USE_MPI)
message(FATAL_ERROR "No-mpi version of hysop is broken, please enable mpi.") message(FATAL_ERROR "No-mpi version of hysop is broken, please enable mpi.")
endif() endif()
set(USE_FORTRAN "ON")
if(WITH_FFTW OR WITH_SCALES OR WITH_EXTRAS) if(WITH_FFTW OR WITH_SCALES OR WITH_EXTRAS)
set(USE_FORTRAN "ON") set(USE_FORTRAN "ON")
endif() endif()
if(NOT WITH_LIB_CXX) if(NOT USE_CXX)
set(WITH_MAIN_CXX "OFF") set(WITH_MAIN_CXX "OFF")
set(WITH_GOOGLE_TESTS "OFF") set(WITH_GOOGLE_TESTS "OFF")
endif() 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 # Force a default build type if not provided by user
# CMAKE_BUILD_TYPE = empty, Debug, Release, RelWithDebInfo or MinSizeRel. # CMAKE_BUILD_TYPE = empty, Debug, Release, RelWithDebInfo or MinSizeRel.
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
...@@ -117,12 +107,14 @@ set(PROJECT_LIBRARY_NAME ${PROJECT_NAME}) ...@@ -117,12 +107,14 @@ set(PROJECT_LIBRARY_NAME ${PROJECT_NAME})
# Note that because of OutOfSourceBuild, binary_dir and source_dir must be different. # Note that because of OutOfSourceBuild, binary_dir and source_dir must be different.
set(LANGLIST) set(LANGLIST)
if(WITH_LIB_CXX) if(USE_CXX)
set(LANGLIST ${LANGLIST} C CXX) set(LANGLIST ${LANGLIST} C CXX)
endif() endif()
if(USE_FORTRAN) if(USE_FORTRAN)
set(LANGLIST ${LANGLIST} Fortran) set(LANGLIST ${LANGLIST} Fortran)
endif() endif()
include(HysopVersion) include(HysopVersion)
project(${PROJECT_NAME} ${LANGLIST}) project(${PROJECT_NAME} ${LANGLIST})
...@@ -154,7 +146,7 @@ if(USE_MPI) ...@@ -154,7 +146,7 @@ if(USE_MPI)
endif() endif()
# --- Wheel, required for a proper build/install process --- # --- Wheel, required for a proper build/install process ---
find_python_module(wheel REQUIRED) find_python_module(wheel REQUIRED)
if(WITH_LIB_CXX) if(USE_CXX)
find_package(SWIG 3.0.2 REQUIRED) find_package(SWIG 3.0.2 REQUIRED)
# WARNING FP : for cmake < 3.0 UseSWIG.cmake # WARNING FP : for cmake < 3.0 UseSWIG.cmake
# does not work properly (bug for swig outdir) # does not work properly (bug for swig outdir)
...@@ -165,7 +157,7 @@ if(WITH_LIB_CXX) ...@@ -165,7 +157,7 @@ if(WITH_LIB_CXX)
endif() endif()
# Find python build dir name --> needed for tests and doc # Find python build dir name --> needed for tests and doc
if(WITH_COMPILED_LIB) if(USE_CXX OR USE_FORTRAN)
execute_process( 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()" 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) OUTPUT_VARIABLE ${PROJECT_NAME}_PYTHON_BUILD_DIR)
...@@ -255,6 +247,7 @@ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_D ...@@ -255,6 +247,7 @@ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_D
set(PYTHON_SETUP "${CMAKE_CURRENT_BINARY_DIR}/setup.py") set(PYTHON_SETUP "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
if(USE_FORTRAN) if(USE_FORTRAN)
# if fortran is enabled, explicit setup of the compiler is required.
add_custom_target(wheel ALL 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/ 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" COMMENT "create wheel file for ${PACKAGE_NAME} package"
...@@ -280,15 +273,17 @@ include(HySoPInstallSetup) ...@@ -280,15 +273,17 @@ include(HySoPInstallSetup)
# set precision for real numbers # set precision for real numbers
# used to generate precision.f95 file/module and constant.py # used to generate precision.f95 file/module and constant.py
if(DOUBLEPREC) if(DOUBLEPREC)
set(WORKING_PRECISION DP) set(WORKING_PRECISION dp)
set(MPI_PRECISION MPI_DOUBLE_PRECISION) set(MPI_PRECISION MPI_DOUBLE_PRECISION)
set(PYTHON_PREC np.float64) set(PYTHON_PREC np.float64)
set(MPI_PYTHON_PREC MPI.DOUBLE) set(MPI_PYTHON_PREC MPI.DOUBLE)
set(f2pymap_for_real double)
else() else()
set(WORKING_PRECISION SP) set(WORKING_PRECISION sp)
set(MPI_PRECISION MPI_FLOAT) set(MPI_PRECISION MPI_FLOAT)
set(PYTHON_PREC np.float32) set(PYTHON_PREC np.float32)
set(MPI_PYTHON_PREC MPI.FLOAT) set(MPI_PYTHON_PREC MPI.FLOAT)
set(f2pymap_for_real float)
endif() endif()
# set data layout ('fortran' order or 'C' order) # set data layout ('fortran' order or 'C' order)
...@@ -304,29 +299,34 @@ if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/constants.py.in) ...@@ -304,29 +299,34 @@ if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/constants.py.in)
configure_file(${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) ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/constants.py)
endif() 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(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 ...") 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) ${CMAKE_BINARY_DIR}/.f2py_f2cmap)
endif() 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) include(fortran_utils)
# Create f2hysop.pyf file
write_main_pyf_file(f2hysop) 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 module files directory (i.e. where .mod will be created)
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules) set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules)
...@@ -346,22 +346,22 @@ if(USE_FORTRAN) ...@@ -346,22 +346,22 @@ if(USE_FORTRAN)
set(Fortran_FLAGS ${CMAKE_Fortran_FLAGS}) set(Fortran_FLAGS ${CMAKE_Fortran_FLAGS})
append_flags(Fortran_FLAGS ${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}}) append_flags(Fortran_FLAGS ${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}})
# --- Generate precision.f95 file ---
if(EXISTS ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/precision.conf.in) if(EXISTS ${CMAKE_SOURCE_DIR}/precision.conf.in)
message(STATUS "Generate precision.f95 file ...") message(STATUS "Generate precision.f95 file ...")
configure_file(${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/precision.conf.in configure_file(${CMAKE_SOURCE_DIR}/precision.conf.in
${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/utils_f/precision.f95) ${GENERATED_FORTRAN_FILES_DIR}/precision.f95)
endif() endif()
endif() endif()
if(WITH_COMPILED_LIB) if(USE_CXX OR USE_FORTRAN)
add_subdirectory(src) #add_subdirectory(src)
#get_directory_property(FORTRAN_INCLUDE_DIRS #get_directory_property(FORTRAN_INCLUDE_DIRS
#DIRECTORY ${CMAKE_SOURCE_DIR}/src #DIRECTORY ${CMAKE_SOURCE_DIR}/src
#DEFINITION FORTRAN_INCLUDE_DIRS) #DEFINITION FORTRAN_INCLUDE_DIRS)
endif() endif()
if(WITH_LIB_CXX) if(USE_CXX)
#C++ variables used by setup.py.in for swig #C++ variables used by setup.py.in for swig
if(DEV_MODE) if(DEV_MODE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter") 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() ...@@ -405,7 +405,7 @@ endif()
# Hysop C++ library is generated in setup.py by swig # Hysop C++ library is generated in setup.py by swig
# --- C++ main and tests --- # --- 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_DIR "${CMAKE_SOURCE_DIR}/src/hysop++" ABSOLUTE)
get_filename_component(CXX_MAIN_DIR "${CXX_DIR}/main" ABSOLUTE) get_filename_component(CXX_MAIN_DIR "${CXX_DIR}/main" ABSOLUTE)
...@@ -554,12 +554,12 @@ if(VERBOSE_MODE) ...@@ -554,12 +554,12 @@ if(VERBOSE_MODE)
if(USE_FORTRAN) if(USE_FORTRAN)
message(STATUS " Fortran compiler : ${CMAKE_Fortran_COMPILER}") message(STATUS " Fortran compiler : ${CMAKE_Fortran_COMPILER}")
else() 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() endif()
if(WITH_LIB_CXX) if(USE_CXX)
message(STATUS " CXX compiler : ${CMAKE_CXX_COMPILER}") message(STATUS " CXX compiler : ${CMAKE_CXX_COMPILER}")
else() 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() endif()
message(STATUS " Sources are in : ${CMAKE_SOURCE_DIR}") message(STATUS " Sources are in : ${CMAKE_SOURCE_DIR}")
message(STATUS " Project uses MPI : ${USE_MPI}") message(STATUS " Project uses MPI : ${USE_MPI}")
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
mkdir build mkdir build
cd build cd build
export FC=mpif90 CC=mpicc CXX=mpic++ F77=mpif90 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 ..
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
mkdir build mkdir build
cd build cd build
export FC=mpif90 CC=mpicc CXX=mpic++ 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
make test make test
...@@ -15,7 +15,10 @@ ...@@ -15,7 +15,10 @@
# --> create f2hysop.pyf that will be used to generate hysop.f2hysop module. # --> create f2hysop.pyf that will be used to generate hysop.f2hysop module.
# #
function(write_main_pyf_file filename) 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} file(WRITE ${_file}
"! -*- f90 -*-\n "! -*- f90 -*-\n
! Generated file - Do not edit.\n ! Generated file - Do not edit.\n
...@@ -24,12 +27,12 @@ python module f2hysop ! in\n ...@@ -24,12 +27,12 @@ python module f2hysop ! in\n
interface\n") interface\n")
file(APPEND ${_file} file(APPEND ${_file}
" ! Example " ! Example
include '@CMAKE_SOURCE_DIR@/hysop/fortran/template.pyf'\n") include '@CMAKE_SOURCE_DIR@/hysop/common_f/template.pyf'\n")
file(APPEND ${_file} file(APPEND ${_file}
" ! precision " ! precision
include '@CMAKE_SOURCE_DIR@/hysop/f2py/parameters.pyf'\n") !! include '@CMAKE_SOURCE_DIR@/hysop/f2py/parameters.pyf'\n")
if(WITH_FFTW) if(WITH_FFTW)
file(APPEND ${_file} file(APPEND ${_file}
" ! fftw " ! fftw
include '@CMAKE_SOURCE_DIR@/hysop/f2py/fftw2py.pyf'\n") include '@CMAKE_SOURCE_DIR@/hysop/f2py/fftw2py.pyf'\n")
endif() endif()
...@@ -46,7 +49,7 @@ python module f2hysop ! in\n ...@@ -46,7 +49,7 @@ python module f2hysop ! in\n
file(APPEND ${_file} " end interface\n file(APPEND ${_file} " end interface\n
end python module f2hysop") end python module f2hysop")
message(STATUS "Generate pyf file ...") message(STATUS "Generate f2hysop.pyf file ...")
configure_file(${_file} ${CMAKE_SOURCE_DIR}/${PACKAGE_NAME}/${filename}.pyf @ONLY) configure_file(${_file} ${GENERATED_FORTRAN_FILES_DIR}/${filename}.pyf @ONLY)
endfunction() endfunction()
{'integer':{'c_int':'int'}, 'real':{'real64':'double', 'real32':'float', 'wp':'@f2pymap_for_real@'}}
{'integer':{'c_int':'int'}, 'real':{'real64':'double', 'wp':'double'}}
! -*- 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
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)
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)
...@@ -6,16 +6,14 @@ from hysop.operator.discrete.discrete import DiscreteOperator ...@@ -6,16 +6,14 @@ from hysop.operator.discrete.discrete import DiscreteOperator
from hysop.tools.profiler import profile from hysop.tools.profiler import profile
import hysop.tools.numpywrappers as npw import hysop.tools.numpywrappers as npw
from hysop.methods_keys import Remesh from hysop.methods_keys import Remesh
from hysop.methods import Rmsh_Linear, L2_1 from hysop.numerics.remeshing import RemeshFormula, Linear, L2_1
from hysop.numerics.remeshing import RemeshFormula
class FilterFineToCoarse(DiscreteOperator): 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): def __init__(self, field_in, field_out, **kwds):
""" """
......
...@@ -25,7 +25,7 @@ class MultiresolutionFilter(Computational): ...@@ -25,7 +25,7 @@ class MultiresolutionFilter(Computational):
""" """
if 'method' not in kwds: if 'method' not in kwds:
kwds['method'] = default.MULTIRESOLUTION_FILER kwds['method'] = default.MULTIRESOLUTION_FILTER
super(MultiresolutionFilter, self).__init__(**kwds) super(MultiresolutionFilter, self).__init__(**kwds)
self.d_in, self.d_out = d_in, d_out self.d_in, self.d_out = d_in, d_out
self.input = self.variables self.input = self.variables
......
...@@ -116,8 +116,9 @@ def test_L21_X(): ...@@ -116,8 +116,9 @@ def test_L21_X():
b, e, err = filter(d_coarse=Discretization([n_middle, 5, 5], b, e, err = filter(d_coarse=Discretization([n_middle, 5, 5],
ghosts=[2, 2, 2]), ghosts=[2, 2, 2]),
d_fine=Discretization([n_large, 5, 5]), d_fine=Discretization([n_large, 5, 5]),
method={Remesh: L21, }, method={Remesh: L2_1, },
func=func_periodic_X) func=func_periodic_X)
print b, e, err
assert b, "max(|error|)=" + str(e) + " <= " + str(err) assert b, "max(|error|)=" + str(e) + " <= " + str(err)
...@@ -125,7 +126,7 @@ def test_L21_Y(): ...@@ -125,7 +126,7 @@ def test_L21_Y():
b, e, err = filter(d_coarse=Discretization([5, n_middle, 5], b, e, err = filter(d_coarse=Discretization([5, n_middle, 5],
ghosts=[2, 2, 2]), ghosts=[2, 2, 2]),
d_fine=Discretization([5, n_large, 5]), d_fine=Discretization([5, n_large, 5]),
method={Remesh: L21, }, method={Remesh: L2_1, },
func=func_periodic_X) func=func_periodic_X)
assert b, "max(|error|)=" + str(e) + " <= " + str(err) assert b, "max(|error|)=" + str(e) + " <= " + str(err)
...@@ -134,7 +135,7 @@ def test_L21_Z(): ...@@ -134,7 +135,7 @@ def test_L21_Z():
b, e, err = filter(d_coarse=Discretization([5, 5, n_middle], b, e, err = filter(d_coarse=Discretization([5, 5, n_middle],
ghosts=[2, 2, 2]), ghosts=[2, 2, 2]),
d_fine=Discretization([5, 5, n_large]), d_fine=Discretization([5, 5, n_large]),
method={Remesh: L21, }, method={Remesh: L2_1, },
func=func_periodic_X) func=func_periodic_X)
assert b, "max(|error|)=" + str(e) + " <= " + str(err) assert b, "max(|error|)=" + str(e) + " <= " + str(err)
...@@ -181,7 +182,7 @@ def test_filter_linear(): ...@@ -181,7 +182,7 @@ def test_filter_linear():
op.setup() op.setup()
topo_coarse = op.discreteFields[f].topology topo_coarse = op.discreteFields[f].topology
topo_fine = [t for t in f.discreteFields.keys() 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.initialize(topo=topo_fine)
f_out = f.discreteFields[topo_coarse] f_out = f.discreteFields[topo_coarse]
op.apply(simu) op.apply(simu)
...@@ -207,7 +208,7 @@ def test_filter_l2_1(): ...@@ -207,7 +208,7 @@ def test_filter_l2_1():
op.setup() op.setup()
topo_coarse = op.discreteFields[f].topology topo_coarse = op.discreteFields[f].topology
topo_fine = [t for t in f.discreteFields.keys() 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.initialize(topo=topo_fine)
f_out = f.discreteFields[topo_coarse] f_out = f.discreteFields[topo_coarse]
op.apply(simu) op.apply(simu)
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """setup.py file for @PYPACKAGE_NAME@
setup.py file for @PYPACKAGE_NAME@
""" """
from setuptools import find_packages from setuptools import find_packages
...@@ -16,26 +15,48 @@ import fnmatch ...@@ -16,26 +15,48 @@ import fnmatch
# tools to deal with fortran dependencies. # tools to deal with fortran dependencies.
import sys import sys
sys.path.append('@CMAKE_SOURCE_DIR@/') sys.path.append('@CMAKE_BINARY_DIR@/')
import sort_f90 import sort_f90
enable_cpp = "@WITH_LIB_CXX@" # --- Check if c++ interface is enabled ---
enable_cpp = "@USE_CXX@"
if enable_cpp: if enable_cpp:
swig_executable = find_executable("@SWIG_EXECUTABLE@") swig_executable = find_executable("@SWIG_EXECUTABLE@")
def parseCMakeVar(var): def parseCMakeVar(var):
"""post-process cmake list-like variable
Example::
a = parseCMakeVar("var1;var2;var3;")
# --> a = ['var', 'var2', 'var3']
"""
if var != "": 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: else:
return [] return []
def parseCMakeDefines(var): 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) defines = parseCMakeVar(var)
if defines == None: if defines is None:
return None return None
# regex to match compiler defines like -DMACRO_NAME or
# regex to match compiler defines like -DMACRO_NAME or -DMACRO_NAME = MACRO_VALUE # -DMACRO_NAME = MACRO_VALUE
p = re.compile('\s*(?:-D)?\s*(\w+)(?:\s*=\s*(\w+))?\s*') p = re.compile('\s*(?:-D)?\s*(\w+)(?:\s*=\s*(\w+))?\s*')
res = list() res = list()
...@@ -44,26 +65,56 @@ def parseCMakeDefines(var): ...@@ -44,26 +65,56 @@ def parseCMakeDefines(var):
if m: if m:
res.append(m.group(1,2)) res.append(m.group(1,2))
else: else:
print "\tWarning: Could extract cmake define from '",d,"'." print "\tWarning: Could extract cmake define from '", d, "'."
return res return res
# --- external libraries to be linked with ---
hysop_link_libraries = parseCMakeVar("@HYSOP_LINK_LIBRARIES@") hysop_link_libraries = parseCMakeVar("@HYSOP_LINK_LIBRARIES@")
hysop_link_libraries_names = set([]) #hysop_link_libraries_names = set([])
hysop_link_libraries_dirs = set([]) #hysop_link_libraries_dirs = set([])
# use set to avoid dupl. # use set to avoid dupl.
link_list = "" #link_list = ""
for lib in hysop_link_libraries: # for lib in hysop_link_libraries:
hysop_link_libraries_names.add(os.path.basename(lib)) # hysop_link_libraries_names.add(os.path.basename(lib))
hysop_link_libraries_dirs.add(os.path.dirname(lib)) # hysop_link_libraries_dirs.add(os.path.dirname(lib))
link_list += lib + " " # link_list += lib + " "
hysop_link_libraries_names = list(hysop_link_libraries_names) # hysop_link_libraries_names = list(hysop_link_libraries_names)
hysop_link_libraries_dirs = list(hysop_link_libraries_dirs) # hysop_link_libraries_dirs = list(hysop_link_libraries_dirs)
def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None, def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None,
libdir=None, libs=None, debug_mode=0): libdir=None, libs=None, debug_mode=0):
"""Create a new f2py module from fortran files """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: if sources is None:
sources = [] sources = []
assert src_dirs is not None assert src_dirs is not None
...@@ -71,29 +122,29 @@ def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None, ...@@ -71,29 +122,29 @@ def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None,
for sdir in src_dirs: for sdir in src_dirs:
sources += glob.glob(os.path.join(sdir, '*.f95')) sources += glob.glob(os.path.join(sdir, '*.f95'))
sources += glob.glob(os.path.join(sdir, '*.f90')) sources += glob.glob(os.path.join(sdir, '*.f90'))
f2py_options = ['--no-lower', '--no-wrap-functions']
options = []
# Reorder source list with fortran modules # Reorder source list with fortran modules
# dependencies. It seems that this is not taken into # dependencies. It seems that this is not taken into
# account in f2py or distutils. # account in f2py or distutils.
if pyf_file is not None: if pyf_file is not None:
sources.append(pyf_file) sources.append(pyf_file)
sources = sort_f90.sort(sources) 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')) options.append(('F2PY_REPORT_ON_ARRAY_COPY', '1'))
if os.uname()[0] == 'Linux': if os.uname()[0] == 'Linux':
options.append(('F2PY_REPORT_ATEXIT', '1')) 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: # --- set include dir ---
while inc_dir.count('') > 0: inc_dir = parseCMakeVar("@MPI_Fortran_INCLUDE_PATH@")
inc_dir.remove('') inc_dir.append('@CMAKE_Fortran_MODULE_DIRECTORY@')
inc_dir.append('@CMAKE_BINARY_DIR@/Modules') # --- set compilation flags ---
fortran_flags = ['@Fortran_FLAGS@'] fortran_flags = ['@Fortran_FLAGS@']
#includes = parseCMakeVar("@FORTRAN_INCLUDE_DIRS@") #includes = parseCMakeVar("@FORTRAN_INCLUDE_DIRS@")
#if(includes != None): #if(includes != None):
#for exti in includes: # for exti in includes:
#inc_dir.append(exti) #i nc_dir.append(exti)
#libs += hysop_link_libraries_names #libs += hysop_link_libraries_names
#libdir += hysop_link_libraries_dirs #libdir += hysop_link_libraries_dirs
# we trust cmake for external libraries and # we trust cmake for external libraries and
...@@ -114,37 +165,58 @@ def create_fortran_extension(name, pyf_file=None, src_dirs=None, sources=None, ...@@ -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): def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None):
"""Create a python module from C++ files, using swig """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_dir = os.path.join('@CMAKE_SOURCE_DIR@', 'swig')
swig_config_file = os.path.join(swig_dir, name+'.i') swig_config_file = os.path.join(swig_dir, name + '.i')
include_dirs = set(inc_dirs) include_dirs = set(inc_dirs)
if sources is None: if sources is None:
sources = [] sources = []
if(src_dirs == None): assert src_dirs is not None or inc_dirs is not None
assert(inc_dirs != None) if(src_dirs is None):
for idir in inc_dirs: assert(inc_dirs is not None)
#sources += glob.glob(os.path.join(idir, '**/*.cpp'), recursive=True) for idir in inc_dirs:
for root, dirnames, filenames in os.walk(idir): #sources += glob.glob(os.path.join(idir, '**/*.cpp'), recursive=True)
for filename in fnmatch.filter(filenames, '*.cpp'): for root, dirnames, filenames in os.walk(idir):
sources.append(os.path.join(root, filename)) for filename in fnmatch.filter(filenames, '*.cpp'):
else: sources.append(os.path.join(root, filename))
for sdir in src_dirs: else:
sources += glob.glob(os.path.join(sdir, '*.cpp')) for sdir in src_dirs:
#else: sources += glob.glob(os.path.join(sdir, '*.cpp'))
#for f in sources:
#include_dirs.add(os.path.dirname(f))
sources.insert(0,swig_config_file) sources.insert(0, swig_config_file)
include_dirs = list(include_dirs) include_dirs = list(include_dirs)
name = 'hysop._' + name name = 'hysop._' + name
swig_opts = ['-I' + swig_dir, swig_opts = ['-I' + swig_dir,
'-O', '-Wextra', '-Werror', '-O', '-Wextra', '-Werror',
'-c++', '-extranative', '-safecstrings'] '-c++', '-extranative', '-safecstrings']
extern_includes = parseCMakeVar("@CXX_EXT_INCLUDES@") extern_includes = parseCMakeVar("@CXX_EXT_INCLUDES@")
if(extern_includes != None): if(extern_includes is not None):
for exti in extern_includes: for exti in extern_includes:
include_dirs.append(exti) include_dirs.append(exti)
...@@ -170,33 +242,10 @@ def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None): ...@@ -170,33 +242,10 @@ def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None):
# List of modules (directories) to be included # List of modules (directories) to be included
with_test = "@WITH_TESTS@" is "ON" with_test = "@WITH_TESTS@" is "ON"
if with_test: if with_test:
packages = find_packages(exclude=["*fakef2py*", "*gpu*"],where="@CMAKE_SOURCE_DIR@") packages = find_packages(exclude=["*gpu*"], where="@CMAKE_SOURCE_DIR@")
else: else:
packages = find_packages(exclude=["*tests*","*fakef2py*", "*gpu*"],where="@CMAKE_SOURCE_DIR@") packages = find_packages(exclude=["*tests*", "*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')
if "@WITH_GPU@" is "ON": if "@WITH_GPU@" is "ON":
packages.append('hysop.gpu') packages.append('hysop.gpu')
...@@ -217,11 +266,12 @@ ext = {} ...@@ -217,11 +266,12 @@ ext = {}
if enable_fortran is "ON": if enable_fortran is "ON":
fortran_root = \ fortran_root = \
'@CMAKE_SOURCE_DIR@/hysop' '@CMAKE_SOURCE_DIR@/hysop'
hysop_libdir = ['@CMAKE_BINARY_DIR@/src'] hysop_libdir = [] ##### ['@CMAKE_BINARY_DIR@/src']
hysoplib = ['@HYSOP_LIBRARY_NAME@'] #####hysoplib = ['@HYSOP_LIBRARY_NAME@']
f2py_options = ['--no-lower'] f2py_options = ['--no-lower']
fortran_src = set([]) fortran_src = set([])
fortran_src.add('f2py/parameters.f90')
####fortran_src.add('f2py/parameters.f90')
# -- fftw fortran sources -- # -- fftw fortran sources --
withfftw = "@WITH_FFTW@" withfftw = "@WITH_FFTW@"
if withfftw is "ON": if withfftw is "ON":
...@@ -230,16 +280,12 @@ if enable_fortran is "ON": ...@@ -230,16 +280,12 @@ if enable_fortran is "ON":
#hysoplib.append('fftw3') #hysoplib.append('fftw3')
#hysoplib.append('fftw3_mpi') #hysoplib.append('fftw3_mpi')
hysop_libdir.append(fftwdir) hysop_libdir.append(fftwdir)
else:
packages.append('hysop.fakef2py')
packages.append('hysop.fakef2py.fftw2py')
# -- scales sources -- # -- scales sources --
withscales = '@WITH_SCALES@' withscales = '@WITH_SCALES@'
if withscales is "ON": if withscales is "ON":
fortran_src.add('f2py/scales2py.f90') fortran_src.add('f2py/scales2py.f90')
else:
packages.append('hysop.fakef2py')
packages.append('hysop.fakef2py.scales2py')
# -- set full path to fortran sources -- # -- set full path to fortran sources --
fortran_src = list(fortran_src) fortran_src = list(fortran_src)
for i in xrange(len(fortran_src)): for i in xrange(len(fortran_src)):
...@@ -247,14 +293,15 @@ if enable_fortran is "ON": ...@@ -247,14 +293,15 @@ if enable_fortran is "ON":
# === Draft for future implementation of fortran interface === # === Draft for future implementation of fortran interface ===
# -- f2py signature file -- # -- 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 -- # -- list of directories which contains fortran sources --
# those dirs must be in hysop package directory # path must be relative to hysop package directory
subdirs = ['fortran',] subdirs = ['common_f', ]
num_dirs = [] num_dirs = []
for sd in subdirs: for sd in subdirs:
num_dirs.append(os.path.join(fortran_root, sd)) num_dirs.append(os.path.join(fortran_root, sd))
num_dirs.append('@GENERATED_FORTRAN_FILES_DIR@')
# create python interface to fortran sources # create python interface to fortran sources
# For the moment, it includes the 'old' interface # For the moment, it includes the 'old' interface
# to scales and fftw (in sources) and the new # to scales and fftw (in sources) and the new
...@@ -262,8 +309,8 @@ if enable_fortran is "ON": ...@@ -262,8 +309,8 @@ if enable_fortran is "ON":
ext['f2hysop'] = create_fortran_extension( ext['f2hysop'] = create_fortran_extension(
name='hysop.f2hysop', name='hysop.f2hysop',
sources=fortran_src, sources=fortran_src,
libdir=hysop_libdir, #libdir=hysop_libdir,
libs=hysoplib, #libs=hysoplib,
pyf_file=pyf_file, pyf_file=pyf_file,
src_dirs=num_dirs) src_dirs=num_dirs)
...@@ -283,12 +330,13 @@ if enable_cpp is "ON": ...@@ -283,12 +330,13 @@ if enable_cpp is "ON":
swig_include_dirs = [os.path.join('@CMAKE_SOURCE_DIR@','swig')] swig_include_dirs = [os.path.join('@CMAKE_SOURCE_DIR@','swig')]
cpp_include_dirs = ['src/fftw','src/hysop++/src'] cpp_include_dirs = ['src/fftw','src/hysop++/src']
for id in cpp_include_dirs: for d in cpp_include_dirs:
swig_include_dirs.append(os.path.join('@CMAKE_SOURCE_DIR@', id)) swig_include_dirs.append(os.path.join('@CMAKE_SOURCE_DIR@', d))
ext = {} ext = {}
cpp2hysop = "@CPP_2_HYSOP@" 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: for ex in ext:
ext_modules.append(ext[ex]) ext_modules.append(ext[ex])
......
""" """
Dependency scanner for F90/95 modules. Dependency scanner for F90/95 modules.
The sort function provided below sorts fortran source files in order of The sort function provided below sorts fortran source files in order of
increasing dependency. That is, the sorting order makes sure that modules are increasing dependency. That is, the sorting order makes sure that modules are
compiled before they are USE'd. compiled before they are USE'd.
See: See:
http://scipy.org/scipy/numpy/ticket/752 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. module. The copyright notice for Scons is included below.
:Author: David Huard, Pearu Peterson :Author: David Huard, Pearu Peterson
:Date: May, 2008 :Date: May, 2008
"""
""" Copyright (c) 2001, 2002, 2003, 2004, 2005,
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 2006, 2007, 2008 The SCons Foundation
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to permit persons to whom the Software is furnished to do so, subject to
the following conditions: the following conditions:
The above copyright notice and this permission notice shall be included The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software. in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
""" """
import re, copy, os import re
import warnings
__all__ = ['FortranFileSorter', 'sort'] __all__ = ['FortranFileSorter', 'sort']
""" """
Regular expression for a module name Regular expression for a module name
------------------------------------ ------------------------------------
An alphanumeric word not beginning with a numeric character. An alphanumeric word not beginning with a numeric character.
[a-z_] : a letter or an underscore [a-z_] : a letter or an underscore
\w* : any number of alphanumeric characters \w* : any number of alphanumeric characters
""" """
modulename = """[a-z_]\w*""" modulename = """[a-z_]\w*"""
""" """
Regular expression for a USE statement Regular expression for a USE statement
-------------------------------------- --------------------------------------
...@@ -95,8 +92,8 @@ Here is a breakdown of the regex: ...@@ -95,8 +92,8 @@ Here is a breakdown of the regex:
(modulename_regex) : match the module name that is being USE'd, see above. (modulename_regex) : match the module name that is being USE'd, see above.
""" """
use_regex = \ use_regex = \
"(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(%s)"%\ "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(%s)" %\
modulename modulename
""" """
...@@ -123,7 +120,7 @@ Here is a breakdown of the regex: ...@@ -123,7 +120,7 @@ Here is a breakdown of the regex:
that make up the defined module name and that make up the defined module name and
save it in a group 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. ...@@ -203,18 +200,20 @@ remove all the comments.
.*$ : ignore the rest of the line .*$ : ignore the rest of the line
""" """
comment_regex = r'(^.*)!?.*$' comment_regex = r'(^.*)!?.*$'
class FortranFileSorter: class FortranFileSorter:
"""Given a list of fortran 90/95 files, return a file list sorted by module """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, dependency. If a file depends on a parent through a USE MODULE statement,
this parent file will occur earlier in the list. this parent file will occur earlier in the list.
Parameters Parameters
---------- ----------
files : sequence files : sequence
The sequence of file names to be sorted. The sequence of file names to be sorted.
""" """
def __init__(self, files): def __init__(self, files):
self.files = files self.files = files
self.use_regex = re.compile(use_regex, re.MULTILINE) self.use_regex = re.compile(use_regex, re.MULTILINE)
...@@ -239,11 +238,11 @@ class FortranFileSorter: ...@@ -239,11 +238,11 @@ class FortranFileSorter:
def match_defined(self, code): def match_defined(self, code):
"""Return the set of defined module in a code string.""" """Return the set of defined module in a code string."""
return set(map(str.lower, self.def_regex.findall(code))) return set(map(str.lower, self.def_regex.findall(code)))
def match_included(self, code): def match_included(self, code):
"""Return the set of included files in a code string.""" """Return the set of included files in a code string."""
return set(self.include_regex.findall(code)) return set(self.include_regex.findall(code))
def externals(self): def externals(self):
"""Return the modules that are used but not defined in the list of """Return the modules that are used but not defined in the list of
files.""" files."""
...@@ -252,7 +251,7 @@ class FortranFileSorter: ...@@ -252,7 +251,7 @@ class FortranFileSorter:
all_used = reduce(set.union, self.mod_used.values()) all_used = reduce(set.union, self.mod_used.values())
all_defined = reduce(set.union, self.mod_defined.values()) all_defined = reduce(set.union, self.mod_defined.values())
return all_used.difference(all_defined) return all_used.difference(all_defined)
def scan(self): def scan(self):
"""For each file, identify the set of modules that are """For each file, identify the set of modules that are
defined, used but not defined in the same file, and the set of defined, used but not defined in the same file, and the set of
...@@ -263,28 +262,28 @@ class FortranFileSorter: ...@@ -263,28 +262,28 @@ class FortranFileSorter:
self.included = {} self.included = {}
for f in self.files: for f in self.files:
code = self.read_code(f) code = self.read_code(f)
code = self.uncomment(code) code = self.uncomment(code)
self.mod_defined[f] = self.match_defined(code) self.mod_defined[f] = self.match_defined(code)
self.mod_used[f] = self.match_used(code) self.mod_used[f] = self.match_used(code)
self.included[f] = self.match_included(code) self.included[f] = self.match_included(code)
# Remove from used the modules defined internally. # Remove from used the modules defined internally.
# That is, keep elements in used but not in defined. # That is, keep elements in used but not in defined.
self.mod_used[f].difference_update(self.mod_defined[f]) self.mod_used[f].difference_update(self.mod_defined[f])
# TODO : Deal with include (do we have too?) # TODO : Deal with include (do we have too?)
def sort(self): def sort(self):
"""Sort the files in order of dependency. """Sort the files in order of dependency.
""" """
ordered_list = [] ordered_list = []
# Take care of modules not defined anywhere in the files. eg. # 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. # start.
defined = self.externals() defined = self.externals()
# This cycles through the files, and appends those whose dependencies # This cycles through the files, and appends those whose dependencies
# are already satisfied by the files in the ordered list. # are already satisfied by the files in the ordered list.
remaining = set(self.files) remaining = set(self.files)
goon = True goon = True
while goon: while goon:
...@@ -292,21 +291,20 @@ class FortranFileSorter: ...@@ -292,21 +291,20 @@ class FortranFileSorter:
for f in remaining: for f in remaining:
dependencies_satisfied = self.mod_used[f].issubset(defined) dependencies_satisfied = self.mod_used[f].issubset(defined)
if dependencies_satisfied: if dependencies_satisfied:
ordered_list.append(f) ordered_list.append(f)
defined.update(self.mod_defined[f]) defined.update(self.mod_defined[f])
goon = True goon = True
remaining.difference_update(set(ordered_list)) remaining.difference_update(set(ordered_list))
ordered_list.extend(list(remaining)) ordered_list.extend(list(remaining))
return ordered_list return ordered_list
def sort(files): def sort(files):
"""Given a list of fortran 90/95 files, return a file list sorted by module """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, dependency. If a file depends on a parent through a USE MODULE statement,
this parent file will occur earlier in the list. this parent file will occur earlier in the list.
Parameters Parameters
---------- ----------
files : sequence files : sequence
...@@ -314,13 +312,10 @@ def sort(files): ...@@ -314,13 +312,10 @@ def sort(files):
""" """
FS = FortranFileSorter(files) FS = FortranFileSorter(files)
FS.scan() FS.scan()
return FS.sort() return FS.sort()
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
print sys.argv[1:] print sys.argv[1:]
sort(sys.argv[1:]) sort(sys.argv[1:])
...@@ -15,7 +15,7 @@ if(WITH_FFTW) ...@@ -15,7 +15,7 @@ if(WITH_FFTW)
list(APPEND ${HYSOP_LIBRARY_NAME}_SRCDIRS fftw) list(APPEND ${HYSOP_LIBRARY_NAME}_SRCDIRS fftw)
endif() endif()
if(WITH_LIB_CXX) if(USE_CXX)
list(APPEND ${HYSOP_LIBRARY_NAME}_SRCDIRS hysop++/src) list(APPEND ${HYSOP_LIBRARY_NAME}_SRCDIRS hysop++/src)
endif() endif()
...@@ -102,4 +102,4 @@ if(WITH_FORTRAN_TESTS) ...@@ -102,4 +102,4 @@ if(WITH_FORTRAN_TESTS)
target_link_libraries(${EXE_NAME} ${HYSOP_LIBRARY_NAME}) target_link_libraries(${EXE_NAME} ${HYSOP_LIBRARY_NAME})
target_link_libraries(${EXE_NAME} ${HYSOP_LINK_LIBRARIES}) target_link_libraries(${EXE_NAME} ${HYSOP_LINK_LIBRARIES})
endif() endif()
endif() endif()
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment