Skip to content

Commit cedcda4

Browse files
committed
Support+test connectivities with missing points.
1 parent 7a7eed7 commit cedcda4

File tree

2 files changed

+67
-8
lines changed

2 files changed

+67
-8
lines changed

lib/iris/fileformats/netcdf.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,11 +1465,6 @@ def _add_mesh(self, cube):
14651465
_setncattr(cf_conn_var, "cf_role", cf_conn_attr_name)
14661466
_setncattr(cf_conn_var, "start_index", conn.start_index)
14671467

1468-
# If content was masked, also add a "_FillValue" property.
1469-
# N.B. for now at least, use -1 as a universal 'safe' value.
1470-
if np.ma.is_masked(conn.indices):
1471-
_setncattr(cf_mesh_var, "_FillValue", -1)
1472-
14731468
# Record the connectivity on the parent mesh var.
14741469
_setncattr(cf_mesh_var, cf_conn_attr_name, cf_conn_name)
14751470
# If the connectivity had the 'alternate' dimension order, add the
@@ -2274,8 +2269,12 @@ def _create_generic_cf_array_var(
22742269
data = self._ensure_valid_dtype(data, element_type, element)
22752270

22762271
if fill_value is not None:
2277-
# Use a specific fill-value in place of the netcdf default.
2278-
data = np.ma.filled(data, fill_value)
2272+
if np.ma.is_masked(data):
2273+
# Use a specific fill-value in place of the netcdf default.
2274+
data = np.ma.filled(data, fill_value)
2275+
else:
2276+
# Create variable without a (non-standard) fill_value
2277+
fill_value = None
22792278

22802279
# Check if this is a dim-coord.
22812280
is_dimcoord = element in cube.dim_coords
@@ -2298,7 +2297,10 @@ def _create_generic_cf_array_var(
22982297

22992298
# Create the CF-netCDF variable.
23002299
cf_var = self._dataset.createVariable(
2301-
cf_name, data.dtype.newbyteorder("="), element_dims
2300+
cf_name,
2301+
data.dtype.newbyteorder("="),
2302+
element_dims,
2303+
fill_value=fill_value,
23022304
)
23032305

23042306
# Add the axis attribute for spatio-temporal CF-netCDF coordinates.

lib/iris/tests/unit/fileformats/netcdf/test_Saver__ugrid.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,63 @@ def test_alternate_connectivity_dim_order(self):
636636
self.assertEqual(mesh_props["face_dimension"], "Mesh2d_face")
637637
self.assertEqual(mesh_props["edge_dimension"], "Mesh2d_edge")
638638

639+
def test_nonuniform_connectivity(self):
640+
# Check handling of connecitivities with missing points.
641+
n_faces = 7
642+
mesh = make_mesh(n_faces=n_faces)
643+
644+
# In this case, add on a partial face-face connectivity.
645+
# construct a vaguely plausible face-face index array
646+
indices = np.ma.arange(n_faces * 4).reshape((7, 4))
647+
indices = indices % 7
648+
# include some missing points -- i.e. not all faces have 4 neighbours
649+
indices[(2, (2, 3))] = np.ma.masked
650+
indices[(3, (0, 2))] = np.ma.masked
651+
indices[6, :] = np.ma.masked
652+
653+
conn = Connectivity(
654+
indices,
655+
cf_role="face_face_connectivity",
656+
)
657+
mesh.add_connectivities(conn)
658+
cube = make_cube(mesh=mesh)
659+
660+
# Save and snapshot the result
661+
dims, vars = self.check_save(cube)
662+
663+
# Check that the mesh saved with the additional connectivity
664+
(mesh_name,) = vars_meshnames(vars)
665+
mesh_props = vars[mesh_name]
666+
self.assertIn("face_face_connectivity", mesh_props)
667+
ff_conn_name = mesh_props["face_face_connectivity"]
668+
669+
# check that the connectivity has the corrects dims and fill-property
670+
ff_props = vars[ff_conn_name]
671+
self.assertEqual(
672+
ff_props["_DIMS"], ["Mesh2d_faces", "Mesh2d_face_N_faces"]
673+
)
674+
self.assertIn("_FillValue", ff_props)
675+
self.assertEqual(ff_props["_FillValue"], -1)
676+
677+
# Check that a 'normal' connectivity does *not* have a _FillValue
678+
fn_conn_name = mesh_props["face_node_connectivity"]
679+
fn_props = vars[fn_conn_name]
680+
self.assertNotIn("_FillValue", fn_props)
681+
682+
# For what it's worth, *also* check the actual data array in the file
683+
ds = nc.Dataset(self.tempfile_path)
684+
try:
685+
conn_var = ds.variables[ff_conn_name]
686+
data = conn_var[:]
687+
finally:
688+
ds.close()
689+
self.assertIsInstance(data, np.ma.MaskedArray)
690+
self.assertEqual(data.fill_value, -1)
691+
# Compare raw values stored, to indices with -1 at missing points
692+
raw_data = data.data
693+
filled_indices = indices.filled(-1)
694+
self.assertArrayEqual(raw_data, filled_indices)
695+
639696

640697
if __name__ == "__main__":
641698
tests.main()

0 commit comments

Comments
 (0)