Пример #1
0
def test_viscosity_filter(vector_grid_type_and_input_ds, filter_args):
    """Test all viscosity-based filters: filters that use a vector Laplacian."""
    grid_type, da_u, da_v, grid_vars, geolat_u = vector_grid_type_and_input_ds

    filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **filter_args)
    filtered_u, filtered_v = filter.apply_to_vector(da_u,
                                                    da_v,
                                                    dims=["y", "x"])

    # check conservation under solid body rotation: u = cos(lat), v=0;
    data_u = np.cos(geolat_u / 360 * 2 * np.pi)
    data_v = np.zeros_like(data_u)
    da_u = xr.DataArray(data_u, dims=["y", "x"])
    da_v = xr.DataArray(data_v, dims=["y", "x"])
    filtered_u, filtered_v = filter.apply_to_vector(da_u,
                                                    da_v,
                                                    dims=["y", "x"])
    xr.testing.assert_allclose(filtered_u, da_u, atol=1e-12)
    xr.testing.assert_allclose(filtered_v, da_v, atol=1e-12)

    # check that we get an error if we pass vector Laplacian to .apply, where
    # the latter method is for scalar Laplacians only
    with pytest.raises(ValueError, match=r"Provided Laplacian *"):
        filtered_u = filter.apply(da_u, dims=["y", "x"])

    # check that we get an error if we leave out any required grid_vars
    for gv in grid_vars:
        grid_vars_missing = {k: v for k, v in grid_vars.items() if k != gv}
        with pytest.raises(ValueError, match=r"Provided `grid_vars` .*"):
            filter = Filter(grid_type=grid_type,
                            grid_vars=grid_vars_missing,
                            **filter_args)
Пример #2
0
def test_iterated_viscosity_filter(vector_grid_type_and_input_ds, filter_args,
                                   n_iterations):
    """Test error in the iterated Gaussian filter for vectors"""
    grid_type, da_u, da_v, grid_vars, _ = vector_grid_type_and_input_ds

    filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **filter_args)
    filtered_u, filtered_v = filter.apply_to_vector(da_u,
                                                    da_v,
                                                    dims=["y", "x"])

    iterated_filter_args = filter_args.copy()
    iterated_filter_args["n_iterations"] = n_iterations
    iterated_filter = Filter(grid_type=grid_type,
                             grid_vars=grid_vars,
                             **iterated_filter_args)
    iteratively_filtered_u, iteratively_filtered_v = iterated_filter.apply_to_vector(
        da_u, da_v, dims=["y", "x"])

    area = 1
    for k, v in grid_vars.items():
        if "area" in k:
            area = v
            break

    # The following tests whether a relative error bound in L^2 holds.
    # See the "Factoring the Gaussian Filter" section of the docs for details.
    difference = (filtered_u - iteratively_filtered_u)**2 + (
        filtered_v - iteratively_filtered_v)**2
    unfiltered = da_u**2 + da_v**2
    assert (difference * area).sum() < (
        (0.01 * (1 + n_iterations))**2) * (unfiltered * area).sum()
Пример #3
0
def test_diffusion_filter(grid_type_and_input_ds, filter_args):
    """Test all diffusion-based filters: filters that use a scalar Laplacian."""
    grid_type, da, grid_vars = grid_type_and_input_ds

    filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **filter_args)
    filter.plot_shape()
    filtered = filter.apply(da, dims=["y", "x"])

    # check conservation
    area = 1
    for k, v in grid_vars.items():
        if "area" in k:
            area = v
            break
    da_sum = (da * area).sum()
    filtered_sum = (filtered * area).sum()
    xr.testing.assert_allclose(da_sum, filtered_sum)

    # check that we get an error if we pass scalar Laplacian to .apply_to vector,
    # where the latter method is for vector Laplacians only
    with pytest.raises(ValueError, match=r"Provided Laplacian *"):
        filtered_u, filtered_v = filter.apply_to_vector(da, da, dims=["y", "x"])

    # check variance reduction
    assert (filtered**2).sum() < (da**2).sum()

    # check that we get an error if we leave out any required grid_vars
    for gv in grid_vars:
        grid_vars_missing = {k: v for k, v in grid_vars.items() if k != gv}
        with pytest.raises(ValueError, match=r"Provided `grid_vars` .*"):
            filter = Filter(
                grid_type=grid_type, grid_vars=grid_vars_missing, **filter_args
            )

    bad_filter_args = copy.deepcopy(filter_args)
    # check that we get an error when transition_width <= 1
    bad_filter_args["transition_width"] = 1
    with pytest.raises(ValueError, match=r"Transition width .*"):
        filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **bad_filter_args)
    bad_filter_args["transition_width"] = np.pi
    # check that we get an error if ndim > 2 and n_steps = 0
    bad_filter_args["ndim"] = 3
    bad_filter_args["n_steps"] = 0
    with pytest.raises(ValueError, match=r"When ndim > 2, you .*"):
        filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **bad_filter_args)
    # check that we get a warning if n_steps < n_steps_default
    bad_filter_args["ndim"] = 2
    bad_filter_args["n_steps"] = 3
    with pytest.warns(UserWarning, match=r"You have set n_steps .*"):
        filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **bad_filter_args)
    # check that we get an error if we pass dx_min != 1 to a regular scalar Laplacian
    if grid_type in area_weighted_regular_grids:
        bad_filter_args["filter_scale"] = 3  # restore good value for filter scale
        bad_filter_args["dx_min"] = 3
        with pytest.raises(ValueError, match=r"Provided Laplacian .*"):
            filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **bad_filter_args)
