diff --git a/lib/iris/tests/stock/mesh.py b/lib/iris/tests/stock/mesh.py index 160db79f63..ca15ee1c97 100644 --- a/lib/iris/tests/stock/mesh.py +++ b/lib/iris/tests/stock/mesh.py @@ -22,13 +22,33 @@ _TEST_N_BOUNDS = 4 -def sample_mesh(n_nodes=None, n_faces=None, n_edges=None): +def sample_mesh(n_nodes=None, n_faces=None, n_edges=None, lazy_values=False): """ Make a test mesh. - Mesh has faces edges, face-coords and edge-coords, numbers of which can be controlled. + Mesh has nodes, plus faces and/or edges, with face-coords and edge-coords, + numbers of which can be controlled. + + Args: + * n_nodes (int or None): + Number of nodes in mesh. Default is 15. Cannot be 0. + * n_edges (int or None): + Number of edges in mesh. Default is 5. + If not 0, edge coords and an 'edge_node_connectivity' are included. + * n_faces (int or None): + Number of faces in mesh. Default is 3. + If not 0, face coords and a 'face_node_connectivity' are included. + * lazy_values (bool): + If True, all content values of coords and connectivities are lazy. """ + if lazy_values: + import dask.array as da + + arr = da + else: + arr = np + if n_nodes is None: n_nodes = _TEST_N_NODES if n_faces is None: @@ -36,43 +56,56 @@ def sample_mesh(n_nodes=None, n_faces=None, n_edges=None): if n_edges is None: n_edges = _TEST_N_EDGES node_x = AuxCoord( - 1100 + np.arange(n_nodes), + 1100 + arr.arange(n_nodes), standard_name="longitude", units="degrees_east", long_name="long-name", var_name="var-name", attributes={"a": 1, "b": "c"}, ) - node_y = AuxCoord(1200 + np.arange(n_nodes), standard_name="latitude") - - # Define a rather arbitrary edge-nodes connectivity. - # Some nodes are left out, because n_edges*2 < n_nodes. - conns = np.arange(n_edges * 2, dtype=int) - # Missing nodes include #0-5, because we add 5. - conns = ((conns + 5) % n_nodes).reshape((n_edges, 2)) - edge_nodes = Connectivity(conns, cf_role="edge_node_connectivity") - conns = np.arange(n_edges * 2, dtype=int) - - # Some numbers for the edge coordinates. - edge_x = AuxCoord(2100 + np.arange(n_edges), standard_name="longitude") - edge_y = AuxCoord(2200 + np.arange(n_edges), standard_name="latitude") - - # Define a rather arbitrary face-nodes connectivity. - # Some nodes are left out, because n_faces*n_bounds < n_nodes. - conns = np.arange(n_faces * _TEST_N_BOUNDS, dtype=int) - conns = (conns % n_nodes).reshape((n_faces, _TEST_N_BOUNDS)) - face_nodes = Connectivity(conns, cf_role="face_node_connectivity") - - # Some numbers for the edge coordinates. - face_x = AuxCoord(3100 + np.arange(n_faces), standard_name="longitude") - face_y = AuxCoord(3200 + np.arange(n_faces), standard_name="latitude") + node_y = AuxCoord(1200 + arr.arange(n_nodes), standard_name="latitude") + + connectivities = [] + if n_edges == 0: + edge_coords_and_axes = None + else: + # Define a rather arbitrary edge-nodes connectivity. + # Some nodes are left out, because n_edges*2 < n_nodes. + conns = arr.arange(n_edges * 2, dtype=int) + # Missing nodes include #0-5, because we add 5. + conns = ((conns + 5) % n_nodes).reshape((n_edges, 2)) + edge_nodes = Connectivity(conns, cf_role="edge_node_connectivity") + connectivities.append(edge_nodes) + + edge_x = AuxCoord( + 2100 + arr.arange(n_edges), standard_name="longitude" + ) + edge_y = AuxCoord(2200 + arr.arange(n_edges), standard_name="latitude") + edge_coords_and_axes = [(edge_x, "x"), (edge_y, "y")] + + if n_faces == 0: + face_coords_and_axes = None + else: + # Define a rather arbitrary face-nodes connectivity. + # Some nodes are left out, because n_faces*n_bounds < n_nodes. + conns = arr.arange(n_faces * _TEST_N_BOUNDS, dtype=int) + conns = (conns % n_nodes).reshape((n_faces, _TEST_N_BOUNDS)) + face_nodes = Connectivity(conns, cf_role="face_node_connectivity") + connectivities.append(face_nodes) + + # Some numbers for the edge coordinates. + face_x = AuxCoord( + 3100 + arr.arange(n_faces), standard_name="longitude" + ) + face_y = AuxCoord(3200 + arr.arange(n_faces), standard_name="latitude") + face_coords_and_axes = [(face_x, "x"), (face_y, "y")] mesh = Mesh( topology_dimension=2, node_coords_and_axes=[(node_x, "x"), (node_y, "y")], - connectivities=[face_nodes, edge_nodes], - edge_coords_and_axes=[(edge_x, "x"), (edge_y, "y")], - face_coords_and_axes=[(face_x, "x"), (face_y, "y")], + connectivities=connectivities, + edge_coords_and_axes=edge_coords_and_axes, + face_coords_and_axes=face_coords_and_axes, ) return mesh @@ -92,7 +125,7 @@ def sample_meshcoord(mesh=None, location="face", axis="x", **extra_kwargs): def sample_mesh_cube( - nomesh=False, n_z=2, with_parts=False, **meshcoord_kwargs + nomesh_faces=None, n_z=2, with_parts=False, **meshcoord_kwargs ): """ Create a 2d test cube with 1 'normal' and 1 unstructured dimension (with a Mesh). @@ -101,8 +134,9 @@ def sample_mesh_cube( By default, the mesh is provided by :func:`sample_mesh`, so coordinates and connectivity are not realistic. Kwargs: - * nomesh(bool): + * nomesh_faces (int or None): If set, don't add MeshCoords, so dim 1 is just a plain anonymous dim. + Set its length to the given value. * n_z (int): Length of the 'normal' dim. If 0, it is *omitted*. * with_parts (bool): @@ -117,9 +151,10 @@ def sample_mesh_cube( 'parts' is (mesh, dim0-dimcoord, dim1-dimcoord, dim1-auxcoord, x-meshcoord [or None], y-meshcoord [or None]). """ + nomesh = nomesh_faces is not None if nomesh: mesh = None - n_faces = 5 + n_faces = nomesh_faces else: mesh = meshcoord_kwargs.pop("mesh", None) if mesh is None: diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index 50125ae398..ac24785bbe 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -2062,8 +2062,9 @@ def _add_test_meshcube(self, nomesh=False, n_z=2, **meshcoord_kwargs): its components as properties of the 'self' TestCase. """ + nomesh_faces = 5 if nomesh else None cube, parts = sample_mesh_cube( - nomesh=nomesh, n_z=n_z, with_parts=True, **meshcoord_kwargs + nomesh_faces=nomesh_faces, n_z=n_z, with_parts=True, **meshcoord_kwargs ) mesh, zco, mesh_dimco, auxco_x, meshx, meshy = parts self.mesh = mesh