diff --git a/uxarray/io/_ugrid.py b/uxarray/io/_ugrid.py index a66dc8c18..91d4b7e6a 100644 --- a/uxarray/io/_ugrid.py +++ b/uxarray/io/_ugrid.py @@ -3,6 +3,7 @@ import uxarray.conventions.ugrid as ugrid from uxarray.constants import INT_DTYPE, INT_FILL_VALUE +from uxarray.conventions.descriptors import DESCRIPTOR_NAMES from uxarray.grid.connectivity import _replace_fill_values @@ -82,9 +83,37 @@ def _read_ugrid(ds): ds = ds.swap_dims(dim_dict) + # Strip non-grid extras (e.g. a stray scalar `time` coordinate, or unrelated data variables + ds = _keep_only_grid_vars(ds) + return ds, dim_dict +def _keep_only_grid_vars(ds): + """Return ``ds`` with only recognized UGRID grid variables/coordinates. + + Anything else on the dataset (a stray scalar ``time`` coordinate, unrelated + data variables, etc.) is dropped so it cannot leak onto ``grid._ds``. + + Runs on the file-read path only + """ + # uxarray's own canonical grid-variable names (the same lists Grid filters against) + keep = {"grid_topology"} + keep.update(ugrid.SPHERICAL_COORD_NAMES) # node/edge/face lon-lat + keep.update(ugrid.CARTESIAN_COORD_NAMES) # node/edge/face x-y-z + keep.update( + ugrid.CONNECTIVITY_NAMES + ) # face_node_connectivity, edge_node_connectivity, ... + keep.update( + DESCRIPTOR_NAMES + ) # n_nodes_per_face, face_areas, boundary_*_indices, ... + + # drop_vars removes variables/coords by name (never bare dimensions), so grid + # dims survive with their variables; errors="ignore" tolerates absent names. + drop = [name for name in ds.variables if name not in keep] + return ds.drop_vars(drop, errors="ignore") + + def _encode_ugrid(ds): """Encodes an unstructured grid represented under a ``Grid`` object as a ``xr.Dataset`` with an updated grid topology variable."""