Skip to content

Commit

Permalink
First steps toward Python 3.11 & Cython3
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterMeisrimelModelon committed Jan 11, 2024
1 parent 7f88eb0 commit 3bb9c8e
Show file tree
Hide file tree
Showing 20 changed files with 99 additions and 67 deletions.
2 changes: 1 addition & 1 deletion doc/sphinx/source/markup.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def mark_solvers():
elif solver[1] == "DAE_OVER":
file.write(' mod = '+problem_name+'(res, y0, yd0, t0)\n\n')
else:
print "Unknown solver type"
print("Unknown solver type")
file.write('.. note::\n\n')
file.write(' For complex problems, it is recommended to check the available :doc:`examples <examples>` and the documentation in the problem class, :class:`'+problem_name+ ' <assimulo.problem.'+problem_name+'>`. It is also recommended to define your problem as a subclass of :class:`'+problem_name+ ' <assimulo.problem.'+problem_name+'>`.\n\n')
file.write('.. warning::\n\n')
Expand Down
55 changes: 33 additions & 22 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#from distutils.core import setup, Extension
import numpy as np
import logging
import sys
import os
import shutil as SH
import shutil
import ctypes.util
import argparse
from os.path import isfile, join
import numpy as np
import numpy.distutils.core as ndc

def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
Expand Down Expand Up @@ -76,7 +77,7 @@ def remove_prefix(name, prefix):
import numpy.distutils as nd

try:
from Cython.Distutils import build_ext
# from Cython.Distutils import build_ext ## TODO: obsolete?
from Cython.Build import cythonize
except ImportError:
msg="Please upgrade to a newer Cython version, >= 0.18."
Expand Down Expand Up @@ -105,7 +106,7 @@ def create_dir(self,d):
def copy_file(self,fi, to_dir):
# copies only files not directories
if not os.path.isdir(fi):
SH.copy2(fi, to_dir)
shutil.copy2(fi, to_dir)
def copy_all_files(self,file_list, from_dir, to_dir):
logging.debug('fromdir {} todir {}'.format(from_dir,to_dir))
for f in file_list:
Expand All @@ -114,8 +115,8 @@ def copy_all_files(self,file_list, from_dir, to_dir):
else:
self.copy_file(f,to_dir)
def __init__(self,args, thirdparty_methods):
# args[0] are optinal arguments given above
# args[1] are argumenets passed to distutils
# args[0] are optional arguments given above
# args[1] are arguments passed to distutils
self.distutil_args=args[1]
if args[0].prefix:
self.prefix = args[0].prefix.replace('/',os.sep) # required in this way for cygwin etc.
Expand Down Expand Up @@ -167,10 +168,11 @@ def fortran_compiler_flags(self):
nd.fcompiler.intel.IntelVisualFCompiler.get_flags=fortran_compiler_flags

self.platform = 'linux'
if 'win' in sys.platform: self.platform = 'win'
if 'darwin' in sys.platform: self.platform = 'mac'
if 'win' in sys.platform:
self.platform = 'win'
if 'darwin' in sys.platform:
self.platform = 'mac'

self.is_python3 = True if sys.version_info.major >= 3 else False
logging.debug('Platform {}'.format(self.platform))

if args[0].sundials_home:
Expand Down Expand Up @@ -241,8 +243,9 @@ def create_assimulo_dirs_and_populate(self):
for f in self.filelist_thirdparty.items():
logging.debug('Thirdparty method {} file {} copied'.format(f[0],f[1]))
self.copy_all_files(f[1],os.path.join("thirdparty", f[0]), self.desThirdParty[f[0]])
license_name = f[0].upper() if f[0].upper() != "RADAU5" else "HAIRER"
try:
SH.copy2(os.path.join("thirdparty",f[0],"LICENSE_{}".format(f[0].upper())),self.desLib)
shutil.copy2(os.path.join("thirdparty", f[0], "LICENSE_{}".format(license_name)), self.desLib)
except IOError:
logging.warning('No license file {} found.'.format("LICENSE_{}".format(f[0].upper())))

Expand All @@ -262,8 +265,8 @@ def create_assimulo_dirs_and_populate(self):
if self.extra_fortran_link_files:
for extra_fortran_lib in self.extra_fortran_link_files:
path_extra_fortran_lib = ctypes.util.find_library(extra_fortran_lib)
if path_extra_fortran_lib != None:
SH.copy2(path_extra_fortran_lib,self.desSrc)
if path_extra_fortran_lib is not None:
shutil.copy2(path_extra_fortran_lib,self.desSrc)
else:
logging.debug("Could not find Fortran link file: "+str(extra_fortran_lib))

