Example #1
0
    def test_expand_grid(self):
        x = [101, 102, 103]
        y = [40, 41, 42, 43]
        vx = Variable('x', value=x, dtype=float, dimensions='xdim')
        vx.set_extrapolated_bounds('x_bnds', 'bounds')
        vy = Variable('y', value=y, dtype=float, dimensions='ydim')
        vy.set_extrapolated_bounds('y_bnds', 'bounds')

        grid = Grid(vx, vy)

        for variable in [vx, vy]:
            self.assertEqual(grid.parent[variable.name].ndim, 1)
        expand_grid(grid)

        for variable in [vx, vy]:
            self.assertEqual(grid.parent[variable.name].ndim, 2)
Example #2
0
def get_esmf_grid(ogrid, regrid_method='auto', value_mask=None):
    """
    Create an ESMF :class:`~ESMF.driver.grid.Grid` object from an OCGIS :class:`ocgis.Grid` object.

    :param ogrid: The target OCGIS grid to convert to an ESMF grid.
    :type ogrid: :class:`~ocgis.Grid`
    :param regrid_method: If ``'auto'`` or :attr:`ESMF.api.constants.RegridMethod.CONSERVE`, use corners/bounds from the
     grid object. If :attr:`ESMF.api.constants.RegridMethod.CONSERVE`, the corners/bounds must be present on the grid.
    :param value_mask: If an ``bool`` :class:`numpy.array` with same shape as ``ogrid``, use a logical *or* operation
     with the OCGIS field mask when creating the input grid's mask. Values of ``True`` in ``value_mask`` are assumed to
     be masked. If ``None`` is provided (the default) then the mask will be set using the spatial mask on ``ogrid``.
    :type value_mask: :class:`numpy.array`
    :rtype: :class:`ESMF.driver.grid.Grid`
    """

    pkwds = get_periodicity_parameters(ogrid)

    egrid = ESMF.Grid(max_index=np.array(ogrid.shape),
                      staggerloc=ESMF.StaggerLoc.CENTER,
                      coord_sys=ESMF.CoordSys.SPH_DEG,
                      num_peri_dims=pkwds['num_peri_dims'],
                      pole_dim=pkwds['pole_dim'],
                      periodic_dim=pkwds['periodic_dim'])

    ovalue_stacked = ogrid.get_value_stacked()
    row = egrid.get_coords(1, staggerloc=ESMF.StaggerLoc.CENTER)
    row[:] = ovalue_stacked[0, ...]
    col = egrid.get_coords(0, staggerloc=ESMF.StaggerLoc.CENTER)
    col[:] = ovalue_stacked[1, ...]

    # Use a logical or operation to merge with value_mask if present
    if value_mask is not None:
        # convert to boolean to make sure
        value_mask = value_mask.astype(bool)
        # do the logical or operation selecting values
        value_mask = np.logical_or(value_mask, ogrid.get_mask(create=True))
    else:
        value_mask = ogrid.get_mask()
    # Follows SCRIP convention where 1 is unmasked and 0 is masked.
    if value_mask is not None:
        esmf_mask = np.invert(value_mask).astype(np.int32)
        egrid.add_item(ESMF.GridItem.MASK,
                       staggerloc=ESMF.StaggerLoc.CENTER,
                       from_file=False)
        egrid.mask[0][:] = esmf_mask

    # Attempt to access corners if requested.
    if regrid_method == 'auto' and ogrid.has_bounds:
        regrid_method = RegridMethod.CONSERVE

    if regrid_method == RegridMethod.CONSERVE:
        # Conversion to ESMF objects requires an expanded grid (non-vectorized).
        # TODO: Create ESMF grids from vectorized OCGIS grids.
        expand_grid(ogrid)
        # Convert to ESMF corners from OCGIS corners.
        corners_esmf = np.zeros(
            [2] + [element + 1 for element in ogrid.x.bounds.shape[0:2]],
            dtype=ogrid.archetype.bounds.dtype)
        get_esmf_corners_from_ocgis_corners(ogrid.y.bounds.get_value(),
                                            fill=corners_esmf[0, :, :])
        get_esmf_corners_from_ocgis_corners(ogrid.x.bounds.get_value(),
                                            fill=corners_esmf[1, :, :])

        # adding corners. first tell the grid object to allocate corners
        egrid.add_coords(staggerloc=[ESMF.StaggerLoc.CORNER])
        # get the coordinate pointers and set the coordinates
        grid_corner = egrid.coords[ESMF.StaggerLoc.CORNER]
        # Note indexing is reversed for ESMF v. OCGIS. In ESMF, the x-coordinate (longitude) is the first
        # coordinate. If this is periodic, the last column corner wraps/connect to the first. This coordinate must
        # be removed.
        if pkwds['num_peri_dims'] is not None:
            grid_corner[0][:] = corners_esmf[1][:, 0:-1]
            grid_corner[1][:] = corners_esmf[0][:, 0:-1]
        else:
            grid_corner[0][:] = corners_esmf[1]
            grid_corner[1][:] = corners_esmf[0]

    return egrid
