|
| 1 | +""" |
| 2 | +Integration tests for the :func:`esmvalcore.preprocessor.regrid.regrid` |
| 3 | +function. |
| 4 | +
|
| 5 | +""" |
| 6 | + |
| 7 | +import unittest |
| 8 | + |
| 9 | +import iris |
| 10 | +import numpy as np |
| 11 | + |
| 12 | +import tests |
| 13 | +from esmvalcore.preprocessor import extract_coordinate_points |
| 14 | +from tests.unit.preprocessor._regrid import _make_cube |
| 15 | + |
| 16 | + |
| 17 | +class Test(tests.Test): |
| 18 | + def setUp(self): |
| 19 | + """Prepare tests.""" |
| 20 | + shape = (3, 4, 4) |
| 21 | + data = np.arange(np.prod(shape)).reshape(shape) |
| 22 | + self.cube = _make_cube(data, dtype=np.float64, rotated=True) |
| 23 | + self.cs = iris.coord_systems.GeogCS(iris.fileformats.pp.EARTH_RADIUS) |
| 24 | + |
| 25 | + def test_extract_point__single_linear(self): |
| 26 | + """Test linear interpolation when extracting a single point""" |
| 27 | + point = extract_coordinate_points( |
| 28 | + self.cube, |
| 29 | + {'grid_latitude': 2.1, 'grid_longitude': 2.1}, |
| 30 | + scheme='linear') |
| 31 | + self.assertEqual(point.shape, (3,)) |
| 32 | + np.testing.assert_allclose(point.data, [5.5, 21.5, 37.5]) |
| 33 | + |
| 34 | + # Exactly centred between grid points. |
| 35 | + point = extract_coordinate_points( |
| 36 | + self.cube, |
| 37 | + {'grid_latitude': 2.5, 'grid_longitude': 2.5}, |
| 38 | + scheme='linear') |
| 39 | + self.assertEqual(point.shape, (3,)) |
| 40 | + np.testing.assert_allclose(point.data, [7.5, 23.5, 39.5]) |
| 41 | + |
| 42 | + # On a (edge) grid point. |
| 43 | + point = extract_coordinate_points( |
| 44 | + self.cube, |
| 45 | + {'grid_latitude': 4, 'grid_longitude': 4}, |
| 46 | + scheme='linear') |
| 47 | + self.assertEqual(point.shape, (3,)) |
| 48 | + np.testing.assert_allclose(point.data, [15, 31, 47]) |
| 49 | + |
| 50 | + # Test two points outside the valid area. |
| 51 | + # These should be masked, since we set up the interpolation |
| 52 | + # schemes that way. |
| 53 | + point = extract_coordinate_points( |
| 54 | + self.cube, |
| 55 | + {'grid_latitude': -1, 'grid_longitude': -1}, |
| 56 | + scheme='linear') |
| 57 | + self.assertEqual(point.shape, (3,)) |
| 58 | + masked = np.ma.array([np.nan] * 3, mask=True) |
| 59 | + self.assert_array_equal(point.data, masked) |
| 60 | + |
| 61 | + point = extract_coordinate_points( |
| 62 | + self.cube, |
| 63 | + {'grid_latitude': 30, 'grid_longitude': 30}, |
| 64 | + scheme='linear') |
| 65 | + self.assertEqual(point.shape, (3,)) |
| 66 | + self.assert_array_equal(point.data, masked) |
| 67 | + |
| 68 | + def test_extract_point__single_nearest(self): |
| 69 | + """Test nearest match when extracting a single point""" |
| 70 | + |
| 71 | + point = extract_coordinate_points( |
| 72 | + self.cube, |
| 73 | + {'grid_latitude': 2.1, 'grid_longitude': 2.1}, |
| 74 | + scheme='nearest') |
| 75 | + self.assertEqual(point.shape, (3,)) |
| 76 | + np.testing.assert_allclose(point.data, [5, 21, 37]) |
| 77 | + |
| 78 | + point = extract_coordinate_points( |
| 79 | + self.cube, |
| 80 | + {'grid_latitude': 4, 'grid_longitude': 4}, |
| 81 | + scheme='nearest') |
| 82 | + self.assertEqual(point.shape, (3,)) |
| 83 | + np.testing.assert_allclose(point.data, [15, 31, 47]) |
| 84 | + |
| 85 | + # Test two points outside the valid area |
| 86 | + point = extract_coordinate_points( |
| 87 | + self.cube, |
| 88 | + {'grid_latitude': -1, 'grid_longitude': -1}, |
| 89 | + scheme='nearest') |
| 90 | + self.assertEqual(point.shape, (3,)) |
| 91 | + masked = np.ma.array(np.empty(3, dtype=np.float64), mask=True) |
| 92 | + self.assert_array_equal(point.data, masked) |
| 93 | + |
| 94 | + point = extract_coordinate_points( |
| 95 | + self.cube, |
| 96 | + {'grid_latitude': 30, 'grid_longitude': 30}, |
| 97 | + scheme='nearest') |
| 98 | + self.assertEqual(point.shape, (3,)) |
| 99 | + self.assert_array_equal(point.data, masked) |
| 100 | + |
| 101 | + def test_extract_point__multiple_linear(self): |
| 102 | + """Test linear interpolation for an array of one coordinate""" |
| 103 | + |
| 104 | + # Test points on the grid edges, on a grid point, halfway and |
| 105 | + # one in between. |
| 106 | + coords = self.cube.coords(dim_coords=True) |
| 107 | + print([coord.standard_name for coord in coords]) |
| 108 | + |
| 109 | + point = extract_coordinate_points( |
| 110 | + self.cube, |
| 111 | + {'grid_latitude': [1, 1.1, 1.5, 2, 4], |
| 112 | + 'grid_longitude': 2}, |
| 113 | + scheme='linear') |
| 114 | + self.assertEqual(point.shape, (3, 5)) |
| 115 | + # Longitude is not a dimension coordinate anymore. |
| 116 | + self.assertEqual(['air_pressure', 'grid_latitude'], [ |
| 117 | + coord.standard_name for coord in point.coords(dim_coords=True)]) |
| 118 | + np.testing.assert_allclose(point.data, [[1, 1.4, 3, 5, 13], |
| 119 | + [17, 17.4, 19., 21., 29], |
| 120 | + [33, 33.4, 35, 37, 45]]) |
| 121 | + |
| 122 | + point = extract_coordinate_points( |
| 123 | + self.cube, |
| 124 | + {'grid_latitude': 4, |
| 125 | + 'grid_longitude': [1, 1.1, 1.5, 2, 4]}, |
| 126 | + scheme='linear') |
| 127 | + self.assertEqual(point.shape, (3, 5)) |
| 128 | + self.assertEqual(['air_pressure', 'grid_longitude'], [ |
| 129 | + coord.standard_name for coord in point.coords(dim_coords=True)]) |
| 130 | + np.testing.assert_allclose(point.data, [[12, 12.1, 12.5, 13, 15], |
| 131 | + [28, 28.1, 28.5, 29, 31], |
| 132 | + [44, 44.1, 44.5, 45, 47]]) |
| 133 | + |
| 134 | + # Test latitude and longitude points outside the grid. |
| 135 | + # These should all be masked. |
| 136 | + coords = self.cube.coords(dim_coords=True) |
| 137 | + point = extract_coordinate_points( |
| 138 | + self.cube, |
| 139 | + {'grid_latitude': [0, 10], 'grid_longitude': 3}, |
| 140 | + scheme='linear') |
| 141 | + self.assertEqual(point.shape, (3, 2)) |
| 142 | + masked = np.ma.array(np.empty((3, 2), dtype=np.float64), mask=True) |
| 143 | + self.assert_array_equal(point.data, masked) |
| 144 | + coords = self.cube.coords(dim_coords=True) |
| 145 | + point = extract_coordinate_points( |
| 146 | + self.cube, |
| 147 | + {'grid_latitude': 2, 'grid_longitude': [0, 10]}, |
| 148 | + scheme='linear') |
| 149 | + coords = point.coords(dim_coords=True) |
| 150 | + self.assertEqual(point.shape, (3, 2)) |
| 151 | + self.assert_array_equal(point.data, masked) |
| 152 | + |
| 153 | + def test_extract_point__multiple_nearest(self): |
| 154 | + """Test nearest match for an array of one coordinate""" |
| 155 | + |
| 156 | + point = extract_coordinate_points( |
| 157 | + self.cube, |
| 158 | + {'grid_latitude': [1, 1.1, 1.5, 1.501, 2, 4], |
| 159 | + 'grid_longitude': 2}, |
| 160 | + scheme='nearest') |
| 161 | + self.assertEqual(point.shape, (3, 6)) |
| 162 | + self.assertEqual(['air_pressure', 'grid_latitude'], [ |
| 163 | + coord.standard_name for coord in point.coords(dim_coords=True)]) |
| 164 | + np.testing.assert_allclose(point.data, [[1, 1, 1, 5, 5, 13], |
| 165 | + [17, 17, 17, 21, 21, 29], |
| 166 | + [33, 33, 33, 37, 37, 45]]) |
| 167 | + point = extract_coordinate_points( |
| 168 | + self.cube, |
| 169 | + {'grid_latitude': 4, |
| 170 | + 'grid_longitude': [1, 1.1, 1.5, 1.501, 2, 4]}, |
| 171 | + scheme='nearest') |
| 172 | + self.assertEqual(point.shape, (3, 6)) |
| 173 | + self.assertEqual(['air_pressure', 'grid_longitude'], [ |
| 174 | + coord.standard_name for coord in point.coords(dim_coords=True)]) |
| 175 | + np.testing.assert_allclose(point.data, [[12, 12, 12, 13, 13, 15], |
| 176 | + [28, 28, 28, 29, 29, 31], |
| 177 | + [44, 44, 44, 45, 45, 47]]) |
| 178 | + point = extract_coordinate_points( |
| 179 | + self.cube, |
| 180 | + {'grid_latitude': [0, 10], |
| 181 | + 'grid_longitude': 3}, |
| 182 | + scheme='nearest') |
| 183 | + masked = np.ma.array(np.empty((3, 2), dtype=np.float64), mask=True) |
| 184 | + self.assertEqual(point.shape, (3, 2)) |
| 185 | + self.assert_array_equal(point.data, masked) |
| 186 | + point = extract_coordinate_points( |
| 187 | + self.cube, |
| 188 | + {'grid_latitude': 2, |
| 189 | + 'grid_longitude': [0, 10]}, |
| 190 | + scheme='nearest') |
| 191 | + self.assertEqual(point.shape, (3, 2)) |
| 192 | + self.assert_array_equal(point.data, masked) |
| 193 | + |
| 194 | + def test_extract_point__multiple_both_linear(self): |
| 195 | + """Test for both latitude and longitude arrays, with |
| 196 | + linear interpolation""" |
| 197 | + point = extract_coordinate_points( |
| 198 | + self.cube, |
| 199 | + {'grid_latitude': [0, 1.1, 1.5, 1.51, 4, 5], |
| 200 | + 'grid_longitude': [0, 1.1, 1.5, 1.51, 4, 5]}, scheme='linear') |
| 201 | + self.assertEqual(point.data.shape, (3, 6, 6)) |
| 202 | + |
| 203 | + result = np.ma.array(np.empty((3, 6, 6), dtype=np.float64), mask=True) |
| 204 | + result[0, 1, 1:5] = [0.5, 0.9, 0.91, 3.4] |
| 205 | + result[0, 2, 1:5] = [2.1, 2.5, 2.51, 5.0] |
| 206 | + result[0, 3, 1:5] = [2.14, 2.54, 2.55, 5.04] |
| 207 | + result[0, 4, 1:5] = [12.1, 12.5, 12.51, 15.0] |
| 208 | + |
| 209 | + result[1, 1, 1:5] = [16.5, 16.9, 16.91, 19.4] |
| 210 | + result[1, 2, 1:5] = [18.10, 18.5, 18.51, 21.0] |
| 211 | + result[1, 3, 1:5] = [18.14, 18.54, 18.55, 21.04] |
| 212 | + result[1, 4, 1:5] = [28.1, 28.5, 28.51, 31.0] |
| 213 | + |
| 214 | + result[2, 1, 1:5] = [32.5, 32.9, 32.91, 35.4] |
| 215 | + result[2, 2, 1:5] = [34.1, 34.5, 34.51, 37] |
| 216 | + result[2, 3, 1:5] = [34.14, 34.54, 34.55, 37.04] |
| 217 | + result[2, 4, 1:5] = [44.1, 44.5, 44.51, 47] |
| 218 | + # Unmask the inner area of the result array. |
| 219 | + # The outer edges of the extracted points are outside the cube |
| 220 | + # grid, and should thus be masked. |
| 221 | + result.mask[:, 1:5, 1:5] = False |
| 222 | + |
| 223 | + np.testing.assert_allclose(point.data, result) |
| 224 | + |
| 225 | + def test_extract_point__multiple_both_nearest(self): |
| 226 | + """Test for both latitude and longitude arrays, with nearest match""" |
| 227 | + point = extract_coordinate_points( |
| 228 | + self.cube, |
| 229 | + {'grid_latitude': [0, 1.1, 1.5, 1.51, 4, 5], |
| 230 | + 'grid_longitude': [0, 1.1, 1.5, 1.51, 4, 5]}, |
| 231 | + scheme='nearest') |
| 232 | + self.assertEqual(point.data.shape, (3, 6, 6)) |
| 233 | + |
| 234 | + result = np.ma.array(np.empty((3, 6, 6), dtype=np.float64), mask=True) |
| 235 | + result[0, 1, 1:5] = [0.0, 0.0, 1.0, 3.0] |
| 236 | + result[0, 2, 1:5] = [0.0, 0.0, 1.0, 3.0] |
| 237 | + result[0, 3, 1:5] = [4.0, 4.0, 5.0, 7.0] |
| 238 | + result[0, 4, 1:5] = [12.0, 12.0, 13.0, 15.0] |
| 239 | + |
| 240 | + result[1, 1, 1:5] = [16.0, 16.0, 17.0, 19.0] |
| 241 | + result[1, 2, 1:5] = [16.0, 16.0, 17.0, 19.0] |
| 242 | + result[1, 3, 1:5] = [20.0, 20.0, 21.0, 23.0] |
| 243 | + result[1, 4, 1:5] = [28.0, 28.0, 29.0, 31.0] |
| 244 | + |
| 245 | + result[2, 1, 1:5] = [32.0, 32.0, 33.0, 35.0] |
| 246 | + result[2, 2, 1:5] = [32.0, 32.0, 33.0, 35.0] |
| 247 | + result[2, 3, 1:5] = [36.0, 36.0, 37.0, 39.0] |
| 248 | + result[2, 4, 1:5] = [44.0, 44.0, 45.0, 47.0] |
| 249 | + result.mask[:, 1:5, 1:5] = False |
| 250 | + |
| 251 | + np.testing.assert_allclose(point.data, result) |
| 252 | + |
| 253 | + def test_wrong_interpolation_scheme(self): |
| 254 | + """Test wrong interpolation scheme raises error.""" |
| 255 | + self.assertRaises( |
| 256 | + ValueError, |
| 257 | + extract_coordinate_points, |
| 258 | + self.cube, {'grid_latitude': 0.}, 'wrong') |
| 259 | + |
| 260 | + |
| 261 | +if __name__ == '__main__': |
| 262 | + unittest.main() |
0 commit comments