From 1a9ba145c4057d205347084a3a51846d805ae4e1 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Fri, 26 Apr 2024 14:57:10 -0600 Subject: [PATCH 1/5] MNT: Update use of trapz for numpy>=2 This has been renamed to `trapezoid`, so do a conditional import to avoid a warning. This can be cleaned up in a couple years. --- src/metpy/calc/indices.py | 12 +++++++++--- src/metpy/calc/thermo.py | 17 ++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/metpy/calc/indices.py b/src/metpy/calc/indices.py index 7b3c349f668..d9f15f25f1b 100644 --- a/src/metpy/calc/indices.py +++ b/src/metpy/calc/indices.py @@ -4,6 +4,12 @@ """Contains calculation of various derived indices.""" import numpy as np +# Can drop fallback once we rely on numpy>=2 +try: + from numpy import trapezoid +except ImportError: + from numpy import trapz as trapezoid + from .basic import wind_speed from .thermo import mixing_ratio, saturation_vapor_pressure from .tools import _remove_nans, get_layer @@ -90,7 +96,7 @@ def precipitable_water(pressure, dewpoint, *, bottom=None, top=None): w = mixing_ratio(saturation_vapor_pressure(dewpoint_layer), pres_layer) # Since pressure is in decreasing order, pw will be the opposite sign of that expected. - pw = -np.trapz(w, pres_layer) / (mpconsts.g * mpconsts.rho_l) + pw = -trapezoid(w, pres_layer) / (mpconsts.g * mpconsts.rho_l) return pw.to('millimeters') @@ -168,7 +174,7 @@ def mean_pressure_weighted(pressure, *args, height=None, bottom=None, depth=None pres_int = 0.5 * (pres_prof[-1] ** 2 - pres_prof[0] ** 2) # Perform integration on the profile for each variable - return [np.trapz(var_prof * pres_prof, x=pres_prof) / pres_int for var_prof in others] + return [trapezoid(var_prof * pres_prof, x=pres_prof) / pres_int for var_prof in others] @exporter.export @@ -228,7 +234,7 @@ def weighted_continuous_average(pressure, *args, height=None, bottom=None, depth pressure, *args, height=height, bottom=bottom, depth=depth ) - return [np.trapz(var_prof, x=pres_prof) / (pres_prof[-1] - pres_prof[0]) + return [trapezoid(var_prof, x=pres_prof) / (pres_prof[-1] - pres_prof[0]) for var_prof in others] diff --git a/src/metpy/calc/thermo.py b/src/metpy/calc/thermo.py index e60e65a7f1b..379785d586f 100644 --- a/src/metpy/calc/thermo.py +++ b/src/metpy/calc/thermo.py @@ -5,6 +5,13 @@ from inspect import Parameter, Signature, signature import numpy as np + +# Can drop fallback once we rely on numpy>=2 +try: + from numpy import trapezoid +except ImportError: + from numpy import trapz as trapezoid + import scipy.integrate as si import scipy.optimize as so import xarray as xr @@ -2455,7 +2462,7 @@ def cape_cin(pressure, temperature, dewpoint, parcel_profile, which_lfc='bottom' x_clipped = x[p_mask].magnitude y_clipped = y[p_mask].magnitude cape = (mpconsts.Rd - * units.Quantity(np.trapz(y_clipped, np.log(x_clipped)), 'K')).to(units('J/kg')) + * units.Quantity(trapezoid(y_clipped, np.log(x_clipped)), 'K')).to(units('J/kg')) # CIN # Only use data between the surface and LFC for calculation @@ -2463,7 +2470,7 @@ def cape_cin(pressure, temperature, dewpoint, parcel_profile, which_lfc='bottom' x_clipped = x[p_mask].magnitude y_clipped = y[p_mask].magnitude cin = (mpconsts.Rd - * units.Quantity(np.trapz(y_clipped, np.log(x_clipped)), 'K')).to(units('J/kg')) + * units.Quantity(trapezoid(y_clipped, np.log(x_clipped)), 'K')).to(units('J/kg')) # Set CIN to 0 if it's returned as a positive value (#1190) if cin > units.Quantity(0, 'J/kg'): @@ -3240,7 +3247,7 @@ def downdraft_cape(pressure, temperature, dewpoint): # Find DCAPE dcape = -(mpconsts.Rd - * units.Quantity(np.trapz(diff, lnp), 'K') + * units.Quantity(trapezoid(diff, lnp), 'K') ).to(units('J/kg')) return dcape, down_pressure, down_parcel_trace @@ -3439,7 +3446,7 @@ def mixed_layer(pressure, *args, height=None, bottom=None, depth=None, interpola ret = [] for datavar_layer in datavars_layer: actual_depth = abs(p_layer[0] - p_layer[-1]) - ret.append(units.Quantity(np.trapz(datavar_layer.m, p_layer.m) / -actual_depth.m, + ret.append(units.Quantity(trapezoid(datavar_layer.m, p_layer.m) / -actual_depth.m, datavar_layer.units)) return ret @@ -3691,7 +3698,7 @@ def thickness_hydrostatic(pressure, temperature, mixing_ratio=None, # Take the integral return ( -mpconsts.nounit.Rd / mpconsts.nounit.g - * np.trapz(layer_virttemp, np.log(layer_p)) + * trapezoid(layer_virttemp, np.log(layer_p)) ) From 37be3c31ecd1a1ac6ecb5ddbff131ab52720e3b4 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Fri, 26 Apr 2024 14:58:21 -0600 Subject: [PATCH 2/5] MNT: Update normalize_axis_index for numpy>=2 This has been moved from the (now) deprecated numeric namespace to an array_utils namespace. Apparently this wasn't a public API before (?) but now is. --- src/metpy/calc/tools.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/metpy/calc/tools.py b/src/metpy/calc/tools.py index 63867264e43..091545d8856 100644 --- a/src/metpy/calc/tools.py +++ b/src/metpy/calc/tools.py @@ -8,7 +8,13 @@ from operator import itemgetter import numpy as np -from numpy.core.numeric import normalize_axis_index + +# Can drop fallback once we rely on numpy>=2 +try: + from numpy.lib.array_utils import normalize_axis_index +except ImportError: + from numpy.core.numeric import normalize_axis_index + import numpy.ma as ma from pyproj import CRS, Geod, Proj from scipy.spatial import cKDTree From 11f952f99dacd198cfa141d64da82e2fc19dd9f6 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Fri, 26 Apr 2024 14:59:23 -0600 Subject: [PATCH 3/5] BUG: Fix version parsing for RC's, etc. We were a bit too stringent here, since versions can include alpha/beta as well as post versions. This was broken when numpy 2.0.0rc1 was installed. --- src/metpy/testing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metpy/testing.py b/src/metpy/testing.py index 7f3de9f4856..a46a5ea8059 100644 --- a/src/metpy/testing.py +++ b/src/metpy/testing.py @@ -84,7 +84,7 @@ def _parse_version_spec(version_spec): tuple of str : Parsed specification groups of package name, comparison, and version """ - pattern = re.compile(r'(\w+)\s*([<>!=]+)\s*([\d.]+)') + pattern = re.compile(r'(\w+)\s*([<>!=]+)\s*([\d\w.]+)') match = pattern.match(version_spec) if not match: From b94ac538a77cb07b4ab1bfdeccb6280b5745ac5a Mon Sep 17 00:00:00 2001 From: Ryan May Date: Fri, 26 Apr 2024 15:00:44 -0600 Subject: [PATCH 4/5] MNT: Fix location of broadcast_to() This symbol is available at the top level of the module, so just use it there--just like the rest of the uses of this function in metpy. The full path here no longer works with numpy>=2. --- tests/calc/test_thermo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/calc/test_thermo.py b/tests/calc/test_thermo.py index 5e2cf1f1085..02f8ab76d02 100644 --- a/tests/calc/test_thermo.py +++ b/tests/calc/test_thermo.py @@ -1299,7 +1299,7 @@ def test_isentropic_pressure_interp(press_3d): """Test calculation of isentropic pressure function.""" lev = [100000., 95000., 90000., 85000.] * units.Pa if press_3d: - lev = np.lib.stride_tricks.broadcast_to(lev[:, None, None], (4, 5, 5)) + lev = np.broadcast_to(lev[:, None, None], (4, 5, 5)) tmp = np.ones((4, 5, 5)) tmp[0, :] = 296. tmp[1, :] = 292. From 941109a4fdc831bb5e04d23a340bf282e0b3ad7a Mon Sep 17 00:00:00 2001 From: Ryan May Date: Fri, 26 Apr 2024 15:02:32 -0600 Subject: [PATCH 5/5] BUG: Fix kwarg in test This was causing a conflict between linewidth and linewidths that matplotlib 3.9.0rc2 caught and errored out on. --- tests/plots/test_declarative.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plots/test_declarative.py b/tests/plots/test_declarative.py index 6093ea361ad..b5142f87e4c 100644 --- a/tests/plots/test_declarative.py +++ b/tests/plots/test_declarative.py @@ -2115,7 +2115,7 @@ def test_declarative_plot_geometry_lines(ccrs): geo.stroke = 'green' geo.labels = ['Irma', '+/- 0.25 deg latitude'] geo.label_facecolor = None - geo.mpl_args = {'linewidth': 1} + geo.mpl_args = {'linewidths': 1} # Place plot in a panel and container panel = MapPanel()