From cc48c366c0e660f0592a98028c4b8044efadd7fa Mon Sep 17 00:00:00 2001 From: mloubout Date: Thu, 20 Jun 2024 11:08:36 -0400 Subject: [PATCH 1/3] deps: support numpy 2.0 --- .github/workflows/pytest-core-nompi.yml | 2 +- requirements.txt | 2 +- setup.py | 27 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pytest-core-nompi.yml b/.github/workflows/pytest-core-nompi.yml index 553fbccb15..f3189f8aaf 100644 --- a/.github/workflows/pytest-core-nompi.yml +++ b/.github/workflows/pytest-core-nompi.yml @@ -163,8 +163,8 @@ jobs: if: "!contains(matrix.name, 'docker')" run: | pip install ${{ env.PIPFLAGS }} --upgrade pip - pip install ${{ env.PIPFLAGS }} -e .[tests] pip install ${{ env.PIPFLAGS }} sympy==${{matrix.sympy}} + pip install ${{ env.PIPFLAGS }} -e .[tests] - name: Check configuration run: | diff --git a/requirements.txt b/requirements.txt index acfe76d53c..0ebd994b1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ pip>=9.0.1 -numpy>1.16,<2.0 +numpy>1.16,<2.1 sympy>=1.9,<1.13 psutil>=5.1.0,<7.0 py-cpuinfo<10 diff --git a/setup.py b/setup.py index 5d22060ba0..ca69dfcc0a 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,37 @@ import versioneer import os +import sys +import pkg_resources from setuptools import setup, find_packages + +def numpy_compat(required): + new_reqs = [r for r in required if "numpy" not in r and "sympy" not in r] + if sys.version_info < (3, 9): + # Numpy 2.0 requires python > 3.8 + new_reqs.extend(["sympy>=1.9,<1.13", "numpy>1.16,<2.0"]) + return new_reqs + + # Due to api changes in numpy 2.0, it requires sympy 1.12.1 at the minimum + # Check if sympy is installed and enforce numpy version accordingly. + # If sympy isn't installed, endforce sympy>=1.12.1 and numpy>=2.0 + try: + sympy_version = pkg_resources.get_distribution("sympy").version + min_ver2 = pkg_resources.parse_version("1.12.1") + if pkg_resources.parse_version(sympy_version) < min_ver2: + new_reqs.append("numpy>1.16,<2.0") + else: + new_reqs.append("numpy>=2.0") + except pkg_resources.DistributionNotFound: + new_reqs.extend(["sympy>=1.12.1", "numpy>=2.0"]) + + return new_reqs + + with open('requirements.txt') as f: required = f.read().splitlines() + required = numpy_compat(required) with open('requirements-optional.txt') as f: optionals = f.read().splitlines() From 5d6b610fd4c3575cdd9c4a1040068f4919a71973 Mon Sep 17 00:00:00 2001 From: mloubout Date: Thu, 20 Jun 2024 15:40:46 -0400 Subject: [PATCH 2/3] CI: tweak docstring test to avoid repr issues on some system --- devito/__init__.py | 10 ++++++++++ devito/arch/compiler.py | 2 ++ 2 files changed, 12 insertions(+) diff --git a/devito/__init__.py b/devito/__init__.py index 214a0ee8f2..da9044ed4f 100644 --- a/devito/__init__.py +++ b/devito/__init__.py @@ -1,7 +1,10 @@ import atexit from itertools import product +import os from . import _version +import numpy as np + # Import the global `configuration` dict from devito.parameters import * # noqa @@ -160,6 +163,13 @@ def mode_performance(): configuration['opt-options']['blockinner'] = True +if "PYTEST_VERSION" in os.environ and np.version.full_version.startswith('2'): + # Avoid change in repr break docstring tests + # Only sets it here for testing + # https://numpy.org/devdocs/release/2.0.0-notes.html#representation-of-numpy-scalars-changed # noqa + np.set_printoptions(legacy="1.25") + + # Ensure the SymPy caches are purged at exit # For whatever reason, if we don't do this the garbage collector won't its # job properly and thus we may end up missing some custom __del__'s diff --git a/devito/arch/compiler.py b/devito/arch/compiler.py index c85ec156f2..9cd94ed597 100644 --- a/devito/arch/compiler.py +++ b/devito/arch/compiler.py @@ -81,6 +81,8 @@ def sniff_compiler_version(cc, allow_fail=False): ver = '.'.join(ver.strip().split('.')[:3]) if not ver: return Version("0") + # Sanitize bad icx formatting + ver = ver.replace("+git", "").replace("git", "") ver = Version(ver) except UnicodeDecodeError: pass From c56da1e5effd62a9cbaa99ea7fa902e311a8fc26 Mon Sep 17 00:00:00 2001 From: mloubout Date: Wed, 26 Jun 2024 08:25:42 -0400 Subject: [PATCH 3/3] tests: enforce numpy arrays for accuracy checks --- tests/test_interpolation.py | 12 ++++++------ tests/test_sparse.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/test_interpolation.py b/tests/test_interpolation.py index 34bd39bbe0..37c42d601f 100644 --- a/tests/test_interpolation.py +++ b/tests/test_interpolation.py @@ -1,6 +1,5 @@ -from math import sin, floor - import numpy as np +from numpy import sin, floor import pytest from sympy import Float @@ -93,8 +92,8 @@ def precompute_linear_interpolation(points, grid, origin, r=2): Allow larger radius with zero weights for testing. """ - gridpoints = [tuple(floor((point[i]-origin[i])/grid.spacing[i]) - for i in range(len(point))) for point in points] + gridpoints = np.array([tuple(floor((point[i]-origin[i])/grid.spacing[i]) + for i in range(len(point))) for point in points]) interpolation_coeffs = np.zeros((len(points), grid.dim, r)) rs = r // 2 - 1 @@ -114,13 +113,14 @@ def test_precomputed_interpolation(r): precomputed values for interpolation coefficients """ shape = (101, 101) - points = [(.05, .9), (.01, .8), (0.07, 0.84)] + points = np.array([(.05, .9), (.01, .8), (0.07, 0.84)]) origin = (0, 0) grid = Grid(shape=shape, origin=origin) def init(data): # This is data with halo so need to shift to match the m.data expectations + print(grid.spacing) for i in range(data.shape[0]): for j in range(data.shape[1]): data[i, j] = sin(grid.spacing[0]*(i-r)) + sin(grid.spacing[1]*(j-r)) @@ -638,7 +638,7 @@ def test_msf_interpolate(): with a TimeFunction """ shape = (101, 101) - points = [(.05, .9), (.01, .8), (0.07, 0.84)] + points = np.array([(.05, .9), (.01, .8), (0.07, 0.84)]) origin = (0, 0) grid = Grid(shape=shape, origin=origin) diff --git a/tests/test_sparse.py b/tests/test_sparse.py index 78613beaba..c6c882c3f2 100644 --- a/tests/test_sparse.py +++ b/tests/test_sparse.py @@ -21,12 +21,12 @@ def _precompute_linear_interpolation(self, points, grid, origin): precomputes gridpoints and coefficients according to a linear scheme to be used in PrecomputedSparseFunction. """ - gridpoints = [ + gridpoints = np.array([ tuple( floor((point[i] - origin[i]) / grid.spacing[i]) for i in range(len(point)) ) for point in points - ] + ]) coefficients = np.zeros((len(points), 2, 2)) for i, point in enumerate(points): @@ -41,7 +41,7 @@ def _precompute_linear_interpolation(self, points, grid, origin): def test_precomputed_interpolation(self): shape = (101, 101) - points = [(0.05, 0.9), (0.01, 0.8), (0.07, 0.84)] + points = np.array([(0.05, 0.9), (0.01, 0.8), (0.07, 0.84)]) origin = (0, 0) grid = Grid(shape=shape, origin=origin)