diff --git a/tests/test_regrid/test_regridder.py b/tests/test_regrid/test_regridder.py index 699e39fd..515881ee 100644 --- a/tests/test_regrid/test_regridder.py +++ b/tests/test_regrid/test_regridder.py @@ -283,3 +283,41 @@ def test_create_percentile_method(): weights = np.ones_like(values) workspace = np.zeros_like(values) assert median(values, weights, workspace) == 2 + + +def test_directional_dependence(): + # Increasing / decreasing x or y direction shouldn't matter for the result. + da = xr.DataArray( + data=[[1.0, 2.0], [3.0, 4.0]], + coords={"y": [17.5, 12.5], "x": [2.5, 7.5]}, + dims=("y", "x"), + ) + target_da = xr.DataArray( + data=[[np.nan, np.nan], [np.nan, np.nan]], + coords={"y": [10.0, 20.0], "x": [0.0, 10.0]}, + dims=("y", "x"), + ) + target_uda = xu.UgridDataArray.from_structured(target_da) + + flip = slice(None, None, -1) + flipy = da.isel(y=flip) + flipx = da.isel(x=flip) + flipxy = da.isel(x=flip, y=flip) + uda = xu.UgridDataArray.from_structured(da) + uda_flipxy = xu.UgridDataArray.from_structured(flipxy) + + # Structured target: test whether the result is the same regardless of source + # orientation. + result = [] + for source in [da, flipy, flipx, flipxy, uda, uda_flipxy]: + regridder = xu.OverlapRegridder(source, taget=target_da) + result.append(regridder.regrid(source)) + assert all(result[0] == item for item in result[1:]) + + # Unstructured target: test whether the result is the same regardless of + # source orientation. + result = [] + for source in [da, flipy, flipx, flipxy, uda, uda_flipxy]: + regridder = xu.OverlapRegridder(source, taget=target_uda) + result.append(regridder.regrid(source)) + assert all(result[0] == item for item in result[1:]) diff --git a/tests/test_regrid/test_structured.py b/tests/test_regrid/test_structured.py index b5006a77..ca6e8db9 100644 --- a/tests/test_regrid/test_structured.py +++ b/tests/test_regrid/test_structured.py @@ -1,5 +1,6 @@ import numpy as np import pytest +import xarray as xr from xugrid.regrid.structured import StructuredGrid1d, StructuredGrid2d @@ -404,3 +405,25 @@ def test_linear_weights_2d( np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10]), np.array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]), ) + + +def test_nonscalar_dx(): + da = xr.DataArray( + [1, 2, 3], coords={"x": [1, 2, 3], "dx": ("x", [1, 1, 1])}, dims=("x",) + ) + grid = StructuredGrid1d(da, name="x") + actual = xr.DataArray([1, 2, 3], coords=grid.coords, dims=grid.dims) + assert actual.identical(da) + + +def test_directional_bounds(): + da = xr.DataArray([1, 2, 3], coords={"y": [1, 2, 3]}, dims=("y",)) + decreasing = da.isel(y=slice(None, None, -1)) + grid_inc = StructuredGrid1d(da, name="y") + grid_dec = StructuredGrid1d(decreasing, name="y") + assert grid_inc.flipped is False + assert grid_dec.flipped is True + assert np.array_equal(grid_inc.bounds, grid_dec.bounds) + assert np.array_equal( + grid_inc.directional_bounds, grid_dec.directional_bounds[::-1] + ) diff --git a/xugrid/regrid/structured.py b/xugrid/regrid/structured.py index 20e1ee1b..c670810a 100644 --- a/xugrid/regrid/structured.py +++ b/xugrid/regrid/structured.py @@ -83,10 +83,12 @@ def __init__(self, obj: Union[xr.DataArray, xr.Dataset], name: str): @property def coords(self) -> dict: - return { - self.name: self.index, - self.dname: self.dvalue, - } + coords = {self.name: self.index} + if isinstance(self.dvalue, np.ndarray): + coords[self.dname] = (self.name, self.dvalue) + else: + coords[self.dname] = self.dvalue + return coords @property def ndim(self) -> int: @@ -104,6 +106,14 @@ def size(self) -> int: def length(self) -> FloatArray: return np.squeeze(abs(np.diff(self.bounds, axis=1))) + @property + def directional_bounds(self): + # Only flip bounds if needed + if self.flipped: + return self.bounds[::-1, :].copy() + else: + return self.bounds + def flip_if_needed(self, index: IntArray) -> IntArray: if self.flipped: return self.size - index - 1 @@ -462,8 +472,8 @@ def convert_to(self, matched_type: Any) -> Any: return self elif matched_type == UnstructuredGrid2d: ugrid2d = Ugrid2d.from_structured_bounds( - self.xbounds.bounds, - self.ybounds.bounds, + self.xbounds.directional_bounds, + self.ybounds.directional_bounds, ) return UnstructuredGrid2d(ugrid2d) else: