diff --git a/.github/workflows/ci-manifest.yml b/.github/workflows/ci-manifest.yml index 40c7bf74de..8e6bfa4d33 100644 --- a/.github/workflows/ci-manifest.yml +++ b/.github/workflows/ci-manifest.yml @@ -23,4 +23,4 @@ concurrency: jobs: manifest: name: "check-manifest" - uses: scitools/workflows/.github/workflows/ci-manifest.yml@2024.07.2 + uses: scitools/workflows/.github/workflows/ci-manifest.yml@2024.07.3 diff --git a/.github/workflows/refresh-lockfiles.yml b/.github/workflows/refresh-lockfiles.yml index b3e60d4256..ffca6c6eb7 100644 --- a/.github/workflows/refresh-lockfiles.yml +++ b/.github/workflows/refresh-lockfiles.yml @@ -14,5 +14,5 @@ on: jobs: refresh_lockfiles: - uses: scitools/workflows/.github/workflows/refresh-lockfiles.yml@2024.07.2 + uses: scitools/workflows/.github/workflows/refresh-lockfiles.yml@2024.07.3 secrets: inherit diff --git a/benchmarks/benchmarks/sperf/equality.py b/benchmarks/benchmarks/sperf/equality.py index 3f70c6fd7f..f67935c9ef 100644 --- a/benchmarks/benchmarks/sperf/equality.py +++ b/benchmarks/benchmarks/sperf/equality.py @@ -13,7 +13,7 @@ class CubeEquality(FileMixin): r"""Benchmark time and memory costs. Benchmark time and memory costs of comparing :class:`~iris.cube.Cube`\\ s - with attached :class:`~iris.experimental.ugrid.mesh.Mesh`\\ es. + with attached :class:`~iris.experimental.ugrid.mesh.MeshXY`\\ es. Uses :class:`FileMixin` as the realistic case will be comparing :class:`~iris.cube.Cube`\\ s that have been loaded from file. diff --git a/benchmarks/benchmarks/unit_style/ugrid.py b/benchmarks/benchmarks/unit_style/ugrid.py index 0890b47e6d..e2f235eb28 100644 --- a/benchmarks/benchmarks/unit_style/ugrid.py +++ b/benchmarks/benchmarks/unit_style/ugrid.py @@ -80,7 +80,7 @@ def setup(self, n_faces): self.object = self.create() -class Mesh(UGridCommon): +class MeshXY(UGridCommon): def setup(self, n_faces, lazy=False): #### # Steal everything from the sample mesh for benchmarking creation of a @@ -123,7 +123,7 @@ def get_coords_and_axes(location): self.eq_object = deepcopy(self.object) def create(self): - return ugrid.Mesh(**self.mesh_kwargs) + return ugrid.MeshXY(**self.mesh_kwargs) def time_add_connectivities(self, n_faces): self.object.add_connectivities(self.face_node) @@ -148,8 +148,8 @@ def time_remove_coords(self, n_faces): @disable_repeat_between_setup -class MeshLazy(Mesh): - """Lazy equivalent of :class:`Mesh`.""" +class MeshXYLazy(MeshXY): + """Lazy equivalent of :class:`MeshXY`.""" def setup(self, n_faces, lazy=True): super().setup(n_faces, lazy=lazy) diff --git a/docs/src/further_topics/ugrid/data_model.rst b/docs/src/further_topics/ugrid/data_model.rst index cad461340d..d7282c71d8 100644 --- a/docs/src/further_topics/ugrid/data_model.rst +++ b/docs/src/further_topics/ugrid/data_model.rst @@ -310,7 +310,7 @@ The Basics The Iris :class:`~iris.cube.Cube` has several new members: * | :attr:`~iris.cube.Cube.mesh` - | The :class:`iris.experimental.ugrid.Mesh` that describes the + | The :class:`iris.experimental.ugrid.MeshXY` that describes the :class:`~iris.cube.Cube`\'s horizontal geography. * | :attr:`~iris.cube.Cube.location` | ``node``/``edge``/``face`` - the mesh element type with which this @@ -320,7 +320,7 @@ The Iris :class:`~iris.cube.Cube` has several new members: indexes over the horizontal :attr:`~iris.cube.Cube.data` positions. These members will all be ``None`` for a :class:`~iris.cube.Cube` with no -associated :class:`~iris.experimental.ugrid.Mesh`. +associated :class:`~iris.experimental.ugrid.MeshXY`. This :class:`~iris.cube.Cube`\'s unstructured dimension has multiple attached :class:`iris.experimental.ugrid.MeshCoord`\s (one for each axis e.g. @@ -333,7 +333,7 @@ the :class:`~iris.cube.Cube`\'s unstructured dimension. from iris.coords import AuxCoord, DimCoord from iris.cube import Cube - from iris.experimental.ugrid import Connectivity, Mesh + from iris.experimental.ugrid import Connectivity, MeshXY node_x = AuxCoord( points=[0.0, 5.0, 0.0, 5.0, 8.0], @@ -368,7 +368,7 @@ the :class:`~iris.cube.Cube`\'s unstructured dimension. ] return [(x, "x"), (y, "y")] - my_mesh = Mesh( + my_mesh = MeshXY( long_name="my_mesh", topology_dimension=2, node_coords_and_axes=[(node_x, "x"), (node_y, "y")], @@ -416,41 +416,41 @@ the :class:`~iris.cube.Cube`\'s unstructured dimension. 0 >>> print(edge_cube.mesh.summary(shorten=True)) - + The Detail ---------- How UGRID information is stored ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* | :class:`iris.experimental.ugrid.Mesh` +* | :class:`iris.experimental.ugrid.MeshXY` | Contains all information about the mesh. | Includes: - * | :attr:`~iris.experimental.ugrid.Mesh.topology_dimension` + * | :attr:`~iris.experimental.ugrid.MeshXY.topology_dimension` | The maximum dimensionality of shape (1D=edge, 2D=face) supported - by this :class:`~iris.experimental.ugrid.Mesh`. Determines which + by this :class:`~iris.experimental.ugrid.MeshXY`. Determines which :class:`~iris.experimental.ugrid.Connectivity`\s are required/optional (see below). * 1-3 collections of :class:`iris.coords.AuxCoord`\s: - * | **Required**: :attr:`~iris.experimental.ugrid.Mesh.node_coords` + * | **Required**: :attr:`~iris.experimental.ugrid.MeshXY.node_coords` | The nodes that are the basis for the mesh. - * | Optional: :attr:`~iris.experimental.ugrid.Mesh.edge_coords`, - :attr:`~iris.experimental.ugrid.Mesh.face_coords` + * | Optional: :attr:`~iris.experimental.ugrid.MeshXY.edge_coords`, + :attr:`~iris.experimental.ugrid.MeshXY.face_coords` | For indicating the 'centres' of the edges/faces. | **NOTE:** generating a :class:`~iris.experimental.ugrid.MeshCoord` from - a :class:`~iris.experimental.ugrid.Mesh` currently (``Jan 2022``) + a :class:`~iris.experimental.ugrid.MeshXY` currently (``Jan 2022``) requires centre coordinates for the given ``location``; to be rectified in future. * 1 or more :class:`iris.experimental.ugrid.Connectivity`\s: * | **Required for 1D (edge) elements**: - :attr:`~iris.experimental.ugrid.Mesh.edge_node_connectivity` + :attr:`~iris.experimental.ugrid.MeshXY.edge_node_connectivity` | Define the edges by connecting nodes. * | **Required for 2D (face) elements**: - :attr:`~iris.experimental.ugrid.Mesh.face_node_connectivity` + :attr:`~iris.experimental.ugrid.MeshXY.face_node_connectivity` | Define the faces by connecting nodes. * Optional: any other connectivity type. See :attr:`iris.experimental.ugrid.mesh.Connectivity.UGRID_CF_ROLES` for the @@ -459,7 +459,7 @@ How UGRID information is stored .. doctest:: ugrid_summaries >>> print(edge_cube.mesh) - Mesh : 'my_mesh' + MeshXY : 'my_mesh' topology_dimension: 2 node node_dimension: 'Mesh2d_node' @@ -485,7 +485,7 @@ How UGRID information is stored | Stores the following information: * | :attr:`~iris.experimental.ugrid.MeshCoord.mesh` - | The :class:`~iris.experimental.ugrid.Mesh` associated with this + | The :class:`~iris.experimental.ugrid.MeshXY` associated with this :class:`~iris.experimental.ugrid.MeshCoord`. This determines the :attr:`~iris.cube.Cube.mesh` attribute of any :class:`~iris.cube.Cube` this :class:`~iris.experimental.ugrid.MeshCoord` is attached to (see @@ -503,7 +503,7 @@ How UGRID information is stored MeshCoords ~~~~~~~~~~ -Links a :class:`~iris.cube.Cube` to a :class:`~iris.experimental.ugrid.Mesh` by +Links a :class:`~iris.cube.Cube` to a :class:`~iris.experimental.ugrid.MeshXY` by attaching to the :class:`~iris.cube.Cube`\'s unstructured dimension, in the same way that all :class:`~iris.coords.Coord`\s attach to :class:`~iris.cube.Cube` dimensions. This allows a single @@ -512,22 +512,22 @@ dimensions (e.g. horizontal mesh plus vertical levels and a time series), using the same logic for every dimension. :class:`~iris.experimental.ugrid.MeshCoord`\s are instantiated using a given -:class:`~iris.experimental.ugrid.Mesh`, ``location`` +:class:`~iris.experimental.ugrid.MeshXY`, ``location`` ("node"/"edge"/"face") and ``axis``. The process interprets the -:class:`~iris.experimental.ugrid.Mesh`\'s -:attr:`~iris.experimental.ugrid.Mesh.node_coords` and if appropriate the -:attr:`~iris.experimental.ugrid.Mesh.edge_node_connectivity`/ -:attr:`~iris.experimental.ugrid.Mesh.face_node_connectivity` and -:attr:`~iris.experimental.ugrid.Mesh.edge_coords`/ -:attr:`~iris.experimental.ugrid.Mesh.face_coords` +:class:`~iris.experimental.ugrid.MeshXY`\'s +:attr:`~iris.experimental.ugrid.MeshXY.node_coords` and if appropriate the +:attr:`~iris.experimental.ugrid.MeshXY.edge_node_connectivity`/ +:attr:`~iris.experimental.ugrid.MeshXY.face_node_connectivity` and +:attr:`~iris.experimental.ugrid.MeshXY.edge_coords`/ +:attr:`~iris.experimental.ugrid.MeshXY.face_coords` to produce a :class:`~iris.coords.Coord` :attr:`~iris.coords.Coord.points` and :attr:`~iris.coords.Coord.bounds` -representation of all the :class:`~iris.experimental.ugrid.Mesh`\'s +representation of all the :class:`~iris.experimental.ugrid.MeshXY`\'s nodes/edges/faces for the given axis. -The method :meth:`iris.experimental.ugrid.Mesh.to_MeshCoords` is available to +The method :meth:`iris.experimental.ugrid.MeshXY.to_MeshCoords` is available to create a :class:`~iris.experimental.ugrid.MeshCoord` for -every axis represented by that :class:`~iris.experimental.ugrid.Mesh`, +every axis represented by that :class:`~iris.experimental.ugrid.MeshXY`, given only the ``location`` argument .. doctest:: ugrid_summaries @@ -535,7 +535,7 @@ given only the ``location`` argument >>> for coord in edge_cube.coords(mesh_coords=True): ... print(coord) MeshCoord : latitude / (degrees_north) - mesh: + mesh: location: 'edge' points: [3. , 1.5, 1.5, 1.5, 0. , 0. ] bounds: [ @@ -550,7 +550,7 @@ given only the ``location`` argument standard_name: 'latitude' axis: 'y' MeshCoord : longitude / (degrees_east) - mesh: + mesh: location: 'edge' points: [2.5, 0. , 5. , 6.5, 2.5, 6.5] bounds: [ diff --git a/docs/src/further_topics/ugrid/operations.rst b/docs/src/further_topics/ugrid/operations.rst index 8c01b8eae5..80ff284f66 100644 --- a/docs/src/further_topics/ugrid/operations.rst +++ b/docs/src/further_topics/ugrid/operations.rst @@ -61,7 +61,7 @@ subsequent example operations on this page. >>> import numpy as np >>> from iris.coords import AuxCoord - >>> from iris.experimental.ugrid import Connectivity, Mesh + >>> from iris.experimental.ugrid import Connectivity, MeshXY # Going to create the following mesh # (node indices are shown to aid understanding): @@ -102,7 +102,7 @@ subsequent example operations on this page. ... indices=face_indices, cf_role="face_node_connectivity" ... ) - >>> my_mesh = Mesh( + >>> my_mesh = MeshXY( ... long_name="my_mesh", ... topology_dimension=2, # Supports 2D (face) elements. ... node_coords_and_axes=[(node_x, "x"), (node_y, "y")], @@ -112,7 +112,7 @@ subsequent example operations on this page. ... ) >>> print(my_mesh) - Mesh : 'my_mesh' + MeshXY : 'my_mesh' topology_dimension: 2 node node_dimension: 'Mesh2d_node' @@ -143,7 +143,7 @@ Making a Cube (with a Mesh) .. rubric:: |tagline: making a cube| Creating a :class:`~iris.cube.Cube` is unchanged; the -:class:`~iris.experimental.ugrid.Mesh` is linked via a +:class:`~iris.experimental.ugrid.MeshXY` is linked via a :class:`~iris.experimental.ugrid.MeshCoord` (see :ref:`ugrid MeshCoords`): .. dropdown:: Code @@ -205,7 +205,7 @@ Save .. note:: UGRID saving support is limited to the NetCDF file format. The Iris saving process automatically detects if the :class:`~iris.cube.Cube` -has an associated :class:`~iris.experimental.ugrid.Mesh` and automatically +has an associated :class:`~iris.experimental.ugrid.MeshXY` and automatically saves the file in a UGRID-conformant format: .. dropdown:: Code @@ -283,7 +283,7 @@ saves the file in a UGRID-conformant format: The :func:`iris.experimental.ugrid.save_mesh` function allows -:class:`~iris.experimental.ugrid.Mesh`\es to be saved to file without +:class:`~iris.experimental.ugrid.MeshXY`\es to be saved to file without associated :class:`~iris.cube.Cube`\s: .. dropdown:: Code @@ -412,7 +412,7 @@ etcetera: .. note:: We recommend caution if constraining on coordinates associated with a - :class:`~iris.experimental.ugrid.Mesh`. An individual coordinate value + :class:`~iris.experimental.ugrid.MeshXY`. An individual coordinate value might not be shared by any other data points, and using a coordinate range will demand notably higher performance given the size of the dimension versus structured grids @@ -420,7 +420,7 @@ etcetera: The :func:`iris.experimental.ugrid.load_mesh` and :func:`~iris.experimental.ugrid.load_meshes` functions allow only -:class:`~iris.experimental.ugrid.Mesh`\es to be loaded from a file without +:class:`~iris.experimental.ugrid.MeshXY`\es to be loaded from a file without creating any associated :class:`~iris.cube.Cube`\s: .. dropdown:: Code @@ -434,7 +434,7 @@ creating any associated :class:`~iris.cube.Cube`\s: ... loaded_mesh = load_mesh(cubelist_path) >>> print(loaded_mesh) - Mesh : 'my_mesh' + MeshXY : 'my_mesh' topology_dimension: 2 node node_dimension: 'Mesh2d_node' @@ -545,7 +545,7 @@ unrelated to spatial position**. This means that subsetted as intended, and subsetting a :class:`~iris.experimental.ugrid.MeshCoord` is therefore set to return an :class:`~iris.coords.AuxCoord` instead - breaking the link between :class:`~iris.cube.Cube` and -:class:`~iris.experimental.ugrid.Mesh`: +:class:`~iris.experimental.ugrid.MeshXY`: .. dropdown:: Code :icon: code @@ -751,7 +751,7 @@ with the The initialisation process is computationally expensive so we use caching to improve performance. Once a regridder has been initialised, it can be used on any :class:`~iris.cube.Cube` which has been defined on the same -:class:`~iris.experimental.ugrid.Mesh` (or on the same **grid** in the case of +:class:`~iris.experimental.ugrid.MeshXY` (or on the same **grid** in the case of :class:`~esmf_regrid.experimental.unstructured_scheme.GridToMeshESMFRegridder`). Since calling a regridder is usually a lot faster than initialising, reusing regridders can save a lot of time. We can demonstrate the reuse of the @@ -819,19 +819,19 @@ Equality .. rubric:: |tagline: equality| -:class:`~iris.experimental.ugrid.Mesh` comparison is supported, and comparing -two ':class:`~iris.experimental.ugrid.Mesh`-:class:`~iris.cube.Cube`\s' will +:class:`~iris.experimental.ugrid.MeshXY` comparison is supported, and comparing +two ':class:`~iris.experimental.ugrid.MeshXY`-:class:`~iris.cube.Cube`\s' will include a comparison of the respective -:class:`~iris.experimental.ugrid.Mesh`\es, with no extra action needed by the +:class:`~iris.experimental.ugrid.MeshXY`\es, with no extra action needed by the user. .. note:: Keep an eye on memory demand when comparing large - :class:`~iris.experimental.ugrid.Mesh`\es, but note that - :class:`~iris.experimental.ugrid.Mesh`\ equality is enabled for lazy + :class:`~iris.experimental.ugrid.MeshXY`\es, but note that + :class:`~iris.experimental.ugrid.MeshXY`\ equality is enabled for lazy processing (:doc:`/userguide/real_and_lazy_data`), so if the - :class:`~iris.experimental.ugrid.Mesh`\es being compared are lazy the + :class:`~iris.experimental.ugrid.MeshXY`\es being compared are lazy the process will use less memory than their total size. Combining Cubes @@ -842,23 +842,23 @@ Combining Cubes Merging or concatenating :class:`~iris.cube.Cube`\s (described in :doc:`/userguide/merge_and_concat`) with two different -:class:`~iris.experimental.ugrid.Mesh`\es is not possible - a +:class:`~iris.experimental.ugrid.MeshXY`\es is not possible - a :class:`~iris.cube.Cube` must be associated with just a single -:class:`~iris.experimental.ugrid.Mesh`, and merge/concatenate are not yet -capable of combining multiple :class:`~iris.experimental.ugrid.Mesh`\es into +:class:`~iris.experimental.ugrid.MeshXY`, and merge/concatenate are not yet +capable of combining multiple :class:`~iris.experimental.ugrid.MeshXY`\es into one. :class:`~iris.cube.Cube`\s that include :class:`~iris.experimental.ugrid.MeshCoord`\s can still be merged/concatenated on dimensions other than the :meth:`~iris.cube.Cube.mesh_dim`, since such :class:`~iris.cube.Cube`\s will by definition share the same -:class:`~iris.experimental.ugrid.Mesh`. +:class:`~iris.experimental.ugrid.MeshXY`. .. seealso:: You may wish to investigate :func:`iris.experimental.ugrid.recombine_submeshes`, which can be used - for a very specific type of :class:`~iris.experimental.ugrid.Mesh` + for a very specific type of :class:`~iris.experimental.ugrid.MeshXY` combination not detailed here. Arithmetic diff --git a/docs/src/further_topics/ugrid/other_meshes.rst b/docs/src/further_topics/ugrid/other_meshes.rst index 2fcbeda0d0..df83c8c4f6 100644 --- a/docs/src/further_topics/ugrid/other_meshes.rst +++ b/docs/src/further_topics/ugrid/other_meshes.rst @@ -25,7 +25,7 @@ A FESOM mesh encoded in a NetCDF file includes: To represent the Voronoi Polygons as faces, the corner coordinates will be used as the **nodes** when creating the Iris -:class:`~iris.experimental.ugrid.mesh.Mesh`. +:class:`~iris.experimental.ugrid.mesh.MeshXY`. .. dropdown:: Code :icon: code @@ -33,7 +33,7 @@ as the **nodes** when creating the Iris .. code-block:: python >>> import iris - >>> from iris.experimental.ugrid import Mesh + >>> from iris.experimental.ugrid import MeshXY >>> temperature_cube = iris.load_cube("my_file.nc", "sea_surface_temperature") @@ -62,7 +62,7 @@ as the **nodes** when creating the Iris # Use a Mesh to represent the Cube's horizontal geography, by replacing # the existing face AuxCoords with new MeshCoords. - >>> fesom_mesh = Mesh.from_coords(temperature_cube.coord('longitude'), + >>> fesom_mesh = MeshXY.from_coords(temperature_cube.coord('longitude'), ... temperature_cube.coord('latitude')) >>> for new_coord in fesom_mesh.to_MeshCoords("face"): ... old_coord = temperature_cube.coord(new_coord.name()) @@ -85,7 +85,7 @@ as the **nodes** when creating the Iris ... >>> print(temperature_cube.mesh) - Mesh : 'unknown' + MeshXY : 'unknown' topology_dimension: 2 node node_dimension: 'Mesh2d_node' @@ -113,7 +113,7 @@ An SMC grid encoded in a NetCDF file includes: From this information we can derive face corner coordinates, which will be used as the **nodes** when creating the Iris -:class:`~iris.experimental.ugrid.mesh.Mesh`. +:class:`~iris.experimental.ugrid.mesh.MeshXY`. .. dropdown:: Code @@ -122,7 +122,7 @@ as the **nodes** when creating the Iris .. code-block:: python >>> import iris - >>> from iris.experimental.ugrid import Mesh + >>> from iris.experimental.ugrid import MeshXY >>> import numpy as np @@ -177,7 +177,7 @@ as the **nodes** when creating the Iris # Use a Mesh to represent the Cube's horizontal geography, by replacing # the existing face AuxCoords with new MeshCoords. - >>> smc_mesh = Mesh.from_coords(faces_x, faces_y) + >>> smc_mesh = MeshXY.from_coords(faces_x, faces_y) >>> for new_coord in smc_mesh.to_MeshCoords("face"): ... old_coord = wave_cube.coord(new_coord.name()) ... unstructured_dim, = old_coord.cube_dims(wave_cube) @@ -209,7 +209,7 @@ as the **nodes** when creating the Iris ... >>> print(wave_cube.mesh) - Mesh : 'unknown' + MeshXY : 'unknown' topology_dimension: 2 node node_dimension: 'Mesh2d_node' @@ -265,7 +265,7 @@ dimensions into a single mesh dimension. Since Iris cubes don't support a "resh >>> import iris >>> from iris.coords import AuxCoord, CellMeasure >>> from iris.cube import Cube - >>> from iris.experimental.ugrid.mesh import Mesh, Connectivity + >>> from iris.experimental.ugrid.mesh import MeshXY, Connectivity >>> filepath = iris.sample_data_path('orca2_votemper.nc') @@ -313,14 +313,14 @@ dimensions into a single mesh dimension. Since Iris cubes don't support a "resh ... ) >>> # Create a mesh object. - >>> mesh = Mesh( + >>> mesh = MeshXY( ... topology_dimension=2, ... node_coords_and_axes=[(node_x_co, 'x'), (node_y_co, 'y')], ... connectivities=face_nodes_conn, ... face_coords_and_axes=[(face_x_co, 'x'), (face_y_co, 'y')] ... ) >>> print(mesh) - Mesh : 'unknown' + MeshXY : 'unknown' topology_dimension: 2 node node_dimension: 'Mesh2d_node' diff --git a/docs/src/further_topics/ugrid/partner_packages.rst b/docs/src/further_topics/ugrid/partner_packages.rst index 1c7a8b8c8c..87a61ae0fe 100644 --- a/docs/src/further_topics/ugrid/partner_packages.rst +++ b/docs/src/further_topics/ugrid/partner_packages.rst @@ -58,7 +58,7 @@ PyVista is described as "VTK for humans" - VTK is a very powerful toolkit for working with meshes, and PyVista brings that power into the Python ecosystem. GeoVista in turn makes it easy to use PyVista specifically for cartographic work, designed from the start with the Iris -:class:`~iris.experimental.ugrid.Mesh` in mind. +:class:`~iris.experimental.ugrid.MeshXY` in mind. Applications ------------ diff --git a/docs/src/whatsnew/3.2.rst b/docs/src/whatsnew/3.2.rst index ce544a5ecc..387cb32a26 100644 --- a/docs/src/whatsnew/3.2.rst +++ b/docs/src/whatsnew/3.2.rst @@ -64,34 +64,34 @@ v3.2.1 (11 Mar 2022) :pull:`4053`, :pull:`4439`) and API (:pull:`4063`, :pull:`4064`), and supporting representation (:pull:`4033`, :pull:`4054`) of data on meshes. Most of this new API can be found in :mod:`iris.experimental.ugrid`. The key - objects introduced are :class:`iris.experimental.ugrid.mesh.Mesh`, + objects introduced are :class:`iris.experimental.ugrid.mesh.MeshXY`, :class:`iris.experimental.ugrid.mesh.MeshCoord` and :obj:`iris.experimental.ugrid.load.PARSE_UGRID_ON_LOAD`. - A :class:`~iris.experimental.ugrid.mesh.Mesh` contains a full description of a UGRID + A :class:`~iris.experimental.ugrid.mesh.MeshXY` contains a full description of a UGRID type mesh. :class:`~iris.experimental.ugrid.mesh.MeshCoord`\ s are coordinates that - reference and represent a :class:`~iris.experimental.ugrid.mesh.Mesh` for use + reference and represent a :class:`~iris.experimental.ugrid.mesh.MeshXY` for use on a :class:`~iris.cube.Cube`. :class:`~iris.cube.Cube`\ s are also given the property :attr:`~iris.cube.Cube.mesh` which returns a - :class:`~iris.experimental.ugrid.mesh.Mesh` if one is attached to the + :class:`~iris.experimental.ugrid.mesh.MeshXY` if one is attached to the :class:`~iris.cube.Cube` via a :class:`~iris.experimental.ugrid.mesh.MeshCoord`. #. `@trexfeathers`_ added support for loading unstructured mesh data from netcdf data, for files using the `CF-UGRID`_ conventions. The context manager :obj:`~iris.experimental.ugrid.load.PARSE_UGRID_ON_LOAD` provides a way to load UGRID files so that :class:`~iris.cube.Cube`\ s can be - returned with a :class:`~iris.experimental.ugrid.mesh.Mesh` attached. + returned with a :class:`~iris.experimental.ugrid.mesh.MeshXY` attached. (:pull:`4058`). #. `@pp-mo`_ added support to save cubes with :ref:`meshes ` to netcdf files, using the `CF-UGRID`_ conventions. The existing :meth:`iris.save` function now does this, when saving cubes with meshes. A routine :meth:`iris.experimental.ugrid.save.save_mesh` allows saving - :class:`~iris.experimental.ugrid.mesh.Mesh` objects to netcdf *without* any associated data + :class:`~iris.experimental.ugrid.mesh.MeshXY` objects to netcdf *without* any associated data (i.e. not attached to cubes). (:pull:`4318` and :pull:`4339`). -#. `@trexfeathers`_ added :meth:`iris.experimental.ugrid.mesh.Mesh.from_coords` - for inferring a :class:`~iris.experimental.ugrid.mesh.Mesh` from an +#. `@trexfeathers`_ added :meth:`iris.experimental.ugrid.mesh.MeshXY.from_coords` + for inferring a :class:`~iris.experimental.ugrid.mesh.MeshXY` from an appropriate collection of :class:`iris.coords.Coord`\ s. #. `@larsbarring`_ updated :func:`~iris.util.equalise_attributes` to return a list of dictionaries @@ -130,7 +130,7 @@ v3.2.1 (11 Mar 2022) :class:`~iris.coords.Coord`, :class:`~iris.coords.CellMeasure`, :class:`~iris.coords.AncillaryVariable`, :class:`~iris.experimental.ugrid.mesh.MeshCoord` and - :class:`~iris.experimental.ugrid.mesh.Mesh`. + :class:`~iris.experimental.ugrid.mesh.MeshXY`. These now all provide a more controllable ``summary()`` method, and more convenient and readable ``str()`` and ``repr()`` output in the style of the :class:`iris.cube.Cube`. diff --git a/docs/src/whatsnew/3.7.rst b/docs/src/whatsnew/3.7.rst index f5070b341d..fdadb20412 100644 --- a/docs/src/whatsnew/3.7.rst +++ b/docs/src/whatsnew/3.7.rst @@ -70,7 +70,7 @@ v3.7.1 (04 Mar 2024) (:pull:`5382`) #. `@trexfeathers`_ included mesh location coordinates - (e.g. :attr:`~iris.experimental.ugrid.Mesh.face_coords`) in + (e.g. :attr:`~iris.experimental.ugrid.MeshXY.face_coords`) in the data variable's ``coordinates`` attribute when saving to NetCDF. (:issue:`5206`, :pull:`5389`) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index e4c89b7003..28a64669e8 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -77,6 +77,11 @@ This document explains the changes made to Iris for this release This is due to changes in :func:`~iris.util.array_equal` which previously ignored masks entirely. (:pull:`4457`) +#. `@trexfeathers`_ renamed the ``Mesh`` class to + :class:`~iris.experimental.ugrid.mesh.MeshXY`, in preparation for a future + more flexible parent class (:class:`~iris.experimental.ugrid.mesh.Mesh`). + (:issue:`6052` :pull:`6056`) + #. `@stephenworsley`_ replaced the ``include_nodes``, ``include_edges`` and ``include_faces`` arguments with a single ``location`` argument in the :class:`~iris.experimental.ugrid.Mesh` methods diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 5c7f9da0eb..47b66b6ead 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -2365,16 +2365,16 @@ def _any_meshcoord(self): @property def mesh(self): - r"""Return the unstructured :class:`~iris.experimental.ugrid.Mesh` associated with the cube. + r"""Return the unstructured :class:`~iris.experimental.ugrid.MeshXY` associated with the cube. - Return the unstructured :class:`~iris.experimental.ugrid.Mesh` + Return the unstructured :class:`~iris.experimental.ugrid.MeshXY` associated with the cube, if the cube has any :class:`~iris.experimental.ugrid.MeshCoord`, or ``None`` if it has none. Returns ------- - :class:`iris.experimental.ugrid.mesh.Mesh` or None + :class:`iris.experimental.ugrid.mesh.MeshXY` or None The mesh of the cube :class:`~iris.experimental.ugrid.MeshCoord`'s, or ``None``. diff --git a/lib/iris/experimental/geovista.py b/lib/iris/experimental/geovista.py index 26bfa2e703..b659f9e1dc 100644 --- a/lib/iris/experimental/geovista.py +++ b/lib/iris/experimental/geovista.py @@ -8,7 +8,7 @@ from geovista.common import VTK_CELL_IDS, VTK_POINT_IDS from iris.exceptions import CoordinateNotFoundError -from iris.experimental.ugrid import Mesh +from iris.experimental.ugrid import MeshXY def _get_coord(cube, axis): @@ -322,7 +322,7 @@ def extract_unstructured_region(cube, polydata, region, **kwargs): if recreate_mesh: coords_on_mesh_dim = region_cube.coords(dimensions=mesh_dim) - new_mesh = Mesh.from_coords( + new_mesh = MeshXY.from_coords( *[c for c in coords_on_mesh_dim if c.has_bounds()] ) diff --git a/lib/iris/experimental/ugrid/__init__.py b/lib/iris/experimental/ugrid/__init__.py index f92cf670c4..05f631d1cc 100644 --- a/lib/iris/experimental/ugrid/__init__.py +++ b/lib/iris/experimental/ugrid/__init__.py @@ -16,14 +16,14 @@ from ...config import get_logger from .load import PARSE_UGRID_ON_LOAD, load_mesh, load_meshes -from .mesh import Connectivity, Mesh, MeshCoord +from .mesh import Connectivity, MeshCoord, MeshXY from .save import save_mesh from .utils import recombine_submeshes __all__ = [ "Connectivity", - "Mesh", "MeshCoord", + "MeshXY", "PARSE_UGRID_ON_LOAD", "load_mesh", "load_meshes", diff --git a/lib/iris/experimental/ugrid/load.py b/lib/iris/experimental/ugrid/load.py index 24fb34bbac..d4e6d8afc3 100644 --- a/lib/iris/experimental/ugrid/load.py +++ b/lib/iris/experimental/ugrid/load.py @@ -3,10 +3,10 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. -r"""Allow the construction of :class:`~iris.experimental.ugrid.mesh.Mesh`. +r"""Allow the construction of :class:`~iris.experimental.ugrid.mesh.MeshXY`. Extensions to Iris' NetCDF loading to allow the construction of -:class:`~iris.experimental.ugrid.mesh.Mesh` from UGRID data in the file. +:class:`~iris.experimental.ugrid.mesh.MeshXY` from UGRID data in the file. Eventual destination: :mod:`iris.fileformats.netcdf`. @@ -31,7 +31,7 @@ CFUGridMeshVariable, CFUGridReader, ) -from .mesh import Connectivity, Mesh +from .mesh import Connectivity, MeshXY # Configure the logger. logger = get_logger(__name__, propagate=True, handler=False) @@ -119,10 +119,10 @@ def _meshes_from_cf(cf_reader): def load_mesh(uris, var_name=None): - """Load a single :class:`~iris.experimental.ugrid.mesh.Mesh` object from one or more NetCDF files. + """Load single :class:`~iris.experimental.ugrid.mesh.MeshXY` object from 1/more NetCDF files. Raises an error if more/less than one - :class:`~iris.experimental.ugrid.mesh.Mesh` is found. + :class:`~iris.experimental.ugrid.mesh.MeshXY` is found. Parameters ---------- @@ -130,12 +130,12 @@ def load_mesh(uris, var_name=None): One or more filenames/URI's. Filenames can include wildcards. Any URI's must support OpenDAP. var_name : str, optional - Only return a :class:`~iris.experimental.ugrid.mesh.Mesh` if its + Only return a :class:`~iris.experimental.ugrid.mesh.MeshXY` if its var_name matches this value. Returns ------- - :class:`iris.experimental.ugrid.mesh.Mesh` + :class:`iris.experimental.ugrid.mesh.MeshXY` """ meshes_result = load_meshes(uris, var_name) @@ -148,7 +148,7 @@ def load_mesh(uris, var_name=None): def load_meshes(uris, var_name=None): - r"""Load :class:`~iris.experimental.ugrid.mesh.Mesh` objects from one or more NetCDF files. + r"""Load :class:`~iris.experimental.ugrid.mesh.MeshXY` objects from one or more NetCDF files. Parameters ---------- @@ -156,7 +156,7 @@ def load_meshes(uris, var_name=None): One or more filenames/URI's. Filenames can include wildcards. Any URI's must support OpenDAP. var_name : str, optional - Only return :class:`~iris.experimental.ugrid.mesh.Mesh` that have + Only return :class:`~iris.experimental.ugrid.mesh.MeshXY` that have var_names matching this value. Returns @@ -164,7 +164,7 @@ def load_meshes(uris, var_name=None): dict A dictionary mapping each mesh-containing file path/URL in the input ``uris`` to a list of the - :class:`~iris.experimental.ugrid.mesh.Mesh` returned from each. + :class:`~iris.experimental.ugrid.mesh.MeshXY` returned from each. """ # TODO: rationalise UGRID/mesh handling once experimental.ugrid is folded @@ -334,9 +334,9 @@ def _build_connectivity(connectivity_var, file_path, element_dims): def _build_mesh(cf, mesh_var, file_path): - """Construct a :class:`~iris.experimental.ugrid.mesh.Mesh`. + """Construct a :class:`~iris.experimental.ugrid.mesh.MeshXY`. - Construct a :class:`~iris.experimental.ugrid.mesh.Mesh` from a given + Construct a :class:`~iris.experimental.ugrid.mesh.MeshXY` from a given :class:`~iris.experimental.ugrid.cf.CFUGridMeshVariable`. TODO: integrate with standard loading API post-pyke. @@ -374,7 +374,7 @@ def _build_mesh(cf, mesh_var, file_path): if not hasattr(mesh_var, "topology_dimension"): msg = ( - f"Mesh variable {mesh_var.cf_name} has no 'topology_dimension'" + f"MeshXY variable {mesh_var.cf_name} has no 'topology_dimension'" f" : *Assuming* topology_dimension={topology_dimension}" ", consistent with the attached connectivities." ) @@ -444,7 +444,7 @@ def _build_mesh(cf, mesh_var, file_path): standard_name, long_name, var_name = get_names(mesh_var, None, attributes) - mesh = Mesh( + mesh = MeshXY( topology_dimension=topology_dimension, node_coords_and_axes=node_coord_args, connectivities=connectivity_args, @@ -472,7 +472,7 @@ def _build_mesh_coords(mesh, cf_var): """Construct a tuple of :class:`~iris.experimental.ugrid.mesh.MeshCoord`. Construct a tuple of :class:`~iris.experimental.ugrid.mesh.MeshCoord` using - from a given :class:`~iris.experimental.ugrid.mesh.Mesh` + from a given :class:`~iris.experimental.ugrid.mesh.MeshXY` and :class:`~iris.fileformats.cf.CFVariable`. TODO: integrate with standard loading API post-pyke. diff --git a/lib/iris/experimental/ugrid/mesh.py b/lib/iris/experimental/ugrid/mesh.py index 9b3baa6511..c90b67e1d6 100644 --- a/lib/iris/experimental/ugrid/mesh.py +++ b/lib/iris/experimental/ugrid/mesh.py @@ -39,7 +39,7 @@ NP_PRINTOPTIONS_EDGEITEMS = 2 # -# Mesh dimension names namedtuples. +# MeshXY dimension names namedtuples. # #: Namedtuple for 1D mesh topology NetCDF variable dimension names. @@ -50,7 +50,7 @@ ) # -# Mesh coordinate manager namedtuples. +# MeshXY coordinate manager namedtuples. # #: Namedtuple for 1D mesh :class:`~iris.coords.AuxCoord` coordinates. @@ -68,7 +68,7 @@ MeshFaceCoords = namedtuple("MeshFaceCoords", ["face_x", "face_y"]) # -# Mesh connectivity manager namedtuples. +# MeshXY connectivity manager namedtuples. # #: Namedtuple for 1D mesh :class:`~iris.experimental.ugrid.mesh.Connectivity` instances. @@ -579,20 +579,60 @@ def xml_element(self, doc): return element -class Mesh(CFVariableMixin): +class Mesh(CFVariableMixin, ABC): """A container representing the UGRID ``cf_role`` ``mesh_topology``. - A container representing the UGRID ``cf_role`` ``mesh_topology``, supporting - 1D network, 2D triangular, and 2D flexible mesh topologies. + Warnings + -------- + This class is not yet implemented. It is a placeholder for a future + implementation of the UGRID mesh with the minimum possible assumptions. For + instance: it is in theory possible for mesh node coordinates to be ANY + combination of ANY coordinate type, e.g. spherical coordinates or an S2 + coordinate; the current :class:`MeshXY` subclass is based on the assumption + of an X and a Y coordinate (e.g. longitude and latitude). + + .. todo:: + If SciTools/iris#5994 is agreed upon: implement this class. + - Move whatever is appropriate from :class:`MeshXY` into this class, + leaving behind only those elements specific to the assumption of + X and Y node coordinates. + - Remove the docstring warning, the NotImplementedError, and the uses + of ABC/abstractmethod. + - Add a cross-reference in the docstring for :class:`MeshXY`. + - Search the Iris codebase for uses of :class:`MeshXY` and work out + if/how they can be refactored to work with the more flexible + :class:`Mesh`. - .. note:: + """ + + @abstractmethod + def __init__(self): + message = ( + f"The {self.__class__.__name__} class is not yet implemented. " + "Use the MeshXY class instead." + ) + raise NotImplementedError(message) + + +class MeshXY(Mesh): + """A container representing the UGRID ``cf_role`` ``mesh_topology``. + + A container representing the UGRID [1]_ ``cf_role`` ``mesh_topology``, supporting + 1D network, 2D triangular, and 2D flexible mesh topologies. - The 3D layered and fully 3D unstructured mesh topologies are not supported - at this time. + Based on the assumption of 2 :attr:`node_coords` - one associated with the + X-axis (e.g. longitude) and 1 with the Y-axis (e.g. latitude). UGRID + describing alternative node coordinates (e.g. spherical) cannot be + represented. - .. seealso:: + Notes + ----- + The 3D layered and fully 3D unstructured mesh topologies are not supported + at this time. - The UGRID Conventions, https://ugrid-conventions.github.io/ugrid-conventions/ + References + ---------- + .. [1] The UGRID Conventions, https://ugrid-conventions.github.io/ugrid-conventions/ """ @@ -620,7 +660,7 @@ def __init__( edge_dimension=None, face_dimension=None, ): - """Mesh initialise. + """MeshXY initialise. .. note:: @@ -697,38 +737,38 @@ def normalise(element, axis): @classmethod def from_coords(cls, *coords): - r"""Construct a :class:`Mesh` by derivation from one or more :class:`~iris.coords.Coord`. + r"""Construct a :class:`MeshXY` by derivation from 1/more :class:`~iris.coords.Coord`. - The :attr:`~Mesh.topology_dimension`, :class:`~iris.coords.Coord` + The :attr:`~MeshXY.topology_dimension`, :class:`~iris.coords.Coord` membership and :class:`Connectivity` membership are all determined based on the shape of the first :attr:`~iris.coords.Coord.bounds`: * ``None`` or ``(n, <2)``: Not supported * ``(n, 2)``: - :attr:`~Mesh.topology_dimension` = ``1``. - :attr:`~Mesh.node_coords` and :attr:`~Mesh.edge_node_connectivity` + :attr:`~MeshXY.topology_dimension` = ``1``. + :attr:`~MeshXY.node_coords` and :attr:`~MeshXY.edge_node_connectivity` constructed from :attr:`~iris.coords.Coord.bounds`. - :attr:`~Mesh.edge_coords` constructed from + :attr:`~MeshXY.edge_coords` constructed from :attr:`~iris.coords.Coord.points`. * ``(n, >=3)``: - :attr:`~Mesh.topology_dimension` = ``2``. - :attr:`~Mesh.node_coords` and :attr:`~Mesh.face_node_connectivity` + :attr:`~MeshXY.topology_dimension` = ``2``. + :attr:`~MeshXY.node_coords` and :attr:`~MeshXY.face_node_connectivity` constructed from :attr:`~iris.coords.Coord.bounds`. - :attr:`~Mesh.face_coords` constructed from + :attr:`~MeshXY.face_coords` constructed from :attr:`~iris.coords.Coord.points`. Parameters ---------- *coords : Iterable of :class:`~iris.coords.Coord` - Coordinates to pass into the :class:`Mesh`. + Coordinates to pass into the :class:`MeshXY`. All :attr:`~iris.coords.Coord.points` must have the same shapes; all :attr:`~iris.coords.Coord.bounds` must have the same shapes, and must not be ``None``. Returns ------- - :class:`Mesh` + :class:`MeshXY` Notes ----- @@ -737,7 +777,7 @@ def from_coords(cls, *coords): computational intensity. .. note:: - :class:`Mesh` currently requires ``X`` and ``Y`` + :class:`MeshXY` currently requires ``X`` and ``Y`` :class:`~iris.coords.Coord` specifically. :meth:`iris.util.guess_coord_axis` is therefore attempted, else the first two :class:`~iris.coords.Coord` are taken. @@ -747,7 +787,7 @@ def from_coords(cls, *coords): from iris import load_cube, sample_data_path from iris.experimental.ugrid import ( PARSE_UGRID_ON_LOAD, - Mesh, + MeshXY, MeshCoord, ) @@ -781,7 +821,7 @@ def from_coords(cls, *coords): latitude: AuxCoord longitude: AuxCoord - >>> new_mesh = Mesh.from_coords(*orig_coords) + >>> new_mesh = MeshXY.from_coords(*orig_coords) >>> new_coords = new_mesh.to_MeshCoords(location=cube_w_mesh.location) # Replace the AuxCoords with MeshCoords. @@ -900,7 +940,7 @@ def axes_assign(coord_list): def __eq__(self, other): result = NotImplemented - if isinstance(other, Mesh): + if isinstance(other, MeshXY): result = self.metadata == other.metadata if result: result = self.all_coords == other.all_coords @@ -928,12 +968,12 @@ def __ne__(self, other): return result def summary(self, shorten=False): - """Return a string representation of the Mesh. + """Return a string representation of the MeshXY. Parameters ---------- shorten : bool, default=False - If True, produce a oneline string form of the form . + If True, produce a oneline string form of the form . If False, produce a multi-line detailed print output. Returns @@ -963,11 +1003,11 @@ def _summary_oneline(self): mesh_name = None if mesh_name: # Use a more human-readable form - mesh_string = f"" + mesh_string = f"" else: # Mimic the generic object.__str__ style. mesh_id = id(self) - mesh_string = f"" + mesh_string = f"" return mesh_string @@ -981,7 +1021,7 @@ def line(text, i_indent=0): indent = indent_str * i_indent lines.append(f"{indent}{text}") - line(f"Mesh : '{self.name()}'") + line(f"MeshXY : '{self.name()}'") line(f"topology_dimension: {self.topology_dimension}", 1) for element in ("node", "edge", "face"): if element == "node": @@ -1096,12 +1136,12 @@ def _set_dimension_names(self, node, edge, face, reset=False): @property def all_connectivities(self): - """All the :class:`~iris.experimental.ugrid.mesh.Connectivity` instances of the :class:`Mesh`.""" + """All the :class:`~iris.experimental.ugrid.mesh.Connectivity` instances of the :class:`MeshXY`.""" return self._connectivity_manager.all_members @property def all_coords(self): - """All the :class:`~iris.coords.AuxCoord` coordinates of the :class:`Mesh`.""" + """All the :class:`~iris.coords.AuxCoord` coordinates of the :class:`MeshXY`.""" return self._coord_manager.all_members @property @@ -1110,14 +1150,14 @@ def boundary_node_connectivity(self): The *optional* UGRID ``boundary_node_connectivity`` :class:`~iris.experimental.ugrid.mesh.Connectivity` of the - :class:`Mesh`. + :class:`MeshXY`. """ return self._connectivity_manager.boundary_node @property def edge_coords(self): - """The *optional* UGRID ``edge`` :class:`~iris.coords.AuxCoord` coordinates of the :class:`Mesh`.""" + """The *optional* UGRID ``edge`` :class:`~iris.coords.AuxCoord` coordinates of the :class:`MeshXY`.""" return self._coord_manager.edge_coords @property @@ -1139,7 +1179,7 @@ def edge_face_connectivity(self): The *optional* UGRID ``edge_face_connectivity`` :class:`~iris.experimental.ugrid.mesh.Connectivity` of the - :class:`Mesh`. + :class:`MeshXY`. """ return self._connectivity_manager.edge_face @@ -1150,16 +1190,16 @@ def edge_node_connectivity(self): The UGRID ``edge_node_connectivity`` :class:`~iris.experimental.ugrid.mesh.Connectivity` of the - :class:`Mesh`, which is **required** for :attr:`Mesh.topology_dimension` + :class:`MeshXY`, which is **required** for :attr:`MeshXY.topology_dimension` of ``1``, and *optionally required* for - :attr:`Mesh.topology_dimension` ``>=2``. + :attr:`MeshXY.topology_dimension` ``>=2``. """ return self._connectivity_manager.edge_node @property def face_coords(self): - """The *optional* UGRID ``face`` :class:`~iris.coords.AuxCoord` coordinates of the :class:`Mesh`.""" + """The *optional* UGRID ``face`` :class:`~iris.coords.AuxCoord` coordinates of the :class:`MeshXY`.""" return self._coord_manager.face_coords @property @@ -1190,7 +1230,7 @@ def face_edge_connectivity(self): The *optional* UGRID ``face_edge_connectivity`` :class:`~iris.experimental.ugrid.mesh.Connectivity` of the - :class:`Mesh`. + :class:`MeshXY`. """ # optional @@ -1202,7 +1242,7 @@ def face_face_connectivity(self): The *optional* UGRID ``face_face_connectivity`` :class:`~iris.experimental.ugrid.mesh.Connectivity` of the - :class:`Mesh`. + :class:`MeshXY`. """ return self._connectivity_manager.face_face @@ -1213,8 +1253,8 @@ def face_node_connectivity(self): The UGRID ``face_node_connectivity`` :class:`~iris.experimental.ugrid.mesh.Connectivity` of the - :class:`Mesh`, which is **required** for :attr:`Mesh.topology_dimension` - of ``2``, and *optionally required* for :attr:`Mesh.topology_dimension` + :class:`MeshXY`, which is **required** for :attr:`MeshXY.topology_dimension` + of ``2``, and *optionally required* for :attr:`MeshXY.topology_dimension` of ``3``. """ @@ -1222,7 +1262,7 @@ def face_node_connectivity(self): @property def node_coords(self): - """The **required** UGRID ``node`` :class:`~iris.coords.AuxCoord` coordinates of the :class:`Mesh`.""" + """The **required** UGRID ``node`` :class:`~iris.coords.AuxCoord` coordinates of the :class:`MeshXY`.""" return self._coord_manager.node_coords @property @@ -1239,14 +1279,14 @@ def node_dimension(self, name): self._metadata_manager.node_dimension = node_dimension def add_connectivities(self, *connectivities): - """Add one or more :class:`~iris.experimental.ugrid.mesh.Connectivity` instances to the :class:`Mesh`. + """Add one or more :class:`~iris.experimental.ugrid.mesh.Connectivity` instances to the :class:`MeshXY`. Parameters ---------- *connectivities : iterable of object A collection of one or more :class:`~iris.experimental.ugrid.mesh.Connectivity` instances to - add to the :class:`Mesh`. + add to the :class:`MeshXY`. """ self._connectivity_manager.add(*connectivities) @@ -1260,7 +1300,7 @@ def add_coords( face_x=None, face_y=None, ): - """Add one or more :class:`~iris.coords.AuxCoord` coordinates to the :class:`Mesh`. + """Add one or more :class:`~iris.coords.AuxCoord` coordinates to the :class:`MeshXY`. Parameters ---------- @@ -1307,14 +1347,14 @@ def connectivities( """Return all :class:`~iris.experimental.ugrid.mesh.Connectivity`. Return all :class:`~iris.experimental.ugrid.mesh.Connectivity` - instances from the :class:`Mesh` that match the provided criteria. + instances from the :class:`MeshXY` that match the provided criteria. Criteria can be either specific properties or other objects with metadata to be matched. .. seealso:: - :meth:`Mesh.connectivity` for matching exactly one connectivity. + :meth:`MeshXY.connectivity` for matching exactly one connectivity. Parameters ---------- @@ -1366,7 +1406,7 @@ def connectivities( ------- list of :class:`~iris.experimental.ugrid.mesh.Connectivity` A list of :class:`~iris.experimental.ugrid.mesh.Connectivity` - instances from the :class:`Mesh` that matched the given criteria. + instances from the :class:`MeshXY` that matched the given criteria. """ result = self._connectivity_manager.filters( @@ -1397,7 +1437,7 @@ def connectivity( """Return a single :class:`~iris.experimental.ugrid.mesh.Connectivity`. Return a single :class:`~iris.experimental.ugrid.mesh.Connectivity` - from the :class:`Mesh` that matches the provided criteria. + from the :class:`MeshXY` that matches the provided criteria. Criteria can be either specific properties or other objects with metadata to be matched. @@ -1410,7 +1450,7 @@ def connectivity( .. seealso:: - :meth:`Mesh.connectivities` for matching zero or more connectivities. + :meth:`MeshXY.connectivities` for matching zero or more connectivities. Parameters ---------- @@ -1462,7 +1502,7 @@ def connectivity( ------- :class:`~iris.experimental.ugrid.mesh.Connectivity` The :class:`~iris.experimental.ugrid.mesh.Connectivity` from the - :class:`Mesh` that matched the given criteria. + :class:`MeshXY` that matched the given criteria. """ result = self._connectivity_manager.filter( @@ -1491,7 +1531,7 @@ def coord( """Return a single :class:`~iris.coords.AuxCoord` coordinate. Return a single :class:`~iris.coords.AuxCoord` coordinate from the - :class:`Mesh` that matches the provided criteria. + :class:`MeshXY` that matches the provided criteria. Criteria can be either specific properties or other objects with metadata to be matched. @@ -1503,7 +1543,7 @@ def coord( .. seealso:: - :meth:`Mesh.coords` for matching zero or more coordinates. + :meth:`MeshXY.coords` for matching zero or more coordinates. Parameters ---------- @@ -1540,7 +1580,7 @@ def coord( Returns ------- :class:`~iris.coords.AuxCoord` - The :class:`~iris.coords.AuxCoord` coordinate from the :class:`Mesh` + The :class:`~iris.coords.AuxCoord` coordinate from the :class:`MeshXY` that matched the given criteria. """ @@ -1565,9 +1605,9 @@ def coords( axis=None, location=None, ): - """Return all :class:`~iris.coords.AuxCoord` coordinates from the :class:`Mesh`. + """Return all :class:`~iris.coords.AuxCoord` coordinates from the :class:`MeshXY`. - Return all :class:`~iris.coords.AuxCoord` coordinates from the :class:`Mesh` that + Return all :class:`~iris.coords.AuxCoord` coordinates from the :class:`MeshXY` that match the provided criteria. Criteria can be either specific properties or other objects with @@ -1575,7 +1615,7 @@ def coords( .. seealso:: - :meth:`Mesh.coord` for matching exactly one coordinate. + :meth:`MeshXY.coord` for matching exactly one coordinate. Parameters ---------- @@ -1613,7 +1653,7 @@ def coords( ------- list of :class:`~iris.coords.AuxCoord` A list of :class:`~iris.coords.AuxCoord` coordinates from the - :class:`Mesh` that matched the given criteria. + :class:`MeshXY` that matched the given criteria. """ result = self._coord_manager.filters( @@ -1642,7 +1682,7 @@ def remove_connectivities( """Remove one or more :class:`~iris.experimental.ugrid.mesh.Connectivity`. Remove one or more :class:`~iris.experimental.ugrid.mesh.Connectivity` - from the :class:`Mesh` that match the provided criteria. + from the :class:`MeshXY` that match the provided criteria. Criteria can be either specific properties or other objects with metadata to be matched. @@ -1697,7 +1737,7 @@ def remove_connectivities( ------- list of :class:`~iris.experimental.ugrid.mesh.Connectivity` A list of :class:`~iris.experimental.ugrid.mesh.Connectivity` - instances removed from the :class:`Mesh` that matched the given + instances removed from the :class:`MeshXY` that matched the given criteria. """ @@ -1723,9 +1763,9 @@ def remove_coords( axis=None, location=None, ): - """Remove one or more :class:`~iris.coords.AuxCoord` from the :class:`Mesh`. + """Remove one or more :class:`~iris.coords.AuxCoord` from the :class:`MeshXY`. - Remove one or more :class:`~iris.coords.AuxCoord` from the :class:`Mesh` + Remove one or more :class:`~iris.coords.AuxCoord` from the :class:`MeshXY` that match the provided criteria. Criteria can be either specific properties or other objects with @@ -1767,7 +1807,7 @@ def remove_coords( ------- list of :class:`~iris.coords.AuxCoord` A list of :class:`~iris.coords.AuxCoord` coordinates removed from - the :class:`Mesh` that matched the given criteria. + the :class:`MeshXY` that matched the given criteria. """ result = self._coord_manager.remove( @@ -1783,7 +1823,7 @@ def remove_coords( return result def xml_element(self, doc): - """Create the :class:`xml.dom.minidom.Element` that describes this :class:`Mesh`. + """Create the :class:`xml.dom.minidom.Element` that describes this :class:`MeshXY`. Parameters ---------- @@ -1794,7 +1834,7 @@ def xml_element(self, doc): ------- :class:`xml.dom.minidom.Element` The :class:`xml.dom.minidom.Element` that will describe this - :class:`Mesh`, and the dictionary of attributes that require + :class:`MeshXY`, and the dictionary of attributes that require to be added to this element. """ @@ -1817,7 +1857,7 @@ def to_MeshCoord(self, location, axis): """Generate a :class:`~iris.experimental.ugrid.mesh.MeshCoord`. Generate a :class:`~iris.experimental.ugrid.mesh.MeshCoord` that - references the current :class:`Mesh`, and passing through the + references the current :class:`MeshXY`, and passing through the ``location`` and ``axis`` arguments. .. seealso:: @@ -1837,7 +1877,7 @@ def to_MeshCoord(self, location, axis): ------- :class:`~iris.experimental.ugrid.mesh.MeshCoord` A :class:`~iris.experimental.ugrid.mesh.MeshCoord` referencing the - current :class:`Mesh`. + current :class:`MeshXY`. """ return MeshCoord(mesh=self, location=location, axis=axis) @@ -1847,7 +1887,7 @@ def to_MeshCoords(self, location): Generate a tuple of :class:`~iris.experimental.ugrid.mesh.MeshCoord`, each referencing - the current :class:`Mesh`, one for each :attr:`AXES` value, passing + the current :class:`MeshXY`, one for each :attr:`AXES` value, passing through the ``location`` argument. .. seealso:: @@ -1863,7 +1903,7 @@ def to_MeshCoords(self, location): ------- tuple of :class:`~iris.experimental.ugrid.mesh.MeshCoord` Tuple of :class:`~iris.experimental.ugrid.mesh.MeshCoord` - referencing the current :class:`Mesh`. One for each value in + referencing the current :class:`MeshXY`. One for each value in :attr:`AXES`, using the value for the ``axis`` argument. """ @@ -1900,7 +1940,7 @@ def dimension_names(self, node=None, edge=None, face=None): The default value of ``None`` will not be assigned to clear the associated ``node``, ``edge`` or ``face``. Instead use - :meth:`Mesh.dimension_names_reset`. + :meth:`MeshXY.dimension_names_reset`. Parameters ---------- @@ -1919,7 +1959,7 @@ def dimension_names(self, node=None, edge=None, face=None): @property def cf_role(self): - """The UGRID ``cf_role`` attribute of the :class:`Mesh`.""" + """The UGRID ``cf_role`` attribute of the :class:`MeshXY`.""" return "mesh_topology" @property @@ -1928,7 +1968,7 @@ def topology_dimension(self): The UGRID ``topology_dimension`` attribute represents the highest dimensionality of all the geometric elements (node, edge, face) represented - within the :class:`Mesh`. + within the :class:`MeshXY`. """ return self._metadata_manager.topology_dimension @@ -2613,15 +2653,15 @@ def face_node(self): class MeshCoord(AuxCoord): """Geographic coordinate values of data on an unstructured mesh. - A MeshCoord references a `~iris.experimental.ugrid.mesh.Mesh`. - When contained in a `~iris.cube.Cube` it connects the cube to the Mesh. + A MeshCoord references a `~iris.experimental.ugrid.mesh.MeshXY`. + When contained in a `~iris.cube.Cube` it connects the cube to the MeshXY. It records (a) which 1-D cube dimension represents the unstructured mesh, and (b) which mesh 'location' the cube data is mapped to -- i.e. is it data on 'face's, 'edge's or 'node's. A MeshCoord also specifies its 'axis' : 'x' or 'y'. Its values are then, accordingly, longitudes or latitudes. The values are taken from the - appropriate coordinates and connectivities in the Mesh, determined by its + appropriate coordinates and connectivities in the MeshXY, determined by its 'location' and 'axis'. Any cube with data on a mesh will have a MeshCoord for each axis, @@ -2631,9 +2671,9 @@ class MeshCoord(AuxCoord): which depends on location. For 'node', the ``.points`` contains node locations. For 'edge', the ``.bounds`` contains edge endpoints, and the ``.points`` contain - edge locations (typically centres), if the Mesh contains them (optional). + edge locations (typically centres), if the MeshXY contains them (optional). For 'face', the ``.bounds`` contain the face corners, and the ``.points`` contain the - face locations (typically centres), if the Mesh contains them (optional). + face locations (typically centres), if the MeshXY contains them (optional). .. note:: As described above, it is possible for a MeshCoord to have bounds but @@ -2656,10 +2696,10 @@ def __init__( self._metadata_manager = metadata_manager_factory(MeshCoordMetadata) # Validate and record the class-specific constructor args. - if not isinstance(mesh, Mesh): + if not isinstance(mesh, MeshXY): msg = ( "'mesh' must be an " - f"{Mesh.__module__}.{Mesh.__name__}, " + f"{MeshXY.__module__}.{MeshXY.__name__}, " f"got {mesh}." ) raise TypeError(msg) @@ -2667,20 +2707,20 @@ def __init__( # NOTE: currently *not* included in metadata. In future it might be. self._mesh = mesh - if location not in Mesh.ELEMENTS: + if location not in MeshXY.ELEMENTS: msg = ( - f"'location' of {location} is not a valid Mesh location', " - f"must be one of {Mesh.ELEMENTS}." + f"'location' of {location} is not a valid MeshXY location', " + f"must be one of {MeshXY.ELEMENTS}." ) raise ValueError(msg) # Held in metadata, readable as self.location, but cannot set it. self._metadata_manager.location = location - if axis not in Mesh.AXES: - # The valid axes are defined by the Mesh class. + if axis not in MeshXY.AXES: + # The valid axes are defined by the MeshXY class. msg = ( - f"'axis' of {axis} is not a valid Mesh axis', " - f"must be one of {Mesh.AXES}." + f"'axis' of {axis} is not a valid MeshXY axis', " + f"must be one of {MeshXY.AXES}." ) raise ValueError(msg) # Held in metadata, readable as self.axis, but cannot set it. @@ -2706,7 +2746,7 @@ def __init__( use_metadict = location_coord.metadata._asdict() unit_unknown = Unit(None) - # N.B. at present, coords in a Mesh are stored+accessed by 'axis', which + # N.B. at present, coords in a MeshXY are stored+accessed by 'axis', which # means they must have a standard_name. So ... # (a) the 'location' (face/edge) coord *always* has a usable phenomenon # identity. @@ -2833,7 +2873,7 @@ def collapsed(self, dims_to_collapse=None): The coordinate that is collapsed is a :class:`~iris.coords.AuxCoord` copy of this :class:`MeshCoord`, since a :class:`MeshCoord` does not have its own points/bounds - they are derived from the - associated :class:`Mesh`. See :meth:`iris.coords.AuxCoord.collapsed`. + associated :class:`MeshXY`. See :meth:`iris.coords.AuxCoord.collapsed`. """ @contextmanager @@ -2894,9 +2934,9 @@ def copy(self, points=None, bounds=None): def __deepcopy__(self, memo): """Make this equivalent to "shallow" copy. - Returns a new MeshCoord based on the same Mesh. + Returns a new MeshCoord based on the same MeshXY. - Required to prevent cube copying from copying the Mesh, which would + Required to prevent cube copying from copying the MeshXY, which would prevent "cube.copy() == cube" : see notes for :meth:`copy`. """ @@ -2982,17 +3022,17 @@ def _construct_access_arrays(self): """Build lazy points and bounds arrays. Build lazy points and bounds arrays, providing dynamic access via the - Mesh, according to the location and axis. + MeshXY, according to the location and axis. Returns ------- array or None Tuple of (points, bounds). Lazy arrays which calculate the correct points and bounds from the - Mesh data, based on the location and axis. - The Mesh coordinates accessed are not identified on construction, - but discovered from the Mesh at the time of calculation, so that - the result is always based on current content in the Mesh. + MeshXY data, based on the location and axis. + The MeshXY coordinates accessed are not identified on construction, + but discovered from the MeshXY at the time of calculation, so that + the result is always based on current content in the MeshXY. """ mesh, location, axis = self.mesh, self.location, self.axis diff --git a/lib/iris/experimental/ugrid/metadata.py b/lib/iris/experimental/ugrid/metadata.py index bc7cc677f7..28b9f413d9 100644 --- a/lib/iris/experimental/ugrid/metadata.py +++ b/lib/iris/experimental/ugrid/metadata.py @@ -139,7 +139,7 @@ def equal(self, other, lenient=None): class MeshMetadata(BaseMetadata): - """Metadata container for a :class:`~iris.experimental.ugrid.mesh.Mesh`.""" + """Metadata container for a :class:`~iris.experimental.ugrid.mesh.MeshXY`.""" # The node_dimension", "edge_dimension" and "face_dimension" members are # stateful only; they not participate in lenient/strict equivalence. @@ -262,8 +262,8 @@ class MeshCoordMetadata(BaseMetadata): _members = ("location", "axis") # NOTE: in future, we may add 'mesh' as part of this metadata, - # as the Mesh seems part of the 'identity' of a MeshCoord. - # For now we omit it, particularly as we don't yet implement Mesh.__eq__. + # as the MeshXY seems part of the 'identity' of a MeshCoord. + # For now we omit it, particularly as we don't yet implement MeshXY.__eq__. # # Thus, for now, the MeshCoord class will need to handle 'mesh' explicitly # in identity / comparison, but in future that may be simplified. diff --git a/lib/iris/experimental/ugrid/save.py b/lib/iris/experimental/ugrid/save.py index 8cfa6ba97a..ddd7e5333c 100644 --- a/lib/iris/experimental/ugrid/save.py +++ b/lib/iris/experimental/ugrid/save.py @@ -3,7 +3,7 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. -"""Extension to Iris' NetCDF saving to allow :class:`~iris.experimental.ugrid.mesh.Mesh` saving in UGRID format. +"""Extension to Iris' NetCDF saving to allow :class:`~iris.experimental.ugrid.mesh.MeshXY` saving in UGRID format. Eventual destination: :mod:`iris.fileformats.netcdf`. @@ -19,7 +19,7 @@ def save_mesh(mesh, filename, netcdf_format="NETCDF4"): Parameters ---------- - mesh : :class:`iris.experimental.ugrid.Mesh` or iterable + mesh : :class:`iris.experimental.ugrid.MeshXY` or iterable Mesh(es) to save. filename : str Name of the netCDF file to create. diff --git a/lib/iris/experimental/ugrid/utils.py b/lib/iris/experimental/ugrid/utils.py index 0074619bf2..b78545c42e 100644 --- a/lib/iris/experimental/ugrid/utils.py +++ b/lib/iris/experimental/ugrid/utils.py @@ -31,7 +31,7 @@ def recombine_submeshes( Describes the mesh and mesh-location onto which the all the ``submesh-cubes``' data are mapped, and acts as a template for the result. - Must have a :class:`~iris.experimental.ugrid.mesh.Mesh`. + Must have a :class:`~iris.experimental.ugrid.mesh.MeshXY`. submesh_cubes : iterable of Cube, or Cube Cubes, each with data on a _subset_ of the ``mesh_cube`` datapoints diff --git a/lib/iris/fileformats/netcdf/saver.py b/lib/iris/fileformats/netcdf/saver.py index 379b0797c6..179adaf9cd 100644 --- a/lib/iris/fileformats/netcdf/saver.py +++ b/lib/iris/fileformats/netcdf/saver.py @@ -271,7 +271,7 @@ def _setncattr(variable, name, attribute): return variable.setncattr(name, attribute) -# NOTE : this matches :class:`iris.experimental.ugrid.mesh.Mesh.ELEMENTS`, +# NOTE : this matches :class:`iris.experimental.ugrid.mesh.MeshXY.ELEMENTS`, # but in the preferred order for coord/connectivity variables in the file. MESH_ELEMENTS = ("node", "edge", "face") @@ -766,7 +766,7 @@ def _add_mesh(self, cube_or_mesh): Parameters ---------- - cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.Mesh` + cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.MeshXY` The Cube or Mesh being saved to the netCDF file. Returns @@ -942,10 +942,10 @@ def _add_aux_coords(self, cube, cf_var_cube, dimension_names): Names associated with the dimensions of the cube. """ from iris.experimental.ugrid.mesh import ( - Mesh, MeshEdgeCoords, MeshFaceCoords, MeshNodeCoords, + MeshXY, ) # Exclude any mesh coords, which are bundled in with the aux-coords. @@ -954,7 +954,7 @@ def _add_aux_coords(self, cube, cf_var_cube, dimension_names): ] # Include any relevant mesh location coordinates. - mesh: Mesh | None = getattr(cube, "mesh") + mesh: MeshXY | None = getattr(cube, "mesh") mesh_location: str | None = getattr(cube, "location") if mesh and mesh_location: location_coords: MeshNodeCoords | MeshEdgeCoords | MeshFaceCoords = getattr( @@ -1120,7 +1120,7 @@ def _get_dim_names(self, cube_or_mesh): Parameters ---------- - cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.Mesh` + cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.MeshXY` The Cube or Mesh being saved to the netCDF file. Returns @@ -1228,7 +1228,7 @@ def record_dimension(names_list, dim_name, length, matching_coords=None): # Name it for the relevant mesh dimension location_dim_attr = f"{location}_dimension" dim_name = getattr(mesh, location_dim_attr) - # NOTE: This cannot currently be empty, as a Mesh + # NOTE: This cannot currently be empty, as a MeshXY # "invents" dimension names which were not given. assert dim_name is not None # Ensure it is a valid variable name. @@ -1482,7 +1482,7 @@ def _get_coord_variable_name(self, cube_or_mesh, coord): Parameters ---------- - cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.Mesh` + cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.MeshXY` The Cube or Mesh being saved to the netCDF file. coord : :class:`iris.coords._DimensionalMetadata` An instance of a coordinate (or similar), for which a CF-netCDF @@ -1527,7 +1527,7 @@ def _get_coord_variable_name(self, cube_or_mesh, coord): from iris.experimental.ugrid.mesh import Connectivity # At present, a location-coord cannot be nameless, as the - # Mesh code relies on guess_coord_axis. + # MeshXY code relies on guess_coord_axis. assert isinstance(coord, Connectivity) location = coord.cf_role.split("_")[0] location_dim_attr = f"{location}_dimension" @@ -1544,7 +1544,7 @@ def _get_mesh_variable_name(self, mesh): Parameters ---------- - mesh : :class:`iris.experimental.ugrid.mesh.Mesh` + mesh : :class:`iris.experimental.ugrid.mesh.MeshXY` An instance of a Mesh for which a CF-netCDF variable name is required. @@ -1570,7 +1570,7 @@ def _create_mesh(self, mesh): Parameters ---------- - mesh : :class:`iris.experimental.ugrid.mesh.Mesh` + mesh : :class:`iris.experimental.ugrid.mesh.MeshXY` The Mesh to be saved to CF-netCDF file. Returns @@ -1660,7 +1660,7 @@ def _create_generic_cf_array_var( Parameters ---------- - cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.Mesh` + cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.experimental.ugrid.MeshXY` The Cube or Mesh being saved to the netCDF file. cube_dim_names : list of str The name of each dimension of the cube. diff --git a/lib/iris/tests/integration/experimental/test_ugrid_load.py b/lib/iris/tests/integration/experimental/test_ugrid_load.py index 5735d6b2c1..613e5f4e37 100644 --- a/lib/iris/tests/integration/experimental/test_ugrid_load.py +++ b/lib/iris/tests/integration/experimental/test_ugrid_load.py @@ -19,7 +19,7 @@ from iris import Constraint, load from iris.experimental.ugrid.load import PARSE_UGRID_ON_LOAD, load_mesh, load_meshes -from iris.experimental.ugrid.mesh import Mesh +from iris.experimental.ugrid.mesh import MeshXY from iris.tests.stock.netcdf import ( _file_from_cdl_template as create_file_from_cdl_template, ) @@ -172,7 +172,7 @@ def test_mesh_bad_topology_dimension(self): def test_mesh_no_topology_dimension(self): # Check that the load generates a suitable warning. - warn_regex = r"Mesh variable.* has no 'topology_dimension'" + warn_regex = r"MeshXY variable.* has no 'topology_dimension'" with pytest.warns(IrisCfWarning, match=warn_regex): template = "minimal_bad_topology_dim" dim_line = "" # don't create ANY topology_dimension property @@ -212,7 +212,7 @@ def common_test(self, file_name, mesh_var_name): tests.get_data_path(["NetCDF", "unstructured_grid", file_name]) ) # NOTE: cannot use CML tests as this isn't supported for non-Cubes. - self.assertIsInstance(mesh, Mesh) + self.assertIsInstance(mesh, MeshXY) self.assertEqual(mesh.var_name, mesh_var_name) def test_full_file(self): diff --git a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex1_1d_mesh.cdl b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex1_1d_mesh.cdl index d022fedc61..faf86c04c5 100644 --- a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex1_1d_mesh.cdl +++ b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex1_1d_mesh.cdl @@ -6,7 +6,7 @@ nMesh1_edge = 4 ; // nEdges Two = 2; variables: -// Mesh topology +// MeshXY topology integer Mesh1 ; Mesh1:cf_role = "mesh_topology" ; Mesh1:long_name = "Topology data of 1D network" ; @@ -19,7 +19,7 @@ Mesh1_edge_nodes:cf_role = "edge_node_connectivity" ; Mesh1_edge_nodes:long_name = "Maps every edge/link to the two nodes that it connects." ; Mesh1_edge_nodes:start_index = 1 ; -// Mesh node coordinates +// MeshXY node coordinates double Mesh1_node_x(nMesh1_node) ; Mesh1_node_x:standard_name = "longitude" ; Mesh1_node_x:long_name = "Longitude of 1D network nodes." ; diff --git a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex2_2d_triangular.cdl b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex2_2d_triangular.cdl index 1e4e483826..0dd01a3c62 100644 --- a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex2_2d_triangular.cdl +++ b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex2_2d_triangular.cdl @@ -8,7 +8,7 @@ Two = 2 ; Three = 3 ; variables: -// Mesh topology +// MeshXY topology integer Mesh2 ; Mesh2:cf_role = "mesh_topology" ; Mesh2:long_name = "Topology data of 2D unstructured mesh" ; @@ -50,7 +50,7 @@ Mesh2_edge_face_links:start_index = 1 ; Mesh2_edge_face_links:_FillValue = -999 ; Mesh2_edge_face_links:comment = "missing neighbor faces are indicated using _FillValue" ; -// Mesh node coordinates +// MeshXY node coordinates double Mesh2_node_x(nMesh2_node) ; Mesh2_node_x:standard_name = "longitude" ; Mesh2_node_x:long_name = "Longitude of 2D mesh nodes." ; diff --git a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex3_2d_flexible.cdl b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex3_2d_flexible.cdl index 2fa077d152..fbbd3aa544 100644 --- a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex3_2d_flexible.cdl +++ b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex3_2d_flexible.cdl @@ -8,7 +8,7 @@ nMaxMesh2_face_nodes = 4 ; // MaxNumNodesPerFace Two = 2 ; variables: -// Mesh topology +// MeshXY topology integer Mesh2 ; Mesh2:cf_role = "mesh_topology" ; Mesh2:long_name = "Topology data of 2D unstructured mesh" ; @@ -52,7 +52,7 @@ Mesh2_edge_face_links:start_index = 1 ; Mesh2_edge_face_links:_FillValue = -999 ; Mesh2_edge_face_links:comment = "missing neighbor faces are indicated using _FillValue" ; -// Mesh node coordinates +// MeshXY node coordinates double Mesh2_node_x(nMesh2_node) ; Mesh2_node_x:standard_name = "longitude" ; Mesh2_node_x:long_name = "Longitude of 2D mesh nodes." ; diff --git a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex4_3d_layered.cdl b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex4_3d_layered.cdl index d154502018..48fab9bdd7 100644 --- a/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex4_3d_layered.cdl +++ b/lib/iris/tests/integration/experimental/ugrid_conventions_examples/ugrid_ex4_3d_layered.cdl @@ -9,7 +9,7 @@ Mesh2_layers = 10 ; Two = 2 ; variables: -// Mesh topology +// MeshXY topology integer Mesh2 ; Mesh2:cf_role = "mesh_topology" ; Mesh2:long_name = "Topology data of 2D unstructured mesh" ; @@ -53,7 +53,7 @@ Mesh2_edge_face_links:start_index = 1 ; Mesh2_edge_face_links:_FillValue = -999 ; Mesh2_edge_face_links:comment = "missing neighbor faces are indicated using _FillValue" ; -// Mesh node coordinates +// MeshXY node coordinates double Mesh2_node_x(nMesh2_node) ; Mesh2_node_x:standard_name = "longitude" ; Mesh2_node_x:long_name = "Longitude of 2D mesh nodes." ; diff --git a/lib/iris/tests/stock/__init__.py b/lib/iris/tests/stock/__init__.py index 822dd6a6c1..e6ef0356a6 100644 --- a/lib/iris/tests/stock/__init__.py +++ b/lib/iris/tests/stock/__init__.py @@ -837,10 +837,10 @@ def flatten_dim_metadata(dim_metadata: icoords._DimensionalMetadata): new_instance = dim_metadata.__class__(flat_values, **kwargs) return new_instance - def remove_duplicate_nodes(mesh: ugrid.Mesh): + def remove_duplicate_nodes(mesh: ugrid.MeshXY): """Remove duplicate nodes from a mesh. - Mesh.from_coords() does not do this due to complications like lazy + MeshXY.from_coords() does not do this due to complications like lazy arrays. Not a problem here. """ # TODO: @@ -885,7 +885,7 @@ def remove_duplicate_nodes(mesh: ugrid.Mesh): return mesh - new_mesh = ugrid.Mesh.from_coords( + new_mesh = ugrid.MeshXY.from_coords( flatten_dim_metadata(default_lon), flatten_dim_metadata(default_lat), ) diff --git a/lib/iris/tests/stock/mesh.py b/lib/iris/tests/stock/mesh.py index cd092fb66c..6333374d6c 100644 --- a/lib/iris/tests/stock/mesh.py +++ b/lib/iris/tests/stock/mesh.py @@ -8,9 +8,9 @@ from iris.coords import AuxCoord, DimCoord from iris.cube import Cube -from iris.experimental.ugrid.mesh import Connectivity, Mesh, MeshCoord +from iris.experimental.ugrid.mesh import Connectivity, MeshCoord, MeshXY -# Default creation controls for creating a test Mesh. +# Default creation controls for creating a test MeshXY. # Note: we're not creating any kind of sensible 'normal' mesh here, the numbers # of nodes/faces/edges are quite arbitrary and the connectivities we generate # are pretty random too. @@ -30,7 +30,7 @@ def sample_mesh( ): """Make a test mesh. - Mesh has nodes, plus faces and/or edges, with face-coords and edge-coords, + MeshXY has nodes, plus faces and/or edges, with face-coords and edge-coords, numbers of which can be controlled. Parameters @@ -118,7 +118,7 @@ def sample_mesh( face_y = AuxCoord(3200 + arr.arange(n_faces), standard_name="latitude") face_coords_and_axes = [(face_x, "x"), (face_y, "y")] - mesh = Mesh( + mesh = MeshXY( topology_dimension=2, node_coords_and_axes=[(node_x, "x"), (node_y, "y")], connectivities=connectivities, @@ -142,7 +142,7 @@ def sample_meshcoord(mesh=None, location="face", axis="x", **extra_kwargs): def sample_mesh_cube(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). + """Create a 2d test cube with 1 'normal' and 1 unstructured dimension (with a MeshXY). Result contains : dimcoords for both dims; an auxcoord on the unstructured dim; 2 mesh-coords. diff --git a/lib/iris/tests/unit/coords/test__DimensionalMetadata.py b/lib/iris/tests/unit/coords/test__DimensionalMetadata.py index da0dccd873..6aaa26e5a9 100644 --- a/lib/iris/tests/unit/coords/test__DimensionalMetadata.py +++ b/lib/iris/tests/unit/coords/test__DimensionalMetadata.py @@ -885,7 +885,7 @@ def test_meshcoord(self): "[...]+bounds shape(3,)>" ), "MeshCoord : longitude / (unknown)", - " mesh: ", + " mesh: ", " location: 'face'", " points: [3100, 3101, 3102]", " bounds: [", diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index 8ae42448c7..878a793448 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -2210,7 +2210,7 @@ def test_fail_meshcoords_different_meshes(self): meshco_y = sample_meshcoord(axis="y") # Own (different) mesh meshco_y.mesh.long_name = "new_name" n_faces = meshco_x.shape[0] - with self.assertRaisesRegex(ValueError, "Mesh.* does not match"): + with self.assertRaisesRegex(ValueError, "MeshXY.* does not match"): Cube( np.zeros(n_faces), aux_coords_and_dims=[(meshco_x, 0), (meshco_y, 0)], diff --git a/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh.py b/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh.py index b897f4f0c0..a47d093af0 100644 --- a/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh.py +++ b/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh.py @@ -65,7 +65,7 @@ class TestProperties1D(TestMeshCommon): @classmethod def setUpClass(cls): super().setUpClass() - # Mesh kwargs with topology_dimension=1 and all applicable + # MeshXY kwargs with topology_dimension=1 and all applicable # arguments populated - this tests correct property setting. cls.kwargs = { "topology_dimension": 1, @@ -78,7 +78,7 @@ def setUpClass(cls): "edge_dimension": "EdgeDim", "edge_coords_and_axes": ((cls.EDGE_LON, "x"), (cls.EDGE_LAT, "y")), } - cls.mesh = mesh.Mesh(**cls.kwargs) + cls.mesh = mesh.MeshXY(**cls.kwargs) def test__metadata_manager(self): self.assertEqual( @@ -95,12 +95,12 @@ def test___getstate__(self): self.assertEqual(expected, self.mesh.__getstate__()) def test___repr__(self): - expected = "" + expected = "" self.assertEqual(expected, repr(self.mesh)) def test___str__(self): expected = [ - "Mesh : 'my_topology_mesh'", + "MeshXY : 'my_topology_mesh'", " topology_dimension: 1", " node", " node_dimension: 'NodeDim'", @@ -127,13 +127,13 @@ def test___eq__(self): # The dimension names do not participate in equality. equivalent_kwargs = self.kwargs.copy() equivalent_kwargs["node_dimension"] = "something_else" - equivalent = mesh.Mesh(**equivalent_kwargs) + equivalent = mesh.MeshXY(**equivalent_kwargs) self.assertEqual(equivalent, self.mesh) def test_different(self): different_kwargs = self.kwargs.copy() different_kwargs["long_name"] = "new_name" - different = mesh.Mesh(**different_kwargs) + different = mesh.MeshXY(**different_kwargs) self.assertNotEqual(different, self.mesh) different_kwargs = self.kwargs.copy() @@ -141,14 +141,14 @@ def test_different(self): new_lat = ncaa[1][0].copy(points=ncaa[1][0].points + 1) new_ncaa = (ncaa[0], (new_lat, "y")) different_kwargs["node_coords_and_axes"] = new_ncaa - different = mesh.Mesh(**different_kwargs) + different = mesh.MeshXY(**different_kwargs) self.assertNotEqual(different, self.mesh) different_kwargs = self.kwargs.copy() conns = self.kwargs["connectivities"] new_conn = conns[0].copy(conns[0].indices + 1) different_kwargs["connectivities"] = new_conn - different = mesh.Mesh(**different_kwargs) + different = mesh.MeshXY(**different_kwargs) self.assertNotEqual(different, self.mesh) def test_all_connectivities(self): @@ -223,7 +223,7 @@ def test_connectivities_elements(self): self.assertEqual([], func(contains_face=True)) def test_coord(self): - # See Mesh.coords tests for thorough coverage of cases. + # See MeshXY.coords tests for thorough coverage of cases. func = self.mesh.coord exception = CoordinateNotFoundError self.assertRaisesRegex(exception, ".*but found 2", func, location="node") @@ -360,15 +360,15 @@ def setUpClass(cls): (cls.FACE_LON, "x"), (cls.FACE_LAT, "y"), ) - cls.mesh = mesh.Mesh(**cls.kwargs) + cls.mesh = mesh.MeshXY(**cls.kwargs) def test___repr__(self): - expected = "" + expected = "" self.assertEqual(expected, repr(self.mesh)) def test___str__(self): expected = [ - "Mesh : 'my_topology_mesh'", + "MeshXY : 'my_topology_mesh'", " topology_dimension: 2", " node", " node_dimension: 'NodeDim'", @@ -417,9 +417,9 @@ def test___str__(self): def test___str__noedgecoords(self): mesh_kwargs = self.kwargs.copy() del mesh_kwargs["edge_coords_and_axes"] - alt_mesh = mesh.Mesh(**mesh_kwargs) + alt_mesh = mesh.MeshXY(**mesh_kwargs) expected = [ - "Mesh : 'my_topology_mesh'", + "MeshXY : 'my_topology_mesh'", " topology_dimension: 2", " node", " node_dimension: 'NodeDim'", @@ -487,8 +487,8 @@ def test_boundary_node(self): self.assertEqual(self.BOUNDARY_NODE, self.mesh.boundary_node_connectivity) def test_connectivity(self): - # See Mesh.connectivities tests for thorough coverage of cases. - # Can only test Mesh.connectivity for 2D since we need >1 connectivity. + # See MeshXY.connectivities tests for thorough coverage of cases. + # Can only test MeshXY.connectivity for 2D since we need >1 connectivity. func = self.mesh.connectivity exception = ConnectivityNotFoundError self.assertRaisesRegex(exception, ".*but found 3", func, contains_node=True) @@ -605,7 +605,7 @@ def setUp(self): # All the tests here want modified meshes, so use standard setUp to # create afresh for each test, allowing them to modify it. super().setUp() - # Mesh kwargs with topology_dimension=1 and all applicable + # MeshXY kwargs with topology_dimension=1 and all applicable # arguments populated - this tests correct property setting. self.kwargs = { "topology_dimension": 1, @@ -624,21 +624,21 @@ def setUp(self): (self.EDGE_LAT, "y"), ), } - self.mesh = mesh.Mesh(**self.kwargs) + self.mesh = mesh.MeshXY(**self.kwargs) def test___repr__basic(self): - expected = "" + expected = "" self.assertEqual(expected, repr(self.mesh)) def test___repr__varname(self): self.mesh.long_name = None - expected = "" + expected = "" self.assertEqual(expected, repr(self.mesh)) def test___repr__noname(self): self.mesh.long_name = None self.mesh.var_name = None - expected = "" + expected = "" self.assertRegex(repr(self.mesh), expected) def test___str__noattributes(self): @@ -667,7 +667,7 @@ def test___str__units_stdname(self): mesh_kwargs = self.kwargs.copy() mesh_kwargs["standard_name"] = "height" # Odd choice ! mesh_kwargs["units"] = "m" - alt_mesh = mesh.Mesh(**mesh_kwargs) + alt_mesh = mesh.MeshXY(**mesh_kwargs) result = str(alt_mesh) # We expect these to appear at the end. expected = "\n".join( @@ -687,10 +687,10 @@ def test___str__units_stdname(self): class TestOperations1D(TestMeshCommon): - # Tests that cannot reuse an existing Mesh instance, instead need a new + # Tests that cannot reuse an existing MeshXY instance, instead need a new # one each time. def setUp(self): - self.mesh = mesh.Mesh( + self.mesh = mesh.MeshXY( topology_dimension=1, node_coords_and_axes=((self.NODE_LON, "x"), (self.NODE_LAT, "y")), connectivities=self.EDGE_NODE, @@ -1024,7 +1024,7 @@ def test_to_MeshCoords_face(self): class TestOperations2D(TestOperations1D): # Additional/specialised tests for topology_dimension=2. def setUp(self): - self.mesh = mesh.Mesh( + self.mesh = mesh.MeshXY( topology_dimension=2, node_coords_and_axes=((self.NODE_LON, "x"), (self.NODE_LAT, "y")), connectivities=(self.FACE_NODE), @@ -1208,7 +1208,7 @@ def test_invalid_topology(self): self.assertRaisesRegex( ValueError, "Expected 'topology_dimension'.*", - mesh.Mesh, + mesh.MeshXY, **kwargs, ) @@ -1220,7 +1220,7 @@ def test_invalid_axes(self): self.assertRaisesRegex( ValueError, "Invalid axis specified for node.*", - mesh.Mesh, + mesh.MeshXY, node_coords_and_axes=( (self.NODE_LON, "foo"), (self.NODE_LAT, "y"), @@ -1234,14 +1234,14 @@ def test_invalid_axes(self): self.assertRaisesRegex( ValueError, "Invalid axis specified for edge.*", - mesh.Mesh, + mesh.MeshXY, edge_coords_and_axes=((self.EDGE_LON, "foo"),), **kwargs, ) self.assertRaisesRegex( ValueError, "Invalid axis specified for face.*", - mesh.Mesh, + mesh.MeshXY, face_coords_and_axes=((self.FACE_LON, "foo"),), **kwargs, ) @@ -1261,7 +1261,7 @@ def test_minimum_connectivities(self): self.assertRaisesRegex( ValueError, ".*requires a edge_node_connectivity.*", - mesh.Mesh, + mesh.MeshXY, **kwargs, ) @@ -1275,7 +1275,7 @@ def test_minimum_coords(self): self.assertRaisesRegex( ValueError, ".*is a required coordinate.*", - mesh.Mesh, + mesh.MeshXY, **kwargs, ) 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 3549e305e5..3f81085fa9 100644 --- a/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py +++ b/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py @@ -21,7 +21,7 @@ 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 +from iris.experimental.ugrid.mesh import Connectivity, MeshCoord, MeshXY import iris.tests.stock.mesh from iris.tests.stock.mesh import sample_mesh, sample_meshcoord from iris.warnings import IrisVagueMetadataWarning @@ -50,7 +50,7 @@ def test_basic(self): def test_derived_properties(self): # Check the derived properties of the meshcoord against the correct # underlying mesh coordinate. - for axis in Mesh.AXES: + for axis in MeshXY.AXES: meshcoord = sample_meshcoord(axis=axis) face_x_coord = meshcoord.mesh.coord(location="face", axis=axis) for key in face_x_coord.metadata._fields: @@ -63,16 +63,16 @@ def test_fail_bad_mesh(self): sample_meshcoord(mesh=mock.sentinel.odd) def test_valid_locations(self): - for loc in Mesh.ELEMENTS: + for loc in MeshXY.ELEMENTS: meshcoord = sample_meshcoord(location=loc) self.assertEqual(meshcoord.location, loc) def test_fail_bad_location(self): - with self.assertRaisesRegex(ValueError, "not a valid Mesh location"): + with self.assertRaisesRegex(ValueError, "not a valid MeshXY location"): sample_meshcoord(location="bad") def test_fail_bad_axis(self): - with self.assertRaisesRegex(ValueError, "not a valid Mesh axis"): + with self.assertRaisesRegex(ValueError, "not a valid MeshXY axis"): sample_meshcoord(axis="q") @@ -280,7 +280,7 @@ def _expected_elements_regexp( # Construct regexp in 'sections' # NB each consumes up to first non-space in the next line regexp = f"MeshCoord : {coord_name} / [^\n]+\n *" - regexp += r"mesh: \\n *" + regexp += r"mesh: \\n *" regexp += f"location: '{location}'\n *" # Now some optional sections : whichever comes first will match @@ -349,7 +349,7 @@ def test_repr__nameless_mesh(self): result = repr(self.meshcoord) re_expected = ( r".MeshCoord: longitude / \(unknown\) " - r"mesh\(.Mesh object at 0x[^>]+.\) location\(face\) " + r"mesh\(.MeshXY object at 0x[^>]+.\) location\(face\) " ) self.assertRegex(result, re_expected) @@ -607,7 +607,7 @@ def lazify(arr): co_edgex = AuxCoord( edge_xs, standard_name="longitude", long_name="edge_x", units=1 ) - # N.B. the Mesh requires 'Y's as well. + # N.B. the MeshXY requires 'Y's as well. co_nodey = co_nodex.copy() co_nodey.rename("latitude") co_nodey.long_name = "node_y" @@ -644,7 +644,7 @@ def lazify(arr): location_axis=inds_location_axis, ) - self.mesh = Mesh( + self.mesh = MeshXY( topology_dimension=2, node_coords_and_axes=[(co_nodex, "x"), (co_nodey, "y")], connectivities=[face_node_conn, edge_node_conn], @@ -875,7 +875,7 @@ def test_faceedge_fail_missing_stdnames(self, location_face_or_edge, axis_x_or_y 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. + # property, or the coordinate cannot be correctly identified in the MeshXY. # This is a bit of a kludge, but works with current code. self.node_coord.axis = axis_x_or_y diff --git a/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py b/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py index aa45e0be70..8ea9c81060 100644 --- a/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py +++ b/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py @@ -2,7 +2,7 @@ # # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. -"""Unit tests for the :meth:`iris.experimental.ugrid.mesh.Mesh.from_coords`.""" +"""Unit tests for the :meth:`iris.experimental.ugrid.mesh.MeshXY.from_coords`.""" # Import iris.tests first so that some things can be initialised before # importing anything else. @@ -12,7 +12,7 @@ from iris.coords import AuxCoord, DimCoord from iris.experimental.ugrid import logger -from iris.experimental.ugrid.mesh import Connectivity, Mesh +from iris.experimental.ugrid.mesh import Connectivity, MeshXY from iris.tests.stock import simple_2d_w_multidim_coords @@ -39,7 +39,7 @@ def setUp(self): ) def create(self): - return Mesh.from_coords(self.lon, self.lat) + return MeshXY.from_coords(self.lon, self.lat) def test_dimensionality(self): mesh = self.create() @@ -207,7 +207,7 @@ def test_no_bounds(self): lon = AuxCoord(points=[0.5, 1.5, 2.5]) lat = AuxCoord(points=[0, 1, 2]) with self.assertRaisesRegex(ValueError, "bounds missing from"): - _ = Mesh.from_coords(lon, lat) + _ = MeshXY.from_coords(lon, lat) def test_1_bound(self): lon = AuxCoord(points=[0.5, 1.5, 2.5], bounds=[[0], [1], [2]]) @@ -215,7 +215,7 @@ def test_1_bound(self): with self.assertRaisesRegex( ValueError, r"Expected coordinate bounds.shape \(n, >=2\)" ): - _ = Mesh.from_coords(lon, lat) + _ = MeshXY.from_coords(lon, lat) class TestInvalidPoints(tests.IrisTest): @@ -225,4 +225,4 @@ def test_2d_coord(self): cube = simple_2d_w_multidim_coords()[:3, :3] coord_1, coord_2 = cube.coords() with self.assertRaisesRegex(ValueError, "Expected coordinate ndim == 1"): - _ = Mesh.from_coords(coord_1, coord_2) + _ = MeshXY.from_coords(coord_1, coord_2) diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py index 599650d759..e86ecf9a52 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py @@ -22,7 +22,7 @@ from iris import save from iris.coords import AuxCoord from iris.cube import Cube, CubeList -from iris.experimental.ugrid.mesh import Connectivity, Mesh +from iris.experimental.ugrid.mesh import Connectivity, MeshXY from iris.experimental.ugrid.save import save_mesh from iris.fileformats.netcdf import _thread_safe_nc from iris.tests.stock import realistic_4d @@ -115,7 +115,7 @@ def apply_xyargs(coords, xyargs): connectivities[role] = conn applyargs(conn, kwargs) - mesh = Mesh( + mesh = MeshXY( topology_dimension=topology_dimension, node_coords_and_axes=zip(node_coords, XY_LOCS), edge_coords_and_axes=zip(edge_coords, XY_LOCS), @@ -196,7 +196,7 @@ def make_cube(mesh=None, location="face", **kwargs): Parameters ---------- - mesh : :class:`iris.experimental.ugrid.mesh.Mesh` or None, optional + mesh : :class:`iris.experimental.ugrid.mesh.MeshXY` or None, optional If None, use 'default_mesh()' location : str, optional, default="face" Which mesh element to map the cube to. @@ -719,7 +719,7 @@ def test_connectivity_dim_order(self): nodesfirst_faces_conn = face_nodes_conn.transpose() nodesfirst_edges_conn = edge_nodes_conn.transpose() # Make a new mesh with both face and edge connectivities 'transposed'. - mesh2 = Mesh( + mesh2 = MeshXY( topology_dimension=mesh.topology_dimension, node_coords_and_axes=zip(mesh.node_coords, XY_LOCS), face_coords_and_axes=zip(mesh.face_coords, XY_LOCS), @@ -768,7 +768,7 @@ def test_connectivity_start_index(self): start_index=1, ) # Make a new mesh with altered connectivities. - mesh2 = Mesh( + mesh2 = MeshXY( topology_dimension=mesh.topology_dimension, node_coords_and_axes=zip(mesh.node_coords, XY_LOCS), face_coords_and_axes=zip(mesh.face_coords, XY_LOCS), @@ -870,7 +870,7 @@ def test_one_dimensional(self): def test_location_coord_units(self): # Check that units on mesh locations are handled correctly. - # NOTE: at present, the Mesh class cannot handle coordinates that are + # NOTE: at present, the MeshXY class cannot handle coordinates that are # not recognised by 'guess_coord_axis' == suitable standard names mesh = make_mesh( nodecoord_xyargs=( @@ -954,7 +954,7 @@ def test_mesh_names(self): (None, None, "meshvar_x"), (None, None, "meshvar_x"), ), - # standard_name only : does not apply to Mesh + # standard_name only : does not apply to MeshXY ( ("air_temperature", None, None), ("air_temperature", None, "Mesh_2d"), @@ -1017,7 +1017,7 @@ def test_location_coord_names(self): # N.B. this is basically centralised in Saver._get_mesh_variable_name, # but we test in an implementation-neutral way (as it's fairly easy). - # Options here are limited because the Mesh relies on guess_axis so, + # Options here are limited because the MeshXY relies on guess_axis so, # for now anyway, coords *must* have a known X/Y-type standard-name coord_names_tests = [ # standard_name only @@ -1041,7 +1041,7 @@ def test_location_coord_names(self): ("projection_x_coordinate", "long name", "x_var_name"), ), # # no standard name ? - # # not possible at present, as Mesh requires a recognisable + # # not possible at present, as MeshXY requires a recognisable # # standard_name to identify the axis of a location-coord. # # TODO: test this if+when Mesh usage is relaxed # ( diff --git a/lib/iris/tests/unit/tests/stock/test_netcdf.py b/lib/iris/tests/unit/tests/stock/test_netcdf.py index dbdd321663..e88d3f6abb 100644 --- a/lib/iris/tests/unit/tests/stock/test_netcdf.py +++ b/lib/iris/tests/unit/tests/stock/test_netcdf.py @@ -9,7 +9,7 @@ from iris import load_cube from iris.experimental.ugrid.load import PARSE_UGRID_ON_LOAD -from iris.experimental.ugrid.mesh import Mesh, MeshCoord +from iris.experimental.ugrid.mesh import MeshCoord, MeshXY # Import iris.tests first so that some things can be initialised before # importing anything else. @@ -50,7 +50,7 @@ def check_cube(self, cube, shape, location, level): # Also a few checks on the attached mesh-related information. last_dim = cube.ndim - 1 - self.assertIsInstance(cube.mesh, Mesh) + self.assertIsInstance(cube.mesh, MeshXY) self.assertEqual(cube.mesh_dim(), last_dim) self.assertEqual(cube.location, location) for coord_name in ("longitude", "latitude"):