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
99 changes: 67 additions & 32 deletions lib/iris/tests/stock/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,57 +22,90 @@
_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:
n_faces = _TEST_N_FACES
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

Expand All @@ -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).
Expand All @@ -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):
Expand All @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion lib/iris/tests/unit/cube/test_Cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down