Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/releases/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
Next release (in development)
=============================

* Added additional validation for ugrid
connectivity(:issue:`165`, :pr:`168`).
* Fix datasets hash_key generation when geometry encoding
is missing a dtype (:issue:`166`, :pr:`167`).
14 changes: 14 additions & 0 deletions src/emsarray/conventions/ugrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,20 @@ def has_valid_face_edge_connectivity(self) -> bool:
)
return False

if '_FillValue' in data_array.encoding:
fill_value = data_array.encoding['_FillValue']

lower_bound = _get_start_index(data_array)
upper_bound = self.edge_count + lower_bound

if lower_bound <= fill_value <= 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

return True

@cached_property
Expand Down
57 changes: 57 additions & 0 deletions tests/conventions/test_ugrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,3 +924,60 @@ 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_below_range = dataset.copy()

dataset_fill_value_in_range_on_lower_boundary = dataset.copy()

dataset_fill_value_in_range = dataset.copy()

dataset_fill_value_in_range_on_upper_boundary = dataset.copy()

dataset_fill_value_above_range = dataset.copy()

# Make sure original dataset is valid
assert dataset.ems.topology.has_valid_face_edge_connectivity is True

# Test valid and invalid fill values
dataset_fill_value_below_range['Mesh2_face_edges'].encoding['_FillValue'] = -1

assert dataset_fill_value_below_range.ems.topology.has_valid_face_edge_connectivity is True

dataset_fill_value_in_range_on_lower_boundary['Mesh2_face_edges'].encoding['_FillValue'] = 0

with pytest.warns(ConventionViolationWarning):
assert dataset_fill_value_in_range_on_lower_boundary.ems.topology.has_valid_face_edge_connectivity is not True

dataset_fill_value_in_range['Mesh2_face_edges'].encoding['_FillValue'] = 44

with pytest.warns(ConventionViolationWarning):
assert dataset_fill_value_in_range.ems.topology.has_valid_face_edge_connectivity is not True

dataset_fill_value_in_range_on_upper_boundary['Mesh2_face_edges'].encoding['_FillValue'] = 88

with pytest.warns(ConventionViolationWarning):
assert dataset_fill_value_in_range_on_upper_boundary.ems.topology.has_valid_face_edge_connectivity is not True

dataset_fill_value_above_range['Mesh2_face_edges'].encoding['_FillValue'] = 89

assert dataset_fill_value_above_range.ems.topology.has_valid_face_edge_connectivity is True
Loading