def test_set_extrapolated_bounds(self): value_grid = [[[40.0, 40.0, 40.0, 40.0], [39.0, 39.0, 39.0, 39.0], [38.0, 38.0, 38.0, 38.0]], [[-100.0, -99.0, -98.0, -97.0], [-100.0, -99.0, -98.0, -97.0], [-100.0, -99.0, -98.0, -97.0]]] actual_corners = [[[[40.5, 40.5, 39.5, 39.5], [40.5, 40.5, 39.5, 39.5], [40.5, 40.5, 39.5, 39.5], [40.5, 40.5, 39.5, 39.5]], [[39.5, 39.5, 38.5, 38.5], [39.5, 39.5, 38.5, 38.5], [39.5, 39.5, 38.5, 38.5], [39.5, 39.5, 38.5, 38.5]], [[38.5, 38.5, 37.5, 37.5], [38.5, 38.5, 37.5, 37.5], [38.5, 38.5, 37.5, 37.5], [38.5, 38.5, 37.5, 37.5]]], [[[-100.5, -99.5, -99.5, -100.5], [-99.5, -98.5, -98.5, -99.5], [-98.5, -97.5, -97.5, -98.5], [-97.5, -96.5, -96.5, -97.5]], [[-100.5, -99.5, -99.5, -100.5], [-99.5, -98.5, -98.5, -99.5], [-98.5, -97.5, -97.5, -98.5], [-97.5, -96.5, -96.5, -97.5]], [[-100.5, -99.5, -99.5, -100.5], [-99.5, -98.5, -98.5, -99.5], [-98.5, -97.5, -97.5, -98.5], [-97.5, -96.5, -96.5, -97.5]]]] for should_extrapolate in [False, True]: y = Variable(name='y', value=value_grid[0], dimensions=['ydim', 'xdim']) x = Variable(name='x', value=value_grid[1], dimensions=['ydim', 'xdim']) if should_extrapolate: y.set_extrapolated_bounds('ybounds', 'bounds') x.set_extrapolated_bounds('xbounds', 'bounds') grid = Grid(x, y) try: grid.set_extrapolated_bounds('ybounds', 'xbounds', 'bounds') except BoundsAlreadyAvailableError: self.assertTrue(should_extrapolate) else: np.testing.assert_equal(grid.y.bounds.get_value(), actual_corners[0]) np.testing.assert_equal(grid.x.bounds.get_value(), actual_corners[1]) # Test vectorized. y = Variable(name='y', value=[1., 2., 3.], dimensions='yy') x = Variable(name='x', value=[10., 20., 30.], dimensions='xx') grid = Grid(x, y) grid.set_extrapolated_bounds('ybounds', 'xbounds', 'bounds') self.assertEqual(grid.x.bounds.ndim, 2) self.assertTrue(grid.is_vectorized)
def test_system(self): from ocgis.regrid.base import create_esmf_grid, iter_esmf_fields, RegridOperation, destroy_esmf_objects import ESMF yc = Variable(name='yc', value=np.arange(-90 + (45 / 2.), 90, 45), dimensions='ydim', dtype=float) xc = Variable(name='xc', value=np.arange(15, 360, 30), dimensions='xdim', dtype=float) ogrid = Grid(y=yc, x=xc, crs=Spherical()) ogrid.set_extrapolated_bounds('xc_bounds', 'yc_bounds', 'bounds') np.random.seed(1) mask = np.random.rand(*ogrid.shape) mask = mask > 0.5 self.assertTrue(mask.sum() > 3) ogrid.set_mask(mask) egrid = create_esmf_grid(ogrid) actual_shape = egrid.size[0].tolist() desired_shape = np.flipud(ogrid.shape).tolist() self.assertEqual(actual_shape, desired_shape) desired = ogrid.get_value_stacked() desired = np.ma.array(desired, mask=False) desired.mask[0, :, :] = ogrid.get_mask() desired.mask[1, :, :] = ogrid.get_mask() desired = desired.sum() actual_col = egrid.get_coords(0) actual_row = egrid.get_coords(1) actual_mask = np.invert(egrid.mask[0].astype(bool)) actual = np.ma.array(actual_row, mask=actual_mask).sum() + np.ma.array(actual_col, mask=actual_mask).sum() self.assertEqual(actual, desired) desired = 9900.0 corners = egrid.coords[ESMF.StaggerLoc.CORNER] actual = corners[0].sum() + corners[1].sum() self.assertEqual(actual, desired) ofield = create_exact_field(ogrid, 'data', ntime=3, crs=Spherical()) variable_name, efield, tidx = list(iter_esmf_fields(ofield, split=False))[0] desired_value = ofield['data'].get_value() self.assertAlmostEqual(efield.data.sum(), desired_value.sum(), places=3) destroy_esmf_objects([egrid, efield]) ofield.grid.set_mask(ofield.grid.get_mask(), cascade=True) desired_value = ofield['data'].get_masked_value() keywords = dict(split=[False, True]) for k in self.iter_product_keywords(keywords): opts = {'split': k.split} dofield = ofield.deepcopy() dofield['data'].get_value().fill(0) ro = RegridOperation(ofield, dofield, regrid_options=opts) actual_field = ro.execute() actual_value = actual_field['data'].get_masked_value() self.assertAlmostEqual(0.0, np.abs(desired_value - actual_value).max())
def test_set_extrapolated_bounds_empty(self): """Test bounds extrapolation works on empty objects.""" dimx = Dimension('x', 2, is_empty=True, dist=True) x = Variable('x', dimensions=dimx) y = Variable('3', dimensions=Dimension('y', 3)) grid = Grid(x, y) self.assertTrue(dimx.is_empty) self.assertTrue(x.is_empty) self.assertTrue(grid.is_empty) self.assertFalse(grid.has_bounds) self.assertEqual(grid.abstraction, 'point') grid.set_extrapolated_bounds('xbnds', 'ybnds', 'bounds') self.assertEqual(grid.abstraction, 'polygon') self.assertTrue(grid.has_bounds) self.assertTrue(grid.is_empty)
def test_get_field_write_target(self): # Test coordinate system names are added to attributes of dimensioned variables. x = Variable('x', dimensions='x', value=[1]) y = Variable('y', dimensions='y', value=[2]) t = Variable('t', dimensions='t', value=[3]) crs = WGS84() d = Variable('data', dimensions=['t', 'y', 'x'], value=[[[1]]]) grid = Grid(x, y) field = Field(grid=grid, time=t, crs=crs) field.add_variable(d, is_data=True) target = DriverNetcdfCF._get_field_write_target_(field) self.assertEqual(target[d.name].attrs['grid_mapping'], crs.name) self.assertEqual(field.x.units, 'degrees_east') # Test bounds units are removed when writing. x = Variable(name='x', value=[1, 2, 3], dtype=float, dimensions='xdim', units='hours') y = Variable(name='y', value=[1, 2, 3], dtype=float, dimensions='ydim', units='hours') grid = Grid(x, y) grid.set_extrapolated_bounds('x_bounds', 'y_bounds', 'bounds') self.assertEqual(x.bounds.units, x.units) self.assertEqual(y.bounds.units, y.units) field = Field(grid=grid) actual = DriverNetcdfCF._get_field_write_target_(field) self.assertEqual(x.bounds.units, x.units) self.assertNumpyMayShareMemory(actual[x.name].get_value(), field[x.name].get_value()) self.assertIsNone(actual[x.name].bounds.units) self.assertIsNone(actual[y.name].bounds.units) self.assertEqual(x.bounds.units, x.units) self.assertEqual(y.bounds.units, y.units) # Test actual coordinate system is triggered. field = Field() src = CFSpherical() dst = WGS84() field.set_crs(src) self.assertEqual(field.crs, src) self.assertIsNone(env.COORDSYS_ACTUAL) env.COORDSYS_ACTUAL = dst actual = DriverNetcdfCF._get_field_write_target_(field) self.assertEqual(actual.crs, dst) self.assertEqual(field.crs, src) self.assertNotIn(src.name, actual) self.assertIn(dst.name, actual)
def test_init(self): # Test a field is always the parent of a grid. grid = self.get_gridxy() self.assertIsInstance(grid.parent, Field) crs = WGS84() grid = self.get_gridxy(crs=crs) self.assertIsInstance(grid, Grid) self.assertIn('x', grid.parent) self.assertIn('y', grid.parent) self.assertEqual(grid.crs, crs) self.assertEqual([dim.name for dim in grid.dimensions], ['ydim', 'xdim']) self.assertEqual(grid.shape, (4, 3)) self.assertTrue(grid.is_vectorized) self.assertEqual(grid.x.ndim, 1) self.assertEqual(grid.y.ndim, 1) # Test with different variable names. x = Variable(name='col', value=[1], dimensions='col') y = Variable(name='row', value=[2], dimensions='row') grid = Grid(x, y) assert_equal(grid.x.get_value(), [1]) assert_equal(grid.y.get_value(), [2]) # Test point and polygon representations. grid = self.get_gridxy(crs=WGS84()) grid.set_extrapolated_bounds('x_bounds', 'y_bounds', 'bounds') targets = ['get_point', 'get_polygon'] targets = [getattr(grid, t)() for t in targets] for t in targets: self.assertIsInstance(t, GeometryVariable) self.assertTrue(grid.is_vectorized) sub = grid[1, 1] targets = ['get_point', 'get_polygon'] targets = [getattr(sub, t)() for t in targets] for t in targets: self.assertEqual(t.shape, (1, 1)) self.assertIsInstance(t, GeometryVariable) self.assertTrue(grid.is_vectorized)
def test_get_field_write_target(self): # Test coordinate system names are added to attributes of dimensioned variables. x = Variable('x', dimensions='x', value=[1]) y = Variable('y', dimensions='y', value=[2]) t = Variable('t', dimensions='t', value=[3]) crs = WGS84() d = Variable('data', dimensions=['t', 'y', 'x'], value=[[[1]]]) grid = Grid(x, y) field = Field(grid=grid, time=t, crs=crs) field.add_variable(d, is_data=True) target = DriverNetcdfCF._get_field_write_target_(field) self.assertEqual(target[d.name].attrs['grid_mapping'], crs.name) self.assertEqual(field.x.units, 'degrees_east') # Test bounds units are removed when writing. x = Variable(name='x', value=[1, 2, 3], dtype=float, dimensions='x', units='hours') y = Variable(name='y', value=[1, 2, 3], dtype=float, dimensions='x', units='hours') grid = Grid(x, y) grid.set_extrapolated_bounds('x_bounds', 'y_bounds', 'bounds') self.assertEqual(x.bounds.units, x.units) self.assertEqual(y.bounds.units, y.units) field = Field(grid=grid) actual = DriverNetcdfCF._get_field_write_target_(field) self.assertEqual(x.bounds.units, x.units) self.assertNumpyMayShareMemory(actual[x.name].get_value(), field[x.name].get_value()) self.assertIsNone(actual[x.name].bounds.units) self.assertIsNone(actual[y.name].bounds.units) self.assertEqual(x.bounds.units, x.units) self.assertEqual(y.bounds.units, y.units)
def test_system_line_subsetting(self): """Test subsetting with a line.""" line = LineString([(-0.4, 0.2), (1.35, 0.3), (1.38, -0.716)]) geom = [{'geom': line, 'crs': None}] x = Variable('x', [-1, -0.5, 0.5, 1.5, 2], 'x') y = Variable('y', [-0.5, 0.5, 1.5], 'y') grid = Grid(x, y) grid.set_extrapolated_bounds('x_bounds', 'y_bounds', 'bounds') field = Field(grid=grid) ops = OcgOperations(dataset=field, geom=geom) ret = ops.execute() field = ret.get_element() desired = [[[-0.5, -0.5, -0.5], [0.5, 0.5, 0.5]], [[-0.5, 0.5, 1.5], [-0.5, 0.5, 1.5]]] actual = field.grid.get_value_stacked().tolist() self.assertEqual(actual, desired) desired = [[True, True, False], [False, False, False]] actual = field.grid.get_mask().tolist() self.assertEqual(actual, desired)
def test_system(self): from ocgis.regrid.base import get_esmf_grid, iter_esmf_fields, RegridOperation, destroy_esmf_objects import ESMF yc = Variable(name='yc', value=np.arange(-90 + (45 / 2.), 90, 45), dimensions='ydim', dtype=float) xc = Variable(name='xc', value=np.arange(15, 360, 30), dimensions='xdim', dtype=float) ogrid = Grid(y=yc, x=xc, crs=Spherical()) ogrid.set_extrapolated_bounds('xc_bounds', 'yc_bounds', 'bounds') np.random.seed(1) mask = np.random.rand(*ogrid.shape) mask = mask > 0.5 self.assertTrue(mask.sum() > 3) ogrid.set_mask(mask) egrid = get_esmf_grid(ogrid) actual_shape = egrid.size[0].tolist() desired_shape = np.flipud(ogrid.shape).tolist() self.assertEqual(actual_shape, desired_shape) desired = ogrid.get_value_stacked() desired = np.ma.array(desired, mask=False) desired.mask[0, :, :] = ogrid.get_mask() desired.mask[1, :, :] = ogrid.get_mask() desired = desired.sum() actual_col = egrid.get_coords(0) actual_row = egrid.get_coords(1) actual_mask = np.invert(egrid.mask[0].astype(bool)) actual = np.ma.array(actual_row, mask=actual_mask).sum() + np.ma.array( actual_col, mask=actual_mask).sum() self.assertEqual(actual, desired) desired = 9900.0 corners = egrid.coords[ESMF.StaggerLoc.CORNER] actual = corners[0].sum() + corners[1].sum() self.assertEqual(actual, desired) ofield = create_exact_field(ogrid, 'data', ntime=3, crs=Spherical()) variable_name, efield, tidx = list( iter_esmf_fields(ofield, split=False))[0] desired_value = ofield['data'].get_value() self.assertAlmostEqual(efield.data.sum(), desired_value.sum(), places=3) destroy_esmf_objects([egrid, efield]) ofield.grid.set_mask(ofield.grid.get_mask(), cascade=True) desired_value = ofield['data'].get_masked_value() keywords = dict(split=[False, True]) for k in self.iter_product_keywords(keywords): opts = {'split': k.split} dofield = ofield.deepcopy() dofield['data'].get_value().fill(0) ro = RegridOperation(ofield, dofield, regrid_options=opts) actual_field = ro.execute() actual_value = actual_field['data'].get_masked_value() self.assertAlmostEqual(0.0, np.abs(desired_value - actual_value).max())
def get_ugrid_data_structure(): x = Variable(name='node_x', value=[10, 20, 30], dtype=float, dimensions='x') y = Variable(name='node_y', value=[-60, -55, -50, -45, -40], dimensions='y') grid = Grid(x, y) grid.set_extrapolated_bounds('x_bounds', 'y_bounds', 'bounds') grid.expand() cindex = np.zeros((grid.archetype.size, 4), dtype=int) xc = grid.x.bounds.get_value().flatten() yc = grid.y.bounds.get_value().flatten() for eidx, (ridx, cidx) in enumerate(itertools.product(*[range(ii) for ii in grid.shape])): curr_element = grid[ridx, cidx] curr_xc = curr_element.x.bounds.get_value().flatten() curr_yc = curr_element.y.bounds.get_value().flatten() for element_node_idx in range(curr_xc.shape[0]): found_idx = find_index([xc, yc], [curr_xc[element_node_idx], curr_yc[element_node_idx]]) cindex[eidx, element_node_idx] = found_idx new_cindex, uindices = reduce_reindex_coordinate_index(cindex.flatten(), start_index=0) new_cindex = new_cindex.reshape(*cindex.shape) xc = xc[uindices] yc = yc[uindices] centers = grid.get_value_stacked() center_xc = centers[1].flatten() center_yc = centers[0].flatten() longitude_attrs = {'standard_name': 'longitude', 'units': 'degrees_east'} latitude_attrs = {'standard_name': 'latitude', 'units': 'degrees_north'} vc = VariableCollection(attrs={'conventions': 'CF-1.6, UGRID-1.0'}) face_center_x = Variable(name='face_center_x', value=center_xc, dimensions='n_face', parent=vc, attrs=longitude_attrs, dtype=float) face_center_y = Variable(name='face_center_y', value=center_yc, dimensions='n_face', parent=vc, attrs=latitude_attrs, dtype=float) face_node_index = Variable(name='face_node_index', value=new_cindex, dimensions=['n_face', 'max_nodes'], parent=vc, attrs={'standard_name': 'face_node_connectivity', 'order': 'counterclockwise'}) face_node_x = Variable(name='face_node_x', value=xc, dimensions='n_node', parent=vc, attrs=longitude_attrs, dtype=float) face_node_y = Variable(name='face_node_y', value=yc, dimensions='n_node', parent=vc, attrs=latitude_attrs, dtype=float) mesh = Variable(name='mesh', attrs={'standard_name': 'mesh_topology', 'cf_role': 'mesh_topology', 'dimension': 2, 'locations': 'face node', 'node_coordinates': 'face_node_x face_node_y', 'face_coordinates': 'face_center_x face_center_y', 'face_node_connectivity': 'face_node_index'}, parent=vc) # path = self.get_temporary_file_path('foo.nc') # vc.write(path) # self.ncdump(path) # # ============================================================================================================== # import matplotlib.pyplot as plt # from descartes import PolygonPatch # from shapely.geometry import Polygon, MultiPolygon # # BLUE = '#6699cc' # GRAY = '#999999' # # fig = plt.figure(num=1) # ax = fig.add_subplot(111) # # polys = [] # # for face_idx in range(face_node_index.shape[0]): # sub = face_node_index[face_idx, :].parent # curr_cindex = sub[face_node_index.name].get_value().flatten() # fcx = sub[face_node_x.name].get_value()[curr_cindex] # fcy = sub[face_node_y.name].get_value()[curr_cindex] # # coords = np.zeros((4, 2)) # coords[:, 0] = fcx # coords[:, 1] = fcy # # poly = Polygon(coords) # polys.append(poly) # patch = PolygonPatch(poly, fc=BLUE, ec=GRAY, alpha=0.5, zorder=2) # ax.add_patch(patch) # # minx, miny, maxx, maxy = MultiPolygon(polys).bounds # w, h = maxx - minx, maxy - miny # ax.set_xlim(minx - 0.2 * w, maxx + 0.2 * w) # ax.set_ylim(miny - 0.2 * h, maxy + 0.2 * h) # ax.set_aspect(1) # # plt.scatter(center_xc, center_yc, zorder=1) # # plt.show() # =============================================================================================================== return vc