diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst
index b44e740724..ea4b52ce2a 100644
--- a/docs/src/whatsnew/latest.rst
+++ b/docs/src/whatsnew/latest.rst
@@ -38,6 +38,15 @@ This document explains the changes made to Iris for this release
#. `@trexfeathers`_ and `Julian Heming`_ added new mappings between CF
standard names and UK Met Office LBFC codes. (:pull:`4859`)
+#. `@pp-mo`_ changed the metadata of a face/edge-type
+ :class:`~iris.experimental.ugrid.mesh.MeshCoord`, to be same as the face/edge
+ coordinate in the mesh from which it takes its ``.points``. Previously, all MeshCoords
+ took their metadata from the node coord, but only a node-type MeshCoord now does
+ that. Also, the MeshCoord ``.var_name`` is now that of the underlying coord, whereas
+ previously this was always None. These changes make MeshCoord more like an ordinary
+ :class:`~iris.coords.AuxCoord`, which avoids some specific known usage problems.
+ (:issue:`4860`, :pull:`5020`)
+
🐛 Bugs Fixed
=============
diff --git a/lib/iris/experimental/ugrid/mesh.py b/lib/iris/experimental/ugrid/mesh.py
index 974a563046..4fd09175af 100644
--- a/lib/iris/experimental/ugrid/mesh.py
+++ b/lib/iris/experimental/ugrid/mesh.py
@@ -2841,16 +2841,60 @@ def __init__(
# Get the 'coord identity' metadata from the relevant node-coordinate.
node_coord = self.mesh.coord(include_nodes=True, axis=self.axis)
+ node_metadict = node_coord.metadata._asdict()
+ # Use node metadata, unless location is face/edge.
+ use_metadict = node_metadict.copy()
+ if location != "node":
+ # Location is either "edge" or "face" - get the relevant coord.
+ kwargs = {f"include_{location}s": True, "axis": axis}
+ location_coord = self.mesh.coord(**kwargs)
+
+ # Take the MeshCoord metadata from the 'location' coord.
+ use_metadict = location_coord.metadata._asdict()
+ unit_unknown = Unit(None)
+
+ # N.B. at present, coords in a Mesh are stored+accessed by 'axis', which
+ # means they must have a standard_name. So ...
+ # (a) the 'location' (face/edge) coord *always* has a useable phenomenon
+ # identity.
+ # (b) we still want to check that location+node coords have the same
+ # phenomenon (i.e. physical meaning identity + units), **but** ...
+ # (c) we will accept/ignore some differences : not just "var_name", but
+ # also "long_name" *and* "attributes". So it is *only* "standard_name"
+ # and "units" that cause an error if they differ.
+ for key in ("standard_name", "units"):
+ bounds_value = use_metadict[key]
+ nodes_value = node_metadict[key]
+ if key == "units" and (
+ bounds_value == unit_unknown or nodes_value == unit_unknown
+ ):
+ # Allow "any" unit to match no-units (for now)
+ continue
+ if bounds_value != nodes_value:
+
+ def fix_repr(val):
+ # Tidy values appearance by converting Unit to string, and
+ # wrapping strings in '', but leaving other types as a
+ # plain str() representation.
+ if isinstance(val, Unit):
+ val = str(val)
+ if isinstance(val, str):
+ val = repr(val)
+ return val
+
+ nodes_value, bounds_value = [
+ fix_repr(val) for val in (nodes_value, bounds_value)
+ ]
+ msg = (
+ f"Node coordinate {node_coord!r} disagrees with the "
+ f"{location} coordinate {location_coord!r}, "
+ f'in having a "{key}" value of {nodes_value} '
+ f"instead of {bounds_value}."
+ )
+ raise ValueError(msg)
+
# Call parent constructor to handle the common constructor args.
- super().__init__(
- points,
- bounds=bounds,
- standard_name=node_coord.standard_name,
- long_name=node_coord.long_name,
- var_name=None, # We *don't* "represent" the underlying node var
- units=node_coord.units,
- attributes=node_coord.attributes,
- )
+ super().__init__(points, bounds=bounds, **use_metadict)
# Define accessors for MeshCoord-specific properties mesh/location/axis.
# These are all read-only.
diff --git a/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml b/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml
index b863adcf55..7422bfe044 100644
--- a/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml
@@ -20,8 +20,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml b/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml
index b46908a648..f9e0511ccb 100644
--- a/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml
@@ -20,8 +20,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_full_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_full_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml
index c260587921..9a819eee9e 100644
--- a/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml
@@ -31,8 +31,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml
index e545e05fdc..9133d98e73 100644
--- a/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml
@@ -20,8 +20,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml
index 4eedfc21b3..05aeab9ccb 100644
--- a/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml
@@ -20,8 +20,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml
index 55155047bb..9dc3e08ee6 100644
--- a/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml
@@ -20,8 +20,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml
index fc52fce0b3..7bb47c5296 100644
--- a/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml
+++ b/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml
@@ -20,8 +20,8 @@
...,
[-42.7342, -40.8934, -46.161, -48.912],
[-40.8934, -38.4268, -42.6612, -46.161],
- [-38.4268, -35.2644, -38.4268, -42.6612]]" id="21594c35" long_name="Latitude of mesh nodes." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
- -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-38.4268, -35.2644, -38.4268, -42.6612]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[33.4328, 36.1226, 38.2012, ..., -44.791,
+ -42.1583, -38.815]" shape="(864,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [-127.5, -135.0, -142.5, -135.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[-41.3152, -33.8068, -26.296, ..., -119.377,
+ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/experimental/ugrid/surface_mean.cml b/lib/iris/tests/results/experimental/ugrid/surface_mean.cml
index 368b3508e3..8ccd602c11 100644
--- a/lib/iris/tests/results/experimental/ugrid/surface_mean.cml
+++ b/lib/iris/tests/results/experimental/ugrid/surface_mean.cml
@@ -20,8 +20,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -71,8 +71,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -122,8 +122,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -173,8 +173,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -224,8 +224,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -275,8 +275,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -326,8 +326,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -377,8 +377,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -428,8 +428,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -479,8 +479,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -530,8 +530,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -581,8 +581,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -632,8 +632,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -683,8 +683,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -734,8 +734,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -785,8 +785,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -836,8 +836,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
@@ -887,8 +887,8 @@
...,
[-37.7044, -36.9373, -37.9318, -38.7655],
[-36.9373, -36.1244, -37.0517, -37.9318],
- [-36.1244, -35.2644, -36.1244, -37.0517]]" id="21594c35" long_name="Latitude of mesh nodes." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
- -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32"/>
+ [-36.1244, -35.2644, -36.1244, -37.0517]]" id="72da1058" long_name="Characteristic latitude of mesh faces." points="[34.8187, 35.6462, 36.4283, ..., -37.8421,
+ -37.0187, -36.1485]" shape="(13824,)" standard_name="latitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_y"/>
+ [226.875, 225.0, 223.125, 225.0]]" id="b5c6bdeb" long_name="Characteristic longitude of mesh faces." points="[315.933, 317.808, 319.683, ..., 228.759,
+ 226.878, 225.0]" shape="(13824,)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="Mesh2d_half_levels_face_x"/>
diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml
index 9fc80a0e4d..e318abad67 100644
--- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml
+++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml
@@ -50,12 +50,7 @@
-
-
-
-
-
-
+
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
-
-
-
-
-
+ [1196, 1197, 1198, 1199]]" id="e0db29d6" points="[3100, 3101, 3102, ..., 3197, 3198, 3199]" shape="(100,)" standard_name="longitude" units="Unit('unknown')" value_type="int64"/>
"
),
- "MeshCoord : longitude / (degrees_east)",
+ "MeshCoord : longitude / (unknown)",
" mesh: ",
" location: 'face'",
" points: [3100, 3101, 3102]",
@@ -926,10 +926,6 @@ def test_meshcoord(self):
" shape: (3,) bounds(3, 4)",
" dtype: int64",
" standard_name: 'longitude'",
- " long_name: 'long-name'",
- " attributes:",
- " a 1",
- " b 'c'",
" axis: 'x'",
]
self.assertLines(expected, result)
diff --git a/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py b/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py
index ce99a8b4be..538cecdc7d 100644
--- a/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py
+++ b/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py
@@ -16,9 +16,10 @@
import dask.array as da
import numpy as np
+import pytest
from iris._lazy_data import as_lazy_data, is_lazy_data
-from iris.common.metadata import BaseMetadata
+from iris.common.metadata import BaseMetadata, CoordMetadata
from iris.coords import AuxCoord, Coord
from iris.cube import Cube
from iris.experimental.ugrid.mesh import Connectivity, Mesh, MeshCoord
@@ -45,16 +46,11 @@ def test_derived_properties(self):
# underlying mesh coordinate.
for axis in Mesh.AXES:
meshcoord = sample_meshcoord(axis=axis)
- # N.B.
- node_x_coord = meshcoord.mesh.coord(include_nodes=True, axis=axis)
- for key in node_x_coord.metadata._fields:
+ face_x_coord = meshcoord.mesh.coord(include_faces=True, axis=axis)
+ for key in face_x_coord.metadata._fields:
meshval = getattr(meshcoord, key)
- if key == "var_name":
- # var_name is unused.
- self.assertIsNone(meshval)
- else:
- # names, units and attributes are derived from the node coord.
- self.assertEqual(meshval, getattr(node_x_coord, key))
+ # All relevant attributes are derived from the face coord.
+ self.assertEqual(meshval, getattr(face_x_coord, key))
def test_fail_bad_mesh(self):
with self.assertRaisesRegex(TypeError, "must be a.*Mesh"):
@@ -270,10 +266,11 @@ def setUp(self):
def _expected_elements_regexp(
self,
standard_name="longitude",
- long_name="long-name",
- attributes=True,
+ long_name=None,
+ attributes=False,
location="face",
axis="x",
+ var_name=None,
):
# Printed name is standard or long -- we don't have a case with neither
coord_name = standard_name or long_name
@@ -282,24 +279,30 @@ def _expected_elements_regexp(
regexp = f"MeshCoord : {coord_name} / [^\n]+\n *"
regexp += r"mesh: \\n *"
regexp += f"location: '{location}'\n *"
+
# Now some optional sections : whichever comes first will match
# arbitrary content leading up to it.
- matched_any_upto = False
- if standard_name:
- regexp += ".*"
- matched_any_upto = True
- regexp += f"standard_name: '{standard_name}'\n *"
- if long_name:
+ matched_upto = False
+
+ def upto_first_expected(regexp, matched_any_upto):
if not matched_any_upto:
regexp += ".*"
matched_any_upto = True
+ return regexp, matched_any_upto
+
+ if standard_name:
+ regexp, matched_upto = upto_first_expected(regexp, matched_upto)
+ regexp += f"standard_name: '{standard_name}'\n *"
+ if long_name:
+ regexp, matched_upto = upto_first_expected(regexp, matched_upto)
regexp += f"long_name: '{long_name}'\n *"
+ if var_name:
+ regexp, matched_upto = upto_first_expected(regexp, matched_upto)
+ regexp += f"var_name: '{var_name}'\n *"
if attributes:
# if we expected attributes, they should come next
# TODO: change this when each attribute goes on a new line
- if not matched_any_upto:
- regexp += ".*"
- matched_any_upto = True
+ regexp, matched_upto = upto_first_expected(regexp, matched_upto)
# match 'attributes:' followed by N*lines with larger indent
regexp += "attributes:(\n [^ \n]+ +[^ \n]+)+\n "
# After those items, expect 'axis' next
@@ -314,7 +317,7 @@ def test_repr(self):
# A simple check for the condensed form.
result = repr(self.meshcoord)
expected = (
- ""
)
self.assertEqual(expected, result)
@@ -331,7 +334,7 @@ def test_repr_lazy(self):
self.assertTrue(self.meshcoord.has_lazy_bounds())
expected = (
- "+bounds shape(3,)>"
)
self.assertEqual(expected, result)
@@ -342,7 +345,7 @@ def test_repr__nameless_mesh(self):
assert self.mesh.name() == "unknown"
result = repr(self.meshcoord)
re_expected = (
- r".MeshCoord: longitude / \(degrees_east\) "
+ r".MeshCoord: longitude / \(unknown\) "
r"mesh\(.Mesh object at 0x[^>]+.\) location\(face\) "
)
self.assertRegex(result, re_expected)
@@ -392,18 +395,6 @@ def test_str_no_long_name(self):
re_expected = self._expected_elements_regexp(long_name=False)
self.assertRegex(result, re_expected)
- def test_str_no_standard_name(self):
- mesh = self.mesh
- # Remove the standard_name of the node coord in the mesh.
- node_coord = mesh.coord(include_nodes=True, axis="x")
- node_coord.standard_name = None
- node_coord.axis = "x" # This is required : but it's a kludge !!
- # Make a new meshcoord, based on the modified mesh.
- meshcoord = sample_meshcoord(mesh=self.mesh)
- result = str(meshcoord)
- re_expected = self._expected_elements_regexp(standard_name=False)
- self.assertRegex(result, re_expected)
-
def test_str_no_attributes(self):
mesh = self.mesh
# No attributes on the node coord in the mesh.
@@ -451,9 +442,11 @@ def test_cube_dims(self):
def test_find_by_name(self):
meshcoord = self.meshcoord
+ # hack to give it a long name
+ meshcoord.long_name = "odd_case"
cube = self.cube
self.assertIs(cube.coord(standard_name="longitude"), meshcoord)
- self.assertIs(cube.coord(long_name="long-name"), meshcoord)
+ self.assertIs(cube.coord(long_name="odd_case"), meshcoord)
def test_find_by_axis(self):
meshcoord = self.meshcoord
@@ -796,5 +789,157 @@ def test_bounds_badvalues__lazy(self):
self._check_bounds_bad_index_values(lazy=True)
+class Test__metadata:
+ def setup_mesh(self, location, axis):
+ # Create a standard test mesh + attach it to the test instance.
+ mesh = sample_mesh()
+
+ # Modify the metadata of specific coordinates used in this test.
+ def select_coord(location, axis):
+ kwargs = {f"include_{location}s": True, "axis": axis}
+ return mesh.coord(**kwargs)
+
+ node_coord = select_coord("node", axis)
+ location_coord = select_coord(location, axis)
+ for i_place, coord in enumerate((node_coord, location_coord)):
+ coord.standard_name = "longitude" if axis == "x" else "latitude"
+ coord.units = "degrees"
+ coord.long_name = f"long_name_{i_place}"
+ coord.var_name = f"var_name_{i_place}"
+ coord.attributes = {"att": i_place}
+
+ # attach all the relevant testcase context to the test instance.
+ self.mesh = mesh
+ self.location = location
+ self.axis = axis
+ self.location_coord = location_coord
+ self.node_coord = node_coord
+
+ def coord_metadata_matches(self, test_coord, ref_coord):
+ # Check that two coords match, in all the basic Coord identity/phenomenon
+ # metadata fields -- so it works even between coords of different subclasses.
+ for key in CoordMetadata._fields:
+ assert getattr(test_coord, key) == getattr(ref_coord, key)
+
+ @pytest.fixture(params=["face", "edge"])
+ def location_face_or_edge(self, request):
+ # Fixture to parametrise over location = face/edge
+ return request.param
+
+ @pytest.fixture(params=["x", "y"])
+ def axis_x_or_y(self, request):
+ # Fixture to parametrise over axis = X/Y
+ return request.param
+
+ def test_node_meshcoord(self, axis_x_or_y):
+ # MeshCoord metadata matches that of the relevant node coord.
+ self.setup_mesh(location="node", axis=axis_x_or_y)
+ meshcoord = self.mesh.to_MeshCoord(
+ location=self.location, axis=self.axis
+ )
+ self.coord_metadata_matches(meshcoord, self.node_coord)
+
+ def test_faceedge_basic(self, location_face_or_edge, axis_x_or_y):
+ # MeshCoord metadata matches that of the face/edge ("points") coord.
+ self.setup_mesh(location_face_or_edge, axis_x_or_y)
+ meshcoord = self.mesh.to_MeshCoord(
+ location=self.location, axis=self.axis
+ )
+ self.coord_metadata_matches(meshcoord, self.location_coord)
+
+ @pytest.mark.parametrize(
+ "fieldname", ["long_name", "var_name", "attributes"]
+ )
+ def test_faceedge_dontcare_fields(
+ self, location_face_or_edge, axis_x_or_y, fieldname
+ ):
+ # Check that it's ok for the face/edge and node coords to have different
+ # long-name, var-name or attributes.
+ self.setup_mesh(location_face_or_edge, axis_x_or_y)
+ if fieldname == "attributes":
+ different_value = {"myattrib": "different attributes"}
+ else:
+ # others are just arbitrary strings.
+ different_value = "different"
+ setattr(self.location_coord, fieldname, different_value)
+ # Mostly.. just check this does not cause an error, as it would do if we
+ # modified "standard_name" or "units" (see other tests) ...
+ meshcoord = self.mesh.to_MeshCoord(
+ location=self.location, axis=self.axis
+ )
+ # ... but also, check that the result matches the expected face/edge coord.
+ self.coord_metadata_matches(meshcoord, self.location_coord)
+
+ def test_faceedge_fail_mismatched_stdnames(
+ self, location_face_or_edge, axis_x_or_y
+ ):
+ # Different "standard_name" for node and face/edge causes an error.
+ self.setup_mesh(location_face_or_edge, axis_x_or_y)
+ node_name = f"projection_{axis_x_or_y}_coordinate"
+ self.node_coord.standard_name = node_name
+ location_name = "longitude" if axis_x_or_y == "x" else "latitude"
+ msg = (
+ "Node coordinate .*"
+ f"disagrees with the {location_face_or_edge} coordinate .*, "
+ 'in having a "standard_name" value of '
+ f"'{node_name}' instead of '{location_name}'"
+ )
+ with pytest.raises(ValueError, match=msg):
+ self.mesh.to_MeshCoord(
+ location=location_face_or_edge, axis=axis_x_or_y
+ )
+
+ def test_faceedge_fail_missing_stdnames(
+ self, location_face_or_edge, axis_x_or_y
+ ):
+ # "standard_name" compared with None also causes an error.
+ self.setup_mesh(location_face_or_edge, axis_x_or_y)
+ self.node_coord.standard_name = None
+ # N.B. in the absence of a standard-name, we **must** provide an extra ".axis"
+ # property, or the coordinate cannot be correctly identified in the Mesh.
+ # This is a bit of a kludge, but works with current code.
+ self.node_coord.axis = axis_x_or_y
+
+ location_name = "longitude" if axis_x_or_y == "x" else "latitude"
+ msg = (
+ "Node coordinate .*"
+ f"disagrees with the {location_face_or_edge} coordinate .*, "
+ 'in having a "standard_name" value of '
+ f"None instead of '{location_name}'"
+ )
+ with pytest.raises(ValueError, match=msg):
+ self.mesh.to_MeshCoord(
+ location=location_face_or_edge, axis=axis_x_or_y
+ )
+
+ def test_faceedge_fail_mismatched_units(
+ self, location_face_or_edge, axis_x_or_y
+ ):
+ # Different "units" for node and face/edge causes an error.
+ self.setup_mesh(location_face_or_edge, axis_x_or_y)
+ self.node_coord.units = "hPa"
+ msg = (
+ "Node coordinate .*"
+ f"disagrees with the {location_face_or_edge} coordinate .*, "
+ 'in having a "units" value of '
+ "'hPa' instead of 'degrees'"
+ )
+ with pytest.raises(ValueError, match=msg):
+ self.mesh.to_MeshCoord(
+ location=location_face_or_edge, axis=axis_x_or_y
+ )
+
+ def test_faceedge_missing_units(self, location_face_or_edge, axis_x_or_y):
+ # Units compared with a None ("unknown") is not an error.
+ self.setup_mesh(location_face_or_edge, axis_x_or_y)
+ self.node_coord.units = None
+ # This is OK
+ meshcoord = self.mesh.to_MeshCoord(
+ location=self.location, axis=self.axis
+ )
+ # ... but also, check that the result matches the expected face/edge coord.
+ self.coord_metadata_matches(meshcoord, self.location_coord)
+
+
if __name__ == "__main__":
tests.main()