Expand Down Expand Up @@ -469,18 +472,24 @@ def cython_extensionlists(self):

# Cythonize main modules
ext_list = cythonize([os.path.join("assimulo", "explicit_ode.pyx")],
include_path=[".", "assimulo"], force = True)
include_path=[".", "assimulo"],
force = True,
compiler_directives={'language_level' : "3str"})
ext_list[-1].include_dirs += ["assimulo", self.incdirs]
ext_list[-1].sources += [os.path.join("assimulo", "ode_event_locator.c")]

remaining_pyx = ["algebraic", "implicit_ode", "ode", "problem", "special_systems", "support"]
ext_list += cythonize([os.path.join("assimulo", "{}.pyx".format(x)) for x in remaining_pyx],
include_path=[".", "assimulo"], force = True)
include_path=[".", "assimulo"],
force = True,
compiler_directives={'language_level' : "3str"})

# Cythonize Solvers
# Euler
ext_list += cythonize([os.path.join("assimulo", "solvers", "euler.pyx")],
include_path=[".", "assimulo", os.path.join("assimulo", "solvers")], force = True)
include_path=[".", "assimulo", os.path.join("assimulo", "solvers")],
force = True,
compiler_directives={'language_level' : "3str"},)

# SUNDIALS
if self.with_SUNDIALS:
Expand All @@ -491,7 +500,9 @@ def cython_extensionlists(self):
#CVode and IDA
ext_list += cythonize(["assimulo" + os.path.sep + "solvers" + os.path.sep + "sundials.pyx"],
include_path=[".","assimulo","assimulo" + os.sep + "lib"],
compile_time_env=compile_time_env, force=True)
compile_time_env=compile_time_env,
force=True,
compiler_directives={'language_level' : "3str"})
ext_list[-1].include_dirs = [np.get_include(), "assimulo","assimulo"+os.sep+"lib", self.incdirs]
ext_list[-1].library_dirs = [self.libdirs]

Expand All @@ -510,7 +521,9 @@ def cython_extensionlists(self):
#Kinsol
ext_list += cythonize(["assimulo"+os.path.sep+"solvers"+os.path.sep+"kinsol.pyx"],
include_path=[".","assimulo","assimulo"+os.sep+"lib"],
compile_time_env=compile_time_env, force=True)
compile_time_env=compile_time_env,
force=True,
compiler_directives={'language_level' : "3str"})
ext_list[-1].include_dirs = [np.get_include(), "assimulo","assimulo"+os.sep+"lib", self.incdirs]
ext_list[-1].library_dirs = [self.libdirs]
ext_list[-1].libraries = ["sundials_kinsol", "sundials_nvecserial"]
Expand All @@ -523,7 +536,8 @@ def cython_extensionlists(self):
## Radau5
ext_list += cythonize([os.path.join("assimulo","thirdparty","radau5","radau5ode.pyx")],
include_path=[".", "assimulo", os.path.join("assimulo", "lib")],
force = True)
force = True,
compiler_directives={'language_level' : "3str"})
ext_list[-1].include_dirs = [np.get_include(), "assimulo", os.path.join("assimulo", "lib"),
os.path.join("assimulo","thirdparty","radau5"),
self.incdirs]
Expand Down Expand Up @@ -573,8 +587,7 @@ def cython_extensionlists(self):
el.extra_compile_args += self.flag_32bit + self.extra_c_flags

for el in ext_list:
if self.is_python3:
el.cython_directives = {"language_level": 3}
# el.cython_directives = {"language_level": "3str"} ## TODO: Redundant?
el.extra_link_args += extra_link_flags
return ext_list

Expand Down Expand Up @@ -718,7 +731,6 @@ def fortran_extensionlists(self):
for pck in thirdparty_methods for place in ['thirdparty','lib']]
logging.debug(license_info)

