From 639fabd1a830cf81c645cd60878badbc5051b8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dieter=20Werthm=C3=BCller?= Date: Wed, 9 Oct 2024 18:21:17 +0200 Subject: [PATCH] NumPy v2 (#344) - Update for NumPy v2 (replace np.infty by np.inf) - Fix warnings - Bump minimum Python to 3.10 - Bump minimum SciPy to 1.10 - No more restriction on Numba version - Docs need new pickleshare --- .github/workflows/linux.yml | 25 ++++++++----------------- .github/workflows/macos_windows.yml | 6 ++---- CHANGELOG.rst | 20 +++++++++++++++++--- CREDITS.rst | 27 ++++++++++++++++----------- Makefile | 4 ++-- README.rst | 2 +- docs/dev/contributing.rst | 2 +- docs/manual/cli.rst | 2 +- emg3d/fields.py | 10 +++++----- emg3d/models.py | 2 +- emg3d/surveys.py | 6 +++--- requirements-dev.txt | 4 ++++ setup.py | 9 ++++----- tests/alternatives.py | 8 ++++---- tests/test_fields.py | 2 +- tests/test_meshes.py | 10 +++++----- tests/test_multiprocessing.py | 1 + tests/test_simulations.py | 2 ++ 18 files changed, 78 insertions(+), 64 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3cdf7883..eb06d98d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -36,34 +36,26 @@ jobs: matrix: os: [ubuntu, ] # macos, windows] # Only Linux currently. case: - - python-version: "3.9" - name: minimal - os: ubuntu - conda: "'scipy=1.9' 'numba=0.53' 'numpy<2.0' 'empymod>=2.3'" - - python-version: "3.10" - name: full - os: ubuntu - conda: "numba scipy xarray h5py discretize matplotlib 'numpy<2.0' 'empymod>=2.3'" # tqdm - python-version: "3.10" - name: plain + name: minimal os: ubuntu - conda: "numba scipy 'numpy<2.0' 'empymod>=2.3'" + conda: "'scipy=1.10' numba 'empymod>=2.3.2'" - python-version: "3.11" name: plain os: ubuntu - conda: "numba scipy 'numpy<2.0' 'empymod>=2.3'" + conda: "scipy numba 'empymod>=2.3.2'" - python-version: "3.11" name: full os: ubuntu - conda: "numba scipy xarray tqdm h5py discretize matplotlib 'numpy<2.0' 'empymod>=2.3'" + conda: "scipy numba 'empymod>=2.3.2' xarray tqdm h5py discretize matplotlib" - python-version: "3.12" name: plain os: ubuntu - conda: "numba scipy 'numpy<2.0' 'empymod>=2.3'" + conda: "scipy numba 'empymod>=2.3.2'" - python-version: "3.12" name: full os: ubuntu - conda: "numba scipy xarray tqdm h5py discretize matplotlib 'numpy<2.0' 'empymod>=2.3'" + conda: "scipy numba 'empymod>=2.3.2' xarray tqdm h5py discretize matplotlib" env: # Used for coveralls flag @@ -95,8 +87,6 @@ jobs: auto-update-conda: true python-version: ${{ matrix.case.python-version }} miniforge-version: "latest" - miniforge-variant: Mambaforge - use-mamba: true - name: Install dependencies shell: bash -l {0} @@ -118,7 +108,8 @@ jobs: - name: Test with pytest shell: bash -l {0} run: | - python -m pip install --no-build-isolation --no-deps . + python -m pip install --upgrade pip + make install pytest --cov=emg3d - name: Coveralls diff --git a/.github/workflows/macos_windows.yml b/.github/workflows/macos_windows.yml index 65b394a1..368470eb 100644 --- a/.github/workflows/macos_windows.yml +++ b/.github/workflows/macos_windows.yml @@ -62,8 +62,6 @@ jobs: auto-update-conda: true python-version: ${{ matrix.python }} miniforge-version: "latest" - miniforge-variant: Mambaforge - use-mamba: true - name: Install dependencies shell: bash -l {0} @@ -72,7 +70,7 @@ jobs: conda config --show-sources conda config --show conda info -a - conda install numba scipy pytest pytest-console-scripts scooby setuptools-scm + conda install scipy numba empymod pytest pytest-console-scripts setuptools-scm - name: Conda list shell: bash -l {0} @@ -81,5 +79,5 @@ jobs: - name: Test with pytest shell: bash -l {0} run: | - python -m pip install . + make install pytest diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1c741830..f769eee5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,13 +6,27 @@ Changelog """""""""" -latest ------- +v1.8.4 : NumPy v2 +----------------- + +**2024-10-09** + +The code is now compatible with NumPy v2. + - Created foundation for new module ``inversion``. -Maintenance +- Bumped the minimum requirements to: + + - Python 3.10 + - SciPy 1.10 + - empymod 2.3.2 + - Numba (without minimum version) + +- Maintenance + - Testing: dropped Python 3.9 (Python 3.13 not added yet). + - Update for NumPy v2: mainly ``np.infty -> np.inf``. - Add notes for ``ipympl`` (interactive plots in modern Jupyter). - Reduce code by making use of new SciPy new features (complex-valued map_coordinate; lazy loading). diff --git a/CREDITS.rst b/CREDITS.rst index 3407b30e..0fbd1c28 100644 --- a/CREDITS.rst +++ b/CREDITS.rst @@ -1,17 +1,22 @@ Credits ####### -This project was started by **Dieter Werthmüller** at -`Delft University of Technology `_ as part of the -*Gitaro.JIM* project (till 05/2021, emg3d v1.0.0), funded through -`MarTERA `_ as part of Horizon 2020, a funding scheme -of the European Research Area. Dieter would like to thank his current employers -who allow him to maintain and further develop the code after the initial -funding ended, namely: - -- 2021-today: `Delft University of Technology `_, - funded through the `Delphi Consortium `_ -- 2021-today: `TERRASYS Geophysics GmbH & Co. KG `_ +This project was started by **Dieter Werthmüller** at TUD as part of the +*Gitaro.JIM* project (see below). +Dieter would like to thank his past and current employers who allowed and allow +him to maintain and further develop the code after the initial funding ended, +namely: + +- 2018-2021: `Delft University of Technology `_; + through the *Gitaro.JIM* project (till 05/2021, emg3d v1.0.0), funded by + `MarTERA `_ as part of Horizon 2020, a funding scheme + of the European Research Area. +- 2021-2024: `Delft University of Technology `_ through + the `Delphi Consortium `_. +- 2021-2022: `TERRASYS Geophysics GmbH & Co. KG + `_. +- 2024-today: `ETH Zurich `_ through the group `Geothermal + Energy and Geofluids `_. For a list of code contributors see https://github.com/emsig/emg3d/graphs/contributors. diff --git a/Makefile b/Makefile index 9592bf84..53c39a5c 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,10 @@ help: @echo "" install: - python -m pip install --no-build-isolation --no-deps -e . + python -m pip install --no-build-isolation --use-pep517 --no-deps -e . dev-install: - python -m pip install -r requirements-dev.txt && python -m pip install --no-build-isolation --no-deps -e . + python -m pip install -r requirements-dev.txt && python -m pip install --no-build-isolation --use-pep517 --no-deps -e . pytest: rm -rf .coverage htmlcov/ .pytest_cache/ && pytest --cov=emg3d && coverage html diff --git a/README.rst b/README.rst index dd756188..e1bdcbb1 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ .. image:: https://img.shields.io/conda/v/conda-forge/emg3d.svg :target: https://anaconda.org/conda-forge/emg3d/ :alt: conda-forge -.. image:: https://img.shields.io/badge/python-3.8+-blue.svg +.. image:: https://img.shields.io/badge/python-3.10+-blue.svg :target: https://www.python.org/downloads/ :alt: Supported Python Versions .. image:: https://img.shields.io/badge/platform-linux,win,osx-blue.svg diff --git a/docs/dev/contributing.rst b/docs/dev/contributing.rst index 85dbe643..35e40e18 100644 --- a/docs/dev/contributing.rst +++ b/docs/dev/contributing.rst @@ -11,7 +11,7 @@ Good places to get started is to browse the existing issues, check out the roadmap, or have a look at any open PR: - `Issues `_; -- `Roadmap-project `_; +- `Roadmap `_; - `PR's `_. There are various different ways to get in touch, see diff --git a/docs/manual/cli.rst b/docs/manual/cli.rst index e8b11961..7648c173 100644 --- a/docs/manual/cli.rst +++ b/docs/manual/cli.rst @@ -124,7 +124,7 @@ remove the comment signs to use them. [noise_opts] # add_noise = True # Set to False to switch noise off. # min_offset = 0.0 # off < min_off set to NaN. - # max_offset = np.infty # off > max_off set to NaN. + # max_offset = np.inf # off > max_off set to NaN. # mean_noise = 0.0 # Mean of the noise. # ntype = white_noise # Type of the noise. diff --git a/emg3d/fields.py b/emg3d/fields.py index 0a8b354c..ceb15491 100644 --- a/emg3d/fields.py +++ b/emg3d/fields.py @@ -696,9 +696,9 @@ def point_source(xx, yy, zz, coo, s): nx, ny, nz = s.shape # Get indices of cells in which source resides. - ix = max(0, np.where(coo[0] < np.r_[xx, np.infty])[0][0]-1) - iy = max(0, np.where(coo[1] < np.r_[yy, np.infty])[0][0]-1) - iz = max(0, np.where(coo[2] < np.r_[zz, np.infty])[0][0]-1) + ix = max(0, np.where(coo[0] < np.r_[xx, np.inf])[0][0]-1) + iy = max(0, np.where(coo[1] < np.r_[yy, np.inf])[0][0]-1) + iz = max(0, np.where(coo[2] < np.r_[zz, np.inf])[0][0]-1) def get_index_and_strength(ic, nc, csrc, cc): """Return index and field strength in c-direction.""" @@ -864,8 +864,8 @@ def min_max_ind(vector, i): """Return [min, max]-index of cells in which points resides.""" vmin = min(points[:, i]) vmax = max(points[:, i]) - return [max(0, np.where(vmin < np.r_[vector, np.infty])[0][0]-1), - max(0, np.where(vmax < np.r_[vector, np.infty])[0][0]-1)] + return [max(0, np.where(vmin < np.r_[vector, np.inf])[0][0]-1), + max(0, np.where(vmax < np.r_[vector, np.inf])[0][0]-1)] rix = min_max_ind(nodes_x, 0) riy = min_max_ind(nodes_y, 1) diff --git a/emg3d/models.py b/emg3d/models.py index 78d84332..ce0eb69e 100644 --- a/emg3d/models.py +++ b/emg3d/models.py @@ -468,7 +468,7 @@ def extract_1d(self, method, p0, p1=None, ellipse=None, merge=False, # Find corresponding indices, limit to grid. def index(nodes, coo): """Return index for interval btw nodes in which coo resides.""" - x = np.asarray(coo < np.r_[nodes, np.infty]).nonzero()[0][0]-1 + x = np.asarray(coo < np.r_[nodes, np.inf]).nonzero()[0][0]-1 return np.clip(x, 0, nodes.size-2) # Start and end indices. diff --git a/emg3d/surveys.py b/emg3d/surveys.py index fe158872..437a79a1 100644 --- a/emg3d/surveys.py +++ b/emg3d/surveys.py @@ -619,7 +619,7 @@ def add_noise(self, min_offset=0.0, min_amplitude='half_nf', dataset it will create a dataset of zeroes. You can use that to obtain the pure noise. - max_offset : float, default: np.infty + max_offset : float, default: np.inf Data points in ``data.observed`` where the offset > max_offset are set to NaN. @@ -639,8 +639,8 @@ def add_noise(self, min_offset=0.0, min_amplitude='half_nf', self.data[add_to].data[cut_amp] = np.nan + 1j*np.nan # Set offsets below min_offset and above max_offset to NaN. - max_offset = kwargs.pop('max_offset', np.infty) - if min_offset > 0.0 or max_offset < np.infty: + max_offset = kwargs.pop('max_offset', np.inf) + if min_offset > 0.0 or max_offset < np.inf: for ks, s in self.sources.items(): for kr, r in self.receivers.items(): off = np.linalg.norm(r.center_abs(s) - s.center) diff --git a/requirements-dev.txt b/requirements-dev.txt index 08e13674..42478f3b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,9 @@ # GLOBAL REQUIREMENTS. -r requirements.txt +# Fix numpy<2 until discretize is ready for 2.0 +numpy<2 + # SOFT DEPENDENCIES tqdm h5py @@ -22,6 +25,7 @@ sphinx_numfig pydata_sphinx_theme sphinx_automodapi ipykernel +pickleshare # FOR TESTING asv diff --git a/setup.py b/setup.py index c368cf7f..7b4bfeb6 100644 --- a/setup.py +++ b/setup.py @@ -26,12 +26,11 @@ "emg3d=emg3d.cli.main:main", ], }, - python_requires=">=3.9", + python_requires=">=3.10", install_requires=[ - "scipy>=1.9", - "numpy<2.0", - "numba>=0.53", - "empymod>=2.3.0", + "scipy>=1.10", + "numba", + "empymod>=2.3.2", ], extras_require={ "full": [ diff --git a/tests/alternatives.py b/tests/alternatives.py index 4b0c7bdc..70e3ea00 100644 --- a/tests/alternatives.py +++ b/tests/alternatives.py @@ -241,7 +241,7 @@ def alt_volume_average(edges_x, edges_y, edges_z, values, """ # Get cell indices. - # First and last edges ignored => first and last cells extend to +/- infty. + # First and last edges ignored => first and last cells extend to +/- inf. ix_l = np.searchsorted(edges_x[1:-1], new_edges_x, 'left') ix_r = np.searchsorted(edges_x[1:-1], new_edges_x, 'right') iy_l = np.searchsorted(edges_y[1:-1], new_edges_y, 'left') @@ -353,9 +353,9 @@ def point_source(xx, yy, zz, src, s): nx, ny, nz = s.shape # Get indices of cells in which source resides. - ix = max(0, np.where(src[0] < np.r_[xx, np.infty])[0][0]-1) - iy = max(0, np.where(src[1] < np.r_[yy, np.infty])[0][0]-1) - iz = max(0, np.where(src[2] < np.r_[zz, np.infty])[0][0]-1) + ix = max(0, np.where(src[0] < np.r_[xx, np.inf])[0][0]-1) + iy = max(0, np.where(src[1] < np.r_[yy, np.inf])[0][0]-1) + iz = max(0, np.where(src[2] < np.r_[zz, np.inf])[0][0]-1) def get_index_and_strength(ic, nc, csrc, cc): """Return index and field strength in c-direction.""" diff --git a/tests/test_fields.py b/tests/test_fields.py index 1ac0230f..b273ec7e 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -78,7 +78,7 @@ def test_dtype(self): with pytest.raises(ValueError, match="must be f>0"): _ = fields.Field(self.grid, frequency=0.0) - with pytest.warns(np.ComplexWarning, match="Casting complex values"): + with pytest.warns(np.exceptions.ComplexWarning, match="Casting compl"): lp = fields.Field(self.grid, self.field, frequency=-1) assert lp.field.dtype == np.float64 diff --git a/tests/test_meshes.py b/tests/test_meshes.py index bbaa2fe1..d1e5fd83 100644 --- a/tests/test_meshes.py +++ b/tests/test_meshes.py @@ -346,14 +346,14 @@ def test_domain_vector(self): vector2 = np.array([-1, 0, 1]) x02, hx2 = meshes.origin_and_widths(vector=vector2, **inp) - assert np.in1d(vector2, x02 + np.cumsum(hx2)).all() + assert np.isin(vector2, x02 + np.cumsum(hx2)).all() vector3 = np.array([-2, -1, 0, 1, 2]) x03, hx3 = meshes.origin_and_widths( # vector will be cut domain=[-1, 1], vector=vector3, **inp) - assert np.in1d(vector3[1:-1], x03 + np.cumsum(hx3)).all() - assert not np.in1d(vector3[0], x03 + np.cumsum(hx3)) - assert not np.in1d(vector3[-1], x03 + np.cumsum(hx3)) + assert np.isin(vector3[1:-1], x03 + np.cumsum(hx3)).all() + assert not np.isin(vector3[0], x03 + np.cumsum(hx3)) + assert not np.isin(vector3[-1], x03 + np.cumsum(hx3)) x04, hx4 = meshes.origin_and_widths( # vector will be cut distance=[1.0, 1.0], vector=vector3, **inp) @@ -362,7 +362,7 @@ def test_domain_vector(self): x05, hx5 = meshes.origin_and_widths( # vector will be expanded distance=[2.0, 2.0], vector=vector2, **inp) - assert np.in1d(np.array([-2, -1, 0, 1, 2]), x05 + np.cumsum(hx5)).all() + assert np.isin(np.array([-2, -1, 0, 1, 2]), x05 + np.cumsum(hx5)).all() def test_seasurface(self): inp = {'frequency': 1/np.pi, 'properties': 9*mu_0, 'domain': [-1, 2], diff --git a/tests/test_multiprocessing.py b/tests/test_multiprocessing.py index 2a6f5895..b729cbfd 100644 --- a/tests/test_multiprocessing.py +++ b/tests/test_multiprocessing.py @@ -27,6 +27,7 @@ def dummy(inp): return inp +@pytest.mark.filterwarnings("ignore:.*lead to deadlocks*:DeprecationWarning") def test_process_map(): # Parallel diff --git a/tests/test_simulations.py b/tests/test_simulations.py index 59973b12..9fe58ace 100644 --- a/tests/test_simulations.py +++ b/tests/test_simulations.py @@ -28,6 +28,7 @@ rng = np.random.default_rng() +@pytest.mark.filterwarnings("ignore:.*lead to deadlocks*:DeprecationWarning") @pytest.mark.skipif(xarray is None, reason="xarray not installed.") class TestSimulation(): if xarray is not None: @@ -695,6 +696,7 @@ def test_compute_1d(self): assert grad.shape == self.model.shape +@pytest.mark.filterwarnings("ignore:.*lead to deadlocks*:DeprecationWarning") @pytest.mark.skipif(xarray is None, reason="xarray not installed.") def test_misfit(): data = 1