Exemple #1
0
    def setup_cache(self):
        SYNTH_DATA_DIR = Path().cwd() / "tmp_data"
        SYNTH_DATA_DIR.mkdir(exist_ok=True)
        file = str(SYNTH_DATA_DIR.joinpath("chunked_cube.nc"))
        lon_bounds = (-180, 180)
        lat_bounds = (-90, 90)
        n_lons_src = 100
        n_lats_src = 200
        n_lons_tgt = 20
        n_lats_tgt = 40
        h = 2000
        # Rotated coord systems prevent pickling of the regridder so are
        # removed for the time being.
        grid = _grid_cube(
            n_lons_src,
            n_lats_src,
            lon_bounds,
            lat_bounds,
            # alt_coord_system=True,
        )
        tgt = _grid_cube(n_lons_tgt, n_lats_tgt, lon_bounds, lat_bounds)

        chunk_size = [n_lats_src, n_lons_src, 10]
        src_data = da.ones([n_lats_src, n_lons_src, h], chunks=chunk_size)
        src = Cube(src_data)
        src.add_dim_coord(grid.coord("latitude"), 0)
        src.add_dim_coord(grid.coord("longitude"), 1)
        iris.save(src, file, chunksizes=chunk_size)
        # Construct regridder with a loaded version of the grid for consistency.
        loaded_src = iris.load_cube(file)
        regridder = ESMFAreaWeightedRegridder(loaded_src, tgt)

        return regridder, file
Exemple #2
0
def test_dim_switching():
    """
    Test calling of :func:`esmf_regrid.schemes.ESMFAreaWeightedRegridder`.

    Checks that the regridder accepts a cube with dimensions in a different
    order than the cube which initialised it. Checks that dimension order is
    inherited from the cube in the calling function in both cases.
    """
    n_lons = 6
    n_lats = 5
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)
    src = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds, circular=True)
    tgt = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds, circular=True)

    regridder = ESMFAreaWeightedRegridder(src, tgt)
    unswitched_result = regridder(src)

    src_switched = src.copy()
    src_switched.transpose()
    switched_result = regridder(src_switched)

    assert unswitched_result.coord(
        dimensions=(0, )).standard_name == "latitude"
    assert unswitched_result.coord(
        dimensions=(1, )).standard_name == "longitude"
    assert switched_result.coord(dimensions=(0, )).standard_name == "longitude"
    assert switched_result.coord(dimensions=(1, )).standard_name == "latitude"
Exemple #3
0
 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
     grid = _grid_cube(
         n_lons_src,
         n_lats_src,
         lon_bounds,
         lat_bounds,
         alt_coord_system=(type == "mixed"),
     )
     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
Exemple #4
0
def test_invalid_mdtol():
    """
    Test initialisation of :func:`esmf_regrid.schemes.ESMFAreaWeightedRegridder`.

    Checks that an error is raised when mdtol is out of range.
    """
    n_lons = 6
    n_lats = 5
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)
    src = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds, circular=True)
    tgt = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds, circular=True)

    match = "Value for mdtol must be in range 0 - 1, got "
    with pytest.raises(ValueError, match=match):
        _ = ESMFAreaWeightedRegridder(src, tgt, mdtol=2)
    with pytest.raises(ValueError, match=match):
        _ = ESMFAreaWeightedRegridder(src, tgt, mdtol=-1)
Exemple #5
0
def test_curvilinear_equivalence():
    """
    Test initialisation of :func:`esmf_regrid.schemes.ESMFAreaWeightedRegridder`.

    Checks that equivalent curvilinear and rectilinear coordinates give the same
    results.
    """
    n_lons_src = 6
    n_lons_tgt = 3
    n_lats_src = 4
    n_lats_tgt = 2
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)
    grid_src = _grid_cube(n_lons_src,
                          n_lats_src,
                          lon_bounds,
                          lat_bounds,
                          circular=True)
    grid_tgt = _grid_cube(n_lons_tgt,
                          n_lats_tgt,
                          lon_bounds,
                          lat_bounds,
                          circular=True)
    curv_src = _curvilinear_cube(n_lons_src, n_lats_src, lon_bounds,
                                 lat_bounds)
    curv_tgt = _curvilinear_cube(n_lons_tgt, n_lats_tgt, lon_bounds,
                                 lat_bounds)

    grid_to_grid = ESMFAreaWeightedRegridder(grid_src, grid_tgt)
    grid_to_curv = ESMFAreaWeightedRegridder(grid_src, curv_tgt)
    curv_to_grid = ESMFAreaWeightedRegridder(curv_src, grid_tgt)
    curv_to_curv = ESMFAreaWeightedRegridder(curv_src, curv_tgt)

    def extract_weights(regridder):
        return regridder.regridder.weight_matrix.todense()

    for regridder in [grid_to_curv, curv_to_grid, curv_to_curv]:
        assert np.allclose(extract_weights(grid_to_grid),
                           extract_weights(regridder))
