Skip to content

Commit

Permalink
Mesh nonexperimental (#6061)
Browse files Browse the repository at this point in the history
* Move all iris.experimental.ugrid to iris.ugrid.

Replace experiment.ugrid, including docstrings and imports.

Fix test_ParseUgridOnLoad

Fix ugrid.load.

Remove PARSE_UGRID from t/i/ugrid/test_ugrid_save

Remove PARSE_UGRID from t/u/ff/nc/saver/test_save

Remove PARSE_UGRID from t/i/exp/geovista/(both)

Remove PARSE_UGRID from t/u/tests/stock/test_netcdf

* Adjust references in docs.

* Fix type.

* Workaround docs build problem.

Include alternative index workaround.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix Mesh -> MeshXY in experimental.ugrid

* Import annotations in new files.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
pp-mo and pre-commit-ci[bot] authored Jul 25, 2024
1 parent c333b7f commit 7c87fb2
Show file tree
Hide file tree
Showing 72 changed files with 416 additions and 323 deletions.
78 changes: 39 additions & 39 deletions docs/src/further_topics/ugrid/data_model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ How Iris Represents This
.. seealso::

Remember this is a prose summary. Precise documentation is at:
:mod:`iris.experimental.ugrid`.
:mod:`iris.ugrid`.

.. note::

Expand All @@ -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.MeshXY` that describes the
| The :class:`iris.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
Expand All @@ -320,10 +320,10 @@ 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.MeshXY`.
associated :class:`~iris.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.
:class:`iris.ugrid.MeshCoord`\s (one for each axis e.g.
``x``/``y``), which can be used to infer the points and bounds of any index on
the :class:`~iris.cube.Cube`\'s unstructured dimension.

Expand All @@ -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, MeshXY
from iris.ugrid import Connectivity, MeshXY

node_x = AuxCoord(
points=[0.0, 5.0, 0.0, 5.0, 8.0],
Expand Down Expand Up @@ -422,38 +422,38 @@ The Detail
----------
How UGRID information is stored
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* | :class:`iris.experimental.ugrid.MeshXY`
* | :class:`iris.ugrid.MeshXY`
| Contains all information about the mesh.
| Includes:
* | :attr:`~iris.experimental.ugrid.MeshXY.topology_dimension`
* | :attr:`~iris.ugrid.MeshXY.topology_dimension`
| The maximum dimensionality of shape (1D=edge, 2D=face) supported
by this :class:`~iris.experimental.ugrid.MeshXY`. Determines which
:class:`~iris.experimental.ugrid.Connectivity`\s are required/optional
by this :class:`~iris.ugrid.MeshXY`. Determines which
:class:`~iris.ugrid.Connectivity`\s are required/optional
(see below).
* 1-3 collections of :class:`iris.coords.AuxCoord`\s:

* | **Required**: :attr:`~iris.experimental.ugrid.MeshXY.node_coords`
* | **Required**: :attr:`~iris.ugrid.MeshXY.node_coords`
| The nodes that are the basis for the mesh.
* | Optional: :attr:`~iris.experimental.ugrid.MeshXY.edge_coords`,
:attr:`~iris.experimental.ugrid.MeshXY.face_coords`
* | Optional: :attr:`~iris.ugrid.Mesh.edge_coords`,
:attr:`~iris.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.MeshXY` currently (``Jan 2022``)
| **NOTE:** generating a :class:`~iris.ugrid.MeshCoord` from
a :class:`~iris.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:
* 1 or more :class:`iris.ugrid.Connectivity`\s:

* | **Required for 1D (edge) elements**:
:attr:`~iris.experimental.ugrid.MeshXY.edge_node_connectivity`
:attr:`~iris.ugrid.MeshXY.edge_node_connectivity`
| Define the edges by connecting nodes.
* | **Required for 2D (face) elements**:
:attr:`~iris.experimental.ugrid.MeshXY.face_node_connectivity`
:attr:`~iris.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
:attr:`iris.ugrid.mesh.Connectivity.UGRID_CF_ROLES` for the
full list of types.

.. doctest:: ugrid_summaries
Expand All @@ -480,54 +480,54 @@ How UGRID information is stored
<AuxCoord: latitude / (degrees_north) [...] shape(2,)>
long_name: 'my_mesh'

* | :class:`iris.experimental.ugrid.MeshCoord`
* | :class:`iris.ugrid.MeshCoord`
| Described in detail in `MeshCoords`_.
| Stores the following information:
* | :attr:`~iris.experimental.ugrid.MeshCoord.mesh`
| The :class:`~iris.experimental.ugrid.MeshXY` associated with this
:class:`~iris.experimental.ugrid.MeshCoord`. This determines the
* | :attr:`~iris.ugrid.MeshCoord.mesh`
| The :class:`~iris.ugrid.MeshXY` associated with this
:class:`~iris.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
this :class:`~iris.ugrid.MeshCoord` is attached to (see
`The Basics`_)
* | :attr:`~iris.experimental.ugrid.MeshCoord.location`
* | :attr:`~iris.ugrid.MeshCoord.location`
| ``node``/``edge``/``face`` - the element detailed by this
:class:`~iris.experimental.ugrid.MeshCoord`. This determines the
:class:`~iris.ugrid.MeshCoord`. This determines the
:attr:`~iris.cube.Cube.location` attribute of any
:class:`~iris.cube.Cube` this
:class:`~iris.experimental.ugrid.MeshCoord` is attached to (see
:class:`~iris.ugrid.MeshCoord` is attached to (see
`The Basics`_).
.. _ugrid MeshCoords:

MeshCoords
~~~~~~~~~~
Links a :class:`~iris.cube.Cube` to a :class:`~iris.experimental.ugrid.MeshXY` by
Links a :class:`~iris.cube.Cube` to a :class:`~iris.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
:class:`~iris.cube.Cube` to have a combination of unstructured and structured
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.MeshXY`, ``location``
:class:`~iris.ugrid.MeshCoord`\s are instantiated using a given
:class:`~iris.ugrid.MeshXY`, ``location``
("node"/"edge"/"face") and ``axis``. The process interprets the
: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`
:class:`~iris.ugrid.MeshXY`\'s
:attr:`~iris.ugrid.MeshXY.node_coords` and if appropriate the
:attr:`~iris.ugrid.MeshXY.edge_node_connectivity`/
:attr:`~iris.ugrid.MeshXY.face_node_connectivity` and
:attr:`~iris.ugrid.MeshXY.edge_coords`/
:attr:`~iris.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.MeshXY`\'s
representation of all the :class:`~iris.ugrid.MeshXY`\'s
nodes/edges/faces for the given axis.

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.MeshXY`,
The method :meth:`iris.ugrid.MeshXY.to_MeshCoords` is available to
create a :class:`~iris.ugrid.MeshCoord` for
every axis represented by that :class:`~iris.ugrid.MeshXY`,
given only the ``location`` argument

.. doctest:: ugrid_summaries
Expand Down
2 changes: 1 addition & 1 deletion docs/src/further_topics/ugrid/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Iris includes specialised handling of mesh-located data (as opposed to
grid-located data). Iris and its :ref:`partner packages <ugrid partners>` are
designed to make working with mesh-located data as simple as possible, with new
capabilities being added all the time. More detail is in this section and in
the :mod:`iris.experimental.ugrid` API documentation.
the :mod:`iris.ugrid` API documentation.

This mesh support is based on the `CF-UGRID Conventions`__; UGRID-conformant
meshes + data can be loaded from a file into Iris' data model, and meshes +
Expand Down
70 changes: 35 additions & 35 deletions docs/src/further_topics/ugrid/operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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, MeshXY
>>> from iris.ugrid import Connectivity, MeshXY

# Going to create the following mesh
# (node indices are shown to aid understanding):
Expand Down Expand Up @@ -143,8 +143,8 @@ Making a Cube (with a Mesh)
.. rubric:: |tagline: making a cube|

Creating a :class:`~iris.cube.Cube` is unchanged; the
:class:`~iris.experimental.ugrid.MeshXY` is linked via a
:class:`~iris.experimental.ugrid.MeshCoord` (see :ref:`ugrid MeshCoords`):
:class:`~iris.ugrid.MeshXY` is linked via a
:class:`~iris.ugrid.MeshCoord` (see :ref:`ugrid MeshCoords`):

.. dropdown:: Code
:icon: code
Expand Down Expand Up @@ -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.MeshXY` and automatically
has an associated :class:`~iris.ugrid.MeshXY` and automatically
saves the file in a UGRID-conformant format:

.. dropdown:: Code
Expand Down Expand Up @@ -282,8 +282,8 @@ saves the file in a UGRID-conformant format:
}
<BLANKLINE>

The :func:`iris.experimental.ugrid.save_mesh` function allows
:class:`~iris.experimental.ugrid.MeshXY`\es to be saved to file without
The :func:`iris.ugrid.save_mesh` function allows
:class:`~iris.ugrid.MeshXY`\es to be saved to file without
associated :class:`~iris.cube.Cube`\s:

.. dropdown:: Code
Expand All @@ -293,7 +293,7 @@ associated :class:`~iris.cube.Cube`\s:

>>> from subprocess import run

>>> from iris.experimental.ugrid import save_mesh
>>> from iris.ugrid import save_mesh

>>> mesh_path = "my_mesh.nc"
>>> save_mesh(my_mesh, mesh_path)
Expand Down Expand Up @@ -356,15 +356,15 @@ Load
While Iris' UGRID support remains :mod:`~iris.experimental`, parsing UGRID when
loading a file remains **optional**. To load UGRID data from a file into the
Iris mesh data model, use the
:const:`iris.experimental.ugrid.PARSE_UGRID_ON_LOAD` context manager:
:const:`iris.ugrid.PARSE_UGRID_ON_LOAD` context manager:

.. dropdown:: Code
:icon: code

.. doctest:: ugrid_operations

>>> from iris import load
>>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
>>> from iris.ugrid import PARSE_UGRID_ON_LOAD

>>> with PARSE_UGRID_ON_LOAD.context():
... loaded_cubelist = load(cubelist_path)
Expand Down Expand Up @@ -412,23 +412,23 @@ etcetera:
.. note::

We recommend caution if constraining on coordinates associated with a
:class:`~iris.experimental.ugrid.MeshXY`. An individual coordinate value
:class:`~iris.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
(:ref:`see the data model detail <ugrid implications>`).

The :func:`iris.experimental.ugrid.load_mesh` and
:func:`~iris.experimental.ugrid.load_meshes` functions allow only
:class:`~iris.experimental.ugrid.MeshXY`\es to be loaded from a file without
The :func:`iris.ugrid.load_mesh` and
:func:`~iris.ugrid.load_meshes` functions allow only
:class:`~iris.ugrid.MeshXY`\es to be loaded from a file without
creating any associated :class:`~iris.cube.Cube`\s:

.. dropdown:: Code
:icon: code

.. doctest:: ugrid_operations

>>> from iris.experimental.ugrid import load_mesh
>>> from iris.ugrid import load_mesh

>>> with PARSE_UGRID_ON_LOAD.context():
... loaded_mesh = load_mesh(cubelist_path)
Expand Down Expand Up @@ -493,7 +493,7 @@ GeoVista :external+geovista:doc:`generated/gallery/index`.
>>> from iris import load_cube, sample_data_path
>>> from iris.experimental.geovista import cube_to_polydata
>>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
>>> from iris.ugrid import PARSE_UGRID_ON_LOAD
>>> with PARSE_UGRID_ON_LOAD.context():
... sample_mesh_cube = load_cube(sample_data_path("mesh_C4_synthetic_float.nc"))
Expand Down Expand Up @@ -541,11 +541,11 @@ As described in :doc:`data_model`, indexing for a range along a
:class:`~iris.cube.Cube`\'s :meth:`~iris.cube.Cube.mesh_dim` will not provide
a contiguous region, since **position on the unstructured dimension is
unrelated to spatial position**. This means that subsetted
:class:`~iris.experimental.ugrid.MeshCoord`\s cannot be reliably interpreted
as intended, and subsetting a :class:`~iris.experimental.ugrid.MeshCoord` is
:class:`~iris.ugrid.MeshCoord`\s cannot be reliably interpreted
as intended, and subsetting a :class:`~iris.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.MeshXY`:
:class:`~iris.ugrid.MeshXY`:
.. dropdown:: Code
:icon: code
Expand Down Expand Up @@ -595,7 +595,7 @@ below:
>>> from geovista.geodesic import BBox
>>> from iris import load_cube, sample_data_path
>>> from iris.experimental.geovista import cube_to_polydata, extract_unstructured_region
>>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
>>> from iris.ugrid import PARSE_UGRID_ON_LOAD
>>> with PARSE_UGRID_ON_LOAD.context():
... sample_mesh_cube = load_cube(sample_data_path("mesh_C4_synthetic_float.nc"))
Expand Down Expand Up @@ -667,7 +667,7 @@ with the
>>> from esmf_regrid.experimental.unstructured_scheme import MeshToGridESMFRegridder
>>> from iris import load, load_cube
>>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
>>> from iris.ugrid import PARSE_UGRID_ON_LOAD
# You could also download these files from github.com/SciTools/iris-test-data.
>>> from iris.tests import get_data_path
Expand Down Expand Up @@ -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.MeshXY` (or on the same **grid** in the case of
:class:`~iris.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
Expand Down Expand Up @@ -819,19 +819,19 @@ Equality
.. rubric:: |tagline: equality|
:class:`~iris.experimental.ugrid.MeshXY` comparison is supported, and comparing
two ':class:`~iris.experimental.ugrid.MeshXY`-:class:`~iris.cube.Cube`\s' will
:class:`~iris.ugrid.MeshXY` comparison is supported, and comparing
two ':class:`~iris.ugrid.MeshXY`-:class:`~iris.cube.Cube`\s' will
include a comparison of the respective
:class:`~iris.experimental.ugrid.MeshXY`\es, with no extra action needed by the
:class:`~iris.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.MeshXY`\es, but note that
:class:`~iris.experimental.ugrid.MeshXY`\ equality is enabled for lazy
:class:`~iris.ugrid.MeshXY`\es, but note that
:class:`~iris.ugrid.MeshXY`\ equality is enabled for lazy
processing (:doc:`/userguide/real_and_lazy_data`), so if the
:class:`~iris.experimental.ugrid.MeshXY`\es being compared are lazy the
:class:`~iris.ugrid.MeshXY`\es being compared are lazy the
process will use less memory than their total size.
Combining Cubes
Expand All @@ -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.MeshXY`\es is not possible - a
:class:`~iris.ugrid.MeshXY`\es is not possible - a
:class:`~iris.cube.Cube` must be associated with just a single
:class:`~iris.experimental.ugrid.MeshXY`, and merge/concatenate are not yet
capable of combining multiple :class:`~iris.experimental.ugrid.MeshXY`\es into
:class:`~iris.ugrid.MeshXY`, and merge/concatenate are not yet
capable of combining multiple :class:`~iris.ugrid.MeshXY`\es into
one.

:class:`~iris.cube.Cube`\s that include
:class:`~iris.experimental.ugrid.MeshCoord`\s can still be merged/concatenated
:class:`~iris.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.MeshXY`.
:class:`~iris.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.MeshXY`
:func:`iris.ugrid.recombine_submeshes`, which can be used
for a very specific type of :class:`~iris.ugrid.MeshXY`
combination not detailed here.

Arithmetic
Expand All @@ -869,7 +869,7 @@ Arithmetic

Cube Arithmetic (described in :doc:`/userguide/cube_maths`)
has been extended to handle :class:`~iris.cube.Cube`\s that include
:class:`~iris.experimental.ugrid.MeshCoord`\s, and hence have a ``cube.mesh``.
:class:`~iris.ugrid.MeshCoord`\s, and hence have a ``cube.mesh``.

Cubes with meshes can be combined in arithmetic operations like
"ordinary" cubes. They can combine with other cubes without that mesh
Expand Down
Loading

0 comments on commit 7c87fb2

Please sign in to comment.