def test_global_grid():
    """Test conversion of a global grid."""
    n_lons = 6
    n_lats = 5
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)

    cube = _grid_cube(
        n_lons,
        n_lats,
        lon_bounds,
        lat_bounds,
        circular=True,
        coord_system=GeogCS(EARTH_RADIUS),
    )
    gridinfo = _cube_to_GridInfo(cube)
    # Ensure conversion to ESMF works without error
    _ = gridinfo.make_esmf_field()

    # The following test ensures there are no overlapping cells.
    # This catches geometric/topological abnormalities that would arise from,
    # for example: switching lat/lon values, using euclidean coords vs spherical.
    rg = Regridder(gridinfo, gridinfo)
    expected_weights = scipy.sparse.identity(n_lats * n_lons)
    assert np.array_equal(expected_weights.todense(),
                          rg.weight_matrix.todense())
    assert gridinfo.crs == GeogCS(EARTH_RADIUS).as_cartopy_crs()
def _regrid_rectilinear_to_unstructured__prepare(
    src_grid_cube,
    target_mesh_cube,
    method,
    precomputed_weights=None,
    resolution=None,
):
    """
    First (setup) part of 'regrid_rectilinear_to_unstructured'.

    Check inputs and calculate the sparse regrid matrix and related info.
    The 'regrid info' returned can be re-used over many 2d slices.

    """
    grid_x = src_grid_cube.coord(axis="x")
    grid_y = src_grid_cube.coord(axis="y")
    mesh = target_mesh_cube.mesh
    location = target_mesh_cube.location
    if mesh is None:
        raise ValueError("The given cube is not defined on a mesh.")
    if method == "conservative":
        if location != "face":
            raise ValueError(
                f"Conservative regridding requires a target cube located on "
                f"the face of a cube, target cube had the {location} location."
            )
        center = False
    elif method == "bilinear":
        if location not in ["face", "node"]:
            raise ValueError(
                f"Bilinear regridding requires a target cube with a node "
                f"or face location, target cube had the {location} location."
            )
        if location == "face" and None in mesh.face_coords:
            raise ValueError(
                "Bilinear regridding requires a target cube on a face location to have "
                "a face center."
            )
        center = True
    else:
        raise ValueError(
            f"method must be either 'bilinear' or 'conservative', got '{method}'."
        )
    assert mesh is not None
    if grid_x.ndim == 1:
        (grid_x_dim,) = src_grid_cube.coord_dims(grid_x)
        (grid_y_dim,) = src_grid_cube.coord_dims(grid_y)
    else:
        grid_y_dim, grid_x_dim = src_grid_cube.coord_dims(grid_x)

    meshinfo = _mesh_to_MeshInfo(mesh, location)
    gridinfo = _cube_to_GridInfo(src_grid_cube, center=center, resolution=resolution)

    regridder = Regridder(
        gridinfo, meshinfo, method=method, precomputed_weights=precomputed_weights
    )

    regrid_info = (grid_x_dim, grid_y_dim, grid_x, grid_y, mesh, location, regridder)

    return regrid_info
def test_curvilinear_grid():
    """Test conversion of a curvilinear global grid."""
    n_lons = 6
    n_lats = 5
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)

    cube = _curvilinear_cube(
        n_lons,
        n_lats,
        lon_bounds,
        lat_bounds,
        coord_system=GeogCS(EARTH_RADIUS),
    )
    gridinfo = _cube_to_GridInfo(cube)
    # Ensure conversion to ESMF works without error
    _ = gridinfo.make_esmf_field()

    # The following test ensures there are no overlapping cells.
    # This catches geometric/topological abnormalities that would arise from,
    # for example: switching lat/lon values, using euclidean coords vs spherical.
    rg = Regridder(gridinfo, gridinfo)
    expected_weights = scipy.sparse.identity(n_lats * n_lons)
    assert np.array_equal(expected_weights.todense(),
                          rg.weight_matrix.todense())
    assert gridinfo.crs == GeogCS(EARTH_RADIUS).as_cartopy_crs()

    # While curvilinear coords do not have the "circular" attribute, the code
    # allows "circular" to be True when setting the core regridder directly.
    # This describes an ESMF object which is topologically different, but ought
    # to be geometrically equivalent to the non-circular case.
    circular_gridinfo = _cube_to_GridInfo(cube)
    circular_gridinfo.circular = True
    rg_circular = Regridder(circular_gridinfo, gridinfo)
    assert np.allclose(expected_weights.todense(),
                       rg_circular.weight_matrix.todense())
def test_local_grid():
    """Test conversion of a local grid."""
    n_lons = 6
    n_lats = 5
    lon_bounds = (-20, 20)
    lat_bounds = (20, 60)

    cube = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds)
    gridinfo = _cube_to_GridInfo(cube)
    # Ensure conversion to ESMF works without error
    _ = gridinfo.make_esmf_field()

    # The following test ensures there are no overlapping cells.
    # Note that this test fails when longitude is circular.
    rg = Regridder(gridinfo, gridinfo)
    expected_weights = scipy.sparse.identity(n_lats * n_lons)
    assert np.array_equal(expected_weights.todense(), rg.weight_matrix.todense())
def test_grid_with_scalars():
    """Test conversion of a grid with scalar coords."""
    n_lons = 1
    n_lats = 5
    lon_bounds = (-20, 20)
    lat_bounds = (20, 60)

    cube = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds)
    # Convert longitude to a scalar
    cube = cube[:, 0]
    assert len(cube.shape) == 1

    gridinfo = _cube_to_GridInfo(cube)
    # Ensure conversion to ESMF works without error
    _ = gridinfo.make_esmf_field()

    # The following test ensures there are no overlapping cells.
    rg = Regridder(gridinfo, gridinfo)
    expected_weights = scipy.sparse.identity(n_lats * n_lons)
    assert np.array_equal(expected_weights.todense(), rg.weight_matrix.todense())