Example #3
0
    def test_get_intersects_ordering(self):
        """Test grid ordering/origins do not influence grid subsetting."""
        keywords = {
            KeywordArgument.OPTIMIZED_BBOX_SUBSET: [False, True],
            'should_wrap': [False, True],
            'reverse_x': [False, True],
            'reverse_y': [False, True],
            'should_expand': [False, True],
        }

        x_value = np.array(
            [155., 160., 165., 170., 175., 180., 185., 190., 195., 200., 205.])
        y_value = np.array([-20., -15., -10., -5., 0., 5., 10., 15., 20.])
        bbox = [168., -12., 191., 5.3]

        for k in self.iter_product_keywords(keywords, as_namedtuple=False):
            reverse_x = k.pop('reverse_x')
            reverse_y = k.pop('reverse_y')
            should_expand = k.pop('should_expand')
            should_wrap = k.pop('should_wrap')

            ompi = OcgDist()
            ompi.create_dimension('dx', len(x_value), dist=True)
            ompi.create_dimension('dy', len(y_value))
            ompi.update_dimension_bounds()

            if reverse_x:
                new_x_value = x_value.copy()
                new_x_value = np.flipud(new_x_value)
            else:
                new_x_value = x_value

            if reverse_y:
                new_y_value = y_value.copy()
                new_y_value = np.flipud(new_y_value)
            else:
                new_y_value = y_value

            if MPI_RANK == 0:
                x = Variable('x', new_x_value, 'dx')
                y = Variable('y', new_y_value, 'dy')
            else:
                x, y = [None, None]

            x = variable_scatter(x, ompi)
            y = variable_scatter(y, ompi)
            grid = Grid(x, y, crs=Spherical())

            with vm.scoped_by_emptyable('scattered', grid):
                if not vm.is_null:
                    if should_expand:
                        expand_grid(grid)

                    if should_wrap:
                        grid = deepcopy(grid)
                        grid.wrap()
                        actual_bbox = MultiPolygon([
                            box(-180, -12, -169, 5.3),
                            box(168, -12, 180, 5.3)
                        ])
                    else:
                        actual_bbox = box(*bbox)

                    live_ranks = vm.get_live_ranks_from_object(grid)
                    with vm.scoped('grid.get_intersects', live_ranks):
                        if not vm.is_null:
                            sub = grid.get_intersects(actual_bbox, **k)
                            with vm.scoped_by_emptyable('sub grid', sub):
                                if not vm.is_null:
                                    if should_wrap:
                                        current_x_value = sub.x.get_value()
                                        current_x_value[
                                            sub.x.get_value() < 0] += 360

                                    self.assertEqual(
                                        sub.extent_global,
                                        (170.0, -10.0, 190.0, 5.0))

                                    if should_expand:
                                        desired = False
                                    else:
                                        desired = True
                                    self.assertEqual(grid.is_vectorized,
                                                     desired)
                                    self.assertEqual(sub.is_vectorized,
                                                     desired)

                                    self.assertFalse(grid.has_allocated_point)
                                    self.assertFalse(
                                        grid.has_allocated_polygon)
