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
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}")
......
......@@ -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 ..
......@@ -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
......@@ -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()
{'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
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):
"""
......
......@@ -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
......
......@@ -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)
......
#!/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])
......
"""
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:])
......@@ -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()
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