diff --git a/test/io/test_scrip.py b/test/io/test_scrip.py index c15464632..e1255066b 100644 --- a/test/io/test_scrip.py +++ b/test/io/test_scrip.py @@ -143,48 +143,15 @@ def test_scrip_dask_lazy_dedup_matches_eager(gridpath, chunks): """Opening a SCRIP grid with ``chunks=`` must produce the same mesh as the eager path, even though the underlying dedup algorithm differs (dask-native vs. Polars) once the corner arrays are dask-backed. - - The comparison is on corner coordinates *in winding order*, not sorted: - the two paths are free to number nodes differently, but the order of - corners within a face is what determines area sign and normal - direction, so it must be preserved exactly. """ grid_file = gridpath("scrip", "outCSne8", "outCSne8.nc") - grid_eager = ux.open_grid(grid_file) grid_lazy = ux.open_grid(grid_file, chunks=chunks) - assert isinstance(grid_lazy._ds["face_node_connectivity"].data, da.Array), ( f"chunks={chunks!r} did not produce a dask-backed connectivity, so this " "test would silently compare the eager path against itself" ) - - assert grid_eager.n_face == grid_lazy.n_face - assert grid_eager.n_node == grid_lazy.n_node - - fnc_eager = grid_eager.face_node_connectivity.values - fnc_lazy = grid_lazy.face_node_connectivity.values - - # Same set of unique nodes, independent of how each path numbered them. - nodes_eager = np.unique( - np.stack([grid_eager.node_lon.values, grid_eager.node_lat.values], 1), axis=0 - ) - nodes_lazy = np.unique( - np.stack([grid_lazy.node_lon.values, grid_lazy.node_lat.values], 1), axis=0 - ) - nt.assert_allclose(nodes_eager, nodes_lazy, atol=1e-10) - - # Same corners per face, in the same order. - nt.assert_allclose( - grid_eager.node_lon.values[fnc_eager], - grid_lazy.node_lon.values[fnc_lazy], - atol=1e-10, - ) - nt.assert_allclose( - grid_eager.node_lat.values[fnc_eager], - grid_lazy.node_lat.values[fnc_lazy], - atol=1e-10, - ) + assert grid_lazy == grid_eager def test_scrip_dask_lazy_dedup_matches_eager_radians(gridpath): @@ -192,25 +159,10 @@ def test_scrip_dask_lazy_dedup_matches_eager_radians(gridpath): radians, i.e. when ``_values_in_degrees`` converts a dask array rather than returning it untouched.""" grid_file = gridpath("scrip", "scrip_radians", "scrip_radians_grid.nc") - grid_eager = ux.open_grid(grid_file) grid_lazy = ux.open_grid(grid_file, chunks={"grid_size": 3}) - assert isinstance(grid_lazy._ds["face_node_connectivity"].data, da.Array) - assert grid_eager.n_node == grid_lazy.n_node - - fnc_eager = grid_eager.face_node_connectivity.values - fnc_lazy = grid_lazy.face_node_connectivity.values - nt.assert_allclose( - grid_eager.node_lon.values[fnc_eager], - grid_lazy.node_lon.values[fnc_lazy], - atol=1e-10, - ) - nt.assert_allclose( - grid_eager.node_lat.values[fnc_eager], - grid_lazy.node_lat.values[fnc_lazy], - atol=1e-10, - ) + assert grid_eager == grid_lazy def test_lookup_node_ids_preserves_input_order(): @@ -378,3 +330,19 @@ def test_open_multigrid_mask_active_value_per_grid_override(gridpath): assert grids["ocn"].n_face == expected_ocn assert grids["atm"].n_face == expected_atm + + +def test_scrip_load_is_deterministic(): + """Ensure loading the same SCRIP grid file repeatedly does not change results. + Regression test for issue #1738. + """ + examples = ["scrip-ne30pg2", "scrip-outCSne8"] + n_faces = [21600, 384] + for example, n_face in zip(examples, n_faces): + for kw in (dict(), dict(chunks="auto"), dict(chunks={"grid_size": n_face//4})): + # load 3 times instead of 2, to drastically reduce the odds of + # non-deterministic results which "just happen" to align. + gridA = ux.tutorial.open_grid(example, **kw) + gridB = ux.tutorial.open_grid(example, **kw) + gridC = ux.tutorial.open_grid(example, **kw) + assert gridA == gridB == gridC