Exemple #6
0
def test_differing_grids():
    """
    Test calling of :func:`esmf_regrid.schemes.ESMFAreaWeightedRegridder`.

    Checks that the regridder raises an error when given a cube with a different
    grid to the one it was initialised with.
    """
    n_lons = 6
    n_lats = 5
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)
    src_init = _grid_cube(n_lons,
                          n_lats,
                          lon_bounds,
                          lat_bounds,
                          circular=True)
    tgt = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds, circular=True)

    n_lons_dif = 7
    src_dif_coord = _grid_cube(n_lons_dif,
                               n_lats,
                               lon_bounds,
                               lat_bounds,
                               circular=True)
    src_dif_circ = _grid_cube(n_lons,
                              n_lats,
                              lon_bounds,
                              lat_bounds,
                              circular=False)

    regridder = ESMFAreaWeightedRegridder(src_init, tgt)

    msg = "The given cube is not defined on the same source grid as this regridder."
    with pytest.raises(ValueError, match=msg):
        _ = regridder(src_dif_coord)
    with pytest.raises(ValueError, match=msg):
        _ = regridder(src_dif_circ)
Exemple #7
0
def test_unit_equivalence():
    """
    Test initialisation of :func:`esmf_regrid.schemes.ESMFAreaWeightedRegridder`.

    Checks that equivalent coordinates in degrees and radians give the same results.
    """
    n_lons_src = 6
    n_lons_tgt = 3
    n_lats_src = 4
    n_lats_tgt = 2
    lon_bounds = (-180, 180)
    lat_bounds = (-90, 90)
    lon_rad_bounds = (-np.pi, np.pi)
    lat_rad_bounds = (-np.pi / 2, np.pi / 2)

    def rad_coords(cube):
        cube.coord("latitude").units = Unit("radians")
        cube.coord("longitude").units = Unit("radians")

    grid_src = _grid_cube(n_lons_src,
                          n_lats_src,
                          lon_bounds,
                          lat_bounds,
                          circular=True)
    grid_src_rad = _grid_cube(n_lons_src,
                              n_lats_src,
                              lon_rad_bounds,
                              lat_rad_bounds,
                              circular=True)
    rad_coords(grid_src_rad)
    grid_tgt = _grid_cube(n_lons_tgt,
                          n_lats_tgt,
                          lon_bounds,
                          lat_bounds,
                          circular=True)
    grid_tgt_rad = _grid_cube(n_lons_tgt,
                              n_lats_tgt,
                              lon_rad_bounds,
                              lat_rad_bounds,
                              circular=True)
    rad_coords(grid_tgt_rad)
    curv_src = _curvilinear_cube(n_lons_src, n_lats_src, lon_bounds,
                                 lat_bounds)
    curv_src_rad = _curvilinear_cube(n_lons_src, n_lats_src, lon_rad_bounds,
                                     lat_rad_bounds)
    rad_coords(curv_src_rad)
    curv_tgt = _curvilinear_cube(n_lons_tgt, n_lats_tgt, lon_bounds,
                                 lat_bounds)
    curv_tgt_rad = _curvilinear_cube(n_lons_tgt, n_lats_tgt, lon_rad_bounds,
                                     lat_rad_bounds)
    rad_coords(curv_tgt_rad)

    grid_to_grid = ESMFAreaWeightedRegridder(grid_src, grid_tgt)
    grid_rad_to_grid = ESMFAreaWeightedRegridder(grid_src_rad, grid_tgt)
    grid_rad_to_curv = ESMFAreaWeightedRegridder(grid_src_rad, curv_tgt)
    curv_to_grid_rad = ESMFAreaWeightedRegridder(curv_src, grid_tgt_rad)
    curv_rad_to_grid = ESMFAreaWeightedRegridder(curv_src_rad, grid_tgt)
    curv_to_curv_rad = ESMFAreaWeightedRegridder(curv_src, curv_tgt_rad)

    def extract_weights(regridder):
        return regridder.regridder.weight_matrix.todense()

    for regridder in [
            grid_rad_to_grid,
            grid_rad_to_curv,
            curv_to_grid_rad,
            curv_rad_to_grid,
            curv_to_curv_rad,
    ]:
        assert np.allclose(extract_weights(grid_to_grid),
                           extract_weights(regridder))