diff --git a/docs/changelog.rst b/docs/changelog.rst index 98e8a1b11..53902391e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,18 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog`_, and this project adheres to `Semantic Versioning`_. +[Unreleased] +------------ + +Fixed +~~~~~ + +- Fixed indexing bug in the ``"mode"`` method in + :class:`xugrid.CentroidLocatorRegridder`, :class:`xugrid.OverlapRegridder`, + :class:`xugrid.RelativeOverlapRegridder`, which gave the method the tendency + to repeat the first value in the source grid across the target grid. + + [0.9.0] 2024-02-15 ------------------ diff --git a/tests/test_regrid/test_reduce.py b/tests/test_regrid/test_reduce.py index 3cf672478..4a696a099 100644 --- a/tests/test_regrid/test_reduce.py +++ b/tests/test_regrid/test_reduce.py @@ -55,6 +55,21 @@ def test_mode(args): # The weights shouldn't be mutated! assert np.allclose(weights, 0.5) + values = np.array([-1, 1, 1, 3, 4]) + indices = np.array([1, 2, 3]) + weights = np.array([1.0, 1.0, 1.0]) + args = (values, indices, weights) + actual = reduce.mode(*args) + assert np.allclose(actual, 1.0) + + values = np.array([99, 1, 2, 3, 4, 5, 6, 7, 8]) + indices = np.array([4, 5, 6]) + weights = np.array([0.5, 0.5, 0.5]) + args = (values, indices, weights) + actual = reduce.mode(*args) + assert np.allclose(actual, 4) + assert np.allclose(weights, 0.5) + def test_median(args): actual = reduce.median(*args) diff --git a/tests/test_regrid/test_regridder.py b/tests/test_regrid/test_regridder.py index 009770c74..984c3b5f9 100644 --- a/tests/test_regrid/test_regridder.py +++ b/tests/test_regrid/test_regridder.py @@ -103,6 +103,16 @@ def test_overlap_regridder_structured( assert broadcasted.dims == ("layer", "y", "x") assert (broadcasted.isel(layer=0) == expected_results_overlap).any() + # Test if "mode" method doesn't repeat first values again + # https://github.com/Deltares/xugrid/issues/236 + grid_data_adapted = grid_data_a.copy() + grid_data_adapted[0, 0] = 99 + regridder = OverlapRegridder( + source=grid_data_adapted, target=grid_data_a, method="mode" + ) + result = regridder.regrid(grid_data_adapted) + assert not np.all(result == 99.0) + def test_overlap_regridder(disk, quads_1): square = quads_1 diff --git a/xugrid/regrid/reduce.py b/xugrid/regrid/reduce.py index 146d08590..f278b80a7 100644 --- a/xugrid/regrid/reduce.py +++ b/xugrid/regrid/reduce.py @@ -122,8 +122,7 @@ def mode(values, indices, weights): return np.nan else: # Find value with highest frequency w_max = 0 - for i in range(accum.size): - w_accum = accum[i] + for w_accum, i in zip(accum, indices): if w_accum > w_max: w_max = w_accum v = values[i]