diff --git a/test/io/test_icon.py b/test/io/test_icon.py index a9c3cd457..e8344ff85 100644 --- a/test/io/test_icon.py +++ b/test/io/test_icon.py @@ -8,3 +8,17 @@ def test_read_icon_grid(gridpath): def test_read_icon_dataset(gridpath): grid_path = gridpath("icon", "R02B04", "icon_grid_0010_R02B04_G.nc") uxds = ux.open_dataset(grid_path, grid_path) + +def test_icon_cross_section(gridpath): + grid_path = gridpath("icon", "R02B04", "icon_grid_0010_R02B04_G.nc") + uxds = ux.open_dataset(grid_path, grid_path) + + # Test cross_section with cell_area variable + result = uxds.cell_area.cross_section(start=(0, -90), end=(0, 90)) + assert result is not None + assert len(result) == 100 # 100 steps by default + assert result.dims == ('steps',) + assert all(result.coords['lon'] == 0.0) # Constant longitude + assert result.coords['lat'].min() == -90.0 + assert result.coords['lat'].max() == 90.0 + assert result.attrs['units'] == 'steradian' diff --git a/uxarray/cross_sections/dataarray_accessor.py b/uxarray/cross_sections/dataarray_accessor.py index a925c122e..b27e5c2b0 100644 --- a/uxarray/cross_sections/dataarray_accessor.py +++ b/uxarray/cross_sections/dataarray_accessor.py @@ -132,7 +132,11 @@ def __call__( data = np.moveaxis(filled, -1, dim_axis) # Build coords dict: keep everything except 'n_face' - coords = {d: self.uxda.coords[d] for d in self.uxda.coords if d != "n_face"} + coords = { + name: self.uxda.coords[name] + for name in self.uxda.coords + if name != "n_face" and "n_face" not in self.uxda.coords[name].dims + } # index along the arc coords[new_dim] = np.arange(steps) diff --git a/uxarray/io/_icon.py b/uxarray/io/_icon.py index 4e3e42c2a..9921535e0 100644 --- a/uxarray/io/_icon.py +++ b/uxarray/io/_icon.py @@ -5,8 +5,66 @@ def _icon_to_ugrid_dims(in_ds): - source_dims_dict = {"vertex": "n_node", "edge": "n_edge", "cell": "n_face"} - return source_dims_dict + """Parse ICON dimension names and map them to UGRID conventions.""" + source_dims_dict = {} + + # Coordinate-driven mappings + if "vlat" in in_ds: + source_dims_dict[in_ds["vlat"].dims[0]] = ugrid.NODE_DIM + if "vlon" in in_ds: + source_dims_dict[in_ds["vlon"].dims[0]] = ugrid.NODE_DIM + + if "elat" in in_ds: + source_dims_dict[in_ds["elat"].dims[0]] = ugrid.EDGE_DIM + if "elon" in in_ds: + source_dims_dict[in_ds["elon"].dims[0]] = ugrid.EDGE_DIM + + if "clat" in in_ds: + source_dims_dict[in_ds["clat"].dims[0]] = ugrid.FACE_DIM + if "clon" in in_ds: + source_dims_dict[in_ds["clon"].dims[0]] = ugrid.FACE_DIM + + # Connectivity-driven mappings + if "vertex_of_cell" in in_ds: + n_max_face_nodes_dim, face_dim = in_ds["vertex_of_cell"].dims + source_dims_dict.setdefault(face_dim, ugrid.FACE_DIM) + source_dims_dict.setdefault(n_max_face_nodes_dim, ugrid.N_MAX_FACE_NODES_DIM) + + if "edge_of_cell" in in_ds: + n_max_face_edges_dim, face_dim = in_ds["edge_of_cell"].dims + source_dims_dict.setdefault(face_dim, ugrid.FACE_DIM) + source_dims_dict.setdefault( + n_max_face_edges_dim, ugrid.FACE_EDGE_CONNECTIVITY_DIMS[1] + ) + + if "neighbor_cell_index" in in_ds: + n_max_face_faces_dim, face_dim = in_ds["neighbor_cell_index"].dims + source_dims_dict.setdefault(face_dim, ugrid.FACE_DIM) + source_dims_dict.setdefault( + n_max_face_faces_dim, ugrid.FACE_FACE_CONNECTIVITY_DIMS[1] + ) + + if "adjacent_cell_of_edge" in in_ds: + two_dim, edge_dim = in_ds["adjacent_cell_of_edge"].dims + source_dims_dict.setdefault(edge_dim, ugrid.EDGE_DIM) + source_dims_dict.setdefault(two_dim, ugrid.EDGE_FACE_CONNECTIVITY_DIMS[1]) + + if "edge_vertices" in in_ds: + two_dim, edge_dim = in_ds["edge_vertices"].dims + source_dims_dict.setdefault(edge_dim, ugrid.EDGE_DIM) + source_dims_dict.setdefault(two_dim, ugrid.EDGE_NODE_CONNECTIVITY_DIMS[1]) + + # Fall back to common ICON dimension names if they were not detected above + for dim, ugrid_dim in { + "vertex": ugrid.NODE_DIM, + "edge": ugrid.EDGE_DIM, + "cell": ugrid.FACE_DIM, + }.items(): + if dim in in_ds.dims: + source_dims_dict.setdefault(dim, ugrid_dim) + + # Keep only dims that actually exist on the dataset + return {dim: name for dim, name in source_dims_dict.items() if dim in in_ds.dims} def _primal_to_ugrid(in_ds, out_ds):