Example #4
0
def create_esmf_grid(ogrid, regrid_method='auto', value_mask=None):
    """
    Create an ESMF :class:`~ESMF.driver.grid.Grid` object from an OCGIS :class:`ocgis.Grid` object.

    :param ogrid: The target OCGIS grid to convert to an ESMF grid.
    :type ogrid: :class:`~ocgis.Grid`
    :param regrid_method: If ``'auto'`` or :attr:`ESMF.api.constants.RegridMethod.CONSERVE`, use corners/bounds from the
     grid object. If :attr:`ESMF.api.constants.RegridMethod.CONSERVE`, the corners/bounds must be present on the grid.
    :param value_mask: If an ``bool`` :class:`numpy.array` with same shape as ``ogrid``, use a logical *or* operation
     with the OCGIS field mask when creating the input grid's mask. Values of ``True`` in ``value_mask`` are assumed to
     be masked. If ``None`` is provided (the default) then the mask will be set using the spatial mask on ``ogrid``.
    :type value_mask: :class:`numpy.array`
    :rtype: :class:`ESMF.driver.grid.Grid`
    """

    assert isinstance(ogrid, Grid)
    assert create_crs(ogrid.crs) == Spherical()

    pkwds = get_periodicity_parameters(ogrid)

    # Fill ESMPy grid coordinate values. ###############################################################################

    dimensions = ogrid.parent.dimensions
    get_dimension = ogrid.dimension_map.get_dimension
    y_dimension = get_dimension(DMK.Y, dimensions=dimensions)
    x_dimension = get_dimension(DMK.X, dimensions=dimensions)

    # ESMPy has index 0 = x-coordinate and index 1 = y-coordinate.
    if vm.size == 1:
        max_index = np.array([x_dimension.size, y_dimension.size],
                             dtype=np.int32)
    else:
        max_index = np.array(
            [x_dimension.size_global, y_dimension.size_global], dtype=np.int32)
    pkwds['coord_sys'] = ESMF.CoordSys.SPH_DEG
    pkwds['staggerloc'] = ESMF.StaggerLoc.CENTER
    pkwds['max_index'] = max_index
    egrid = ESMF.Grid(**pkwds)

    # msg = (egrid.lower_bounds, egrid.upper_bounds)
    # ocgis_lh(msg, level=logging.WARN, logger='ocli.chunked_rwg', force=True)

    egrid._ocgis['dimnames'] = (x_dimension.name, y_dimension.name)
    egrid._ocgis['dimnames_backref'] = get_dimension_names(ogrid.dimensions)
    egrid._ocgis['dimension_map'] = deepcopy(ogrid.dimension_map)

    ogrid_dimnames = (y_dimension.name, x_dimension.name)
    is_yx_order = get_dimension_names(ogrid.dimensions) == ogrid_dimnames

    ovalue_stacked = ogrid.get_value_stacked()
    row = egrid.get_coords(1, staggerloc=ESMF.StaggerLoc.CENTER)
    orow = ovalue_stacked[0, ...]
    if is_yx_order:
        orow = np.swapaxes(orow, 0, 1)
    row[:] = orow

    col = egrid.get_coords(0, staggerloc=ESMF.StaggerLoc.CENTER)
    ocol = ovalue_stacked[1, ...]
    if is_yx_order:
        ocol = np.swapaxes(ocol, 0, 1)
    col[:] = ocol

    ####################################################################################################################

    # Use a logical or operation to merge with value_mask if present
    if value_mask is not None:
        # convert to boolean to make sure
        value_mask = value_mask.astype(bool)
        # do the logical or operation selecting values
        value_mask = np.logical_or(value_mask, ogrid.get_mask(create=True))
    else:
        value_mask = ogrid.get_mask()
    # Follows SCRIP convention where 1 is unmasked and 0 is masked.
    if value_mask is not None:
        esmf_mask = np.invert(value_mask).astype(np.int32)
        esmf_mask = np.swapaxes(esmf_mask, 0, 1)
        egrid.add_item(ESMF.GridItem.MASK,
                       staggerloc=ESMF.StaggerLoc.CENTER,
                       from_file=False)
        egrid.mask[0][:] = esmf_mask

    # Attempt to access corners if requested.
    if regrid_method == 'auto' and ogrid.has_bounds:
        regrid_method = ESMF.RegridMethod.CONSERVE

    if regrid_method == ESMF.RegridMethod.CONSERVE:
        # Conversion to ESMF objects requires an expanded grid (non-vectorized).
        # TODO: Create ESMF grids from vectorized OCGIS grids.
        expand_grid(ogrid)
        # Convert to ESMF corners from OCGIS corners.
        corners_esmf = np.zeros([2] + [element + 1 for element in max_index],
                                dtype=col.dtype)
        get_esmf_corners_from_ocgis_corners(ogrid.y.bounds.get_value(),
                                            fill=corners_esmf[0, :, :])
        get_esmf_corners_from_ocgis_corners(ogrid.x.bounds.get_value(),
                                            fill=corners_esmf[1, :, :])

        # adding corners. first tell the grid object to allocate corners
        egrid.add_coords(staggerloc=[ESMF.StaggerLoc.CORNER])
        # get the coordinate pointers and set the coordinates
        grid_corner = egrid.coords[ESMF.StaggerLoc.CORNER]
        # Note indexing is reversed for ESMF v. OCGIS. In ESMF, the x-coordinate (longitude) is the first
        # coordinate. If this is periodic, the last column corner wraps/connect to the first. This coordinate must
        # be removed.
        if pkwds['num_peri_dims'] is not None:
            grid_corner[0][:] = corners_esmf[1][0:-1, :]
            grid_corner[1][:] = corners_esmf[0][0:-1, :]
        else:
            grid_corner[0][:] = corners_esmf[1]
            grid_corner[1][:] = corners_esmf[0]

    return egrid