import numpy.distutils.core as ndc
ndc.setup(name=NAME,
version=VERSION,
license=LICENSE,
Expand All @@ -741,4 +753,3 @@ def fortran_extensionlists(self):

if change_dir:
os.chdir(curr_dir) #Change back to original directory

2 changes: 1 addition & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def wrap(func):

try:
import os
curr_dir = os.path.dirname(os.path.abspath(__file__));
curr_dir = os.path.dirname(os.path.abspath(__file__))
_fpath=os.path.join(curr_dir,'version.txt')
with open(_fpath, 'r') as f:
__version__=f.readline().strip()
Expand Down
2 changes: 2 additions & 0 deletions src/algebraic.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION

import numpy as N
cimport numpy as N
from timeit import default_timer as timer
Expand Down
6 changes: 4 additions & 2 deletions src/explicit_ode.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION

from ode cimport ODE
from problem import Explicit_Problem, Delay_Explicit_Problem, SingPerturbed_Problem, cExplicit_Problem

Expand Down Expand Up @@ -48,7 +50,7 @@ cdef void c2py_d(N.ndarray[double, ndim=1, mode='c'] dest, double* source, int d
"""Copy (double *) C vector to 1D numpy array."""
memcpy(N.PyArray_DATA(dest), source, dim*sizeof(double))

cdef int callback_event(int n_y, int n_g, double t, double* y_in, double* g_out, void* f_event_EXT):
cdef int callback_event(int n_y, int n_g, double t, double* y_in, double* g_out, void* f_event_EXT) noexcept:
"""Event indicator callback function to event_locator.c"""
cdef N.ndarray[double, ndim=1, mode="c"]y_py = N.empty(n_y, dtype = N.double)
c2py_d(y_py, y_in, n_y)
Expand All @@ -58,7 +60,7 @@ cdef int callback_event(int n_y, int n_g, double t, double* y_in, double* g_out,
py2c_d(g_out, g_high, n_g)
return ret

cdef int callback_interp(int n, double t, double* y_out, void* f_interp_EXT):
cdef int callback_interp(int n, double t, double* y_out, void* f_interp_EXT) noexcept:
"""Interpolation callback function to event_locator.c"""
y_interp = (<object>f_interp_EXT)(t)
py2c_d(y_out, y_interp, n)
Expand Down
2 changes: 2 additions & 0 deletions src/implicit_ode.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION

from ode cimport ODE
from problem import Implicit_Problem, cImplicit_Problem, Overdetermined_Problem
from problem import cExplicit_Problem
Expand Down
9 changes: 5 additions & 4 deletions src/lib/sundials_callbacks_ida_cvode.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import cython
import traceback
from assimulo.exception import AssimuloRecoverableError

cdef int cv_rhs(realtype t, N_Vector yv, N_Vector yvdot, void* problem_data):
Expand Down Expand Up @@ -750,11 +751,11 @@ cdef void cv_err(int error_code, const char *module, const char *function, char
cdef ProblemData pData = <ProblemData>problem_data

if error_code > 0 and pData.verbose > 0: #Warning
print '[CVode Warning]', msg
print('[CVode Warning]', msg)

if pData.verbose > 2: #Verbosity is greater than NORMAL, print warnings and errors
if error_code < 0: #Error
print '[CVode Error]', msg
print('[CVode Error]', msg)

cdef void ida_err(int error_code, const char *module, const char *function, char *msg, void *problem_data):
"""
Expand All @@ -763,11 +764,11 @@ cdef void ida_err(int error_code, const char *module, const char *function, char
cdef ProblemData pData = <ProblemData>problem_data

if error_code > 0 and pData.verbose > 0: #Warning
print '[IDA Warning]', msg
print('[IDA Warning]', msg)

if pData.verbose > 2: #Verbosity is greater than NORMAL, print warnings and errors
if error_code < 0: #Error
print '[IDA Error]', msg
print('[IDA Error]', msg)


cdef class ProblemData:
Expand Down
17 changes: 9 additions & 8 deletions src/lib/sundials_callbacks_kinsol.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import cython
import traceback
from assimulo.exception import AssimuloRecoverableError

IF SUNDIALS_VERSION >= (3,0,0):
Expand Down Expand Up @@ -229,9 +230,9 @@ cdef void kin_err(int err_code, const char *module, const char *function, char *
else:
category = 0

print "Error occured in <function: %s>."%function
print "<message: %s>"%msg
#print "<functionNorm: %g, scaledStepLength: %g, tolerance: %g>"%(fnorm, snorm, pData.TOL)
print("Error occured in <function: %s>."%function)
print("<message: %s>"%msg)
#print("<functionNorm: %g, scaledStepLength: %g, tolerance: %g>"%(fnorm, snorm, pData.TOL))


cdef void kin_info(const char *module, const char *function, char *msg, void *eh_data):
Expand All @@ -246,8 +247,8 @@ cdef void kin_info(const char *module, const char *function, char *msg, void *eh

pData.log.append([module, function, msg])

#print "KinsolInfo <calling_function:%s>"%function
#print "<message: %s>"%msg
#print("KinsolInfo <calling_function:%s>"%function)
#print("<message: %s>"%msg)
"""
# Get the number of iterations
KINGetNumNonlinSolvIters(kin_mem, &nniters)
Expand All @@ -262,9 +263,9 @@ cdef void kin_info(const char *module, const char *function, char *msg, void *eh
if ("KINSolInit" in function or "KINSol" in function) and "nni" in msg:
print "<iteration_index:%d>"%nniters
print "ivs", N_VGetArrayPointer(kin_mem->kin_uu), block->n);
print "<scaled_residual_norm:%E>", kin_mem->kin_fnorm);
print("<iteration_index:%d>"%nniters)
print("ivs", N_VGetArrayPointer(kin_mem->kin_uu), block->n))
print("<scaled_residual_norm:%E>", kin_mem->kin_fnorm))
print "residuals",
realtype* f = N_VGetArrayPointer(kin_mem->kin_fval);
f[i]*residual_scaling_factors[i]
Expand Down
8 changes: 5 additions & 3 deletions src/ode.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION

import numpy as N
cimport numpy as N
from timeit import default_timer as timer
Expand Down Expand Up @@ -555,9 +557,9 @@ cdef class ODE:
"""
cdef i = 0
for i in self.event_data:
print 'Time, t = %e'%i[0]
print ' Event info, ', i[1]
print 'Number of events: ', len(self.event_data)
print('Time, t = %e'%i[0])
print('Event info, ', i[1])
print('Number of events: ', len(self.event_data))

def print_statistics(self, verbose=NORMAL):
"""
Expand Down
2 changes: 2 additions & 0 deletions src/problem.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION

import numpy as N
cimport numpy as N

Expand Down
5 changes: 4 additions & 1 deletion src/solvers/euler.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION

cimport numpy as N
import numpy as N
import numpy.linalg as LIN
Expand Down Expand Up @@ -363,7 +365,8 @@ cdef class ImplicitEuler(Explicit_ODE):
"""
This calculates the next step in the integration.
"""
cdef double new_norm, old_norm
cdef double new_norm = 0
cdef double old_norm = 0
cdef double tn1 = t+h
cdef N.ndarray yn = y.copy() #Old y
#cdef N.ndarray yn1 = y.copy() #First newton guess
Expand Down
2 changes: 1 addition & 1 deletion src/solvers/kinsol.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ cdef class KINSOL(Algebraic):
if flag < 0:
raise KINSOLError(flag)
if flag == KIN_STEP_LT_STPTOL:
print 'Scaled step length too small. Either an approximate solution or a local minimum is reached. Check value of residual.'
print('Scaled step length too small. Either an approximate solution or a local minimum is reached. Check value of residual.')

self.store_statistics()

Expand Down
4 changes: 2 additions & 2 deletions src/solvers/odepack.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def integrate_start(self, t, y):
"""
Helper program for the initialization of LSODAR
"""
#print ' We have rkstarter {} and rkstarter_active {}'.format(self.rkstarter, self._rkstarter_active)
#print('We have rkstarter {} and rkstarter_active {}'.format(self.rkstarter, self._rkstarter_active))
if not(self.rkstarter>1 and self._rkstarter_active):
# first call or classical restart after a discontinuity
ISTATE=1
Expand Down Expand Up @@ -409,7 +409,7 @@ def state_events(t,y):
opts["output_index"] = output_index
# deciding on restarting options
self._rkstarter_active = True if ISTATE == 3 and self.rkstarter > 1 else False
#print 'rkstarter_active set to {} and ISTATE={}'.format(self._rkstarter_active, ISTATE)
#print('rkstarter_active set to {} and ISTATE={}'.format(self._rkstarter_active, ISTATE))

#Retrieving statistics
self.statistics["nstatefcns"] += IWORK[9]
Expand Down
Loading

0 comments on commit 3bb9c8e

Please sign in to comment.