Source code for iris.experimental.mesh_coord_indexing
# Copyright Iris contributors
#
# 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.
"""Experimental module for alternative modes of indexing a :class:`~iris.mesh.MeshCoord`.
.. z_reference:: iris.experimental.mesh_coord_indexing
:tags: topic_mesh
API reference
:class:`Options` describes the available indexing modes.
Select the desired option using the run-time setting :data:`SETTING`.
Examples
--------
.. testsetup::
import iris
from iris.experimental.mesh_coord_indexing import SETTING
my_mesh_cube = iris.load_cube(iris.sample_data_path("mesh_C4_synthetic_float.nc"))
# Remove non-compliant content.
my_mesh = my_mesh_cube.mesh
wanted_roles = ["edge_node_connectivity", "face_node_connectivity"]
for conn in my_mesh.all_connectivities:
if conn is not None and conn.cf_role not in wanted_roles:
my_mesh.remove_connectivities(conn)
# Capture original state.
original_setting = SETTING.value
.. testcleanup::
# Restore original state.
SETTING.value = original_setting
Here is a simple :class:`~iris.cube.Cube` with :class:`~iris.mesh.MeshCoord` s:
>>> print(my_mesh_cube)
synthetic / (1) (-- : 96)
Mesh coordinates:
latitude x
longitude x
Mesh:
name Topology data of 2D unstructured mesh
location face
Attributes:
NCO 'netCDF Operators version 4.7.5 (Homepage = http://nco.sf.net, Code = h ...'
history 'Mon Apr 12 01:44:41 2021: ncap2 -s synthetic=float(synthetic) mesh_C4_synthetic.nc ...'
nco_openmp_thread_number 1
>>> print(my_mesh_cube.aux_coords)
(<MeshCoord: latitude / (degrees) mesh(Topology data of 2D unstructured mesh) location(face) [...]+bounds shape(96,)>, <MeshCoord: longitude / (degrees) mesh(Topology data of 2D unstructured mesh) location(face) [...]+bounds shape(96,)>)
Here is the default indexing behaviour:
>>> from iris.experimental import mesh_coord_indexing
>>> print(mesh_coord_indexing.SETTING.value)
Options.AUX_COORD
>>> indexed_cube = my_mesh_cube[:36]
>>> print(indexed_cube.aux_coords)
(<AuxCoord: latitude / (degrees) [29.281, 33.301, ..., 33.301, 29.281]+bounds shape(36,)>, <AuxCoord: longitude / (degrees) [325.894, 348.621, ..., 191.379, 214.106]+bounds shape(36,)>)
Set the indexing mode to return a new mesh:
>>> mesh_coord_indexing.SETTING.value = mesh_coord_indexing.Options.NEW_MESH
>>> indexed_cube = my_mesh_cube[:36]
>>> print(indexed_cube.aux_coords)
(<MeshCoord: latitude / (degrees) mesh(<MeshXY object at ...>) location(face) [...]+bounds shape(36,)>, <MeshCoord: longitude / (degrees) mesh(<MeshXY object at ...>) location(face) [...]+bounds shape(36,)>)
Or set via a context manager:
>>> with mesh_coord_indexing.SETTING.context(mesh_coord_indexing.Options.AUX_COORD):
... indexed_cube = my_mesh_cube[:36]
... print(indexed_cube.aux_coords)
(<AuxCoord: latitude / (degrees) [29.281, 33.301, ..., 33.301, 29.281]+bounds shape(36,)>, <AuxCoord: longitude / (degrees) [325.894, 348.621, ..., 191.379, 214.106]+bounds shape(36,)>)
"""
from contextlib import contextmanager
import enum
import threading
# TODO: update the full documentation
[docs]
class Options(enum.Enum):
"""Options for what is returned when a :class:`~iris.mesh.MeshCoord` is indexed.
See the module docstring for usage instructions:
:mod:`~iris.experimental.mesh_coord_indexing`.
"""
AUX_COORD = enum.auto()
"""The default. Convert the ``MeshCoord`` to a
:class:`~iris.coords.AuxCoord` and index that AuxCoord.
"""
NEW_MESH = enum.auto()
"""Index the :attr:`~iris.mesh.MeshCoord.mesh` of the ``MeshCoord`` to
produce a new :class:`~iris.mesh.MeshXY` instance, then return a new
:class:`~iris.mesh.MeshCoord` instance based on that new mesh. The returned
:class:`~iris.mesh.MeshXY` is generated via the experimental
:class:`~iris.mesh.components._MeshIndexSet` class. While
:class:`~iris.mesh.components._MeshIndexSet` remains experimental, the
properties of the returned :class:`~iris.mesh.MeshXY` instance are liable to
change.
"""
MESH_INDEX_SET = enum.auto()
"""**EXPERIMENTAL.** Produce a :class:`iris.mesh.components._MeshIndexSet`
instance that references the original :class:`~iris.mesh.MeshXY` instance,
then return a new :class:`~iris.mesh.MeshCoord` instance based on that new
index set. :class:`~iris.mesh.components._MeshIndexSet` is a read-only
indexed 'view' onto its original :class:`~iris.mesh.MeshXY`; behaviour of
this class may change from release to release while the design is
finalised.
"""
class _Setting(threading.local):
"""Setting for what is returned when a :class:`~iris.mesh.MeshCoord` is indexed.
See the module docstring for usage instructions:
:mod:`~iris.experimental.mesh_coord_indexing`.
"""
def __init__(self):
self._value = Options.AUX_COORD
@property
def value(self):
return self._value
@value.setter
def value(self, value):
self._value = Options(value)
@contextmanager
def context(self, value):
new_value = Options(value)
original_value = self._value
try:
self._value = new_value
yield
finally:
self._value = original_value
SETTING = _Setting()
"""
Run-time setting for alternative modes of indexing a
:class:`~iris.mesh.MeshCoord`. See the module docstring for usage
instructions: :mod:`~iris.experimental.mesh_coord_indexing`.
"""