Built using Python {{ python_version }}.
diff --git a/docs/src/_templates/custom_sidebar_logo_version.html b/docs/src/_templates/custom_sidebar_logo_version.html
new file mode 100644
index 0000000000..c9d9ac6e2e
--- /dev/null
+++ b/docs/src/_templates/custom_sidebar_logo_version.html
@@ -0,0 +1,26 @@
+{% if on_rtd %}
+ {% if rtd_version == 'latest' %}
+
+ {%- block docs_body %}
+
+ {% if on_rtd and rtd_version == 'latest' %}
+
You are viewing the
latest unreleased documentation
-
v{{ version }}. You may prefer a
-
stable
- version.
+
v{{ version }}. You can switch to a
stable version
+ via the flyout menu in the bottom corner of the screen.
{%- endif %}
{{ super() }}
{%- endblock %}
-
-/*-----------------------------------------------------z----------------------*/
-
-{% block menu %}
- {{ super() }}
-
- {# menu_links and menu_links_name are set in conf.py (html_context) #}
-
- {% if menu_links %}
-
-
- {% if menu_links_name %}
- {{ menu_links_name }}
- {% else %}
- External links
- {% endif %}
-
-
-
- {% for text, link in menu_links %}
- - {{ text }}
- {% endfor %}
-
- {% endif %}
-{% endblock %}
-
diff --git a/docs/src/common_links.inc b/docs/src/common_links.inc
index 67fc493e3e..4d03a92715 100644
--- a/docs/src/common_links.inc
+++ b/docs/src/common_links.inc
@@ -3,25 +3,25 @@
.. _black: https://black.readthedocs.io/en/stable/
.. _cartopy: https://github.com/SciTools/cartopy
-.. _.cirrus.yml: https://github.com/SciTools/iris/blob/main/.cirrus.yml
.. _flake8: https://flake8.pycqa.org/en/stable/
.. _.flake8.yml: https://github.com/SciTools/iris/blob/main/.flake8
.. _cirrus-ci: https://cirrus-ci.com/github/SciTools/iris
.. _conda: https://docs.conda.io/en/latest/
.. _contributor: https://github.com/SciTools/scitools.org.uk/blob/master/contributors.json
.. _core developers: https://github.com/SciTools/scitools.org.uk/blob/master/contributors.json
-.. _discussions: https://github.com/SciTools/iris/discussions
-.. _generating sss keys for GitHub: https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account
+.. _generating ssh keys for GitHub: https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account
+.. _GitHub Actions: https://docs.github.com/en/actions
.. _GitHub Help Documentation: https://docs.github.com/en/github
-.. _Iris GitHub Discussions: https://github.com/SciTools/iris/discussions
+.. _GitHub Discussions: https://github.com/SciTools/iris/discussions
.. _Iris: https://github.com/SciTools/iris
.. _Iris GitHub: https://github.com/SciTools/iris
+.. _Iris GitHub Actions: https://github.com/SciTools/iris/actions
.. _iris-sample-data: https://github.com/SciTools/iris-sample-data
.. _iris-test-data: https://github.com/SciTools/iris-test-data
.. _isort: https://pycqa.github.io/isort/
.. _issue: https://github.com/SciTools/iris/issues
.. _issues: https://github.com/SciTools/iris/issues
-.. _legacy documentation: https://scitools.org.uk/iris/docs/v2.4.0/
+.. _legacy documentation: https://github.com/SciTools/scitools.org.uk/tree/master/iris/docs/archive
.. _matplotlib: https://matplotlib.org/stable/
.. _napolean: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/sphinxcontrib.napoleon.html
.. _nox: https://nox.thea.codes/en/stable/
@@ -38,21 +38,28 @@
.. _using git: https://docs.github.com/en/github/using-git
.. _requirements/ci/: https://github.com/SciTools/iris/tree/main/requirements/ci
.. _CF-UGRID: https://ugrid-conventions.github.io/ugrid-conventions/
+.. _issues on GitHub: https://github.com/SciTools/iris/issues?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc
+.. _python-stratify: https://github.com/SciTools/python-stratify
+.. _iris-esmf-regrid: https://github.com/SciTools-incubator/iris-esmf-regrid
+.. _netCDF4: https://github.com/Unidata/netcdf4-python
.. comment
- Core developers (@github names) in alphabetical order:
+ Core developers and prolific contributors (@github names) in alphabetical order:
.. _@abooton: https://github.com/abooton
.. _@alastair-gemmell: https://github.com/alastair-gemmell
.. _@ajdawson: https://github.com/ajdawson
.. _@bjlittle: https://github.com/bjlittle
.. _@bouweandela: https://github.com/bouweandela
+.. _@bsherratt: https://github.com/bsherratt
.. _@corinnebosley: https://github.com/corinnebosley
.. _@cpelley: https://github.com/cpelley
.. _@djkirkham: https://github.com/djkirkham
.. _@DPeterK: https://github.com/DPeterK
+.. _@ESadek-MO: https://github.com/ESadek-MO
.. _@esc24: https://github.com/esc24
+.. _@HGWright: https://github.com/HGWright
.. _@jamesp: https://github.com/jamesp
.. _@jonseddon: https://github.com/jonseddon
.. _@jvegasbsc: https://github.com/jvegasbsc
@@ -63,6 +70,7 @@
.. _@QuLogic: https://github.com/QuLogic
.. _@rcomer: https://github.com/rcomer
.. _@rhattersley: https://github.com/rhattersley
+.. _@schlunma: https://github.com/schlunma
.. _@stephenworsley: https://github.com/stephenworsley
.. _@tkknight: https://github.com/tkknight
.. _@trexfeathers: https://github.com/trexfeathers
diff --git a/docs/src/community/index.rst b/docs/src/community/index.rst
new file mode 100644
index 0000000000..114cb96fe9
--- /dev/null
+++ b/docs/src/community/index.rst
@@ -0,0 +1,58 @@
+.. include:: ../common_links.inc
+
+.. todo:
+ consider scientific-python.org
+ consider scientific-python.org/specs/
+
+Iris in the Community
+=====================
+
+Iris aims to be a valuable member of the open source scientific Python
+community.
+
+We listen out for developments in our dependencies and neighbouring projects,
+and we reach out to them when we can solve problems together; please feel free
+to reach out to us!
+
+We are aware of our place in the user's wider 'toolbox' - offering unique
+functionality and interoperating smoothly with other packages.
+
+We welcome contributions from all; whether that's an opinion, a 1-line
+clarification, or a whole new feature 🙂
+
+Quick Links
+-----------
+
+* `GitHub Discussions`_
+* :ref:`Getting involved
`
+* `Twitter `_
+
+Interoperability
+----------------
+
+There's a big choice of Python tools out there! Each one has strengths and
+weaknesses in different areas, so we don't want to force a single choice for your
+whole workflow - we'd much rather make it easy for you to choose the right tool
+for the moment, switching whenever you need. Below are our ongoing efforts at
+smoother interoperability:
+
+.. not using toctree due to combination of child pages and cross-references.
+
+* The :mod:`iris.pandas` module
+* :doc:`iris_xarray`
+
+.. toctree::
+ :maxdepth: 1
+ :hidden:
+
+ iris_xarray
+
+Plugins
+-------
+
+Iris can be extended with **plugins**! See below for further information:
+
+.. toctree::
+ :maxdepth: 2
+
+ plugins
diff --git a/docs/src/community/iris_xarray.rst b/docs/src/community/iris_xarray.rst
new file mode 100644
index 0000000000..859597da78
--- /dev/null
+++ b/docs/src/community/iris_xarray.rst
@@ -0,0 +1,154 @@
+.. include:: ../common_links.inc
+
+======================
+Iris ❤️ :term:`Xarray`
+======================
+
+There is a lot of overlap between Iris and :term:`Xarray`, but some important
+differences too. Below is a summary of the most important differences, so that
+you can be prepared, and to help you choose the best package for your use case.
+
+Overall Experience
+------------------
+
+Iris is the more specialised package, focussed on making it as easy
+as possible to work with meteorological and climatological data. Iris
+is built to natively handle many key concepts, such as the CF conventions,
+coordinate systems and bounded coordinates. Iris offers a smaller toolkit of
+operations compared to Xarray, particularly around API for sophisticated
+computation such as array manipulation and multi-processing.
+
+Xarray's more generic data model and community-driven development give it a
+richer range of operations and broader possible uses. Using Xarray
+specifically for meteorology/climatology may require deeper knowledge
+compared to using Iris, and you may prefer to add Xarray plugins
+such as :ref:`cfxarray` to get the best experience. Advanced users can likely
+achieve better performance with Xarray than with Iris.
+
+Conversion
+----------
+There are multiple ways to convert between Iris and Xarray objects.
+
+* Xarray includes the :meth:`~xarray.DataArray.to_iris` and
+ :meth:`~xarray.DataArray.from_iris` methods - detailed in the
+ `Xarray IO notes on Iris`_. Since Iris evolves independently of Xarray, be
+ vigilant for concepts that may be lost during the conversion.
+* Because both packages are closely linked to the :term:`NetCDF Format`, it is
+ feasible to save a NetCDF file using one package then load that file using
+ the other package. This will be lossy in places, as both Iris and Xarray
+ are opinionated on how certain NetCDF concepts relate to their data models.
+* The Iris development team are exploring an improved 'bridge' between the two
+ packages. Follow the conversation on GitHub: `iris#4994`_. This project is
+ expressly intended to be as lossless as possible.
+
+Regridding
+----------
+Iris and Xarray offer a range of regridding methods - both natively and via
+additional packages such as `iris-esmf-regrid`_ and `xESMF`_ - which overlap
+in places
+but tend to cover a different set of use cases (e.g. Iris handles unstructured
+meshes but offers access to fewer ESMF methods). The behaviour of these
+regridders also differs slightly (even between different regridders attached to
+the same package) so the appropriate package to use depends highly on the
+particulars of the use case.
+
+Plotting
+--------
+Xarray and Iris have a large overlap of functionality when creating
+:term:`Matplotlib` plots and both support the plotting of multidimensional
+coordinates. This means the experience is largely similar using either package.
+
+Xarray supports further plotting backends through external packages (e.g. Bokeh through `hvPlot`_)
+and, if a user is already familiar with `pandas`_, the interface should be
+familiar. It also supports some different plot types to Iris, and therefore can
+be used for a wider variety of plots. It also has benefits regarding "out of
+the box", quick customisations to plots. However, if further customisation is
+required, knowledge of matplotlib is still required.
+
+In both cases, :term:`Cartopy` is/can be used. Iris does more work
+automatically for the user here, creating Cartopy
+:class:`~cartopy.mpl.geoaxes.GeoAxes` for latitude and longitude coordinates,
+whereas the user has to do this manually in Xarray.
+
+Statistics
+----------
+Both libraries are quite comparable with generally similar capabilities,
+performance and laziness. Iris offers more specificity in some cases, such as
+some more specific unique functions and masked tolerance in most statistics.
+Xarray seems more approachable however, with some less unique but more
+convenient solutions (these tend to be wrappers to :term:`Dask` functions).
+
+Laziness and Multi-Processing with :term:`Dask`
+-----------------------------------------------
+Iris and Xarray both support lazy data and out-of-core processing through
+utilisation of Dask.
+
+While both Iris and Xarray expose :term:`NumPy` conveniences at the API level
+(e.g. the `ndim()` method), only Xarray exposes Dask conveniences. For example
+:attr:`xarray.DataArray.chunks`, which gives the user direct control
+over the underlying Dask array chunks. The Iris API instead takes control of
+such concepts and user control is only possible by manipulating the underlying
+Dask array directly (accessed via :meth:`iris.cube.Cube.core_data`).
+
+:class:`xarray.DataArray`\ s comply with `NEP-18`_, allowing NumPy arrays to be
+based on them, and they also include the necessary extra members for Dask
+arrays to be based on them too. Neither of these is currently possible with
+Iris :class:`~iris.cube.Cube`\ s, although an ambition for the future.
+
+NetCDF File Control
+-------------------
+(More info: :term:`NetCDF Format`)
+
+Unlike Iris, Xarray generally provides full control of major file structures,
+i.e. dimensions + variables, including their order in the file. It mostly
+respects these in a file input, and can reproduce them on output.
+However, attribute handling is not so complete: like Iris, it interprets and
+modifies some recognised aspects, and can add some extra attributes not in the
+input.
+
+.. todo:
+ More detail on dates and fill values (@pp-mo suggestion).
+
+Handling of dates and fill values have some special problems here.
+
+Ultimately, nearly everything wanted in a particular desired result file can
+be achieved in Xarray, via provided override mechanisms (`loading keywords`_
+and the '`encoding`_' dictionaries).
+
+Missing Data
+------------
+Xarray uses :data:`numpy.nan` to represent missing values and this will support
+many simple use cases assuming the data are floats. Iris enables more
+sophisticated missing data handling by representing missing values as masks
+(:class:`numpy.ma.MaskedArray` for real data and :class:`dask.array.Array`
+for lazy data) which allows data to be any data type and to include either/both
+a mask and :data:`~numpy.nan`\ s.
+
+.. _cfxarray:
+
+`cf-xarray`_
+-------------
+Iris has a data model entirely based on :term:`CF Conventions`. Xarray has a
+data model based on :term:`NetCDF Format` with cf-xarray acting as translation
+into CF. Xarray/cf-xarray methods can be
+called and data accessed with CF like arguments (e.g. axis, standard name) and
+there are some CF specific utilities (similar
+to Iris utilities). Iris tends to cover more of and be stricter about CF.
+
+
+.. seealso::
+
+ * `Xarray IO notes on Iris`_
+ * `Xarray notes on other NetCDF libraries`_
+
+.. _Xarray IO notes on Iris: https://docs.xarray.dev/en/stable/user-guide/io.html#iris
+.. _Xarray notes on other NetCDF libraries: https://docs.xarray.dev/en/stable/getting-started-guide/faq.html#what-other-netcdf-related-python-libraries-should-i-know-about
+.. _loading keywords: https://docs.xarray.dev/en/stable/generated/xarray.open_dataset.html#xarray.open_dataset
+.. _encoding: https://docs.xarray.dev/en/stable/user-guide/io.html#writing-encoded-data
+.. _xESMF: https://github.com/pangeo-data/xESMF/
+.. _seaborn: https://seaborn.pydata.org/
+.. _hvPlot: https://hvplot.holoviz.org/
+.. _pandas: https://pandas.pydata.org/
+.. _NEP-18: https://numpy.org/neps/nep-0018-array-function-protocol.html
+.. _cf-xarray: https://github.com/xarray-contrib/cf-xarray
+.. _iris#4994: https://github.com/SciTools/iris/issues/4994
diff --git a/docs/src/community/plugins.rst b/docs/src/community/plugins.rst
new file mode 100644
index 0000000000..0d79d64623
--- /dev/null
+++ b/docs/src/community/plugins.rst
@@ -0,0 +1,68 @@
+.. _namespace package: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/
+
+.. _community_plugins:
+
+Plugins
+=======
+
+Iris supports **plugins** under the ``iris.plugins`` `namespace package`_.
+This allows packages that extend Iris' functionality to be developed and
+maintained independently, while still being installed into ``iris.plugins``
+instead of a separate package. For example, a plugin may provide loaders or
+savers for additional file formats, or alternative visualisation methods.
+
+
+Using plugins
+-------------
+
+Once a plugin is installed, it can be used either via the
+:func:`iris.use_plugin` function, or by importing it directly:
+
+.. code-block:: python
+
+ import iris
+
+ iris.use_plugin("my_plugin")
+ # OR
+ import iris.plugins.my_plugin
+
+
+Creating plugins
+----------------
+
+The choice of a `namespace package`_ makes writing a plugin relatively
+straightforward: it simply needs to appear as a folder within ``iris/plugins``,
+then can be distributed in the same way as any other package. An example
+repository layout:
+
+.. code-block:: text
+
+ + lib
+ + iris
+ + plugins
+ + my_plugin
+ - __init__.py
+ - (more code...)
+ - README.md
+ - pyproject.toml
+ - setup.cfg
+ - (other project files...)
+
+In particular, note that there must **not** be any ``__init__.py`` files at
+higher levels than the plugin itself.
+
+The package name - how it is referred to by PyPI/conda, specified by
+``metadata.name`` in ``setup.cfg`` - is recommended to include both "iris" and
+the plugin name. Continuing this example, its ``setup.cfg`` should include, at
+minimum:
+
+.. code-block:: ini
+
+ [metadata]
+ name = iris-my-plugin
+
+ [options]
+ packages = find_namespace:
+
+ [options.packages.find]
+ where = lib
diff --git a/docs/src/conf.py b/docs/src/conf.py
index 19f22e808f..576a099b90 100644
--- a/docs/src/conf.py
+++ b/docs/src/conf.py
@@ -20,15 +20,16 @@
# ----------------------------------------------------------------------------
import datetime
+from importlib.metadata import version as get_version
import ntpath
import os
from pathlib import Path
import re
+from subprocess import run
import sys
+from urllib.parse import quote
import warnings
-import iris
-
# function to write useful output to stdout, prefixing the source.
def autolog(message):
@@ -41,20 +42,33 @@ def autolog(message):
# -- Are we running on the readthedocs server, if so do some setup -----------
on_rtd = os.environ.get("READTHEDOCS") == "True"
+# This is the rtd reference to the version, such as: latest, stable, v3.0.1 etc
+rtd_version = os.environ.get("READTHEDOCS_VERSION")
+if rtd_version is not None:
+ # Make rtd_version safe for use in shields.io badges.
+ rtd_version = rtd_version.replace("_", "__")
+ rtd_version = rtd_version.replace("-", "--")
+ rtd_version = quote(rtd_version)
+
+# branch, tag, external (for pull request builds), or unknown.
+rtd_version_type = os.environ.get("READTHEDOCS_VERSION_TYPE")
+
+# For local testing purposes we can force being on RTD and the version
+# on_rtd = True # useful for testing
+# rtd_version = "latest" # useful for testing
+# rtd_version = "stable" # useful for testing
+# rtd_version_type = "tag" # useful for testing
+# rtd_version = "my_branch" # useful for testing
+
if on_rtd:
autolog("Build running on READTHEDOCS server")
# list all the READTHEDOCS environment variables that may be of use
- # at some point
autolog("Listing all environment variables on the READTHEDOCS server...")
for item, value in os.environ.items():
autolog("[READTHEDOCS] {} = {}".format(item, value))
-# This is the rtd reference to the version, such as: latest, stable, v3.0.1 etc
-# For local testing purposes this could be explicitly set latest or stable.
-rtd_version = os.environ.get("READTHEDOCS_VERSION")
-
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
@@ -82,20 +96,11 @@ def autolog(message):
author = "Iris Developers"
# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-
-# The short X.Y version.
-if iris.__version__ == "dev":
- version = "dev"
-else:
- # major.minor.patch-dev -> major.minor.patch
- version = ".".join(iris.__version__.split("-")[0].split(".")[:3])
-# The full version, including alpha/beta/rc tags.
-release = iris.__version__
-
-autolog("Iris Version = {}".format(version))
-autolog("Iris Release = {}".format(release))
+# |version|, also used in various other places throughout the built documents.
+version = get_version("scitools-iris")
+release = version
+autolog(f"Iris Version = {version}")
+autolog(f"Iris Release = {release}")
# -- General configuration ---------------------------------------------------
@@ -153,12 +158,9 @@ def _dotv(version):
"sphinx_copybutton",
"sphinx.ext.napoleon",
"sphinx_panels",
- # TODO: Spelling extension disabled until the dependencies can be included
- # "sphinxcontrib.spelling",
"sphinx_gallery.gen_gallery",
"matplotlib.sphinxext.mathmpl",
"matplotlib.sphinxext.plot_directive",
- "image_test_output",
]
if skip_api == "1":
@@ -171,6 +173,7 @@ def _dotv(version):
# -- panels extension ---------------------------------------------------------
# See https://sphinx-panels.readthedocs.io/en/latest/
+panels_add_bootstrap_css = False
# -- Napoleon extension -------------------------------------------------------
# See https://sphinxcontrib-napoleon.readthedocs.io/en/latest/sphinxcontrib.napoleon.html
@@ -188,16 +191,6 @@ def _dotv(version):
napoleon_use_keyword = True
napoleon_custom_sections = None
-# -- spellingextension --------------------------------------------------------
-# See https://sphinxcontrib-spelling.readthedocs.io/en/latest/customize.html
-spelling_lang = "en_GB"
-# The lines in this file must only use line feeds (no carriage returns).
-spelling_word_list_filename = ["spelling_allow.txt"]
-spelling_show_suggestions = False
-spelling_show_whole_line = False
-spelling_ignore_importable_modules = True
-spelling_ignore_python_builtins = True
-
# -- copybutton extension -----------------------------------------------------
# See https://sphinx-copybutton.readthedocs.io/en/latest/
copybutton_prompt_text = r">>> |\.\.\. "
@@ -229,6 +222,8 @@ def _dotv(version):
"numpy": ("https://numpy.org/doc/stable/", None),
"python": ("https://docs.python.org/3/", None),
"scipy": ("https://docs.scipy.org/doc/scipy/", None),
+ "pandas": ("https://pandas.pydata.org/docs/", None),
+ "dask": ("https://docs.dask.org/en/stable/", None),
}
# The name of the Pygments (syntax highlighting) style to use.
@@ -246,6 +241,10 @@ def _dotv(version):
extlinks = {
"issue": ("https://github.com/SciTools/iris/issues/%s", "Issue #"),
"pull": ("https://github.com/SciTools/iris/pull/%s", "PR #"),
+ "discussion": (
+ "https://github.com/SciTools/iris/discussions/%s",
+ "Discussion #",
+ ),
}
# -- Doctest ("make doctest")--------------------------------------------------
@@ -257,43 +256,74 @@ def _dotv(version):
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-html_logo = "_static/iris-logo-title.png"
-html_favicon = "_static/favicon.ico"
-html_theme = "sphinx_rtd_theme"
+html_logo = "_static/iris-logo-title.svg"
+html_favicon = "_static/iris-logo.svg"
+html_theme = "pydata_sphinx_theme"
+
+# See https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/configuring.html#configure-the-search-bar-position
+html_sidebars = {
+ "**": [
+ "custom_sidebar_logo_version",
+ "search-field",
+ "sidebar-nav-bs",
+ "sidebar-ethical-ads",
+ ]
+}
+# See https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/configuring.html
html_theme_options = {
- "display_version": True,
- "style_external_links": True,
- "logo_only": "True",
+ "footer_items": ["copyright", "sphinx-version", "custom_footer"],
+ "collapse_navigation": True,
+ "navigation_depth": 3,
+ "show_prev_next": True,
+ "navbar_align": "content",
+ "github_url": "https://github.com/SciTools/iris",
+ "twitter_url": "https://twitter.com/scitools_iris",
+ # icons available: https://fontawesome.com/v5.15/icons?d=gallery&m=free
+ "icon_links": [
+ {
+ "name": "GitHub Discussions",
+ "url": "https://github.com/SciTools/iris/discussions",
+ "icon": "far fa-comments",
+ },
+ {
+ "name": "PyPI",
+ "url": "https://pypi.org/project/scitools-iris/",
+ "icon": "fas fa-box",
+ },
+ {
+ "name": "Conda",
+ "url": "https://anaconda.org/conda-forge/iris",
+ "icon": "fas fa-boxes",
+ },
+ ],
+ "use_edit_page_button": True,
+ "show_toc_level": 1,
+ # Omitted `theme-switcher` below to disable it
+ # Info: https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/light-dark.html#configure-default-theme-mode
+ "navbar_end": ["navbar-icon-links"],
}
+rev_parse = run(["git", "rev-parse", "--short", "HEAD"], capture_output=True)
+commit_sha = rev_parse.stdout.decode().strip()
+
html_context = {
+ # pydata_theme
+ "github_repo": "iris",
+ "github_user": "scitools",
+ "github_version": "main",
+ "doc_path": "docs/src",
+ # default theme. Also disabled the button in the html_theme_options.
+ # Info: https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/light-dark.html#configure-default-theme-mode
+ "default_mode": "light",
+ # custom
+ "on_rtd": on_rtd,
"rtd_version": rtd_version,
+ "rtd_version_type": rtd_version_type,
"version": version,
"copyright_years": copyright_years,
"python_version": build_python_version,
- # menu_links and menu_links_name are used in _templates/layout.html
- # to include some nice icons. See http://fontawesome.io for a list of
- # icons (used in the sphinx_rtd_theme)
- "menu_links_name": "Support",
- "menu_links": [
- (
- ' Source Code',
- "https://github.com/SciTools/iris",
- ),
- (
- ' GitHub Discussions',
- "https://github.com/SciTools/iris/discussions",
- ),
- (
- ' StackOverflow for "How Do I?"',
- "https://stackoverflow.com/questions/tagged/python-iris",
- ),
- (
- ' Legacy Documentation',
- "https://scitools.org.uk/iris/docs/v2.4.0/index.html",
- ),
- ],
+ "commit_sha": commit_sha,
}
# Add any paths that contain custom static files (such as style sheets) here,
@@ -302,12 +332,24 @@ def _dotv(version):
html_static_path = ["_static"]
html_style = "theme_override.css"
+# this allows for using datatables: https://datatables.net/
+html_css_files = [
+ "https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css",
+]
+
+html_js_files = [
+ "https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js",
+]
+
# url link checker. Some links work but report as broken, lets ignore them.
# See https://www.sphinx-doc.org/en/1.2/config.html#options-for-the-linkcheck-builder
linkcheck_ignore = [
+ "http://catalogue.ceda.ac.uk/uuid/82adec1f896af6169112d09cc1174499",
"http://cfconventions.org",
"http://code.google.com/p/msysgit/downloads/list",
"http://effbot.org",
+ "https://help.github.com",
+ "https://docs.github.com",
"https://github.com",
"http://www.personal.psu.edu/cab38/ColorBrewer/ColorBrewer_updates.html",
"http://schacon.github.com/git",
@@ -316,6 +358,7 @@ def _dotv(version):
"https://software.ac.uk/how-cite-software",
"http://www.esrl.noaa.gov/psd/data/gridded/conventions/cdc_netcdf_standard.shtml",
"http://www.nationalarchives.gov.uk/doc/open-government-licence",
+ "https://www.metoffice.gov.uk/",
]
# list of sources to exclude from the build.
@@ -335,6 +378,11 @@ def _dotv(version):
"ignore_pattern": r"__init__\.py",
# force gallery building, unless overridden (see src/Makefile)
"plot_gallery": "'True'",
+ # force re-registering of nc-time-axis with matplotlib for each example,
+ # required for sphinx-gallery>=0.11.0
+ "reset_modules": (
+ lambda gallery_conf, fname: sys.modules.pop("nc_time_axis", None),
+ ),
}
# -----------------------------------------------------------------------------
diff --git a/docs/src/developers_guide/assets/developer-settings-github-apps.png b/docs/src/developers_guide/assets/developer-settings-github-apps.png
new file mode 100644
index 0000000000..a63994d087
Binary files /dev/null and b/docs/src/developers_guide/assets/developer-settings-github-apps.png differ
diff --git a/docs/src/developers_guide/assets/download-pem.png b/docs/src/developers_guide/assets/download-pem.png
new file mode 100644
index 0000000000..cbceb1304d
Binary files /dev/null and b/docs/src/developers_guide/assets/download-pem.png differ
diff --git a/docs/src/developers_guide/assets/generate-key.png b/docs/src/developers_guide/assets/generate-key.png
new file mode 100644
index 0000000000..ac894dc71b
Binary files /dev/null and b/docs/src/developers_guide/assets/generate-key.png differ
diff --git a/docs/src/developers_guide/assets/gha-token-example.png b/docs/src/developers_guide/assets/gha-token-example.png
new file mode 100644
index 0000000000..cba1cf6935
Binary files /dev/null and b/docs/src/developers_guide/assets/gha-token-example.png differ
diff --git a/docs/src/developers_guide/assets/install-app.png b/docs/src/developers_guide/assets/install-app.png
new file mode 100644
index 0000000000..31259de588
Binary files /dev/null and b/docs/src/developers_guide/assets/install-app.png differ
diff --git a/docs/src/developers_guide/assets/install-iris-actions.png b/docs/src/developers_guide/assets/install-iris-actions.png
new file mode 100644
index 0000000000..db16dee55b
Binary files /dev/null and b/docs/src/developers_guide/assets/install-iris-actions.png differ
diff --git a/docs/src/developers_guide/assets/installed-app.png b/docs/src/developers_guide/assets/installed-app.png
new file mode 100644
index 0000000000..ab87032393
Binary files /dev/null and b/docs/src/developers_guide/assets/installed-app.png differ
diff --git a/docs/src/developers_guide/assets/iris-actions-secret.png b/docs/src/developers_guide/assets/iris-actions-secret.png
new file mode 100644
index 0000000000..f32456d0f2
Binary files /dev/null and b/docs/src/developers_guide/assets/iris-actions-secret.png differ
diff --git a/docs/src/developers_guide/assets/iris-github-apps.png b/docs/src/developers_guide/assets/iris-github-apps.png
new file mode 100644
index 0000000000..50753532b7
Binary files /dev/null and b/docs/src/developers_guide/assets/iris-github-apps.png differ
diff --git a/docs/src/developers_guide/assets/iris-secrets-created.png b/docs/src/developers_guide/assets/iris-secrets-created.png
new file mode 100644
index 0000000000..19b0ba11dc
Binary files /dev/null and b/docs/src/developers_guide/assets/iris-secrets-created.png differ
diff --git a/docs/src/developers_guide/assets/iris-security-actions.png b/docs/src/developers_guide/assets/iris-security-actions.png
new file mode 100644
index 0000000000..7cbe3a7dc2
Binary files /dev/null and b/docs/src/developers_guide/assets/iris-security-actions.png differ
diff --git a/docs/src/developers_guide/assets/iris-settings.png b/docs/src/developers_guide/assets/iris-settings.png
new file mode 100644
index 0000000000..70714235c2
Binary files /dev/null and b/docs/src/developers_guide/assets/iris-settings.png differ
diff --git a/docs/src/developers_guide/assets/org-perms-members.png b/docs/src/developers_guide/assets/org-perms-members.png
new file mode 100644
index 0000000000..99fd8985e2
Binary files /dev/null and b/docs/src/developers_guide/assets/org-perms-members.png differ
diff --git a/docs/src/developers_guide/assets/repo-perms-contents.png b/docs/src/developers_guide/assets/repo-perms-contents.png
new file mode 100644
index 0000000000..4c325c334d
Binary files /dev/null and b/docs/src/developers_guide/assets/repo-perms-contents.png differ
diff --git a/docs/src/developers_guide/assets/repo-perms-pull-requests.png b/docs/src/developers_guide/assets/repo-perms-pull-requests.png
new file mode 100644
index 0000000000..812f5ef951
Binary files /dev/null and b/docs/src/developers_guide/assets/repo-perms-pull-requests.png differ
diff --git a/docs/src/developers_guide/assets/scitools-settings.png b/docs/src/developers_guide/assets/scitools-settings.png
new file mode 100644
index 0000000000..8d7e728ab5
Binary files /dev/null and b/docs/src/developers_guide/assets/scitools-settings.png differ
diff --git a/docs/src/developers_guide/assets/user-perms.png b/docs/src/developers_guide/assets/user-perms.png
new file mode 100644
index 0000000000..607c7dcdb6
Binary files /dev/null and b/docs/src/developers_guide/assets/user-perms.png differ
diff --git a/docs/src/developers_guide/assets/webhook-active.png b/docs/src/developers_guide/assets/webhook-active.png
new file mode 100644
index 0000000000..538362f335
Binary files /dev/null and b/docs/src/developers_guide/assets/webhook-active.png differ
diff --git a/docs/src/developers_guide/asv_example_images/commits.png b/docs/src/developers_guide/asv_example_images/commits.png
new file mode 100644
index 0000000000..4e0d695322
Binary files /dev/null and b/docs/src/developers_guide/asv_example_images/commits.png differ
diff --git a/docs/src/developers_guide/asv_example_images/comparison.png b/docs/src/developers_guide/asv_example_images/comparison.png
new file mode 100644
index 0000000000..e146d30696
Binary files /dev/null and b/docs/src/developers_guide/asv_example_images/comparison.png differ
diff --git a/docs/src/developers_guide/asv_example_images/scalability.png b/docs/src/developers_guide/asv_example_images/scalability.png
new file mode 100644
index 0000000000..260c3ef536
Binary files /dev/null and b/docs/src/developers_guide/asv_example_images/scalability.png differ
diff --git a/docs/src/developers_guide/ci_checks.png b/docs/src/developers_guide/ci_checks.png
old mode 100755
new mode 100644
index e088e03a66..54ab672b3c
Binary files a/docs/src/developers_guide/ci_checks.png and b/docs/src/developers_guide/ci_checks.png differ
diff --git a/docs/src/developers_guide/contributing_benchmarks.rst b/docs/src/developers_guide/contributing_benchmarks.rst
new file mode 100644
index 0000000000..65bc9635b6
--- /dev/null
+++ b/docs/src/developers_guide/contributing_benchmarks.rst
@@ -0,0 +1,62 @@
+.. include:: ../common_links.inc
+
+.. _contributing.benchmarks:
+
+Benchmarking
+============
+Iris includes architecture for benchmarking performance and other metrics of
+interest. This is done using the `Airspeed Velocity`_ (ASV) package.
+
+Full detail on the setup and how to run or write benchmarks is in
+`benchmarks/README.md`_ in the Iris repository.
+
+Continuous Integration
+----------------------
+The primary purpose of `Airspeed Velocity`_, and Iris' specific benchmarking
+setup, is to monitor for performance changes using statistical comparison
+between commits, and this forms part of Iris' continuous integration.
+
+Accurately assessing performance takes longer than functionality pass/fail
+tests, so the benchmark suite is not automatically run against open pull
+requests, instead it is **run overnight against each the commits of the
+previous day** to check if any commit has introduced performance shifts.
+Detected shifts are reported in a new Iris GitHub issue.
+
+If a pull request author/reviewer suspects their changes may cause performance
+shifts, a convenience is available (currently via Nox) to replicate the
+overnight benchmark run but comparing the current ``HEAD`` with a requested
+branch (e.g. ``upstream/main``). Read more in `benchmarks/README.md`_.
+
+Other Uses
+----------
+Even when not statistically comparing commits, ASV's accurate execution time
+results - recorded using a sophisticated system of repeats - have other
+applications.
+
+* Absolute numbers can be interpreted providing they are recorded on a
+ dedicated resource.
+* Results for a series of commits can be visualised for an intuitive
+ understanding of when and why changes occurred.
+
+ .. image:: asv_example_images/commits.png
+ :width: 300
+
+* Parameterised benchmarks make it easy to visualise:
+
+ * Comparisons
+
+ .. image:: asv_example_images/comparison.png
+ :width: 300
+
+ * Scalability
+
+ .. image:: asv_example_images/scalability.png
+ :width: 300
+
+This also isn't limited to execution times. ASV can also measure memory demand,
+and even arbitrary numbers (e.g. file size, regridding accuracy), although
+without the repetition logic that execution timing has.
+
+
+.. _Airspeed Velocity: https://github.com/airspeed-velocity/asv
+.. _benchmarks/README.md: https://github.com/SciTools/iris/blob/main/benchmarks/README.md
diff --git a/docs/src/developers_guide/contributing_ci_tests.rst b/docs/src/developers_guide/contributing_ci_tests.rst
index 0257ff7cff..1d06434843 100644
--- a/docs/src/developers_guide/contributing_ci_tests.rst
+++ b/docs/src/developers_guide/contributing_ci_tests.rst
@@ -13,51 +13,50 @@ The `Iris`_ GitHub repository is configured to run checks against all its
branches automatically whenever a pull-request is created, updated or merged.
The checks performed are:
-* :ref:`testing_cirrus`
+* :ref:`testing_gha`
* :ref:`testing_cla`
* :ref:`pre_commit_ci`
-.. _testing_cirrus:
+.. _testing_gha:
-Cirrus-CI
-*********
+GitHub Actions
+**************
Iris unit and integration tests are an essential mechanism to ensure
that the Iris code base is working as expected. :ref:`developer_running_tests`
may be performed manually by a developer locally. However Iris is configured to
-use the `cirrus-ci`_ service for automated Continuous Integration (CI) testing.
+use `GitHub Actions`_ (GHA) for automated Continuous Integration (CI) testing.
-The `cirrus-ci`_ configuration file `.cirrus.yml`_ in the root of the Iris repository
-defines the tasks to be performed by `cirrus-ci`_. For further details
-refer to the `Cirrus-CI Documentation`_. The tasks performed during CI include:
+The Iris GHA YAML configuration files in the ``.github/workflows`` directory
+defines the CI tasks to be performed. For further details
+refer to the `GitHub Actions`_ documentation. The tasks performed during CI include:
-* linting the code base and ensuring it adheres to the `black`_ format
* running the system, integration and unit tests for Iris
* ensuring the documentation gallery builds successfully
* performing all doc-tests within the code base
* checking all URL references within the code base and documentation are valid
-The above `cirrus-ci`_ tasks are run automatically against all `Iris`_ branches
+The above GHA tasks are run automatically against all `Iris`_ branches
on GitHub whenever a pull-request is submitted, updated or merged. See the
-`Cirrus-CI Dashboard`_ for details of recent past and active Iris jobs.
+`Iris GitHub Actions`_ dashboard for details of recent past and active CI jobs.
-.. _cirrus_test_env:
+.. _gha_test_env:
-Cirrus CI Test environment
---------------------------
+GitHub Actions Test Environment
+-------------------------------
-The test environment on the Cirrus-CI service is determined from the requirement files
-in ``requirements/ci/py**.yml``. These are conda environment files that list the entire
-set of build, test and run requirements for Iris.
+The CI test environments for our GHA is determined from the requirement files
+in ``requirements/ci/pyXX.yml``. These are conda environment files list the top-level
+package dependencies for running and testing Iris.
For reproducible test results, these environments are resolved for all their dependencies
-and stored as lock files in ``requirements/ci/nox.lock``. The test environments will not
-resolve the dependencies each time, instead they will use the lock file to reproduce the
-same exact environment each time.
+and stored as conda lock files in the ``requirements/ci/nox.lock`` directory. The test environments
+will not resolve the dependencies each time, instead they will use the lock files to reproduce the
+exact same environment each time.
-**If you have updated the requirement yaml files with new dependencies, you will need to
+**If you have updated the requirement YAML files with new dependencies, you will need to
generate new lock files.** To do this, run the command::
python tools/update_lockfiles.py -o requirements/ci/nox.lock requirements/ci/py*.yml
@@ -68,49 +67,22 @@ or simply::
and add the changed lockfiles to your pull request.
+.. note::
+
+ If your installation of conda runs through Artifactory or another similar
+ proxy then you will need to amend that lockfile to use URLs that Github
+ Actions can access. A utility to strip out Artifactory exists in the
+ ``ssstack`` tool.
+
New lockfiles are generated automatically each week to ensure that Iris continues to be
tested against the latest available version of its dependencies.
Each week the yaml files in ``requirements/ci`` are resolved by a GitHub Action.
If the resolved environment has changed, a pull request is created with the new lock files.
-The CI test suite will run on this pull request and fixes for failed tests can be pushed to
-the ``auto-update-lockfiles`` branch to be included in the PR.
-Once a developer has pushed to this branch, the auto-update process will not run again until
-the PR is merged, to prevent overwriting developer commits.
-The auto-updater can still be invoked manually in this situation by going to the `GitHub Actions`_
-page for the workflow, and manually running using the "Run Workflow" button.
-By default, this will also not override developer commits. To force an update, you must
-confirm "yes" in the "Run Worflow" prompt.
-
-
-.. _skipping Cirrus-CI tasks:
-
-Skipping Cirrus-CI Tasks
-------------------------
-
-As a developer you may wish to not run all the CI tasks when you are actively
-developing e.g., you are writing documentation and there is no need for linting,
-or long running compute intensive testing tasks to be executed.
-
-As a convenience, it is possible to easily skip one or more tasks by setting
-the appropriate environment variable within the `.cirrus.yml`_ file to a
-**non-empty** string:
-
-* ``SKIP_LINT_TASK`` to skip `flake8`_ linting and `black`_ formatting
-* ``SKIP_TEST_MINIMAL_TASK`` to skip restricted unit and integration testing
-* ``SKIP_TEST_FULL_TASK`` to skip full unit and integration testing
-* ``SKIP_GALLERY_TASK`` to skip building the documentation gallery
-* ``SKIP_DOCTEST_TASK`` to skip running the documentation doc-tests
-* ``SKIP_LINKCHECK_TASK`` to skip checking for broken documentation URL references
-* ``SKIP_ALL_TEST_TASKS`` which is equivalent to setting ``SKIP_TEST_MINIMAL_TASK`` and ``SKIP_TEST_FULL_TASK``
-* ``SKIP_ALL_DOC_TASKS`` which is equivalent to setting ``SKIP_GALLERY_TASK``, ``SKIP_DOCTEST_TASK``, and ``SKIP_LINKCHECK_TASK``
-
-e.g., to skip the linting task, the following are all equivalent::
-
- SKIP_LINT_TASK: "1"
- SKIP_LINT_TASK: "true"
- SKIP_LINT_TASK: "false"
- SKIP_LINT_TASK: "skip"
- SKIP_LINT_TASK: "unicorn"
+The CI test suite will run on this pull request. If the tests fail, a developer
+will need to create a new branch based off the ``auto-update-lockfiles`` branch
+and add the required fixes to this new branch. If the fixes are made to the
+``auto-update-lockfiles`` branch these will be overwritten the next time the
+Github Action is run.
GitHub Checklist
@@ -146,9 +118,5 @@ pull-requests given the `Iris`_ GitHub repository `.pre-commit-config.yaml`_.
See the `pre-commit.ci dashboard`_ for details of recent past and active Iris jobs.
-
-.. _Cirrus-CI Dashboard: https://cirrus-ci.com/github/SciTools/iris
-.. _Cirrus-CI Documentation: https://cirrus-ci.org/guide/writing-tasks/
.. _.pre-commit-config.yaml: https://github.com/SciTools/iris/blob/main/.pre-commit-config.yaml
.. _pre-commit.ci dashboard: https://results.pre-commit.ci/repo/github/5312648
-.. _GitHub Actions: https://github.com/SciTools/iris/actions/workflows/refresh-lockfiles.yml
diff --git a/docs/src/developers_guide/contributing_codebase_index.rst b/docs/src/developers_guide/contributing_codebase_index.rst
index 88986c0c7a..b59a196ff0 100644
--- a/docs/src/developers_guide/contributing_codebase_index.rst
+++ b/docs/src/developers_guide/contributing_codebase_index.rst
@@ -1,7 +1,7 @@
.. _contributing.documentation.codebase:
-Contributing to the Code Base
-=============================
+Working with the Code Base
+==========================
.. toctree::
:maxdepth: 3
diff --git a/docs/src/developers_guide/contributing_deprecations.rst b/docs/src/developers_guide/contributing_deprecations.rst
index 1ecafdca9f..0b22e2cbd2 100644
--- a/docs/src/developers_guide/contributing_deprecations.rst
+++ b/docs/src/developers_guide/contributing_deprecations.rst
@@ -25,29 +25,29 @@ deprecation is accompanied by the introduction of a new public API.
Under these circumstances the following points apply:
- - Using the deprecated API must result in a concise deprecation warning which
- is an instance of :class:`iris.IrisDeprecation`.
- It is easiest to call
- :func:`iris._deprecation.warn_deprecated`, which is a
- simple wrapper to :func:`warnings.warn` with the signature
- `warn_deprecation(message, **kwargs)`.
- - Where possible, your deprecation warning should include advice on
- how to avoid using the deprecated API. For example, you might
- reference a preferred API, or more detailed documentation elsewhere.
- - You must update the docstring for the deprecated API to include a
- Sphinx deprecation directive:
-
- :literal:`.. deprecated:: `
-
- where you should replace `` with the major and minor version
- of Iris in which this API is first deprecated. For example: `1.8`.
-
- As with the deprecation warning, you should include advice on how to
- avoid using the deprecated API within the content of this directive.
- Feel free to include more detail in the updated docstring than in the
- deprecation warning.
- - You should check the documentation for references to the deprecated
- API and update them as appropriate.
+- Using the deprecated API must result in a concise deprecation warning which
+ is an instance of :class:`iris.IrisDeprecation`.
+ It is easiest to call
+ :func:`iris._deprecation.warn_deprecated`, which is a
+ simple wrapper to :func:`warnings.warn` with the signature
+ `warn_deprecation(message, **kwargs)`.
+- Where possible, your deprecation warning should include advice on
+ how to avoid using the deprecated API. For example, you might
+ reference a preferred API, or more detailed documentation elsewhere.
+- You must update the docstring for the deprecated API to include a
+ Sphinx deprecation directive:
+
+ :literal:`.. deprecated:: `
+
+ where you should replace `` with the major and minor version
+ of Iris in which this API is first deprecated. For example: `1.8`.
+
+ As with the deprecation warning, you should include advice on how to
+ avoid using the deprecated API within the content of this directive.
+ Feel free to include more detail in the updated docstring than in the
+ deprecation warning.
+- You should check the documentation for references to the deprecated
+ API and update them as appropriate.
Changing a Default
------------------
@@ -64,14 +64,14 @@ it causes the corresponding public API to use its new default behaviour.
The following points apply in addition to those for removing a public
API:
- - You should add a new boolean attribute to :data:`iris.FUTURE` (by
- modifying :class:`iris.Future`) that controls the default behaviour
- of the public API that needs updating. The initial state of the new
- boolean attribute should be `False`. You should name the new boolean
- attribute to indicate that setting it to `True` will select the new
- default behaviour.
- - You should include a reference to this :data:`iris.FUTURE` flag in your
- deprecation warning and corresponding Sphinx deprecation directive.
+- You should add a new boolean attribute to :data:`iris.FUTURE` (by
+ modifying :class:`iris.Future`) that controls the default behaviour
+ of the public API that needs updating. The initial state of the new
+ boolean attribute should be `False`. You should name the new boolean
+ attribute to indicate that setting it to `True` will select the new
+ default behaviour.
+- You should include a reference to this :data:`iris.FUTURE` flag in your
+ deprecation warning and corresponding Sphinx deprecation directive.
Removing a Deprecation
@@ -94,11 +94,11 @@ and/or example code should be removed/updated as appropriate.
Changing a Default
------------------
- - You should update the initial state of the relevant boolean attribute
- of :data:`iris.FUTURE` to `True`.
- - You should deprecate setting the relevant boolean attribute of
- :class:`iris.Future` in the same way as described in
- :ref:`removing-a-public-api`.
+- You should update the initial state of the relevant boolean attribute
+ of :data:`iris.FUTURE` to `True`.
+- You should deprecate setting the relevant boolean attribute of
+ :class:`iris.Future` in the same way as described in
+ :ref:`removing-a-public-api`.
.. rubric:: Footnotes
diff --git a/docs/src/developers_guide/contributing_documentation_full.rst b/docs/src/developers_guide/contributing_documentation_full.rst
index 77b898c0f3..a470def683 100755
--- a/docs/src/developers_guide/contributing_documentation_full.rst
+++ b/docs/src/developers_guide/contributing_documentation_full.rst
@@ -1,3 +1,4 @@
+.. include:: ../common_links.inc
.. _contributing.documentation_full:
@@ -31,7 +32,7 @@ The build can be run from the documentation directory ``docs/src``.
The build output for the html is found in the ``_build/html`` sub directory.
When updating the documentation ensure the html build has *no errors* or
-*warnings* otherwise it may fail the automated `cirrus-ci`_ build.
+*warnings* otherwise it may fail the automated `Iris GitHub Actions`_ build.
Once the build is complete, if it is rerun it will only rebuild the impacted
build artefacts so should take less time.
@@ -60,27 +61,36 @@ If you wish to run a full clean build you can run::
make clean
make html
-This is useful for a final test before committing your changes.
+This is useful for a final test before committing your changes. Having built
+the documentation, you can view them in your default browser via::
+
+ make show
.. note:: In order to preserve a clean build for the html, all **warnings**
have been promoted to be **errors** to ensure they are addressed.
This **only** applies when ``make html`` is run.
-.. _cirrus-ci: https://cirrus-ci.com/github/SciTools/iris
-
.. _contributing.documentation.testing:
Testing
~~~~~~~
-There are a ways to test various aspects of the documentation. The
-``make`` commands shown below can be run in the ``docs`` or
-``docs/src`` directory.
+There are various ways to test aspects of the documentation.
Each :ref:`contributing.documentation.gallery` entry has a corresponding test.
-To run the tests::
+To run all the gallery tests::
+
+ pytest -v docs/gallery_tests/test_gallery_examples.py
+
+To run a test for a single gallery example, use the ``pytest -k`` option for
+pattern matching, e.g.::
+
+ pytest -v -k plot_coriolis docs/gallery_tests/test_gallery_examples.py
+
+If a gallery test fails, follow the instructions in :ref:`testing.graphics`.
- make gallerytest
+The ``make`` commands shown below can be run in the ``docs`` or ``docs/src``
+directory.
Many documentation pages includes python code itself that can be run to ensure
it is still valid or to demonstrate examples. To ensure these tests pass
@@ -103,19 +113,7 @@ adding it to the ``linkcheck_ignore`` array that is defined in the
If this fails check the output for the text **broken** and then correct
or ignore the url.
-.. comment
- Finally, the spelling in the documentation can be checked automatically via the
- command::
-
- make spelling
-
- The spelling check may pull up many technical abbreviations and acronyms. This
- can be managed by using an **allow** list in the form of a file. This file,
- or list of files is set in the `conf.py`_ using the string list
- ``spelling_word_list_filename``.
-
-
-.. note:: In addition to the automated `cirrus-ci`_ build of all the
+.. note:: In addition to the automated `Iris GitHub Actions`_ build of all the
documentation build options above, the
https://readthedocs.org/ service is also used. The configuration
of this held in a file in the root of the
@@ -148,7 +146,7 @@ can exclude the module from the API documentation. Add the entry to the
Gallery
~~~~~~~
-The Iris :ref:`sphx_glr_generated_gallery` uses a sphinx extension named
+The Iris :ref:`gallery_index` uses a sphinx extension named
`sphinx-gallery `_
that auto generates reStructuredText (rst) files based upon a gallery source
directory that abides directory and filename convention.
@@ -157,13 +155,13 @@ The code for the gallery entries are in ``docs/gallery_code``.
Each sub directory in this directory is a sub section of the gallery. The
respective ``README.rst`` in each folder is included in the gallery output.
-For each gallery entry there must be a corresponding test script located in
-``docs/gallery_tests``.
-
To add an entry to the gallery simple place your python code into the
appropriate sub directory and name it with a prefix of ``plot_``. If your
gallery entry does not fit into any existing sub directories then create a new
-directory and place it in there.
+directory and place it in there. A test for the gallery entry will be
+automatically generated (see Testing_ for how to run it). To add a new
+reference image for this test, follow the instructions in
+:ref:`testing.graphics`.
The reStructuredText (rst) output of the gallery is located in
``docs/src/generated/gallery``.
diff --git a/docs/src/developers_guide/contributing_getting_involved.rst b/docs/src/developers_guide/contributing_getting_involved.rst
index f7bd4733a3..9ec6559114 100644
--- a/docs/src/developers_guide/contributing_getting_involved.rst
+++ b/docs/src/developers_guide/contributing_getting_involved.rst
@@ -1,8 +1,9 @@
.. include:: ../common_links.inc
.. _development_where_to_start:
+.. _developers_guide:
-Getting Involved
+Developers Guide
----------------
Iris_ is an Open Source project hosted on Github and as such anyone with a
@@ -17,7 +18,7 @@ The `Iris GitHub`_ project has been configured to use templates for each of
the above issue types when creating a `new issue`_ to ensure the appropriate
information is provided.
-Alternatively, **join the conversation** in `Iris GitHub Discussions`_, when
+Alternatively, **join the conversation** in Iris `GitHub Discussions`_, when
you would like the opinions of the Iris community.
A `pull request`_ may also be created by anyone who has become a
@@ -25,7 +26,7 @@ A `pull request`_ may also be created by anyone who has become a
``main`` branch are only given to **core developers** of Iris_, this is
to ensure a measure of control.
-To get started we suggest reading recent `issues`_, `discussions`_ and
+To get started we suggest reading recent `issues`_, `GitHub Discussions`_ and
`pull requests`_ for Iris.
If you are new to using GitHub we recommend reading the
@@ -36,5 +37,30 @@ If you are new to using GitHub we recommend reading the
`Governance `_
section of the `SciTools`_ ogranization web site.
-
.. _GitHub getting started: https://docs.github.com/en/github/getting-started-with-github
+
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Developers Guide
+ :name: development_index
+ :hidden:
+
+ gitwash/index
+ contributing_documentation
+ contributing_codebase_index
+ contributing_changes
+ github_app
+ release
+
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Reference
+ :hidden:
+
+ ../generated/api/iris
+ ../whatsnew/index
+ ../techpapers/index
+ ../copyright
+ ../voted_issues
diff --git a/docs/src/developers_guide/contributing_graphics_tests.rst b/docs/src/developers_guide/contributing_graphics_tests.rst
index 1268aa2686..7964c008c5 100644
--- a/docs/src/developers_guide/contributing_graphics_tests.rst
+++ b/docs/src/developers_guide/contributing_graphics_tests.rst
@@ -2,72 +2,17 @@
.. _testing.graphics:
-Graphics Tests
-**************
+Adding or Updating Graphics Tests
+=================================
-Iris may be used to create various forms of graphical output; to ensure
-the output is consistent, there are automated tests to check against
-known acceptable graphical output. See :ref:`developer_running_tests` for
-more information.
-
-At present graphical tests are used in the following areas of Iris:
-
-* Module ``iris.tests.test_plot``
-* Module ``iris.tests.test_quickplot``
-* :ref:`sphx_glr_generated_gallery` plots contained in
- ``docs/gallery_tests``.
-
-
-Challenges
-==========
-
-Iris uses many dependencies that provide functionality, an example that
-applies here is matplotlib_. For more information on the dependences, see
-:ref:`installing_iris`. When there are updates to the matplotlib_ or a
-dependency of matplotlib, this may result in a change in the rendered graphical
-output. This means that there may be no changes to Iris_, but due to an
-updated dependency any automated tests that compare a graphical output to a
-known acceptable output may fail. The failure may also not be visually
-perceived as it may be a simple pixel shift.
-
-
-Testing Strategy
-================
-
-The `Iris Cirrus-CI matrix`_ defines multiple test runs that use
-different versions of Python to ensure Iris is working as expected.
-
-To make this manageable, the ``iris.tests.IrisTest_nometa.check_graphic`` test
-routine tests against multiple alternative **acceptable** results. It does
-this using an image **hash** comparison technique which avoids storing
-reference images in the Iris repository itself.
-
-This consists of:
-
- * The ``iris.tests.IrisTest_nometa.check_graphic`` function uses a perceptual
- **image hash** of the outputs (see https://github.com/JohannesBuchner/imagehash)
- as the basis for checking test results.
-
- * The hashes of known **acceptable** results for each test are stored in a
- lookup dictionary, saved to the repo file
- ``lib/iris/tests/results/imagerepo.json``
- (`link `_) .
-
- * An actual reference image for each hash value is stored in a *separate*
- public repository https://github.com/SciTools/test-iris-imagehash.
-
- * The reference images allow human-eye assessment of whether a new output is
- judged to be close enough to the older ones, or not.
-
- * The utility script ``iris/tests/idiff.py`` automates checking, enabling the
- developer to easily compare proposed new **acceptable** result images
- against the existing accepted reference images, for each failing test.
+.. note::
-The acceptable images for each test can be viewed online. The :ref:`testing.imagehash_index` lists all the graphical tests in the test suite and
-shows the known acceptable result images for comparison.
+ If a large number of images tests are failing due to an update to the
+ libraries used for image hashing, follow the instructions on
+ :ref:`refresh-imagerepo`.
-Reviewing Failing Tests
-=======================
+Generating New Results
+----------------------
When you find that a graphics test in the Iris testing suite has failed,
following changes in Iris or the run dependencies, this is the process
@@ -76,14 +21,24 @@ you should follow:
#. Create a new, empty directory to store temporary image results, at the path
``lib/iris/tests/result_image_comparison`` in your Iris repository checkout.
-#. **In your Iris repo root directory**, run the relevant (failing) tests
- directly as python scripts, or by using a command such as::
+#. Run the relevant (failing) tests directly as python scripts, or using
+ ``pytest``.
+
+The results of the failing image tests will now be available in
+``lib/iris/tests/result_image_comparison``.
+
+.. note::
+
+ The ``result_image_comparison`` folder is covered by a project
+ ``.gitignore`` setting, so those files *will not show up* in a
+ ``git status`` check.
- python -m unittest discover paths/to/test/files
+Reviewing Failing Tests
+-----------------------
-#. In the ``iris/lib/iris/tests`` folder, run the command::
+#. Run ``iris/lib/iris/tests/graphics/idiff.py`` with python, e.g.:
- python idiff.py
+ python idiff.py
This will open a window for you to visually inspect
side-by-side **old**, **new** and **difference** images for each failed
@@ -92,29 +47,28 @@ you should follow:
If the change is **accepted**:
- * the imagehash value of the new result image is added into the relevant
- set of 'valid result hashes' in the image result database file,
- ``tests/results/imagerepo.json``
+ * the imagehash value of the new result image is added into the relevant
+ set of 'valid result hashes' in the image result database file,
+ ``tests/results/imagerepo.json``
- * the relevant output file in ``tests/result_image_comparison`` is
- renamed according to the image hash value, as ``.png``.
- A copy of this new PNG file must then be added into the reference image
- repository at https://github.com/SciTools/test-iris-imagehash
- (See below).
+ * the relevant output file in ``tests/result_image_comparison`` is renamed
+ according to the test name. A copy of this new PNG file must then be added
+ into the ``iris-test-data`` repository, at
+ https://github.com/SciTools/iris-test-data (See below).
If a change is **skipped**:
- * no further changes are made in the repo.
+ * no further changes are made in the repo.
- * when you run ``iris/tests/idiff.py`` again, the skipped choice will be
- presented again.
+ * when you run ``iris/tests/idiff.py`` again, the skipped choice will be
+ presented again.
If a change is **rejected**:
- * the output image is deleted from ``result_image_comparison``.
+ * the output image is deleted from ``result_image_comparison``.
- * when you run ``iris/tests/idiff.py`` again, the skipped choice will not
- appear, unless the relevant failing test is re-run.
+ * when you run ``iris/tests/idiff.py`` again, the skipped choice will not
+ appear, unless the relevant failing test is re-run.
#. **Now re-run the tests**. The **new** result should now be recognised and the
relevant test should pass. However, some tests can perform *multiple*
@@ -123,46 +77,66 @@ you should follow:
re-run may encounter further (new) graphical test failures. If that
happens, simply repeat the check-and-accept process until all tests pass.
+#. You're now ready to :ref:`add-graphics-test-changes`
-Add Your Changes to Iris
-========================
-To add your changes to Iris, you need to make two pull requests (PR).
+Adding a New Image Test
+-----------------------
-#. The first PR is made in the ``test-iris-imagehash`` repository, at
- https://github.com/SciTools/test-iris-imagehash.
+If you attempt to run ``idiff.py`` when there are new graphical tests for which
+no baseline yet exists, you will get a warning that ``idiff.py`` is ``Ignoring
+unregistered test result...``. In this case,
- * First, add all the newly-generated referenced PNG files into the
- ``images/v4`` directory. In your Iris repo, these files are to be found
- in the temporary results folder ``iris/tests/result_image_comparison``.
+#. rename the relevant images from ``iris/tests/result_image_comparison`` by
- * Then, to update the file which lists available images,
- ``v4_files_listing.txt``, run from the project root directory::
+ * removing the ``result-`` prefix
- python recreate_v4_files_listing.py
+ * fully qualifying the test name if it isn't already (i.e. it should start
+ ``iris.tests...``or ``gallery_tests...``)
- * Create a PR proposing these changes, in the usual way.
+#. run the tests in the mode that lets them create missing data (see
+ :ref:`create-missing`). This will update ``imagerepo.json`` with the new
+ test name and image hash.
-#. The second PR is created in the Iris_ repository, and
- should only include the change to the image results database,
- ``tests/results/imagerepo.json``.
- The description box of this pull request should contain a reference to
- the matching one in ``test-iris-imagehash``.
+#. and then add them to the Iris test data as covered in
+ :ref:`add-graphics-test-changes`.
-.. note::
- The ``result_image_comparison`` folder is covered by a project
- ``.gitignore`` setting, so those files *will not show up* in a
- ``git status`` check.
+.. _refresh-imagerepo:
-.. important::
+Refreshing the Stored Hashes
+----------------------------
- The Iris pull-request will not test successfully in Cirrus-CI until the
- ``test-iris-imagehash`` pull request has been merged. This is because there
- is an Iris_ test which ensures the existence of the reference images (uris)
- for all the targets in the image results database. It will also fail
- if you forgot to run ``recreate_v4_files_listing.py`` to update the
- image-listing file in ``test-iris-imagehash``.
+From time to time, a new version of the image hashing library will cause all
+image hashes to change. The image hashes stored in
+``tests/results/imagerepo.json`` can be refreshed using the baseline images
+stored in the ``iris-test-data`` repository (at
+https://github.com/SciTools/iris-test-data) using the script
+``tests/graphics/recreate_imagerepo.py``. Use the ``--help`` argument for the
+command line arguments.
-.. _Iris Cirrus-CI matrix: https://github.com/scitools/iris/blob/main/.cirrus.yml
+.. _add-graphics-test-changes:
+
+Add Your Changes to Iris
+------------------------
+
+To add your changes to Iris, you need to make two pull requests (PR).
+
+#. The first PR is made in the ``iris-test-data`` repository, at
+ https://github.com/SciTools/iris-test-data.
+
+ * Add all the newly-generated referenced PNG files into the
+ ``test_data/images`` directory. In your Iris repo, these files are to be found
+ in the temporary results folder ``iris/tests/result_image_comparison``.
+
+ * Create a PR proposing these changes, in the usual way.
+
+#. The second PR is the one that makes the changes you intend to the Iris_ repository.
+ The description box of this pull request should contain a reference to
+ the matching one in ``iris-test-data``.
+
+ * This PR should include updating the version of the test data in
+ ``.github/workflows/ci-tests.yml`` and
+ ``.github/workflows/ci-docs-tests.yml`` to the new version created by the
+ merging of your ``iris-test-data`` PR.
diff --git a/docs/src/developers_guide/contributing_pull_request_checklist.rst b/docs/src/developers_guide/contributing_pull_request_checklist.rst
index 5afb461d68..57bc9fd728 100644
--- a/docs/src/developers_guide/contributing_pull_request_checklist.rst
+++ b/docs/src/developers_guide/contributing_pull_request_checklist.rst
@@ -16,8 +16,8 @@ is merged. Before submitting a pull request please consider this list.
#. **Provide a helpful description** of the Pull Request. This should include:
- * The aim of the change / the problem addressed / a link to the issue.
- * How the change has been delivered.
+ * The aim of the change / the problem addressed / a link to the issue.
+ * How the change has been delivered.
#. **Include a "What's New" entry**, if appropriate.
See :ref:`whats_new_contributions`.
@@ -31,10 +31,11 @@ is merged. Before submitting a pull request please consider this list.
#. **Check all new dependencies added to the** `requirements/ci/`_ **yaml
files.** If dependencies have been added then new nox testing lockfiles
- should be generated too, see :ref:`cirrus_test_env`.
+ should be generated too, see :ref:`gha_test_env`.
#. **Check the source documentation been updated to explain all new or changed
- features**. See :ref:`docstrings`.
+ features**. Note, we now use numpydoc strings. Any touched code should
+ be updated to use the docstrings formatting. See :ref:`docstrings`.
#. **Include code examples inside the docstrings where appropriate**. See
:ref:`contributing.documentation.testing`.
@@ -42,8 +43,6 @@ is merged. Before submitting a pull request please consider this list.
#. **Check the documentation builds without warnings or errors**. See
:ref:`contributing.documentation.building`
-#. **Check for any new dependencies in the** `.cirrus.yml`_ **config file.**
-
#. **Check for any new dependencies in the** `readthedocs.yml`_ **file**. This
file is used to build the documentation that is served from
https://scitools-iris.readthedocs.io/en/latest/
@@ -51,12 +50,10 @@ is merged. Before submitting a pull request please consider this list.
#. **Check for updates needed for supporting projects for test or example
data**. For example:
- * `iris-test-data`_ is a github project containing all the data to support
- the tests.
- * `iris-sample-data`_ is a github project containing all the data to support
- the gallery and examples.
- * `test-iris-imagehash`_ is a github project containing reference plot
- images to support Iris :ref:`testing.graphics`.
+ * `iris-test-data`_ is a github project containing all the data to support
+ the tests.
+ * `iris-sample-data`_ is a github project containing all the data to support
+ the gallery and examples.
If new files are required by tests or code examples, they must be added to
the appropriate supporting project via a suitable pull-request. This pull
diff --git a/docs/src/developers_guide/contributing_running_tests.rst b/docs/src/developers_guide/contributing_running_tests.rst
index ab36172283..f60cedba05 100644
--- a/docs/src/developers_guide/contributing_running_tests.rst
+++ b/docs/src/developers_guide/contributing_running_tests.rst
@@ -5,13 +5,22 @@
Running the Tests
*****************
-Using setuptools for Testing Iris
-=================================
+There are two options for running the tests:
-.. warning:: The `setuptools`_ ``test`` command was deprecated in `v41.5.0`_. See :ref:`using nox`.
+* Use an environment you created yourself. This requires more manual steps to
+ set up, but gives you more flexibility. For example, you can run a subset of
+ the tests or use ``python`` interactively to investigate any issues. See
+ :ref:`test manual env`.
-A prerequisite of running the tests is to have the Python environment
-setup. For more information on this see :ref:`installing_from_source`.
+* Use ``nox``. This will automatically generate an environment and run test
+ sessions consistent with our GitHub continuous integration. See :ref:`using nox`.
+
+.. _test manual env:
+
+Testing Iris in a Manually Created Environment
+==============================================
+
+To create a suitable environment for running the tests, see :ref:`installing_from_source`.
Many Iris tests will use data that may be defined in the test itself, however
this is not always the case as sometimes example files may be used. Due to
@@ -32,81 +41,76 @@ The example command below uses ``~/projects`` as the parent directory::
git clone git@github.com:SciTools/iris-test-data.git
export OVERRIDE_TEST_DATA_REPOSITORY=~/projects/iris-test-data/test_data
-All the Iris tests may be run from the root ``iris`` project directory via::
+All the Iris tests may be run from the root ``iris`` project directory using
+``pytest``. For example::
- python setup.py test
-
-You can also run a specific test, the example below runs the tests for
-mapping::
+ pytest -n 2
- cd lib/iris/tests
- python test_mapping.py
+will run the tests across two processes. For more options, use the command
+``pytest -h``. Below is a trimmed example of the output::
-When running the test directly as above you can view the command line options
-using the commands ``python test_mapping.py -h`` or
-``python test_mapping.py --help``.
+ ============================= test session starts ==============================
+ platform linux -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0
+ rootdir: /path/to/git/clone/iris, configfile: pyproject.toml, testpaths: lib/iris
+ plugins: xdist-2.5.0, forked-1.4.0
+ gw0 I / gw1 I
+ gw0 [6361] / gw1 [6361]
-.. tip:: A useful command line option to use is ``-d``. This will display
- matplotlib_ figures as the tests are run. For example::
-
- python test_mapping.py -d
-
- You can also use the ``-d`` command line option when running all
- the tests but this will take a while to run and will require the
- manual closing of each of the figures for the tests to continue.
-
-The output from running the tests is verbose as it will run ~5000 separate
-tests. Below is a trimmed example of the output::
-
- running test
- Running test suite(s): default
-
- Running test discovery on iris.tests with 2 processors.
- test_circular_subset (iris.tests.experimental.regrid.test_regrid_area_weighted_rectilinear_src_and_grid.TestAreaWeightedRegrid) ... ok
- test_cross_section (iris.tests.experimental.regrid.test_regrid_area_weighted_rectilinear_src_and_grid.TestAreaWeightedRegrid) ... ok
- test_different_cs (iris.tests.experimental.regrid.test_regrid_area_weighted_rectilinear_src_and_grid.TestAreaWeightedRegrid) ... ok
- ...
+ ........................................................................ [ 1%]
+ ........................................................................ [ 2%]
+ ........................................................................ [ 3%]
...
- test_ellipsoid (iris.tests.unit.experimental.raster.test_export_geotiff.TestProjection) ... SKIP: Test requires 'gdal'.
- test_no_ellipsoid (iris.tests.unit.experimental.raster.test_export_geotiff.TestProjection) ... SKIP: Test requires 'gdal'.
+ .......................ssssssssssssssssss............................... [ 99%]
+ ........................ [100%]
+ =============================== warnings summary ===============================
...
+ -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
+ =========================== short test summary info ============================
+ SKIPPED [1] lib/iris/tests/experimental/test_raster.py:152: Test requires 'gdal'.
+ SKIPPED [1] lib/iris/tests/experimental/test_raster.py:155: Test requires 'gdal'.
...
- test_slice (iris.tests.test_util.TestAsCompatibleShape) ... ok
- test_slice_and_transpose (iris.tests.test_util.TestAsCompatibleShape) ... ok
- test_transpose (iris.tests.test_util.TestAsCompatibleShape) ... ok
-
- ----------------------------------------------------------------------
- Ran 4762 tests in 238.649s
-
- OK (SKIP=22)
+ ========= 6340 passed, 21 skipped, 1659 warnings in 193.57s (0:03:13) ==========
There may be some tests that have been **skipped**. This is due to a Python
decorator being present in the test script that will intentionally skip a test
if a certain condition is not met. In the example output above there are
-**22** skipped tests, at the point in time when this was run this was primarily
-due to an experimental dependency not being present.
-
+**21** skipped tests. At the point in time when this was run this was due to an
+experimental dependency not being present.
.. tip::
The most common reason for tests to be skipped is when the directory for the
``iris-test-data`` has not been set which would shows output such as::
- test_coord_coord_map (iris.tests.test_plot.Test1dScatter) ... SKIP: Test(s) require external data.
- test_coord_coord (iris.tests.test_plot.Test1dScatter) ... SKIP: Test(s) require external data.
- test_coord_cube (iris.tests.test_plot.Test1dScatter) ... SKIP: Test(s) require external data.
-
+ SKIPPED [1] lib/iris/tests/unit/fileformats/test_rules.py:157: Test(s) require external data.
+ SKIPPED [1] lib/iris/tests/unit/fileformats/pp/test__interpret_field.py:97: Test(s) require external data.
+ SKIPPED [1] lib/iris/tests/unit/util/test_demote_dim_coord_to_aux_coord.py:29: Test(s) require external data.
+
All Python decorators that skip tests will be defined in
``lib/iris/tests/__init__.py`` with a function name with a prefix of
``skip_``.
+You can also run a specific test module. The example below runs the tests for
+mapping::
+
+ cd lib/iris/tests
+ python test_mapping.py
+
+When running the test directly as above you can view the command line options
+using the commands ``python test_mapping.py -h`` or
+``python test_mapping.py --help``.
+
+.. tip:: A useful command line option to use is ``-d``. This will display
+ matplotlib_ figures as the tests are run. For example::
+
+ python test_mapping.py -d
.. _using nox:
Using Nox for Testing Iris
==========================
-Iris has adopted the use of the `nox`_ tool for automated testing on `cirrus-ci`_
+The `nox`_ tool has for adopted for automated testing on `Iris GitHub Actions`_
and also locally on the command-line for developers.
`nox`_ is similar to `tox`_, but instead leverages the expressiveness and power of a Python
@@ -124,15 +128,12 @@ automates the process of:
* building the documentation and executing the doc-tests
* building the documentation gallery
* running the documentation URL link check
-* linting the code-base
-* ensuring the code-base style conforms to the `black`_ standard
-
You can perform all of these tasks manually yourself, however the onus is on you to first ensure
that all of the required package dependencies are installed and available in the testing environment.
`Nox`_ has been configured to automatically do this for you, and provides a means to easily replicate
-the remote testing behaviour of `cirrus-ci`_ locally for the developer.
+the remote testing behaviour of `Iris GitHub Actions`_ locally for the developer.
Installing Nox
diff --git a/docs/src/developers_guide/contributing_testing.rst b/docs/src/developers_guide/contributing_testing.rst
index d0c96834a9..a65bcebd55 100644
--- a/docs/src/developers_guide/contributing_testing.rst
+++ b/docs/src/developers_guide/contributing_testing.rst
@@ -8,8 +8,8 @@ Test Categories
There are two main categories of tests within Iris:
- - :ref:`testing.unit_test`
- - :ref:`testing.integration`
+- :ref:`testing.unit_test`
+- :ref:`testing.integration`
Ideally, all code changes should be accompanied by one or more unit
tests, and by zero or more integration tests.
diff --git a/docs/src/developers_guide/contributing_testing_index.rst b/docs/src/developers_guide/contributing_testing_index.rst
index c5cf1b997b..2f5ae411e8 100644
--- a/docs/src/developers_guide/contributing_testing_index.rst
+++ b/docs/src/developers_guide/contributing_testing_index.rst
@@ -7,7 +7,8 @@ Testing
:maxdepth: 3
contributing_testing
+ testing_tools
contributing_graphics_tests
- imagehash_index
contributing_running_tests
contributing_ci_tests
+ contributing_benchmarks
diff --git a/docs/src/developers_guide/documenting/docstrings.rst b/docs/src/developers_guide/documenting/docstrings.rst
index 8a06024ee2..eeefc71e40 100644
--- a/docs/src/developers_guide/documenting/docstrings.rst
+++ b/docs/src/developers_guide/documenting/docstrings.rst
@@ -8,10 +8,10 @@ Every public object in the Iris package should have an appropriate docstring.
This is important as the docstrings are used by developers to understand
the code and may be read directly in the source or via the :ref:`Iris`.
-This document has been influenced by the following PEP's,
-
- * Attribute Docstrings :pep:`224`
- * Docstring Conventions :pep:`257`
+.. note::
+ As of April 2022 we are looking to adopt `numpydoc`_ strings as standard.
+ We aim to complete the adoption over time as we do changes to the codebase.
+ For examples of use see `numpydoc`_ and `sphinxcontrib-napoleon`_
For consistency always use:
@@ -20,91 +20,14 @@ For consistency always use:
docstrings.
* ``u"""Unicode triple-quoted string"""`` for Unicode docstrings
-All docstrings should be written in reST (reStructuredText) markup. See the
-:ref:`reST_quick_start` for more detail.
-
-There are two forms of docstrings: **single-line** and **multi-line**
-docstrings.
-
-
-Single-Line Docstrings
-======================
-
-The single line docstring of an object must state the **purpose** of that
-object, known as the **purpose section**. This terse overview must be on one
-line and ideally no longer than 80 characters.
-
-
-Multi-Line Docstrings
-=====================
-
-Multi-line docstrings must consist of at least a purpose section akin to the
-single-line docstring, followed by a blank line and then any other content, as
-described below. The entire docstring should be indented to the same level as
-the quotes at the docstring's first line.
-
-
-Description
------------
-
-The multi-line docstring *description section* should expand on what was
-stated in the one line *purpose section*. The description section should try
-not to document *argument* and *keyword argument* details. Such information
-should be documented in the following *arguments and keywords section*.
-
-
-Sample Multi-Line Docstring
----------------------------
-
-Here is a simple example of a standard docstring:
-
-.. literalinclude:: docstrings_sample_routine.py
-
-This would be rendered as:
-
- .. currentmodule:: documenting.docstrings_sample_routine
-
- .. automodule:: documenting.docstrings_sample_routine
- :members:
- :undoc-members:
-
-Additionally, a summary can be extracted automatically, which would result in:
-
- .. autosummary::
-
- documenting.docstrings_sample_routine.sample_routine
-
-
-Documenting Classes
-===================
-
-The class constructor should be documented in the docstring for its
-``__init__`` or ``__new__`` method. Methods should be documented by their own
-docstring, not in the class header itself.
-
-If a class subclasses another class and its behaviour is mostly inherited from
-that class, its docstring should mention this and summarise the differences.
-Use the verb "override" to indicate that a subclass method replaces a
-superclass method and does not call the superclass method; use the verb
-"extend" to indicate that a subclass method calls the superclass method
-(in addition to its own behaviour).
-
-
-Attribute and Property Docstrings
----------------------------------
-
-Here is a simple example of a class containing an attribute docstring and a
-property docstring:
-
-.. literalinclude:: docstrings_attribute.py
+All docstrings can use reST (reStructuredText) markup to augment the
+rendered formatting. See the :ref:`reST_quick_start` for more detail.
-This would be rendered as:
+For more information including examples pleasee see:
- .. currentmodule:: documenting.docstrings_attribute
+* `numpydoc`_
+* `sphinxcontrib-napoleon`_
- .. automodule:: documenting.docstrings_attribute
- :members:
- :undoc-members:
-.. note:: The purpose section of the property docstring **must** state whether
- the property is read-only.
+.. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html#style-guide
+.. _sphinxcontrib-napoleon: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html
\ No newline at end of file
diff --git a/docs/src/developers_guide/documenting/rest_guide.rst b/docs/src/developers_guide/documenting/rest_guide.rst
index 4845132b15..c4330b1e63 100644
--- a/docs/src/developers_guide/documenting/rest_guide.rst
+++ b/docs/src/developers_guide/documenting/rest_guide.rst
@@ -14,8 +14,8 @@ reST is a lightweight markup language intended to be highly readable in
source format. This guide will cover some of the more frequently used advanced
reST markup syntaxes, for the basics of reST the following links may be useful:
- * https://www.sphinx-doc.org/en/master/usage/restructuredtext/
- * http://packages.python.org/an_example_pypi_project/sphinx.html
+* https://www.sphinx-doc.org/en/master/usage/restructuredtext/
+* http://packages.python.org/an_example_pypi_project/sphinx.html
Reference documentation for reST can be found at http://docutils.sourceforge.net/rst.html.
diff --git a/docs/src/developers_guide/documenting/whats_new_contributions.rst b/docs/src/developers_guide/documenting/whats_new_contributions.rst
index ebb553024b..aa19722a69 100644
--- a/docs/src/developers_guide/documenting/whats_new_contributions.rst
+++ b/docs/src/developers_guide/documenting/whats_new_contributions.rst
@@ -1,17 +1,19 @@
+.. include:: ../../common_links.inc
+
.. _whats_new_contributions:
=================================
Contributing a "What's New" Entry
=================================
-Iris uses a file named ``latest.rst`` to keep a draft of upcoming changes
-that will form the next release. Contributions to the :ref:`iris_whatsnew`
-document are written by the developer most familiar with the change made.
-The contribution should be included as part of the Iris Pull Request that
-introduces the change.
+Iris uses a file named ``latest.rst`` to keep a draft of upcoming development
+changes that will form the next stable release. Contributions to the
+:ref:`iris_whatsnew` document are written by the developer most familiar
+with the change made. The contribution should be included as part of
+the Iris Pull Request that introduces the change.
-The ``latest.rst`` and the past release notes are kept in
-``docs/src/whatsnew/``. If you are writing the first contribution after
+The ``latest.rst`` and the past release notes are kept in the
+``docs/src/whatsnew/`` directory. If you are writing the first contribution after
an Iris release: **create the new** ``latest.rst`` by copying the content from
``latest.rst.template`` in the same directory.
@@ -33,12 +35,12 @@ situation is thought likely (large PR, high repo activity etc.):
a **new pull request** be created specifically for the "What's New" entry,
which references the main pull request and titled (e.g. for PR#9999):
- What's New for #9999
+ What's New for #9999
* PR author: create the "What's New" pull request
* PR reviewer: once the "What's New" PR is created, **merge the main PR**.
- (this will fix any `cirrus-ci`_ linkcheck errors where the links in the
+ (this will fix any `Iris GitHub Actions`_ linkcheck errors where the links in the
"What's New" PR reference new features introduced in the main PR)
* PR reviewer: review the "What's New" PR, merge once acceptable
@@ -69,6 +71,9 @@ The required content, in order, is as follows:
user name. Link the name to their GitHub profile. E.g.
```@tkknight `_ changed...``
+ * Bigger changes take a lot of effort to review, too! Make sure you credit
+ the reviewer(s) where appropriate.
+
* The new/changed behaviour
* Context to the change. Possible examples include: what this fixes, why
@@ -82,8 +87,9 @@ The required content, in order, is as follows:
For example::
- #. `@tkknight `_ changed changed argument ``x``
- to be optional in :class:`~iris.module.class` and
+ #. `@tkknight `_ and
+ `@trexfeathers `_ (reviewer) changed
+ argument ``x`` to be optional in :class:`~iris.module.class` and
:meth:`iris.module.method`. This allows greater flexibility as requested in
:issue:`9999`. (:pull:`1111`, :pull:`9999`)
@@ -93,13 +99,11 @@ links to code. For more inspiration on possible content and references, please
examine past what's :ref:`iris_whatsnew` entries.
.. note:: The reStructuredText syntax will be checked as part of building
- the documentation. Any warnings should be corrected.
- `cirrus-ci`_ will automatically build the documentation when
+ the documentation. Any warnings should be corrected. The
+ `Iris GitHub Actions`_ will automatically build the documentation when
creating a pull request, however you can also manually
:ref:`build ` the documentation.
-.. _cirrus-ci: https://cirrus-ci.com/github/SciTools/iris
-
Contribution Categories
=======================
diff --git a/docs/src/developers_guide/github_app.rst b/docs/src/developers_guide/github_app.rst
new file mode 100644
index 0000000000..402cfe0c75
--- /dev/null
+++ b/docs/src/developers_guide/github_app.rst
@@ -0,0 +1,281 @@
+.. include:: ../common_links.inc
+
+Token GitHub App
+----------------
+
+.. note::
+
+ This section of the documentation is applicable only to GitHub `SciTools`_
+ Organisation **owners** and **administrators**.
+
+.. note::
+
+ The ``iris-actions`` GitHub App has been rebranded with the more generic
+ name ``scitools-ci``, as the app can be used for any `SciTools`_ repository,
+ not just ``iris`` specifically.
+
+ All of the following instructions are still applicable.
+
+
+This section describes how to create, configure, install and use our `SciTools`_
+GitHub App for generating tokens for use with *GitHub Actions* (GHA).
+
+
+Background
+^^^^^^^^^^
+
+Our GitHub *Continuous Integration* (CI) workflows require fully reproducible
+`conda`_ environments to test ``iris`` and build our documentation.
+
+The ``iris`` `refresh-lockfiles`_ GHA workflow uses the `conda-lock`_ package to routinely
+generate a platform specific ``lockfile`` containing all the package dependencies
+required by ``iris`` for a specific version of ``python``.
+
+The environment lockfiles created by the `refresh-lockfiles`_ GHA are contributed
+back to ``iris`` though a pull-request that is automatically generated using the
+third-party `create-pull-request`_ GHA. By default, pull-requests created by such an
+action using the standard ``GITHUB_TOKEN`` **cannot** trigger other workflows, such
+as our CI.
+
+As a result, we use a dedicated authentication **GitHub App** to securely generate tokens
+for the `create-pull-request`_ GHA, which then permits our full suite of CI testing workflows
+to be triggered against the lockfiles pull-request. Ensuring that the CI is triggered gives us
+confidence that the proposed new lockfiles have not introduced a package level incompatibility
+or issue within ``iris``. See :ref:`use gha`.
+
+
+Create GitHub App
+^^^^^^^^^^^^^^^^^
+
+The **GitHub App** is created for the sole purpose of generating tokens for use with actions,
+and **must** be owned by the `SciTools`_ organisation.
+
+To create a minimal `GitHub App`_ for this purpose, perform the following steps:
+
+1. Click the `SciTools`_ organisation ``⚙️ Settings`` option.
+
+.. figure:: assets/scitools-settings.png
+ :alt: SciTools organisation Settings option
+ :align: center
+ :width: 75%
+
+2. Click the ``GitHub Apps`` option from the ``<> Developer settings``
+ section in the left hand sidebar.
+
+.. figure:: assets/developer-settings-github-apps.png
+ :alt: Developer settings, GitHub Apps option
+ :align: center
+ :width: 25%
+
+3. Now click the ``New GitHub App`` button to display the ``Register new GitHub App``
+ form.
+
+Within the ``Register new GitHub App`` form, complete the following fields:
+
+4. Set the **mandatory** ``GitHub App name`` field to be ``iris-actions``.
+5. Set the **mandatory** ``Homepage URL`` field to be ``https://github.com/SciTools/iris``
+6. Under the ``Webhook`` section, **uncheck** the ``Active`` checkbox.
+ Note that, **no** ``Webhook URL`` is required.
+
+.. figure:: assets/webhook-active.png
+ :alt: Webhook active checkbox
+ :align: center
+ :width: 75%
+
+7. Under the ``Repository permissions`` section, set the ``Contents`` field to
+ be ``Access: Read and write``.
+
+.. figure:: assets/repo-perms-contents.png
+ :alt: Repository permissions Contents option
+ :align: center
+ :width: 75%
+
+8. Under the ``Repository permissions`` section, set the ``Pull requests`` field
+ to be ``Access: Read and write``.
+
+.. figure:: assets/repo-perms-pull-requests.png
+ :alt: Repository permissions Pull requests option
+ :align: center
+ :width: 75%
+
+9. Under the ``Organization permissions`` section, set the ``Members`` field to
+ be ``Access: Read-only``.
+
+.. figure:: assets/org-perms-members.png
+ :alt: Organization permissions Members
+ :align: center
+ :width: 75%
+
+10. Under the ``User permissions`` section, for the ``Where can this GitHub App be installed?``
+ field, **check** the ``Only on this account`` radio-button i.e., only allow
+ this GitHub App to be installed on the **SciTools** account.
+
+.. figure:: assets/user-perms.png
+ :alt: User permissions
+ :align: center
+ :width: 75%
+
+11. Finally, click the ``Create GitHub App`` button.
+
+
+Configure GitHub App
+^^^^^^^^^^^^^^^^^^^^
+
+Creating the GitHub App will automatically redirect you to the ``SciTools settings / iris-actions``
+form for the newly created app.
+
+Perform the following GitHub App configuration steps:
+
+.. _app id:
+
+1. Under the ``About`` section, note of the GitHub ``App ID`` as this value is
+ required later. See :ref:`gha secrets`.
+2. Under the ``Display information`` section, optionally upload the ``iris`` logo
+ as a ``png`` image.
+3. Under the ``Private keys`` section, click the ``Generate a private key`` button.
+
+.. figure:: assets/generate-key.png
+ :alt: Private keys Generate a private key
+ :align: center
+ :width: 75%
+
+.. _private key:
+
+GitHub will automatically generate a private key to sign access token requests
+for the app. Also a separate browser pop-up window will appear with the GitHub
+App private key in ``OpenSSL PEM`` format.
+
+.. figure:: assets/download-pem.png
+ :alt: Download OpenSSL PEM file
+ :align: center
+ :width: 50%
+
+.. important::
+
+ Please ensure that you save the ``OpenSSL PEM`` file and **securely** archive
+ its contents. The private key within this file is required later.
+ See :ref:`gha secrets`.
+
+
+Install GitHub App
+^^^^^^^^^^^^^^^^^^
+
+To install the GitHub App:
+
+1. Select the ``Install App`` option from the top left menu of the
+ ``Scitools settings / iris-actions`` form, then click the ``Install`` button.
+
+.. figure:: assets/install-app.png
+ :alt: Private keys Generate a private key
+ :align: center
+ :width: 75%
+
+2. Select the ``Only select repositories`` radio-button from the ``Install iris-actions``
+ form, and choose the ``SciTools/iris`` repository.
+
+.. figure:: assets/install-iris-actions.png
+ :alt: Install iris-actions GitHub App
+ :align: center
+ :width: 75%
+
+3. Click the ``Install`` button.
+
+ The successfully installed ``iris-actions`` GitHub App is now available under
+ the ``GitHub Apps`` option in the ``Integrations`` section of the `SciTools`_
+ organisation ``Settings``. Note that, to reconfigure the installed app click
+ the ``⚙️ App settings`` option.
+
+.. figure:: assets/installed-app.png
+ :alt: Installed GitHub App
+ :align: center
+ :width: 80%
+
+4. Finally, confirm that the ``iris-actions`` GitHub App is now available within
+ the `SciTools/iris`_ repository by clicking the ``GitHub apps`` option in the
+ ``⚙️ Settings`` section.
+
+.. figure:: assets/iris-github-apps.png
+ :alt: Iris installed GitHub App
+ :align: center
+ :width: 80%
+
+
+.. _gha secrets:
+
+Create Repository Secrets
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The GitHub Action that requests an access token from the ``iris-actions``
+GitHub App must be configured with the following information:
+
+* the ``App ID``, and
+* the ``OpenSSL PEM`` private key
+
+associated with the ``iris-actions`` GitHub App. This **sensitive** information is
+made **securely** available by creating `SciTools/iris`_ repository secrets:
+
+1. Click the `SciTools/iris`_ repository ``⚙️ Settings`` option.
+
+.. figure:: assets/iris-settings.png
+ :alt: Iris Settings
+ :align: center
+ :width: 75%
+
+2. Click the ``Actions`` option from the ``Security`` section in the left hand
+ sidebar.
+
+.. figure:: assets/iris-security-actions.png
+ :alt: Iris Settings Security Actions
+ :align: center
+ :width: 25%
+
+3. Click the ``New repository secret`` button.
+
+.. figure:: assets/iris-actions-secret.png
+ :alt: Iris Actions Secret
+ :align: center
+ :width: 75%
+
+4. Complete the ``Actions secrets / New secret`` form for the ``App ID``:
+
+ * Set the ``Name`` field to be ``AUTH_APP_ID``.
+ * Set the ``Value`` field to be the numerical ``iris-actions`` GitHub ``App ID``.
+ See :ref:`here `.
+ * Click the ``Add secret`` button.
+
+5. Click the ``New repository secret`` button again, and complete the form
+ for the ``OpenSSL PEM``:
+
+ * Set the ``Name`` field to be ``AUTH_APP_PRIVATE_KEY``.
+ * Set the ``Value`` field to be the entire contents of the ``OpenSSL PEM`` file.
+ See :ref:`here `.
+ * Click the ``Add secret`` button.
+
+A summary of the newly created `SciTools/iris`_ repository secrets is now available:
+
+.. figure:: assets/iris-secrets-created.png
+ :alt: Iris Secrets created
+ :align: center
+ :width: 75%
+
+
+.. _use gha:
+
+Use GitHub App
+^^^^^^^^^^^^^^
+
+The following example workflow shows how to use the `github-app-token`_ GHA
+to generate a token for use with the `create-pull-request`_ GHA:
+
+.. figure:: assets/gha-token-example.png
+ :alt: GitHub Action token example
+ :align: center
+ :width: 50%
+
+
+.. _GitHub App: https://docs.github.com/en/developers/apps/building-github-apps/creating-a-github-app
+.. _SciTools/iris: https://github.com/SciTools/iris
+.. _conda-lock: https://github.com/conda-incubator/conda-lock
+.. _create-pull-request: https://github.com/peter-evans/create-pull-request
+.. _github-app-token: https://github.com/tibdex/github-app-token
+.. _refresh-lockfiles: https://github.com/SciTools/iris/blob/main/.github/workflows/refresh-lockfiles.yml
diff --git a/docs/src/developers_guide/gitwash/development_workflow.rst b/docs/src/developers_guide/gitwash/development_workflow.rst
index 0536ebfb62..b086922d5b 100644
--- a/docs/src/developers_guide/gitwash/development_workflow.rst
+++ b/docs/src/developers_guide/gitwash/development_workflow.rst
@@ -25,7 +25,7 @@ In what follows we'll refer to the upstream iris ``main`` branch, as
* If you can possibly avoid it, avoid merging trunk or any other branches into
your feature branch while you are working.
* If you do find yourself merging from trunk, consider :ref:`rebase-on-trunk`
-* Ask on the `Iris GitHub Discussions`_ if you get stuck.
+* Ask on the Iris `GitHub Discussions`_ if you get stuck.
* Ask for code review!
This way of working helps to keep work well organized, with readable history.
@@ -157,7 +157,7 @@ Ask for Your Changes to be Reviewed or Merged
When you are ready to ask for someone to review your code and consider a merge:
#. Go to the URL of your forked repo, say
- ``http://github.com/your-user-name/iris``.
+ ``https://github.com/your-user-name/iris``.
#. Use the 'Switch Branches' dropdown menu near the top left of the page to
select the branch with your changes:
@@ -190,7 +190,7 @@ Delete a Branch on Github
git push origin :my-unwanted-branch
Note the colon ``:`` before ``test-branch``. See also:
-http://github.com/guides/remove-a-remote-branch
+https://github.com/guides/remove-a-remote-branch
Several People Sharing a Single Repository
@@ -203,7 +203,7 @@ share it via github.
First fork iris into your account, as from :ref:`forking`.
Then, go to your forked repository github page, say
-``http://github.com/your-user-name/iris``, select :guilabel:`Settings`,
+``https://github.com/your-user-name/iris``, select :guilabel:`Settings`,
:guilabel:`Manage Access` and then :guilabel:`Invite collaborator`.
.. note:: For more information on sharing your repository see the
diff --git a/docs/src/developers_guide/gitwash/forking.rst b/docs/src/developers_guide/gitwash/forking.rst
index 161847ed79..baeb243c86 100644
--- a/docs/src/developers_guide/gitwash/forking.rst
+++ b/docs/src/developers_guide/gitwash/forking.rst
@@ -7,7 +7,7 @@ Making Your own Copy (fork) of Iris
===================================
You need to do this only once. The instructions here are very similar
-to the instructions at http://help.github.com/forking/, please see
+to the instructions at https://help.github.com/forking/, please see
that page for more detail. We're repeating some of it here just to give the
specifics for the `Iris`_ project, and to suggest some default names.
@@ -18,7 +18,7 @@ Set up and Configure a Github Account
If you don't have a github account, go to the github page, and make one.
You then need to configure your account to allow write access, see
-the `generating sss keys for GitHub`_ help on `github help`_.
+the `generating ssh keys for GitHub`_ help on `github help`_.
Create Your own Forked Copy of Iris
diff --git a/docs/src/developers_guide/gitwash/git_links.inc b/docs/src/developers_guide/gitwash/git_links.inc
index 9a87b55d4d..11d037ccf4 100644
--- a/docs/src/developers_guide/gitwash/git_links.inc
+++ b/docs/src/developers_guide/gitwash/git_links.inc
@@ -9,8 +9,8 @@
nipy, NIPY, Nipy, etc...
.. _git: http://git-scm.com/
-.. _github: http://github.com
-.. _github help: http://help.github.com
+.. _github: https://github.com
+.. _github help: https://help.github.com
.. _git documentation: https://git-scm.com/docs
.. _git clone: http://schacon.github.com/git/git-clone.html
diff --git a/docs/src/developers_guide/gitwash/set_up_fork.rst b/docs/src/developers_guide/gitwash/set_up_fork.rst
index d5c5bc5c44..5318825488 100644
--- a/docs/src/developers_guide/gitwash/set_up_fork.rst
+++ b/docs/src/developers_guide/gitwash/set_up_fork.rst
@@ -15,7 +15,7 @@ Overview
git clone git@github.com:your-user-name/iris.git
cd iris
- git remote add upstream git://github.com/SciTools/iris.git
+ git remote add upstream git@github.com/SciTools/iris.git
In Detail
=========
diff --git a/docs/src/developers_guide/imagehash_index.rst b/docs/src/developers_guide/imagehash_index.rst
deleted file mode 100644
index a11ae8a531..0000000000
--- a/docs/src/developers_guide/imagehash_index.rst
+++ /dev/null
@@ -1,20 +0,0 @@
-.. include:: ../common_links.inc
-
-.. _testing.imagehash_index:
-
-Graphical Test Hash Index
-*************************
-
-The iris test suite produces plots of data using matplotlib and cartopy.
-The images produced are compared to known "good" output, the images for
-which are kept in `scitools/test-iris-imagehash `_.
-
-For an overview of iris' graphics tests, see :ref:`testing.graphics`
-
-Typically running the iris test suite will output the rendered
-images to ``$PROJECT_DIR/iris_image_test_output``.
-The known good output for each test can be seen at the links below
-for comparison.
-
-
-.. imagetest-list::
\ No newline at end of file
diff --git a/docs/src/developers_guide/release.rst b/docs/src/developers_guide/release.rst
index 09b884302b..bae77a7d21 100644
--- a/docs/src/developers_guide/release.rst
+++ b/docs/src/developers_guide/release.rst
@@ -19,7 +19,8 @@ A Release Manager will be nominated for each release of Iris. This role involves
* deciding which features and bug fixes should be included in the release
* managing the project board for the release
-* using a `GitHub Releases Discussion Forum`_ for documenting intent and capturing any
+* using :discussion:`GitHub Discussion releases category `
+ for documenting intent and capturing any
discussion about the release
The Release Manager will make the release, ensuring that all the steps outlined
@@ -99,12 +100,14 @@ Steps to achieve this can be found in the :ref:`iris_development_releases_steps`
The Release
-----------
-The final steps of the release are to change the version string ``__version__``
-in the source of :literal:`iris.__init__.py` and ensure the release date and details
+The final steps of the release are to ensure that the release date and details
are correct in the relevant ``whatsnew`` page within the documentation.
-Once all checks are complete, the release is cut by the creation of a new tag
-in the ``SciTools/iris`` repository.
+There is no need to update the ``iris.__version__``, as this is managed
+automatically by `setuptools-scm`_.
+
+Once all checks are complete, the release is published on GitHub by
+creating a new tag in the ``SciTools/iris`` repository.
Update conda-forge
@@ -120,6 +123,14 @@ conda package on the `conda-forge Anaconda channel`_.
Update PyPI
-----------
+.. note::
+
+ As part of our Continuous-Integration (CI), the building and publishing of
+ PyPI artifacts is now automated by a dedicated GitHub Action.
+
+ The following instructions **no longer** require to be performed manually,
+ but remain part of the documentation for reference purposes only.
+
Update the `scitools-iris`_ project on PyPI with the latest Iris release.
To do this perform the following steps.
@@ -178,13 +189,13 @@ For further details on how to test Iris, see :ref:`developer_running_tests`.
Merge Back
----------
-After the release is cut, the changes from the release branch should be merged
+After the release is published, the changes from the release branch should be merged
back onto the ``SciTools/iris`` ``main`` branch.
To achieve this, first cut a local branch from the latest ``main`` branch,
and `git merge` the :literal:`.x` release branch into it. Ensure that the
-``iris.__version__``, ``docs/src/whatsnew/index.rst`` and ``docs/src/whatsnew/latest.rst``
-are correct, before committing these changes and then proposing a pull-request
+``docs/src/whatsnew/index.rst`` and ``docs/src/whatsnew/latest.rst`` are
+correct, before committing these changes and then proposing a pull-request
on the ``main`` branch of ``SciTools/iris``.
@@ -198,6 +209,11 @@ branch, and then released by tagging ``v1.9.1``.
New features shall not be included in a point release, these are for bug fixes.
+``whatsnew`` entries should be added to the existing
+``docs/src/whatsnew/v1.9.rst`` file in a new ``v1.9.1`` section. A template for
+this bugfix patches section can be found in the
+``docs/src/whatsnew/latest.rst.template`` file.
+
A point release does not require a release candidate, but the rest of the
release process is to be followed, including the merge back of changes into
``main``.
@@ -213,23 +229,22 @@ These steps assume a release for ``1.9.0`` is to be created.
Release Steps
~~~~~~~~~~~~~
-#. Create the release feature branch ``v1.9.x`` on `SciTools/iris`_.
- The only exception is for a point/bugfix release, as it should already exist
-#. Update the ``iris.__init__.py`` version string e.g., to ``1.9.0``
#. Update the ``whatsnew`` for the release:
- * Use ``git`` to rename ``docs/src/whatsnew/latest.rst`` to the release
- version file ``v1.9.rst``
- * Use ``git`` to delete the ``docs/src/whatsnew/latest.rst.template`` file
- * In ``v1.9.rst`` remove the ``[unreleased]`` caption from the page title.
- Note that, the Iris version and release date are updated automatically
- when the documentation is built
- * Review the file for correctness
- * Work with the development team to populate the ``Release Highlights``
- dropdown at the top of the file, which provides extra detail on notable
- changes
- * Use ``git`` to add and commit all changes, including removal of
- ``latest.rst.template``
+ * Use ``git`` to rename ``docs/src/whatsnew/latest.rst`` to the release
+ version file ``v1.9.rst``
+ * Use ``git`` to delete the ``docs/src/whatsnew/latest.rst.template`` file
+ * In ``v1.9.rst`` remove the ``[unreleased]`` caption from the page title.
+ Replace this with ``[release candidate]`` for the release candidate and
+ remove this for the actual release.
+ Note that, the Iris version and release date are updated automatically
+ when the documentation is built
+ * Review the file for correctness
+ * Work with the development team to populate the ``Release Highlights``
+ dropdown at the top of the file, which provides extra detail on notable
+ changes
+ * Use ``git`` to add and commit all changes, including removal of
+ ``latest.rst.template``.
#. Update the ``whatsnew`` index ``docs/src/whatsnew/index.rst``
@@ -240,6 +255,9 @@ Release Steps
#. Once all the above steps are complete, the release is cut, using
the :guilabel:`Draft a new release` button on the
`Iris release page `_
+ and targeting the release branch if it exists
+#. Create the release feature branch ``v1.9.x`` on `SciTools/iris`_ if it doesn't
+ already exist. For point/bugfix releases use the branch which already exists
Post Release Steps
@@ -247,26 +265,27 @@ Post Release Steps
#. Check the documentation has built on `Read The Docs`_. The build is
triggered by any commit to ``main``. Additionally check that the versions
- available in the pop out menu in the bottom left corner include the new
+ available in the pop out menu in the bottom right corner include the new
release version. If it is not present you will need to configure the
versions available in the **admin** dashboard in `Read The Docs`_.
#. Review the `Active Versions`_ for the ``scitools-iris`` project on
`Read The Docs`_ to ensure that the appropriate versions are ``Active``
and/or ``Hidden``. To do this ``Edit`` the appropriate version e.g.,
see `Editing v3.0.0rc0`_ (must be logged into Read the Docs).
-#. Copy ``docs/src/whatsnew/latest.rst.template`` to
- ``docs/src/whatsnew/latest.rst``. This will reset
- the file with the ``unreleased`` heading and placeholders for the
- ``whatsnew`` headings
-#. Add back in the reference to ``latest.rst`` to the ``whatsnew`` index
- ``docs/src/whatsnew/index.rst``
-#. Update ``iris.__init__.py`` version string to show as ``1.10.dev0``
-#. Merge back to ``main``
+#. Merge back to ``main``. This should be done after all releases, including
+ the release candidate, and also after major changes to the release branch.
+#. On main, make a new ``latest.rst`` from ``latest.rst.template`` and update
+ the include statement and the toctree in ``index.rst`` to point at the new
+ ``latest.rst``.
+#. Consider updating ``docs/src/userguide/citation.rst`` on ``main`` to include
+ the version number, date and `Zenodo DOI `_
+ of the new release. Ideally this would be updated before the release, but
+ the DOI for the new version is only available once the release has been
+ created in GitHub.
.. _SciTools/iris: https://github.com/SciTools/iris
.. _tag on the SciTools/Iris: https://github.com/SciTools/iris/releases
-.. _GitHub Releases Discussion Forum: https://github.com/SciTools/iris/discussions/categories/releases
.. _conda-forge Anaconda channel: https://anaconda.org/conda-forge/iris
.. _conda-forge iris-feedstock: https://github.com/conda-forge/iris-feedstock
.. _CFEP-05: https://github.com/conda-forge/cfep/blob/master/cfep-05.md
@@ -276,4 +295,5 @@ Post Release Steps
.. _rc_iris: https://anaconda.org/conda-forge/iris/labels
.. _Generating Distribution Archives: https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives
.. _Packaging Your Project: https://packaging.python.org/guides/distributing-packages-using-setuptools/#packaging-your-project
-.. _latest CF standard names: http://cfconventions.org/standard-names.html
\ No newline at end of file
+.. _latest CF standard names: http://cfconventions.org/standard-names.html
+.. _setuptools-scm: https://github.com/pypa/setuptools_scm
diff --git a/docs/src/developers_guide/testing_tools.rst b/docs/src/developers_guide/testing_tools.rst
new file mode 100755
index 0000000000..dd628d37fc
--- /dev/null
+++ b/docs/src/developers_guide/testing_tools.rst
@@ -0,0 +1,80 @@
+.. include:: ../common_links.inc
+
+.. _testing_tools:
+
+Testing tools
+*************
+
+Iris has various internal convenience functions and utilities available to
+support writing tests. Using these makes tests quicker and easier to write, and
+also consistent with the rest of Iris (which makes it easier to work with the
+code). Most of these conveniences are accessed through the
+:class:`iris.tests.IrisTest` class, from
+which Iris' test classes then inherit.
+
+.. tip::
+
+ All functions listed on this page are defined within
+ :mod:`iris.tests.__init__.py` as methods of
+ :class:`iris.tests.IrisTest_nometa` (which :class:`iris.tests.IrisTest`
+ inherits from). They can be accessed within a test using
+ ``self.exampleFunction``.
+
+Custom assertions
+=================
+
+:class:`iris.tests.IrisTest` supports a variety of custom unittest-style
+assertions, such as :meth:`~iris.tests.IrisTest_nometa.assertArrayEqual`,
+:meth:`~iris.tests.IrisTest_nometa.assertArrayAlmostEqual`.
+
+.. _create-missing:
+
+Saving results
+--------------
+
+Some tests compare the generated output to the expected result contained in a
+file. Custom assertions for this include
+:meth:`~iris.tests.IrisTest_nometa.assertCMLApproxData`
+:meth:`~iris.tests.IrisTest_nometa.assertCDL`
+:meth:`~iris.tests.IrisTest_nometa.assertCML` and
+:meth:`~iris.tests.IrisTest_nometa.assertTextFile`. See docstrings for more
+information.
+
+.. note::
+
+ Sometimes code changes alter the results expected from a test containing the
+ above methods. These can be updated by removing the existing result files
+ and then running the file containing the test with a ``--create-missing``
+ command line argument, or setting the ``IRIS_TEST_CREATE_MISSING``
+ environment variable to anything non-zero. This will create the files rather
+ than erroring, allowing you to commit the updated results.
+
+Context managers
+================
+
+Capturing exceptions and logging
+--------------------------------
+
+:class:`iris.tests.IrisTest` includes several context managers that can be used
+to make test code tidier and easier to read. These include
+:meth:`~iris.tests.IrisTest_nometa.assertWarnsRegexp` and
+:meth:`~iris.tests.IrisTest_nometa.assertLogs`.
+
+Temporary files
+---------------
+
+It's also possible to generate temporary files in a concise fashion with
+:meth:`~iris.tests.IrisTest_nometa.temp_filename`.
+
+Patching
+========
+
+:meth:`~iris.tests.IrisTest_nometa.patch` is a wrapper around ``unittest.patch``
+that will be automatically cleaned up at the end of the test.
+
+Graphic tests
+=============
+
+As a package capable of generating graphical outputs, Iris has utilities for
+creating and updating graphical tests - see :ref:`testing.graphics` for more
+information.
\ No newline at end of file
diff --git a/docs/src/further_topics/index.rst b/docs/src/further_topics/index.rst
deleted file mode 100644
index 81bff2f764..0000000000
--- a/docs/src/further_topics/index.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-.. _further topics:
-
-Introduction
-============
-
-Some specific areas of Iris may require further explanation or a deep dive
-into additional detail above and beyond that offered by the
-:ref:`User Guide `.
-
-This section provides a collection of additional material on focused topics
-that may be of interest to the more advanced or curious user.
-
-.. hint::
-
- If you wish further documentation on any specific topics or areas of Iris
- that are missing, then please let us know by raising a :issue:`GitHub Documentation Issue`
- on `SciTools/Iris`_.
-
-
-* :doc:`metadata`
-* :doc:`lenient_metadata`
-* :doc:`lenient_maths`
-* :ref:`ugrid`
-
-
-.. _SciTools/iris: https://github.com/SciTools/iris
diff --git a/docs/src/further_topics/metadata.rst b/docs/src/further_topics/metadata.rst
index 1b81f7055c..4c55047d4c 100644
--- a/docs/src/further_topics/metadata.rst
+++ b/docs/src/further_topics/metadata.rst
@@ -1,3 +1,4 @@
+.. _further topics:
.. _metadata:
Metadata
@@ -63,25 +64,26 @@ For example, the collective metadata used to define an
``var_name``, ``units``, and ``attributes`` members. Note that, these are the
actual `data attribute`_ names of the metadata members on the Iris class.
+
.. _metadata members table:
-.. table:: - Iris classes that model `CF Conventions`_ metadata
+.. table:: Iris classes that model `CF Conventions`_ metadata
:widths: auto
:align: center
- =================== ======================================= ============================== ========================================== ================================= ======================== ============================== ===================
- Metadata Members :class:`~iris.coords.AncillaryVariable` :class:`~iris.coords.AuxCoord` :class:`~iris.aux_factory.AuxCoordFactory` :class:`~iris.coords.CellMeasure` :class:`~iris.cube.Cube` :class:`~iris.coords.DimCoord` Metadata Members
- =================== ======================================= ============================== ========================================== ================================= ======================== ============================== ===================
- ``standard_name`` ✔ ✔ ✔ ✔ ✔ ✔ ``standard_name``
- ``long_name`` ✔ ✔ ✔ ✔ ✔ ✔ ``long_name``
- ``var_name`` ✔ ✔ ✔ ✔ ✔ ✔ ``var_name``
- ``units`` ✔ ✔ ✔ ✔ ✔ ✔ ``units``
- ``attributes`` ✔ ✔ ✔ ✔ ✔ ✔ ``attributes``
- ``coord_system`` ✔ ✔ ✔ ``coord_system``
- ``climatological`` ✔ ✔ ✔ ``climatological``
- ``measure`` ✔ ``measure``
- ``cell_methods`` ✔ ``cell_methods``
- ``circular`` ✔ ``circular``
- =================== ======================================= ============================== ========================================== ================================= ======================== ============================== ===================
+ =================== ======================================= ============================== ========================================== ================================= ======================== ==============================
+ Metadata Members :class:`~iris.coords.AncillaryVariable` :class:`~iris.coords.AuxCoord` :class:`~iris.aux_factory.AuxCoordFactory` :class:`~iris.coords.CellMeasure` :class:`~iris.cube.Cube` :class:`~iris.coords.DimCoord`
+ =================== ======================================= ============================== ========================================== ================================= ======================== ==============================
+ ``standard_name`` ✔ ✔ ✔ ✔ ✔ ✔
+ ``long_name`` ✔ ✔ ✔ ✔ ✔ ✔
+ ``var_name`` ✔ ✔ ✔ ✔ ✔ ✔
+ ``units`` ✔ ✔ ✔ ✔ ✔ ✔
+ ``attributes`` ✔ ✔ ✔ ✔ ✔ ✔
+ ``coord_system`` ✔ ✔ ✔
+ ``climatological`` ✔ ✔ ✔
+ ``measure`` ✔
+ ``cell_methods`` ✔
+ ``circular`` ✔
+ =================== ======================================= ============================== ========================================== ================================= ======================== ==============================
.. note::
@@ -387,10 +389,10 @@ instances. Normally, this would cause issues. For example,
.. doctest:: richer-metadata
- >>> simply = {"one": np.int(1), "two": np.array([1.0, 2.0])}
+ >>> simply = {"one": np.int32(1), "two": np.array([1.0, 2.0])}
>>> simply
{'one': 1, 'two': array([1., 2.])}
- >>> fruity = {"one": np.int(1), "two": np.array([1.0, 2.0])}
+ >>> fruity = {"one": np.int32(1), "two": np.array([1.0, 2.0])}
>>> fruity
{'one': 1, 'two': array([1., 2.])}
>>> simply == fruity
@@ -417,7 +419,7 @@ However, metadata class equality is rich enough to handle this eventuality,
>>> metadata1
CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': 1, 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),))
- >>> metadata2 = cube.metadata._replace(attributes={"one": np.int(1), "two": np.array([1000.0, 2000.0])})
+ >>> metadata2 = cube.metadata._replace(attributes={"one": np.int32(1), "two": np.array([1000.0, 2000.0])})
>>> metadata2
CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': 1, 'two': array([1000., 2000.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),))
>>> metadata1 == metadata2
diff --git a/docs/src/further_topics/ugrid/data_model.rst b/docs/src/further_topics/ugrid/data_model.rst
index 4a2f64f627..cc3cc7b793 100644
--- a/docs/src/further_topics/ugrid/data_model.rst
+++ b/docs/src/further_topics/ugrid/data_model.rst
@@ -52,7 +52,7 @@ example.
.. _data_structured_grid:
.. figure:: images/data_structured_grid.svg
:alt: Diagram of how data is represented on a structured grid
- :align: right
+ :align: left
:width: 1280
Data on a structured grid.
@@ -131,7 +131,7 @@ example of what is described above.
.. _data_ugrid_mesh:
.. figure:: images/data_ugrid_mesh.svg
:alt: Diagram of how data is represented on an unstructured mesh
- :align: right
+ :align: left
:width: 1280
Data on an unstructured mesh
@@ -157,7 +157,7 @@ elements. See :numref:`ugrid_element_centres` for a visualised example.
.. _ugrid_element_centres:
.. figure:: images/ugrid_element_centres.svg
:alt: Diagram demonstrating mesh face-centred data.
- :align: right
+ :align: left
:width: 1280
Data can be assigned to mesh edge/face/volume 'centres'
@@ -180,7 +180,7 @@ Every node is completely independent - every one can have unique X andY (and Z)
.. _ugrid_node_independence:
.. figure:: images/ugrid_node_independence.svg
:alt: Diagram demonstrating the independence of each mesh node
- :align: right
+ :align: left
:width: 300
Every mesh node is completely independent
@@ -199,7 +199,7 @@ array. See :numref:`ugrid_variable_faces`.
.. _ugrid_variable_faces:
.. figure:: images/ugrid_variable_faces.svg
:alt: Diagram demonstrating mesh faces with variable node counts
- :align: right
+ :align: left
:width: 300
Mesh faces can have different node counts (using masking)
@@ -216,7 +216,7 @@ areas (faces). See :numref:`ugrid_edge_data`.
.. _ugrid_edge_data:
.. figure:: images/ugrid_edge_data.svg
:alt: Diagram demonstrating data assigned to mesh edges
- :align: right
+ :align: left
:width: 300
Data can be assigned to mesh edges
@@ -405,6 +405,9 @@ the :class:`~iris.cube.Cube`\'s unstructured dimension.
Mesh coordinates:
latitude x -
longitude x -
+ Mesh:
+ name my_mesh
+ location edge
>>> print(edge_cube.location)
edge
diff --git a/docs/src/further_topics/ugrid/images/fesom_mesh.png b/docs/src/further_topics/ugrid/images/fesom_mesh.png
new file mode 100644
index 0000000000..283899a94b
Binary files /dev/null and b/docs/src/further_topics/ugrid/images/fesom_mesh.png differ
diff --git a/docs/src/further_topics/ugrid/images/orca_grid.png b/docs/src/further_topics/ugrid/images/orca_grid.png
new file mode 100644
index 0000000000..6676e84fbb
Binary files /dev/null and b/docs/src/further_topics/ugrid/images/orca_grid.png differ
diff --git a/docs/src/further_topics/ugrid/images/smc_mesh.png b/docs/src/further_topics/ugrid/images/smc_mesh.png
new file mode 100644
index 0000000000..8c5a9d86eb
Binary files /dev/null and b/docs/src/further_topics/ugrid/images/smc_mesh.png differ
diff --git a/docs/src/further_topics/ugrid/index.rst b/docs/src/further_topics/ugrid/index.rst
index 81ba24428a..c45fd271a2 100644
--- a/docs/src/further_topics/ugrid/index.rst
+++ b/docs/src/further_topics/ugrid/index.rst
@@ -38,6 +38,7 @@ Read on to find out more...
* :doc:`data_model` - learn why the mesh experience is so different.
* :doc:`partner_packages` - meet some optional dependencies that provide powerful mesh operations.
* :doc:`operations` - experience how your workflows will look when written for mesh data.
+* :doc:`other_meshes` - check out some examples of converting various mesh formats into Iris' mesh format.
..
Need an actual TOC to get Sphinx working properly, but have hidden it in
@@ -50,5 +51,6 @@ Read on to find out more...
data_model
partner_packages
operations
+ other_meshes
__ CF-UGRID_
diff --git a/docs/src/further_topics/ugrid/operations.rst b/docs/src/further_topics/ugrid/operations.rst
index f96e3e406c..a4e0e593d7 100644
--- a/docs/src/further_topics/ugrid/operations.rst
+++ b/docs/src/further_topics/ugrid/operations.rst
@@ -189,6 +189,9 @@ Creating a :class:`~iris.cube.Cube` is unchanged; the
Mesh coordinates:
latitude x -
longitude x -
+ Mesh:
+ name my_mesh
+ location edge
Save
@@ -392,6 +395,9 @@ etcetera:
Mesh coordinates:
latitude x -
longitude x -
+ Mesh:
+ name my_mesh
+ location face
Attributes:
Conventions 'CF-1.7'
@@ -620,6 +626,9 @@ the link between :class:`~iris.cube.Cube` and
Mesh coordinates:
latitude x -
longitude x -
+ Mesh:
+ name my_mesh
+ location edge
# Sub-setted MeshCoords have become AuxCoords.
>>> print(edge_cube[:-1])
@@ -976,13 +985,26 @@ on dimensions other than the :meth:`~iris.cube.Cube.mesh_dim`, since such
Arithmetic
----------
-.. |tagline: arithmetic| replace:: |pending|
+.. |tagline: arithmetic| replace:: |unchanged|
.. rubric:: |tagline: arithmetic|
-:class:`~iris.cube.Cube` Arithmetic (described in :doc:`/userguide/cube_maths`)
-has not yet been adapted to handle :class:`~iris.cube.Cube`\s that include
-:class:`~iris.experimental.ugrid.MeshCoord`\s.
+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``.
+
+Cubes with meshes can be combined in arithmetic operations like
+"ordinary" cubes. They can combine with other cubes without that mesh
+(and its dimension); or with a matching mesh, which may be on a different
+dimension.
+Arithmetic can also be performed between a cube with a mesh and a mesh
+coordinate with a matching mesh.
+
+In all cases, the result will have the same mesh as the input cubes.
+
+Meshes only match if they are fully equal -- i.e. they contain all the same
+coordinates and connectivities, with identical names, units, attributes and
+data content.
.. todo:
diff --git a/docs/src/further_topics/ugrid/other_meshes.rst b/docs/src/further_topics/ugrid/other_meshes.rst
new file mode 100644
index 0000000000..38abeeca03
--- /dev/null
+++ b/docs/src/further_topics/ugrid/other_meshes.rst
@@ -0,0 +1,360 @@
+.. _other_meshes:
+
+Converting Other Mesh Formats
+*****************************
+
+Iris' Mesh Data Model is based primarily on the CF-UGRID conventions (see
+:doc:`data_model`), but other mesh formats can be converted to fit into this
+model, **enabling use of Iris' specialised mesh support**. Below are some
+examples demonstrating how this works for various mesh formats.
+
+.. contents::
+ :local:
+
+`FESOM 1.4`_ Voronoi Polygons
+-----------------------------
+.. figure:: images/fesom_mesh.png
+ :width: 300
+ :alt: Sample of FESOM mesh voronoi polygons, with variable numbers of sides.
+
+A FESOM mesh encoded in a NetCDF file includes:
+
+* X+Y point coordinates
+* X+Y corners coordinates of the Voronoi Polygons around these points -
+ represented as the bounds of the coordinates
+
+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`.
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> import iris
+ >>> from iris.experimental.ugrid import Mesh
+
+
+ >>> temperature_cube = iris.load_cube("my_file.nc", "sea_surface_temperature")
+ >>> print(temperature_cube)
+ sea_surface_temperature / (degC) (time: 12; -- : 126859)
+ Dimension coordinates:
+ time x -
+ Auxiliary coordinates:
+ latitude - x
+ longitude - x
+ Cell methods:
+ mean where sea area
+ mean time
+ Attributes:
+ grid 'FESOM 1.4 (unstructured grid in the horizontal with 126859 wet nodes;...
+ ...
+
+ >>> print(temperature_cube.coord("longitude"))
+ AuxCoord : longitude / (degrees)
+ points:
+ bounds:
+ shape: (126859,) bounds(126859, 18)
+ dtype: float64
+ standard_name: 'longitude'
+ var_name: 'lon'
+
+ # 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'),
+ ... temperature_cube.coord('latitude'))
+ >>> for new_coord in fesom_mesh.to_MeshCoords("face"):
+ ... old_coord = temperature_cube.coord(new_coord.name())
+ ... unstructured_dim, = old_coord.cube_dims(temperature_cube)
+ ... temperature_cube.remove_coord(old_coord)
+ ... temperature_cube.add_aux_coord(new_coord, unstructured_dim)
+
+ >>> print(temperature_cube)
+ sea_surface_temperature / (degC) (time: 12; -- : 126859)
+ Dimension coordinates:
+ time x -
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Cell methods:
+ mean where sea area
+ mean time
+ Attributes:
+ grid 'FESOM 1.4 (unstructured grid in the horizontal with 126859 wet nodes;...
+ ...
+
+ >>> print(temperature_cube.mesh)
+ Mesh : 'unknown'
+ topology_dimension: 2
+ node
+ node_dimension: 'Mesh2d_node'
+ node coordinates
+ shape(2283462,)>
+ shape(2283462,)>
+ face
+ face_dimension: 'Mesh2d_face'
+ face_node_connectivity: shape(126859, 18)>
+ face coordinates
+ shape(126859,)>
+ shape(126859,)>
+
+`WAVEWATCH III`_ Spherical Multi-Cell (SMC) WAVE Quad Grid
+----------------------------------------------------------
+.. figure:: images/smc_mesh.png
+ :width: 300
+ :alt: Sample of an SMC mesh, with decreasing quad sizes at the coastlines.
+
+An SMC grid encoded in a NetCDF file includes:
+
+* X+Y face centre coordinates
+* X+Y base face sizes
+* X+Y face size factors
+
+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`.
+
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> import iris
+ >>> from iris.experimental.ugrid import Mesh
+ >>> import numpy as np
+
+
+ >>> wave_cube = iris.load_cube("my_file.nc", "sea_surface_wave_significant_height")
+ >>> print(wave_cube)
+ sea_surface_wave_significant_height / (m) (time: 7; -- : 666328)
+ Dimension coordinates:
+ time x -
+ Auxiliary coordinates:
+ forecast_period x -
+ latitude - x
+ latitude cell size factor - x
+ longitude - x
+ longitude cell size factor - x
+ Scalar coordinates:
+ forecast_reference_time 2021-12-05 00:00:00
+ Attributes:
+ SIN4 namelist parameter BETAMAX 1.39
+ SMC_grid_type 'seapoint'
+ WAVEWATCH_III_switches 'NOGRB SHRD PR2 UNO SMC FLX0 LN1 ST4 NL1 BT1 DB1 TR0 BS0 IC0 IS0 REF0 WNT1...
+ WAVEWATCH_III_version_number '7.13'
+ altitude_resolution 'n/a'
+ area 'Global wave model GS512L4EUK'
+ base_lat_size 0.029296871
+ base_lon_size 0.043945305
+ ...
+
+ >>> faces_x = wave_cube.coord("longitude")
+ >>> faces_y = wave_cube.coord("latitude")
+ >>> face_size_factor_x = wave_cube.coord("longitude cell size factor")
+ >>> face_size_factor_y = wave_cube.coord("latitude cell size factor")
+ >>> base_x_size = wave_cube.attributes["base_lon_size"]
+ >>> base_y_size = wave_cube.attributes["base_lat_size"]
+
+ # Calculate face corners from face centres and face size factors.
+ >>> face_centres_x = faces_x.points
+ >>> face_centres_y = faces_y.points
+ >>> face_size_x = face_size_factor_x.points * base_x_size
+ >>> face_size_y = face_size_factor_y.points * base_y_size
+
+ >>> x_mins = (face_centres_x - 0.5 * face_size_x).reshape(-1, 1)
+ >>> x_maxs = (face_centres_x + 0.5 * face_size_x).reshape(-1, 1)
+ >>> y_mins = (face_centres_y - 0.5 * face_size_y).reshape(-1, 1)
+ >>> y_maxs = (face_centres_y + 0.5 * face_size_y).reshape(-1, 1)
+
+ >>> face_corners_x = np.hstack([x_mins, x_maxs, x_maxs, x_mins])
+ >>> face_corners_y = np.hstack([y_mins, y_mins, y_maxs, y_maxs])
+
+ # Add face corners as coordinate bounds.
+ >>> faces_x.bounds = face_corners_x
+ >>> faces_y.bounds = face_corners_y
+
+ # 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)
+ >>> 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)
+ ... wave_cube.remove_coord(old_coord)
+ ... wave_cube.add_aux_coord(new_coord, unstructured_dim)
+
+ >>> print(wave_cube)
+ sea_surface_wave_significant_height / (m) (time: 7; -- : 666328)
+ Dimension coordinates:
+ time x -
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Auxiliary coordinates:
+ forecast_period x -
+ latitude cell size factor - x
+ longitude cell size factor - x
+ Scalar coordinates:
+ forecast_reference_time 2021-12-05 00:00:00
+ Attributes:
+ SIN4 namelist parameter BETAMAX 1.39
+ SMC_grid_type 'seapoint'
+ WAVEWATCH_III_switches 'NOGRB SHRD PR2 UNO SMC FLX0 LN1 ST4 NL1 BT1 DB1 TR0 BS0 IC0 IS0 REF0 WNT1...
+ WAVEWATCH_III_version_number '7.13'
+ altitude_resolution 'n/a'
+ area 'Global wave model GS512L4EUK'
+ base_lat_size 0.029296871
+ base_lon_size 0.043945305
+ ...
+
+ >>> print(wave_cube.mesh)
+ Mesh : 'unknown'
+ topology_dimension: 2
+ node
+ node_dimension: 'Mesh2d_node'
+ node coordinates
+
+
+ face
+ face_dimension: 'Mesh2d_face'
+ face_node_connectivity:
+ face coordinates
+
+
+
+
+.. _ORCA_example:
+
+`NEMO`_ data on ORCA tripolar grid
+----------------------------------
+.. figure:: images/orca_grid.png
+ :width: 300
+ :alt: Plot of ORCA-gridded data from NEMO.
+
+NEMO can use various grids, but is frequently used with ORCA type grids.
+ORCA grids store global data in 2-dimensional ny * nx arrays. All cells are
+four-sided. The grids are based on tri-polar layouts, but X and Y spacings are
+irregular and not given by any defined functional forms.
+
+* arrays (ny, nx) of face-located data variables
+* arrays (ny, nx) of X+Y face centre coordinates
+* arrays (ny, nx, 4) of X+Y face corner coordinates
+ (all faces are quadrilaterals)
+
+For simplicity, we treat each face corner as an independent node, and use a face-node
+connectivity which simply lists the nodes in sequence,
+i.e. [[0, 1, 2, 3], [4, 5, 6, 7], ...].
+
+.. Note::
+ This is the simplest solution, but produces approx 4x more nodes than
+ necessary, since the coordinate bounds contain many duplicate locations.
+ Removing the duplicates is quite easy, but often not necessary.
+
+To make an unstructured cube, the data must be 'flattened' to convert the given X and Y
+dimensions into a single mesh dimension. Since Iris cubes don't support a "reshape" or
+"flatten" operations, we create a new cube from the flattened data.
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> import numpy as np
+ >>> import iris
+ >>> from iris.coords import AuxCoord, CellMeasure
+ >>> from iris.cube import Cube
+ >>> from iris.experimental.ugrid.mesh import Mesh, Connectivity
+
+
+ >>> filepath = iris.sample_data_path('orca2_votemper.nc')
+ >>> cube = iris.load_cube(filepath)
+ >>> print(cube)
+ sea_water_potential_temperature / (degC) (-- : 148; -- : 180)
+ Auxiliary coordinates:
+ latitude x x
+ longitude x x
+ Scalar coordinates:
+ depth 4.999938 m, bound=(0.0, 10.0) m
+ time 0001-01-01 12:00:00
+ Cell methods:
+ mean time
+ Attributes:
+ Conventions 'CF-1.5'
+
+
+ >>> co_x = cube.coord("longitude")
+ >>> co_y = cube.coord("latitude")
+ >>> ny, nx = co_x.shape
+ >>> n_faces = ny * nx
+
+ >>> # Create face coords from flattened face-points
+ >>> face_x_co = AuxCoord(co_x.points.flatten())
+ >>> face_y_co = AuxCoord(co_y.points.flatten())
+ >>> assert face_x_co.shape == (n_faces,)
+ >>> face_x_co.metadata = co_x.metadata
+ >>> face_y_co.metadata = co_y.metadata
+
+ >>> # Create node coordinates from bound points.
+ >>> n_nodes = n_faces * 4
+ >>> node_x_co = AuxCoord(co_x.bounds.flatten())
+ >>> node_y_co = AuxCoord(co_y.bounds.flatten())
+ >>> assert node_x_co.shape == (n_nodes,)
+ >>> node_x_co.metadata = co_x.metadata
+ >>> node_y_co.metadata = co_y.metadata
+
+ >>> # Create a face-node Connectivity matching the order of nodes in the bounds array
+ >>> face_node_inds = np.arange(n_nodes).reshape((n_faces, 4))
+ >>> face_nodes_conn = Connectivity(
+ ... indices=face_node_inds,
+ ... cf_role='face_node_connectivity',
+ ... long_name='face_inds', units='1',
+ ... )
+
+ >>> # Create a mesh object.
+ >>> mesh = Mesh(
+ ... 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'
+ topology_dimension: 2
+ node
+ node_dimension: 'Mesh2d_node'
+ node coordinates
+
+
+ face
+ face_dimension: 'Mesh2d_face'
+ face_node_connectivity:
+ face coordinates
+
+
+
+
+ >>> # Create an unstructured version of the input with flattened data
+ >>> meshcube = Cube(cube.core_data().flatten())
+ >>> meshcube.metadata = cube.metadata
+
+ >>> # Attach the mesh by adding the mesh 'face' MeshCoords into the cube
+ >>> mesh_dim = meshcube.ndim - 1
+ >>> for co in mesh.to_MeshCoords('face'):
+ ... meshcube.add_aux_coord(co, mesh_dim)
+ ...
+
+ >>> print(meshcube)
+ sea_water_potential_temperature / (degC) (-- : 26640)
+ Mesh coordinates:
+ latitude x
+ longitude x
+ Mesh:
+ name unknown
+ location face
+ Cell methods:
+ mean time
+ Attributes:
+ Conventions 'CF-1.5'
+
+
+.. _WAVEWATCH III: https://github.com/NOAA-EMC/WW3
+.. _FESOM 1.4: https://fesom.de/models/fesom14/
+.. _NEMO: https://www.nemo-ocean.eu/
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/partner_packages.rst b/docs/src/further_topics/ugrid/partner_packages.rst
index 8e36f4ffc2..75b54b037f 100644
--- a/docs/src/further_topics/ugrid/partner_packages.rst
+++ b/docs/src/further_topics/ugrid/partner_packages.rst
@@ -1,3 +1,5 @@
+.. include:: ../../common_links.inc
+
.. _ugrid partners:
Iris' Mesh Partner Packages
@@ -97,4 +99,3 @@ Applications
.. _GeoVista: https://github.com/bjlittle/geovista
.. _PyVista: https://docs.pyvista.org/index.html
-.. _iris-esmf-regrid: https://github.com/SciTools-incubator/iris-esmf-regrid
diff --git a/docs/src/getting_started.rst b/docs/src/getting_started.rst
new file mode 100644
index 0000000000..24299a4060
--- /dev/null
+++ b/docs/src/getting_started.rst
@@ -0,0 +1,15 @@
+.. _getting_started_index:
+
+Getting Started
+===============
+
+To get started with Iris we recommend reading :ref:`why_iris` was created and to
+explore the examples in the :ref:`gallery_index` after :ref:`installing_iris`
+Iris.
+
+.. toctree::
+ :maxdepth: 1
+
+ why_iris
+ installing
+ generated/gallery/index
\ No newline at end of file
diff --git a/docs/src/index.rst b/docs/src/index.rst
index d6fc5f2f7e..531c0e0b26 100644
--- a/docs/src/index.rst
+++ b/docs/src/index.rst
@@ -1,7 +1,9 @@
+.. include:: common_links.inc
.. _iris_docs:
-Iris |version|
-========================
+
+Iris
+====
**A powerful, format-agnostic, community-driven Python package for analysing
and visualising Earth science data.**
@@ -11,149 +13,152 @@ giving you a powerful, format-agnostic interface for working with your data.
It excels when working with multi-dimensional Earth Science data, where tabular
representations become unwieldy and inefficient.
-`CF Standard names `_,
-`units `_, and coordinate metadata
-are built into Iris, giving you a rich and expressive interface for maintaining
-an accurate representation of your data. Its treatment of data and
-associated metadata as first-class objects includes:
-
-* visualisation interface based on `matplotlib `_ and
- `cartopy `_,
-* unit conversion,
-* subsetting and extraction,
-* merge and concatenate,
-* aggregations and reductions (including min, max, mean and weighted averages),
-* interpolation and regridding (including nearest-neighbor, linear and
- area-weighted), and
-* operator overloads (``+``, ``-``, ``*``, ``/``, etc.).
-
-A number of file formats are recognised by Iris, including CF-compliant NetCDF,
-GRIB, and PP, and it has a plugin architecture to allow other formats to be
-added seamlessly.
-
-Building upon `NumPy `_ and
-`dask `_, Iris scales from efficient
-single-machine workflows right through to multi-core clusters and HPC.
-Interoperability with packages from the wider scientific Python ecosystem comes
-from Iris' use of standard NumPy/dask arrays as its underlying data storage.
-
-Iris is part of SciTools, for more information see https://scitools.org.uk/.
-For **Iris 2.4** and earlier documentation please see the
-:link-badge:`https://scitools.org.uk/iris/docs/v2.4.0/,"legacy documentation",cls=badge-info text-white`.
-
+For more information see :ref:`why_iris`.
.. panels::
:container: container-lg pb-3
- :column: col-lg-4 col-md-4 col-sm-6 col-xs-12 p-2
+ :column: col-lg-4 col-md-4 col-sm-6 col-xs-12 p-2 text-center
+ :img-top-cls: w-50 m-auto px-1 py-2
- Install Iris as a user or developer.
- +++
- .. link-button:: installing_iris
- :type: ref
- :text: Installing Iris
- :classes: btn-outline-primary btn-block
---
- Example code to create a variety of plots.
+ :img-top: _static/icon_shuttle.svg
+
+ Information on Iris, how to install and a gallery of examples that
+ create plots.
+++
- .. link-button:: sphx_glr_generated_gallery
+ .. link-button:: getting_started
:type: ref
- :text: Gallery
- :classes: btn-outline-primary btn-block
+ :text: Getting Started
+ :classes: btn-outline-info btn-block
+
+
---
- Find out what has recently changed in Iris.
+ :img-top: _static/icon_instructions.svg
+
+ Learn how to use Iris, including loading, navigating, saving,
+ plotting and more.
+++
- .. link-button:: iris_whatsnew
+ .. link-button:: user_guide_index
:type: ref
- :text: What's New
- :classes: btn-outline-primary btn-block
+ :text: User Guide
+ :classes: btn-outline-info btn-block
+
---
- Learn how to use Iris.
+ :img-top: _static/icon_development.svg
+
+ As a developer you can contribute to Iris.
+++
- .. link-button:: user_guide_index
+ .. link-button:: development_where_to_start
:type: ref
- :text: User Guide
- :classes: btn-outline-primary btn-block
+ :text: Developers Guide
+ :classes: btn-outline-info btn-block
+
---
+ :img-top: _static/icon_api.svg
+
Browse full Iris functionality by module.
+++
.. link-button:: Iris
:type: ref
:text: Iris API
- :classes: btn-outline-primary btn-block
+ :classes: btn-outline-info btn-block
+
---
- As a developer you can contribute to Iris.
+ :img-top: _static/icon_new_product.svg
+
+ Find out what has recently changed in Iris.
+++
- .. link-button:: development_where_to_start
+ .. link-button:: iris_whatsnew
:type: ref
- :text: Getting Involved
- :classes: btn-outline-primary btn-block
+ :text: What's New
+ :classes: btn-outline-info btn-block
+
+ ---
+ :img-top: _static/icon_thumb.png
+
+ Raise the profile of issues by voting on them.
+ +++
+ .. link-button:: voted_issues_top
+ :type: ref
+ :text: Voted Issues
+ :classes: btn-outline-info btn-block
+
+
+Icons made by `FreePik `_ from
+`Flaticon `_
+
+
+.. _iris_support:
+
+Support
+~~~~~~~
+
+We, the Iris developers have adopted `GitHub Discussions`_ to capture any
+discussions or support questions related to Iris.
+
+See also `StackOverflow for "How Do I? `_
+that may be useful but we do not actively monitor this.
+
+The legacy support resources:
+
+* `Users Google Group `_
+* `Developers Google Group `_
+* `Legacy Documentation`_ (Iris 2.4 or earlier). This is an archive of zip
+ files of past documentation. You can download, unzip and view the
+ documentation locally (index.html). There may be some incorrect rendering
+ and older javascvript (.js) files may show a warning when uncompressing, in
+ which case we suggest you use a different unzip tool.
.. toctree::
- :maxdepth: 1
:caption: Getting Started
+ :maxdepth: 1
:hidden:
- installing
- generated/gallery/index
+ getting_started
.. toctree::
- :maxdepth: 1
:caption: User Guide
+ :maxdepth: 1
:name: userguide_index
:hidden:
userguide/index
- userguide/iris_cubes
- userguide/loading_iris_cubes
- userguide/saving_iris_cubes
- userguide/navigating_a_cube
- userguide/subsetting_a_cube
- userguide/real_and_lazy_data
- userguide/plotting_a_cube
- userguide/interpolation_and_regridding
- userguide/merge_and_concat
- userguide/cube_statistics
- userguide/cube_maths
- userguide/citation
- userguide/code_maintenance
-
-
-.. _developers_guide:
+
.. toctree::
+ :caption: Developers Guide
:maxdepth: 1
- :caption: Further Topics
+ :name: developers_index
:hidden:
- further_topics/index
- further_topics/metadata
- further_topics/lenient_metadata
- further_topics/lenient_maths
- further_topics/ugrid/index
+ developers_guide/contributing_getting_involved
.. toctree::
- :maxdepth: 2
- :caption: Developers Guide
- :name: development_index
+ :caption: Community
+ :maxdepth: 1
+ :name: community_index
:hidden:
- developers_guide/contributing_getting_involved
- developers_guide/gitwash/index
- developers_guide/contributing_documentation
- developers_guide/contributing_codebase_index
- developers_guide/contributing_changes
- developers_guide/release
+ Community
.. toctree::
+ :caption: Iris API
:maxdepth: 1
- :caption: Reference
:hidden:
generated/api/iris
+
+
+.. toctree::
+ :caption: What's New in Iris
+ :maxdepth: 1
+ :name: whats_new_index
+ :hidden:
+
whatsnew/index
- techpapers/index
- copyright
+
+.. todolist::
\ No newline at end of file
diff --git a/docs/src/installing.rst b/docs/src/installing.rst
index 37a8942ab3..b2481973c0 100644
--- a/docs/src/installing.rst
+++ b/docs/src/installing.rst
@@ -1,7 +1,7 @@
.. _installing_iris:
-Installing Iris
-===============
+Installing
+==========
Iris is available using conda for the following platforms:
@@ -14,7 +14,7 @@ Subsystem for Linux). This is a great option to get started with Iris
for users and developers. Be aware that we do not currently test against
any WSL_ distributions.
-.. _WSL: https://docs.microsoft.com/en-us/windows/wsl/install-win10
+.. _WSL: https://learn.microsoft.com/en-us/windows/wsl/install
.. note:: Iris is currently supported and tested against |python_support|
running on Linux. We do not currently actively test on other
@@ -119,9 +119,9 @@ Running the Tests
To ensure your setup is configured correctly you can run the test suite using
the command::
- python setup.py test
+ pytest
-For more information see :ref:`developer_running_tests`.
+For more information see :ref:`test manual env`.
Custom Site Configuration
diff --git a/docs/src/spelling_allow.txt b/docs/src/spelling_allow.txt
deleted file mode 100644
index ed883ac3bf..0000000000
--- a/docs/src/spelling_allow.txt
+++ /dev/null
@@ -1,361 +0,0 @@
-Admin
-Albers
-Arakawa
-Arg
-Args
-Autoscale
-Biggus
-CF
-CI
-Cartopy
-Checklist
-Color
-Conda
-Constraining
-DAP
-Dask
-Debian
-Duchon
-EO
-Eos
-Exner
-Fieldsfile
-Fieldsfiles
-FillValue
-Gb
-GeogCS
-Hovmoller
-Jul
-Jun
-Jupyter
-Lanczos
-Mappables
-Matplotlib
-Mb
-Modeling
-Mollweide
-NetCDF
-Nino
-PPfield
-PPfields
-Perez
-Proj
-Quickplot
-Regrids
-Royer
-Scitools
-Scitools
-Sep
-Stehfest
-Steroegraphic
-Subsetting
-TestCodeFormat
-TestLicenseHeaders
-Torvalds
-Trans
-Trenberth
-Tri
-URIs
-URLs
-Ubuntu
-Ugrid
-Unidata
-Vol
-Vuuren
-Workflow
-Yury
-Zaytsev
-Zorder
-abf
-abl
-advection
-aggregator
-aggregators
-alphap
-ancils
-antimeridian
-ap
-arg
-args
-arithmetic
-arraylike
-atol
-auditable
-aux
-basemap
-behaviour
-betap
-bhulev
-biggus
-blev
-boolean
-boundpoints
-branchname
-broadcastable
-bugfix
-bugfixes
-builtin
-bulev
-carrée
-cartesian
-celsius
-center
-centrepoints
-cf
-cftime
-chunksizes
-ci
-clabel
-cmap
-cmpt
-codebase
-color
-colorbar
-colorbars
-complevel
-conda
-config
-constraining
-convertor
-coord
-coords
-cs
-datafiles
-datatype
-datetime
-datetimes
-ddof
-deepcopy
-deprecations
-der
-dewpoint
-dict
-dicts
-diff
-discontiguities
-discontiguous
-djf
-docstring
-docstrings
-doi
-dom
-dropdown
-dtype
-dtypes
-dx
-dy
-edgecolor
-endian
-endianness
-equirectangular
-eta
-etc
-fh
-fieldsfile
-fieldsfiles
-fileformat
-fileformats
-filename
-filenames
-filepath
-filespec
-fullname
-func
-geolocations
-github
-gregorian
-grib
-gribapi
-gridcell
-griddata
-gridlines
-hPa
-hashable
-hindcast
-hyperlink
-hyperlinks
-idiff
-ieee
-ifunc
-imagehash
-inc
-init
-inline
-inplace
-int
-interable
-interpolator
-ints
-io
-isosurfaces
-iterable
-jja
-jupyter
-kwarg
-kwargs
-landsea
-lat
-latlon
-latlons
-lats
-lbcode
-lbegin
-lbext
-lbfc
-lbft
-lblrec
-lbmon
-lbmond
-lbnrec
-lbrsvd
-lbtim
-lbuser
-lbvc
-lbyr
-lbyrd
-lh
-lhs
-linewidth
-linted
-linting
-lon
-lons
-lt
-mam
-markup
-matplotlib
-matplotlibrc
-max
-mdtol
-meaned
-mercator
-metadata
-min
-mpl
-nanmask
-nc
-ndarray
-neighbor
-ness
-netCDF
-netcdf
-netcdftime
-nimrod
-np
-nsigma
-numpy
-nx
-ny
-online
-orog
-paramId
-params
-parsable
-pcolormesh
-pdf
-placeholders
-plugin
-png
-proj
-ps
-pseudocolor
-pseudocolour
-pseudocoloured
-py
-pyplot
-quickplot
-rST
-rc
-rd
-reST
-reStructuredText
-rebase
-rebases
-rebasing
-regrid
-regridded
-regridder
-regridders
-regridding
-regrids
-rel
-repo
-repos
-reprojecting
-rh
-rhs
-rst
-rtol
-scipy
-scitools
-seekable
-setup
-sines
-sinh
-spec
-specs
-src
-ssh
-st
-stashcode
-stashcodes
-stats
-std
-stdout
-str
-subcube
-subcubes
-submodule
-submodules
-subsetting
-sys
-tanh
-tb
-testcases
-tgt
-th
-timepoint
-timestamp
-timesteps
-todo
-tol
-tos
-traceback
-travis
-tripolar
-tuple
-tuples
-txt
-udunits
-ufunc
-ugrid
-ukmo
-un
-unhandled
-unicode
-unittest
-unrotate
-unrotated
-uris
-url
-urls
-util
-var
-versioning
-vmax
-vmin
-waypoint
-waypoints
-whitespace
-wildcard
-wildcards
-windspeeds
-withnans
-workflow
-workflows
-xN
-xx
-xxx
-zeroth
-zlev
-zonal
diff --git a/docs/src/sphinxext/image_test_output.py b/docs/src/sphinxext/image_test_output.py
deleted file mode 100644
index 9e492a5be9..0000000000
--- a/docs/src/sphinxext/image_test_output.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright Iris contributors
-#
-# This file is part of Iris and is released under the LGPL license.
-# See COPYING and COPYING.LESSER in the root of the repository for full
-# licensing details.
-
-import json
-import re
-from typing import Dict, List
-
-from docutils import nodes
-from sphinx.application import Sphinx
-from sphinx.util.docutils import SphinxDirective
-
-ImageRepo = Dict[str, List[str]]
-
-HASH_MATCH = re.compile(r"([^\/]+)\.png$")
-
-
-def hash_from_url(url: str) -> str:
- match = HASH_MATCH.search(url)
- if not match:
- raise ValueError(f"url {url} does not match form `http...hash.png`")
- else:
- return match.groups()[0]
-
-
-class ImageTestDirective(SphinxDirective):
- def run(self):
- with open(self.config["image_test_json"], "r") as fh:
- imagerepo = json.load(fh)
- enum_list = nodes.enumerated_list()
- nodelist = []
- nodelist.append(enum_list)
- for test in sorted(imagerepo):
- link_node = nodes.raw(
- "",
- f'{test}',
- format="html",
- )
- li_node = nodes.list_item("")
- li_node += link_node
- enum_list += li_node
- return nodelist
-
-
-def collect_imagehash_pages(app: Sphinx):
- """Generate pages for each entry in the imagerepo.json"""
- with open(app.config["image_test_json"], "r") as fh:
- imagerepo: ImageRepo = json.load(fh)
- pages = []
- for test, hashfiles in imagerepo.items():
- hashstrs = [hash_from_url(h) for h in hashfiles]
- pages.append(
- (
- f"generated/image_test/{test}",
- {"test": test, "hashfiles": zip(hashstrs, hashfiles)},
- "imagehash.html",
- )
- )
- return pages
-
-
-def setup(app: Sphinx):
- app.add_config_value(
- "image_test_json",
- "../../lib/iris/tests/results/imagerepo.json",
- "html",
- )
-
- app.add_directive("imagetest-list", ImageTestDirective)
- app.connect("html-collect-pages", collect_imagehash_pages)
-
- return {
- "version": "0.1",
- "parallel_read_safe": True,
- "parallel_write_safe": True,
- }
diff --git a/docs/src/techpapers/um_files_loading.rst b/docs/src/techpapers/um_files_loading.rst
index 72d34962ce..f8c94cab08 100644
--- a/docs/src/techpapers/um_files_loading.rst
+++ b/docs/src/techpapers/um_files_loading.rst
@@ -350,7 +350,7 @@ information is contained in the :attr:`~iris.coords.Coord.units` property.
always 1st Jan 1970 (times before this are represented as negative values).
The units.calendar property of time coordinates is set from the lowest decimal
-digit of LBTIM, known as LBTIM.IC. Note that the non-gregorian calendars (e.g.
+digit of LBTIM, known as LBTIM.IC. Note that the non-standard calendars (e.g.
360-day 'model' calendar) are defined in CF, not udunits.
There are a number of different time encoding methods used in UM data, but the
diff --git a/docs/src/userguide/citation.rst b/docs/src/userguide/citation.rst
index 0a3a85fb89..1498b9dfe1 100644
--- a/docs/src/userguide/citation.rst
+++ b/docs/src/userguide/citation.rst
@@ -15,11 +15,12 @@ For example::
@manual{Iris,
author = {{Met Office}},
- title = {Iris: A Python package for analysing and visualising meteorological and oceanographic data sets},
- edition = {v1.2},
- year = {2010 - 2013},
+ title = {Iris: A powerful, format-agnostic, and community-driven Python package for analysing and visualising Earth science data },
+ edition = {v3.4},
+ year = {2010 - 2022},
address = {Exeter, Devon },
- url = {http://scitools.org.uk/}
+ url = {http://scitools.org.uk/},
+ doi = {10.5281/zenodo.7386117}
}
@@ -33,7 +34,7 @@ Suggested format::
For example::
- Iris. v1.2. 28-Feb-2013. Met Office. UK. https://github.com/SciTools/iris/archive/v1.2.0.tar.gz 01-03-2013
+ Iris. v3.4. 1-Dec-2022. Met Office. UK. https://doi.org/10.5281/zenodo.7386117 22-12-2022
********************
@@ -46,7 +47,7 @@ Suggested format::
For example::
- Iris. Met Office. git@github.com:SciTools/iris.git 06-03-2013
+ Iris. Met Office. git@github.com:SciTools/iris.git 22-12-2022
.. _How to cite and describe software: https://software.ac.uk/how-cite-software
diff --git a/docs/src/userguide/code_maintenance.rst b/docs/src/userguide/code_maintenance.rst
index b2b498bc80..c01c1975a7 100644
--- a/docs/src/userguide/code_maintenance.rst
+++ b/docs/src/userguide/code_maintenance.rst
@@ -12,17 +12,17 @@ In practice, as Iris develops, most users will want to periodically upgrade
their installed version to access new features or at least bug fixes.
This is obvious if you are still developing other code that uses Iris, or using
-code from other sources.
+code from other sources.
However, even if you have only legacy code that remains untouched, some code
maintenance effort is probably still necessary:
- * On the one hand, *in principle*, working code will go on working, as long
- as you don't change anything else.
+* On the one hand, *in principle*, working code will go on working, as long
+ as you don't change anything else.
- * However, such "version stasis" can easily become a growing burden, if you
- are simply waiting until an update becomes unavoidable, often that will
- eventually occur when you need to update some other software component,
- for some completely unconnected reason.
+* However, such "version stasis" can easily become a growing burden, if you
+ are simply waiting until an update becomes unavoidable, often that will
+ eventually occur when you need to update some other software component,
+ for some completely unconnected reason.
Principles of Change Management
@@ -35,13 +35,13 @@ In Iris, however, we aim to reduce code maintenance problems to an absolute
minimum by following defined change management rules.
These ensure that, *within a major release number* :
- * you can be confident that your code will still work with subsequent minor
- releases
+* you can be confident that your code will still work with subsequent minor
+ releases
- * you will be aware of future incompatibility problems in advance
+* you will be aware of future incompatibility problems in advance
- * you can defer making code compatibility changes for some time, until it
- suits you
+* you can defer making code compatibility changes for some time, until it
+ suits you
The above applies to minor version upgrades : e.g. code that works with version
"1.4.2" should still work with a subsequent minor release such as "1.5.0" or
diff --git a/docs/src/userguide/cube_maths.rst b/docs/src/userguide/cube_maths.rst
index e8a1744a44..56a2041bd3 100644
--- a/docs/src/userguide/cube_maths.rst
+++ b/docs/src/userguide/cube_maths.rst
@@ -5,8 +5,8 @@ Cube Maths
==========
-The section :doc:`navigating_a_cube` highlighted that
-every cube has a data attribute;
+The section :doc:`navigating_a_cube` highlighted that
+every cube has a data attribute;
this attribute can then be manipulated directly::
cube.data -= 273.15
@@ -37,8 +37,8 @@ Let's load some air temperature which runs from 1860 to 2100::
filename = iris.sample_data_path('E1_north_america.nc')
air_temp = iris.load_cube(filename, 'air_temperature')
-We can now get the first and last time slices using indexing
-(see :ref:`subsetting_a_cube` for a reminder)::
+We can now get the first and last time slices using indexing
+(see :ref:`cube_indexing` for a reminder)::
t_first = air_temp[0, :, :]
t_last = air_temp[-1, :, :]
@@ -50,8 +50,8 @@ We can now get the first and last time slices using indexing
t_first = air_temp[0, :, :]
t_last = air_temp[-1, :, :]
-And finally we can subtract the two.
-The result is a cube of the same size as the original two time slices,
+And finally we can subtract the two.
+The result is a cube of the same size as the original two time slices,
but with the data representing their difference:
>>> print(t_last - t_first)
@@ -70,8 +70,8 @@ but with the data representing their difference:
.. note::
- Notice that the coordinates "time" and "forecast_period" have been removed
- from the resultant cube;
+ Notice that the coordinates "time" and "forecast_period" have been removed
+ from the resultant cube;
this is because these coordinates differed between the two input cubes.
@@ -165,18 +165,24 @@ broadcasting behaviour::
>>> print(result.summary(True))
unknown / (K) (time: 240; latitude: 37; longitude: 49)
+
+.. seealso::
+
+ Relevant gallery example:
+ :ref:`sphx_glr_generated_gallery_general_plot_anomaly_log_colouring.py` (Anomaly)
+
Combining Multiple Phenomena to Form a New One
----------------------------------------------
-Combining cubes of potential-temperature and pressure we can calculate
+Combining cubes of potential-temperature and pressure we can calculate
the associated temperature using the equation:
.. math::
-
+
T = \theta (\frac{p}{p_0}) ^ {(287.05 / 1005)}
-Where :math:`p` is pressure, :math:`\theta` is potential temperature,
-:math:`p_0` is the potential temperature reference pressure
+Where :math:`p` is pressure, :math:`\theta` is potential temperature,
+:math:`p_0` is the potential temperature reference pressure
and :math:`T` is temperature.
First, let's load pressure and potential temperature cubes::
@@ -185,7 +191,7 @@ First, let's load pressure and potential temperature cubes::
phenomenon_names = ['air_potential_temperature', 'air_pressure']
pot_temperature, pressure = iris.load_cubes(filename, phenomenon_names)
-In order to calculate :math:`\frac{p}{p_0}` we can define a coordinate which
+In order to calculate :math:`\frac{p}{p_0}` we can define a coordinate which
represents the standard reference pressure of 1000 hPa::
import iris.coords
@@ -199,7 +205,7 @@ the :meth:`iris.coords.Coord.convert_units` method::
p0.convert_units(pressure.units)
-Now we can combine all of this information to calculate the air temperature
+Now we can combine all of this information to calculate the air temperature
using the equation above::
temperature = pot_temperature * ( (pressure / p0) ** (287.05 / 1005) )
@@ -213,12 +219,12 @@ The result could now be plotted using the guidance provided in the
.. only:: html
- A very similar example to this can be found in
+ A very similar example to this can be found in
:ref:`sphx_glr_generated_gallery_meteorology_plot_deriving_phenomena.py`.
.. only:: latex
- A very similar example to this can be found in the examples section,
+ A very similar example to this can be found in the examples section,
with the title "Deriving Exner Pressure and Air Temperature".
.. _cube_maths_combining_units:
@@ -243,7 +249,7 @@ unit (if ``a`` had units ``'m2'`` then ``a ** 0.5`` would result in a cube
with units ``'m'``).
Iris inherits units from `cf_units `_
-which in turn inherits from `UDUNITS `_.
+which in turn inherits from `UDUNITS `_.
As well as the units UDUNITS provides, cf units also provides the units
``'no-unit'`` and ``'unknown'``. A unit of ``'no-unit'`` means that the
associated data is not suitable for describing with a unit, cf units
diff --git a/docs/src/userguide/cube_statistics.rst b/docs/src/userguide/cube_statistics.rst
index 980f1e132f..08297c2a51 100644
--- a/docs/src/userguide/cube_statistics.rst
+++ b/docs/src/userguide/cube_statistics.rst
@@ -4,6 +4,11 @@
Cube Statistics
===============
+.. seealso::
+
+ Relevant gallery example:
+ :ref:`sphx_glr_generated_gallery_general_plot_zonal_means.py` (Collapsing)
+
.. _cube-statistics-collapsing:
Collapsing Entire Data Dimensions
diff --git a/docs/src/userguide/glossary.rst b/docs/src/userguide/glossary.rst
new file mode 100644
index 0000000000..5c24f03372
--- /dev/null
+++ b/docs/src/userguide/glossary.rst
@@ -0,0 +1,214 @@
+.. include:: ../common_links.inc
+
+.. _glossary:
+
+Glossary
+=============
+
+.. glossary::
+
+ Cartopy
+ A python package for producing maps, and other geospatial data.
+ Allows plotting on these maps, over a range of projections.
+
+ | **Related:** :term:`Matplotlib`
+ | **More information:** `CartoPy Site `_
+ |
+
+ CF Conventions
+ Rules for storing meteorological Climate and Forecast data in
+ :term:`NetCDF Format` files, defining a standard metadata format to
+ describe what the data is.
+ This also forms the data model which iris is based on.
+
+ | **Related:** :term:`NetCDF Format`
+ | **More information:** `CF Conventions `_
+ |
+
+ Coordinate
+ A container for data points, comes in three main flavours.
+
+ - Dimensional Coordinate -
+ A coordinate that describes a single data dimension of a cube.
+ They can only contain numerical values, in a sorted order (ascending
+ or descending).
+ - Auxiliary Coordinate -
+ A coordinate that can map to multiple data dimensions. Can
+ contain any type of data.
+ - Scalar Coordinate -
+ A coordinate that is not mapped to any data dimension, instead
+ representing the cube as a whole.
+
+ | **Related:** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Cube
+ Cubes are the main method of storing data in Iris. A cube can consist of:
+
+ - Array of :term:`Phenomenon` Data (Required)
+ - :term:`Coordinates `
+ - :term:`Standard Name`
+ - :term:`Long Name`
+ - :term:`Unit`
+ - :term:`Cell Methods `
+ - :term:`Coordinate Factories `
+
+ | **Related:** :term:`NumPy`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Cell Method
+ A cell method represents that a cube's data has been derived from
+ a past statistical operation, such as a
+ MEAN or SUM operation.
+
+ | **Related:** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Coordinate Factory
+ A coordinate factory derives coordinates (sometimes referred to as
+ derived coordinates) from the values of existing coordinates.
+ E.g. A hybrid height factory might use "height above sea level"
+ and "height at ground level" coordinate data to calculate a
+ "height above ground level" coordinate.
+
+ | **Related:** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+
+ Dask
+ A data analytics python library. Iris predominantly uses Dask Arrays;
+ a collection of NumPy-esque arrays. The data is operated in batches,
+ so that not all data is in RAM at once.
+
+ | **Related:** :term:`Lazy Data` **|** :term:`NumPy`
+ | **More information:** :doc:`real_and_lazy_data`
+ |
+
+ Fields File (FF) Format
+ A meteorological file format, the output of the Unified Model.
+
+ | **Related:** :term:`GRIB Format`
+ **|** :term:`Post Processing (PP) Format` **|** :term:`NetCDF Format`
+ | **More information:** `Unified Model `_
+ |
+
+ GRIB Format
+ A WMO-standard meteorological file format.
+
+ | **Related:** :term:`Fields File (FF) Format`
+ **|** :term:`Post Processing (PP) Format` **|** :term:`NetCDF Format`
+ | **More information:** `GRIB 1 User Guide `_
+ **|** `GRIB 2 User Guide.pdf `_
+ |
+
+ Lazy Data
+ Data stored in hard drive, and then temporarily loaded into RAM in
+ batches when needed. Allows of less memory usage and faster performance,
+ thanks to parallel processing.
+
+ | **Related:** :term:`Dask` **|** :term:`Real Data`
+ | **More information:** :doc:`real_and_lazy_data`
+ |
+
+ Long Name
+ A name describing a :term:`phenomenon`, not limited to the
+ the same restraints as :term:`standard name`.
+
+ | **Related:** :term:`Standard Name` **|** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Matplotlib
+ A python package for plotting and projecting data in a wide variety
+ of formats.
+
+ | **Related:** :term:`CartoPy` **|** :term:`NumPy`
+ | **More information:** `matplotlib`_
+ |
+
+ Metadata
+ The information which describes a phenomenon.
+ Within Iris specifically, all information which
+ distinguishes one phenomenon from another,
+ e.g. :term:`units ` or :term:`Cell Methods `
+
+ | **Related:** :term:`Phenomenon` **|** :term:`Cube`
+ | **More information:** :doc:`../further_topics/metadata`
+ |
+
+ NetCDF Format
+ A flexible file format for storing multi-dimensional array-like data.
+ When Iris loads this format, it also especially recognises and interprets data
+ encoded according to the :term:`CF Conventions`.
+
+ __ `NetCDF4`_
+
+ | **Related:** :term:`Fields File (FF) Format`
+ **|** :term:`GRIB Format` **|** :term:`Post Processing (PP) Format`
+ | **More information:** `NetCDF-4 Python Git`__
+ |
+
+ NumPy
+ A mathematical Python library, predominantly based around
+ multi-dimensional arrays.
+
+ | **Related:** :term:`Dask` **|** :term:`Cube`
+ **|** :term:`Xarray`
+ | **More information:** `NumPy.org `_
+ |
+
+ Phenomenon
+ The primary data which is measured, usually within a cube, e.g.
+ air temperature.
+
+ | **Related:** :term:`Metadata`
+ **|** :term:`Standard Name` **|** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Post Processing (PP) Format
+ A meteorological file format, created from a post processed
+ :term:`Fields File (FF) Format`.
+
+ | **Related:** :term:`GRIB Format` **|** :term:`NetCDF Format`
+ | **More information:** `PP Wikipedia Page `_
+ |
+
+ Real Data
+ Data that has been loaded into RAM, as opposed to sitting
+ on the hard drive.
+
+ | **Related:** :term:`Lazy Data` **|** :term:`NumPy`
+ | **More information:** :doc:`real_and_lazy_data`
+ |
+
+ Standard Name
+ A name describing a :term:`phenomenon`, one from a fixed list
+ defined at `CF Standard Names `_.
+
+ | **Related:** :term:`Long Name` **|** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Unit
+ The unit with which the :term:`phenomenon` is measured e.g. m / sec.
+
+ | **Related:** :term:`Cube`
+ | **More information:** :doc:`iris_cubes`
+ |
+
+ Xarray
+ A python library for sophisticated labelled multi-dimensional operations.
+ Has a broader scope than Iris - it is not focused on meteorological data.
+
+ | **Related:** :term:`NumPy`
+ | **More information:** `Xarray Documentation `_
+ |
+
+----
+
+`To top `_
diff --git a/docs/src/userguide/index.rst b/docs/src/userguide/index.rst
index 2a3b32fe11..fdd0c4d03e 100644
--- a/docs/src/userguide/index.rst
+++ b/docs/src/userguide/index.rst
@@ -1,31 +1,48 @@
.. _user_guide_index:
.. _user_guide_introduction:
-Introduction
-============
+User Guide
+==========
-If you are reading this user guide for the first time it is strongly recommended that you read the user guide
-fully before experimenting with your own data files.
+If you are reading this user guide for the first time it is strongly
+recommended that you read the user guide fully before experimenting with your
+own data files.
-
-Much of the content has supplementary links to the reference documentation; you will not need to follow these
-links in order to understand the guide but they may serve as a useful reference for future exploration.
+Much of the content has supplementary links to the reference documentation;
+you will not need to follow these links in order to understand the guide but
+they may serve as a useful reference for future exploration.
.. only:: html
- Since later pages depend on earlier ones, try reading this user guide sequentially using the ``next`` and ``previous`` links.
-
-
-* :doc:`iris_cubes`
-* :doc:`loading_iris_cubes`
-* :doc:`saving_iris_cubes`
-* :doc:`navigating_a_cube`
-* :doc:`subsetting_a_cube`
-* :doc:`real_and_lazy_data`
-* :doc:`plotting_a_cube`
-* :doc:`interpolation_and_regridding`
-* :doc:`merge_and_concat`
-* :doc:`cube_statistics`
-* :doc:`cube_maths`
-* :doc:`citation`
-* :doc:`code_maintenance`
+ Since later pages depend on earlier ones, try reading this user guide
+ sequentially using the ``next`` and ``previous`` links at the bottom
+ of each page.
+
+
+.. toctree::
+ :maxdepth: 2
+
+ iris_cubes
+ loading_iris_cubes
+ saving_iris_cubes
+ navigating_a_cube
+ subsetting_a_cube
+ real_and_lazy_data
+ plotting_a_cube
+ interpolation_and_regridding
+ merge_and_concat
+ cube_statistics
+ cube_maths
+ citation
+ code_maintenance
+ glossary
+
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Further Topics
+
+ ../further_topics/metadata
+ ../further_topics/lenient_metadata
+ ../further_topics/lenient_maths
+ ../further_topics/ugrid/index
diff --git a/docs/src/userguide/interpolation_and_regridding.rst b/docs/src/userguide/interpolation_and_regridding.rst
index f590485606..deae4427ed 100644
--- a/docs/src/userguide/interpolation_and_regridding.rst
+++ b/docs/src/userguide/interpolation_and_regridding.rst
@@ -19,14 +19,14 @@ In Iris we refer to the available types of interpolation and regridding as
`schemes`. The following are the interpolation schemes that are currently
available in Iris:
- * linear interpolation (:class:`iris.analysis.Linear`), and
- * nearest-neighbour interpolation (:class:`iris.analysis.Nearest`).
+* linear interpolation (:class:`iris.analysis.Linear`), and
+* nearest-neighbour interpolation (:class:`iris.analysis.Nearest`).
The following are the regridding schemes that are currently available in Iris:
- * linear regridding (:class:`iris.analysis.Linear`),
- * nearest-neighbour regridding (:class:`iris.analysis.Nearest`), and
- * area-weighted regridding (:class:`iris.analysis.AreaWeighted`, first-order conservative).
+* linear regridding (:class:`iris.analysis.Linear`),
+* nearest-neighbour regridding (:class:`iris.analysis.Nearest`), and
+* area-weighted regridding (:class:`iris.analysis.AreaWeighted`, first-order conservative).
The linear, nearest-neighbor, and area-weighted regridding schemes support
lazy regridding, i.e. if the source cube has lazy data, the resulting cube
@@ -42,8 +42,8 @@ Interpolation
Interpolating a cube is achieved with the :meth:`~iris.cube.Cube.interpolate`
method. This method expects two arguments:
- #. the sample points to interpolate, and
- #. the interpolation scheme to use.
+#. the sample points to interpolate, and
+#. the interpolation scheme to use.
The result is a new cube, interpolated at the sample points.
@@ -51,9 +51,9 @@ Sample points must be defined as an iterable of ``(coord, value(s))`` pairs.
The `coord` argument can be either a coordinate name or coordinate instance.
The specified coordinate must exist on the cube being interpolated! For example:
- * coordinate names and scalar sample points: ``[('latitude', 51.48), ('longitude', 0)]``,
- * a coordinate instance and a scalar sample point: ``[(cube.coord('latitude'), 51.48)]``, and
- * a coordinate name and a NumPy array of sample points: ``[('longitude', np.linspace(-11, 2, 14))]``
+* coordinate names and scalar sample points: ``[('latitude', 51.48), ('longitude', 0)]``,
+* a coordinate instance and a scalar sample point: ``[(cube.coord('latitude'), 51.48)]``, and
+* a coordinate name and a NumPy array of sample points: ``[('longitude', np.linspace(-11, 2, 14))]``
are all examples of valid sample points.
@@ -175,11 +175,11 @@ The extrapolation mode is controlled by the ``extrapolation_mode`` keyword.
For the available interpolation schemes available in Iris, the ``extrapolation_mode``
keyword must be one of:
- * ``extrapolate`` -- the extrapolation points will be calculated by extending the gradient of the closest two points,
- * ``error`` -- a ValueError exception will be raised, notifying an attempt to extrapolate,
- * ``nan`` -- the extrapolation points will be be set to NaN,
- * ``mask`` -- the extrapolation points will always be masked, even if the source data is not a MaskedArray, or
- * ``nanmask`` -- if the source data is a MaskedArray the extrapolation points will be masked. Otherwise they will be set to NaN.
+* ``extrapolate`` -- the extrapolation points will be calculated by extending the gradient of the closest two points,
+* ``error`` -- a ValueError exception will be raised, notifying an attempt to extrapolate,
+* ``nan`` -- the extrapolation points will be be set to NaN,
+* ``mask`` -- the extrapolation points will always be masked, even if the source data is not a MaskedArray, or
+* ``nanmask`` -- if the source data is a MaskedArray the extrapolation points will be masked. Otherwise they will be set to NaN.
Using an extrapolation mode is achieved by constructing an interpolation scheme
with the extrapolation mode keyword set as required. The constructed scheme
@@ -206,8 +206,8 @@ intensive part of an interpolation is setting up the interpolator.
To cache an interpolator you must set up an interpolator scheme and call the
scheme's interpolator method. The interpolator method takes as arguments:
- #. a cube to be interpolated, and
- #. an iterable of coordinate names or coordinate instances of the coordinates that are to be interpolated over.
+#. a cube to be interpolated, and
+#. an iterable of coordinate names or coordinate instances of the coordinates that are to be interpolated over.
For example:
@@ -244,8 +244,8 @@ regridding is based on the **horizontal** grid of *another cube*.
Regridding a cube is achieved with the :meth:`cube.regrid() ` method.
This method expects two arguments:
- #. *another cube* that defines the target grid onto which the cube should be regridded, and
- #. the regridding scheme to use.
+#. *another cube* that defines the target grid onto which the cube should be regridded, and
+#. the regridding scheme to use.
.. note::
@@ -278,15 +278,15 @@ mode when defining the regridding scheme.
For the available regridding schemes in Iris, the ``extrapolation_mode`` keyword
must be one of:
- * ``extrapolate`` --
+* ``extrapolate`` --
- * for :class:`~iris.analysis.Linear` the extrapolation points will be calculated by extending the gradient of the closest two points.
- * for :class:`~iris.analysis.Nearest` the extrapolation points will take their value from the nearest source point.
+ * for :class:`~iris.analysis.Linear` the extrapolation points will be calculated by extending the gradient of the closest two points.
+ * for :class:`~iris.analysis.Nearest` the extrapolation points will take their value from the nearest source point.
- * ``nan`` -- the extrapolation points will be be set to NaN.
- * ``error`` -- a ValueError exception will be raised, notifying an attempt to extrapolate.
- * ``mask`` -- the extrapolation points will always be masked, even if the source data is not a MaskedArray.
- * ``nanmask`` -- if the source data is a MaskedArray the extrapolation points will be masked. Otherwise they will be set to NaN.
+* ``nan`` -- the extrapolation points will be be set to NaN.
+* ``error`` -- a ValueError exception will be raised, notifying an attempt to extrapolate.
+* ``mask`` -- the extrapolation points will always be masked, even if the source data is not a MaskedArray.
+* ``nanmask`` -- if the source data is a MaskedArray the extrapolation points will be masked. Otherwise they will be set to NaN.
The ``rotated_psl`` cube is defined on a limited area rotated pole grid. If we regridded
the ``rotated_psl`` cube onto the global grid as defined by the ``global_air_temp`` cube
@@ -395,8 +395,8 @@ intensive part of a regrid is setting up the regridder.
To cache a regridder you must set up a regridder scheme and call the
scheme's regridder method. The regridder method takes as arguments:
- #. a cube (that is to be regridded) defining the source grid, and
- #. a cube defining the target grid to regrid the source cube to.
+#. a cube (that is to be regridded) defining the source grid, and
+#. a cube defining the target grid to regrid the source cube to.
For example:
diff --git a/docs/src/userguide/iris_cubes.rst b/docs/src/userguide/iris_cubes.rst
index d13dee369c..29d8f3cefc 100644
--- a/docs/src/userguide/iris_cubes.rst
+++ b/docs/src/userguide/iris_cubes.rst
@@ -4,82 +4,105 @@
Iris Data Structures
====================
-The top level object in Iris is called a cube. A cube contains data and metadata about a phenomenon.
+The top level object in Iris is called a cube. A cube contains data and
+metadata about a phenomenon.
-In Iris, a cube is an interpretation of the *Climate and Forecast (CF) Metadata Conventions* whose purpose is to:
+In Iris, a cube is an interpretation of the *Climate and Forecast (CF)
+Metadata Conventions* whose purpose is to:
- *require conforming datasets to contain sufficient metadata that they are self-describing... including physical
- units if appropriate, and that each value can be located in space (relative to earth-based coordinates) and time.*
+.. panels::
+ :container: container-lg pb-3
+ :column: col-lg-12 p-2
-Whilst the CF conventions are often mentioned alongside NetCDF, Iris implements several major format importers which can take
-files of specific formats and turn them into Iris cubes. Additionally, a framework is provided which allows users
-to extend Iris' import capability to cater for specialist or unimplemented formats.
+ *require conforming datasets to contain sufficient metadata that they are
+ self-describing... including physical units if appropriate, and that each
+ value can be located in space (relative to earth-based coordinates) and
+ time.*
-A single cube describes one and only one phenomenon, always has a name, a unit and
-an n-dimensional data array to represents the cube's phenomenon. In order to locate the
-data spatially, temporally, or in any other higher-dimensional space, a collection of *coordinates*
-exist on the cube.
+
+Whilst the CF conventions are often mentioned alongside NetCDF, Iris implements
+several major format importers which can take files of specific formats and
+turn them into Iris cubes. Additionally, a framework is provided which allows
+users to extend Iris' import capability to cater for specialist or
+unimplemented formats.
+
+A single cube describes one and only one phenomenon, always has a name, a unit
+and an n-dimensional data array to represents the cube's phenomenon. In order
+to locate the data spatially, temporally, or in any other higher-dimensional
+space, a collection of *coordinates* exist on the cube.
Coordinates
===========
-A coordinate is a container to store metadata about some dimension(s) of a cube's data array and therefore,
-by definition, its phenomenon.
-
- * Each coordinate has a name and a unit.
- * When a coordinate is added to a cube, the data dimensions that it represents are also provided.
-
- * The shape of a coordinate is always the same as the shape of the associated data dimension(s) on the cube.
- * A dimension not explicitly listed signifies that the coordinate is independent of that dimension.
- * Each dimension of a coordinate must be mapped to a data dimension. The only coordinates with no mapping are
- scalar coordinates.
-
- * Depending on the underlying data that the coordinate is representing, its values may be discrete points or be
- bounded to represent interval extents (e.g. temperature at *point x* **vs** rainfall accumulation *between 0000-1200 hours*).
- * Coordinates have an attributes dictionary which can hold arbitrary extra metadata, excluding certain restricted CF names
- * More complex coordinates may contain a coordinate system which is necessary to fully interpret the values
- contained within the coordinate.
-
+A coordinate is a container to store metadata about some dimension(s) of a
+cube's data array and therefore, by definition, its phenomenon.
+
+* Each coordinate has a name and a unit.
+* When a coordinate is added to a cube, the data dimensions that it
+ represents are also provided.
+
+ * The shape of a coordinate is always the same as the shape of the
+ associated data dimension(s) on the cube.
+ * A dimension not explicitly listed signifies that the coordinate is
+ independent of that dimension.
+ * Each dimension of a coordinate must be mapped to a data dimension. The
+ only coordinates with no mapping are scalar coordinates.
+
+* Depending on the underlying data that the coordinate is representing, its
+ values may be discrete points or be bounded to represent interval extents
+ (e.g. temperature at *point x* **vs** rainfall accumulation *between
+ 0000-1200 hours*).
+* Coordinates have an attributes dictionary which can hold arbitrary extra
+ metadata, excluding certain restricted CF names
+* More complex coordinates may contain a coordinate system which is
+ necessary to fully interpret the values contained within the coordinate.
+
There are two classes of coordinates:
- **DimCoord**
-
- * Numeric
- * Monotonic
- * Representative of, at most, a single data dimension (1d)
+**DimCoord**
+
+* Numeric
+* Monotonic
+* Representative of, at most, a single data dimension (1d)
+
+**AuxCoord**
+
+* May be of any type, including strings
+* May represent multiple data dimensions (n-dimensional)
- **AuxCoord**
-
- * May be of any type, including strings
- * May represent multiple data dimensions (n-dimensional)
-
Cube
====
A cube consists of:
- * a standard name and/or a long name and an appropriate unit
- * a data array who's values are representative of the phenomenon
- * a collection of coordinates and associated data dimensions on the cube's data array, which are split into two separate lists:
+* a standard name and/or a long name and an appropriate unit
+* a data array who's values are representative of the phenomenon
+* a collection of coordinates and associated data dimensions on the cube's
+ data array, which are split into two separate lists:
+
+ * *dimension coordinates* - DimCoords which uniquely map to exactly one
+ data dimension, ordered by dimension.
+ * *auxiliary coordinates* - DimCoords or AuxCoords which map to as many
+ data dimensions as the coordinate has dimensions.
- * *dimension coordinates* - DimCoords which uniquely map to exactly one data dimension, ordered by dimension.
- * *auxiliary coordinates* - DimCoords or AuxCoords which map to as many data dimensions as the coordinate has dimensions.
-
- * an attributes dictionary which, other than some protected CF names, can hold arbitrary extra metadata.
- * a list of cell methods to represent operations which have already been applied to the data (e.g. "mean over time")
- * a list of coordinate "factories" used for deriving coordinates from the values of other coordinates in the cube
+* an attributes dictionary which, other than some protected CF names, can
+ hold arbitrary extra metadata.
+* a list of cell methods to represent operations which have already been
+ applied to the data (e.g. "mean over time")
+* a list of coordinate "factories" used for deriving coordinates from the
+ values of other coordinates in the cube
Cubes in Practice
-----------------
-
A Simple Cube Example
=====================
-Suppose we have some gridded data which has 24 air temperature readings (in Kelvin) which is located at
-4 different longitudes, 2 different latitudes and 3 different heights. Our data array can be represented pictorially:
+Suppose we have some gridded data which has 24 air temperature readings
+(in Kelvin) which is located at 4 different longitudes, 2 different latitudes
+and 3 different heights. Our data array can be represented pictorially:
.. image:: multi_array.png
@@ -87,61 +110,66 @@ Where dimensions 0, 1, and 2 have lengths 3, 2 and 4 respectively.
The Iris cube to represent this data would consist of:
- * a standard name of ``air_temperature`` and a unit of ``kelvin``
- * a data array of shape ``(3, 2, 4)``
- * a coordinate, mapping to dimension 0, consisting of:
-
- * a standard name of ``height`` and unit of ``meters``
- * an array of length 3 representing the 3 ``height`` points
-
- * a coordinate, mapping to dimension 1, consisting of:
-
- * a standard name of ``latitude`` and unit of ``degrees``
- * an array of length 2 representing the 2 latitude points
- * a coordinate system such that the ``latitude`` points could be fully located on the globe
-
- * a coordinate, mapping to dimension 2, consisting of:
-
- * a standard name of ``longitude`` and unit of ``degrees``
- * an array of length 4 representing the 4 longitude points
- * a coordinate system such that the ``longitude`` points could be fully located on the globe
-
+* a standard name of ``air_temperature`` and a unit of ``kelvin``
+* a data array of shape ``(3, 2, 4)``
+* a coordinate, mapping to dimension 0, consisting of:
+
+ * a standard name of ``height`` and unit of ``meters``
+ * an array of length 3 representing the 3 ``height`` points
+* a coordinate, mapping to dimension 1, consisting of:
+ * a standard name of ``latitude`` and unit of ``degrees``
+ * an array of length 2 representing the 2 latitude points
+ * a coordinate system such that the ``latitude`` points could be fully
+ located on the globe
-Pictorially the cube has taken on more information than a simple array:
+* a coordinate, mapping to dimension 2, consisting of:
+
+ * a standard name of ``longitude`` and unit of ``degrees``
+ * an array of length 4 representing the 4 longitude points
+ * a coordinate system such that the ``longitude`` points could be fully
+ located on the globe
+
+Pictorially the cube has taken on more information than a simple array:
.. image:: multi_array_to_cube.png
-Additionally further information may be optionally attached to the cube.
-For example, it is possible to attach any of the following:
-
- * a coordinate, not mapping to any data dimensions, consisting of:
-
- * a standard name of ``time`` and unit of ``days since 2000-01-01 00:00``
- * a data array of length 1 representing the time that the data array is valid for
-
- * an auxiliary coordinate, mapping to dimensions 1 and 2, consisting of:
-
- * a long name of ``place name`` and no unit
- * a 2d string array of shape ``(2, 4)`` with the names of the 8 places that the lat/lons correspond to
-
- * an auxiliary coordinate "factory", which can derive its own mapping, consisting of:
-
- * a standard name of ``height`` and a unit of ``feet``
- * knowledge of how data values for this coordinate can be calculated given the ``height in meters`` coordinate
-
- * a cell method of "mean" over "ensemble" to indicate that the data has been meaned over
- a collection of "ensembles" (i.e. multiple model runs).
+Additionally further information may be optionally attached to the cube.
+For example, it is possible to attach any of the following:
+
+* a coordinate, not mapping to any data dimensions, consisting of:
+
+ * a standard name of ``time`` and unit of ``days since 2000-01-01 00:00``
+ * a data array of length 1 representing the time that the data array is
+ valid for
+
+* an auxiliary coordinate, mapping to dimensions 1 and 2, consisting of:
+
+ * a long name of ``place name`` and no unit
+ * a 2d string array of shape ``(2, 4)`` with the names of the 8 places
+ that the lat/lons correspond to
+
+* an auxiliary coordinate "factory", which can derive its own mapping,
+ consisting of:
+
+ * a standard name of ``height`` and a unit of ``feet``
+ * knowledge of how data values for this coordinate can be calculated
+ given the ``height in meters`` coordinate
+
+* a cell method of "mean" over "ensemble" to indicate that the data has been
+ meaned over a collection of "ensembles" (i.e. multiple model runs).
Printing a Cube
===============
-Every Iris cube can be printed to screen as you will see later in the user guide. It is worth familiarising yourself with the
-output as this is the quickest way of inspecting the contents of a cube. Here is the result of printing a real life cube:
+Every Iris cube can be printed to screen as you will see later in the user
+guide. It is worth familiarising yourself with the output as this is the
+quickest way of inspecting the contents of a cube. Here is the result of
+printing a real life cube:
.. _hybrid_cube_printout:
@@ -150,7 +178,7 @@ output as this is the quickest way of inspecting the contents of a cube. Here is
import iris
filename = iris.sample_data_path('uk_hires.pp')
- # NOTE: Every time the output of this cube changes, the full list of deductions below should be re-assessed.
+ # NOTE: Every time the output of this cube changes, the full list of deductions below should be re-assessed.
print(iris.load_cube(filename, 'air_potential_temperature'))
.. testoutput::
@@ -178,16 +206,22 @@ output as this is the quickest way of inspecting the contents of a cube. Here is
Using this output we can deduce that:
- * The cube represents air potential temperature.
- * There are 4 data dimensions, and the data has a shape of ``(3, 7, 204, 187)``
- * The 4 data dimensions are mapped to the ``time``, ``model_level_number``,
- ``grid_latitude``, ``grid_longitude`` coordinates respectively
- * There are three 1d auxiliary coordinates and one 2d auxiliary (``surface_altitude``)
- * There is a single ``altitude`` derived coordinate, which spans 3 data dimensions
- * There are 7 distinct values in the "model_level_number" coordinate. Similar inferences can
- be made for the other dimension coordinates.
- * There are 7, not necessarily distinct, values in the ``level_height`` coordinate.
- * There is a single ``forecast_reference_time`` scalar coordinate representing the entire cube.
- * The cube has one further attribute relating to the phenomenon.
- In this case the originating file format, PP, encodes information in a STASH code which in some cases can
- be useful for identifying advanced experiment information relating to the phenomenon.
+* The cube represents air potential temperature.
+* There are 4 data dimensions, and the data has a shape of ``(3, 7, 204, 187)``
+* The 4 data dimensions are mapped to the ``time``, ``model_level_number``,
+ ``grid_latitude``, ``grid_longitude`` coordinates respectively
+* There are three 1d auxiliary coordinates and one 2d auxiliary
+ (``surface_altitude``)
+* There is a single ``altitude`` derived coordinate, which spans 3 data
+ dimensions
+* There are 7 distinct values in the "model_level_number" coordinate. Similar
+ inferences can
+ be made for the other dimension coordinates.
+* There are 7, not necessarily distinct, values in the ``level_height``
+ coordinate.
+* There is a single ``forecast_reference_time`` scalar coordinate representing
+ the entire cube.
+* The cube has one further attribute relating to the phenomenon.
+ In this case the originating file format, PP, encodes information in a STASH
+ code which in some cases can be useful for identifying advanced experiment
+ information relating to the phenomenon.
diff --git a/docs/src/userguide/loading_iris_cubes.rst b/docs/src/userguide/loading_iris_cubes.rst
index fb938975e8..33ad932d70 100644
--- a/docs/src/userguide/loading_iris_cubes.rst
+++ b/docs/src/userguide/loading_iris_cubes.rst
@@ -39,15 +39,15 @@ This shows that there were 2 cubes as a result of loading the file, they were:
The ``surface_altitude`` cube was 2 dimensional with:
- * the two dimensions have extents of 204 and 187 respectively and are
- represented by the ``grid_latitude`` and ``grid_longitude`` coordinates.
+* the two dimensions have extents of 204 and 187 respectively and are
+ represented by the ``grid_latitude`` and ``grid_longitude`` coordinates.
The ``air_potential_temperature`` cubes were 4 dimensional with:
- * the same length ``grid_latitude`` and ``grid_longitude`` dimensions as
- ``surface_altitide``
- * a ``time`` dimension of length 3
- * a ``model_level_number`` dimension of length 7
+* the same length ``grid_latitude`` and ``grid_longitude`` dimensions as
+ ``surface_altitide``
+* a ``time`` dimension of length 3
+* a ``model_level_number`` dimension of length 7
.. note::
@@ -55,7 +55,7 @@ The ``air_potential_temperature`` cubes were 4 dimensional with:
(even if it only contains one :class:`iris.cube.Cube` - see
:ref:`strict-loading`). Anything that can be done with a Python
:class:`list` can be done with an :class:`iris.cube.CubeList`.
-
+
The order of this list should not be relied upon. Ways of loading a
specific cube or cubes are covered in :ref:`constrained-loading` and
:ref:`strict-loading`.
@@ -206,241 +206,8 @@ a specific ``model_level_number``::
level_10 = iris.Constraint(model_level_number=10)
cubes = iris.load(filename, level_10)
-Constraints can be combined using ``&`` to represent a more restrictive
-constraint to ``load``::
-
- filename = iris.sample_data_path('uk_hires.pp')
- forecast_6 = iris.Constraint(forecast_period=6)
- level_10 = iris.Constraint(model_level_number=10)
- cubes = iris.load(filename, forecast_6 & level_10)
-
-.. note::
-
- Whilst ``&`` is supported, the ``|`` that might reasonably be expected is
- not. Explanation as to why is in the :class:`iris.Constraint` reference
- documentation.
-
- For an example of constraining to multiple ranges of the same coordinate to
- generate one cube, see the :class:`iris.Constraint` reference documentation.
-
- To generate multiple cubes, each constrained to a different range of the
- same coordinate, use :py:func:`iris.load_cubes`.
-
-As well as being able to combine constraints using ``&``,
-the :class:`iris.Constraint` class can accept multiple arguments,
-and a list of values can be given to constrain a coordinate to one of
-a collection of values::
-
- filename = iris.sample_data_path('uk_hires.pp')
- level_10_or_16_fp_6 = iris.Constraint(model_level_number=[10, 16], forecast_period=6)
- cubes = iris.load(filename, level_10_or_16_fp_6)
-
-A common requirement is to limit the value of a coordinate to a specific range,
-this can be achieved by passing the constraint a function::
-
- def bottom_16_levels(cell):
- # return True or False as to whether the cell in question should be kept
- return cell <= 16
-
- filename = iris.sample_data_path('uk_hires.pp')
- level_lt_16 = iris.Constraint(model_level_number=bottom_16_levels)
- cubes = iris.load(filename, level_lt_16)
-
-.. note::
-
- As with many of the examples later in this documentation, the
- simple function above can be conveniently written as a lambda function
- on a single line::
-
- bottom_16_levels = lambda cell: cell <= 16
-
-
-Note also the :ref:`warning on equality constraints with floating point coordinates `.
-
-
-Cube attributes can also be part of the constraint criteria. Supposing a
-cube attribute of ``STASH`` existed, as is the case when loading ``PP`` files,
-then specific STASH codes can be filtered::
-
- filename = iris.sample_data_path('uk_hires.pp')
- level_10_with_stash = iris.AttributeConstraint(STASH='m01s00i004') & iris.Constraint(model_level_number=10)
- cubes = iris.load(filename, level_10_with_stash)
-
-.. seealso::
-
- For advanced usage there are further examples in the
- :class:`iris.Constraint` reference documentation.
-
-
-Constraining a Circular Coordinate Across its Boundary
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Occasionally you may need to constrain your cube with a region that crosses the
-boundary of a circular coordinate (this is often the meridian or the dateline /
-antimeridian). An example use-case of this is to extract the entire Pacific Ocean
-from a cube whose longitudes are bounded by the dateline.
-
-This functionality cannot be provided reliably using constraints. Instead you should use the
-functionality provided by :meth:`cube.intersection `
-to extract this region.
-
-
-.. _using-time-constraints:
-
-Constraining on Time
-^^^^^^^^^^^^^^^^^^^^
-Iris follows NetCDF-CF rules in representing time coordinate values as normalised,
-purely numeric, values which are normalised by the calendar specified in the coordinate's
-units (e.g. "days since 1970-01-01").
-However, when constraining by time we usually want to test calendar-related
-aspects such as hours of the day or months of the year, so Iris
-provides special features to facilitate this:
-
-Firstly, when Iris evaluates Constraint expressions, it will convert time-coordinate
-values (points and bounds) from numbers into :class:`~datetime.datetime`-like objects
-for ease of calendar-based testing.
-
- >>> filename = iris.sample_data_path('uk_hires.pp')
- >>> cube_all = iris.load_cube(filename, 'air_potential_temperature')
- >>> print('All times :\n' + str(cube_all.coord('time')))
- All times :
- DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar)
- points: [2009-11-19 10:00:00, 2009-11-19 11:00:00, 2009-11-19 12:00:00]
- shape: (3,)
- dtype: float64
- standard_name: 'time'
- >>> # Define a function which accepts a datetime as its argument (this is simplified in later examples).
- >>> hour_11 = iris.Constraint(time=lambda cell: cell.point.hour == 11)
- >>> cube_11 = cube_all.extract(hour_11)
- >>> print('Selected times :\n' + str(cube_11.coord('time')))
- Selected times :
- DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar)
- points: [2009-11-19 11:00:00]
- shape: (1,)
- dtype: float64
- standard_name: 'time'
-
-Secondly, the :class:`iris.time` module provides flexible time comparison
-facilities. An :class:`iris.time.PartialDateTime` object can be compared to
-objects such as :class:`datetime.datetime` instances, and this comparison will
-then test only those 'aspects' which the PartialDateTime instance defines:
-
- >>> import datetime
- >>> from iris.time import PartialDateTime
- >>> dt = datetime.datetime(2011, 3, 7)
- >>> print(dt > PartialDateTime(year=2010, month=6))
- True
- >>> print(dt > PartialDateTime(month=6))
- False
- >>>
-
-These two facilities can be combined to provide straightforward calendar-based
-time selections when loading or extracting data.
-
-The previous constraint example can now be written as:
-
- >>> the_11th_hour = iris.Constraint(time=iris.time.PartialDateTime(hour=11))
- >>> print(iris.load_cube(
- ... iris.sample_data_path('uk_hires.pp'),
- ... 'air_potential_temperature' & the_11th_hour).coord('time'))
- DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar)
- points: [2009-11-19 11:00:00]
- shape: (1,)
- dtype: float64
- standard_name: 'time'
-
-It is common that a cube will need to be constrained between two given dates.
-In the following example we construct a time sequence representing the first
-day of every week for many years:
-
-.. testsetup:: timeseries_range
-
- import datetime
- import numpy as np
- from iris.time import PartialDateTime
- long_ts = iris.cube.Cube(np.arange(150), long_name='data', units='1')
- _mondays = iris.coords.DimCoord(7 * np.arange(150), standard_name='time', units='days since 2007-04-09')
- long_ts.add_dim_coord(_mondays, 0)
-
-
-.. doctest:: timeseries_range
- :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
-
- >>> print(long_ts.coord('time'))
- DimCoord : time / (days since 2007-04-09, gregorian calendar)
- points: [
- 2007-04-09 00:00:00, 2007-04-16 00:00:00, ...,
- 2010-02-08 00:00:00, 2010-02-15 00:00:00]
- shape: (150,)
- dtype: int64
- standard_name: 'time'
-
-Given two dates in datetime format, we can select all points between them.
-
-.. doctest:: timeseries_range
- :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
-
- >>> d1 = datetime.datetime.strptime('20070715T0000Z', '%Y%m%dT%H%MZ')
- >>> d2 = datetime.datetime.strptime('20070825T0000Z', '%Y%m%dT%H%MZ')
- >>> st_swithuns_daterange_07 = iris.Constraint(
- ... time=lambda cell: d1 <= cell.point < d2)
- >>> within_st_swithuns_07 = long_ts.extract(st_swithuns_daterange_07)
- >>> print(within_st_swithuns_07.coord('time'))
- DimCoord : time / (days since 2007-04-09, gregorian calendar)
- points: [
- 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00,
- 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00]
- shape: (6,)
- dtype: int64
- standard_name: 'time'
-
-Alternatively, we may rewrite this using :class:`iris.time.PartialDateTime`
-objects.
-
-.. doctest:: timeseries_range
- :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
-
- >>> pdt1 = PartialDateTime(year=2007, month=7, day=15)
- >>> pdt2 = PartialDateTime(year=2007, month=8, day=25)
- >>> st_swithuns_daterange_07 = iris.Constraint(
- ... time=lambda cell: pdt1 <= cell.point < pdt2)
- >>> within_st_swithuns_07 = long_ts.extract(st_swithuns_daterange_07)
- >>> print(within_st_swithuns_07.coord('time'))
- DimCoord : time / (days since 2007-04-09, gregorian calendar)
- points: [
- 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00,
- 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00]
- shape: (6,)
- dtype: int64
- standard_name: 'time'
-
-A more complex example might require selecting points over an annually repeating
-date range. We can select points within a certain part of the year, in this case
-between the 15th of July through to the 25th of August. By making use of
-PartialDateTime this becomes simple:
-
-.. doctest:: timeseries_range
-
- >>> st_swithuns_daterange = iris.Constraint(
- ... time=lambda cell: PartialDateTime(month=7, day=15) <= cell < PartialDateTime(month=8, day=25))
- >>> within_st_swithuns = long_ts.extract(st_swithuns_daterange)
- ...
- >>> # Note: using summary(max_values) to show more of the points
- >>> print(within_st_swithuns.coord('time').summary(max_values=100))
- DimCoord : time / (days since 2007-04-09, gregorian calendar)
- points: [
- 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00,
- 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00,
- 2008-07-21 00:00:00, 2008-07-28 00:00:00, 2008-08-04 00:00:00,
- 2008-08-11 00:00:00, 2008-08-18 00:00:00, 2009-07-20 00:00:00,
- 2009-07-27 00:00:00, 2009-08-03 00:00:00, 2009-08-10 00:00:00,
- 2009-08-17 00:00:00, 2009-08-24 00:00:00]
- shape: (17,)
- dtype: int64
- standard_name: 'time'
-
-Notice how the dates printed are between the range specified in the ``st_swithuns_daterange``
-and that they span multiple years.
+Further details on using :class:`iris.Constraint` are
+discussed later in :ref:`cube_extraction`.
.. _strict-loading:
diff --git a/docs/src/userguide/merge_and_concat.rst b/docs/src/userguide/merge_and_concat.rst
index e8425df5ec..b521d49a59 100644
--- a/docs/src/userguide/merge_and_concat.rst
+++ b/docs/src/userguide/merge_and_concat.rst
@@ -22,14 +22,14 @@ result in fewer cubes as output. The following diagram illustrates the two proce
There is one major difference between the ``merge`` and ``concatenate`` processes.
- * The ``merge`` process combines multiple input cubes into a
- single resultant cube with new dimensions created from the
- *scalar coordinate values* of the input cubes.
+* The ``merge`` process combines multiple input cubes into a
+ single resultant cube with new dimensions created from the
+ *scalar coordinate values* of the input cubes.
- * The ``concatenate`` process combines multiple input cubes into a
- single resultant cube with the same *number of dimensions* as the input cubes,
- but with the length of one or more dimensions extended by *joining together
- sequential dimension coordinates*.
+* The ``concatenate`` process combines multiple input cubes into a
+ single resultant cube with the same *number of dimensions* as the input cubes,
+ but with the length of one or more dimensions extended by *joining together
+ sequential dimension coordinates*.
Let's imagine 28 individual cubes representing the
temperature at a location ``(y, x)``; one cube for each day of February. We can use
@@ -253,6 +253,11 @@ which are described below.
Using CubeList.concatenate
==========================
+.. seealso::
+
+ Relevant gallery example:
+ :ref:`sphx_glr_generated_gallery_general_plot_projections_and_annotations.py` (Brief concatenating examples)
+
The :meth:`CubeList.concatenate ` method operates on a list
of cubes and returns a new :class:`~iris.cube.CubeList` containing the cubes
that have been concatenated.
diff --git a/docs/src/userguide/navigating_a_cube.rst b/docs/src/userguide/navigating_a_cube.rst
index c5924a61c6..b4c16b094b 100644
--- a/docs/src/userguide/navigating_a_cube.rst
+++ b/docs/src/userguide/navigating_a_cube.rst
@@ -110,6 +110,10 @@ cube with the :attr:`Cube.cell_methods ` attribute:
print(cube.cell_methods)
+.. seealso::
+
+ Relevant gallery example:
+ :ref:`sphx_glr_generated_gallery_meteorology_plot_wind_barbs.py`
Accessing Coordinates on the Cube
---------------------------------
@@ -176,6 +180,10 @@ We can add and remove coordinates via :func:`Cube.add_dim_coord>> import iris
@@ -34,15 +42,14 @@ A subset of a cube can be "extracted" from a multi-dimensional cube in order to
In this example we start with a 3 dimensional cube, with dimensions of ``height``, ``grid_latitude`` and ``grid_longitude``,
-and extract every point where the latitude is 0, resulting in a 2d cube with axes of ``height`` and ``grid_longitude``.
-
+and use :class:`iris.Constraint` to extract every point where the latitude is 0, resulting in a 2d cube with axes of ``height`` and ``grid_longitude``.
.. _floating-point-warning:
.. warning::
Caution is required when using equality constraints with floating point coordinates such as ``grid_latitude``.
Printing the points of a coordinate does not necessarily show the full precision of the underlying number and it
- is very easy return no matches to a constraint when one was expected.
+ is very easy to return no matches to a constraint when one was expected.
This can be avoided by using a function as the argument to the constraint::
def near_zero(cell):
@@ -68,6 +75,33 @@ The two steps required to get ``height`` of 9000 m at the equator can be simplif
equator_height_9km_slice = cube.extract(iris.Constraint(grid_latitude=0, height=9000))
print(equator_height_9km_slice)
+Alternatively, constraints can be combined using ``&``::
+
+ cube = iris.load_cube(filename, 'electron density')
+ equator_constraint = iris.Constraint(grid_latitude=0)
+ height_constraint = iris.Constraint(height=9000)
+ equator_height_9km_slice = cube.extract(equator_constraint & height_constraint)
+
+.. note::
+
+ Whilst ``&`` is supported, the ``|`` that might reasonably be expected is
+ not. Explanation as to why is in the :class:`iris.Constraint` reference
+ documentation.
+
+ For an example of constraining to multiple ranges of the same coordinate to
+ generate one cube, see the :class:`iris.Constraint` reference documentation.
+
+A common requirement is to limit the value of a coordinate to a specific range,
+this can be achieved by passing the constraint a function::
+
+ def below_9km(cell):
+ # return True or False as to whether the cell in question should be kept
+ return cell <= 9000
+
+ cube = iris.load_cube(filename, 'electron density')
+ height_below_9km = iris.Constraint(height=below_9km)
+ below_9km_slice = cube.extract(height_below_9km)
+
As we saw in :doc:`loading_iris_cubes` the result of :func:`iris.load` is a :class:`CubeList `.
The ``extract`` method also exists on a :class:`CubeList ` and behaves in exactly the
same way as loading with constraints:
@@ -100,9 +134,203 @@ same way as loading with constraints:
source 'Data from Met Office Unified Model'
um_version '7.3'
+Cube attributes can also be part of the constraint criteria. Supposing a
+cube attribute of ``STASH`` existed, as is the case when loading ``PP`` files,
+then specific STASH codes can be filtered::
+
+ filename = iris.sample_data_path('uk_hires.pp')
+ level_10_with_stash = iris.AttributeConstraint(STASH='m01s00i004') & iris.Constraint(model_level_number=10)
+ cubes = iris.load(filename).extract(level_10_with_stash)
+
+.. seealso::
+
+ For advanced usage there are further examples in the
+ :class:`iris.Constraint` reference documentation.
+
+Constraining a Circular Coordinate Across its Boundary
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Occasionally you may need to constrain your cube with a region that crosses the
+boundary of a circular coordinate (this is often the meridian or the dateline /
+antimeridian). An example use-case of this is to extract the entire Pacific Ocean
+from a cube whose longitudes are bounded by the dateline.
+
+This functionality cannot be provided reliably using constraints. Instead you should use the
+functionality provided by :meth:`cube.intersection `
+to extract this region.
+
+
+.. _using-time-constraints:
+
+Constraining on Time
+^^^^^^^^^^^^^^^^^^^^
+Iris follows NetCDF-CF rules in representing time coordinate values as normalised,
+purely numeric, values which are normalised by the calendar specified in the coordinate's
+units (e.g. "days since 1970-01-01").
+However, when constraining by time we usually want to test calendar-related
+aspects such as hours of the day or months of the year, so Iris
+provides special features to facilitate this.
+
+Firstly, when Iris evaluates :class:`iris.Constraint` expressions, it will convert
+time-coordinate values (points and bounds) from numbers into :class:`~datetime.datetime`-like
+objects for ease of calendar-based testing.
+
+ >>> filename = iris.sample_data_path('uk_hires.pp')
+ >>> cube_all = iris.load_cube(filename, 'air_potential_temperature')
+ >>> print('All times :\n' + str(cube_all.coord('time')))
+ All times :
+ DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar)
+ points: [2009-11-19 10:00:00, 2009-11-19 11:00:00, 2009-11-19 12:00:00]
+ shape: (3,)
+ dtype: float64
+ standard_name: 'time'
+ >>> # Define a function which accepts a datetime as its argument (this is simplified in later examples).
+ >>> hour_11 = iris.Constraint(time=lambda cell: cell.point.hour == 11)
+ >>> cube_11 = cube_all.extract(hour_11)
+ >>> print('Selected times :\n' + str(cube_11.coord('time')))
+ Selected times :
+ DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar)
+ points: [2009-11-19 11:00:00]
+ shape: (1,)
+ dtype: float64
+ standard_name: 'time'
+
+Secondly, the :class:`iris.time` module provides flexible time comparison
+facilities. An :class:`iris.time.PartialDateTime` object can be compared to
+objects such as :class:`datetime.datetime` instances, and this comparison will
+then test only those 'aspects' which the PartialDateTime instance defines:
+
+ >>> import datetime
+ >>> from iris.time import PartialDateTime
+ >>> dt = datetime.datetime(2011, 3, 7)
+ >>> print(dt > PartialDateTime(year=2010, month=6))
+ True
+ >>> print(dt > PartialDateTime(month=6))
+ False
+
+These two facilities can be combined to provide straightforward calendar-based
+time selections when loading or extracting data.
+
+The previous constraint example can now be written as:
+
+ >>> the_11th_hour = iris.Constraint(time=iris.time.PartialDateTime(hour=11))
+ >>> print(iris.load_cube(
+ ... iris.sample_data_path('uk_hires.pp'),
+ ... 'air_potential_temperature' & the_11th_hour).coord('time'))
+ DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar)
+ points: [2009-11-19 11:00:00]
+ shape: (1,)
+ dtype: float64
+ standard_name: 'time'
+
+It is common that a cube will need to be constrained between two given dates.
+In the following example we construct a time sequence representing the first
+day of every week for many years:
+
+.. testsetup:: timeseries_range
+
+ import datetime
+ import numpy as np
+ from iris.time import PartialDateTime
+ long_ts = iris.cube.Cube(np.arange(150), long_name='data', units='1')
+ _mondays = iris.coords.DimCoord(7 * np.arange(150), standard_name='time', units='days since 2007-04-09')
+ long_ts.add_dim_coord(_mondays, 0)
+
+
+.. doctest:: timeseries_range
+ :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
+
+ >>> print(long_ts.coord('time'))
+ DimCoord : time / (days since 2007-04-09, standard calendar)
+ points: [
+ 2007-04-09 00:00:00, 2007-04-16 00:00:00, ...,
+ 2010-02-08 00:00:00, 2010-02-15 00:00:00]
+ shape: (150,)
+ dtype: int64
+ standard_name: 'time'
+
+Given two dates in datetime format, we can select all points between them.
+Instead of constraining at loaded time, we already have the time coord so
+we constrain that coord using :class:`iris.cube.Cube.extract`
+
+.. doctest:: timeseries_range
+ :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
+
+ >>> d1 = datetime.datetime.strptime('20070715T0000Z', '%Y%m%dT%H%MZ')
+ >>> d2 = datetime.datetime.strptime('20070825T0000Z', '%Y%m%dT%H%MZ')
+ >>> st_swithuns_daterange_07 = iris.Constraint(
+ ... time=lambda cell: d1 <= cell.point < d2)
+ >>> within_st_swithuns_07 = long_ts.extract(st_swithuns_daterange_07)
+ >>> print(within_st_swithuns_07.coord('time'))
+ DimCoord : time / (days since 2007-04-09, standard calendar)
+ points: [
+ 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00,
+ 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00]
+ shape: (6,)
+ dtype: int64
+ standard_name: 'time'
+
+Alternatively, we may rewrite this using :class:`iris.time.PartialDateTime`
+objects.
+
+.. doctest:: timeseries_range
+ :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
+
+ >>> pdt1 = PartialDateTime(year=2007, month=7, day=15)
+ >>> pdt2 = PartialDateTime(year=2007, month=8, day=25)
+ >>> st_swithuns_daterange_07 = iris.Constraint(
+ ... time=lambda cell: pdt1 <= cell.point < pdt2)
+ >>> within_st_swithuns_07 = long_ts.extract(st_swithuns_daterange_07)
+ >>> print(within_st_swithuns_07.coord('time'))
+ DimCoord : time / (days since 2007-04-09, standard calendar)
+ points: [
+ 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00,
+ 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00]
+ shape: (6,)
+ dtype: int64
+ standard_name: 'time'
+
+A more complex example might require selecting points over an annually repeating
+date range. We can select points within a certain part of the year, in this case
+between the 15th of July through to the 25th of August. By making use of
+PartialDateTime this becomes simple:
+
+.. doctest:: timeseries_range
+
+ >>> st_swithuns_daterange = iris.Constraint(
+ ... time=lambda cell: PartialDateTime(month=7, day=15) <= cell.point < PartialDateTime(month=8, day=25))
+ >>> within_st_swithuns = long_ts.extract(st_swithuns_daterange)
+ ...
+ >>> # Note: using summary(max_values) to show more of the points
+ >>> print(within_st_swithuns.coord('time').summary(max_values=100))
+ DimCoord : time / (days since 2007-04-09, standard calendar)
+ points: [
+ 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00,
+ 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00,
+ 2008-07-21 00:00:00, 2008-07-28 00:00:00, 2008-08-04 00:00:00,
+ 2008-08-11 00:00:00, 2008-08-18 00:00:00, 2009-07-20 00:00:00,
+ 2009-07-27 00:00:00, 2009-08-03 00:00:00, 2009-08-10 00:00:00,
+ 2009-08-17 00:00:00, 2009-08-24 00:00:00]
+ shape: (17,)
+ dtype: int64
+ standard_name: 'time'
+
+Notice how the dates printed are between the range specified in the ``st_swithuns_daterange``
+and that they span multiple years.
+
+The above examples involve constraining on the points of the time coordinate. Constraining
+on bounds can be done in the following way::
+
+ filename = iris.sample_data_path('ostia_monthly.nc')
+ cube = iris.load_cube(filename, 'surface_temperature')
+ dtmin = datetime.datetime(2008, 1, 1)
+ cube.extract(iris.Constraint(time = lambda cell: any(bound > dtmin for bound in cell.bound)))
+
+The above example constrains to cells where either the upper or lower bound occur
+after 1st January 2008.
Cube Iteration
-^^^^^^^^^^^^^^^
+--------------
It is not possible to directly iterate over an Iris cube. That is, you cannot use code such as
``for x in cube:``. However, you can iterate over cube slices, as this section details.
@@ -151,9 +379,10 @@ slicing the 3 dimensional cube (15, 100, 100) by longitude (i starts at 0 and 15
Once the your code can handle a 2d slice, it is then an easy step to loop over **all** 2d slices within the bigger
cube using the slices method.
+.. _cube_indexing:
Cube Indexing
-^^^^^^^^^^^^^
+-------------
In the same way that you would expect a numeric multidimensional array to be **indexed** to take a subset of your
original array, you can **index** a Cube for the same purpose.
diff --git a/docs/src/voted_issues.rst b/docs/src/voted_issues.rst
new file mode 100644
index 0000000000..7d983448b9
--- /dev/null
+++ b/docs/src/voted_issues.rst
@@ -0,0 +1,56 @@
+.. include:: common_links.inc
+
+.. _voted_issues_top:
+
+Voted Issues
+============
+
+You can help us to prioritise development of new features by leaving a 👍
+reaction on the header (not subsequent comments) of any issue.
+
+.. tip:: We suggest you subscribe to the issue so you will be updated.
+ When viewing the issue there is a **Notifications**
+ section where you can select to subscribe.
+
+Below is a sorted table of all issues that have 1 or more 👍 from our github
+project. Please note that there is more development activity than what is on
+the below table.
+
+.. _voted-issues.json: https://github.com/scitools/voted_issues/blob/main/voted-issues.json
+
+.. raw:: html
+
+
+
+
+ | 👍 |
+ Issue |
+ Author |
+ Title |
+
+
+
+
+
+
+
+
+
+
+.. note:: The data in this table is updated every 30 minutes and is sourced
+ from `voted-issues.json`_.
+ For the latest data please see the `issues on GitHub`_.
+ Note that the list on Github does not show the number of votes 👍
+ only the total number of comments for the whole issue.
\ No newline at end of file
diff --git a/docs/src/whatsnew/1.0.rst b/docs/src/whatsnew/1.0.rst
index b226dc609b..c256c33566 100644
--- a/docs/src/whatsnew/1.0.rst
+++ b/docs/src/whatsnew/1.0.rst
@@ -147,8 +147,7 @@ the surface pressure. In return, it provides a virtual "pressure"
coordinate whose values are derived from the given components.
This facility is utilised by the GRIB2 loader to automatically provide
-the derived "pressure" coordinate for certain data [#f1]_ from the
-`ECMWF `_.
+the derived "pressure" coordinate for certain data [#f1]_ from the ECMWF.
.. [#f1] Where the level type is either 105 or 119, and where the
surface pressure has an ECMWF paramId of
diff --git a/docs/src/whatsnew/2.1.rst b/docs/src/whatsnew/2.1.rst
index 18c562d3da..33f3a013b1 100644
--- a/docs/src/whatsnew/2.1.rst
+++ b/docs/src/whatsnew/2.1.rst
@@ -1,3 +1,5 @@
+.. include:: ../common_links.inc
+
v2.1 (06 Jun 2018)
******************
@@ -67,7 +69,7 @@ Incompatible Changes
as an alternative.
* This release of Iris contains a number of updated metadata translations.
- See this
+ See this
`changelist `_
for further information.
@@ -84,7 +86,7 @@ Internal
calendar.
* Iris updated its time-handling functionality from the
- `netcdf4-python `_
+ `netcdf4-python`__
``netcdftime`` implementation to the standalone module
`cftime `_.
cftime is entirely compatible with netcdftime, but some issues may
@@ -92,6 +94,8 @@ Internal
In this situation, simply replacing ``netcdftime.datetime`` with
``cftime.datetime`` should be sufficient.
+__ `netCDF4`_
+
* Iris now requires version 2 of Matplotlib, and ``>=1.14`` of NumPy.
Full requirements can be seen in the `requirements `_
directory of the Iris' the source.
diff --git a/docs/src/whatsnew/3.0.rst b/docs/src/whatsnew/3.0.rst
index 771a602954..223ef60011 100644
--- a/docs/src/whatsnew/3.0.rst
+++ b/docs/src/whatsnew/3.0.rst
@@ -97,9 +97,8 @@ v3.0.2 (27 May 2021)
from collaborators targeting the Iris ``master`` branch. (:pull:`4007`)
[``pre-v3.1.0``]
- #. `@bjlittle`_ added conditional task execution to `.cirrus.yml`_ to allow
- developers to easily disable `cirrus-ci`_ tasks. See
- :ref:`skipping Cirrus-CI tasks`. (:pull:`4019`) [``pre-v3.1.0``]
+ #. `@bjlittle`_ added conditional task execution to ``.cirrus.yml`` to allow
+ developers to easily disable `cirrus-ci`_ tasks. (:pull:`4019`) [``pre-v3.1.0``]
#. `@pp-mo`_ adjusted the use of :func:`dask.array.from_array` in :func:`iris._lazy_data.as_lazy_data`,
to avoid the dask 'test access'. This makes loading of netcdf files with a
diff --git a/docs/src/whatsnew/3.1.rst b/docs/src/whatsnew/3.1.rst
index bd046a0a24..1f076572bc 100644
--- a/docs/src/whatsnew/3.1.rst
+++ b/docs/src/whatsnew/3.1.rst
@@ -227,9 +227,8 @@ This document explains the changes made to Iris for this release
#. `@akuhnregnier`_ replaced `deprecated numpy 1.20 aliases for builtin types`_.
(:pull:`3997`)
-#. `@bjlittle`_ added conditional task execution to `.cirrus.yml`_ to allow
- developers to easily disable `cirrus-ci`_ tasks. See
- :ref:`skipping Cirrus-CI tasks`. (:pull:`4019`)
+#. `@bjlittle`_ added conditional task execution to ``.cirrus.yml`` to allow
+ developers to easily disable `cirrus-ci`_ tasks. (:pull:`4019`)
#. `@bjlittle`_ and `@jamesp`_ addressed a regression in behaviour when using
`conda`_ 4.10.0 within `cirrus-ci`_. (:pull:`4084`)
@@ -291,9 +290,8 @@ This document explains the changes made to Iris for this release
#. `@bjlittle`_ enabled `cirrus-ci`_ compute credits for non-draft pull-requests
from collaborators targeting the Iris ``master`` branch. (:pull:`4007`)
-#. `@bjlittle`_ added conditional task execution to `.cirrus.yml`_ to allow
- developers to easily disable `cirrus-ci`_ tasks. See
- :ref:`skipping Cirrus-CI tasks`. (:pull:`4019`)
+#. `@bjlittle`_ added conditional task execution to ``.cirrus.yml`` to allow
+ developers to easily disable `cirrus-ci`_ tasks. (:pull:`4019`)
diff --git a/docs/src/whatsnew/3.2.rst b/docs/src/whatsnew/3.2.rst
new file mode 100644
index 0000000000..723f26345e
--- /dev/null
+++ b/docs/src/whatsnew/3.2.rst
@@ -0,0 +1,408 @@
+.. include:: ../common_links.inc
+
+v3.2 (15 Feb 2022)
+******************
+
+This document explains the changes made to Iris for this release
+(:doc:`View all changes `.)
+
+
+.. dropdown:: :opticon:`report` v3.2.0 Release Highlights
+ :container: + shadow
+ :title: text-primary text-center font-weight-bold
+ :body: bg-light
+ :animate: fade-in
+ :open:
+
+ The highlights for this minor release of Iris include:
+
+ * We've added experimental support for
+ :ref:`Meshes `, which can now be loaded and
+ attached to a cube. Mesh support is based on the `CF-UGRID`_ model.
+ * We've also dropped support for ``Python 3.7``.
+
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
+
+
+v3.2.1 (11 Mar 2022)
+====================
+
+.. dropdown:: :opticon:`alert` v3.2.1 Patches
+ :container: + shadow
+ :title: text-primary text-center font-weight-bold
+ :body: bg-light
+ :animate: fade-in
+
+ 📢 **Welcome** to `@dennissergeev`_, who made his first contribution to Iris. Nice work!
+
+ The patches in this release of Iris include:
+
+ 🐛 **Bugs Fixed**
+
+ #. `@dennissergeev`_ changed _crs_distance_differentials() so that it uses the `Globe`
+ attribute from a given CRS instead of creating a new `ccrs.Globe()` object.
+ Iris can now handle non-Earth semi-major axes, as discussed in :issue:`4582` (:pull:`4605`).
+
+ #. `@trexfeathers`_ avoided a dimensionality mismatch when streaming the
+ :attr:`~iris.coords.Coord.bounds` array for a scalar
+ :class:`~iris.coords.Coord`. (:pull:`4610`).
+
+
+📢 Announcements
+================
+
+#. Welcome to `@wjbenfold`_, `@tinyendian`_, `@larsbarring`_, `@bsherratt`_ and
+ `@aaronspring`_ who made their first contributions to Iris. The first of
+ many we hope!
+#. Congratulations to `@wjbenfold`_ who has become a core developer for Iris! 🎉
+
+
+✨ Features
+===========
+
+#. `@bjlittle`_, `@pp-mo`_, `@trexfeathers`_ and `@stephenworsley`_ added
+ support for :ref:`unstructured meshes `. This involved
+ adding a data model (:pull:`3968`, :pull:`4014`, :pull:`4027`, :pull:`4036`,
+ :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`,
+ :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
+ type mesh. :class:`~iris.experimental.ugrid.mesh.MeshCoord`\ s are coordinates that
+ reference and represent a :class:`~iris.experimental.ugrid.mesh.Mesh` 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.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.
+ (: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
+ (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
+ appropriate collection of :class:`iris.coords.Coord`\ s.
+
+#. `@larsbarring`_ updated :func:`~iris.util.equalise_attributes` to return a list of dictionaries
+ containing the attributes removed from each :class:`~iris.cube.Cube`. (:pull:`4357`)
+
+#. `@trexfeathers`_ enabled streaming of **all** lazy arrays when saving to
+ NetCDF files (was previously just :class:`~iris.cube.Cube`
+ :attr:`~iris.cube.Cube.data`). This is
+ important given the much greater size of
+ :class:`~iris.coords.AuxCoord` :attr:`~iris.coords.AuxCoord.points` and
+ :class:`~iris.experimental.ugrid.mesh.Connectivity`
+ :attr:`~iris.experimental.ugrid.mesh.Connectivity.indices` under the
+ :ref:`mesh model `. (:pull:`4375`)
+
+#. `@bsherratt`_ added a ``threshold`` parameter to
+ :meth:`~iris.cube.Cube.intersection` (:pull:`4363`)
+
+#. `@wjbenfold`_ added test data to ci benchmarks so that it is accessible to
+ benchmark scripts. Also added a regridding benchmark that uses this data
+ (:pull:`4402`)
+
+#. `@pp-mo`_ updated to the latest CF Standard Names Table ``v78`` (21 Sept 2021).
+ (:issue:`4479`, :pull:`4483`)
+
+#. `@SimonPeatman`_ added support for filenames in the form of a :class:`~pathlib.PurePath`
+ in :func:`~iris.load`, :func:`~iris.load_cube`, :func:`~iris.load_cubes`,
+ :func:`~iris.load_raw` and :func:`~iris.save` (:issue:`3411`, :pull:`3917`).
+ Support for :class:`~pathlib.PurePath` is yet to be implemented across the rest
+ of Iris (:issue:`4523`).
+
+#. `@pp-mo`_ removed broken tooling for deriving Iris metadata translations
+ from ``Metarelate``. From now we intend to manage phenonemon translation
+ in Iris itself. (:pull:`4484`)
+
+#. `@pp-mo`_ improved printout of various cube data component objects :
+ :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`.
+ 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`.
+ They also no longer realise lazy data. (:pull:`4499`).
+
+
+🐛 Bugs Fixed
+=============
+
+#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.intersection` for special cases where
+ one cell's bounds align with the requested maximum and negative minimum, fixing
+ :issue:`4221`. (:pull:`4278`)
+
+#. `@bsherratt`_ fixed further edge cases in
+ :meth:`~iris.cube.Cube.intersection`, including :issue:`3698` (:pull:`4363`)
+
+#. `@tinyendian`_ fixed the error message produced by :meth:`~iris.cube.CubeList.concatenate_cube`
+ when a cube list contains cubes with different names, which will no longer report
+ "Cube names differ: var1 != var1" if var1 appears multiple times in the list
+ (:issue:`4342`, :pull:`4345`)
+
+#. `@larsbarring`_ fixed :class:`~iris.coord_systems.GeoCS` to handle spherical ellipsoid
+ parameter inverse_flattening = 0 (:issue:`4146`, :pull:`4348`)
+
+#. `@pdearnshaw`_ fixed an error in the call to :class:`cftime.datetime` in
+ :mod:`~iris.fileformats.pp_save_rules` that prevented the saving to PP of climate
+ means for DJF (:pull:`4391`)
+
+#. `@wjbenfold`_ improved the error message for failure of :meth:`~iris.cube.CubeList.concatenate`
+ to indicate that the value of a scalar coordinate may be mismatched, rather than the metadata
+ (:issue:`4096`, :pull:`4387`)
+
+#. `@bsherratt`_ fixed a regression to the NAME file loader introduced in 3.0.4,
+ as well as some long-standing bugs with vertical coordinates and number
+ formats. (:pull:`4411`)
+
+#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.subset` to alway return ``None`` if
+ no value match is found. (:pull:`4417`)
+
+#. `@wjbenfold`_ changed :meth:`iris.util.points_step` to stop it from warning
+ when applied to a single point (:issue:`4250`, :pull:`4367`)
+
+#. `@trexfeathers`_ changed :class:`~iris.coords._DimensionalMetadata` and
+ :class:`~iris.experimental.ugrid.Connectivity` equality methods to preserve
+ array laziness, allowing efficient comparisons even with larger-than-memory
+ objects. (:pull:`4439`)
+
+#. `@rcomer`_ modified :meth:`~iris.cube.Cube.aggregated_by` to calculate new
+ coordinate bounds using minimum and maximum for unordered coordinates,
+ fixing :issue:`1528`. (:pull:`4315`)
+
+#. `@wjbenfold`_ changed how a delayed unit conversion is performed on a cube
+ so that a cube with lazy data awaiting a unit conversion can be pickled.
+ (:issue:`4354`, :pull:`4377`)
+
+#. `@pp-mo`_ fixed a bug in netcdf loading, whereby *any* rotated latlon coordinate
+ was mistakenly interpreted as a latitude, usually resulting in two 'latitude's
+ instead of one latitude and one longitude.
+ (:issue:`4460`, :pull:`4470`)
+
+#. `@wjbenfold`_ stopped :meth:`iris.coord_systems.GeogCS.as_cartopy_projection`
+ from assuming the globe to be the Earth (:issue:`4408`, :pull:`4497`)
+
+#. `@rcomer`_ corrected the ``long_name`` mapping from UM stash code ``m01s09i215``
+ to indicate cloud fraction greater than 7.9 oktas, rather than 7.5
+ (:issue:`3305`, :pull:`4535`)
+
+#. `@lbdreyer`_ fixed a bug in :class:`iris.io.load_http` which was missing an import
+ (:pull:`4580`)
+
+
+💣 Incompatible Changes
+=======================
+
+#. N/A
+
+
+🚀 Performance Enhancements
+===========================
+
+#. `@wjbenfold`_ resolved an issue that previously caused regridding with lazy
+ data to take significantly longer than with real data. Benchmark
+ :class:`benchmarks.HorizontalChunkedRegridding` shows a time decrease
+ from >10s to 625ms. (:issue:`4280`, :pull:`4400`)
+
+#. `@bjlittle`_ included an optimisation to :class:`~iris.cube.Cube.coord_dims`
+ to avoid unnecessary processing whenever a coordinate instance that already
+ exists within the cube is provided. (:pull:`4549`)
+
+
+🔥 Deprecations
+===============
+
+#. `@wjbenfold`_ removed :mod:`iris.experimental.equalise_cubes`. In ``v3.0``
+ the experimental ``equalise_attributes`` functionality was moved to the
+ :mod:`iris.util.equalise_attributes` function. Since then, calling the
+ :func:`iris.experimental.equalise_cubes.equalise_attributes` function raised
+ an exception. (:issue:`3528`, :pull:`4496`)
+
+#. `@wjbenfold`_ deprecated :func:`iris.util.approx_equal` in preference for
+ :func:`math.isclose`. The :func:`~iris.util.approx_equal` function will be
+ removed in a future release of Iris. (:pull:`4514`)
+
+#. `@wjbenfold`_ deprecated :mod:`iris.experimental.raster` as it is not
+ believed to still be in use. The deprecation warnings invite users to contact
+ the Iris Developers if this isn't the case. (:pull:`4525`)
+
+#. `@wjbenfold`_ deprecated :mod:`iris.fileformats.abf` and
+ :mod:`iris.fileformats.dot` as they are not believed to still be in use. The
+ deprecation warnings invite users to contact the Iris Developers if this
+ isn't the case. (:pull:`4515`)
+
+#. `@wjbenfold`_ removed the :func:`iris.util.as_compatible_shape` function,
+ which was deprecated in ``v3.0``. Instead use
+ :class:`iris.common.resolve.Resolve`. For example, rather than calling
+ ``as_compatible_shape(src_cube, target_cube)`` replace with
+ ``Resolve(src_cube, target_cube)(target_cube.core_data())``. (:pull:`4513`)
+
+#. `@wjbenfold`_ deprecated :func:`iris.analysis.maths.intersection_of_cubes` in
+ preference for :meth:`iris.cube.CubeList.extract_overlapping`. The
+ :func:`~iris.analysis.maths.intersection_of_cubes` function will be removed in
+ a future release of Iris. (:pull:`4541`)
+
+#. `@pp-mo`_ deprecated :mod:`iris.experimental.regrid_conservative`. This is
+ now replaced by `iris-emsf-regrid`_. (:pull:`4551`)
+
+#. `@pp-mo`_ deprecated everything in :mod:`iris.experimental.regrid`.
+ Most features have a preferred exact alternative, as suggested, *except*
+ :class:`iris.experimental.regrid.ProjectedUnstructuredLinear` : that has no
+ identical equivalent, but :class:`iris.analysis.UnstructuredNearest` is
+ suggested as being quite close (though possibly slower). (:pull:`4548`)
+
+
+🔗 Dependencies
+===============
+
+#. `@bjlittle`_ introduced the ``cartopy >=0.20`` minimum pin.
+ (:pull:`4331`)
+
+#. `@trexfeathers`_ introduced the ``cf-units >=3`` and ``nc-time-axis >=1.3``
+ minimum pins. (:pull:`4356`)
+
+#. `@bjlittle`_ introduced the ``numpy >=1.19`` minimum pin, in
+ accordance with `NEP-29`_ deprecation policy. (:pull:`4386`)
+
+#. `@bjlittle`_ dropped support for ``Python 3.7``, as per the `NEP-29`_
+ backwards compatibility and deprecation policy schedule. (:pull:`4481`)
+
+
+📚 Documentation
+================
+
+#. `@rcomer`_ updated the "Plotting Wind Direction Using Quiver" Gallery
+ example. (:pull:`4120`)
+
+#. `@trexfeathers`_ included Iris `GitHub Discussions`_ in
+ :ref:`get involved `. (:pull:`4307`)
+
+#. `@wjbenfold`_ improved readability in :ref:`userguide interpolation
+ section `. (:pull:`4314`)
+
+#. `@wjbenfold`_ added explanation about the absence of | operator for
+ :class:`iris.Constraint` to :ref:`userguide loading section
+ ` and to api reference documentation. (:pull:`4321`)
+
+#. `@trexfeathers`_ added more detail on making `iris-test-data`_ available
+ during :ref:`developer_running_tests`. (:pull:`4359`)
+
+#. `@lbdreyer`_ added a section to the release documentation outlining the role
+ of the :ref:`release_manager`. (:pull:`4413`)
+
+#. `@trexfeathers`_ encouraged contributors to include type hinting in code
+ they are working on - :ref:`code_formatting`. (:pull:`4390`)
+
+#. `@wjbenfold`_ updated Cartopy documentation links to point to the renamed
+ :class:`cartopy.mpl.geoaxes.GeoAxes`. (:pull:`4464`)
+
+#. `@wjbenfold`_ clarified behaviour of :func:`iris.load` in :ref:`userguide
+ loading section `. (:pull:`4462`)
+
+#. `@bjlittle`_ migrated readthedocs to use mambaforge for `faster documentation building`_.
+ (:pull:`4476`)
+
+#. `@wjbenfold`_ contributed `@alastair-gemmell`_'s :ref:`step-by-step guide to
+ contributing to the docs ` to the docs.
+ (:pull:`4461`)
+
+#. `@pp-mo`_ improved and corrected docstrings of
+ :class:`iris.analysis.PointInCell`, making it clear what is the actual
+ calculation performed. (:pull:`4548`)
+
+#. `@pp-mo`_ removed reference in docstring of
+ :class:`iris.analysis.UnstructuredNearest` to the obsolete (deprecated)
+ :class:`iris.experimental.regrid.ProjectedUnstructuredNearest`.
+ (:pull:`4548`)
+
+
+💼 Internal
+===========
+
+#. `@trexfeathers`_ set the linkcheck to ignore
+ http://www.nationalarchives.gov.uk/doc/open-government-licence since this
+ always works locally, but never within CI. (:pull:`4307`)
+
+#. `@wjbenfold`_ netCDF integration tests now skip ``TestConstrainedLoad`` if
+ test data is missing (:pull:`4319`)
+
+#. `@wjbenfold`_ excluded ``Good First Issue`` labelled issues from being
+ marked stale. (:pull:`4317`)
+
+#. `@tkknight`_ added additional make targets for reducing the time of the
+ documentation build including ``html-noapi`` and ``html-quick``.
+ Useful for development purposes only. For more information see
+ :ref:`contributing.documentation.building` the documentation. (:pull:`4333`)
+
+#. `@rcomer`_ modified the ``animation`` test to prevent it throwing a warning
+ that sometimes interferes with unrelated tests. (:pull:`4330`)
+
+#. `@rcomer`_ removed a now redundant workaround in :func:`~iris.plot.contourf`.
+ (:pull:`4349`)
+
+#. `@trexfeathers`_ refactored :mod:`iris.experimental.ugrid` into sub-modules.
+ (:pull:`4347`).
+
+#. `@bjlittle`_ enabled the `sort-all`_ `pre-commit`_ hook to automatically
+ sort ``__all__`` entries into alphabetical order. (:pull:`4353`)
+
+#. `@rcomer`_ modified a NetCDF saver test to prevent it triggering a numpy
+ deprecation warning. (:issue:`4374`, :pull:`4376`)
+
+#. `@akuhnregnier`_ removed addition of period from
+ :func:`~iris.analysis.cartography.wrap_lons` and updated affected tests
+ using ``assertArrayAllClose`` following :issue:`3993`.
+ (:pull:`4421`)
+
+#. `@rcomer`_ updated some tests to work with Matplotlib v3.5. (:pull:`4428`)
+
+#. `@rcomer`_ applied minor fixes to some regridding tests. (:pull:`4432`)
+
+#. `@lbdreyer`_ corrected the license PyPI classifier. (:pull:`4435`)
+
+#. `@aaronspring`_ exchanged ``dask`` with
+ ``dask-core`` in testing environments reducing the number of dependencies
+ installed for testing. (:pull:`4434`)
+
+#. `@wjbenfold`_ prevented github action runs in forks (:issue:`4441`,
+ :pull:`4444`)
+
+#. `@wjbenfold`_ fixed tests for hybrid formulae that weren't being found by
+ nose (:issue:`4431`, :pull:`4450`)
+
+.. comment
+ Whatsnew author names (@github name) in alphabetical order. Note that,
+ core dev names are automatically included by the common_links.inc:
+
+.. _@aaronspring: https://github.com/aaronspring
+.. _@akuhnregnier: https://github.com/akuhnregnier
+.. _@bsherratt: https://github.com/bsherratt
+.. _@dennissergeev: https://github.com/dennissergeev
+.. _@larsbarring: https://github.com/larsbarring
+.. _@pdearnshaw: https://github.com/pdearnshaw
+.. _@SimonPeatman: https://github.com/SimonPeatman
+.. _@tinyendian: https://github.com/tinyendian
+
+.. comment
+ Whatsnew resources in alphabetical order:
+
+.. _NEP-29: https://numpy.org/neps/nep-0029-deprecation_policy.html
+.. _UGRID: http://ugrid-conventions.github.io/ugrid-conventions/
+.. _iris-emsf-regrid: https://github.com/SciTools-incubator/iris-esmf-regrid
+.. _faster documentation building: https://docs.readthedocs.io/en/stable/guides/conda.html#making-builds-faster-with-mamba
+.. _sort-all: https://github.com/aio-libs/sort-all
diff --git a/docs/src/whatsnew/3.3.rst b/docs/src/whatsnew/3.3.rst
new file mode 100644
index 0000000000..c2e47f298a
--- /dev/null
+++ b/docs/src/whatsnew/3.3.rst
@@ -0,0 +1,373 @@
+.. include:: ../common_links.inc
+
+v3.3 (1 Sep 2022)
+*****************
+
+This document explains the changes made to Iris for this release
+(:doc:`View all changes `.)
+
+
+.. dropdown:: :opticon:`report` v3.3.0 Release Highlights
+ :container: + shadow
+ :title: text-primary text-center font-weight-bold
+ :body: bg-light
+ :animate: fade-in
+ :open:
+
+ The highlights for this minor release of Iris include:
+
+ * We've added support for datums, loading them from NetCDF when the
+ :obj:`iris.FUTURE.datum_support` flag is set.
+ * We've greatly improved the speed of linear interpolation.
+ * We've added the function :func:`iris.pandas.as_cubes` for richer
+ conversion from Pandas.
+ * We've improved the functionality of :func:`iris.util.mask_cube`.
+ * We've improved the functionality and performance of the
+ :obj:`iris.analysis.PERCENTILE` aggregator.
+ * We've completed implementation of our :ref:`contributing.benchmarks`
+ infrastructure.
+
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
+
+
+v3.3.1 (29 Sep 2022)
+====================
+
+.. dropdown:: :opticon:`alert` v3.3.1 Patches
+ :container: + shadow
+ :title: text-primary text-center font-weight-bold
+ :body: bg-light
+ :animate: fade-in
+
+ The patches in this release of Iris include:
+
+ #. `@pp-mo`_ fixed the Jupyter notebook display of :class:`~iris.cube.CubeList`.
+ (:issue:`4973`, :pull:`4976`)
+
+ #. `@pp-mo`_ fixed a bug in NAME loaders where data with no associated statistic would
+ load as a cube with invalid cell-methods, which cannot be printed or saved to netcdf.
+ (:issue:`3288`, :pull:`4933`)
+
+ #. `@pp-mo`_ ensured that :data:`iris.cube.Cube.cell_methods` must always be an iterable
+ of :class:`iris.coords.CellMethod` objects (:pull:`4933`).
+
+ #. `@trexfeathers`_ advanced the Cartopy pin to ``>=0.21``, as Cartopy's
+ change to default Transverse Mercator projection affects an Iris test.
+ See `SciTools/cartopy@fcb784d`_ and `SciTools/cartopy@8860a81`_ for more
+ details. (:pull:`4992`)
+
+ #. `@trexfeathers`_ introduced the ``netcdf4!=1.6.1`` pin to avoid a
+ problem with segfaults. (:pull:`4992`)
+
+
+📢 Announcements
+================
+
+#. Welcome to `@krikru`_ who made their first contribution to Iris 🎉
+
+
+✨ Features
+===========
+
+#. `@schlunma`_ added weighted aggregation over "group coordinates":
+ :meth:`~iris.cube.Cube.aggregated_by` now accepts the keyword `weights` if a
+ :class:`~iris.analysis.WeightedAggregator` is used. (:issue:`4581`,
+ :pull:`4589`)
+
+#. `@wjbenfold`_ added support for ``false_easting`` and ``false_northing`` to
+ :class:`~iris.coord_systems.Mercator`. (:issue:`3107`, :pull:`4524`)
+
+#. `@rcomer`_ and `@wjbenfold`_ (reviewer) implemented lazy aggregation for the
+ :obj:`iris.analysis.PERCENTILE` aggregator. (:pull:`3901`)
+
+#. `@pp-mo`_ fixed cube arithmetic operation for cubes with meshes.
+ (:issue:`4454`, :pull:`4651`)
+
+#. `@wjbenfold`_ added support for CF-compliant treatment of
+ ``standard_parallel`` and ``scale_factor_at_projection_origin`` to
+ :class:`~iris.coord_systems.Mercator`. (:issue:`3844`, :pull:`4609`)
+
+#. `@wjbenfold`_ added support datums associated with coordinate systems (e.g.
+ :class:`~iris.coord_systems.GeogCS` other subclasses of
+ :class:`~iris.coord_systems.CoordSystem`). Loading of datum information from
+ a netCDF file only happens when the :obj:`iris.FUTURE.datum_support` flag is
+ set. (:issue:`4619`, :pull:`4704`)
+
+#. `@wjbenfold`_ and `@stephenworsley`_ (reviewer) added a maximum run length
+ aggregator (:class:`~iris.analysis.MAX_RUN`). (:pull:`4676`)
+
+#. `@wjbenfold`_ and `@rcomer`_ (reviewer) added a ``climatological`` keyword to
+ :meth:`~iris.cube.Cube.aggregated_by` that causes the climatological flag to
+ be set and the point for each cell to equal its first bound, thereby
+ preserving the time of year. (:issue:`1422`, :issue:`4098`, :issue:`4665`,
+ :pull:`4723`)
+
+#. `@wjbenfold`_ and `@pp-mo`_ (reviewer) implemented the
+ :class:`~iris.coord_systems.PolarStereographic` CRS. (:issue:`4770`,
+ :pull:`4773`)
+
+#. `@rcomer`_ and `@wjbenfold`_ (reviewer) enabled passing of the
+ :func:`numpy.percentile` keywords through the :obj:`~iris.analysis.PERCENTILE`
+ aggregator. (:pull:`4791`)
+
+#. `@wjbenfold`_ and `@bjlittle`_ (reviewer) implemented
+ :func:`iris.plot.fill_between` and :func:`iris.quickplot.fill_between`.
+ (:issue:`3493`, :pull:`4647`)
+
+#. `@rcomer`_ and `@bjlittle`_ (reviewer) re-wrote :func:`iris.util.mask_cube`
+ to provide lazy evaluation and greater flexibility with respect to input types.
+ (:issue:`3936`, :pull:`4889`)
+
+#. `@stephenworsley`_ and `@lbdreyer`_ added a new kwarg ``expand_extras`` to
+ :func:`iris.util.new_axis` which can be used to specify instances of
+ :class:`~iris.coords.AuxCoord`, :class:`~iris.coords.CellMeasure` and
+ :class:`~iris.coords.AncillaryVariable` which should also be expanded to map
+ to the new axis. (:pull:`4896`)
+
+#. `@stephenworsley`_ updated to the latest CF Standard Names Table ``v79``
+ (19 March 2022). (:pull:`4910`)
+
+#. `@trexfeathers`_ and `@lbdreyer`_ (reviewer) added
+ :func:`iris.pandas.as_cubes`, which provides richer conversion from
+ Pandas :class:`~pandas.Series` / :class:`~pandas.DataFrame`\s to one or more
+ :class:`~iris.cube.Cube`\s. This includes: n-dimensional datasets,
+ :class:`~iris.coords.AuxCoord`\s, :class:`~iris.coords.CellMeasure`\s,
+ :class:`~iris.coords.AncillaryVariable`\s, and multi-dimensional
+ coordinates. (:pull:`4890`)
+
+
+🐛 Bugs Fixed
+=============
+
+#. `@rcomer`_ reverted part of the change from :pull:`3906` so that
+ :func:`iris.plot.plot` no longer defaults to placing a "Y" coordinate (e.g.
+ latitude) on the y-axis of the plot. (:issue:`4493`, :pull:`4601`)
+
+#. `@rcomer`_ enabled passing of scalar objects to :func:`~iris.plot.plot` and
+ :func:`~iris.plot.scatter`. (:pull:`4616`)
+
+#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.aggregated_by` with `mdtol` for 1D
+ cubes where an aggregated section is entirely masked, reported at
+ :issue:`3190`. (:pull:`4246`)
+
+#. `@rcomer`_ ensured that a :class:`matplotlib.axes.Axes`'s position is preserved
+ when Iris replaces it with a :class:`cartopy.mpl.geoaxes.GeoAxes`, fixing
+ :issue:`1157`. (:pull:`4273`)
+
+#. `@rcomer`_ fixed :meth:`~iris.coords.Coord.nearest_neighbour_index` for edge
+ cases where the requested point is float and the coordinate has integer
+ bounds, reported at :issue:`2969`. (:pull:`4245`)
+
+#. `@rcomer`_ modified bounds setting on :obj:`~iris.coords.DimCoord` instances
+ so that the order of the cell bounds is automatically reversed
+ to match the coordinate's direction if necessary. This is consistent with
+ the `Bounds for 1-D coordinate variables` subsection of the `Cell Boundaries`_
+ section of the CF Conventions and ensures that contiguity is preserved if a
+ coordinate's direction is reversed. (:issue:`3249`, :issue:`423`,
+ :issue:`4078`, :issue:`3756`, :pull:`4466`)
+
+#. `@wjbenfold`_ and `@evertrol`_ prevented an ``AttributeError`` being logged
+ to ``stderr`` when a :class:`~iris.fileformats.cf.CFReader` that fails to
+ initialise is garbage collected. (:issue:`3312`, :pull:`4646`)
+
+#. `@wjbenfold`_ fixed plotting of circular coordinates to extend kwarg arrays
+ as well as the data. (:issue:`466`, :pull:`4649`)
+
+#. `@wjbenfold`_ and `@rcomer`_ (reviewer) corrected the axis on which masking
+ is applied when an aggregator adds a trailing dimension. (:pull:`4755`)
+
+#. `@rcomer`_ and `@pp-mo`_ ensured that all methods to create or modify a
+ :class:`iris.cube.CubeList` check that it only contains cubes. According to
+ code comments, this was supposedly already the case, but there were several bugs
+ and loopholes. (:issue:`1897`, :pull:`4767`)
+
+#. `@rcomer`_ modified cube arithmetic to handle mismatches in the cube's data
+ array type. This prevents masks being lost in some cases and therefore
+ resolves :issue:`2987`. (:pull:`3790`)
+
+#. `@krikru`_ and `@rcomer`_ updated :mod:`iris.quickplot` such that the
+ colorbar is added to the correct ``axes`` when specified as a keyword
+ argument to a plotting routine. Otherwise, by default the colorbar will be
+ added to the current axes of the current figure. (:pull:`4894`)
+
+#. `@rcomer`_ and `@bjlittle`_ (reviewer) modified :func:`iris.util.mask_cube` so it
+ either works in place or returns a new cube (:issue:`3717`, :pull:`4889`)
+
+
+💣 Incompatible Changes
+=======================
+
+#. `@rcomer`_ and `@bjlittle`_ (reviewer) updated Iris's calendar handling to be
+ consistent with ``cf-units`` version 3.1. In line with the `Calendar`_
+ section in version 1.9 of the CF Conventions, we now use "standard" rather
+ than the deprecated "gregorian" label for the default calendar. Units may
+ still be instantiated with ``calendar="gregorian"`` but their calendar
+ attribute will be silently changed to "standard". This may cause failures in
+ code that explicitly checks the calendar attribute. (:pull:`4847`)
+
+
+🚀 Performance
+==============
+
+#. `@wjbenfold`_ added caching to the calculation of the points array in a
+ :class:`~iris.coords.DimCoord` created using
+ :meth:`~iris.coords.DimCoord.from_regular`. (:pull:`4698`)
+
+#. `@wjbenfold`_ introduced caching in :func:`_lazy_data._optimum_chunksize` and
+ :func:`iris.fileformats.pp_load_rules._epoch_date_hours` to reduce time spent
+ repeating calculations. (:pull:`4716`)
+
+#. `@pp-mo`_ made :meth:`~iris.cube.Cube.add_aux_factory` faster.
+ (:pull:`4718`)
+
+#. `@wjbenfold`_ and `@rcomer`_ (reviewer) permitted the fast percentile
+ aggregation method to be used on masked data when the missing data tolerance
+ is set to 0. (:issue:`4735`, :pull:`4755`)
+
+#. `@wjbenfold`_ improved the speed of linear interpolation using
+ :meth:`iris.analysis.trajectory.interpolate` (:pull:`4366`)
+
+#. NumPy ``v1.23`` behaviour changes mean that
+ :func:`iris.experimental.ugrid.utils.recombine_submeshes` now uses ~3x as
+ much memory; testing shows a ~16-million point mesh will now use ~600MB.
+ Investigated by `@pp-mo`_ and `@trexfeathers`_. (:issue:`4845`)
+
+
+🔥 Deprecations
+===============
+
+#. `@trexfeathers`_ and `@lbdreyer`_ (reviewer) deprecated
+ :func:`iris.pandas.as_cube` in favour of the new
+ :func:`iris.pandas.as_cubes` - see `✨ Features`_ for more details.
+ (:pull:`4890`)
+
+
+🔗 Dependencies
+===============
+
+#. `@rcomer`_ introduced the ``nc-time-axis >=1.4`` minimum pin, reflecting that
+ we no longer use the deprecated :class:`nc_time_axis.CalendarDateTime`
+ when plotting against time coordinates. (:pull:`4584`)
+
+#. `@wjbenfold`_ and `@bjlittle`_ (reviewer) unpinned ``pillow``. (:pull:`4826`)
+
+#. `@rcomer`_ introduced the ``cf-units >=3.1`` minimum pin, reflecting the
+ alignment of calendar behaviour in the two packages (see Incompatible Changes).
+ (:pull:`4847`)
+
+#. `@bjlittle`_ introduced the ``sphinx-gallery >=0.11.0`` minimum pin.
+ (:pull:`4885`)
+
+#. `@trexfeathers`_ updated the install process to work with setuptools
+ ``>=v64``, making ``v64`` the minimum compatible version. (:pull:`4903`)
+
+#. `@stephenworsley`_ and `@trexfeathers`_ introduced the ``shapely !=1.8.3``
+ pin, avoiding a bug caused by its interaction with cartopy.
+ (:pull:`4911`, :pull:`4917`)
+
+
+📚 Documentation
+================
+
+#. `@tkknight`_ added a page to show the issues that have been voted for. See
+ :ref:`voted_issues_top`. (:issue:`3307`, :pull:`4617`)
+
+#. `@wjbenfold`_ added a note about fixing proxy URLs in lockfiles generated
+ because dependencies have changed. (:pull:`4666`)
+
+#. `@lbdreyer`_ moved most of the User Guide's :class:`iris.Constraint` examples
+ from :ref:`loading_iris_cubes` to :ref:`cube_extraction` and added an
+ example of constraining on bounded time. (:pull:`4656`)
+
+#. `@tkknight`_ adopted the `PyData Sphinx Theme`_ for the documentation.
+ (:discussion:`4344`, :pull:`4661`)
+
+#. `@tkknight`_ updated our developers guidance to show our intent to adopt
+ numpydoc strings and fixed some API documentation rendering.
+ See :ref:`docstrings`. (:issue:`4657`, :pull:`4689`)
+
+#. `@trexfeathers`_ and `@lbdreyer`_ added a page with examples of converting
+ various mesh formats into the Iris Mesh Data Model. (:pull:`4739`)
+
+#. `@rcomer`_ updated the "Load a Time Series of Data From the NEMO Model"
+ gallery example. (:pull:`4741`)
+
+#. `@wjbenfold`_ added developer documentation to highlight some of the
+ utilities offered by :class:`iris.IrisTest` and how to update CML and other
+ output files. (:issue:`4544`, :pull:`4600`)
+
+#. `@trexfeathers`_ and `@abooton`_ modernised the Iris logo to be SVG format.
+ (:pull:`3935`)
+
+
+💼 Internal
+===========
+
+#. `@trexfeathers`_ and `@pp-mo`_ finished implementing a mature benchmarking
+ infrastructure (see :ref:`contributing.benchmarks`), building on 2 hard
+ years of lessons learned 🎉. (:pull:`4477`, :pull:`4562`, :pull:`4571`,
+ :pull:`4583`, :pull:`4621`)
+
+#. `@wjbenfold`_ used the aforementioned benchmarking infrastructure to
+ introduce deep (large 3rd dimension) loading and realisation benchmarks.
+ (:pull:`4654`)
+
+#. `@wjbenfold`_ made :func:`iris.tests.stock.simple_1d` respect the
+ ``with_bounds`` argument. (:pull:`4658`)
+
+#. `@lbdreyer`_ replaced `nose`_ with `pytest`_ as Iris' test runner.
+ (:pull:`4734`)
+
+#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) migrated to GitHub Actions
+ for Continuous-Integration. (:pull:`4503`)
+
+#. `@pp-mo`_ made tests run certain linux executables from the Python env,
+ specifically ncdump and ncgen. These could otherwise fail when run in IDEs
+ such as PyCharm and Eclipse, which don't automatically include the Python env
+ bin in the system PATH.
+ (:pull:`4794`)
+
+#. `@trexfeathers`_ and `@pp-mo`_ improved generation of stock NetCDF files.
+ (:pull:`4827`, :pull:`4836`)
+
+#. `@rcomer`_ removed some now redundant testing functions. (:pull:`4838`,
+ :pull:`4878`)
+
+#. `@bjlittle`_ and `@jamesp`_ (reviewer) and `@lbdreyer`_ (reviewer) extended
+ the GitHub Continuous-Integration to cover testing on ``py38``, ``py39``,
+ and ``py310``. (:pull:`4840`)
+
+#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) adopted `setuptools-scm`_ for
+ automated ``iris`` package versioning. (:pull:`4841`)
+
+#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) added building, testing and
+ publishing of ``iris`` PyPI ``sdist`` and binary ``wheels`` as part of
+ our GitHub Continuous-Integration. (:pull:`4849`)
+
+#. `@rcomer`_ and `@wjbenfold`_ (reviewer) used ``pytest`` parametrization to
+ streamline the gallery test code. (:pull:`4792`)
+
+#. `@trexfeathers`_ improved settings to better working with
+ ``setuptools_scm``. (:pull:`4925`)
+
+
+.. comment
+ Whatsnew author names (@github name) in alphabetical order. Note that,
+ core dev names are automatically included by the common_links.inc:
+
+.. _@evertrol: https://github.com/evertrol
+.. _@krikru: https://github.com/krikru
+
+
+.. comment
+ Whatsnew resources in alphabetical order:
+
+.. _Calendar: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#calendar
+.. _Cell Boundaries: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#cell-boundaries
+.. _nose: https://nose.readthedocs.io
+.. _PyData Sphinx Theme: https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html
+.. _pytest: https://docs.pytest.org
+.. _setuptools-scm: https://github.com/pypa/setuptools_scm
+.. _SciTools/cartopy@fcb784d: https://github.com/SciTools/cartopy/commit/fcb784daa65d95ed9a74b02ca292801c02bc4108
+.. _SciTools/cartopy@8860a81: https://github.com/SciTools/cartopy/commit/8860a8186d4dc62478e74c83f3b2b3e8f791372e
diff --git a/docs/src/whatsnew/3.4.rst b/docs/src/whatsnew/3.4.rst
new file mode 100644
index 0000000000..02fc574e51
--- /dev/null
+++ b/docs/src/whatsnew/3.4.rst
@@ -0,0 +1,302 @@
+.. include:: ../common_links.inc
+
+v3.4 (01 Dec 2022)
+******************
+
+This document explains the changes made to Iris for this release
+(:doc:`View all changes `.)
+
+
+.. dropdown:: :opticon:`report` v3.4.0 Release Highlights
+ :container: + shadow
+ :title: text-primary text-center font-weight-bold
+ :body: bg-light
+ :animate: fade-in
+ :open:
+
+ The highlights for this minor release of Iris include:
+
+ * We have **archived older Iris documentation** - everything before
+ ``v3.0.0`` - so older versions will soon no longer appear in search
+ engines. If you need this older documentation: please
+ see :ref:`iris_support`.
+ * We have added a :ref:`glossary` to the Iris documentation.
+ * We have completed work to make **Pandas interoperability** handle
+ n-dimensional :class:`~iris.cube.Cube`\s.
+ * We have **begun refactoring Iris' regridding**, which has already improved
+ performance and functionality, with more potential in future!
+ * We have made several other significant `🚀 Performance Enhancements`_.
+
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
+
+
+v3.4.1 (21 Feb 2023)
+====================
+
+.. dropdown:: :opticon:`alert` v3.4.1 Patches
+ :container: + shadow
+ :title: text-primary text-center font-weight-bold
+ :body: bg-light
+ :animate: fade-in
+
+ The patches in this release of Iris include:
+
+ #. `@trexfeathers`_ and `@pp-mo`_ made Iris' use of the `netCDF4`_ library
+ thread-safe. (:pull:`5095`)
+
+ #. `@trexfeathers`_ and `@pp-mo`_ removed the netCDF4 pin mentioned in
+ `🔗 Dependencies`_ point 3. (:pull:`5095`)
+
+
+📢 Announcements
+================
+
+#. Welcome to `@ESadek-MO`_, `@TTV-Intrepid`_ and `@hsteptoe`_, who made their
+ first contributions to Iris 🎉
+
+ .. _try_experimental_stratify:
+
+#. Do you enjoy `python-stratify`_? Did you know that Iris includes a
+ convenience for using `python-stratify`_ with :class:`~iris.cube.Cube`\s?
+ It has been 'experimental' for several years now, without receiving much
+ feedback, so it's **use it or lose it** time: please try out
+ :mod:`iris.experimental.stratify` and let us know what you think!
+
+
+✨ Features
+===========
+
+#. `@ESadek-MO`_ edited :func:`~iris.io.expand_filespecs` to allow expansion of
+ non-existing paths, and added expansion functionality to :func:`~iris.io.save`.
+ (:issue:`4772`, :pull:`4913`)
+
+#. `@trexfeathers`_ and `Julian Heming`_ added new mappings between CF
+ standard names and UK Met Office LBFC codes. (:pull:`4859`)
+
+#. `@pp-mo`_ changed the metadata of a face/edge-type
+ :class:`~iris.experimental.ugrid.mesh.MeshCoord`, to be same as the face/edge
+ coordinate in the mesh from which it takes its ``.points``. Previously, all MeshCoords
+ took their metadata from the node coord, but only a node-type MeshCoord now does
+ that. Also, the MeshCoord ``.var_name`` is now that of the underlying coord, whereas
+ previously this was always None. These changes make MeshCoord more like an ordinary
+ :class:`~iris.coords.AuxCoord`, which avoids some specific known usage problems.
+ (:issue:`4860`, :pull:`5020`)
+
+#. `@Esadek-MO`_ and `@trexfeathers`_ added dim coord
+ prioritisation to ``_get_lon_lat_coords()`` in :mod:`iris.analysis.cartography`.
+ This allows :func:`iris.analysis.cartography.area_weights` and
+ :func:`~iris.analysis.cartography.project` to handle cubes which contain
+ both dim and aux coords of the same type e.g. ``longitude`` and ``grid_longitude``.
+ (:issue:`3916`, :pull:`5029`).
+
+#. `@stephenworsley`_ added the ability to regrid derived coordinates with the
+ :obj:`~iris.analysis.PointInCell` regridding scheme. (:pull:`4807`)
+
+#. `@trexfeathers`_ made NetCDF loading more tolerant by enabling skipping of
+ :class:`~iris.coords.DimCoord`\s, :class:`~iris.coords.AuxCoord`\s,
+ :class:`~iris.coords.CellMeasure`\s and
+ :class:`~iris.coords.AncillaryVariable`\s if they cannot be added to a
+ :class:`~iris.cube.Cube` (e.g. due to CF non-compliance). This is done via
+ a new error class: :class:`~iris.exceptions.CannotAddError` (subclass of
+ :class:`ValueError`). (:pull:`5054`)
+
+#. `@pp-mo`_ implemented == and != comparisons for :class:`~iris.Constraint` s.
+ A simple constraint is now == to another one constructed in the same way.
+ However, equality is limited for more complex cases : value-matching functions must
+ be the same identical function, and for &-combinations order is significant,
+ i.e. ``(c1 & c2) != (c2 & c1)``.
+ (:issue:`3616`, :pull:`3749`).
+
+#. `@hsteptoe`_ and `@trexfeathers`_ improved
+ :func:`iris.pandas.as_data_frame`\'s conversion of :class:`~iris.cube.Cube`\s to
+ :class:`~pandas.DataFrame`\s. This includes better handling of multiple
+ :class:`~iris.cube.Cube` dimensions, auxiliary coordinates and attribute
+ information. **Note:** the improvements are opt-in, by setting the
+ :obj:`iris.FUTURE.pandas_ndim` flag (see :class:`iris.Future` for more).
+ (:issue:`4526`, :pull:`4909`, :pull:`4669`, :pull:`5059`, :pull:`5074`)
+
+
+🐛 Bugs Fixed
+=============
+
+#. `@rcomer`_ and `@pp-mo`_ (reviewer) factored masking into the returned
+ sum-of-weights calculation from :obj:`~iris.analysis.SUM`. (:pull:`4905`)
+
+#. `@schlunma`_ fixed a bug which prevented using
+ :meth:`iris.cube.Cube.collapsed` on coordinates whose number of bounds
+ differs from 0 or 2. This enables the use of this method on mesh
+ coordinates. (:issue:`4672`, :pull:`4870`)
+
+#. `@bjlittle`_ and `@lbdreyer`_ (reviewer) fixed the building of the CF
+ Standard Names module ``iris.std_names`` for the ``setup.py`` commands
+ ``develop`` and ``std_names``. (:issue:`4951`, :pull:`4952`)
+
+#. `@lbdreyer`_ and `@pp-mo`_ (reviewer) fixed the cube print out such that
+ scalar ancillary variables are displayed in a dedicated section rather than
+ being added to the vector ancillary variables section. Further, ancillary
+ variables and cell measures that map to a cube dimension of length 1 are now
+ included in the respective vector sections. (:pull:`4945`)
+
+#. `@rcomer`_ removed some old redundant code that prevented determining the
+ order of time cells. (:issue:`4697`, :pull:`4729`)
+
+#. `@stephenworsley`_ improved the accuracy of the error messages for
+ :meth:`~iris.cube.Cube.coord` when failing to find coordinates in the case where
+ a coordinate is given as the argument. Similarly, improved the error messages for
+ :meth:`~iris.cube.Cube.cell_measure` and :meth:`~iris.cube.Cube.ancillary_variable`.
+ (:issue:`4898`, :pull:`4928`)
+
+#. `@stephenworsley`_ fixed a bug which caused derived coordinates to be realised
+ after calling :meth:`iris.cube.Cube.aggregated_by`. (:issue:`3637`, :pull:`4947`)
+
+#. `@rcomer`_ corrected the ``standard_name`` mapping from UM stash code ``m01s30i311``
+ to indicate that this is the upward, rather than northward part of the flow.
+ (:pull:`5060`)
+
+#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) fixed an issue which prevented
+ uncompressed PP fields with additional trailing padded words in the field
+ data to be loaded and saved. (:pull:`5058`)
+
+#. `@lbdreyer`_ and `@trexfeathers`_ (reviewer) fixed the handling of data when
+ regridding with :class:`~iris.analysis.UnstructuredNearest` or calling
+ :func:`~iris.analysis.trajectory.interpolate` such that the data type and mask is
+ preserved. (:issue:`4463`, :pull:`5062`)
+
+
+💣 Incompatible Changes
+=======================
+
+#. `@trexfeathers`_ altered testing to accept new Dask copying behaviour from
+ `dask/dask#9555`_ - copies of a Dask array created using ``da.from_array()``
+ will all ``compute()`` to a shared identical array. So creating a
+ :class:`~iris.cube.Cube` using ``Cube(data=da.from_array(...``, then
+ using :class:`~iris.cube.Cube` :meth:`~iris.cube.Cube.copy`,
+ will produce two :class:`~iris.cube.Cube`\s that both return an identical
+ array when requesting :class:`~iris.cube.Cube` :attr:`~iris.cube.Cube.data`.
+ We do not expect this to affect typical user workflows but please get in
+ touch if you need help. (:pull:`5041`)
+
+#. `@trexfeathers`_ moved ``iris.experimental.animate.animate()`` to
+ :func:`iris.plot.animate`, in recognition of its successful use over several
+ years since introduction. (:pull:`5056`)
+
+
+🚀 Performance Enhancements
+===========================
+
+#. `@rcomer`_ and `@pp-mo`_ (reviewer) increased aggregation speed for
+ :obj:`~iris.analysis.SUM`, :obj:`~iris.analysis.COUNT` and
+ :obj:`~iris.analysis.PROPORTION` on real data. (:pull:`4905`)
+
+#. `@bouweandela`_ made :meth:`iris.coords.Coord.cells` faster for time
+ coordinates. This also affects :meth:`iris.cube.Cube.extract`,
+ :meth:`iris.cube.Cube.subset`, and :meth:`iris.coords.Coord.intersect`.
+ (:pull:`4969`)
+
+#. `@bouweandela`_ improved the speed of :meth:`iris.cube.Cube.subset` /
+ :meth:`iris.coords.Coord.intersect`.
+ (:pull:`4955`)
+
+#. `@stephenworsley`_ improved the speed of the :obj:`~iris.analysis.PointInCell`
+ regridding scheme. (:pull:`4807`)
+
+
+🔥 Deprecations
+===============
+
+#. `@hsteptoe`_ and `@trexfeathers`_ (reviewer) deprecated
+ :func:`iris.pandas.as_series` in favour of the new
+ :func:`iris.pandas.as_data_frame` - see `✨ Features`_ for more details.
+ (:pull:`4669`)
+
+
+🔗 Dependencies
+===============
+
+#. `@rcomer`_ introduced the ``dask >=2.26`` minimum pin, so that Iris can benefit
+ from Dask's support for `NEP13`_ and `NEP18`_. (:pull:`4905`)
+
+#. `@trexfeathers`_ advanced the Cartopy pin to ``>=0.21``, as Cartopy's
+ change to default Transverse Mercator projection affects an Iris test.
+ See `SciTools/cartopy@fcb784d`_ and `SciTools/cartopy@8860a81`_ for more
+ details.
+ (:pull:`4968`)
+
+#. `@trexfeathers`_ introduced the ``netcdf4<1.6.1`` pin to avoid a problem
+ with segfaults. (:pull:`4968`, :pull:`5075`, :issue:`5016`)
+
+#. `@trexfeathers`_ updated the Matplotlib colormap registration in
+ :mod:`iris.palette` in response to a deprecation warning. Using the new
+ Matplotlib API also means a ``matplotlib>=3.5`` pin. (:pull:`4998`)
+
+#. See `💣 Incompatible Changes`_ for notes about `dask/dask#9555`_.
+
+
+📚 Documentation
+================
+
+#. `@ESadek-MO`_, `@TTV-Intrepid`_ and `@trexfeathers`_ added a gallery example for zonal
+ means plotted parallel to a cartographic plot. (:pull:`4871`)
+
+#. `@Esadek-MO`_ added a key-terms :ref:`glossary` page into the user guide. (:pull:`4902`)
+
+#. `@pp-mo`_ added a :ref:`code example `
+ for converting ORCA-gridded data to an unstructured cube. (:pull:`5013`)
+#. `@Esadek-MO`_ added links to relevant Gallery examples within the User Guide
+ to improve understanding. (:pull:`5009`)
+
+#. `@trexfeathers`_ changed the warning header for the **latest** documentation
+ to reference Read the Docs' built-in version switcher, instead of generating
+ its own independent links. (:pull:`5055`)
+
+#. `@tkknight`_ updated the links for the Iris documentation to v2.4 and
+ earlier to point to the archive of zip files instead. (:pull:`5064`)
+
+#. `@Esadek-MO`_ began adding notes at the bottom of functions to
+ to clarify if the function preserves laziness or not. See :issue:`3292` for
+ the ongoing checklist. (:pull:`5066`)
+
+💼 Internal
+===========
+
+#. `@rcomer`_ removed the obsolete ``setUpClass`` method from Iris testing.
+ (:pull:`4927`)
+
+#. `@bjlittle`_ and `@lbdreyer`_ (reviewer) removed support for
+ ``python setup.py test``, which is a deprecated approach to executing
+ package tests, see `pypa/setuptools#1684`_. Also performed assorted
+ ``setup.py`` script hygiene. (:pull:`4948`, :pull:`4949`, :pull:`4950`)
+
+#. `@pp-mo`_ split the module :mod:`iris.fileformats.netcdf` into separate
+ :mod:`~iris.fileformats.netcdf.loader` and :mod:`~iris.fileformats.netcdf.saver`
+ submodules, just to make the code easier to handle.
+
+#. `@trexfeathers`_ adapted the benchmark for importing :mod:`iris.palette` to
+ cope with new colormap behaviour in Matplotlib `v3.6`. (:pull:`4998`)
+
+#. `@rcomer`_ removed a now redundant workaround for an old matplotlib bug,
+ highlighted by :issue:`4090`. (:pull:`4999`)
+
+#. `@rcomer`_ added the ``show`` option to the documentation Makefiles, as a
+ convenient way for contributors to view their built documentation.
+ (:pull:`5000`)
+
+.. comment
+ Whatsnew author names (@github name) in alphabetical order. Note that,
+ core dev names are automatically included by the common_links.inc:
+
+.. _@TTV-Intrepid: https://github.com/TTV-Intrepid
+.. _Julian Heming: https://www.metoffice.gov.uk/research/people/julian-heming
+.. _@hsteptoe: https://github.com/hsteptoe
+
+
+.. comment
+ Whatsnew resources in alphabetical order:
+
+.. _NEP13: https://numpy.org/neps/nep-0013-ufunc-overrides.html
+.. _NEP18: https://numpy.org/neps/nep-0018-array-function-protocol.html
+.. _pypa/setuptools#1684: https://github.com/pypa/setuptools/issues/1684
+.. _SciTools/cartopy@fcb784d: https://github.com/SciTools/cartopy/commit/fcb784daa65d95ed9a74b02ca292801c02bc4108
+.. _SciTools/cartopy@8860a81: https://github.com/SciTools/cartopy/commit/8860a8186d4dc62478e74c83f3b2b3e8f791372e
+.. _dask/dask#9555: https://github.com/dask/dask/pull/9555
diff --git a/docs/src/whatsnew/index.rst b/docs/src/whatsnew/index.rst
index fabb056484..005fac70c4 100644
--- a/docs/src/whatsnew/index.rst
+++ b/docs/src/whatsnew/index.rst
@@ -1,16 +1,20 @@
+.. include:: ../common_links.inc
+
.. _iris_whatsnew:
What's New in Iris
-******************
-
-These "What's new" pages describe the important changes between major
-Iris versions.
+------------------
+.. include:: latest.rst
.. toctree::
:maxdepth: 1
+ :hidden:
latest.rst
+ 3.4.rst
+ 3.3.rst
+ 3.2.rst
3.1.rst
3.0.rst
2.4.rst
diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst
index e2d4c2bc0b..c5c3b2d173 100644
--- a/docs/src/whatsnew/latest.rst
+++ b/docs/src/whatsnew/latest.rst
@@ -14,13 +14,9 @@ This document explains the changes made to Iris for this release
:animate: fade-in
:open:
- The highlights for this minor release of Iris include:
+ The highlights for this major/minor release of Iris include:
- * We've added experimental support for
- :ref:`Meshes `, which can now be loaded and
- attached to a cube. Mesh support is based on the based on `CF-UGRID`_
- model.
- * We've also dropped support for ``Python 3.7``.
+ * We're so proud to fully support `@ed-hawkins`_ and `#ShowYourStripes`_ ❤️
And finally, get in touch with us on :issue:`GitHub` if you have
any issues or feature requests for improving Iris. Enjoy!
@@ -29,154 +25,23 @@ This document explains the changes made to Iris for this release
📢 Announcements
================
-#. Welcome to `@wjbenfold`_, `@tinyendian`_, `@larsbarring`_, `@bsherratt`_ and
- `@aaronspring`_ who made their first contributions to Iris. The first of
- many we hope!
-#. Congratulations to `@wjbenfold`_ who has become a core developer for Iris! 🎉
+#. Congratulations to `@ESadek-MO`_ who has become a core developer for Iris! 🎉
+#. Welcome and congratulations to `@HGWright`_ for making his first contribution to Iris! 🎉
✨ Features
===========
-#. `@bjlittle`_, `@pp-mo`_, `@trexfeathers`_ and `@stephenworsley`_ added
- support for :ref:`unstructured meshes `. This involved
- adding a data model (:pull:`3968`, :pull:`4014`, :pull:`4027`, :pull:`4036`,
- :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`,
- :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
- type mesh. :class:`~iris.experimental.ugrid.mesh.MeshCoord`\ s are coordinates that
- reference and represent a :class:`~iris.experimental.ugrid.mesh.Mesh` 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.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.
- (: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
- (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
- appropriate collection of :class:`iris.coords.Coord`\ s.
-
-#. `@larsbarring`_ updated :func:`~iris.util.equalise_attributes` to return a list of dictionaries
- containing the attributes removed from each :class:`~iris.cube.Cube`. (:pull:`4357`)
-
-#. `@trexfeathers`_ enabled streaming of **all** lazy arrays when saving to
- NetCDF files (was previously just :class:`~iris.cube.Cube`
- :attr:`~iris.cube.Cube.data`). This is
- important given the much greater size of
- :class:`~iris.coords.AuxCoord` :attr:`~iris.coords.AuxCoord.points` and
- :class:`~iris.experimental.ugrid.mesh.Connectivity`
- :attr:`~iris.experimental.ugrid.mesh.Connectivity.indices` under the
- :ref:`mesh model `. (:pull:`4375`)
-
-#. `@bsherratt`_ added a ``threshold`` parameter to
- :meth:`~iris.cube.Cube.intersection` (:pull:`4363`)
-
-#. `@wjbenfold`_ added test data to ci benchmarks so that it is accessible to
- benchmark scripts. Also added a regridding benchmark that uses this data
- (:pull:`4402`)
-
-#. `@pp-mo`_ updated to the latest CF Standard Names Table ``v78`` (21 Sept 2021).
- (:issue:`4479`, :pull:`4483`)
-
-#. `@SimonPeatman`_ added support for filenames in the form of a :class:`~pathlib.PurePath`
- in :func:`~iris.load`, :func:`~iris.load_cube`, :func:`~iris.load_cubes`,
- :func:`~iris.load_raw` and :func:`~iris.save` (:issue:`3411`, :pull:`3917`).
- Support for :class:`~pathlib.PurePath` is yet to be implemented across the rest
- of Iris (:issue:`4523`).
-
-#. `@pp-mo`_ removed broken tooling for deriving Iris metadata translations
- from `Metarelate`_. From now we intend to manage phenonemon translation
- in Iris itself. (:pull:`4484`)
-
-#. `@pp-mo`_ improved printout of various cube data component objects :
- :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`.
- 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`.
- They also no longer realise lazy data. (:pull:`4499`).
+#. `@bsherratt`_ added support for plugins - see the corresponding
+ :ref:`documentation page` for further information.
+ (:pull:`5144`)
🐛 Bugs Fixed
=============
-#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.intersection` for special cases where
- one cell's bounds align with the requested maximum and negative minimum, fixing
- :issue:`4221`. (:pull:`4278`)
-
-#. `@bsherratt`_ fixed further edge cases in
- :meth:`~iris.cube.Cube.intersection`, including :issue:`3698` (:pull:`4363`)
-
-#. `@tinyendian`_ fixed the error message produced by :meth:`~iris.cube.CubeList.concatenate_cube`
- when a cube list contains cubes with different names, which will no longer report
- "Cube names differ: var1 != var1" if var1 appears multiple times in the list
- (:issue:`4342`, :pull:`4345`)
-
-#. `@larsbarring`_ fixed :class:`~iris.coord_systems.GeoCS` to handle spherical ellipsoid
- parameter inverse_flattening = 0 (:issue:`4146`, :pull:`4348`)
-
-#. `@pdearnshaw`_ fixed an error in the call to :class:`cftime.datetime` in
- :mod:`~iris.fileformats.pp_save_rules` that prevented the saving to PP of climate
- means for DJF (:pull:`4391`)
-
-#. `@wjbenfold`_ improved the error message for failure of :meth:`~iris.cube.CubeList.concatenate`
- to indicate that the value of a scalar coordinate may be mismatched, rather than the metadata
- (:issue:`4096`, :pull:`4387`)
-
-#. `@bsherratt`_ fixed a regression to the NAME file loader introduced in 3.0.4,
- as well as some long-standing bugs with vertical coordinates and number
- formats. (:pull:`4411`)
-
-#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.subset` to alway return ``None`` if
- no value match is found. (:pull:`4417`)
-
-#. `@wjbenfold`_ changed :meth:`iris.util.points_step` to stop it from warning
- when applied to a single point (:issue:`4250`, :pull:`4367`)
-
-#. `@trexfeathers`_ changed :class:`~iris.coords._DimensionalMetadata` and
- :class:`~iris.experimental.ugrid.Connectivity` equality methods to preserve
- array laziness, allowing efficient comparisons even with larger-than-memory
- objects. (:pull:`4439`)
-
-#. `@rcomer`_ modified :meth:`~iris.cube.Cube.aggregated_by` to calculate new
- coordinate bounds using minimum and maximum for unordered coordinates,
- fixing :issue:`1528`. (:pull:`4315`)
-
-#. `@wjbenfold`_ changed how a delayed unit conversion is performed on a cube
- so that a cube with lazy data awaiting a unit conversion can be pickled.
- (:issue:`4354`, :pull:`4377`)
-
-#. `@pp-mo`_ fixed a bug in netcdf loading, whereby *any* rotated latlon coordinate
- was mistakenly interpreted as a latitude, usually resulting in two 'latitude's
- instead of one latitude and one longitude.
- (:issue:`4460`, :pull:`4470`)
-
-#. `@wjbenfold`_ stopped :meth:`iris.coord_systems.GeogCS.as_cartopy_projection`
- from assuming the globe to be the Earth (:issue:`4408`, :pull:`4497`)
-
-#. `@rcomer`_ corrected the ``long_name`` mapping from UM stash code ``m01s09i215``
- to indicate cloud fraction greater than 7.9 oktas, rather than 7.5
- (:issue:`3305`, :pull:`4535`)
+#. `@trexfeathers`_ and `@pp-mo`_ made Iris' use of the `netCDF4`_ library
+ thread-safe. (:pull:`5095`)
💣 Incompatible Changes
@@ -188,195 +53,78 @@ This document explains the changes made to Iris for this release
🚀 Performance Enhancements
===========================
-#. `@wjbenfold`_ resolved an issue that previously caused regridding with lazy
- data to take significantly longer than with real data. Benchmark
- :class:`benchmarks.HorizontalChunkedRegridding` shows a time decrease
- from >10s to 625ms. (:issue:`4280`, :pull:`4400`)
-
-#. `@bjlittle`_ included an optimisation to :class:`~iris.cube.Cube.coord_dims`
- to avoid unnecessary processing whenever a coordinate instance that already
- exists within the cube is provided. (:pull:`4549`)
+#. N/A
🔥 Deprecations
===============
-#. `@wjbenfold`_ removed :mod:`iris.experimental.equalise_cubes`. In ``v3.0``
- the experimental ``equalise_attributes`` functionality was moved to the
- :mod:`iris.util.equalise_attributes` function. Since then, calling the
- :func:`iris.experimental.equalise_cubes.equalise_attributes` function raised
- an exception. (:issue:`3528`, :pull:`4496`)
-
-#. `@wjbenfold`_ deprecated :func:`iris.util.approx_equal` in preference for
- :func:`math.isclose`. The :func:`~iris.util.approx_equal` function will be
- removed in a future release of Iris. (:pull:`4514`)
-
-#. `@wjbenfold`_ deprecated :mod:`iris.experimental.raster` as it is not
- believed to still be in use. The deprecation warnings invite users to contact
- the Iris Developers if this isn't the case. (:pull:`4525`)
-
-#. `@wjbenfold`_ deprecated :mod:`iris.fileformats.abf` and
- :mod:`iris.fileformats.dot` as they are not believed to still be in use. The
- deprecation warnings invite users to contact the Iris Developers if this
- isn't the case. (:pull:`4515`)
-
-#. `@wjbenfold`_ removed the :func:`iris.util.as_compatible_shape` function,
- which was deprecated in ``v3.0``. Instead use
- :class:`iris.common.resolve.Resolve`. For example, rather than calling
- ``as_compatible_shape(src_cube, target_cube)`` replace with
- ``Resolve(src_cube, target_cube)(target_cube.core_data())``. (:pull:`4513`)
-
-#. `@wjbenfold`_ deprecated :func:`iris.analysis.maths.intersection_of_cubes` in
- preference for :meth:`iris.cube.CubeList.extract_overlapping`. The
- :func:`~iris.analysis.maths.intersection_of_cubes` function will be removed in
- a future release of Iris. (:pull:`4541`)
-
-#. `@pp-mo`_ deprecated :mod:`iris.experimental.regrid_conservative`. This is
- now replaced by `iris-emsf-regrid`_. (:pull:`4551`)
-
-#. `@pp-mo`_ deprecated everything in :mod:`iris.experimental.regrid`.
- Most features have a preferred exact alternative, as suggested, *except*
- :class:`iris.experimental.regrid.ProjectedUnstructuredLinear` : that has no
- identical equivalent, but :class:`iris.analysis.UnstructuredNearest` is
- suggested as being quite close (though possibly slower). (:pull:`4548`)
+#. N/A
🔗 Dependencies
===============
-#. `@bjlittle`_ introduced the ``cartopy >=0.20`` minimum pin.
- (:pull:`4331`)
-
-#. `@trexfeathers`_ introduced the ``cf-units >=3`` and ``nc-time-axis >=1.3``
- minimum pins. (:pull:`4356`)
-
-#. `@bjlittle`_ introduced the ``numpy >=1.19`` minimum pin, in
- accordance with `NEP-29`_ deprecation policy. (:pull:`4386`)
-
-#. `@bjlittle`_ dropped support for ``Python 3.7``, as per the `NEP-29`_
- backwards compatibility and deprecation policy schedule. (:pull:`4481`)
+#. N/A
📚 Documentation
================
-#. `@rcomer`_ updated the "Plotting Wind Direction Using Quiver" Gallery
- example. (:pull:`4120`)
-
-#. `@trexfeathers`_ included `Iris GitHub Discussions`_ in
- :ref:`get involved `. (:pull:`4307`)
+#. `@rcomer`_ clarified instructions for updating gallery tests. (:pull:`5100`)
+#. `@tkknight`_ unpinned ``pydata-sphinx-theme`` and set the default to use
+ the light version (not dark) while we make the docs dark mode friendly
+ (:pull:`5129`)
-#. `@wjbenfold`_ improved readability in :ref:`userguide interpolation
- section `. (:pull:`4314`)
+#. `@jonseddon`_ updated the citation to a more recent version of Iris. (:pull:`5116`)
-#. `@wjbenfold`_ added explanation about the absence of | operator for
- :class:`iris.Constraint` to :ref:`userguide loading section
- ` and to api reference documentation. (:pull:`4321`)
+#. `@rcomer`_ linked the :obj:`~iris.analysis.PERCENTILE` aggregator from the
+ :obj:`~iris.analysis.MEDIAN` docstring, noting that the former handles lazy
+ data. (:pull:`5128`)
-#. `@trexfeathers`_ added more detail on making `iris-test-data`_ available
- during :ref:`developer_running_tests`. (:pull:`4359`)
+#. `@trexfeathers`_ updated the WSL link to Microsoft's latest documentation,
+ and removed an ECMWF link in the ``v1.0`` What's New that was failing the
+ linkcheck CI. (:pull:`5109`)
-#. `@lbdreyer`_ added a section to the release documentation outlining the role
- of the :ref:`release_manager`. (:pull:`4413`)
+#. `@trexfeathers`_ added a new top-level :doc:`/community/index` section,
+ as a one-stop place to find out about getting involved, and how we relate
+ to other projects. (:pull:`5025`)
-#. `@trexfeathers`_ encouraged contributors to include type hinting in code
- they are working on - :ref:`code_formatting`. (:pull:`4390`)
+#. The **Iris community**, with help from the **Xarray community**, produced
+ the :doc:`/community/iris_xarray` page, highlighting the similarities and
+ differences between the two packages. (:pull:`5025`)
-#. `@wjbenfold`_ updated Cartopy documentation links to point to the renamed
- :class:`cartopy.mpl.geoaxes.GeoAxes`. (:pull:`4464`)
-
-#. `@wjbenfold`_ clarified behaviour of :func:`iris.load` in :ref:`userguide
- loading section `. (:pull:`4462`)
-
-#. `@bjlittle`_ migrated readthedocs to use mambaforge for `faster documentation building`_.
- (:pull:`4476`)
-
-#. `@wjbenfold`_ contributed `@alastair-gemmell`_'s :ref:`step-by-step guide to
- contributing to the docs ` to the docs.
- (:pull:`4461`)
-
-#. `@pp-mo`_ improved and corrected docstrings of
- :class:`iris.analysis.PointInCell`, making it clear what is the actual
- calculation performed. (:pull:`4548`)
-
-#. `@pp-mo`_ removed reference in docstring of
- :class:`iris.analysis.UnstructuredNearest` to the obsolete (deprecated)
- :class:`iris.experimental.regrid.ProjectedUnstructuredNearest`.
- (:pull:`4548`)
+#. `@bjlittle`_ added a new section to the `README.md`_ to show our support
+ for the outstanding work of `@ed-hawkins`_ et al for `#ShowYourStripes`_.
+ (:pull:`5141`)
+#. `@HGWright`_ fixed some typo's from Gitwash. (:pull:`5145`)
💼 Internal
===========
-#. `@trexfeathers`_ set the linkcheck to ignore
- http://www.nationalarchives.gov.uk/doc/open-government-licence since this
- always works locally, but never within CI. (:pull:`4307`)
-
-#. `@wjbenfold`_ netCDF integration tests now skip ``TestConstrainedLoad`` if
- test data is missing (:pull:`4319`)
-
-#. `@wjbenfold`_ excluded ``Good First Issue`` labelled issues from being
- marked stale. (:pull:`4317`)
-
-#. `@tkknight`_ added additional make targets for reducing the time of the
- documentation build including ``html-noapi`` and ``html-quick``.
- Useful for development purposes only. For more information see
- :ref:`contributing.documentation.building` the documentation. (:pull:`4333`)
-
-#. `@rcomer`_ modified the ``animation`` test to prevent it throwing a warning
- that sometimes interferes with unrelated tests. (:pull:`4330`)
-
-#. `@rcomer`_ removed a now redundant workaround in :func:`~iris.plot.contourf`.
- (:pull:`4349`)
-
-#. `@trexfeathers`_ refactored :mod:`iris.experimental.ugrid` into sub-modules.
- (:pull:`4347`).
-
-#. `@bjlittle`_ enabled the `sort-all`_ `pre-commit`_ hook to automatically
- sort ``__all__`` entries into alphabetical order. (:pull:`4353`)
-
-#. `@rcomer`_ modified a NetCDF saver test to prevent it triggering a numpy
- deprecation warning. (:issue:`4374`, :pull:`4376`)
-
-#. `@akuhnregnier`_ removed addition of period from
- :func:`~iris.analysis.cartography.wrap_lons` and updated affected tests
- using ``assertArrayAllClose`` following :issue:`3993`.
- (:pull:`4421`)
-
-#. `@rcomer`_ updated some tests to work with Matplotlib v3.5. (:pull:`4428`)
-
-#. `@rcomer`_ applied minor fixes to some regridding tests. (:pull:`4432`)
-
-#. `@lbdreyer`_ corrected the license PyPI classifier. (:pull:`4435`)
+#. `@fnattino`_ changed the order of ``ncgen`` arguments in the command to
+ create NetCDF files for testing (caused errors on OS X). (:pull:`5105`)
-#. `@aaronspring `_ exchanged ``dask`` with
- ``dask-core`` in testing environments reducing the number of dependencies
- installed for testing. (:pull:`4434`)
+#. `@rcomer`_ removed some old infrastructure that printed test timings.
+ (:pull:`5101`)
-#. `@wjbenfold`_ prevented github action runs in forks (:issue:`4441`,
- :pull:`4444`)
+#. `@lbdreyer`_ and `@trexfeathers`_ (reviewer) added coverage testing. This
+ can be enabled by using the "--coverage" flag when running the tests with
+ nox i.e. ``nox --session tests -- --coverage``. (:pull:`4765`)
-#. `@wjbenfold`_ fixed tests for hybrid formulae that weren't being found by
- nose (:issue:`4431`, :pull:`4450`)
+#. `@lbdreyer`_ and `@trexfeathers`_ (reviewer) removed the ``--coding-tests``
+ option from Iris' test runner. (:pull:`4765`)
.. comment
Whatsnew author names (@github name) in alphabetical order. Note that,
core dev names are automatically included by the common_links.inc:
-.. _@aaronspring: https://github.com/aaronspring
-.. _@akuhnregnier: https://github.com/akuhnregnier
-.. _@bsherratt: https://github.com/bsherratt
-.. _@larsbarring: https://github.com/larsbarring
-.. _@pdearnshaw: https://github.com/pdearnshaw
-.. _@SimonPeatman: https://github.com/SimonPeatman
-.. _@tinyendian: https://github.com/tinyendian
+.. _@fnattino: https://github.com/fnattino
+.. _@ed-hawkins: https://github.com/ed-hawkins
.. comment
Whatsnew resources in alphabetical order:
-.. _NEP-29: https://numpy.org/neps/nep-0029-deprecation_policy.html
-.. _Metarelate: http://www.metarelate.net/
-.. _UGRID: http://ugrid-conventions.github.io/ugrid-conventions/
-.. _iris-emsf-regrid: https://github.com/SciTools-incubator/iris-esmf-regrid
-.. _faster documentation building: https://docs.readthedocs.io/en/stable/guides/conda.html#making-builds-faster-with-mamba
-.. _sort-all: https://github.com/aio-libs/sort-all
+.. _#ShowYourStripes: https://showyourstripes.info/s/globe/
+.. _README.md: https://github.com/SciTools/iris#-----
diff --git a/docs/src/whatsnew/latest.rst.template b/docs/src/whatsnew/latest.rst.template
index 79c578ca65..a0ce415a65 100644
--- a/docs/src/whatsnew/latest.rst.template
+++ b/docs/src/whatsnew/latest.rst.template
@@ -42,7 +42,7 @@ v3.X.X (DD MMM YYYY)
NOTE: section above is a template for bugfix patches
====================================================
(Please remove this section when creating an initial 'latest.rst')
-
+
📢 Announcements
@@ -109,4 +109,3 @@ NOTE: section above is a template for bugfix patches
.. comment
Whatsnew resources in alphabetical order:
-
diff --git a/docs/src/why_iris.rst b/docs/src/why_iris.rst
new file mode 100644
index 0000000000..82b791b4bd
--- /dev/null
+++ b/docs/src/why_iris.rst
@@ -0,0 +1,43 @@
+.. _why_iris:
+
+Why Iris
+========
+
+**A powerful, format-agnostic, community-driven Python package for analysing
+and visualising Earth science data.**
+
+Iris implements a data model based on the `CF conventions `_
+giving you a powerful, format-agnostic interface for working with your data.
+It excels when working with multi-dimensional Earth Science data, where tabular
+representations become unwieldy and inefficient.
+
+`CF Standard names `_,
+`units `_, and coordinate metadata
+are built into Iris, giving you a rich and expressive interface for maintaining
+an accurate representation of your data. Its treatment of data and
+associated metadata as first-class objects includes:
+
+.. rst-class:: squarelist
+
+* visualisation interface based on `matplotlib `_ and
+ `cartopy `_,
+* unit conversion,
+* subsetting and extraction,
+* merge and concatenate,
+* aggregations and reductions (including min, max, mean and weighted averages),
+* interpolation and regridding (including nearest-neighbor, linear and
+ area-weighted), and
+* operator overloads (``+``, ``-``, ``*``, ``/``, etc.).
+
+A number of file formats are recognised by Iris, including CF-compliant NetCDF,
+GRIB, and PP, and it has a plugin architecture to allow other formats to be
+added seamlessly.
+
+Building upon `NumPy `_ and
+`dask `_, Iris scales from efficient
+single-machine workflows right through to multi-core clusters and HPC.
+Interoperability with packages from the wider scientific Python ecosystem comes
+from Iris' use of standard NumPy/dask arrays as its underlying data storage.
+
+Iris is part of SciTools, for more information see https://scitools.org.uk/.
+For **Iris 2.4** and earlier documentation please see :ref:`iris_support`.
\ No newline at end of file
diff --git a/etc/cf-standard-name-table.xml b/etc/cf-standard-name-table.xml
index bd76168192..9c5fcd9cf0 100644
--- a/etc/cf-standard-name-table.xml
+++ b/etc/cf-standard-name-table.xml
@@ -1,7 +1,7 @@
- 78
- 2021-09-21T11:55:06Z
+ 79
+ 2022-03-19T15:25:54Z
Centre for Environmental Data Analysis
support@ceda.ac.uk
@@ -8014,6 +8014,20 @@
The phrase "magnitude_of_X" means magnitude of a vector X. The surface called "surface" means the lower boundary of the atmosphere. "Surface stress" means the shear stress (force per unit area) exerted by the wind at the surface. A downward stress is a downward flux of momentum. Over large bodies of water, wind stress can drive near-surface currents. "Downward" indicates a vector component which is positive when directed downward (negative upward).
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of 19’-butanoyloxyfucoxanthin is C46H64O8. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/BUTAXXXX/1/.
+
+
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of 19'-hexanoyloxyfucoxanthin is C48H68O8. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/HEXAXXXX/2/.
+
+
kg m-3
@@ -8028,6 +8042,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for aceto-nitrile is CH3CN. The IUPAC name for aceto-nitrile is ethanenitrile.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ATPXZZDZ/2/.
+
+
kg m-3
@@ -8042,6 +8063,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. Alkenes are unsaturated hydrocarbons as they contain chemical double bonds between adjacent carbon atoms. Alkenes contain only hydrogen and carbon combined in the general proportions C(n)H(2n); "alkenes" is the term used in standard names to describe the group of chemical species having this common structure that are represented within a given model. The list of individual species that are included in a quantity having a group chemical standard name can vary between models. Where possible, the data variable should be accompanied by a complete description of the species represented, for example, by using a comment attribute. Standard names exist for some individual alkene species, e.g., ethene and propene.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of alpha-carotene is C40H56. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/BECAXXP1/2/.
+
+
kg m-3
@@ -8112,6 +8140,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for benzene is C6H6. Benzene is the simplest aromatic hydrocarbon and has a ring structure consisting of six carbon atoms joined by alternating single and double chemical bonds. Each carbon atom is additionally bonded to one hydrogen atom. There are standard names that refer to aromatic_compounds as a group, as well as those for individual species.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of beta-carotene is C40H56. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/BBCAXXP1/2/.
+
+
kg m-3
@@ -8217,6 +8252,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula of carbon tetrachloride is CCl4. The IUPAC name for carbon tetrachloride is tetrachloromethane.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Carotene" refers to the sum of all forms of the carotenoid pigment carotene. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CAROXXXX/1/.
+
+
kg m-3
@@ -8287,6 +8329,41 @@
'Mass concentration' means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. Chlorophyll-a is the most commonly occurring form of natural chlorophyll. The chemical formula of chlorophyll-a is C55H72O5N4Mg.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CHLBXXPX/2/.
+
+
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. Chlorophyll c1c2 (sometimes written c1-c2 or c1+c2) means the sum of chlorophyll c1 and chlorophyll c2. The chemical formula of chlorophyll c1 is C35H30MgN4O5, and chlorophyll c2 is C35H28MgN4O5. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CHLC12PX/3/.
+
+
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. The chemical formula of chlorophyll c3 is C36H44MgN4O7. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CHLC03PX/2/.
+
+
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. Chlorophyll-c means chlorophyll c1+c2+c3. The chemical formula of chlorophyll c1 is C35H30MgN4O5, and chlorophyll c2 is C35H28MgN4O5. The chemical formula of chlorophyll c3 is C36H44MgN4O7.
+
+
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of chlorophyllide-a is C35H34MgN4O5.
+
+
kg m-3
@@ -8322,6 +8399,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. Condensed water means liquid and ice.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of diadinoxanthin is C40H54O3. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/DIADXXXX/2/.
+
+
kg m-3
@@ -8378,6 +8462,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for dinitrogen pentoxide is N2O5.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen".
+
+
kg m-3
@@ -8455,6 +8546,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for formic acid is HCOOH. The IUPAC name for formic acid is methanoic acid.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of fucoxanthin is C42H58O6. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/FUCXZZZZ/2/.
+
+
kg m-3
@@ -8637,6 +8735,13 @@
Mass concentration means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The mass concentration of liquid water takes into account all cloud droplets and liquid precipitation regardless of drop size or fall speed.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of lutein is C40H56O2.
+
+
kg m-3
@@ -8707,6 +8812,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for molecular hydrogen is H2.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen".
+
+
kg m-3
@@ -8833,6 +8945,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Aerosol" means the system of suspended liquid or solid particles in air (except cloud droplets) and their carrier gas, the air itself. Aerosol takes up ambient water (a process known as hygroscopic growth) depending on the relative humidity and the composition of the aerosol. "Dry aerosol particles" means aerosol particles without any water uptake. The term "particulate_organic_matter_dry_aerosol" means all particulate organic matter dry aerosol except elemental carbon. It is the sum of primary_particulate_organic_matter_dry_aerosol and secondary_particulate_organic_matter_dry_aerosol.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/PERDXXXX/2/.
+
+
kg m-3
@@ -8861,6 +8980,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. It means the ratio of the mass of X to the mass of Y (including X). A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Petroleum hydrocarbons are compounds containing just carbon and hydrogen originating from the fossil fuel crude oil.
+
+ kg m-3
+
+
+ Concentration of phaeopigment per unit volume of the water body, where the filtration size or collection method is unspecified (equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/. "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Phaeopigments are a group of non-photosynthetic pigments that are the degradation product of algal chlorophyll pigments. Phaeopigments contain phaeophytin, which fluoresces in response to excitation light, and phaeophorbide, which is colorless and does not fluoresce (source: https://academic.oup.com/plankt/article/24/11/1221/1505482). Phaeopigment concentration commonly increases during the development phase of marine phytoplankton blooms, and declines in the post bloom stage (source: https://www.sciencedirect.com/science/article/pii/0967063793901018).
+
+
kg m-3
@@ -8931,6 +9057,13 @@
Mass concentration means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Aerosol" means the system of suspended liquid or solid particles in air (except cloud droplets) and their carrier gas, the air itself. Aerosol particles take up ambient water (a process known as hygroscopic growth) depending on the relative humidity and the composition of the particles. "Dry aerosol particles" means aerosol particles without any water uptake. "Pm2p5 aerosol" means atmospheric particulate compounds with an aerodynamic diameter of less than or equal to 2.5 micrometers.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of prasinoxanthin is C40H56O4. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/PXAPXXXX/2/.
+
+
kg m-3
@@ -9036,6 +9169,13 @@
"Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula for toluene is C6H5CH3. Toluene has the same structure as benzene, except that one of the hydrogen atoms is replaced by a methyl group. The IUPAC name for toluene is methylbenzene.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of violaxanthin is C40H56O4.
+
+
kg m-3
@@ -9064,6 +9204,13 @@
Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for xylene is C6H4C2H6. In chemistry, xylene is a generic term for a group of three isomers of dimethylbenzene. The IUPAC names for the isomers are 1,2-dimethylbenzene, 1,3-dimethylbenzene and 1,4-dimethylbenzene. Xylene is an aromatic hydrocarbon. There are standard names that refer to aromatic_compounds as a group, as well as those for individual species.
+
+ kg m-3
+
+
+ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of zeaxanthin is C40H56O2. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ZEAXXXXX/2/.
+
+
kg m-3
@@ -10737,6 +10884,13 @@
Mole concentration means number of moles per unit volume, also called "molarity", and is used in the construction mole_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for aceto-nitrile is CH3CN. The IUPAC name for aceto-nitrile is ethanenitrile.
+
+ mol m-3
+
+
+ "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ATPXZZDZ/2/.
+
+
mol m-3
@@ -11185,6 +11339,13 @@
Mole concentration means number of moles per unit volume, also called "molarity", and is used in the construction mole_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The concentration of any chemical species, whether particulate or dissolved, may vary with depth in the ocean. A depth profile may go through one or more local minima in concentration. The mole_concentration_of_molecular_oxygen_in_sea_water_at_shallowest_local_minimum_in_vertical_profile is the mole concentration of oxygen at the local minimum in the concentration profile that occurs closest to the sea surface. The chemical formula for molecular oxygen is O2.
+
+ mol m-3
+
+
+ "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Dissolved nitrogen" means the sum of all nitrogen in solution: inorganic nitrogen (nitrite, nitrate and ammonium) plus nitrogen in carbon compounds.
+
+
mol m-3
@@ -11199,6 +11360,20 @@
"Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Dissolved organic nitrogen" describes the nitrogen held in carbon compounds in solution. These are mostly generated by plankton excretion and decay.
+
+ mol m-3
+
+
+ "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Organic phosphorus" means phosphorus in carbon compounds. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ORGPDSZZ/4/.
+
+
+
+ mol m-3
+
+
+ "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Phosphorus means phosphorus in all chemical forms, commonly referred to as "total phosphorus". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/TPHSDSZZ/6/.
+
+
mol m-3
@@ -11626,6 +11801,13 @@
Mole concentration means number of moles per unit volume, also called "molarity", and is used in the construction mole_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for ozone is O3.
+
+ mol m-3
+
+
+ "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The phrase "expressed_as" is used in the construction "A_expressed_as_B", where B is a chemical constituent of A. It means that the quantity indicated by the standard name is calculated solely with respect to the B contained in A, neglecting all other chemical constituents of A.
+
+
mol m-3
@@ -18595,21 +18777,21 @@
Pa
- "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xx" indicates the component of the tensor along the grid x_ axis.
+ "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xx" indicates the component of the tensor along the grid x_ axis.
Pa
- "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xy" indicates the lateral contributions to x_ and y_ components of the tensor.
+ "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xy" indicates the lateral contributions to x_ and y_ components of the tensor.
Pa
- "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "yy" indicates the component of the tensor along the grid y_ axis.
+ "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "yy" indicates the component of the tensor along the grid y_ axis.
@@ -31472,16 +31654,12 @@
-
- biological_taxon_lsid
-
-
temperature_in_ground
-
- surface_snow_density
+
+ biological_taxon_lsid
@@ -31516,14 +31694,18 @@
tendency_of_atmosphere_mass_content_of_water_vapor_due_to_sublimation_of_surface_snow_and_ice
-
- atmosphere_upward_absolute_vorticity
+
+ surface_snow_density
atmosphere_upward_relative_vorticity
+
+ atmosphere_upward_absolute_vorticity
+
+
area_type
@@ -31532,34 +31714,46 @@
area_type
-
- iron_growth_limitation_of_diazotrophic_phytoplankton
+
+ mass_fraction_of_liquid_precipitation_in_air
-
- growth_limitation_of_diazotrophic_phytoplankton_due_to_solar_irradiance
+
+ mass_fraction_of_liquid_precipitation_in_air
tendency_of_mole_concentration_of_particulate_organic_matter_expressed_as_carbon_in_sea_water_due_to_net_primary_production_by_diazotrophic_phytoplankton
-
- mole_concentration_of_diazotrophic_phytoplankton_expressed_as_carbon_in_sea_water
+
+ nitrogen_growth_limitation_of_diazotrophic_phytoplankton
-
- mass_fraction_of_liquid_precipitation_in_air
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton
-
- mass_fraction_of_liquid_precipitation_in_air
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton
+
+
+
+ mole_concentration_of_diazotrophic_phytoplankton_expressed_as_carbon_in_sea_water
mass_concentration_of_diazotrophic_phytoplankton_expressed_as_chlorophyll_in_sea_water
+
+ iron_growth_limitation_of_diazotrophic_phytoplankton
+
+
+
+ growth_limitation_of_diazotrophic_phytoplankton_due_to_solar_irradiance
+
+
air_pseudo_equivalent_potential_temperature
@@ -31576,64 +31770,300 @@
tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_riming_from_cloud_liquid_water
-
- nitrogen_growth_limitation_of_diazotrophic_phytoplankton
+
+ sea_water_velocity_from_direction
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton
+
+ sea_water_velocity_to_direction
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton
+
+ sea_water_velocity_to_direction
-
- air_pseudo_equivalent_temperature
+
+ integral_wrt_depth_of_product_of_salinity_and_sea_water_density
-
- air_equivalent_temperature
+
+ integral_wrt_depth_of_product_of_conservative_temperature_and_sea_water_density
-
- atmosphere_mass_content_of_convective_cloud_liquid_water
+
+ integral_wrt_depth_of_product_of_potential_temperature_and_sea_water_density
-
- effective_radius_of_cloud_liquid_water_particles_at_liquid_water_cloud_top
+
+ volume_fraction_of_condensed_water_in_soil_at_wilting_point
-
- northward_heat_flux_in_air_due_to_eddy_advection
+
+ volume_fraction_of_condensed_water_in_soil_at_field_capacity
-
- northward_eliassen_palm_flux_in_air
+
+ volume_fraction_of_condensed_water_in_soil_at_critical_point
-
- net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_wood
+
+ volume_fraction_of_condensed_water_in_soil
-
- net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_leaves
+
+ product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity
-
- net_primary_productivity_of_biomass_expressed_as_carbon
+
+ product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity
-
- mole_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
+
+ product_of_lagrangian_tendency_of_air_pressure_and_geopotential_height
-
- mole_concentration_of_microzooplankton_expressed_as_nitrogen_in_sea_water
+
+ product_of_lagrangian_tendency_of_air_pressure_and_air_temperature
-
- mole_concentration_of_mesozooplankton_expressed_as_nitrogen_in_sea_water
+
+ product_of_lagrangian_tendency_of_air_pressure_and_air_temperature
+
+
+
+ tendency_of_sea_water_salinity_expressed_as_salt_content_due_to_parameterized_dianeutral_mixing
+
+
+
+ tendency_of_sea_water_potential_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing
+
+
+
+ tendency_of_sea_water_conservative_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing
+
+
+
+ effective_radius_of_stratiform_cloud_snow_particles
+
+
+
+ tendency_of_atmosphere_moles_of_cfc11
+
+
+
+ moles_of_cfc11_per_unit_mass_in_sea_water
+
+
+
+ atmosphere_moles_of_cfc11
+
+
+
+ tendency_of_atmosphere_moles_of_cfc113
+
+
+
+ atmosphere_moles_of_cfc113
+
+
+
+ tendency_of_atmosphere_moles_of_cfc114
+
+
+
+ atmosphere_moles_of_cfc114
+
+
+
+ tendency_of_atmosphere_moles_of_cfc115
+
+
+
+ atmosphere_moles_of_cfc115
+
+
+
+ tendency_of_atmosphere_moles_of_cfc12
+
+
+
+ atmosphere_moles_of_cfc12
+
+
+
+ tendency_of_atmosphere_moles_of_halon1202
+
+
+
+ atmosphere_moles_of_halon1202
+
+
+
+ tendency_of_atmosphere_moles_of_halon1211
+
+
+
+ atmosphere_moles_of_halon1211
+
+
+
+ tendency_of_atmosphere_moles_of_halon1301
+
+
+
+ atmosphere_moles_of_halon1301
+
+
+
+ tendency_of_atmosphere_moles_of_halon2402
+
+
+
+ atmosphere_moles_of_halon2402
+
+
+
+ tendency_of_atmosphere_moles_of_hcc140a
+
+
+
+ atmosphere_moles_of_hcc140a
+
+
+
+ tendency_of_troposphere_moles_of_hcc140a
+
+
+
+ tendency_of_middle_atmosphere_moles_of_hcc140a
+
+
+
+ tendency_of_troposphere_moles_of_hcfc22
+
+
+
+ tendency_of_atmosphere_moles_of_hcfc22
+
+
+
+ atmosphere_moles_of_hcfc22
+
+
+
+ tendency_of_atmosphere_number_content_of_aerosol_particles_due_to_turbulent_deposition
+
+
+
+ lagrangian_tendency_of_atmosphere_sigma_coordinate
+
+
+
+ lagrangian_tendency_of_atmosphere_sigma_coordinate
+
+
+
+ electrical_mobility_diameter_of_ambient_aerosol_particles
+
+
+
+ diameter_of_ambient_aerosol_particles
+
+
+
+ mass_concentration_of_biomass_burning_dry_aerosol_particles_in_air
+
+
+
+ effective_radius_of_stratiform_cloud_rain_particles
+
+
+
+ effective_radius_of_stratiform_cloud_ice_particles
+
+
+
+ effective_radius_of_stratiform_cloud_graupel_particles
+
+
+
+ effective_radius_of_convective_cloud_snow_particles
+
+
+
+ effective_radius_of_convective_cloud_rain_particles
+
+
+
+ effective_radius_of_convective_cloud_ice_particles
+
+
+
+ histogram_of_backscattering_ratio_in_air_over_height_above_reference_ellipsoid
+
+
+
+ backscattering_ratio_in_air
+
+
+
+ product_of_northward_wind_and_lagrangian_tendency_of_air_pressure
+
+
+
+ product_of_eastward_wind_and_lagrangian_tendency_of_air_pressure
+
+
+
+ carbon_mass_flux_into_litter_and_soil_due_to_anthropogenic_land_use_or_land_cover_change
+
+
+
+ floating_ice_shelf_area_fraction
+
+
+
+ atmosphere_moles_of_carbon_tetrachloride
+
+
+
+ mole_fraction_of_methylglyoxal_in_air
+
+
+
+ mole_fraction_of_dichlorine_peroxide_in_air
+
+
+
+ atmosphere_mass_content_of_convective_cloud_liquid_water
+
+
+
+ effective_radius_of_cloud_liquid_water_particles_at_liquid_water_cloud_top
+
+
+
+ air_equivalent_temperature
+
+
+
+ air_pseudo_equivalent_temperature
+
+
+
+ mass_content_of_cloud_liquid_water_in_atmosphere_layer
+
+
+
+ air_equivalent_potential_temperature
+
+
+
+ number_concentration_of_stratiform_cloud_liquid_water_particles_at_stratiform_liquid_water_cloud_top
+
+
+
+ number_concentration_of_convective_cloud_liquid_water_particles_at_convective_liquid_water_cloud_top
@@ -31660,360 +32090,104 @@
atmosphere_mass_content_of_cloud_liquid_water
-
- mass_fraction_of_sulfate_dry_aerosol_particles_in_air
-
-
-
- mass_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
-
-
-
- mass_fraction_of_ammonium_dry_aerosol_particles_in_air
-
-
-
- tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_shallow_convection
-
-
-
- tendency_of_mass_content_of_water_vapor_in_atmosphere_layer
-
-
-
- mass_content_of_cloud_ice_in_atmosphere_layer
-
-
-
- mass_concentration_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air
-
-
-
- mass_concentration_of_mercury_dry_aerosol_particles_in_air
-
-
-
- mass_concentration_of_coarse_mode_ambient_aerosol_particles_in_air
-
-
-
- sea_water_velocity_to_direction
-
-
-
- sea_water_velocity_to_direction
-
-
-
- gross_primary_productivity_of_biomass_expressed_as_carbon
-
-
-
- eastward_water_vapor_flux_in_air
-
-
-
- atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles
-
-
-
- tendency_of_middle_atmosphere_moles_of_carbon_monoxide
-
-
-
- tendency_of_atmosphere_mass_content_of_water_vapor_due_to_advection
-
-
-
- tendency_of_atmosphere_mass_content_of_water_vapor
-
-
-
- lwe_thickness_of_atmosphere_mass_content_of_water_vapor
-
-
-
- change_over_time_in_atmosphere_mass_content_of_water_due_to_advection
-
-
-
- change_over_time_in_atmosphere_mass_content_of_water_due_to_advection
-
-
-
- atmosphere_mass_content_of_water_vapor
-
-
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_gravitational_settling
-
-
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_gravitational_settling
-
-
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_dry_deposition
-
-
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_dry_deposition
-
-
-
- tendency_of_middle_atmosphere_moles_of_methyl_bromide
-
-
-
- atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur
-
-
-
- atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur
-
-
-
- atmosphere_mass_content_of_sulfate
-
-
-
- atmosphere_mass_content_of_sulfate
-
-
-
- tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition
-
-
-
- tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production
-
-
-
- tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production
-
-
-
- tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition
-
-
-
- atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles
-
-
-
- tendency_of_atmosphere_mass_content_of_water_vapor_due_to_deep_convection
-
-
-
- tendency_of_atmosphere_mass_content_of_water_vapor_due_to_convection
-
-
-
- atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles
-
-
-
- mass_content_of_cloud_liquid_water_in_atmosphere_layer
-
-
-
- air_equivalent_potential_temperature
-
-
-
- number_concentration_of_stratiform_cloud_liquid_water_particles_at_stratiform_liquid_water_cloud_top
-
-
-
- number_concentration_of_convective_cloud_liquid_water_particles_at_convective_liquid_water_cloud_top
-
-
-
- wave_frequency
-
-
-
- upward_eastward_momentum_flux_in_air_due_to_nonorographic_eastward_gravity_waves
-
-
-
- tendency_of_troposphere_moles_of_carbon_monoxide
-
-
-
- tendency_of_atmosphere_moles_of_sulfate_dry_aerosol_particles
-
-
-
- tendency_of_atmosphere_mass_content_of_nitrate_dry_aerosol_particles_due_to_dry_deposition
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_waste_treatment_and_disposal
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_savanna_and_grassland_fires
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_maritime_transport
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_land_transport
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_forest_fires
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_agricultural_waste_burning
-
-
-
- tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_turbulent_deposition
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production_and_emission
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production_and_emission
-
-
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_gravitational_settling
+
+ mole_fraction_of_noy_expressed_as_nitrogen_in_air
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition
+
+ tendency_of_atmosphere_moles_of_methane
-
- atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles
+
+ rate_of_hydroxyl_radical_destruction_due_to_reaction_with_nmvoc
-
- integral_wrt_depth_of_product_of_conservative_temperature_and_sea_water_density
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_miscellaneous_phytoplankton
-
- integral_wrt_depth_of_product_of_salinity_and_sea_water_density
+
+ mole_fraction_of_inorganic_bromine_in_air
-
- tendency_of_atmosphere_moles_of_methyl_bromide
+
+ water_vapor_saturation_deficit_in_air
-
- integral_wrt_depth_of_product_of_potential_temperature_and_sea_water_density
+
+ tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_agricultural_waste_burning
-
- atmosphere_moles_of_methyl_bromide
+
+ tendency_of_atmosphere_moles_of_carbon_tetrachloride
-
- product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity
+
+ tendency_of_atmosphere_moles_of_carbon_monoxide
-
- product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity
+
+ platform_yaw
-
- tendency_of_sea_water_potential_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing
+
+ platform_pitch
-
- tendency_of_sea_water_conservative_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing
+
+ platform_roll
-
- volume_fraction_of_condensed_water_in_soil_at_wilting_point
+
+ tendency_of_specific_humidity_due_to_stratiform_precipitation
-
- volume_fraction_of_condensed_water_in_soil_at_field_capacity
+
+ tendency_of_air_temperature_due_to_stratiform_precipitation
-
- volume_fraction_of_condensed_water_in_soil_at_critical_point
+
+ stratiform_precipitation_flux
-
- volume_fraction_of_condensed_water_in_soil
+
+ stratiform_precipitation_amount
-
- product_of_lagrangian_tendency_of_air_pressure_and_geopotential_height
+
+ lwe_thickness_of_stratiform_precipitation_amount
-
- product_of_lagrangian_tendency_of_air_pressure_and_air_temperature
+
+ lwe_stratiform_precipitation_rate
-
- product_of_lagrangian_tendency_of_air_pressure_and_air_temperature
+
+ water_evaporation_amount_from_canopy
-
- tendency_of_sea_water_salinity_expressed_as_salt_content_due_to_parameterized_dianeutral_mixing
+
+ water_evaporation_flux_from_canopy
-
- atmosphere_moles_of_methane
+
+ precipitation_flux_onto_canopy
-
- electrical_mobility_diameter_of_ambient_aerosol_particles
+
+ outgoing_water_volume_transport_along_river_channel
-
- histogram_of_backscattering_ratio_in_air_over_height_above_reference_ellipsoid
+
+ tendency_of_sea_ice_amount_due_to_conversion_of_snow_to_sea_ice
tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_emission
-
- effective_radius_of_stratiform_cloud_snow_particles
-
-
-
- mass_concentration_of_biomass_burning_dry_aerosol_particles_in_air
-
-
-
- atmosphere_mass_content_of_nitric_acid_trihydrate_ambient_aerosol_particles
-
-
-
- atmosphere_mass_content_of_nitrate_dry_aerosol_particles
-
-
-
- atmosphere_mass_content_of_mercury_dry_aerosol_particles
-
-
-
- backscattering_ratio_in_air
-
-
-
- product_of_northward_wind_and_lagrangian_tendency_of_air_pressure
+
+ mass_fraction_of_mercury_dry_aerosol_particles_in_air
@@ -32024,256 +32198,224 @@
tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_wet_deposition
-
- tendency_of_atmosphere_moles_of_cfc11
-
-
-
- moles_of_cfc11_per_unit_mass_in_sea_water
-
-
-
- atmosphere_moles_of_cfc11
-
-
-
- tendency_of_atmosphere_moles_of_hcc140a
-
-
-
- effective_radius_of_convective_cloud_rain_particles
-
-
-
- tendency_of_troposphere_moles_of_hcc140a
-
-
-
- tendency_of_middle_atmosphere_moles_of_hcc140a
-
-
-
- tendency_of_troposphere_moles_of_hcfc22
-
-
-
- tendency_of_atmosphere_moles_of_hcfc22
+
+ stratiform_cloud_area_fraction
-
- atmosphere_moles_of_hcfc22
+
+ magnitude_of_sea_ice_displacement
-
- tendency_of_atmosphere_number_content_of_aerosol_particles_due_to_turbulent_deposition
+
+ surface_downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water
-
- lagrangian_tendency_of_atmosphere_sigma_coordinate
+
+ surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
-
- lagrangian_tendency_of_atmosphere_sigma_coordinate
+
+ surface_downwelling_shortwave_flux_in_air_assuming_clear_sky
-
- diameter_of_ambient_aerosol_particles
+
+ surface_downwelling_shortwave_flux_in_air
-
- effective_radius_of_stratiform_cloud_ice_particles
+
+ surface_downwelling_radiative_flux_per_unit_wavelength_in_sea_water
-
- effective_radius_of_convective_cloud_ice_particles
+
+ surface_downwelling_radiative_flux_per_unit_wavelength_in_air
-
- effective_radius_of_stratiform_cloud_graupel_particles
+
+ surface_downwelling_radiance_per_unit_wavelength_in_sea_water
-
- effective_radius_of_stratiform_cloud_rain_particles
+
+ surface_downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
-
- effective_radius_of_convective_cloud_snow_particles
+
+ surface_downwelling_photon_radiance_per_unit_wavelength_in_sea_water
-
- product_of_eastward_wind_and_lagrangian_tendency_of_air_pressure
+
+ surface_downwelling_photon_flux_per_unit_wavelength_in_sea_water
-
- carbon_mass_flux_into_litter_and_soil_due_to_anthropogenic_land_use_or_land_cover_change
+
+ surface_downwelling_longwave_flux_in_air
-
- stratiform_cloud_area_fraction
+
+ integral_wrt_time_of_surface_downwelling_shortwave_flux_in_air
-
- sea_water_velocity_from_direction
+
+ integral_wrt_time_of_surface_downwelling_longwave_flux_in_air
-
- thickness_of_stratiform_snowfall_amount
+
+ downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water
-
- optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles
+
+ downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
-
- optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles
+
+ downwelling_radiative_flux_per_unit_wavelength_in_sea_water
-
- lwe_thickness_of_stratiform_snowfall_amount
+
+ downwelling_radiative_flux_per_unit_wavelength_in_air
-
- equivalent_thickness_at_stp_of_atmosphere_ozone_content
+
+ downwelling_radiance_per_unit_wavelength_in_sea_water
-
- atmosphere_optical_thickness_due_to_water_in_ambient_aerosol_particles
+
+ downwelling_radiance_per_unit_wavelength_in_air
-
- atmosphere_optical_thickness_due_to_dust_dry_aerosol_particles
+
+ downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
-
- atmosphere_optical_thickness_due_to_dust_ambient_aerosol_particles
+
+ downwelling_photon_radiance_per_unit_wavelength_in_sea_water
-
- atmosphere_optical_thickness_due_to_ambient_aerosol_particles
+
+ downwelling_photon_flux_per_unit_wavelength_in_sea_water
-
- atmosphere_optical_thickness_due_to_ambient_aerosol_particles
+
+ surface_upwelling_shortwave_flux_in_air_assuming_clear_sky
-
- atmosphere_net_upward_convective_mass_flux
+
+ surface_upwelling_longwave_flux_in_air_assuming_clear_sky
-
- mass_fraction_of_mercury_dry_aerosol_particles_in_air
+
+ upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
-
- atmosphere_moles_of_hcc140a
+
+ upwelling_radiative_flux_per_unit_wavelength_in_sea_water
-
- floating_ice_shelf_area_fraction
+
+ upwelling_radiative_flux_per_unit_wavelength_in_air
-
- atmosphere_moles_of_carbon_tetrachloride
+
+ upwelling_radiance_per_unit_wavelength_in_air
-
- mole_fraction_of_methylglyoxal_in_air
+
+ surface_upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
-
- mole_fraction_of_dichlorine_peroxide_in_air
+
+ surface_upwelling_shortwave_flux_in_air
-
- mole_fraction_of_noy_expressed_as_nitrogen_in_air
+
+ surface_upwelling_radiative_flux_per_unit_wavelength_in_sea_water
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_miscellaneous_phytoplankton
+
+ surface_upwelling_radiative_flux_per_unit_wavelength_in_air
-
- mole_fraction_of_inorganic_bromine_in_air
+
+ surface_upwelling_radiance_per_unit_wavelength_in_sea_water
-
- water_vapor_saturation_deficit_in_air
+
+ volume_scattering_coefficient_of_radiative_flux_in_air_due_to_ambient_aerosol_particles
-
- tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_agricultural_waste_burning
+
+ volume_scattering_coefficient_of_radiative_flux_in_air_due_to_dried_aerosol_particles
-
- tendency_of_atmosphere_moles_of_carbon_tetrachloride
+
+ soil_mass_content_of_carbon
-
- tendency_of_atmosphere_moles_of_carbon_monoxide
+
+ slow_soil_pool_mass_content_of_carbon
-
- tendency_of_atmosphere_moles_of_cfc113
+
+ root_mass_content_of_carbon
-
- atmosphere_moles_of_cfc113
+
+ miscellaneous_living_matter_mass_content_of_carbon
-
- tendency_of_atmosphere_moles_of_cfc114
+
+ fast_soil_pool_mass_content_of_carbon
-
- atmosphere_moles_of_cfc114
+
+ medium_soil_pool_mass_content_of_carbon
-
- tendency_of_atmosphere_moles_of_cfc115
+
+ leaf_mass_content_of_carbon
-
- atmosphere_moles_of_cfc115
+
+ carbon_mass_content_of_forestry_and_agricultural_products
-
- tendency_of_atmosphere_moles_of_cfc12
+
+ carbon_mass_content_of_forestry_and_agricultural_products
-
- atmosphere_moles_of_cfc12
+
+ surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration_for_biomass_maintenance
-
- tendency_of_atmosphere_moles_of_halon1202
+
+ surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration_for_biomass_growth
-
- atmosphere_moles_of_halon1202
+
+ surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration
-
- tendency_of_atmosphere_moles_of_halon1211
+
+ surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_respiration_in_soil
-
- atmosphere_moles_of_halon1211
+
+ surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_heterotrophic_respiration
-
- tendency_of_atmosphere_moles_of_halon1301
+
+ northward_transformed_eulerian_mean_air_velocity
-
- atmosphere_moles_of_halon1301
+
+ eastward_transformed_eulerian_mean_air_velocity
-
- tendency_of_atmosphere_moles_of_halon2402
+
+ surface_litter_mass_content_of_carbon
-
- atmosphere_moles_of_halon2402
+
+ litter_mass_content_of_carbon
@@ -32308,14 +32450,14 @@
mole_concentration_of_diatoms_expressed_as_nitrogen_in_sea_water
-
- tendency_of_mole_concentration_of_dissolved_inorganic_phosphorus_in_sea_water_due_to_biological_processes
-
-
tendency_of_mole_concentration_of_dissolved_inorganic_silicon_in_sea_water_due_to_biological_processes
+
+ tendency_of_mole_concentration_of_dissolved_inorganic_phosphorus_in_sea_water_due_to_biological_processes
+
+
tendency_of_atmosphere_mole_concentration_of_carbon_monoxide_due_to_chemical_destruction
@@ -32324,56 +32466,64 @@
volume_extinction_coefficient_in_air_due_to_ambient_aerosol_particles
-
- atmosphere_mass_content_of_convective_cloud_condensed_water
+
+ water_vapor_partial_pressure_in_air
-
- water_evaporation_flux_from_canopy
+
+ platform_name
-
- precipitation_flux_onto_canopy
+
+ platform_id
-
- surface_downwelling_shortwave_flux_in_air_assuming_clear_sky
+
+ mass_flux_of_carbon_into_litter_from_vegetation
-
- surface_downwelling_radiance_per_unit_wavelength_in_sea_water
+
+ subsurface_litter_mass_content_of_carbon
-
- upwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+ stem_mass_content_of_carbon
-
- downwelling_photon_flux_per_unit_wavelength_in_sea_water
+
+ mole_concentration_of_dissolved_inorganic_14C_in_sea_water
-
- downwelling_radiance_per_unit_wavelength_in_sea_water
+
+ surface_downward_mass_flux_of_14C_dioxide_abiotic_analogue_expressed_as_carbon
-
- surface_downwelling_photon_radiance_per_unit_wavelength_in_sea_water
+
+ surface_downward_mass_flux_of_13C_dioxide_abiotic_analogue_expressed_as_13C
-
- surface_downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ mole_concentration_of_dissolved_inorganic_13C_in_sea_water
-
- surface_upwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+ surface_upwelling_radiance_per_unit_wavelength_in_air_reflected_by_sea_water
-
- surface_downwelling_shortwave_flux_in_air
+
+ surface_upwelling_radiance_per_unit_wavelength_in_air_emerging_from_sea_water
-
- tendency_of_sea_ice_amount_due_to_conversion_of_snow_to_sea_ice
+
+ surface_upwelling_radiance_per_unit_wavelength_in_air
+
+
+
+ surface_upwelling_longwave_flux_in_air
+
+
+
+ incoming_water_volume_transport_along_river_channel
@@ -32392,792 +32542,820 @@
sea_ice_temperature_expressed_as_heat_content
-
- outgoing_water_volume_transport_along_river_channel
+
+ water_evapotranspiration_flux
-
- lwe_thickness_of_stratiform_precipitation_amount
+
+ surface_water_evaporation_flux
-
- tendency_of_atmosphere_moles_of_methane
+
+ water_volume_transport_into_sea_water_from_rivers
-
- rate_of_hydroxyl_radical_destruction_due_to_reaction_with_nmvoc
+
+ stratiform_graupel_flux
-
- magnitude_of_sea_ice_displacement
+
+ wood_debris_mass_content_of_carbon
-
- surface_downwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+ toa_outgoing_shortwave_flux_assuming_clear_sky_and_no_aerosol
-
- surface_downwelling_radiative_flux_per_unit_wavelength_in_air
+
+ water_flux_into_sea_water_from_rivers
-
- surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+ integral_wrt_height_of_product_of_northward_wind_and_specific_humidity
-
- surface_downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ integral_wrt_height_of_product_of_eastward_wind_and_specific_humidity
-
- surface_downwelling_photon_flux_per_unit_wavelength_in_sea_water
+
+ integral_wrt_depth_of_sea_water_temperature
-
- surface_downwelling_longwave_flux_in_air
+
+ integral_wrt_depth_of_sea_water_temperature
-
- integral_wrt_time_of_surface_downwelling_shortwave_flux_in_air
+
+ integral_wrt_depth_of_sea_water_temperature
-
- integral_wrt_time_of_surface_downwelling_longwave_flux_in_air
+
+ integral_wrt_depth_of_sea_water_temperature
-
- downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ integral_wrt_depth_of_sea_water_practical_salinity
-
- downwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+ northward_ocean_heat_transport_due_to_parameterized_eddy_advection
-
- downwelling_radiative_flux_per_unit_wavelength_in_air
+
+ tendency_of_ocean_eddy_kinetic_energy_content_due_to_parameterized_eddy_advection
-
- downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+ ocean_tracer_laplacian_diffusivity_due_to_parameterized_mesoscale_eddy_advection
-
- downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ ocean_tracer_biharmonic_diffusivity_due_to_parameterized_mesoscale_eddy_advection
-
- downwelling_radiance_per_unit_wavelength_in_air
+
+ upward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
-
- downwelling_photon_radiance_per_unit_wavelength_in_sea_water
+
+ sea_water_y_velocity_due_to_parameterized_mesoscale_eddies
-
- surface_upwelling_shortwave_flux_in_air_assuming_clear_sky
+
+ sea_water_x_velocity_due_to_parameterized_mesoscale_eddies
-
- surface_upwelling_longwave_flux_in_air_assuming_clear_sky
+
+ eastward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
-
- upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+ northward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
-
- upwelling_radiative_flux_per_unit_wavelength_in_air
+
+ tendency_of_sea_water_temperature_due_to_parameterized_eddy_advection
-
- upwelling_radiance_per_unit_wavelength_in_air
+
+ tendency_of_sea_water_salinity_due_to_parameterized_eddy_advection
-
- surface_upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+ ocean_y_overturning_mass_streamfunction_due_to_parameterized_eddy_advection
-
- surface_upwelling_shortwave_flux_in_air
+
+ ocean_meridional_overturning_mass_streamfunction_due_to_parameterized_eddy_advection
-
- surface_upwelling_radiance_per_unit_wavelength_in_sea_water
+
+ ocean_mass_y_transport_due_to_advection_and_parameterized_eddy_advection
-
- incoming_water_volume_transport_along_river_channel
+
+ | |