diff --git a/src/emsarray/conventions/ugrid.py b/src/emsarray/conventions/ugrid.py index 77eda9a..967fcfb 100644 --- a/src/emsarray/conventions/ugrid.py +++ b/src/emsarray/conventions/ugrid.py @@ -748,6 +748,31 @@ def has_valid_face_edge_connectivity(self) -> bool: ) return False + try: + fill_value = data_array.encoding['_FillValue'] + except KeyError: + return True + + lower_bound = _get_start_index(data_array) + theoretical_upper_bound = self.face_count * self.max_node_count + actual_upper_bound = numpy.nanmax(data_array) + + if lower_bound < fill_value < actual_upper_bound: + warnings.warn( + f"Got a face_edge_connectivity variable {data_array.name!r} with " + f"a _FillValue inside the actual index range", + ConventionViolationWarning, + ) + return False + + if lower_bound < fill_value < theoretical_upper_bound: + warnings.warn( + f"Got a face_edge_connectivity variable {data_array.name!r} with " + f"a _FillValue inside the theoretical index range", + ConventionViolationWarning, + ) + return False + return True @cached_property diff --git a/tests/conventions/test_ugrid.py b/tests/conventions/test_ugrid.py index 0da3517..f7ecc2c 100644 --- a/tests/conventions/test_ugrid.py +++ b/tests/conventions/test_ugrid.py @@ -924,3 +924,40 @@ def da(attrs: dict) -> xarray.DataArray: with pytest.raises(ConventionViolationError): _get_start_index(da({'start_index': 2})) + + +def test_has_valid_face_edge_connectivity(): + # Create dataset with face_edges + dataset = make_dataset(width=3, make_edges=True, make_face_coordinates=True) + topology = dataset.ems.topology + topology.mesh_variable.attrs.update({ + 'face_edge_connectivity': 'Mesh2_face_edges', + }) + + mesh2_face_edges_array = topology.face_edge_array + + mesh2_face_edges = xarray.DataArray( + mesh2_face_edges_array, + dims=[topology.face_dimension, topology.max_node_dimension], + ) + + dataset = dataset.assign({ + 'Mesh2_face_edges': mesh2_face_edges, + }) + + dataset_fill_value_in_actual_range = dataset.copy() + + dataset_fill_value_in_theoretical_range = dataset.copy() + + # Make sure original dataset is valid + assert dataset.ems.topology.has_valid_face_edge_connectivity is True + + dataset_fill_value_in_actual_range['Mesh2_face_edges'].encoding['_FillValue'] = 2 + + with pytest.warns(ConventionViolationWarning): + assert dataset_fill_value_in_actual_range.ems.topology.has_valid_face_edge_connectivity is not True + + dataset_fill_value_in_theoretical_range['Mesh2_face_edges'].encoding['_FillValue'] = 88 + + with pytest.warns(ConventionViolationWarning): + assert dataset_fill_value_in_theoretical_range.ems.topology.has_valid_face_edge_connectivity is not True