def test_fail_coords_bad_units(self): # Check error with bad coords units. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) co_y.units = 'm' with self.assertRaisesRegexp(ValueError, 'must have angular units'): gridcell_angles(co_x, co_y)
def test_fail_different_shapes(self): # Check error with mismatched shapes. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) co_y = co_y[1:] with self.assertRaisesRegexp(ValueError, 'must have same shape'): gridcell_angles(co_x, co_y)
def test_fail_noncoord_coord(self): # Check that passing an array + a coord gives an error. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) with self.assertRaisesRegexp(ValueError, 'is a Coordinate, but .* is not'): gridcell_angles(co_x.points, co_y)
def test_fail_coords_bad_units(self): # Check error with bad coords units. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) co_y.units = "m" with self.assertRaisesRegex(ValueError, "must have angular units"): gridcell_angles(co_x, co_y)
def test_fail_coord_noncoord(self): # Check that passing a coord + an array gives an error. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) with self.assertRaisesRegex(ValueError, 'is a Coordinate, but .* is not'): gridcell_angles(co_x, co_y.bounds)
def test_fail_different_coord_system(self): # Check error with mismatched coord systems. cube = sample_2d_latlons(regional=True, rotated=True) cube.coord(axis="x").coord_system = None with self.assertRaisesRegex(ValueError, "must have same coordinate system"): gridcell_angles(cube)
def test_fail_different_shapes(self): # Check error with mismatched shapes. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) co_y = co_y[1:] with self.assertRaisesRegex(ValueError, "must have same shape"): gridcell_angles(co_x, co_y)
def test_fail_noncoord_coord(self): # Check that passing an array + a coord gives an error. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) with self.assertRaisesRegex(ValueError, "is a Coordinate, but .* is not"): gridcell_angles(co_x.points, co_y)
def test_fail_different_coord_system(self): # Check error with mismatched coord systems. cube = sample_2d_latlons(regional=True, rotated=True) cube.coord(axis='x').coord_system = None with self.assertRaisesRegexp(ValueError, 'must have same coordinate system'): gridcell_angles(cube)
def test_fail_cube_dims(self): # Check error with mismatched cube dims. cube = self.standard_regional_cube # Make 5x6 into 5x5. cube = cube[:, :-1] co_x = cube.coord(axis='x') pts, bds = co_x.points, co_x.bounds co_new_x = co_x.copy(points=pts.transpose((1, 0)), bounds=bds.transpose((1, 0, 2))) cube.remove_coord(co_x) cube.add_aux_coord(co_new_x, (1, 0)) with self.assertRaisesRegexp(ValueError, 'must have the same cube dimensions'): gridcell_angles(cube)
def test_fail_cube_dims(self): # Check error with mismatched cube dims. cube = self.standard_regional_cube # Make 5x6 into 5x5. cube = cube[:, :-1] co_x = cube.coord(axis="x") pts, bds = co_x.points, co_x.bounds co_new_x = co_x.copy(points=pts.transpose((1, 0)), bounds=bds.transpose((1, 0, 2))) cube.remove_coord(co_x) cube.add_aux_coord(co_new_x, (1, 0)) with self.assertRaisesRegex(ValueError, "must have the same cube dimensions"): gridcell_angles(cube)
def test_bounded_coord_args(self): # Check that passing the coords gives the same result as the cube. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) result = gridcell_angles(co_x, co_y) self.assertArrayAllClose(result.data, self.standard_small_cube_results)
def _check_multiple_orientations_and_latitudes( self, method="mid-lhs, mid-rhs", atol_degrees=0.005, cellsize_degrees=1.0, ): cube = _2d_multicells_testcube(cellsize_degrees=cellsize_degrees) # Calculate gridcell angles at each point. angles_cube = gridcell_angles(cube, cell_angle_boundpoints=method) # Check that the results are a close match to the original intended # gridcell orientation angles. # NOTE: neither the above gridcell construction nor the calculation # itself are exact : Errors scale as the square of gridcell sizes. angles_cube.convert_units("degrees") angles_calculated = angles_cube.data # Note: the gridcell angles **should** just match the longitudes at # each point angles_expected = cube.coord("longitude").points # Wrap both into standard range for comparison. angles_calculated = (angles_calculated + 360.0) % 360.0 angles_expected = (angles_expected + 360.0) % 360.0 # Assert (toleranced) equality, and return results. self.assertArrayAllClose(angles_calculated, angles_expected, atol=atol_degrees) return angles_calculated, angles_expected
def _check_multiple_orientations_and_latitudes(self, method='mid-lhs, mid-rhs', atol_degrees=0.005, cellsize_degrees=1.0): cube = _2d_multicells_testcube(cellsize_degrees=cellsize_degrees) # Calculate gridcell angles at each point. angles_cube = gridcell_angles(cube, cell_angle_boundpoints=method) # Check that the results are a close match to the original intended # gridcell orientation angles. # NOTE: neither the above gridcell construction nor the calculation # itself are exact : Errors scale as the square of gridcell sizes. angles_cube.convert_units('degrees') angles_calculated = angles_cube.data # Note: the gridcell angles **should** just match the longitudes at # each point angles_expected = cube.coord('longitude').points # Wrap both into standard range for comparison. angles_calculated = (angles_calculated + 360.) % 360. angles_expected = (angles_expected + 360.) % 360. # Assert (toleranced) equality, and return results. self.assertArrayAllClose(angles_calculated, angles_expected, atol=atol_degrees) return angles_calculated, angles_expected
def test_points_array_args(self): # Check we can calculate from points arrays alone (no coords). co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) # As previous, the leftmost and rightmost columns are not good. result = gridcell_angles(co_x.points, co_y.points) self.assertArrayAllClose(result.data[:, 1:-1], self.standard_small_cube_results[:, 1:-1])
def test_coords_radians_args(self): # Check it still works with coords converted to radians. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) for coord in (co_x, co_y): coord.convert_units("radians") result = gridcell_angles(co_x, co_y) self.assertArrayAllClose(result.data, self.standard_small_cube_results)
def test_points_array_args(self): # Check we can calculate from points arrays alone (no coords). co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) # As previous, the leftmost and rightmost columns are not good. result = gridcell_angles(co_x.points, co_y.points) self.assertArrayAllClose(result.data[:, 1:-1], self.standard_small_cube_results[:, 1:-1])
def test_bounds_array_args(self): # Check we can calculate from bounds values alone. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) # Results drawn from coord bounds should be nearly the same, # but not exactly, because of the different 'midpoint' values. result = gridcell_angles(co_x.bounds, co_y.bounds) self.assertArrayAllClose(result.data, self.standard_small_cube_results, atol=0.1)
def test_coords_radians_args(self): # Check it still works with coords converted to radians. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) for coord in (co_x, co_y): coord.convert_units('radians') result = gridcell_angles(co_x, co_y) self.assertArrayAllClose(result.data, self.standard_small_cube_results)
def test_bounds_array_args(self): # Check we can calculate from bounds values alone. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) # Results drawn from coord bounds should be nearly the same, # but not exactly, because of the different 'midpoint' values. result = gridcell_angles(co_x.bounds, co_y.bounds) self.assertArrayAllClose(result.data, self.standard_small_cube_results, atol=0.1)
def setUp(self): # Make a small "normal" contiguous-bounded cube to test on. # This one is regional. self.standard_regional_cube = sample_2d_latlons(regional=True, transformed=True) # Record the standard correct angle answers. result_cube = gridcell_angles(self.standard_regional_cube) result_cube.convert_units("degrees") self.standard_result_cube = result_cube self.standard_small_cube_results = result_cube.data
def setUp(self): # Make a small "normal" contiguous-bounded cube to test on. # This one is regional. self.standard_regional_cube = sample_2d_latlons( regional=True, transformed=True) # Record the standard correct angle answers. result_cube = gridcell_angles(self.standard_regional_cube) result_cube.convert_units('degrees') self.standard_result_cube = result_cube self.standard_small_cube_results = result_cube.data
def test_unbounded_regional_coord_args(self): # Remove the coord bounds to check points-based calculation. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ('x', 'y')) for coord in (co_x, co_y): coord.bounds = None result = gridcell_angles(co_x, co_y) # Note: in this case, we can expect the leftmost and rightmost columns # to be rubbish, because the data is not global. # But the rest should match okay. self.assertArrayAllClose(result.data[:, 1:-1], self.standard_small_cube_results[:, 1:-1])
def test_unbounded_global(self): # For a contiguous global grid, a result based on points, i.e. with the # bounds removed, should be a reasonable match for the 'ideal' one # based on the bounds. # Make a global cube + calculate ideal bounds-based results. global_cube = sample_2d_latlons(transformed=True) result_cube = gridcell_angles(global_cube) result_cube.convert_units("degrees") global_cube_results = result_cube.data # Check a points-based calculation on the same basic grid. co_x, co_y = (global_cube.coord(axis=ax) for ax in ("x", "y")) for coord in (co_x, co_y): coord.bounds = None result = gridcell_angles(co_x, co_y) # In this case, the match is actually rather poor (!). self.assertArrayAllClose(result.data, global_cube_results, atol=7.5) # Leaving off first + last columns again gives a decent result. self.assertArrayAllClose(result.data[:, 1:-1], global_cube_results[:, 1:-1])
def test_unbounded_regional_coord_args(self): # Remove the coord bounds to check points-based calculation. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) for coord in (co_x, co_y): coord.bounds = None result = gridcell_angles(co_x, co_y) # Note: in this case, we can expect the leftmost and rightmost columns # to be rubbish, because the data is not global. # But the rest should match okay. self.assertArrayAllClose(result.data[:, 1:-1], self.standard_small_cube_results[:, 1:-1])
def test_nonlatlon_coord_system(self): # Check with points specified in an unexpected coord system. cube = sample_2d_latlons(regional=True, rotated=True) result = gridcell_angles(cube) self.assertArrayAllClose(result.data, self.standard_small_cube_results) # Check that the result has transformed (true-latlon) coordinates. self.assertEqual(len(result.coords()), 2) x_coord = result.coord(axis="x") y_coord = result.coord(axis="y") self.assertEqual(x_coord.shape, cube.shape) self.assertEqual(y_coord.shape, cube.shape) self.assertIsNotNone(cube.coord_system) self.assertIsNone(x_coord.coord_system) self.assertIsNone(y_coord.coord_system)
def test_nonlatlon_coord_system(self): # Check with points specified in an unexpected coord system. cube = sample_2d_latlons(regional=True, rotated=True) result = gridcell_angles(cube) self.assertArrayAllClose(result.data, self.standard_small_cube_results) # Check that the result has transformed (true-latlon) coordinates. self.assertEqual(len(result.coords()), 2) x_coord = result.coord(axis='x') y_coord = result.coord(axis='y') self.assertEqual(x_coord.shape, cube.shape) self.assertEqual(y_coord.shape, cube.shape) self.assertIsNotNone(cube.coord_system) self.assertIsNone(x_coord.coord_system) self.assertIsNone(y_coord.coord_system)
def test_unbounded_global(self): # For a contiguous global grid, a result based on points, i.e. with the # bounds removed, should be a reasonable match for the 'ideal' one # based on the bounds. # Make a global cube + calculate ideal bounds-based results. global_cube = sample_2d_latlons(transformed=True) result_cube = gridcell_angles(global_cube) result_cube.convert_units('degrees') global_cube_results = result_cube.data # Check a points-based calculation on the same basic grid. co_x, co_y = (global_cube.coord(axis=ax) for ax in ('x', 'y')) for coord in (co_x, co_y): coord.bounds = None result = gridcell_angles(co_x, co_y) # In this case, the match is actually rather poor (!). self.assertArrayAllClose(result.data, global_cube_results, atol=7.5) # Leaving off first + last columns again gives a decent result. self.assertArrayAllClose(result.data[:, 1:-1], global_cube_results[:, 1:-1])
def test_fail_non2d_coords(self): # Check error with bad args. cube = lat_lon_cube() with self.assertRaisesRegexp(ValueError, 'inputs must have 2-dimensional shape'): gridcell_angles(cube)
def test_bounded_coord_args(self): # Check that passing the coords gives the same result as the cube. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) result = gridcell_angles(co_x, co_y) self.assertArrayAllClose(result.data, self.standard_small_cube_results)
def test_fail_nonarraylike(self): # Check error with bad args. co_x, co_y = 1, 2 with self.assertRaisesRegexp(ValueError, 'must have array shape property'): gridcell_angles(co_x, co_y)
def test_fail_nonarraylike(self): # Check error with bad args. co_x, co_y = 1, 2 with self.assertRaisesRegex(ValueError, "must have array shape property"): gridcell_angles(co_x, co_y)
def test_fail_non2d_coords(self): # Check error with bad args. cube = lat_lon_cube() with self.assertRaisesRegex(ValueError, "inputs must have 2-dimensional shape"): gridcell_angles(cube)