Пример #4
0
def test_diffusion_filter(grid_type_and_input_ds, filter_args):
    """Test all diffusion-based filters: filters that use a scalar Laplacian."""
    grid_type, da, grid_vars = grid_type_and_input_ds

    filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **filter_args)
    filter.plot_shape()
    filtered = filter.apply(da, dims=["y", "x"])

    # check conservation
    # this would need to be replaced by a proper area-weighted integral
    da_sum = da.sum()
    filtered_sum = filtered.sum()
    xr.testing.assert_allclose(da_sum, filtered_sum)

    # check that we get an error if we pass scalar Laplacian to .apply_to vector,
    # where the latter method is for vector Laplacians only
    with pytest.raises(ValueError, match=r"Provided Laplacian *"):
        filtered_u, filtered_v = filter.apply_to_vector(da,
                                                        da,
                                                        dims=["y", "x"])

    # check variance reduction
    assert (filtered**2).sum() < (da**2).sum()

    # check that we get an error if we leave out any required grid_vars
    for gv in grid_vars:
        grid_vars_missing = {k: v for k, v in grid_vars.items() if k != gv}
        with pytest.raises(ValueError, match=r"Provided `grid_vars` .*"):
            filter = Filter(grid_type=grid_type,
                            grid_vars=grid_vars_missing,
                            **filter_args)

    bad_filter_args = copy.deepcopy(filter_args)
    # check that we get an error if ndim > 2 and n_steps = 0
    bad_filter_args["ndim"] = 3
    bad_filter_args["n_steps"] = 0
    with pytest.raises(ValueError, match=r"When ndim > 2, you .*"):
        filter = Filter(grid_type=grid_type,
                        grid_vars=grid_vars,
                        **bad_filter_args)
    # check that we get a warning if n_steps < n_steps_default
    bad_filter_args["ndim"] = 2
    bad_filter_args["n_steps"] = 3
    with pytest.warns(UserWarning, match=r"Warning: You have set n_steps .*"):
        filter = Filter(grid_type=grid_type,
                        grid_vars=grid_vars,
                        **bad_filter_args)
    # check that we get a warning if numerical instability possible
    bad_filter_args["n_steps"] = 0
    bad_filter_args["filter_scale"] = 1000
    with pytest.warns(UserWarning,
                      match=r"Warning: Filter scale much larger .*"):
        filter = Filter(grid_type=grid_type,
                        grid_vars=grid_vars,
                        **bad_filter_args)
Пример #5
0
def _get_results(grid_data_and_input_ds, filter_args):
    grid_type, data, grid_vars = grid_data_and_input_ds

    filter = Filter(grid_type=grid_type, grid_vars=grid_vars, **filter_args)

    if len(data) == 2:  # vector grid
        (filtered_u, filtered_v) = filter.apply_to_vector(*data,
                                                          dims=["y", "x"])
        filtered = np.stack([filtered_u.data, filtered_v.data])
    else:
        filtered = filter.apply(data, dims=["y", "x"])
        filtered = filtered.data

    filtered = filtered.astype("f4")  # use single precision to save space
    return filtered