def test_grid(self): # Test mask variable information is propagated through property. grid = self.get_gridxy(with_xy_bounds=True) self.assertTrue(grid.is_vectorized) self.assertTrue(grid.has_bounds) np.random.seed(1) value = np.random.rand(*grid.shape) select = value > 0.4 mask_var = create_spatial_mask_variable('nonstandard', select, grid.dimensions) grid.set_mask(mask_var) field = Field(grid=grid) self.assertTrue(field.grid.has_bounds) self.assertEqual(field.dimension_map.get_spatial_mask(), mask_var.name) self.assertNumpyAll(field.grid.get_mask(), mask_var.get_mask()) # Test dimension map bounds are updated appropriately. dim = Dimension('count', 2) x = Variable(name='x', value=[1., 2.], dimensions=dim) y = Variable(name='y', value=[1., 2.], dimensions=dim) xb = Variable(name='xb', value=[[0., 1.5], [1.5, 2.5]], dimensions=[dim, 'bounds']) yb = Variable(name='yb', value=[[0., 1.5], [1.5, 2.5]], dimensions=[dim, 'bounds']) variables = [x, y, xb, yb] dmap = DimensionMap() dmap.set_variable(DMK.X, x, bounds=xb) dmap.set_variable(DMK.Y, y, bounds=yb) f = Field(dimension_map=dmap, variables=variables) self.assertTrue(f.grid.has_bounds)
def test_init_dimension_map(self): """Test initializing with a dimension map only.""" dmap = DimensionMap() x = Variable(value=[1, 2, 3], dimensions='elements', name='x') y = Variable(value=[4, 5, 6], dimensions='elements', name='y') topo = dmap.get_topology(Topology.POINT, create=True) topo.set_variable(DMK.X, x) topo.set_variable(DMK.Y, y) f = Field(variables=[x, y], dimension_map=dmap) p = PointGC(parent=f) self.assertNumpyAll(x.get_value(), p.x.get_value()) self.assertNumpyAll(y.get_value(), p.y.get_value())
def test_get_name_mapping(self): dimension_map = {'crs': {'variable': 'latitude_longitude'}, 'level': {'variable': None, 'dimension': []}, 'time': {'variable': u'time', 'attrs': {'axis': 'T'}, 'bounds': u'time_bnds', 'dimension': [u'time']}, 'driver': 'netcdf-cf', 'spatial_mask': {'variable': None}, 'groups': {}, 'realization': {'variable': None, 'dimension': []}, 'y': {'variable': u'lat', 'attrs': {}, 'bounds': u'lat_vertices', 'dimension': [u'rlat']}, 'x': {'variable': u'lon', 'attrs': {}, 'bounds': u'lon_vertices', 'dimension': [u'rlon']}} dimension_map = DimensionMap.from_dict(dimension_map) actual = get_name_mapping(dimension_map) desired = {'y': [u'rlat'], 'x': [u'rlon'], 'time': [u'time']} self.assertEqual(actual, desired)
def create_dimension_map(self, group_metadata, **kwargs): ret = DimensionMap() ret.set_driver(self) topo = ret.get_topology(Topology.POINT, create=True) topo.set_variable(DMK.X, 'grid_center_lon', dimension='grid_size') topo.set_variable(DMK.Y, 'grid_center_lat', dimension='grid_size') if 'grid_corner_lon' in group_metadata['variables']: topo = ret.get_topology(Topology.POLYGON, create=True) topo.set_variable(DMK.X, 'grid_corner_lon', dimension='grid_size') topo.set_variable(DMK.Y, 'grid_corner_lat', dimension='grid_size') if 'grid_imask' in group_metadata['variables']: # Use the intrinsic SCRIP default attributes associated with the variable. ret.set_spatial_mask('grid_imask', default_attrs={}) # The isomorphic property covers all possible mesh topologies. ret.set_property(DMK.IS_ISOMORPHIC, True) return ret
def __iter__(self): non_iterables = [AbstractRequestObject, dict, Field] if env.USE_ESMF: import ESMF non_iterables.append(ESMF.Field) if isinstance(self._value, tuple(non_iterables)): to_itr = [self._value] else: to_itr = self._value for uid, element in enumerate(to_itr, start=1): if isinstance(element, dict): element = RequestDataset(**element) if env.USE_ESMF and isinstance(element, ESMF.Field): from ocgis.regrid.base import get_ocgis_field_from_esmf_field dimension_map = { DimensionMapKey.X: { DimensionMapKey.VARIABLE: 'x', DimensionMapKey.DIMENSION: ['x'] }, DimensionMapKey.Y: { DimensionMapKey.VARIABLE: 'y', DimensionMapKey.DIMENSION: ['y'] } } dimension_map = DimensionMap.from_dict(dimension_map) element = get_ocgis_field_from_esmf_field( element, dimensions=self.esmf_field_dimensions, dimension_map=dimension_map) try: element = element.copy() except AttributeError: element = copy(element) if element.uid is None: element.uid = uid # TODO: Remove me once the driver does not accept request datasets at initialization. # Try to change the driver UID. try: element.driver.rd.uid = uid except AttributeError: # The field driver does not keep a copy of the request dataset. if hasattr(element.driver, 'rd'): raise yield element
def get_ocgis_grid_from_esmf_grid(egrid, crs=None, dimension_map=None): """ Create an OCGIS :class:`~ocgis.interface.base.dimension.spatial.SpatialDimension` object from an ESMF :class:`~ESMF.driver.grid.Grid`. :type egrid: :class:`ESMF.driver.grid.Grid` :param crs: The coordinate system to attach to the output spatial dimension. :type crs: :class:`ocgis.interface.base.crs.CoordinateReferenceSystem` :param dimension_map: Dimension map for the outgoing OCGIS field/grid. :type dimension_map: :class:`ocgis.DimensionMap` :rtype: :class:`~ocgis.Grid` """ if dimension_map is None: dimension_map = { DimensionMapKey.X: { 'variable': 'x', 'bounds': 'x_bounds', DimensionMapKey.DIMENSION: ['x'] }, DimensionMapKey.Y: { 'variable': 'y', 'bounds': 'y_bounds', DimensionMapKey.DIMENSION: ['y'] } } dimension_map = DimensionMap.from_dict(dimension_map) else: assert isinstance(dimension_map, DimensionMap) # OCGIS grid values are built on centers. coords = egrid.coords[ESMF.StaggerLoc.CENTER] shape_coords_list = list(coords[0].shape) dtype_coords = coords[0].dtype # construct the ocgis grid array and fill grid_value = np.zeros([2] + shape_coords_list, dtype=dtype_coords) grid_value[0, ...] = coords[1] grid_value[1, ...] = coords[0] # Build OCGIS corners array if corners are present on the ESMF grid object. has_corners = get_esmf_grid_has_corners(egrid) if has_corners: corner = egrid.coords[ESMF.StaggerLoc.CORNER] grid_corners = np.zeros([2] + shape_coords_list + [4], dtype=dtype_coords) slices = [(0, 0), (0, 1), (1, 1), (1, 0)] for ii, jj in iter_array(coords[0], use_mask=False): row_slice = slice(ii, ii + 2) col_slice = slice(jj, jj + 2) row_corners = corner[1][row_slice, col_slice] col_corners = corner[0][row_slice, col_slice] for kk, slc in enumerate(slices): grid_corners[:, ii, jj, kk] = row_corners[slc], col_corners[slc] else: grid_corners = None # Does the grid have a mask? has_mask = False if egrid.mask is not None: if egrid.mask[ESMF.StaggerLoc.CENTER] is not None: has_mask = True if has_mask: # if there is a mask, update the grid values egrid_mask = egrid.mask[ESMF.StaggerLoc.CENTER] egrid_mask = np.invert(egrid_mask.astype(bool)) # actually construct the masked arrays grid_value = np.ma.array(grid_value) if grid_corners is not None: grid_corners = np.ma.array(grid_corners) grid_dimensions = [ dimension_map.get_dimension(DimensionMapKey.Y)[0], dimension_map.get_dimension(DimensionMapKey.X)[0] ] if grid_corners is not None: grid_bounds_dimensions = deepcopy(grid_dimensions) grid_bounds_dimensions.append(constants.DEFAULT_NAME_CORNERS_DIMENSION) name = dimension_map.get_bounds(DimensionMapKey.X) x_bounds = Variable( name=name, value=grid_corners[1, ...], dimensions=['y', 'x', constants.DEFAULT_NAME_CORNERS_DIMENSION]) name = dimension_map.get_bounds(DimensionMapKey.Y) y_bounds = Variable( name=name, value=grid_corners[0, ...], dimensions=['y', 'x', constants.DEFAULT_NAME_CORNERS_DIMENSION]) else: x_bounds, y_bounds = [None] * 2 name = dimension_map.get_variable(DimensionMapKey.X) x = Variable(name=name, dimensions=grid_dimensions, value=grid_value[1, ...], bounds=x_bounds) name = dimension_map.get_variable(DimensionMapKey.Y) y = Variable(name=name, dimensions=grid_dimensions, value=grid_value[0, ...], bounds=y_bounds) ogrid = Grid(x, y, crs=crs) if has_mask: ogrid.set_mask(egrid_mask) return ogrid
def create_dimension_map(self, group_metadata, strict=False): from ocgis import DimensionMap return DimensionMap()
def __init__(self, **kwargs): kwargs = kwargs.copy() dimension_map = kwargs.pop('dimension_map', None) # Flag updated by driver to indicate if the coordinate system is assigned or implied. self._has_assigned_coordinate_system = False # Flag to indicate if this is a regrid destination. self.regrid_destination = kwargs.pop('regrid_destination', False) # Flag to indicate if this is a regrid source. self.regrid_source = kwargs.pop('regrid_source', True) # Other incoming data objects may have a coordinate system which should be used. crs = kwargs.pop(KeywordArgument.CRS, 'auto') # Add grid variable metadata to dimension map. grid = kwargs.pop(KeywordArgument.GRID, 'auto') # Configure the driver. driver = kwargs.pop(KeywordArgument.DRIVER, 'auto') # Extract standard coordinate variables from the field keyword arguments. k = (DimensionMapKey.GEOM, DimensionMapKey.REALIZATION, DimensionMapKey.TIME, DimensionMapKey.LEVEL) s = OrderedDict() for ii in k: s[ii] = kwargs.pop(ii, None) grid_abstraction = kwargs.pop(KeywordArgument.GRID_ABSTRACTION, 'auto') if grid_abstraction is None: raise ValueError("'{}' may not be None.".format(KeywordArgument.GRID_ABSTRACTION)) grid_is_isomorphic = kwargs.pop('grid_is_isomorphic', 'auto') if grid_is_isomorphic is None: raise ValueError("'{}' may not be None.".format('grid_is_isomorphic')) # TODO: This should maybe be part of the dimension map? Time variables are not dependent on fields. self.format_time = kwargs.pop(KeywordArgument.FORMAT_TIME, True) # Use tags to set data variables. is_data = kwargs.pop(KeywordArgument.IS_DATA, []) VariableCollection.__init__(self, **kwargs) dimension_map = deepcopy(dimension_map) if dimension_map is None: dimension_map = DimensionMap() elif isinstance(dimension_map, dict): dimension_map = DimensionMap.from_dict(dimension_map) self.dimension_map = dimension_map self.set_grid(grid, crs=crs) if driver != 'auto': self.dimension_map.set_driver(driver) if grid_abstraction != 'auto': self.dimension_map.set_grid_abstraction(grid_abstraction) if grid_is_isomorphic != 'auto': self.dimension_map.set_property(DMK.IS_ISOMORPHIC, grid_is_isomorphic) # Append the data variable tagged variable names. is_data = list(get_iter(is_data, dtype=Variable)) is_data_variable_names = get_variable_names(is_data) for idvn in is_data_variable_names: self.append_to_tags(TagName.DATA_VARIABLES, idvn, create=True) for idx, dvn in enumerate(is_data_variable_names): if dvn not in self: if isinstance(is_data[idx], Variable): self.add_variable(is_data[idx]) # Configure the field updating the dimension map in the process. cvar = s[DimensionMapKey.REALIZATION] if cvar is not None: self.set_realization(cvar) cvar = s[DimensionMapKey.TIME] if cvar is not None: self.set_time(cvar) cvar = s[DimensionMapKey.LEVEL] if cvar is not None: self.set_level(cvar) cvar = s[DimensionMapKey.GEOM] if cvar is not None: self.set_geom(cvar, crs=crs) if crs != 'auto': self.set_crs(crs)