From 9003c52deb289ceeb1c78e7f4b6b22fef510b3f2 Mon Sep 17 00:00:00 2001 From: rpmanser Date: Sat, 14 Aug 2021 15:06:55 -0500 Subject: [PATCH] Use `array_type` fixture; fix bugs for masked array inputs to functions * Use `array_type` as needed `test_basic.py` * Fix bug in `wind_direction()` for masked arrays when calm. Boolean indexing of a masked array resulted in modification of the mask itself. * Fix bug in `smooth_gaussian()` where function returned a `numpy.ndarray` when given a `numpy.ma.array` * Remove `test_direction_masked()` --- src/metpy/calc/basic.py | 16 +- tests/calc/test_basic.py | 376 ++++++++++++++++++++++----------------- 2 files changed, 223 insertions(+), 169 deletions(-) diff --git a/src/metpy/calc/basic.py b/src/metpy/calc/basic.py index 1ab37eb34dc..09fe35887a2 100644 --- a/src/metpy/calc/basic.py +++ b/src/metpy/calc/basic.py @@ -104,8 +104,14 @@ def wind_direction(u, v, convention='from'): wdir[mask] += units.Quantity(360., 'deg') # avoid unintended modification of `pint.Quantity` by direct use of magnitude calm_mask = (np.asarray(u.magnitude) == 0.) & (np.asarray(v.magnitude) == 0.) + + if hasattr(wdir, "mask"): + array_mask = wdir.mask + else: + array_mask = False + # np.any check required for legacy numpy which treats 0-d False boolean index as zero - if np.any(calm_mask): + if np.any(calm_mask & np.logical_not(array_mask)): wdir[calm_mask] = units.Quantity(0., 'deg') return wdir.reshape(origshape).to('degrees') @@ -798,8 +804,12 @@ def smooth_gaussian(scalar_grid, n): # Assume the last two axes represent the horizontal directions sgma_seq = [sgma if i > num_ax - 3 else 0 for i in range(num_ax)] - # Compute smoothed field - return gaussian_filter(scalar_grid, sgma_seq, truncate=2 * np.sqrt(2)) + filter_args = {'sigma': sgma_seq, 'truncate': 2 * np.sqrt(2)} + if hasattr(scalar_grid, 'mask'): + smoothed = gaussian_filter(scalar_grid.data, **filter_args) + return np.ma.array(smoothed, mask=scalar_grid.mask) + else: + return gaussian_filter(scalar_grid, **filter_args) @exporter.export diff --git a/tests/calc/test_basic.py b/tests/calc/test_basic.py index 77a47c10a59..0984803dab3 100644 --- a/tests/calc/test_basic.py +++ b/tests/calc/test_basic.py @@ -15,34 +15,39 @@ pressure_to_height_std, sigma_to_pressure, smooth_circular, smooth_gaussian, smooth_n_point, smooth_rectangular, smooth_window, wind_components, wind_direction, wind_speed, windchill) -from metpy.testing import assert_almost_equal, assert_array_almost_equal, assert_array_equal +from metpy.testing import (assert_almost_equal, assert_array_almost_equal, assert_array_equal, + xfail_dask) from metpy.units import units def test_wind_comps_basic(array_type): """Test the basic wind component calculation.""" - speed = array_type([4, 4, 4, 4, 25, 25, 25, 25, 10.], 'mph') - dirs = array_type([0, 45, 90, 135, 180, 225, 270, 315, 360], 'deg') + mask = [False, True, False, True, False, True, False, True, False] + speed = array_type([4, 4, 4, 4, 25, 25, 25, 25, 10.], 'mph', mask=mask) + dirs = array_type([0, 45, 90, 135, 180, 225, 270, 315, 360], 'deg', mask=mask) s2 = np.sqrt(2.) u, v = wind_components(speed, dirs) - true_u = array_type([0, -4 / s2, -4, -4 / s2, 0, 25 / s2, 25, 25 / s2, 0], 'mph') - true_v = array_type([-4, -4 / s2, 0, 4 / s2, 25, 25 / s2, 0, -25 / s2, -10], 'mph') + true_u = array_type([0, -4 / s2, -4, -4 / s2, 0, 25 / s2, 25, 25 / s2, 0], + 'mph', mask=mask) + true_v = array_type([-4, -4 / s2, 0, 4 / s2, 25, 25 / s2, 0, -25 / s2, -10], + 'mph', mask=mask) assert_array_almost_equal(true_u, u, 4) assert_array_almost_equal(true_v, v, 4) -def test_wind_comps_with_north_and_calm(): +def test_wind_comps_with_north_and_calm(array_type): """Test that the wind component calculation handles northerly and calm winds.""" - speed = np.array([0, 5, 5]) * units.mph - dirs = np.array([0, 360, 0]) * units.deg + mask = [False, True, False] + speed = array_type([0, 5, 5], 'mph', mask=mask) + dirs = array_type([0, 360, 0], 'deg', mask=mask) u, v = wind_components(speed, dirs) - true_u = np.array([0, 0, 0]) * units.mph - true_v = np.array([0, -5, -5]) * units.mph + true_u = array_type([0, 0, 0], 'mph', mask=mask) + true_v = array_type([0, -5, -5], 'mph', mask=mask) assert_array_almost_equal(true_u, u, 4) assert_array_almost_equal(true_v, v, 4) @@ -55,56 +60,47 @@ def test_wind_comps_scalar(): assert_almost_equal(v, 6.9282 * units('m/s'), 3) -def test_speed(): +def test_speed(array_type): """Test calculating wind speed.""" - u = np.array([4., 2., 0., 0.]) * units('m/s') - v = np.array([0., 2., 4., 0.]) * units('m/s') + mask = [False, True, False, True] + u = array_type([4., 2., 0., 0.], 'm/s', mask=mask) + v = array_type([0., 2., 4., 0.], 'm/s', mask=mask) speed = wind_speed(u, v) s2 = np.sqrt(2.) - true_speed = np.array([4., 2 * s2, 4., 0.]) * units('m/s') + true_speed = array_type([4., 2 * s2, 4., 0.], 'm/s', mask=mask) assert_array_almost_equal(true_speed, speed, 4) -def test_direction(): +def test_direction(array_type): """Test calculating wind direction.""" - u = np.array([4., 2., 0., 0.]) * units('m/s') - v = np.array([0., 2., 4., 0.]) * units('m/s') + # The last two (u, v) pairs and their masks test masking calm and negative directions + mask = [False, True, False, True, True] + u = array_type([4., 2., 0., 0., 1.], 'm/s', mask=mask) + v = array_type([0., 2., 4., 0., -1], 'm/s', mask=mask) + + xfail_dask(u, 'Item assignment with not supported') direc = wind_direction(u, v) - true_dir = np.array([270., 225., 180., 0.]) * units.deg + true_dir = array_type([270., 225., 180., 0., 315.], 'degree', mask=mask) assert_array_almost_equal(true_dir, direc, 4) -def test_direction_masked(): - """Test calculating wind direction from masked wind components.""" - mask = np.array([True, False, True, False]) - u = np.array([4., 2., 0., 0.]) - v = np.array([0., 2., 4., 0.]) - - u_masked = units.Quantity(np.ma.array(u, mask=mask), units('m/s')) - v_masked = units.Quantity(np.ma.array(v, mask=mask), units('m/s')) - - direc = wind_direction(u_masked, v_masked) - - true_dir = np.array([270., 225., 180., 0.]) - true_dir_masked = units.Quantity(np.ma.array(true_dir, mask=mask), units.deg) - - assert_array_almost_equal(true_dir_masked, direc, 4) - - -def test_direction_with_north_and_calm(): +def test_direction_with_north_and_calm(array_type): """Test how wind direction handles northerly and calm winds.""" - u = np.array([0., -0., 0.]) * units('m/s') - v = np.array([0., 0., -5.]) * units('m/s') + mask = [False, False, False, True, True] + u = array_type([0., -0., 0., 1., 1.], 'm/s', mask=mask) + v = array_type([0., 0., -5., 1., 1.], 'm/s', mask=mask) + + xfail_dask(u, 'Boolean index assignment in Dask expects equally shaped arrays') direc = wind_direction(u, v) - true_dir = np.array([0., 0., 360.]) * units.deg + true_dir = array_type([0., 0., 360., 225., 225.], 'deg', mask=mask) assert_array_almost_equal(true_dir, direc, 4) @@ -115,11 +111,17 @@ def test_direction_dimensions(): assert str(d.units) == 'degree' -def test_oceanographic_direction(): +def test_oceanographic_direction(array_type): """Test oceanographic direction (to) convention.""" - d = wind_direction(5 * units('m/s'), -5 * units('m/s'), convention='to') - true_dir = 135 * units.deg - assert_almost_equal(d, true_dir, 4) + mask = [False, True, False] + u = array_type([5., 5., 0.], 'm/s', mask=mask) + v = array_type([-5., 0., 5.], 'm/s', mask=mask) + + xfail_dask(u, 'Boolean index assignment in Dask expects equally shaped arrays') + + direc = wind_direction(u, v, convention='to') + true_dir = array_type([135., 90., 360.], 'deg', mask=mask) + assert_almost_equal(direc, true_dir, 4) def test_invalid_direction_convention(): @@ -161,13 +163,13 @@ def test_windchill_scalar(): assert_almost_equal(wc, -18.9357 * units.degC, 0) -def test_windchill_basic(): +def test_windchill_basic(array_type): """Test the basic wind chill calculation.""" - temp = np.array([40, -10, -45, 20]) * units.degF - speed = np.array([5, 55, 25, 15]) * units.mph + temp = array_type([40, -10, -45, 20], 'degF') + speed = array_type([5, 55, 25, 15], 'mph') wc = windchill(temp, speed) - values = np.array([36, -46, -84, 6]) * units.degF + values = array_type([36, -46, -84, 6], 'degF') assert_array_almost_equal(wc, values, 0) @@ -209,13 +211,16 @@ def test_windchill_face_level(): assert_array_almost_equal(wc, values, 0) -def test_heat_index_basic(): +def test_heat_index_basic(array_type): """Test the basic heat index calculation.""" - temp = np.array([80, 88, 92, 110, 86]) * units.degF - rh = np.array([40, 100, 70, 40, 88]) * units.percent + mask = [False, True, False, True, False] + temp = array_type([80, 88, 92, 110, 86], 'degF', mask=mask) + rh = array_type([40, 100, 70, 40, 88], 'percent', mask=mask) + + xfail_dask(temp, 'operands could not be broadcast together with shapes (0, 5) (nan,)') hi = heat_index(temp, rh) - values = np.array([80, 121, 112, 136, 104]) * units.degF + values = array_type([80, 121, 112, 136, 104], 'degF', mask=mask) assert_array_almost_equal(hi, values, 0) @@ -281,12 +286,13 @@ def test_heat_index_kelvin(): assert_almost_equal(hi.to('degC'), 50.3406 * units.degC, 4) -def test_height_to_geopotential(): +def test_height_to_geopotential(array_type): """Test conversion from height to geopotential.""" - height = units.Quantity([0, 1000, 2000, 3000], units.m) + mask = [False, True, False, True] + height = array_type([0, 1000, 2000, 3000], 'meter', mask=mask) geopot = height_to_geopotential(height) - assert_array_almost_equal(geopot, units.Quantity([0., 9805, 19607, - 29406], units('m**2 / second**2')), 0) + truth = array_type([0., 9805, 19607, 29406], 'm**2 / second**2', mask=mask) + assert_array_almost_equal(geopot, truth, 0) # See #1075 regarding previous destructive cancellation in floating point @@ -299,12 +305,17 @@ def test_height_to_geopotential_32bit(): assert_almost_equal(height_to_geopotential(heights), truth, 2) -def test_geopotential_to_height(): +def test_geopotential_to_height(array_type): """Test conversion from geopotential to height.""" - geopotential = units.Quantity([0., 9805.11102602, 19607.14506998, 29406.10358006], - units('m**2 / second**2')) + mask = [False, True, False, True] + geopotential = array_type( + [0., 9805.11102602, 19607.14506998, 29406.10358006], + 'm**2 / second**2', + mask=mask, + ) height = geopotential_to_height(geopotential) - assert_array_almost_equal(height, units.Quantity([0, 1000, 2000, 3000], units.m), 0) + truth = array_type([0, 1000, 2000, 3000], 'meter', mask=mask) + assert_array_almost_equal(height, truth, 0) # See #1075 regarding previous destructive cancellation in floating point @@ -317,20 +328,22 @@ def test_geopotential_to_height_32bit(): assert_almost_equal(geopotential_to_height(geopot), truth, 2) -def test_pressure_to_heights_basic(): +def test_pressure_to_heights_basic(array_type): """Test basic pressure to height calculation for standard atmosphere.""" - pressures = np.array([975.2, 987.5, 956., 943.]) * units.mbar + mask = [False, True, False, True] + pressures = array_type([975.2, 987.5, 956., 943.], 'mbar', mask=mask) heights = pressure_to_height_std(pressures) - values = np.array([321.5, 216.5, 487.6, 601.7]) * units.meter - assert_almost_equal(heights, values, 1) + values = array_type([321.5, 216.5, 487.6, 601.7], 'meter', mask=mask) + assert_array_almost_equal(heights, values, 1) -def test_heights_to_pressure_basic(): +def test_heights_to_pressure_basic(array_type): """Test basic height to pressure calculation for standard atmosphere.""" - heights = np.array([321.5, 216.5, 487.6, 601.7]) * units.meter + mask = [False, True, False, True] + heights = array_type([321.5, 216.5, 487.6, 601.7], 'meter', mask=mask) pressures = height_to_pressure_std(heights) - values = np.array([975.2, 987.5, 956., 943.]) * units.mbar - assert_almost_equal(pressures, values, 1) + values = array_type([975.2, 987.5, 956., 943.], 'mbar', mask=mask) + assert_array_almost_equal(pressures, values, 1) def test_pressure_to_heights_units(): @@ -338,33 +351,44 @@ def test_pressure_to_heights_units(): assert_almost_equal(pressure_to_height_std(29 * units.inHg), 262.8498 * units.meter, 3) -def test_coriolis_force(): +def test_coriolis_force(array_type): """Test basic coriolis force calculation.""" - lat = np.array([-90., -30., 0., 30., 90.]) * units.degrees + mask = [False, True, False, True, False] + lat = array_type([-90., -30., 0., 30., 90.], 'degrees', mask=mask) cor = coriolis_parameter(lat) - values = np.array([-1.4584232E-4, -.72921159E-4, 0, .72921159E-4, - 1.4584232E-4]) * units('s^-1') - assert_almost_equal(cor, values, 7) + values = array_type([-1.4584232E-4, -.72921159E-4, 0, .72921159E-4, + 1.4584232E-4], 's^-1', mask=mask) + assert_array_almost_equal(cor, values, 7) -def test_add_height_to_pressure(): +def test_add_height_to_pressure(array_type): """Test the pressure at height above pressure calculation.""" - pressure = add_height_to_pressure(1000 * units.hPa, 877.17421094 * units.meter) - assert_almost_equal(pressure, 900 * units.hPa, 2) + mask = [False, True, False] + pressure_in = array_type([1000., 900., 800.], 'hPa', mask=mask) + height = array_type([877.17421094, 500., 300.], 'meter', mask=mask) + pressure_out = add_height_to_pressure(pressure_in, height) + truth = array_type([900., 846.725, 770.666], 'hPa', mask=mask) + assert_array_almost_equal(pressure_out, truth, 2) -def test_add_pressure_to_height(): +def test_add_pressure_to_height(array_type): """Test the height at pressure above height calculation.""" - height = add_pressure_to_height(110.8286757 * units.m, 100 * units.hPa) - assert_almost_equal(height, 987.971601 * units.meter, 3) + mask = [False, True, False] + height_in = array_type([110.8286757, 250., 500.], 'meter', mask=mask) + pressure = array_type([100., 200., 300.], 'hPa', mask=mask) + height_out = add_pressure_to_height(height_in, pressure) + truth = array_type([987.971601, 2114.957, 3534.348], 'meter', mask=mask) + assert_array_almost_equal(height_out, truth, 3) -def test_sigma_to_pressure(): +def test_sigma_to_pressure(array_type): """Test sigma_to_pressure.""" surface_pressure = 1000. * units.hPa model_top_pressure = 0. * units.hPa - sigma = np.arange(0., 1.1, 0.1) - expected = np.arange(0., 1100., 100.) * units.hPa + sigma_values = np.arange(0., 1.1, 0.1) + mask = np.zeros_like(sigma_values)[::2] = 1 + sigma = array_type(sigma_values, '', mask=mask) + expected = array_type(np.arange(0., 1100., 100.), 'hPa', mask=mask) pressure = sigma_to_pressure(sigma, surface_pressure, model_top_pressure) assert_array_almost_equal(pressure, expected, 5) @@ -389,14 +413,21 @@ def test_coriolis_units(): assert f.units == units('1/second') -def test_apparent_temperature(): +def test_apparent_temperature(array_type): """Test the apparent temperature calculation.""" - temperature = np.array([[90, 90, 70], - [20, 20, 60]]) * units.degF - rel_humidity = np.array([[60, 20, 60], - [10, 10, 10]]) * units.percent - wind = np.array([[5, 3, 3], - [10, 1, 10]]) * units.mph + temperature = array_type([[90, 90, 70], + [20, 20, 60]], 'degF') + rel_humidity = array_type([[60, 20, 60], + [10, 10, 10]], 'percent') + wind = array_type([[5, 3, 3], + [10, 1, 10]], 'mph') + + reason = ( + 'boolean index did not match indexed array along dimension 0; dimension is 2 but ' + 'corresponding boolean dimension is 3' + ) + xfail_dask(temperature, reason) + truth = units.Quantity(np.ma.array([[99.6777178, 86.3357671, 70], [8.8140662, 20, 60]], mask=[[False, False, True], [False, True, True]]), units.degF) @@ -455,34 +486,41 @@ def test_apparent_temperature_mask_undefined_true(): assert_array_equal(app_temperature.mask, mask) -def test_smooth_gaussian(): +def test_smooth_gaussian(array_type): """Test the smooth_gaussian function with a larger n.""" m = 10 s = np.zeros((m, m)) + for i in np.ndindex(s.shape): s[i] = i[0] + i[1]**2 - s = smooth_gaussian(s, 4) - s_true = np.array([[0.40077472, 1.59215426, 4.59665817, 9.59665817, 16.59665817, - 25.59665817, 36.59665817, 49.59665817, 64.51108392, 77.87487258], - [1.20939518, 2.40077472, 5.40527863, 10.40527863, 17.40527863, - 26.40527863, 37.40527863, 50.40527863, 65.31970438, 78.68349304], - [2.20489127, 3.39627081, 6.40077472, 11.40077472, 18.40077472, - 27.40077472, 38.40077472, 51.40077472, 66.31520047, 79.67898913], - [3.20489127, 4.39627081, 7.40077472, 12.40077472, 19.40077472, - 28.40077472, 39.40077472, 52.40077472, 67.31520047, 80.67898913], - [4.20489127, 5.39627081, 8.40077472, 13.40077472, 20.40077472, - 29.40077472, 40.40077472, 53.40077472, 68.31520047, 81.67898913], - [5.20489127, 6.39627081, 9.40077472, 14.40077472, 21.40077472, - 30.40077472, 41.40077472, 54.40077472, 69.31520047, 82.67898913], - [6.20489127, 7.39627081, 10.40077472, 15.40077472, 22.40077472, - 31.40077472, 42.40077472, 55.40077472, 70.31520047, 83.67898913], - [7.20489127, 8.39627081, 11.40077472, 16.40077472, 23.40077472, - 32.40077472, 43.40077472, 56.40077472, 71.31520047, 84.67898913], - [8.20038736, 9.3917669, 12.39627081, 17.39627081, 24.39627081, - 33.39627081, 44.39627081, 57.39627081, 72.31069656, 85.67448522], - [9.00900782, 10.20038736, 13.20489127, 18.20489127, 25.20489127, - 34.20489127, 45.20489127, 58.20489127, 73.11931702, 86.48310568]]) - assert_array_almost_equal(s, s_true) + + mask = np.zeros_like(s) + mask[::2, ::2] = 1 + scalar_grid = array_type(s, '', mask=mask) + + s_actual = smooth_gaussian(scalar_grid, 4) + s_true = array_type([[0.40077472, 1.59215426, 4.59665817, 9.59665817, 16.59665817, + 25.59665817, 36.59665817, 49.59665817, 64.51108392, 77.87487258], + [1.20939518, 2.40077472, 5.40527863, 10.40527863, 17.40527863, + 26.40527863, 37.40527863, 50.40527863, 65.31970438, 78.68349304], + [2.20489127, 3.39627081, 6.40077472, 11.40077472, 18.40077472, + 27.40077472, 38.40077472, 51.40077472, 66.31520047, 79.67898913], + [3.20489127, 4.39627081, 7.40077472, 12.40077472, 19.40077472, + 28.40077472, 39.40077472, 52.40077472, 67.31520047, 80.67898913], + [4.20489127, 5.39627081, 8.40077472, 13.40077472, 20.40077472, + 29.40077472, 40.40077472, 53.40077472, 68.31520047, 81.67898913], + [5.20489127, 6.39627081, 9.40077472, 14.40077472, 21.40077472, + 30.40077472, 41.40077472, 54.40077472, 69.31520047, 82.67898913], + [6.20489127, 7.39627081, 10.40077472, 15.40077472, 22.40077472, + 31.40077472, 42.40077472, 55.40077472, 70.31520047, 83.67898913], + [7.20489127, 8.39627081, 11.40077472, 16.40077472, 23.40077472, + 32.40077472, 43.40077472, 56.40077472, 71.31520047, 84.67898913], + [8.20038736, 9.3917669, 12.39627081, 17.39627081, 24.39627081, + 33.39627081, 44.39627081, 57.39627081, 72.31069656, 85.67448522], + [9.00900782, 10.20038736, 13.20489127, 18.20489127, 25.20489127, + 34.20489127, 45.20489127, 58.20489127, 73.11931702, 86.48310568]], + '', mask=mask) + assert_array_almost_equal(s_actual, s_true) def test_smooth_gaussian_small_n(): @@ -517,19 +555,19 @@ def test_smooth_gaussian_3d_units(): assert_array_almost_equal(s[1, :, :], s_true) -def test_smooth_n_pt_5(): +def test_smooth_n_pt_5(array_type): """Test the smooth_n_pt function using 5 points.""" - hght = np.array([[5640., 5640., 5640., 5640., 5640.], - [5684., 5676., 5666., 5659., 5651.], - [5728., 5712., 5692., 5678., 5662.], - [5772., 5748., 5718., 5697., 5673.], - [5816., 5784., 5744., 5716., 5684.]]) + hght = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5676., 5666., 5659., 5651.], + [5728., 5712., 5692., 5678., 5662.], + [5772., 5748., 5718., 5697., 5673.], + [5816., 5784., 5744., 5716., 5684.]], '') shght = smooth_n_point(hght, 5, 1) - s_true = np.array([[5640., 5640., 5640., 5640., 5640.], - [5684., 5675.75, 5666.375, 5658.875, 5651.], - [5728., 5711.5, 5692.75, 5677.75, 5662.], - [5772., 5747.25, 5719.125, 5696.625, 5673.], - [5816., 5784., 5744., 5716., 5684.]]) + s_true = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5675.75, 5666.375, 5658.875, 5651.], + [5728., 5711.5, 5692.75, 5677.75, 5662.], + [5772., 5747.25, 5719.125, 5696.625, 5673.], + [5816., 5784., 5744., 5716., 5684.]], '') assert_array_almost_equal(shght, s_true) @@ -652,19 +690,19 @@ def test_smooth_gaussian_temperature(): assert_array_almost_equal(smooth_t, smooth_t_true, 4) -def test_smooth_window(): +def test_smooth_window(array_type): """Test smooth_window with default configuration.""" - hght = [[5640., 5640., 5640., 5640., 5640.], - [5684., 5676., 5666., 5659., 5651.], - [5728., 5712., 5692., 5678., 5662.], - [5772., 5748., 5718., 5697., 5673.], - [5816., 5784., 5744., 5716., 5684.]] * units.m + hght = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5676., 5666., 5659., 5651.], + [5728., 5712., 5692., 5678., 5662.], + [5772., 5748., 5718., 5697., 5673.], + [5816., 5784., 5744., 5716., 5684.]], 'meter') smoothed = smooth_window(hght, np.array([[1, 0, 1], [0, 0, 0], [1, 0, 1]])) - truth = [[5640., 5640., 5640., 5640., 5640.], - [5684., 5675., 5667.5, 5658.5, 5651.], - [5728., 5710., 5695., 5677., 5662.], - [5772., 5745., 5722.5, 5695.5, 5673.], - [5816., 5784., 5744., 5716., 5684.]] * units.m + truth = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5675., 5667.5, 5658.5, 5651.], + [5728., 5710., 5695., 5677., 5662.], + [5772., 5745., 5722.5, 5695.5, 5673.], + [5816., 5784., 5744., 5716., 5684.]], 'meter') assert_array_almost_equal(smoothed, truth) @@ -685,35 +723,35 @@ def test_smooth_window_1d_dataarray(): xr.testing.assert_allclose(smoothed, truth) -def test_smooth_rectangular(): +def test_smooth_rectangular(array_type): """Test smooth_rectangular with default configuration.""" - hght = [[5640., 5640., 5640., 5640., 5640.], - [5684., 5676., 5666., 5659., 5651.], - [5728., 5712., 5692., 5678., 5662.], - [5772., 5748., 5718., 5697., 5673.], - [5816., 5784., 5744., 5716., 5684.]] * units.m + hght = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5676., 5666., 5659., 5651.], + [5728., 5712., 5692., 5678., 5662.], + [5772., 5748., 5718., 5697., 5673.], + [5816., 5784., 5744., 5716., 5684.]], 'meter') smoothed = smooth_rectangular(hght, (5, 3)) - truth = [[5640., 5640., 5640., 5640., 5640.], - [5684., 5676., 5666., 5659., 5651.], - [5728., 5710.66667, 5694., 5677.33333, 5662.], - [5772., 5748., 5718., 5697., 5673.], - [5816., 5784., 5744., 5716., 5684.]] * units.m + truth = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5676., 5666., 5659., 5651.], + [5728., 5710.66667, 5694., 5677.33333, 5662.], + [5772., 5748., 5718., 5697., 5673.], + [5816., 5784., 5744., 5716., 5684.]], 'meter') assert_array_almost_equal(smoothed, truth, 4) -def test_smooth_circular(): +def test_smooth_circular(array_type): """Test smooth_circular with default configuration.""" - hght = [[5640., 5640., 5640., 5640., 5640.], - [5684., 5676., 5666., 5659., 5651.], - [5728., 5712., 5692., 5678., 5662.], - [5772., 5748., 5718., 5697., 5673.], - [5816., 5784., 5744., 5716., 5684.]] * units.m + hght = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5676., 5666., 5659., 5651.], + [5728., 5712., 5692., 5678., 5662.], + [5772., 5748., 5718., 5697., 5673.], + [5816., 5784., 5744., 5716., 5684.]], 'meter') smoothed = smooth_circular(hght, 2, 2) - truth = [[5640., 5640., 5640., 5640., 5640.], - [5684., 5676., 5666., 5659., 5651.], - [5728., 5712., 5693.98817, 5678., 5662.], - [5772., 5748., 5718., 5697., 5673.], - [5816., 5784., 5744., 5716., 5684.]] * units.m + truth = array_type([[5640., 5640., 5640., 5640., 5640.], + [5684., 5676., 5666., 5659., 5651.], + [5728., 5712., 5693.98817, 5678., 5662.], + [5772., 5748., 5718., 5697., 5673.], + [5816., 5784., 5744., 5716., 5684.]], 'meter') assert_array_almost_equal(smoothed, truth, 4) @@ -734,13 +772,16 @@ def test_altimeter_to_station_pressure_inhg(): assert_almost_equal(res, truth, 3) -def test_altimeter_to_station_pressure_hpa(): +def test_altimeter_to_station_pressure_hpa(array_type): """Test the altimeter to station pressure function with hectopascals.""" - altim = 1013 * units.hectopascal - elev = 500 * units.m + mask = [False, True, False, True] + altim = array_type([1000., 1005., 1010., 1013.], 'hectopascal', mask=mask) + elev = array_type([2000., 1500., 1000., 500.], 'meter', mask=mask) res = altimeter_to_station_pressure(altim, elev) - truth = 954.639265 * units.hectopascal - assert_almost_equal(res, truth, 3) + truth = array_type( + [784.262996, 838.651657, 896.037821, 954.639265], 'hectopascal', mask=mask + ) + assert_array_almost_equal(res, truth, 3) def test_altimiter_to_sea_level_pressure_inhg(): @@ -753,11 +794,14 @@ def test_altimiter_to_sea_level_pressure_inhg(): assert_almost_equal(res, truth, 3) -def test_altimeter_to_sea_level_pressure_hpa(): +def test_altimeter_to_sea_level_pressure_hpa(array_type): """Test the altimeter to sea level pressure function with hectopascals.""" - altim = 1013 * units.hectopascal - elev = 500 * units.m - temp = 0 * units.degC + mask = [False, True, False, True] + altim = array_type([1000., 1005., 1010., 1013], 'hectopascal', mask=mask) + elev = array_type([2000., 1500., 1000., 500.], 'meter', mask=mask) + temp = array_type([-3., -2., -1., 0.], 'degC') res = altimeter_to_sea_level_pressure(altim, elev, temp) - truth = 1016.246 * units.hectopascal - assert_almost_equal(res, truth, 3) + truth = array_type( + [1009.963556, 1013.119712, 1015.885392, 1016.245615], 'hectopascal', mask=mask + ) + assert_array_almost_equal(res, truth, 3)