From fae5a5f8c7e331097c6ac3f729ce9ba6bf84e9ad Mon Sep 17 00:00:00 2001 From: William Kearney Date: Thu, 9 Jan 2025 11:09:08 +0100 Subject: [PATCH 1/4] Add a test that compares fillsinks on arrays with different layouts This makes the comparison using array_equal and also checks to make sure that the memory layout was not changed by fillsinks. --- tests/test_grid_object.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_grid_object.py b/tests/test_grid_object.py index 8da6ef6..9de72bd 100755 --- a/tests/test_grid_object.py +++ b/tests/test_grid_object.py @@ -3,6 +3,8 @@ import topotoolbox as topo +import opensimplex + @pytest.fixture def square_dem(): @@ -67,6 +69,30 @@ def test_fillsinks(square_dem, wide_dem, tall_dem): assert sink < 8 +def test_fillsinks_order(): + opensimplex.seed(12) + + x = np.arange(0,128) + y = np.arange(0,256) + + dem_C = topo.GridObject() + dem_C.z = 64 * (opensimplex.noise2array(x,y) + 1) + + assert dem_C.z.flags.c_contiguous + + dem_F = topo.GridObject() + dem_F.z = np.asfortranarray(dem_C.z) + + assert dem_F.z.flags.f_contiguous + + filled_C = dem_C.fillsinks() + assert filled_C.z.flags.c_contiguous + + filled_F = dem_F.fillsinks() + assert filled_F.z.flags.f_contiguous + + assert np.array_equal(filled_F.z, filled_C.z) + def test_identifyflats(square_dem, wide_dem, tall_dem): # TODO: add more tests for dem in [square_dem, wide_dem, tall_dem]: From 0672987c04491479989cc9e5e25ca6a0ef4834ab Mon Sep 17 00:00:00 2001 From: William Kearney Date: Thu, 9 Jan 2025 11:20:50 +0100 Subject: [PATCH 2/4] Add a dims property and test that it gives the appropriate results --- src/topotoolbox/grid_object.py | 12 ++++++++++++ tests/test_grid_object.py | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/topotoolbox/grid_object.py b/src/topotoolbox/grid_object.py index 1a240ad..e31088d 100755 --- a/src/topotoolbox/grid_object.py +++ b/src/topotoolbox/grid_object.py @@ -64,6 +64,18 @@ def columns(self): """ return self.z.shape[1] + @property + def dims(self): + """The dimensions of the grid in the correct order for libtopotoolbox + """ + if self.z.flags.c_contiguous: + return (self.columns, self.rows) + + if self.z.flags.f_contiguous: + return (self.rows, self.columns) + + raise TypeError("Grid is not stored as a contiguous row- or column-major array") + def reproject(self, crs: 'CRS', resolution: 'float | None' = None, diff --git a/tests/test_grid_object.py b/tests/test_grid_object.py index 9de72bd..73052e7 100755 --- a/tests/test_grid_object.py +++ b/tests/test_grid_object.py @@ -78,12 +78,22 @@ def test_fillsinks_order(): dem_C = topo.GridObject() dem_C.z = 64 * (opensimplex.noise2array(x,y) + 1) + assert dem_C.shape[0] == 256 + assert dem_C.shape[1] == 128 + assert dem_C.z.flags.c_contiguous + assert dem_C.dims[0] == 128 + assert dem_C.dims[1] == 256 dem_F = topo.GridObject() dem_F.z = np.asfortranarray(dem_C.z) + assert dem_F.shape[0] == 256 + assert dem_F.shape[1] == 128 + assert dem_F.z.flags.f_contiguous + assert dem_F.dims[0] == 256 + assert dem_F.dims[1] == 128 filled_C = dem_C.fillsinks() assert filled_C.z.flags.c_contiguous From cd0eba3fc5aa22689f03b61f6c334026ac19217d Mon Sep 17 00:00:00 2001 From: William Kearney Date: Thu, 9 Jan 2025 11:22:02 +0100 Subject: [PATCH 3/4] Remove the memory order conversion from fillsinks This now passes the test that ensures that the memory order does not change within fillsinks, but it will fail the test that compares the two arrays. --- src/topotoolbox/grid_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topotoolbox/grid_object.py b/src/topotoolbox/grid_object.py index e31088d..15ec241 100755 --- a/src/topotoolbox/grid_object.py +++ b/src/topotoolbox/grid_object.py @@ -149,7 +149,7 @@ def fillsinks(self, """ - dem = self.z.astype(np.float32, order='F') + dem = self.z.astype(np.float32) output = np.zeros_like(dem) restore_nans = False From 700344be47c45c8de32427810499f4a7098c55cb Mon Sep 17 00:00:00 2001 From: William Kearney Date: Thu, 9 Jan 2025 11:49:37 +0100 Subject: [PATCH 4/4] Use GridObject.dims as an argument to fillsinks This should now work if the input array is row or column major. --- src/topotoolbox/grid_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topotoolbox/grid_object.py b/src/topotoolbox/grid_object.py index 15ec241..c1f1ada 100755 --- a/src/topotoolbox/grid_object.py +++ b/src/topotoolbox/grid_object.py @@ -173,9 +173,9 @@ def fillsinks(self, if hybrid: queue = np.zeros_like(dem, dtype=np.int64) - _grid.fillsinks_hybrid(output, queue, dem, bc, self.shape) + _grid.fillsinks_hybrid(output, queue, dem, bc, self.dims) else: - _grid.fillsinks(output, dem, bc, self.shape) + _grid.fillsinks(output, dem, bc, self.dims) if restore_nans: dem[nans] = np.nan