Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Numpy2] Support for numpy==2.0.0 #2395

Open
wants to merge 63 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
8930af0
add numpy 2 from conda-forge dev
valeriupredoi Apr 12, 2024
a3e0632
temp remove PyPI numpy - add numpy 2 from conda-forge dev
valeriupredoi Apr 12, 2024
233eb67
run a GA
valeriupredoi Apr 12, 2024
3687ea0
remove numpy from env
valeriupredoi Apr 12, 2024
bf8dff5
manually install numpy 2.0
valeriupredoi Apr 12, 2024
29284bc
correct conda forge channel
valeriupredoi Apr 15, 2024
23429bc
correct conda forge channel
valeriupredoi Apr 15, 2024
50910b4
do not install manually numpy, like a peasant
valeriupredoi Apr 15, 2024
4d5d1eb
revert to manual installation
valeriupredoi Apr 15, 2024
9fb584a
comment out numpy gubbins i environment yml
valeriupredoi Apr 15, 2024
91a87ed
Merge branch 'main' into numpy2-dev
valeriupredoi May 7, 2024
6eb3d00
Merge branch 'main' into numpy2-dev
valeriupredoi May 10, 2024
ade96ca
Merge branch 'main' into numpy2-dev
valeriupredoi May 13, 2024
ac75b84
Merge branch 'main' into numpy2-dev
valeriupredoi May 27, 2024
d36350a
deactivate direct download
valeriupredoi May 27, 2024
5dfa45a
use direct download again
valeriupredoi May 27, 2024
baedee8
use direct download again
valeriupredoi May 27, 2024
5f91615
Merge branch 'main' into numpy2-dev
valeriupredoi Jun 6, 2024
038099d
Merge branch 'main' into numpy2-dev
valeriupredoi Jun 17, 2024
ccb8f2f
use conda forge package
valeriupredoi Jun 17, 2024
882c1cd
dont install from conda package
valeriupredoi Jun 17, 2024
6d9cda5
restore numpy dep
valeriupredoi Jun 17, 2024
e3e2e25
completeley remove line that installed numpy2 from anaconda package
valeriupredoi Jun 17, 2024
30c99e5
unpin pandas
valeriupredoi Jun 19, 2024
98ee116
unpin pandas
valeriupredoi Jun 19, 2024
0e2799b
release numpy to choose its path
valeriupredoi Jun 19, 2024
03a46fa
replace np.NaN with np.nan
valeriupredoi Jun 19, 2024
af8944e
replace np.NaN with np.nan
valeriupredoi Jun 19, 2024
6a8fe23
fix for new output of np.ogrid
valeriupredoi Jun 19, 2024
e849a73
add printout to test
valeriupredoi Jun 19, 2024
3ec3fe5
explicitly cast Python int
valeriupredoi Jun 20, 2024
26a5228
use vstack instead of simple array
valeriupredoi Jun 20, 2024
ecf68f8
make list out of now tuple
valeriupredoi Jun 20, 2024
c10ce96
explicit cast to numpy strings ffs
valeriupredoi Jun 20, 2024
f822bb8
reqwite the distance stat with sqrt account for masks
valeriupredoi Jun 21, 2024
061a4fb
account for variations in rstol for numpy 2.0
valeriupredoi Jun 21, 2024
a4707ef
add note on sqrt bug
valeriupredoi Jun 21, 2024
266781a
temprary pin numpy<2
valeriupredoi Jun 21, 2024
73d455b
temprary pin numpy<2
valeriupredoi Jun 21, 2024
3007575
unpin and let numpy be two
valeriupredoi Jun 21, 2024
7386b7e
unpin and let numpy be two
valeriupredoi Jun 21, 2024
bf01de0
Merge branch 'main' into numpy2-dev
valeriupredoi Jun 24, 2024
043407a
use the force and xfail the icon test instead
valeriupredoi Jun 24, 2024
a3ccff6
remove commented out pandas pins
valeriupredoi Jun 24, 2024
aefb52c
remove commented out pandas pins
valeriupredoi Jun 24, 2024
1741727
unrun GA
valeriupredoi Jun 24, 2024
4afc351
Update esmvalcore/preprocessor/_compare_with_refs.py
valeriupredoi Jul 3, 2024
6464ecf
Merge branch 'main' into numpy2-dev
valeriupredoi Jul 3, 2024
85b2aa4
remove numpy2 related comment
valeriupredoi Jul 3, 2024
05dea66
remove numpy2 related comment
valeriupredoi Jul 3, 2024
64da79d
Merge branch 'main' into numpy2-dev
valeriupredoi Jul 8, 2024
ea3c702
Merge branch 'main' into numpy2-dev
valeriupredoi Jul 9, 2024
0b2e975
Merge branch 'main' into numpy2-dev
valeriupredoi Aug 5, 2024
b345843
Merge branch 'main' into numpy2-dev
valeriupredoi Sep 13, 2024
55edd79
Merge branch 'main' into numpy2-dev
valeriupredoi Sep 19, 2024
400ccc4
Merge branch 'main' into numpy2-dev
valeriupredoi Sep 27, 2024
e6073eb
run precommit twice
valeriupredoi Sep 27, 2024
803017d
run precommit twice
valeriupredoi Sep 27, 2024
0ee7dcd
Merge branch 'main' into numpy2-dev
valeriupredoi Oct 24, 2024
c4cb2f1
unpin numpy
valeriupredoi Oct 24, 2024
9c5eace
well I have just found one of those rare occasions when merge resulte…
valeriupredoi Oct 24, 2024
519769c
Merge branch 'main' into numpy2-dev
valeriupredoi Oct 30, 2024
fb6cdc3
Merge branch 'main' into numpy2-dev
valeriupredoi Nov 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ dependencies:
- nc-time-axis
- nested-lookup
- netcdf4
- numpy !=1.24.3,<2.0.0 # avoid pulling 2.0.0rcX
- numpy !=1.24.3
- packaging
- pandas
- pillow
Expand Down
6 changes: 5 additions & 1 deletion esmvalcore/preprocessor/_compare_with_refs.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,11 @@ def _calculate_rmse(
weights = get_weights(cube, coords) if weighted else None
squared_error = (cube.core_data() - reference.core_data()) ** 2
npx = get_array_module(squared_error)
rmse = npx.sqrt(npx.ma.average(squared_error, axis=axis, weights=weights))
mse = npx.ma.average(squared_error, axis=axis, weights=weights)
if isinstance(mse, da.Array):
rmse = da.reductions.safe_sqrt(mse)
else:
rmse = np.ma.sqrt(mse)

# Metadata
metadata = CubeMetadata(
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/preprocessor/_derive/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def _create_pressure_array(cube, ps_cube, top_limit):
ps_4d_array = iris.util.broadcast_to_shape(ps_cube.data, shape, [0, 2, 3])

# Set pressure levels below the surface pressure to NaN
pressure_4d = np.where((ps_4d_array - p_4d_array) < 0, np.NaN, p_4d_array)
pressure_4d = np.where((ps_4d_array - p_4d_array) < 0, np.nan, p_4d_array)

# Make top_limit last pressure level
top_limit_array = np.full(ps_cube.shape, top_limit, dtype=np.float32)
Expand Down
2 changes: 2 additions & 0 deletions esmvalcore/preprocessor/_derive/co2s.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def _get_first_unmasked_data(array, axis):
*[da.arange(array.shape[i]) for i in range(array.ndim) if i != axis],
indexing="ij",
)

indices = list(indices)
indices.insert(axis, indices_first_positive)
first_unmasked_data = np.array(array)[tuple(indices)]
return first_unmasked_data
Expand Down
5 changes: 4 additions & 1 deletion esmvalcore/preprocessor/_regrid_esmpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,11 @@ def get_grid(
num_peri_dims = 1
else:
num_peri_dims = 0

# previous to numpy 2.0, a np.array(esmpy_lat.shape) was used
# numpy>=2.0 throws ValueError: matrix transpose with ndim<2 is undefined
grid = esmpy.Grid(
np.array(esmpy_lat.shape),
np.vstack(esmpy_lat.shape),
num_peri_dims=num_peri_dims,
staggerloc=[esmpy.StaggerLoc.CENTER],
)
Expand Down
8 changes: 6 additions & 2 deletions esmvalcore/preprocessor/_regrid_unstructured.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,12 @@ def _get_weights_and_idx(
src_points_with_convex_hull = self._add_convex_hull_twice(
src_points, hull.vertices
)
src_points_with_convex_hull[-2 * n_hull : -n_hull, 1] -= 360
src_points_with_convex_hull[-n_hull:, 1] += 360

# explicitly casting to int32 since without it, in Numpy 2.0
# one gets OverflowError: Python integer 360 out of bounds for int8
# see notes https://numpy.org/devdocs/numpy_2_0_migration_guide.html
src_points_with_convex_hull[-2 * n_hull : -n_hull, 1] -= np.int32(360)
src_points_with_convex_hull[-n_hull:, 1] += np.int32(360)

# Actual weights calculation
(weights, indices) = self._calculate_weights(
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/preprocessor/_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -1597,7 +1597,7 @@ def _transform_to_lst_eager(
"""
# Apart from the time index, all other dimensions will stay the same; this
# is ensured with np.ogrid
idx = np.ogrid[tuple(slice(0, d) for d in data.shape)]
idx = list(np.ogrid[tuple(slice(0, d) for d in data.shape)])
time_index = broadcast_to_shape(
time_index, data.shape, (time_dim, lon_dim)
)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ dependencies = [
"nc-time-axis", # needed by iris.plot
"nested-lookup",
"netCDF4",
"numpy!=1.24.3,<2.0.0", # avoid pulling 2.0.0rc1
"numpy!=1.24.3",
"packaging",
"pandas",
"pillow",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
from tests import PreprocessorFile


def assert_allclose(array_1, array_2):
def assert_allclose(array_1, array_2, rtol=1e-7):
"""Assert that (masked) array 1 is close to (masked) array 2."""
if np.ma.is_masked(array_1) or np.ma.is_masked(array_2):
mask_1 = np.ma.getmaskarray(array_1)
mask_2 = np.ma.getmaskarray(array_2)
np.testing.assert_equal(mask_1, mask_2)
np.testing.assert_allclose(array_1[~mask_1], array_2[~mask_2])
np.testing.assert_allclose(array_1[~mask_1], array_2[~mask_2], rtol)
else:
np.testing.assert_allclose(array_1, array_2)
np.testing.assert_allclose(array_1, array_2, rtol)


def products_set_to_dict(products):
Expand Down Expand Up @@ -473,7 +473,10 @@ def test_distance_metric(
assert out_cube.shape == ()
assert out_cube.dtype == np.float32
assert not out_cube.has_lazy_data()
assert_allclose(out_cube.data, ref_data)
# an rtol=1e-6 is needed for numpy >=2.0
assert_allclose(
out_cube.data, np.array(ref_data, dtype=np.float32), rtol=1e-6
)
assert out_cube.var_name == var_name
assert out_cube.long_name == long_name
assert out_cube.standard_name is None
Expand Down Expand Up @@ -684,7 +687,8 @@ def test_distance_metric_masked_data(
expected_data = np.ma.masked_invalid(data)
else:
expected_data = np.array(data, dtype=np.float32)
assert_allclose(out_cube.data, expected_data)
# an rtol=1e-6 is needed for numpy >=2.0
assert_allclose(out_cube.data, expected_data, rtol=1e-6)
assert out_cube.var_name == var_name
assert out_cube.long_name == long_name
assert out_cube.standard_name is None
Expand Down Expand Up @@ -740,6 +744,7 @@ def test_distance_metric_fully_masked_data(
assert out_cube.dtype == np.float64

expected_data = np.ma.masked_all(())
print("out/in/metric", out_cube.data, expected_data, metric)
assert_allclose(out_cube.data, expected_data)
assert out_cube.var_name == var_name
assert out_cube.long_name == long_name
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/preprocessor/_derive/test_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def test_low_lev_below_surf_press():
"""Test for lowest level below surface pressure."""
plev = 970
top_limit = 5
col = np.array([np.NaN, 900, 800])
col = np.array([np.nan, 900, 800])
col = np.insert(col, 0, plev)
col = np.append(col, top_limit)
result = np.array([0, 120, 845])
Expand All @@ -197,7 +197,7 @@ def test_low_lev_below_surf_press():
np.atleast_3d(result),
)

col = np.array([np.NaN, np.NaN, 900, 800])
col = np.array([np.nan, np.nan, 900, 800])
col = np.insert(col, 0, plev)
col = np.append(col, top_limit)
result = np.array([0, 0, 120, 845])
Expand Down
5 changes: 4 additions & 1 deletion tests/unit/preprocessor/_time/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -1063,9 +1063,12 @@ def test_season_not_available(self):
name="clim_season",
seasons=["JFMAMJ", "JASOND"],
)

# numpy>=2.0 these need to be explicitly cast to numpy strings
two_seasons = [np.str_("JASOND"), np.str_("JFMAMJ")]
msg = (
"Seasons ('DJF', 'MAM', 'JJA', 'SON') do not match prior season "
"extraction ['JASOND', 'JFMAMJ']."
f"extraction {two_seasons}."
)
with pytest.raises(ValueError, match=re.escape(msg)):
seasonal_statistics(cube, "mean")
Expand Down