def test(self): metadata = deepcopy(self.metadata) angleOfRotation = mock.sentinel.angleOfRotation shapeOfTheEarth = mock.sentinel.shapeOfTheEarth section = {'latitudeOfSouthernPole': 45000000, 'longitudeOfSouthernPole': 90000000, 'angleOfRotation': angleOfRotation, 'shapeOfTheEarth': shapeOfTheEarth} # The called being tested. grid_definition_template_5(section, metadata) from iris_grib._load_convert import \ ellipsoid_geometry, \ ellipsoid, \ grid_definition_template_4_and_5 as gdt_4_5 self.assertEqual(ellipsoid_geometry.call_count, 1) ellipsoid.assert_called_once_with(shapeOfTheEarth, self.major, self.minor, self.radius) from iris.coord_systems import RotatedGeogCS RotatedGeogCS.assert_called_once_with(-45.0, 270.0, angleOfRotation, self.ellipsoid) gdt_4_5.assert_called_once_with(section, metadata, 'grid_latitude', 'grid_longitude', self.cs) expected = deepcopy(self.metadata) expected['dim_coords_and_dims'].append((self.coord, self.dim)) self.assertEqual(metadata, expected)
def test(self): metadata = deepcopy(self.metadata) angleOfRotation = mock.sentinel.angleOfRotation shapeOfTheEarth = mock.sentinel.shapeOfTheEarth section = {'latitudeOfSouthernPole': 45000000, 'longitudeOfSouthernPole': 90000000, 'angleOfRotation': angleOfRotation, 'shapeOfTheEarth': shapeOfTheEarth} # The called being tested. grid_definition_template_5(section, metadata) from iris.fileformats.grib._load_convert import \ ellipsoid_geometry, \ ellipsoid, \ grid_definition_template_4_and_5 as gdt_4_5 self.assertEqual(ellipsoid_geometry.call_count, 1) ellipsoid.assert_called_once_with(shapeOfTheEarth, self.major, self.minor, self.radius) from iris.coord_systems import RotatedGeogCS RotatedGeogCS.assert_called_once_with(-45.0, 270.0, angleOfRotation, self.ellipsoid) gdt_4_5.assert_called_once_with(section, metadata, 'grid_latitude', 'grid_longitude', self.cs) expected = deepcopy(self.metadata) expected['dim_coords_and_dims'].append((self.coord, self.dim)) self.assertEqual(metadata, expected)
class Test_init(tests.IrisTest): def setUp(self): self.pole_lon = 171.77 self.pole_lat = 49.55 self.rotation_about_new_pole = 180.0 self.rp_crs = RotatedGeogCS(self.pole_lat, self.pole_lon, self.rotation_about_new_pole) def test_crs_creation(self): self.assertEqual(self.pole_lon, self.rp_crs.grid_north_pole_longitude) self.assertEqual(self.pole_lat, self.rp_crs.grid_north_pole_latitude) self.assertEqual(self.rotation_about_new_pole, self.rp_crs.north_pole_grid_longitude) def test_as_cartopy_crs(self): if cartopy.__version__ < "0.12": with mock.patch("warnings.warn") as warn: accrs = self.rp_crs.as_cartopy_crs() self.assertEqual(warn.call_count, 1) else: accrs = self.rp_crs.as_cartopy_crs() expected = ccrs.RotatedGeodetic(self.pole_lon, self.pole_lat, self.rotation_about_new_pole) self.assertEqual( sorted(accrs.proj4_init.split(" +")), sorted(expected.proj4_init.split(" +")), ) def test_as_cartopy_projection(self): if cartopy.__version__ < "0.12": with mock.patch("warnings.warn") as warn: _ = self.rp_crs.as_cartopy_projection() self.assertEqual(warn.call_count, 1) else: accrsp = self.rp_crs.as_cartopy_projection() expected = ccrs.RotatedPole(self.pole_lon, self.pole_lat, self.rotation_about_new_pole) self.assertEqual( sorted(accrsp.proj4_init.split(" +")), sorted(expected.proj4_init.split(" +")), ) def _check_crs_default(self, crs): # Check for property defaults when no kwargs options are set. # NOTE: except ellipsoid, which is done elsewhere. self.assertEqualAndKind(crs.north_pole_grid_longitude, 0.0) def test_optional_args_missing(self): # Check that unused 'north_pole_grid_longitude' defaults to 0.0. crs = RotatedGeogCS(self.pole_lon, self.pole_lat) self._check_crs_default(crs) def test_optional_args_None(self): # Check that 'north_pole_grid_longitude=None' defaults to 0.0. crs = RotatedGeogCS(self.pole_lon, self.pole_lat, north_pole_grid_longitude=None) self._check_crs_default(crs)
def test_init(self): rcs = RotatedGeogCS(30, 40, north_pole_grid_longitude=50, ellipsoid=GeogCS(6371229)) self.assertXMLElement(rcs, ("coord_systems", "RotatedGeogCS_init.xml")) rcs = RotatedGeogCS(30, 40, north_pole_grid_longitude=50) self.assertXMLElement(rcs, ("coord_systems", "RotatedGeogCS_init_a.xml")) rcs = RotatedGeogCS(30, 40) self.assertXMLElement(rcs, ("coord_systems", "RotatedGeogCS_init_b.xml"))
def setup(self, type): lon_bounds = (-180, 180) lat_bounds = (-90, 90) n_lons_src = 20 n_lats_src = 40 n_lons_tgt = 20 n_lats_tgt = 40 h = 100 if type == "large source": n_lons_src = 100 n_lats_src = 200 if type == "large target": n_lons_tgt = 100 n_lats_tgt = 200 if type == "mixed": coord_system_src = RotatedGeogCS(0, 90, 90) else: coord_system_src = None grid = _grid_cube( n_lons_src, n_lats_src, lon_bounds, lat_bounds, coord_system=coord_system_src, ) tgt = _grid_cube(n_lons_tgt, n_lats_tgt, lon_bounds, lat_bounds) src_data = np.arange(n_lats_src * n_lons_src * h).reshape( [n_lats_src, n_lons_src, h]) src = Cube(src_data) src.add_dim_coord(grid.coord("latitude"), 0) src.add_dim_coord(grid.coord("longitude"), 1) self.regridder = ESMFAreaWeightedRegridder(src, tgt) self.src = src
def realistic_3d(): """ Returns a realistic 3d cube. >>> print(repr(realistic_3d())) <iris 'Cube' of air_potential_temperature (time: 7; grid_latitude: 9; grid_longitude: 11)> """ data = np.arange(7*9*11).reshape((7,9,11)) lat_pts = np.linspace(-4, 4, 9) lon_pts = np.linspace(-5, 5, 11) time_pts = np.linspace(394200, 394236, 7) forecast_period_pts = np.linspace(0, 36, 7) ll_cs = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) lat = icoords.DimCoord(lat_pts, standard_name='grid_latitude', units='degrees', coord_system=ll_cs) lon = icoords.DimCoord(lon_pts, standard_name='grid_longitude', units='degrees', coord_system=ll_cs) time = icoords.DimCoord(time_pts, standard_name='time', units='hours since 1970-01-01 00:00:00') forecast_period = icoords.DimCoord(forecast_period_pts, standard_name='forecast_period', units='hours') height = icoords.DimCoord(1000.0, standard_name='air_pressure', units='Pa') cube = iris.cube.Cube(data, standard_name='air_potential_temperature', units='K', dim_coords_and_dims=[(time, 0), (lat, 1), (lon, 2)], aux_coords_and_dims=[(forecast_period, 0), (height, None)], attributes={'source': 'Iris test case'}) return cube
def test_str(self): rcs = RotatedGeogCS(30, 40, north_pole_grid_longitude=50, ellipsoid=GeogCS(6371229)) expected = "RotatedGeogCS(30.0, 40.0, "\ "north_pole_grid_longitude=50.0, ellipsoid=GeogCS(6371229.0))" self.assertEqual(expected, str(rcs)) rcs = RotatedGeogCS(30, 40, north_pole_grid_longitude=50) expected = "RotatedGeogCS(30.0, 40.0, north_pole_grid_longitude=50.0)" self.assertEqual(expected, str(rcs)) rcs = RotatedGeogCS(30, 40) expected = "RotatedGeogCS(30.0, 40.0)" self.assertEqual(expected, str(rcs))
def _default_coord_system(self): # Define an alternate, rotated coordinate system to test." self.default_ellipsoid = GeogCS(PP_DEFAULT_EARTH_RADIUS) cs = RotatedGeogCS(grid_north_pole_latitude=90.0, grid_north_pole_longitude=0.0, ellipsoid=self.default_ellipsoid) return cs
def test__shape_of_earth_spherical(self): cs = RotatedGeogCS(grid_north_pole_latitude=90.0, grid_north_pole_longitude=0.0, ellipsoid=GeogCS(52431.0)) test_cube = self._make_test_cube(cs=cs) grid_definition_template_5(test_cube, self.mock_grib) self._check_key('shapeOfTheEarth', 1) self._check_key('scaleFactorOfRadiusOfSphericalEarth', 0) self._check_key('scaledValueOfRadiusOfSphericalEarth', 52431.0)
def test__rotated_pole(self): cs = RotatedGeogCS(grid_north_pole_latitude=75.3, grid_north_pole_longitude=54.321, ellipsoid=self.default_ellipsoid) test_cube = self._make_test_cube(cs=cs) grid_definition_template_5(test_cube, self.mock_grib) self._check_key("latitudeOfSouthernPole", -75300000) self._check_key("longitudeOfSouthernPole", 234321000) self._check_key("angleOfRotation", 0)
def test_grid_definition_template_5(self): # Irregular (variable resolution) rotated lat/lon grid. x_points = np.array([0, 2, 7]) y_points = np.array([1, 3, 6]) coord_units = '1' cs = RotatedGeogCS(34.0, 117.0, ellipsoid=self.ellipsoid) test_cube = self._make_test_cube(cs, x_points, y_points, coord_units) grid_definition_section(test_cube, self.mock_grib) self._check_key('gridDefinitionTemplateNumber', 5)
def test_grid_definition_template_1(self): # Rotated lat/lon (Plate Carree). x_points = np.arange(3) y_points = np.arange(3) coord_units = 'degrees' cs = RotatedGeogCS(34.0, 117.0, ellipsoid=self.ellipsoid) test_cube = self._make_test_cube(cs, x_points, y_points, coord_units) grid_definition_section(test_cube, self.mock_grib) self._check_key('gridDefinitionTemplateNumber', 1)
def test_alternative_cs(self): # Check the result is just the same in a different coordinate system. cs = RotatedGeogCS(grid_north_pole_latitude=75.3, grid_north_pole_longitude=102.5, ellipsoid=GeogCS(100.0)) for cube in (self.src_cube, self.grid_cube): for coord_name in ('longitude', 'latitude'): cube.coord(coord_name).coord_system = cs self._check_expected()
def test__fail_rotated_pole_nonstandard_meridian(self): cs = RotatedGeogCS(grid_north_pole_latitude=90.0, grid_north_pole_longitude=0.0, north_pole_grid_longitude=22.5, ellipsoid=self.default_ellipsoid) test_cube = self._make_test_cube(cs=cs) with self.assertRaisesRegexp( TranslationError, 'not yet support .* rotated prime meridian.'): grid_definition_template_5(test_cube, self.mock_grib)
def test_rotated_geog_cs(self): coord_system = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) expected = {'grid_mapping_name': b'rotated_latitude_longitude', 'north_pole_grid_longitude': 0.0, 'grid_north_pole_longitude': 177.5, 'grid_north_pole_latitude': 37.5, 'longitude_of_prime_meridian': 0.0, 'earth_radius': 6371229.0, } self._test(coord_system, expected)
def test_rotated_geog_cs(self): coord_system = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) expected = { "grid_mapping_name": b"rotated_latitude_longitude", "north_pole_grid_longitude": 0.0, "grid_north_pole_longitude": 177.5, "grid_north_pole_latitude": 37.5, "longitude_of_prime_meridian": 0.0, "earth_radius": 6371229.0, } self._test(coord_system, expected)
class Test_init(tests.IrisTest): def setUp(self): self.pole_lon = 171.77 self.pole_lat = 49.55 self.rotation_about_new_pole = 180.0 self.rp_crs = RotatedGeogCS(self.pole_lat, self.pole_lon, self.rotation_about_new_pole) def test_crs_creation(self): self.assertEqual(self.pole_lon, self.rp_crs.grid_north_pole_longitude) self.assertEqual(self.pole_lat, self.rp_crs.grid_north_pole_latitude) self.assertEqual(self.rotation_about_new_pole, self.rp_crs.north_pole_grid_longitude) def test_as_cartopy_crs(self): if cartopy.__version__ < "0.12": with mock.patch("warnings.warn") as warn: accrs = self.rp_crs.as_cartopy_crs() self.assertEqual(warn.call_count, 1) else: accrs = self.rp_crs.as_cartopy_crs() expected = ccrs.RotatedGeodetic(self.pole_lon, self.pole_lat, self.rotation_about_new_pole) self.assertEqual( sorted(accrs.proj4_init.split(" +")), sorted(expected.proj4_init.split(" +")), ) def test_as_cartopy_projection(self): if cartopy.__version__ < "0.12": with mock.patch("warnings.warn") as warn: _ = self.rp_crs.as_cartopy_projection() self.assertEqual(warn.call_count, 1) else: accrsp = self.rp_crs.as_cartopy_projection() expected = ccrs.RotatedPole(self.pole_lon, self.pole_lat, self.rotation_about_new_pole) self.assertEqual( sorted(accrsp.proj4_init.split(" +")), sorted(expected.proj4_init.split(" +")), )
def test_rotated_regridding(): """ Test for :func:`esmf_regrid.schemes.regrid_rectilinear_to_rectilinear`. Test the regriding of a rotated pole coordinate system. The test is designed to that it should be possible to verify the result by inspection. """ src_coord_system = RotatedGeogCS(0, 90, 90) tgt_coord_system = None n_lons = 4 n_lats = 4 lon_bounds = (-180, 180) lat_bounds = (-90, 90) src = _grid_cube( n_lons, n_lats, lon_bounds, lat_bounds, circular=True, coord_system=src_coord_system, ) tgt = _grid_cube( n_lons, n_lats, lon_bounds, lat_bounds, circular=True, coord_system=tgt_coord_system, ) src_data = np.arange(n_lons * n_lats).reshape([n_lats, n_lons]) # src_mask = np.empty([n_lats, n_lons]) # src_mask[:] = np.array([1, 0, 0, 1])[:, np.newaxis] src_mask = np.array([[1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1]]) src_data = ma.array(src_data, mask=src_mask) src.data = src_data no_mdtol_result = regrid_rectilinear_to_rectilinear(src, tgt) full_mdtol_result = regrid_rectilinear_to_rectilinear(src, tgt, mdtol=1) expected_data = np.array([[5, 4, 8, 9], [5, 4, 8, 9], [6, 7, 11, 10], [6, 7, 11, 10]]) expected_mask = np.array([[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [0, 0, 0, 0]]) no_mdtol_expected_data = ma.array(expected_data, mask=expected_mask) # Lenient check for data. assert np.allclose(no_mdtol_expected_data, no_mdtol_result.data) assert np.allclose(expected_data, full_mdtol_result.data)
def test__shape_of_earth_flattened(self): ellipsoid = GeogCS(semi_major_axis=1456.0, semi_minor_axis=1123.0) cs = RotatedGeogCS(grid_north_pole_latitude=90.0, grid_north_pole_longitude=0.0, ellipsoid=ellipsoid) test_cube = self._make_test_cube(cs=cs) grid_definition_template_5(test_cube, self.mock_grib) self._check_key('shapeOfTheEarth', 7) self._check_key('scaleFactorOfEarthMajorAxis', 0) self._check_key('scaledValueOfEarthMajorAxis', 1456.0) self._check_key('scaleFactorOfEarthMinorAxis', 0) self._check_key('scaledValueOfEarthMinorAxis', 1123.0)
class Test_init(tests.IrisTest): def setUp(self): self.pole_lon = 171.77 self.pole_lat = 49.55 self.rotation_about_new_pole = 180.0 self.rp_crs = RotatedGeogCS(self.pole_lat, self.pole_lon, self.rotation_about_new_pole) def test_crs_creation(self): self.assertEqual(self.pole_lon, self.rp_crs.grid_north_pole_longitude) self.assertEqual(self.pole_lat, self.rp_crs.grid_north_pole_latitude) self.assertEqual(self.rotation_about_new_pole, self.rp_crs.north_pole_grid_longitude) def test_as_cartopy_crs(self): if cartopy.__version__ < '0.12': with mock.patch('warnings.warn') as warn: accrs = self.rp_crs.as_cartopy_crs() self.assertEqual(warn.call_count, 1) else: accrs = self.rp_crs.as_cartopy_crs() expected = ccrs.RotatedGeodetic(self.pole_lon, self.pole_lat, self.rotation_about_new_pole) self.assertEqual(sorted(accrs.proj4_init.split(' +')), sorted(expected.proj4_init.split(' +'))) def test_as_cartopy_projection(self): if cartopy.__version__ < '0.12': with mock.patch('warnings.warn') as warn: accrs = self.rp_crs.as_cartopy_projection() self.assertEqual(warn.call_count, 1) else: accrsp = self.rp_crs.as_cartopy_projection() expected = ccrs.RotatedPole(self.pole_lon, self.pole_lat, self.rotation_about_new_pole) self.assertEqual(sorted(accrsp.proj4_init.split(' +')), sorted(expected.proj4_init.split(' +')))
def test_rotated_geog_cs(self): coord_system = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) cube = self.cube_with_cs(coord_system) expected = {'grid_mapping_name': 'rotated_latitude_longitude', 'north_pole_grid_longitude': 0.0, 'grid_north_pole_longitude': 177.5, 'grid_north_pole_latitude': 37.5, 'longitude_of_prime_meridian': 0.0, 'earth_radius': 6371229.0, } grid_variable = self.construct_cf_grid_mapping_variable(cube) actual = self.variable_attributes(grid_variable) # To see obvious differences, check that they keys are the same. self.assertEqual(sorted(actual.keys()), sorted(expected.keys())) # Now check that the values are equivalent. self.assertEqual(actual, expected)
def _generate_extended_cube(): cube_list = iris.cube.CubeList() lower_bound = 0 upper_bound = 70 period = 70 data = np.arange(70 * 9 * 11).reshape((70, 9, 11)) lat_pts = np.linspace(-4, 4, 9) lon_pts = np.linspace(-5, 5, 11) ll_cs = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) for i in range(0, 100): time_pts = np.linspace(lower_bound, upper_bound - 1, 70) lat = icoords.DimCoord( lat_pts, standard_name="grid_latitude", units="degrees", coord_system=ll_cs, ) lon = icoords.DimCoord( lon_pts, standard_name="grid_longitude", units="degrees", coord_system=ll_cs, ) time = icoords.DimCoord( time_pts, standard_name="time", units="days since 1970-01-01 00:00:00" ) cube = iris.cube.Cube( data, standard_name="air_potential_temperature", units="K", dim_coords_and_dims=[(time, 0), (lat, 1), (lon, 2)], attributes={"source": "Iris test case"}, ) lower_bound = lower_bound + 70 upper_bound = upper_bound + 70 period = period + 70 cube_list.append(cube) cube = cube_list.concatenate_cube() return cube
def external(*args, **kwargs): """ Prep and call _grid_cube, saving to a NetCDF file. Saving to a file allows the original python executable to pick back up. Remember that all arguments must work as strings, hence the fresh construction of a ``coord_system`` within the function. """ from iris import save from iris.coord_systems import RotatedGeogCS from esmf_regrid.tests.unit.schemes.test__cube_to_GridInfo import ( _grid_cube as original, ) save_path = kwargs.pop("save_path") if kwargs.pop("alt_coord_system"): kwargs["coord_system"] = RotatedGeogCS(0, 90, 90) cube = original(*args, **kwargs) save(cube, save_path)
def realistic_3d(): data = np.arange(7 * 9 * 11).reshape((7, 9, 11)) lat_pts = np.linspace(-4, 4, 9) lon_pts = np.linspace(-5, 5, 11) time_pts = np.linspace(394200, 394236, 7) forecast_period_pts = np.linspace(0, 36, 7) ll_cs = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) lat = icoords.DimCoord( lat_pts, standard_name="grid_latitude", units="degrees", coord_system=ll_cs, ) lon = icoords.DimCoord( lon_pts, standard_name="grid_longitude", units="degrees", coord_system=ll_cs, ) time = icoords.DimCoord(time_pts, standard_name="time", units="hours since 1970-01-01 00:00:00") forecast_period = icoords.DimCoord(forecast_period_pts, standard_name="forecast_period", units="hours") height = icoords.DimCoord(1000.0, standard_name="air_pressure", units="Pa") cube = iris.cube.Cube( data, standard_name="air_potential_temperature", units="K", dim_coords_and_dims=[(time, 0), (lat, 1), (lon, 2)], aux_coords_and_dims=[(forecast_period, 0), (height, None)], attributes={"source": "Iris test case"}, ) return cube
def test_optional_args_None(self): # Check that 'north_pole_grid_longitude=None' defaults to 0.0. crs = RotatedGeogCS(self.pole_lon, self.pole_lat, north_pole_grid_longitude=None) self._check_crs_default(crs)
def setUp(self): self.pole_lon = 171.77 self.pole_lat = 49.55 self.rotation_about_new_pole = 180.0 self.rp_crs = RotatedGeogCS(self.pole_lat, self.pole_lon, self.rotation_about_new_pole)
def realistic_4d(): """ Returns a realistic 4d cube. >>> print(repr(realistic_4d())) <iris 'Cube' of air_potential_temperature (time: 6; model_level_number: 70; grid_latitude: 100; grid_longitude: 100)> """ data_path = tests.get_data_path(('stock', 'stock_arrays.npz')) if not os.path.isfile(data_path): raise IOError('Test data is not available at {}.'.format(data_path)) r = np.load(data_path) # sort the arrays based on the order they were originally given. # The names given are of the form 'arr_1' or 'arr_10' _, arrays = zip(*sorted(r.items(), key=lambda item: int(item[0][4:]))) lat_pts, lat_bnds, lon_pts, lon_bnds, level_height_pts, \ level_height_bnds, model_level_pts, sigma_pts, sigma_bnds, time_pts, \ _source_pts, forecast_period_pts, data, orography = arrays ll_cs = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) lat = icoords.DimCoord(lat_pts, standard_name='grid_latitude', units='degrees', bounds=lat_bnds, coord_system=ll_cs) lon = icoords.DimCoord(lon_pts, standard_name='grid_longitude', units='degrees', bounds=lon_bnds, coord_system=ll_cs) level_height = icoords.DimCoord(level_height_pts, long_name='level_height', units='m', bounds=level_height_bnds, attributes={'positive': 'up'}) model_level = icoords.DimCoord(model_level_pts, standard_name='model_level_number', units='1', attributes={'positive': 'up'}) sigma = icoords.AuxCoord(sigma_pts, long_name='sigma', units='1', bounds=sigma_bnds) orography = icoords.AuxCoord(orography, standard_name='surface_altitude', units='m') time = icoords.DimCoord(time_pts, standard_name='time', units='hours since 1970-01-01 00:00:00') forecast_period = icoords.DimCoord(forecast_period_pts, standard_name='forecast_period', units='hours') hybrid_height = iris.aux_factory.HybridHeightFactory( level_height, sigma, orography) cube = iris.cube.Cube(data, standard_name='air_potential_temperature', units='K', dim_coords_and_dims=[(time, 0), (model_level, 1), (lat, 2), (lon, 3)], aux_coords_and_dims=[(orography, (2, 3)), (level_height, 1), (sigma, 1), (forecast_period, None)], attributes={'source': 'Iris test case'}, aux_factories=[hybrid_height]) return cube
def sample_2d_latlons(regional=False, rotated=False, transformed=False): """ Construct small 2d cubes with 2d X and Y coordinates. This makes cubes with 'expanded' coordinates (4 bounds per cell), analagous to ORCA data. The coordinates are always geographical, so either it has a coord system or they are "true" lats + lons. ( At present, they are always latitudes and longitudes, but maybe in a rotated system. ) The results always have fully contiguous bounds. Kwargs: * regional (bool): If False (default), results cover the whole globe, and there is implicit connectivity between rhs + lhs of the array. If True, coverage is regional and edges do not connect. * rotated (bool): If False, X and Y coordinates are true-latitudes and longitudes, with an implicit coordinate system (i.e. None). If True, the X and Y coordinates are lats+lons in a selected rotated-latlon coordinate system. * transformed (bool): Build coords from rotated coords as for 'rotated', but then replace their values with the equivalent "true" lats + lons, and no coord-system (defaults to true-latlon). In this case, the X and Y coords are no longer 'meshgrid' style, i.e. the points + bounds values vary in *both* dimensions. .. note:: 'transformed' is an alternative to 'rotated' : when 'transformed' is set, then 'rotated' has no effect. .. Some sample results printouts :: >>> print(sample_2d_latlons()) test_data / (unknown) (-- : 5; -- : 6) Auxiliary coordinates: latitude x x longitude x x >>> >>> print(sample_2d_latlons().coord(axis='x')[0, :2]) AuxCoord(array([ 37.5 , 93.75]), bounds=array([[ 0. , 65.625, 65.625, 0. ], [ 65.625, 121.875, 121.875, 65.625]]), standard_name='longitude', units=Unit('degrees')) >>> print(np.round(sample_2d_latlons().coord(axis='x').points, 3)) [[ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75]] >>> print(np.round(sample_2d_latlons().coord(axis='y').points, 3)) [[-85. -85. -85. -85. -85. -85. ] [-47.5 -47.5 -47.5 -47.5 -47.5 -47.5] [-10. -10. -10. -10. -10. -10. ] [ 27.5 27.5 27.5 27.5 27.5 27.5] [ 65. 65. 65. 65. 65. 65. ]] >>> print(np.round( sample_2d_latlons(rotated=True).coord(axis='x').points, 3)) [[ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75] [ 37.5 93.75 150. 206.25 262.5 318.75]] >>> print(sample_2d_latlons(rotated=True).coord(axis='y').coord_system) RotatedGeogCS(75.0, 120.0) >>> print( sample_2d_latlons(transformed=True).coord(axis='y').coord_system) None >>> print(np.round( sample_2d_latlons(transformed=True).coord(axis='x').points, 3)) [[ -50.718 -40.983 -46.74 -71.938 -79.293 -70.146] [ -29.867 17.606 77.936 157.145 -141.037 -93.172] [ -23.139 31.007 87.699 148.322 -154.639 -100.505] [ -16.054 41.218 92.761 143.837 -164.738 -108.105] [ 10.86 61.78 100.236 137.285 175.511 -135.446]] >>> print(np.round( sample_2d_latlons(transformed=True).coord(axis='y').points, 3)) [[-70.796 -74.52 -79.048 -79.26 -74.839 -70.96 ] [-34.99 -46.352 -59.721 -60.34 -47.305 -35.499] [ 1.976 -10.626 -22.859 -23.349 -11.595 1.37 ] [ 38.914 25.531 14.312 13.893 24.585 38.215] [ 74.197 60.258 51.325 51.016 59.446 73.268]] >>> """ def sample_cube(xargs, yargs): # Make a test cube with given latitude + longitude coordinates. # xargs/yargs are args for np.linspace (start, stop, N), to make the X # and Y coordinate points. x0, x1, nx = xargs y0, y1, ny = yargs # Data has cycling values, staggered a bit in successive rows. data = np.zeros((ny, nx)) data.flat[:] = np.arange(ny * nx) % (nx + 2) # Build a 2d cube with longitude + latitude coordinates. cube = Cube(data, long_name="test_data") x_pts = np.linspace(x0, x1, nx, endpoint=True) y_pts = np.linspace(y0, y1, ny, endpoint=True) co_x = DimCoord(x_pts, standard_name="longitude", units="degrees") co_y = DimCoord(y_pts, standard_name="latitude", units="degrees") cube.add_dim_coord(co_y, 0) cube.add_dim_coord(co_x, 1) return cube # Start by making a "normal" cube with separate 1-D X and Y coords. if regional: # Make a small regional cube. cube = sample_cube(xargs=(150.0, 243.75, 6), yargs=(-10.0, 40.0, 5)) # Add contiguous bounds. for ax in ("x", "y"): cube.coord(axis=ax).guess_bounds() else: # Global data, but at a drastically reduced resolution. cube = sample_cube(xargs=(37.5, 318.75, 6), yargs=(-85.0, 65.0, 5)) # Make contiguous bounds and adjust outer edges to ensure it is global. for name in ("longitude", "latitude"): coord = cube.coord(name) coord.guess_bounds() bds = coord.bounds.copy() # Make bounds global, by fixing lowest and uppermost values. if name == "longitude": bds[0, 0] = 0.0 bds[-1, 1] = 360.0 else: bds[0, 0] = -90.0 bds[-1, 1] = 90.0 coord.bounds = bds # Now convert the 1-d coords to 2-d equivalents. # Get original 1-d coords. co_1d_x, co_1d_y = [cube.coord(axis=ax).copy() for ax in ("x", "y")] # Calculate 2-d equivalents. co_2d_x, co_2d_y = grid_coords_2d_from_1d(co_1d_x, co_1d_y) # Remove the old grid coords. for coord in (co_1d_x, co_1d_y): cube.remove_coord(coord) # Add the new grid coords. for coord in (co_2d_x, co_2d_y): cube.add_aux_coord(coord, (0, 1)) if transformed or rotated: # Put the cube locations into a rotated coord system. pole_lat, pole_lon = 75.0, 120.0 if transformed: # Reproject coordinate values from rotated to true lat-lons. co_x, co_y = [cube.coord(axis=ax) for ax in ("x", "y")] # Unrotate points. lons, lats = co_x.points, co_y.points lons, lats = unrotate_pole(lons, lats, pole_lon, pole_lat) co_x.points, co_y.points = lons, lats # Unrotate bounds. lons, lats = co_x.bounds, co_y.bounds # Note: save the shape, flatten + then re-apply the shape, because # "unrotate_pole" uses "cartopy.crs.CRS.transform_points", which # only works on arrays of 1 or 2 dimensions. shape = lons.shape lons, lats = unrotate_pole(lons.flatten(), lats.flatten(), pole_lon, pole_lat) co_x.bounds, co_y.bounds = lons.reshape(shape), lats.reshape(shape) else: # "Just" rotate operation : add a coord-system to each coord. cs = RotatedGeogCS(pole_lat, pole_lon) for coord in cube.coords(): coord.coord_system = cs return cube
def realistic_4d(): """ Returns a realistic 4d cube. >>> print(repr(realistic_4d())) <iris 'Cube' of air_potential_temperature (time: 6; model_level_number: 70; grid_latitude: 100; grid_longitude: 100)> """ data_path = tests.get_data_path(("stock", "stock_arrays.npz")) if not os.path.isfile(data_path): raise IOError("Test data is not available at {}.".format(data_path)) r = np.load(data_path) # sort the arrays based on the order they were originally given. # The names given are of the form 'arr_1' or 'arr_10' _, arrays = zip(*sorted(r.items(), key=lambda item: int(item[0][4:]))) ( lat_pts, lat_bnds, lon_pts, lon_bnds, level_height_pts, level_height_bnds, model_level_pts, sigma_pts, sigma_bnds, time_pts, _source_pts, forecast_period_pts, data, orography, ) = arrays ll_cs = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) lat = icoords.DimCoord( lat_pts, standard_name="grid_latitude", units="degrees", bounds=lat_bnds, coord_system=ll_cs, ) lon = icoords.DimCoord( lon_pts, standard_name="grid_longitude", units="degrees", bounds=lon_bnds, coord_system=ll_cs, ) level_height = icoords.DimCoord( level_height_pts, long_name="level_height", units="m", bounds=level_height_bnds, attributes={"positive": "up"}, ) model_level = icoords.DimCoord( model_level_pts, standard_name="model_level_number", units="1", attributes={"positive": "up"}, ) sigma = icoords.AuxCoord(sigma_pts, long_name="sigma", units="1", bounds=sigma_bnds) orography = icoords.AuxCoord(orography, standard_name="surface_altitude", units="m") time = icoords.DimCoord(time_pts, standard_name="time", units="hours since 1970-01-01 00:00:00") forecast_period = icoords.DimCoord(forecast_period_pts, standard_name="forecast_period", units="hours") hybrid_height = iris.aux_factory.HybridHeightFactory( level_height, sigma, orography) cube = iris.cube.Cube( data, standard_name="air_potential_temperature", units="K", dim_coords_and_dims=[(time, 0), (model_level, 1), (lat, 2), (lon, 3)], aux_coords_and_dims=[ (orography, (2, 3)), (level_height, 1), (sigma, 1), (forecast_period, None), ], attributes={"source": "Iris test case"}, aux_factories=[hybrid_height], ) return cube
def realistic_4d(): """ Returns a realistic 4d cube. >>> print repr(realistic_4d()) <iris 'Cube' of air_potential_temperature (time: 6; model_level_number: 70; grid_latitude: 100; grid_longitude: 100)> """ # the stock arrays were created in Iris 0.8 with: # >>> fname = iris.sample_data_path('PP', 'COLPEX', 'theta_and_orog_subset.pp') # >>> theta = iris.load_cube(fname, 'air_potential_temperature') # >>> for coord in theta.coords(): # ... print coord.name, coord.has_points(), coord.has_bounds(), coord.units # ... # grid_latitude True True degrees # grid_longitude True True degrees # level_height True True m # model_level True False 1 # sigma True True 1 # time True False hours since 1970-01-01 00:00:00 # source True False no_unit # forecast_period True False hours # >>> arrays = [] # >>> for coord in theta.coords(): # ... if coord.has_points(): arrays.append(coord.points) # ... if coord.has_bounds(): arrays.append(coord.bounds) # >>> arrays.append(theta.data) # >>> arrays.append(theta.coord('sigma').coord_system.orography.data) # >>> np.savez('stock_arrays.npz', *arrays) data_path = os.path.join(os.path.dirname(__file__), 'stock_arrays.npz') r = np.load(data_path) # sort the arrays based on the order they were originally given. The names given are of the form 'arr_1' or 'arr_10' _, arrays = zip(*sorted(r.iteritems(), key=lambda item: int(item[0][4:]))) lat_pts, lat_bnds, lon_pts, lon_bnds, level_height_pts, \ level_height_bnds, model_level_pts, sigma_pts, sigma_bnds, time_pts, \ _source_pts, forecast_period_pts, data, orography = arrays ll_cs = RotatedGeogCS(37.5, 177.5, ellipsoid=GeogCS(6371229.0)) lat = icoords.DimCoord(lat_pts, standard_name='grid_latitude', units='degrees', bounds=lat_bnds, coord_system=ll_cs) lon = icoords.DimCoord(lon_pts, standard_name='grid_longitude', units='degrees', bounds=lon_bnds, coord_system=ll_cs) level_height = icoords.DimCoord(level_height_pts, long_name='level_height', units='m', bounds=level_height_bnds, attributes={'positive': 'up'}) model_level = icoords.DimCoord(model_level_pts, standard_name='model_level_number', units='1', attributes={'positive': 'up'}) sigma = icoords.AuxCoord(sigma_pts, long_name='sigma', units='1', bounds=sigma_bnds) orography = icoords.AuxCoord(orography, standard_name='surface_altitude', units='m') time = icoords.DimCoord(time_pts, standard_name='time', units='hours since 1970-01-01 00:00:00') forecast_period = icoords.DimCoord(forecast_period_pts, standard_name='forecast_period', units='hours') hybrid_height = iris.aux_factory.HybridHeightFactory( level_height, sigma, orography) cube = iris.cube.Cube(data, standard_name='air_potential_temperature', units='K', dim_coords_and_dims=[(time, 0), (model_level, 1), (lat, 2), (lon, 3)], aux_coords_and_dims=[(orography, (2, 3)), (level_height, 1), (sigma, 1), (forecast_period, None)], attributes={'source': 'Iris test case'}, aux_factories=[hybrid_height]) return cube
def test_multidim(self): # Testing with >2D data to demonstrate correct operation over # additional non-XY dimensions (including data masking), which is # handled by the PointInCell wrapper class. # Define a simple target grid first, in plain latlon coordinates. plain_latlon_cs = GeogCS(EARTH_RADIUS) grid_x_coord = DimCoord(points=[15.0, 25.0, 35.0], bounds=[[10.0, 20.0], [20.0, 30.0], [30.0, 40.0]], standard_name='longitude', units='degrees', coord_system=plain_latlon_cs) grid_y_coord = DimCoord(points=[-30.0, -50.0], bounds=[[-20.0, -40.0], [-40.0, -60.0]], standard_name='latitude', units='degrees', coord_system=plain_latlon_cs) grid_cube = Cube(np.zeros((2, 3))) grid_cube.add_dim_coord(grid_y_coord, 0) grid_cube.add_dim_coord(grid_x_coord, 1) # Define some key points in true-lat/lon thta have known positions # First 3x2 points in the centre of each output cell. x_centres, y_centres = np.meshgrid(grid_x_coord.points, grid_y_coord.points) # An extra point also falling in cell 1, 1 x_in11, y_in11 = 26.3, -48.2 # An extra point completely outside the target grid x_out, y_out = 70.0, -40.0 # Define a rotated coord system for the source data pole_lon, pole_lat = -125.3, 53.4 src_cs = RotatedGeogCS(grid_north_pole_latitude=pole_lat, grid_north_pole_longitude=pole_lon, ellipsoid=plain_latlon_cs) # Concatenate all the testpoints in a flat array, and find the rotated # equivalents. xx = list(x_centres.flat[:]) + [x_in11, x_out] yy = list(y_centres.flat[:]) + [y_in11, y_out] xx, yy = rotate_pole(lons=np.array(xx), lats=np.array(yy), pole_lon=pole_lon, pole_lat=pole_lat) # Define handy index numbers for all these. i00, i01, i02, i10, i11, i12, i_in, i_out = range(8) # Build test data in the shape Z,YX = (3, 8) data = [[1, 2, 3, 11, 12, 13, 7, 99], [1, 2, 3, 11, 12, 13, 7, 99], [7, 6, 5, 51, 52, 53, 12, 1]] mask = [[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]] src_data = np.ma.array(data, mask=mask, dtype=float) # Make the source cube. src_cube = Cube(src_data) src_x = AuxCoord(xx, standard_name='grid_longitude', units='degrees', coord_system=src_cs) src_y = AuxCoord(yy, standard_name='grid_latitude', units='degrees', coord_system=src_cs) src_z = DimCoord(np.arange(3), long_name='z') src_cube.add_dim_coord(src_z, 0) src_cube.add_aux_coord(src_x, 1) src_cube.add_aux_coord(src_y, 1) # Add in some extra metadata, to ensure it gets copied over. src_cube.add_aux_coord(DimCoord([0], long_name='extra_scalar_coord')) src_cube.attributes['extra_attr'] = 12.3 # Define what the expected answers should be, shaped (3, 2, 3). expected_result = [ [[1.0, 2.0, 3.0], [11.0, 0.5 * (12 + 7), 13.0]], [[1.0, -999, 3.0], [11.0, 12.0, 13.0]], [[7.0, 6.0, 5.0], [51.0, 0.5 * (52 + 12), 53.0]], ] expected_result = np.ma.masked_less(expected_result, 0) # Perform the calculation with the regridder. regridder = Regridder(src_cube, grid_cube) # Check all is as expected. result = regridder(src_cube) self.assertEqual(result.coord('z'), src_cube.coord('z')) self.assertEqual(result.coord('extra_scalar_coord'), src_cube.coord('extra_scalar_coord')) self.assertEqual(result.coord('longitude'), grid_cube.coord('longitude')) self.assertEqual(result.coord('latitude'), grid_cube.coord('latitude')) self.assertMaskedArrayAlmostEqual(result.data, expected_result)
def test_rotated(self): cs = RotatedGeogCS(30, 40, ellipsoid=GeogCS(6371229)) self.assertXMLElement(cs, ("coord_systems", "CoordSystem_xml_element.xml"))