Example #5
0
File: base.py Project: NCPP/ocgis
def create_esmf_grid(ogrid, regrid_method='auto', value_mask=None):
    """
    Create an ESMF :class:`~ESMF.driver.grid.Grid` object from an OCGIS :class:`ocgis.Grid` object.

    :param ogrid: The target OCGIS grid to convert to an ESMF grid.
    :type ogrid: :class:`~ocgis.Grid`
    :param regrid_method: If ``'auto'`` or :attr:`ESMF.api.constants.RegridMethod.CONSERVE`, use corners/bounds from the
     grid object. If :attr:`ESMF.api.constants.RegridMethod.CONSERVE`, the corners/bounds must be present on the grid.
    :param value_mask: If an ``bool`` :class:`numpy.array` with same shape as ``ogrid``, use a logical *or* operation
     with the OCGIS field mask when creating the input grid's mask. Values of ``True`` in ``value_mask`` are assumed to
     be masked. If ``None`` is provided (the default) then the mask will be set using the spatial mask on ``ogrid``.
    :type value_mask: :class:`numpy.array`
    :rtype: :class:`ESMF.driver.grid.Grid`
    """

    assert isinstance(ogrid, Grid)
    assert create_crs(ogrid.crs) == Spherical()

    pkwds = get_periodicity_parameters(ogrid)

    # Fill ESMPy grid coordinate values. ###############################################################################

    dimensions = ogrid.parent.dimensions
    get_dimension = ogrid.dimension_map.get_dimension
    y_dimension = get_dimension(DMK.Y, dimensions=dimensions)
    x_dimension = get_dimension(DMK.X, dimensions=dimensions)

    # ESMPy has index 0 = x-coordinate and index 1 = y-coordinate.
    if vm.size == 1:
        max_index = np.array([x_dimension.size, y_dimension.size], dtype=np.int32)
    else:
        max_index = np.array([x_dimension.size_global, y_dimension.size_global], dtype=np.int32)
    pkwds['coord_sys'] = ESMF.CoordSys.SPH_DEG
    pkwds['staggerloc'] = ESMF.StaggerLoc.CENTER
    pkwds['max_index'] = max_index
    egrid = ESMF.Grid(**pkwds)

    # msg = (egrid.lower_bounds, egrid.upper_bounds)
    # ocgis_lh(msg, level=logging.WARN, logger='ocli.chunked_rwg', force=True)

    egrid._ocgis['dimnames'] = (x_dimension.name, y_dimension.name)
    egrid._ocgis['dimnames_backref'] = get_dimension_names(ogrid.dimensions)
    egrid._ocgis['dimension_map'] = deepcopy(ogrid.dimension_map)

    ogrid_dimnames = (y_dimension.name, x_dimension.name)
    is_yx_order = get_dimension_names(ogrid.dimensions) == ogrid_dimnames

    ovalue_stacked = ogrid.get_value_stacked()
    row = egrid.get_coords(1, staggerloc=ESMF.StaggerLoc.CENTER)
    orow = ovalue_stacked[0, ...]
    if is_yx_order:
        orow = np.swapaxes(orow, 0, 1)
    row[:] = orow

    col = egrid.get_coords(0, staggerloc=ESMF.StaggerLoc.CENTER)
    ocol = ovalue_stacked[1, ...]
    if is_yx_order:
        ocol = np.swapaxes(ocol, 0, 1)
    col[:] = ocol

    ####################################################################################################################

    # Use a logical or operation to merge with value_mask if present
    if value_mask is not None:
        # convert to boolean to make sure
        value_mask = value_mask.astype(bool)
        # do the logical or operation selecting values
        value_mask = np.logical_or(value_mask, ogrid.get_mask(create=True))
    else:
        value_mask = ogrid.get_mask()
    # Follows SCRIP convention where 1 is unmasked and 0 is masked.
    if value_mask is not None:
        esmf_mask = np.invert(value_mask).astype(np.int32)
        esmf_mask = np.swapaxes(esmf_mask, 0, 1)
        egrid.add_item(ESMF.GridItem.MASK, staggerloc=ESMF.StaggerLoc.CENTER, from_file=False)
        egrid.mask[0][:] = esmf_mask

    # Attempt to access corners if requested.
    if regrid_method == 'auto' and ogrid.has_bounds:
        regrid_method = ESMF.RegridMethod.CONSERVE

    if regrid_method == ESMF.RegridMethod.CONSERVE:
        # Conversion to ESMF objects requires an expanded grid (non-vectorized).
        # TODO: Create ESMF grids from vectorized OCGIS grids.
        expand_grid(ogrid)
        # Convert to ESMF corners from OCGIS corners.
        corners_esmf = np.zeros([2] + [element + 1 for element in max_index], dtype=col.dtype)
        get_esmf_corners_from_ocgis_corners(ogrid.y.bounds.get_value(), fill=corners_esmf[0, :, :])
        get_esmf_corners_from_ocgis_corners(ogrid.x.bounds.get_value(), fill=corners_esmf[1, :, :])

        # adding corners. first tell the grid object to allocate corners
        egrid.add_coords(staggerloc=[ESMF.StaggerLoc.CORNER])
        # get the coordinate pointers and set the coordinates
        grid_corner = egrid.coords[ESMF.StaggerLoc.CORNER]
        # Note indexing is reversed for ESMF v. OCGIS. In ESMF, the x-coordinate (longitude) is the first
        # coordinate. If this is periodic, the last column corner wraps/connect to the first. This coordinate must
        # be removed.
        if pkwds['num_peri_dims'] is not None:
            grid_corner[0][:] = corners_esmf[1][0:-1, :]
            grid_corner[1][:] = corners_esmf[0][0:-1, :]
        else:
            grid_corner[0][:] = corners_esmf[1]
            grid_corner[1][:] = corners_esmf[0]

    return egrid