diff --git a/.cirrus.yml b/.cirrus.yml
index b3992de64a4..c9c1d718596 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -38,7 +38,7 @@ env:
# Conda packages to be installed.
CONDA_CACHE_PACKAGES: "nox pip"
# Git commit hash for iris test data.
- IRIS_TEST_DATA_VERSION: "2.5"
+ IRIS_TEST_DATA_VERSION: "2.7"
# Base directory for the iris-test-data.
IRIS_TEST_DATA_DIR: ${HOME}/iris-test-data
@@ -60,7 +60,6 @@ linux_task_template: &LINUX_TASK_TEMPLATE
- echo "$(date +%Y).$(expr $(date +%U) / ${CACHE_PERIOD}):${CONDA_CACHE_BUILD}"
- uname -r
populate_script:
- - export CONDA_OVERRIDE_LINUX="$(uname -r | cut -d'+' -f1)"
- bash miniconda.sh -b -p ${HOME}/miniconda
- conda config --set always_yes yes --set changeps1 no
- conda config --set show_channel_urls True
@@ -141,8 +140,6 @@ task:
only_if: ${SKIP_TEST_TASK} == ""
<< : *CREDITS_TEMPLATE
matrix:
- env:
- PY_VER: 3.7
env:
PY_VER: 3.8
name: "${CIRRUS_OS}: py${PY_VER} tests"
@@ -153,7 +150,6 @@ task:
<< : *IRIS_TEST_DATA_TEMPLATE
<< : *LINUX_TASK_TEMPLATE
tests_script:
- - export CONDA_OVERRIDE_LINUX="$(uname -r | cut -d'+' -f1)"
- echo "[Resources]" > ${SITE_CFG}
- echo "test_data_dir = ${IRIS_TEST_DATA_DIR}/test_data" >> ${SITE_CFG}
- echo "doc_dir = ${CIRRUS_WORKING_DIR}/docs" >> ${SITE_CFG}
@@ -174,7 +170,6 @@ task:
<< : *IRIS_TEST_DATA_TEMPLATE
<< : *LINUX_TASK_TEMPLATE
tests_script:
- - export CONDA_OVERRIDE_LINUX="$(uname -r | cut -d'+' -f1)"
- echo "[Resources]" > ${SITE_CFG}
- echo "test_data_dir = ${IRIS_TEST_DATA_DIR}/test_data" >> ${SITE_CFG}
- echo "doc_dir = ${CIRRUS_WORKING_DIR}/docs" >> ${SITE_CFG}
@@ -197,7 +192,6 @@ task:
name: "${CIRRUS_OS}: py${PY_VER} link check"
<< : *LINUX_TASK_TEMPLATE
tests_script:
- - export CONDA_OVERRIDE_LINUX="$(uname -r | cut -d'+' -f1)"
- mkdir -p ${MPL_RC_DIR}
- echo "backend : agg" > ${MPL_RC_FILE}
- echo "image.cmap : viridis" >> ${MPL_RC_FILE}
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000000..e9b45d116af
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,15 @@
+# Reference:
+# - https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/keeping-your-actions-up-to-date-with-dependabot
+# - https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ # Check for updates to GitHub Actions every weekday
+ interval: "daily"
+ labels:
+ - "New: Pull Request"
+ - "Bot"
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index b489eba0360..d4c01af48a0 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -1,10 +1,11 @@
-# This is a basic workflow to help you get started with Actions
+# Use ASV to check for performance regressions in the last 24 hours' commits.
name: benchmark-check
on:
- # Triggers the workflow on push or pull request events but only for the master branch
- pull_request:
+ schedule:
+ # Runs every day at 23:00.
+ - cron: "0 23 * * *"
jobs:
benchmark:
@@ -16,35 +17,29 @@ jobs:
IRIS_TEST_DATA_PATH: benchmarks/iris-test-data
IRIS_TEST_DATA_VERSION: "2.5"
# Lets us manually bump the cache to rebuild
+ ENV_CACHE_BUILD: "0"
TEST_DATA_CACHE_BUILD: "2"
+ PY_VER: 3.8
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
-
- - name: Fetch the PR base branch too
- run: |
- git fetch --depth=1 origin ${{ github.event.pull_request.base.ref }}
- git branch _base FETCH_HEAD
- echo PR_BASE_SHA=$(git rev-parse _base) >> $GITHUB_ENV
+ with:
+ fetch-depth: 0
- name: Install Nox
run: |
pip install nox
- - name: Cache .nox and .asv/env directories
+ - name: Cache environment directories
id: cache-env-dir
uses: actions/cache@v2
with:
path: |
.nox
benchmarks/.asv/env
- # Make sure GHA never gets an exact cache match by using the unique
- # github.sha. This means it will always store this run as a new
- # cache (Nox may have made relevant changes during run). Cache
- # restoration still succeeds via the partial restore-key match.
- key: ${{ runner.os }}-${{ github.sha }}
- restore-keys: ${{ runner.os }}
+ $CONDA/pkgs
+ key: ${{ runner.os }}-${{ hashFiles('requirements/') }}-${{ env.ENV_CACHE_BUILD }}
- name: Cache test data directory
id: cache-test-data
@@ -62,16 +57,51 @@ jobs:
unzip -q iris-test-data.zip
mkdir --parents ${GITHUB_WORKSPACE}/${IRIS_TEST_DATA_LOC_PATH}
mv iris-test-data-${IRIS_TEST_DATA_VERSION} ${GITHUB_WORKSPACE}/${IRIS_TEST_DATA_PATH}
-
+
- name: Set test data var
run: |
echo "OVERRIDE_TEST_DATA_REPOSITORY=${GITHUB_WORKSPACE}/${IRIS_TEST_DATA_PATH}/test_data" >> $GITHUB_ENV
- - name: Run CI benchmarks
+ - name: Run overnight benchmarks
+ run: |
+ first_commit=$(git log --after="$(date -d "1 day ago" +"%Y-%m-%d") 23:00:00" --pretty=format:"%h" | tail -n 1)
+ if [ "$first_commit" != "" ]
+ then
+ nox --session="benchmarks(overnight)" -- $first_commit
+ fi
+
+ - name: Create issues for performance shifts
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- mkdir --parents benchmarks/.asv
- set -o pipefail
- nox --session="benchmarks(ci compare)" | tee benchmarks/.asv/ci_compare.txt
+ if [ -d benchmarks/.asv/performance-shifts ]
+ then
+ cd benchmarks/.asv/performance-shifts
+ for commit_file in *
+ do
+ pr_number=$(git log "$commit_file"^! --oneline | grep -o "#[0-9]*" | tail -1 | cut -c 2-)
+ assignee=$(gh pr view $pr_number --json author -q '.["author"]["login"]' --repo $GITHUB_REPOSITORY)
+ title="Performance Shift(s): \`$commit_file\`"
+ body="
+ Benchmark comparison has identified performance shifts at commit \
+ $commit_file (#$pr_number). Please review the report below and \
+ take corrective/congratulatory action as appropriate \
+ :slightly_smiling_face:
+
+
+ Performance shift report
+
+ \`\`\`
+ $(cat $commit_file)
+ \`\`\`
+
+
+
+ Generated by GHA run [\`${{github.run_id}}\`](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})
+ "
+ gh issue create --title "$title" --body "$body" --assignee $assignee --label "Bot" --label "Type: Performance" --repo $GITHUB_REPOSITORY
+ done
+ fi
- name: Archive asv results
if: ${{ always() }}
@@ -80,4 +110,3 @@ jobs:
name: asv-report
path: |
benchmarks/.asv/results
- benchmarks/.asv/ci_compare.txt
diff --git a/.github/workflows/refresh-lockfiles.yml b/.github/workflows/refresh-lockfiles.yml
old mode 100755
new mode 100644
index 643825b3668..96572fb815a
--- a/.github/workflows/refresh-lockfiles.yml
+++ b/.github/workflows/refresh-lockfiles.yml
@@ -22,7 +22,9 @@ on:
default: "no"
schedule:
# Run once a week on a Saturday night
- - cron: 1 0 * * 6
+ # N.B. "should" be quoted, according to
+ # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onschedule
+ - cron: "1 0 * * 6"
jobs:
@@ -35,7 +37,7 @@ jobs:
# the lockfile bot has made the head commit, abort the workflow.
# This job can be manually overridden by running directly from the github actions panel
# (known as a "workflow_dispatch") and setting the `clobber` input to "yes".
- - uses: actions/script@v4
+ - uses: actions/script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -71,7 +73,7 @@ jobs:
strategy:
matrix:
- python: ['37', '38']
+ python: ['38']
steps:
- uses: actions/checkout@v2
@@ -108,13 +110,25 @@ jobs:
rm -r artifacts
- name: Create Pull Request
- uses: peter-evans/create-pull-request@052fc72b4198ba9fbc81b818c6e1859f747d49a8
+ id: cpr
+ uses: peter-evans/create-pull-request@18f7dc018cc2cd597073088f7c7591b9d1c02672
with:
commit-message: Updated environment lockfiles
committer: "Lockfile bot "
author: "Lockfile bot "
delete-branch: true
branch: auto-update-lockfiles
- title: Update CI environment lockfiles
+ title: "[iris.ci] environment lockfiles auto-update"
body: |
Lockfiles updated to the latest resolvable environment.
+ labels: |
+ New: Pull Request
+ Bot
+
+ - name: Check Pull Request
+ if: steps.cpr.outputs.pull-request-number != ''
+ run: |
+ echo "pull-request #${{ steps.cpr.outputs.pull-request-number }}"
+ echo "pull-request URL ${{ steps.cpr.outputs.pull-request-url }}"
+ echo "pull-request operation [${{ steps.cpr.outputs.pull-request-operation }}]"
+ echo "pull-request head SHA ${{ steps.cpr.outputs.pull-request-head-sha }}"
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index a38a03637e8..a1bb0fca6cc 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -1,16 +1,20 @@
# See https://github.com/actions/stale
name: Stale issues and pull-requests
+
on:
schedule:
- - cron: 0 0 * * *
+ # Run once a day
+ # N.B. "should" be quoted, according to
+ # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onschedule
+ - cron: "0 0 * * *"
jobs:
stale:
if: "github.repository == 'SciTools/iris'"
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v4.0.0
+ - uses: actions/stale@v4.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -59,11 +63,11 @@ jobs:
stale-pr-label: Stale
# Labels on issues exempted from stale.
- exempt-issue-labels: |
+ exempt-issue-labels:
"Status: Blocked,Status: Decision Required,Peloton 🚴♂️,Good First Issue"
# Labels on prs exempted from stale.
- exempt-pr-labels: |
+ exempt-pr-labels:
"Status: Blocked,Status: Decision Required,Peloton 🚴♂️,Good First Issue"
# Max number of operations per run.
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 97dff666cfc..ee036038e45 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -29,7 +29,7 @@ repos:
- id: no-commit-to-branch
- repo: https://github.com/psf/black
- rev: 21.12b0
+ rev: 22.1.0
hooks:
- id: black
pass_filenames: false
@@ -50,14 +50,14 @@ repos:
args: [--filter-files]
- repo: https://github.com/asottile/blacken-docs
- rev: v1.12.0
+ rev: v1.12.1
hooks:
- id: blacken-docs
types: [file, rst]
additional_dependencies: [black==21.6b0]
- repo: https://github.com/aio-libs/sort-all
- rev: v1.1.0
+ rev: v1.2.0
hooks:
- id: sort-all
types: [file, python]
diff --git a/benchmarks/README.md b/benchmarks/README.md
new file mode 100644
index 00000000000..baa1afe7001
--- /dev/null
+++ b/benchmarks/README.md
@@ -0,0 +1,80 @@
+# Iris Performance Benchmarking
+
+Iris uses an [Airspeed Velocity](https://github.com/airspeed-velocity/asv)
+(ASV) setup to benchmark performance. This is primarily designed to check for
+performance shifts between commits using statistical analysis, but can also
+be easily repurposed for manual comparative and scalability analyses.
+
+The benchmarks are automatically run overnight
+[by a GitHub Action](../.github/workflows/benchmark.yml), with any notable
+shifts in performance being flagged in a new GitHub issue.
+
+## Running benchmarks
+
+`asv ...` commands must be run from this directory. You will need to have ASV
+installed, as well as Nox (see
+[Benchmark environments](#benchmark-environments)).
+
+[Iris' noxfile](../noxfile.py) includes a `benchmarks` session that provides
+conveniences for setting up before benchmarking, and can also replicate the
+automated overnight run locally. See the session docstring for detail.
+
+### Environment variables
+
+* ``DATA_GEN_PYTHON`` - required - path to a Python executable that can be
+used to generate benchmark test objects/files; see
+[Data generation](#data-generation). The Nox session sets this automatically,
+but will defer to any value already set in the shell.
+* ``BENCHMARK_DATA`` - optional - path to a directory for benchmark synthetic
+test data, which the benchmark scripts will create if it doesn't already
+exist. Defaults to ``/benchmarks/.data/`` if not set.
+
+## Writing benchmarks
+
+[See the ASV docs](https://asv.readthedocs.io/) for full detail.
+
+### Data generation
+**Important:** be sure not to use the benchmarking environment to generate any
+test objects/files, as this environment changes with each commit being
+benchmarked, creating inconsistent benchmark 'conditions'. The
+[generate_data](./benchmarks/generate_data/__init__.py) module offers a
+solution; read more detail there.
+
+### ASV re-run behaviour
+
+Note that ASV re-runs a benchmark multiple times between its `setup()` routine.
+This is a problem for benchmarking certain Iris operations such as data
+realisation, since the data will no longer be lazy after the first run.
+Consider writing extra steps to restore objects' original state _within_ the
+benchmark itself.
+
+If adding steps to the benchmark will skew the result too much then re-running
+can be disabled by setting an attribute on the benchmark: `number = 1`. To
+maintain result accuracy this should be accompanied by increasing the number of
+repeats _between_ `setup()` calls using the `repeat` attribute.
+`warmup_time = 0` is also advisable since ASV performs independent re-runs to
+estimate run-time, and these will still be subject to the original problem.
+
+### Scaling / non-Scaling Performance Differences
+
+When comparing performance between commits/file-type/whatever it can be helpful
+to know if the differences exist in scaling or non-scaling parts of the Iris
+functionality in question. This can be done using a size parameter, setting
+one value to be as small as possible (e.g. a scalar `Cube`), and the other to
+be significantly larger (e.g. a 1000x1000 `Cube`). Performance differences
+might only be seen for the larger value, or the smaller, or both, getting you
+closer to the root cause.
+
+## Benchmark environments
+
+We have disabled ASV's standard environment management, instead using an
+environment built using the same Nox scripts as Iris' test environments. This
+is done using ASV's plugin architecture - see
+[asv_delegated_conda.py](asv_delegated_conda.py) and the extra config items in
+[asv.conf.json](asv.conf.json).
+
+(ASV is written to control the environment(s) that benchmarks are run in -
+minimising external factors and also allowing it to compare between a matrix
+of dependencies (each in a separate environment). We have chosen to sacrifice
+these features in favour of testing each commit with its intended dependencies,
+controlled by Nox + lock-files).
diff --git a/benchmarks/asv.conf.json b/benchmarks/asv.conf.json
index 9ea1cdb101d..3468b2fca99 100644
--- a/benchmarks/asv.conf.json
+++ b/benchmarks/asv.conf.json
@@ -3,18 +3,25 @@
"project": "scitools-iris",
"project_url": "https://github.com/SciTools/iris",
"repo": "..",
- "environment_type": "nox-conda",
+ "environment_type": "conda-delegated",
"show_commit_url": "http://github.com/scitools/iris/commit/",
"benchmark_dir": "./benchmarks",
"env_dir": ".asv/env",
"results_dir": ".asv/results",
"html_dir": ".asv/html",
- "plugins": [".nox_asv_plugin"],
- // The commit to checkout to first run Nox to set up the environment.
- "nox_setup_commit": "HEAD",
- // The path of the noxfile's location relative to the project root.
- "noxfile_rel_path": "noxfile.py",
- // The ``--session`` arg to be used with ``--install-only`` to prep an environment.
- "nox_session_name": "tests"
+ "plugins": [".asv_delegated_conda"],
+
+ // The command(s) that create/update an environment correctly for the
+ // checked-out commit.
+ // Interpreted the same as build_command, with following exceptions:
+ // * No build-time environment variables.
+ // * Is run in the same environment as the ASV install itself.
+ "delegated_env_commands": [
+ "sed -i 's/_PY_VERSIONS_ALL/_PY_VERSION_LATEST/g' noxfile.py",
+ "nox --envdir={conf_dir}/.asv/env/nox01 --session=tests --install-only --no-error-on-external-run --verbose"
+ ],
+ // The parent directory of the above environment.
+ // The most recently modified environment in the directory will be used.
+ "delegated_env_parent": "{conf_dir}/.asv/env/nox01"
}
diff --git a/benchmarks/asv_delegated_conda.py b/benchmarks/asv_delegated_conda.py
new file mode 100644
index 00000000000..250a4e032d8
--- /dev/null
+++ b/benchmarks/asv_delegated_conda.py
@@ -0,0 +1,208 @@
+# 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.
+"""
+ASV plug-in providing an alternative :class:`asv.plugins.conda.Conda`
+subclass that manages the Conda environment via custom user scripts.
+
+"""
+
+from os import environ
+from os.path import getmtime
+from pathlib import Path
+from shutil import copy2, copytree, rmtree
+from tempfile import TemporaryDirectory
+
+from asv import util as asv_util
+from asv.config import Config
+from asv.console import log
+from asv.plugins.conda import Conda
+from asv.repo import Repo
+
+
+class CondaDelegated(Conda):
+ """
+ Manage a Conda environment using custom user scripts, run at each commit.
+
+ Ignores user input variations - ``matrix`` / ``pythons`` /
+ ``conda_environment_file``, since environment is being managed outside ASV.
+
+ Original environment creation behaviour is inherited, but upon checking out
+ a commit the custom script(s) are run and the original environment is
+ replaced with a symlink to the custom environment. This arrangement is then
+ re-used in subsequent runs.
+
+ """
+
+ tool_name = "conda-delegated"
+
+ def __init__(
+ self,
+ conf: Config,
+ python: str,
+ requirements: dict,
+ tagged_env_vars: dict,
+ ) -> None:
+ """
+ Parameters
+ ----------
+ conf : Config instance
+
+ python : str
+ Version of Python. Must be of the form "MAJOR.MINOR".
+
+ requirements : dict
+ Dictionary mapping a PyPI package name to a version
+ identifier string.
+
+ tagged_env_vars : dict
+ Environment variables, tagged for build vs. non-build
+
+ """
+ ignored = ["`python`"]
+ if requirements:
+ ignored.append("`requirements`")
+ if tagged_env_vars:
+ ignored.append("`tagged_env_vars`")
+ if conf.conda_environment_file:
+ ignored.append("`conda_environment_file`")
+ message = (
+ f"Ignoring ASV setting(s): {', '.join(ignored)}. Benchmark "
+ "environment management is delegated to third party script(s)."
+ )
+ log.warning(message)
+ requirements = {}
+ tagged_env_vars = {}
+ conf.conda_environment_file = None
+
+ super().__init__(conf, python, requirements, tagged_env_vars)
+ self._update_info()
+
+ self._env_commands = self._interpolate_commands(
+ conf.delegated_env_commands
+ )
+ # Again using _interpolate_commands to get env parent path - allows use
+ # of the same ASV env variables.
+ env_parent_interpolated = self._interpolate_commands(
+ conf.delegated_env_parent
+ )
+ # Returns list of tuples, we just want the first.
+ env_parent_first = env_parent_interpolated[0]
+ # The 'command' is the first item in the returned tuple.
+ env_parent_string = " ".join(env_parent_first[0])
+ self._delegated_env_parent = Path(env_parent_string).resolve()
+
+ @property
+ def name(self):
+ """Get a name to uniquely identify this environment."""
+ return asv_util.sanitize_filename(self.tool_name)
+
+ def _update_info(self) -> None:
+ """Make sure class properties reflect the actual environment being used."""
+ # Follow symlink if it has been created.
+ actual_path = Path(self._path).resolve()
+ self._path = str(actual_path)
+
+ # Get custom environment's Python version if it exists yet.
+ try:
+ get_version = (
+ "from sys import version_info; "
+ "print(f'{version_info.major}.{version_info.minor}')"
+ )
+ actual_python = self.run(["-c", get_version])
+ self._python = actual_python
+ except OSError:
+ pass
+
+ def _prep_env(self) -> None:
+ """Run the custom environment script(s) and switch to using that environment."""
+ message = f"Running delegated environment management for: {self.name}"
+ log.info(message)
+ env_path = Path(self._path)
+
+ def copy_asv_files(src_parent: Path, dst_parent: Path) -> None:
+ """For copying between self._path and a temporary cache."""
+ asv_files = list(src_parent.glob("asv*"))
+ # build_root_path.name usually == "project" .
+ asv_files += [src_parent / Path(self._build_root).name]
+ for src_path in asv_files:
+ dst_path = dst_parent / src_path.name
+ if not dst_path.exists():
+ # Only caching in case the environment has been rebuilt.
+ # If the dst_path already exists: rebuilding hasn't
+ # happened. Also a non-issue when copying in the reverse
+ # direction because the cache dir is temporary.
+ if src_path.is_dir():
+ func = copytree
+ else:
+ func = copy2
+ func(src_path, dst_path)
+
+ with TemporaryDirectory(prefix="delegated_asv_cache_") as asv_cache:
+ asv_cache_path = Path(asv_cache)
+ # Cache all of ASV's files as delegated command may remove and
+ # re-build the environment.
+ copy_asv_files(env_path.resolve(), asv_cache_path)
+
+ # Adapt the build_dir to the cache location.
+ build_root_path = Path(self._build_root)
+ build_dir_original = build_root_path / self._repo_subdir
+ build_dir_subpath = build_dir_original.relative_to(
+ build_root_path.parent
+ )
+ build_dir = asv_cache_path / build_dir_subpath
+
+ # Run the script(s) for delegated environment creation/updating.
+ # (An adaptation of self._interpolate_and_run_commands).
+ for command, env, return_codes, cwd in self._env_commands:
+ local_envs = dict(environ)
+ local_envs.update(env)
+ if cwd is None:
+ cwd = str(build_dir)
+ _ = asv_util.check_output(
+ command,
+ timeout=self._install_timeout,
+ cwd=cwd,
+ env=local_envs,
+ valid_return_codes=return_codes,
+ )
+
+ # Replace the env that ASV created with a symlink to the env
+ # created/updated by the custom script.
+ delegated_env_path = sorted(
+ self._delegated_env_parent.glob("*"),
+ key=getmtime,
+ reverse=True,
+ )[0]
+ if env_path.resolve() != delegated_env_path:
+ try:
+ env_path.unlink(missing_ok=True)
+ except IsADirectoryError:
+ rmtree(env_path)
+ env_path.symlink_to(
+ delegated_env_path, target_is_directory=True
+ )
+
+ # Check that environment exists.
+ try:
+ env_path.resolve(strict=True)
+ except FileNotFoundError:
+ message = f"Path does not resolve to environment: {env_path}"
+ log.error(message)
+ raise RuntimeError(message)
+
+ # Restore ASV's files from the cache (if necessary).
+ copy_asv_files(asv_cache_path, env_path.resolve())
+
+ # Record new environment information in properties.
+ self._update_info()
+
+ def checkout_project(self, repo: Repo, commit_hash: str) -> None:
+ """Check out the working tree of the project at given commit hash."""
+ super().checkout_project(repo, commit_hash)
+ self._prep_env()
+ log.info(
+ f"Environment {self.name} updated to spec at {commit_hash[:8]}"
+ )
diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py
index 2e741c3da03..4a964a648d9 100644
--- a/benchmarks/benchmarks/__init__.py
+++ b/benchmarks/benchmarks/__init__.py
@@ -5,45 +5,4 @@
# licensing details.
"""Common code for benchmarks."""
-import os
-from pathlib import Path
-
-# Environment variable names
-_ASVDIR_VARNAME = "ASV_DIR" # As set in nightly script "asv_nightly/asv.sh"
-_DATADIR_VARNAME = "BENCHMARK_DATA" # For local runs
-
ARTIFICIAL_DIM_SIZE = int(10e3) # For all artificial cubes, coords etc.
-
-# Work out where the benchmark data dir is.
-asv_dir = os.environ.get("ASV_DIR", None)
-if asv_dir:
- # For an overnight run, this comes from the 'ASV_DIR' setting.
- benchmark_data_dir = Path(asv_dir) / "data"
-else:
- # For a local run, you set 'BENCHMARK_DATA'.
- benchmark_data_dir = os.environ.get(_DATADIR_VARNAME, None)
- if benchmark_data_dir is not None:
- benchmark_data_dir = Path(benchmark_data_dir)
-
-
-def testdata_path(*path_names):
- """
- Return the path of a benchmark test data file.
-
- These are based from a test-data location dir, which is either
- ${}/data (for overnight tests), or ${} for local testing.
-
- If neither of these were set, an error is raised.
-
- """.format(
- _ASVDIR_VARNAME, _DATADIR_VARNAME
- )
- if benchmark_data_dir is None:
- msg = (
- "Benchmark data dir is not defined : "
- 'Either "${}" or "${}" must be set.'
- )
- raise (ValueError(msg.format(_ASVDIR_VARNAME, _DATADIR_VARNAME)))
- path = benchmark_data_dir.joinpath(*path_names)
- path = str(path) # Because Iris doesn't understand Path objects yet.
- return path
diff --git a/benchmarks/benchmarks/generate_data/__init__.py b/benchmarks/benchmarks/generate_data/__init__.py
new file mode 100644
index 00000000000..a56f2e46230
--- /dev/null
+++ b/benchmarks/benchmarks/generate_data/__init__.py
@@ -0,0 +1,94 @@
+# 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.
+"""
+Scripts for generating supporting data for benchmarking.
+
+Data generated using Iris should use :func:`run_function_elsewhere`, which
+means that data is generated using a fixed version of Iris and a fixed
+environment, rather than those that get changed when the benchmarking run
+checks out a new commit.
+
+Downstream use of data generated 'elsewhere' requires saving; usually in a
+NetCDF file. Could also use pickling but there is a potential risk if the
+benchmark sequence runs over two different Python versions.
+
+"""
+from inspect import getsource
+from os import environ
+from pathlib import Path
+from subprocess import CalledProcessError, check_output, run
+from textwrap import dedent
+
+#: Python executable used by :func:`run_function_elsewhere`, set via env
+#: variable of same name. Must be path of Python within an environment that
+#: includes Iris (including dependencies and test modules) and Mule.
+try:
+ DATA_GEN_PYTHON = environ["DATA_GEN_PYTHON"]
+ _ = check_output([DATA_GEN_PYTHON, "-c", "a = True"])
+except KeyError:
+ error = "Env variable DATA_GEN_PYTHON not defined."
+ raise KeyError(error)
+except (CalledProcessError, FileNotFoundError, PermissionError):
+ error = (
+ "Env variable DATA_GEN_PYTHON not a runnable python executable path."
+ )
+ raise ValueError(error)
+
+# The default location of data files used in benchmarks. Used by CI.
+default_data_dir = (Path(__file__).parents[2] / ".data").resolve()
+# Optionally override the default data location with environment variable.
+BENCHMARK_DATA = Path(environ.get("BENCHMARK_DATA", default_data_dir))
+if BENCHMARK_DATA == default_data_dir:
+ BENCHMARK_DATA.mkdir(exist_ok=True)
+elif not BENCHMARK_DATA.is_dir():
+ message = f"Not a directory: {BENCHMARK_DATA} ."
+ raise ValueError(message)
+
+# Manual flag to allow the rebuilding of synthetic data.
+# False forces a benchmark run to re-make all the data files.
+REUSE_DATA = True
+
+
+def run_function_elsewhere(func_to_run, *args, **kwargs):
+ """
+ Run a given function using the :const:`DATA_GEN_PYTHON` executable.
+
+ This structure allows the function to be written natively.
+
+ Parameters
+ ----------
+ func_to_run : FunctionType
+ The function object to be run.
+ NOTE: the function must be completely self-contained, i.e. perform all
+ its own imports (within the target :const:`DATA_GEN_PYTHON`
+ environment).
+ *args : tuple, optional
+ Function call arguments. Must all be expressible as simple literals,
+ i.e. the ``repr`` must be a valid literal expression.
+ **kwargs: dict, optional
+ Function call keyword arguments. All values must be expressible as
+ simple literals (see ``*args``).
+
+ Returns
+ -------
+ str
+ The ``stdout`` from the run.
+
+ """
+ func_string = dedent(getsource(func_to_run))
+ func_string = func_string.replace("@staticmethod\n", "")
+ func_call_term_strings = [repr(arg) for arg in args]
+ func_call_term_strings += [
+ f"{name}={repr(val)}" for name, val in kwargs.items()
+ ]
+ func_call_string = (
+ f"{func_to_run.__name__}(" + ",".join(func_call_term_strings) + ")"
+ )
+ python_string = "\n".join([func_string, func_call_string])
+ result = run(
+ [DATA_GEN_PYTHON, "-c", python_string], capture_output=True, check=True
+ )
+ return result.stdout
diff --git a/benchmarks/benchmarks/generate_data/um_files.py b/benchmarks/benchmarks/generate_data/um_files.py
new file mode 100644
index 00000000000..1037954f08f
--- /dev/null
+++ b/benchmarks/benchmarks/generate_data/um_files.py
@@ -0,0 +1,215 @@
+# 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.
+"""
+Generate FF, PP and NetCDF files based on a minimal synthetic FF file.
+
+NOTE: uses the Mule package, so depends on an environment with Mule installed.
+"""
+
+
+def _create_um_files(
+ len_x: int, len_y: int, len_z: int, len_t: int, compress, save_paths: dict
+) -> None:
+ """
+ Generate an FF object of given shape and compression, save to FF/PP/NetCDF.
+
+ This is run externally
+ (:func:`benchmarks.generate_data.run_function_elsewhere`), so all imports
+ are self-contained and input parameters are simple types.
+ """
+ from copy import deepcopy
+ from datetime import datetime
+ from tempfile import NamedTemporaryFile
+
+ from mo_pack import compress_wgdos as mo_pack_compress
+ from mule import ArrayDataProvider, Field3, FieldsFile
+ from mule.pp import fields_to_pp_file
+ import numpy as np
+
+ from iris import load_cube
+ from iris import save as save_cube
+
+ def packing_patch(*compress_args, **compress_kwargs) -> bytes:
+ """
+ Force conversion from returned :class:`memoryview` to :class:`bytes`.
+
+ Downstream uses of :func:`mo_pack.compress_wgdos` were written
+ for the ``Python2`` behaviour, where the returned buffer had a
+ different ``__len__`` value to the current :class:`memoryview`.
+ Unable to fix directly in Mule, so monkey patching for now.
+ """
+ return mo_pack_compress(*compress_args, **compress_kwargs).tobytes()
+
+ import mo_pack
+
+ mo_pack.compress_wgdos = packing_patch
+
+ ########
+
+ template = {
+ "fixed_length_header": {"dataset_type": 3, "grid_staggering": 3},
+ "integer_constants": {
+ "num_p_levels": len_z,
+ "num_cols": len_x,
+ "num_rows": len_y,
+ },
+ "real_constants": {},
+ "level_dependent_constants": {"dims": (len_z + 1, None)},
+ }
+ new_ff = FieldsFile.from_template(deepcopy(template))
+
+ data_array = np.arange(len_x * len_y).reshape(len_x, len_y)
+ array_provider = ArrayDataProvider(data_array)
+
+ def add_field(level_: int, time_step_: int) -> None:
+ """
+ Add a minimal field to the new :class:`~mule.FieldsFile`.
+
+ Includes the minimum information to allow Mule saving and Iris
+ loading, as well as incrementation for vertical levels and time
+ steps to allow generation of z and t dimensions.
+ """
+ new_field = Field3.empty()
+ # To correspond to the header-release 3 class used.
+ new_field.lbrel = 3
+ # Mule uses the first element of the lookup to test for
+ # unpopulated fields (and skips them), so the first element should
+ # be set to something. The year will do.
+ new_field.raw[1] = datetime.now().year
+
+ # Horizontal.
+ new_field.lbcode = 1
+ new_field.lbnpt = len_x
+ new_field.lbrow = len_y
+ new_field.bdx = new_ff.real_constants.col_spacing
+ new_field.bdy = new_ff.real_constants.row_spacing
+ new_field.bzx = new_ff.real_constants.start_lon - 0.5 * new_field.bdx
+ new_field.bzy = new_ff.real_constants.start_lat - 0.5 * new_field.bdy
+
+ # Hemisphere.
+ new_field.lbhem = 32
+ # Processing.
+ new_field.lbproc = 0
+
+ # Vertical.
+ # Hybrid height values by simulating sequences similar to those in a
+ # theta file.
+ new_field.lbvc = 65
+ if level_ == 0:
+ new_field.lblev = 9999
+ else:
+ new_field.lblev = level_
+
+ level_1 = level_ + 1
+ six_rec = 20 / 3
+ three_rec = six_rec / 2
+
+ new_field.blev = level_1**2 * six_rec - six_rec
+ new_field.brsvd1 = (
+ level_1**2 * six_rec + (six_rec * level_1) - three_rec
+ )
+
+ brsvd2_simulated = np.linspace(0.995, 0, len_z)
+ shift = min(len_z, 2)
+ bhrlev_simulated = np.concatenate(
+ [np.ones(shift), brsvd2_simulated[:-shift]]
+ )
+ new_field.brsvd2 = brsvd2_simulated[level_]
+ new_field.bhrlev = bhrlev_simulated[level_]
+
+ # Time.
+ new_field.lbtim = 11
+
+ new_field.lbyr = time_step_
+ for attr_name in ["lbmon", "lbdat", "lbhr", "lbmin", "lbsec"]:
+ setattr(new_field, attr_name, 0)
+
+ new_field.lbyrd = time_step_ + 1
+ for attr_name in ["lbmond", "lbdatd", "lbhrd", "lbmind", "lbsecd"]:
+ setattr(new_field, attr_name, 0)
+
+ # Data and packing.
+ new_field.lbuser1 = 1
+ new_field.lbpack = int(compress)
+ new_field.bacc = 0
+ new_field.bmdi = -1
+ new_field.lbext = 0
+ new_field.set_data_provider(array_provider)
+
+ new_ff.fields.append(new_field)
+
+ for time_step in range(len_t):
+ for level in range(len_z):
+ add_field(level, time_step + 1)
+
+ ff_path = save_paths.get("FF", None)
+ pp_path = save_paths.get("PP", None)
+ nc_path = save_paths.get("NetCDF", None)
+
+ if ff_path:
+ new_ff.to_file(ff_path)
+ if pp_path:
+ fields_to_pp_file(str(pp_path), new_ff.fields)
+ if nc_path:
+ temp_ff_path = None
+ # Need an Iris Cube from the FF content.
+ if ff_path:
+ # Use the existing file.
+ ff_cube = load_cube(ff_path)
+ else:
+ # Make a temporary file.
+ temp_ff_path = NamedTemporaryFile()
+ new_ff.to_file(temp_ff_path.name)
+ ff_cube = load_cube(temp_ff_path.name)
+
+ save_cube(ff_cube, nc_path, zlib=compress)
+ if temp_ff_path:
+ temp_ff_path.close()
+
+
+FILE_EXTENSIONS = {"FF": "", "PP": ".pp", "NetCDF": ".nc"}
+
+
+def create_um_files(
+ len_x: int,
+ len_y: int,
+ len_z: int,
+ len_t: int,
+ compress: bool,
+ file_types: list,
+) -> dict:
+ """
+ Generate FF-based FF / PP / NetCDF files with specified shape and compression.
+
+ All files representing a given shape are saved in a dedicated directory. A
+ dictionary of the saved paths is returned.
+
+ If the required files exist, they are re-used, unless
+ :const:`benchmarks.REUSE_DATA` is ``False``.
+ """
+ # Self contained imports to avoid linting confusion with _create_um_files().
+ from . import BENCHMARK_DATA, REUSE_DATA, run_function_elsewhere
+
+ save_name_sections = ["UM", len_x, len_y, len_z, len_t]
+ save_name = "_".join(str(section) for section in save_name_sections)
+ save_dir = BENCHMARK_DATA / save_name
+ if not save_dir.is_dir():
+ save_dir.mkdir(parents=True)
+
+ save_paths = {}
+ files_exist = True
+ for file_type in file_types:
+ file_ext = FILE_EXTENSIONS[file_type]
+ save_path = (save_dir / f"{compress}").with_suffix(file_ext)
+ files_exist = files_exist and save_path.is_file()
+ save_paths[file_type] = str(save_path)
+
+ if not REUSE_DATA or not files_exist:
+ _ = run_function_elsewhere(
+ _create_um_files, len_x, len_y, len_z, len_t, compress, save_paths
+ )
+
+ return save_paths
diff --git a/benchmarks/benchmarks/loading.py b/benchmarks/benchmarks/loading.py
new file mode 100644
index 00000000000..4558c3b5cba
--- /dev/null
+++ b/benchmarks/benchmarks/loading.py
@@ -0,0 +1,185 @@
+# 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.
+"""
+File loading benchmark tests.
+
+Where applicable benchmarks should be parameterised for two sizes of input data:
+ * minimal: enables detection of regressions in parts of the run-time that do
+ NOT scale with data size.
+ * large: large enough to exclusively detect regressions in parts of the
+ run-time that scale with data size. Size should be _just_ large
+ enough - don't want to bloat benchmark runtime.
+
+"""
+
+from iris import AttributeConstraint, Constraint, load, load_cube
+from iris.cube import Cube
+from iris.fileformats.um import structured_um_loading
+
+from .generate_data import BENCHMARK_DATA, REUSE_DATA, run_function_elsewhere
+from .generate_data.um_files import create_um_files
+
+
+class LoadAndRealise:
+ params = [
+ [(2, 2, 2), (1280, 960, 5)],
+ [False, True],
+ ["FF", "PP", "NetCDF"],
+ ]
+ param_names = ["xyz", "compressed", "file_format"]
+
+ def setup_cache(self) -> dict:
+ file_type_args = self.params[2]
+ file_path_dict = {}
+ for xyz in self.params[0]:
+ file_path_dict[xyz] = {}
+ x, y, z = xyz
+ for compress in self.params[1]:
+ file_path_dict[xyz][compress] = create_um_files(
+ x, y, z, 1, compress, file_type_args
+ )
+ return file_path_dict
+
+ def setup(
+ self,
+ file_path_dict: dict,
+ xyz: tuple,
+ compress: bool,
+ file_format: str,
+ ) -> None:
+ self.file_path = file_path_dict[xyz][compress][file_format]
+ self.cube = self.load()
+
+ def load(self) -> Cube:
+ return load_cube(self.file_path)
+
+ def time_load(self, _, __, ___, ____) -> None:
+ _ = self.load()
+
+ def time_realise(self, _, __, ___, ____) -> None:
+ # Don't touch cube.data - permanent realisation plays badly with ASV's
+ # re-run strategy.
+ assert self.cube.has_lazy_data()
+ self.cube.core_data().compute()
+
+
+class STASHConstraint:
+ # xyz sizes mimic LoadAndRealise to maximise file re-use.
+ params = [[(2, 2, 2), (1280, 960, 5)], ["FF", "PP"]]
+ param_names = ["xyz", "file_format"]
+
+ def setup_cache(self) -> dict:
+ file_type_args = self.params[1]
+ file_path_dict = {}
+ for xyz in self.params[0]:
+ x, y, z = xyz
+ file_path_dict[xyz] = create_um_files(
+ x, y, z, 1, False, file_type_args
+ )
+ return file_path_dict
+
+ def setup(
+ self, file_path_dict: dict, xyz: tuple, file_format: str
+ ) -> None:
+ self.file_path = file_path_dict[xyz][file_format]
+
+ def time_stash_constraint(self, _, __, ___) -> None:
+ _ = load_cube(self.file_path, AttributeConstraint(STASH="m??s??i901"))
+
+
+class TimeConstraint:
+ params = [[3, 20], ["FF", "PP", "NetCDF"]]
+ param_names = ["time_dim_len", "file_format"]
+
+ def setup_cache(self) -> dict:
+ file_type_args = self.params[1]
+ file_path_dict = {}
+ for time_dim_len in self.params[0]:
+ file_path_dict[time_dim_len] = create_um_files(
+ 20, 20, 5, time_dim_len, False, file_type_args
+ )
+ return file_path_dict
+
+ def setup(
+ self, file_path_dict: dict, time_dim_len: int, file_format: str
+ ) -> None:
+ self.file_path = file_path_dict[time_dim_len][file_format]
+ self.time_constr = Constraint(time=lambda cell: cell.point.year < 3)
+
+ def time_time_constraint(self, _, __, ___) -> None:
+ _ = load_cube(self.file_path, self.time_constr)
+
+
+class ManyVars:
+ FILE_PATH = BENCHMARK_DATA / "many_var_file.nc"
+
+ @staticmethod
+ def _create_file(save_path: str) -> None:
+ """Is run externally - everything must be self-contained."""
+ import numpy as np
+
+ from iris import save
+ from iris.coords import AuxCoord
+ from iris.cube import Cube
+
+ data_len = 8
+ data = np.arange(data_len)
+ cube = Cube(data, units="unknown")
+ extra_vars = 80
+ names = ["coord_" + str(i) for i in range(extra_vars)]
+ for name in names:
+ coord = AuxCoord(data, long_name=name, units="unknown")
+ cube.add_aux_coord(coord, 0)
+ save(cube, save_path)
+
+ def setup_cache(self) -> None:
+ if not REUSE_DATA or not self.FILE_PATH.is_file():
+ # See :mod:`benchmarks.generate_data` docstring for full explanation.
+ _ = run_function_elsewhere(
+ self._create_file,
+ str(self.FILE_PATH),
+ )
+
+ def time_many_var_load(self) -> None:
+ _ = load(str(self.FILE_PATH))
+
+
+class StructuredFF:
+ """
+ Test structured loading of a large-ish fieldsfile.
+
+ Structured load of the larger size should show benefit over standard load,
+ avoiding the cost of merging.
+ """
+
+ params = [[(2, 2, 2), (1280, 960, 5)], [False, True]]
+ param_names = ["xyz", "structured_loading"]
+
+ def setup_cache(self) -> dict:
+ file_path_dict = {}
+ for xyz in self.params[0]:
+ x, y, z = xyz
+ file_path_dict[xyz] = create_um_files(x, y, z, 1, False, ["FF"])
+ return file_path_dict
+
+ def setup(self, file_path_dict, xyz, structured_load):
+ self.file_path = file_path_dict[xyz]["FF"]
+ self.structured_load = structured_load
+
+ def load(self):
+ """Load the whole file (in fact there is only 1 cube)."""
+
+ def _load():
+ _ = load(self.file_path)
+
+ if self.structured_load:
+ with structured_um_loading():
+ _load()
+ else:
+ _load()
+
+ def time_structured_load(self, _, __, ___):
+ self.load()
diff --git a/benchmarks/benchmarks/plot.py b/benchmarks/benchmarks/plot.py
index 45905abd2ff..24899776dc8 100644
--- a/benchmarks/benchmarks/plot.py
+++ b/benchmarks/benchmarks/plot.py
@@ -22,7 +22,7 @@ def setup(self):
# Should generate 10 distinct contours, regardless of dim size.
dim_size = int(ARTIFICIAL_DIM_SIZE / 5)
repeat_number = int(dim_size / 10)
- repeat_range = range(int((dim_size ** 2) / repeat_number))
+ repeat_range = range(int((dim_size**2) / repeat_number))
data = np.repeat(repeat_range, repeat_number)
data = data.reshape((dim_size,) * 2)
diff --git a/benchmarks/nox_asv_plugin.py b/benchmarks/nox_asv_plugin.py
deleted file mode 100644
index 6c9ce142721..00000000000
--- a/benchmarks/nox_asv_plugin.py
+++ /dev/null
@@ -1,249 +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.
-"""
-ASV plug-in providing an alternative ``Environment`` subclass, which uses Nox
-for environment management.
-
-"""
-from importlib.util import find_spec
-from pathlib import Path
-from shutil import copy2, copytree
-from tempfile import TemporaryDirectory
-
-from asv import util as asv_util
-from asv.config import Config
-from asv.console import log
-from asv.environment import get_env_name
-from asv.plugins.conda import Conda, _find_conda
-from asv.repo import Repo, get_repo
-
-
-class NoxConda(Conda):
- """
- Manage a Conda environment using Nox, updating environment at each commit.
-
- Defers environment management to the project's noxfile, which must be able
- to create/update the benchmarking environment using ``nox --install-only``,
- with the ``--session`` specified in ``asv.conf.json.nox_session_name``.
-
- Notes
- -----
- If not all benchmarked commits support this use of Nox: the plugin will
- need to be modified to prep the environment in other ways.
-
- """
-
- tool_name = "nox-conda"
-
- @classmethod
- def matches(cls, python: str) -> bool:
- """Used by ASV to work out if this type of environment can be used."""
- result = find_spec("nox") is not None
- if result:
- result = super().matches(python)
-
- if result:
- message = (
- f"NOTE: ASV env match check incomplete. Not possible to know "
- f"if selected Nox session (asv.conf.json.nox_session_name) is "
- f"compatible with ``--python={python}`` until project is "
- f"checked out."
- )
- log.warning(message)
-
- return result
-
- def __init__(self, conf: Config, python: str, requirements: dict) -> None:
- """
- Parameters
- ----------
- conf: Config instance
-
- python : str
- Version of Python. Must be of the form "MAJOR.MINOR".
-
- requirements : dict
- Dictionary mapping a PyPI package name to a version
- identifier string.
-
- """
- from nox.sessions import _normalize_path
-
- # Need to checkout the project BEFORE the benchmark run - to access a noxfile.
- self.project_temp_checkout = TemporaryDirectory(
- prefix="nox_asv_checkout_"
- )
- repo = get_repo(conf)
- repo.checkout(self.project_temp_checkout.name, conf.nox_setup_commit)
- self.noxfile_rel_path = conf.noxfile_rel_path
- self.setup_noxfile = (
- Path(self.project_temp_checkout.name) / self.noxfile_rel_path
- )
- self.nox_session_name = conf.nox_session_name
-
- # Some duplication of parent code - need these attributes BEFORE
- # running inherited code.
- self._python = python
- self._requirements = requirements
- self._env_dir = conf.env_dir
-
- # Prepare the actual environment path, to override self._path.
- nox_envdir = str(Path(self._env_dir).absolute() / self.hashname)
- nox_friendly_name = self._get_nox_session_name(python)
- self._nox_path = Path(_normalize_path(nox_envdir, nox_friendly_name))
-
- # For storing any extra conda requirements from asv.conf.json.
- self._extra_reqs_path = self._nox_path / "asv-extra-reqs.yaml"
-
- super().__init__(conf, python, requirements)
-
- @property
- def _path(self) -> str:
- """
- Using a property to override getting and setting in parent classes -
- unable to modify parent classes as this is a plugin.
-
- """
- return str(self._nox_path)
-
- @_path.setter
- def _path(self, value) -> None:
- """Enforce overriding of this variable by disabling modification."""
- pass
-
- @property
- def name(self) -> str:
- """Overridden to prevent inclusion of user input requirements."""
- return get_env_name(self.tool_name, self._python, {})
-
- def _get_nox_session_name(self, python: str) -> str:
- nox_cmd_substring = (
- f"--noxfile={self.setup_noxfile} "
- f"--session={self.nox_session_name} "
- f"--python={python}"
- )
-
- list_output = asv_util.check_output(
- ["nox", "--list", *nox_cmd_substring.split(" ")],
- display_error=False,
- dots=False,
- )
- list_output = list_output.split("\n")
- list_matches = list(filter(lambda s: s.startswith("*"), list_output))
- matches_count = len(list_matches)
-
- if matches_count == 0:
- message = f"No Nox sessions found for: {nox_cmd_substring} ."
- log.error(message)
- raise RuntimeError(message)
- elif matches_count > 1:
- message = (
- f"Ambiguous - >1 Nox session found for: {nox_cmd_substring} ."
- )
- log.error(message)
- raise RuntimeError(message)
- else:
- line = list_matches[0]
- session_name = line.split(" ")[1]
- assert isinstance(session_name, str)
- return session_name
-
- def _nox_prep_env(self, setup: bool = False) -> None:
- message = f"Running Nox environment update for: {self.name}"
- log.info(message)
-
- build_root_path = Path(self._build_root)
- env_path = Path(self._path)
-
- def copy_asv_files(src_parent: Path, dst_parent: Path) -> None:
- """For copying between self._path and a temporary cache."""
- asv_files = list(src_parent.glob("asv*"))
- # build_root_path.name usually == "project" .
- asv_files += [src_parent / build_root_path.name]
- for src_path in asv_files:
- dst_path = dst_parent / src_path.name
- if not dst_path.exists():
- # Only cache-ing in case Nox has rebuilt the env @
- # self._path. If the dst_path already exists: rebuilding
- # hasn't happened. Also a non-issue when copying in the
- # reverse direction because the cache dir is temporary.
- if src_path.is_dir():
- func = copytree
- else:
- func = copy2
- func(src_path, dst_path)
-
- with TemporaryDirectory(prefix="nox_asv_cache_") as asv_cache:
- asv_cache_path = Path(asv_cache)
- if setup:
- noxfile = self.setup_noxfile
- else:
- # Cache all of ASV's files as Nox may remove and re-build the environment.
- copy_asv_files(env_path, asv_cache_path)
- # Get location of noxfile in cache.
- noxfile_original = (
- build_root_path / self._repo_subdir / self.noxfile_rel_path
- )
- noxfile_subpath = noxfile_original.relative_to(
- build_root_path.parent
- )
- noxfile = asv_cache_path / noxfile_subpath
-
- nox_cmd = [
- "nox",
- f"--noxfile={noxfile}",
- # Place the env in the ASV env directory, instead of the default.
- f"--envdir={env_path.parent}",
- f"--session={self.nox_session_name}",
- f"--python={self._python}",
- "--install-only",
- "--no-error-on-external-run",
- "--verbose",
- ]
-
- _ = asv_util.check_output(nox_cmd)
- if not env_path.is_dir():
- message = f"Expected Nox environment not found: {env_path}"
- log.error(message)
- raise RuntimeError(message)
-
- if not setup:
- # Restore ASV's files from the cache (if necessary).
- copy_asv_files(asv_cache_path, env_path)
-
- def _setup(self) -> None:
- """Used for initial environment creation - mimics parent method where possible."""
- try:
- self.conda = _find_conda()
- except IOError as e:
- raise asv_util.UserError(str(e))
- if find_spec("nox") is None:
- raise asv_util.UserError("Module not found: nox")
-
- message = f"Creating Nox-Conda environment for {self.name} ."
- log.info(message)
-
- try:
- self._nox_prep_env(setup=True)
- finally:
- # No longer need the setup checkout now that the environment has been built.
- self.project_temp_checkout.cleanup()
-
- conda_args, pip_args = self._get_requirements(self.conda)
- if conda_args or pip_args:
- message = (
- "Ignoring user input package requirements. Benchmark "
- "environment management is exclusively performed by Nox."
- )
- log.warning(message)
-
- def checkout_project(self, repo: Repo, commit_hash: str) -> None:
- """Check out the working tree of the project at given commit hash."""
- super().checkout_project(repo, commit_hash)
- self._nox_prep_env()
- log.info(
- f"Environment {self.name} updated to spec at {commit_hash[:8]}"
- )
diff --git a/docs/gallery_code/meteorology/plot_wind_barbs.py b/docs/gallery_code/meteorology/plot_wind_barbs.py
index c3c056eb4ac..b09040c64e9 100644
--- a/docs/gallery_code/meteorology/plot_wind_barbs.py
+++ b/docs/gallery_code/meteorology/plot_wind_barbs.py
@@ -30,7 +30,7 @@ def main():
# To illustrate the full range of barbs, scale the wind speed up to pretend
# that a storm is passing over
- magnitude = (uwind ** 2 + vwind ** 2) ** 0.5
+ magnitude = (uwind**2 + vwind**2) ** 0.5
magnitude.convert_units("knot")
max_speed = magnitude.collapsed(
("latitude", "longitude"), iris.analysis.MAX
@@ -41,7 +41,7 @@ def main():
vwind = vwind / max_speed * max_desired
# Create a cube containing the wind speed
- windspeed = (uwind ** 2 + vwind ** 2) ** 0.5
+ windspeed = (uwind**2 + vwind**2) ** 0.5
windspeed.rename("windspeed")
windspeed.convert_units("knot")
diff --git a/docs/gallery_code/meteorology/plot_wind_speed.py b/docs/gallery_code/meteorology/plot_wind_speed.py
index fd03f542057..40d9d0da002 100644
--- a/docs/gallery_code/meteorology/plot_wind_speed.py
+++ b/docs/gallery_code/meteorology/plot_wind_speed.py
@@ -27,7 +27,7 @@ def main():
vwind = iris.load_cube(infile, "y_wind")
# Create a cube containing the wind speed.
- windspeed = (uwind ** 2 + vwind ** 2) ** 0.5
+ windspeed = (uwind**2 + vwind**2) ** 0.5
windspeed.rename("windspeed")
# Plot the wind speed as a contour plot.
diff --git a/docs/src/common_links.inc b/docs/src/common_links.inc
index 0b0240b633e..3d62347f493 100644
--- a/docs/src/common_links.inc
+++ b/docs/src/common_links.inc
@@ -37,6 +37,7 @@
.. _test-iris-imagehash: https://github.com/SciTools/test-iris-imagehash
.. _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/
.. _voteable issues on GitHub: https://github.com/SciTools/iris/issues?q=is%3Aopen+is%3Aissue+label%3A%22Feature%3A+Voteable%22+sort%3Areactions-%2B1-desc
diff --git a/docs/src/conf.py b/docs/src/conf.py
index 287794368a1..4a5d866c2f3 100644
--- a/docs/src/conf.py
+++ b/docs/src/conf.py
@@ -200,7 +200,9 @@ def _dotv(version):
# -- copybutton extension -----------------------------------------------------
# See https://sphinx-copybutton.readthedocs.io/en/latest/
-copybutton_prompt_text = ">>> "
+copybutton_prompt_text = r">>> |\.\.\. "
+copybutton_prompt_is_regexp = True
+copybutton_line_continuation_character = "\\"
# sphinx.ext.todo configuration -----------------------------------------------
# See https://www.sphinx-doc.org/en/master/usage/extensions/todo.html
@@ -209,6 +211,7 @@ def _dotv(version):
# api generation configuration
autodoc_member_order = "groupwise"
autodoc_default_flags = ["show-inheritance"]
+autodoc_typehints = "none"
autosummary_generate = True
autosummary_imported_members = True
autopackage_name = ["iris"]
@@ -324,6 +327,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.
@@ -339,8 +343,10 @@ def _dotv(version):
"gallery_dirs": ["generated/gallery"],
# filename pattern for the files in the gallery
"filename_pattern": "/plot_",
- # filename patternt to ignore in the gallery
+ # filename pattern to ignore in the gallery
"ignore_pattern": r"__init__\.py",
+ # force gallery building, unless overridden (see src/Makefile)
+ "plot_gallery": "'True'",
}
# -----------------------------------------------------------------------------
diff --git a/docs/src/developers_guide/documenting/whats_new_contributions.rst b/docs/src/developers_guide/documenting/whats_new_contributions.rst
index ebb553024bc..576fc5f6a68 100644
--- a/docs/src/developers_guide/documenting/whats_new_contributions.rst
+++ b/docs/src/developers_guide/documenting/whats_new_contributions.rst
@@ -4,16 +4,21 @@
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`
+Iris uses a file named ``dev.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
-an Iris release: **create the new** ``latest.rst`` by copying the content from
-``latest.rst.template`` in the same directory.
+The ``dev.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** ``dev.rst`` by copying the content from
+``dev.rst.template`` in the same directory.
+
+.. note::
+
+ Ensure that the symbolic link ``latest.rst`` references the ``dev.rst`` file
+ within the ``docs/src/whatsnew`` directory.
Since the `Contribution categories`_ include Internal changes, **all** Iris
Pull Requests should be accompanied by a "What's New" contribution.
@@ -22,7 +27,7 @@ Pull Requests should be accompanied by a "What's New" contribution.
Git Conflicts
=============
-If changes to ``latest.rst`` are being suggested in several simultaneous
+If changes to ``dev.rst`` are being suggested in several simultaneous
Iris Pull Requests, Git will likely encounter merge conflicts. If this
situation is thought likely (large PR, high repo activity etc.):
@@ -43,7 +48,7 @@ situation is thought likely (large PR, high repo activity etc.):
* PR reviewer: review the "What's New" PR, merge once acceptable
-These measures should mean the suggested ``latest.rst`` changes are outstanding
+These measures should mean the suggested ``dev.rst`` changes are outstanding
for the minimum time, minimising conflicts and minimising the need to rebase or
merge from trunk.
diff --git a/docs/src/developers_guide/release.rst b/docs/src/developers_guide/release.rst
index bcf075e4ae7..f4d44781fc6 100644
--- a/docs/src/developers_guide/release.rst
+++ b/docs/src/developers_guide/release.rst
@@ -36,6 +36,14 @@ Ensure that any behaviour which has been deprecated for the correct number of
previous releases is now finally changed. More detail, including the correct
number of releases, is in :ref:`iris_development_deprecations`.
+Standard Names
+~~~~~~~~~~~~~~
+
+Update the file ``etc/cf-standard-name-table.xml`` to the latest CF standard names,
+from the `latest CF standard names`_.
+( This is used during build to automatically generate the sourcefile
+``lib/iris/std_names.py``. )
+
Release Branch
--------------
@@ -175,9 +183,9 @@ 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
-on the ``main`` branch of ``SciTools/iris``.
+``iris.__version__``, ``docs/src/whatsnew/index.rst``, ``docs/src/whatsnew/dev.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``.
Point Releases
@@ -210,9 +218,11 @@ Release Steps
#. 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
+ * Use ``git`` to rename ``docs/src/whatsnew/dev.rst`` to the release
version file ``v1.9.rst``
- * Use ``git`` to delete the ``docs/src/whatsnew/latest.rst.template`` file
+ * Update the symbolic link ``latest.rst`` to reference the latest
+ whatsnew ``v1.9.rst``
+ * Use ``git`` to delete the ``docs/src/whatsnew/dev.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
@@ -221,11 +231,11 @@ Release Steps
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``
+ ``dev.rst.template`` and update to the ``latest.rst`` symbolic link.
#. Update the ``whatsnew`` index ``docs/src/whatsnew/index.rst``
- * Remove the reference to ``latest.rst``
+ * Remove the reference to ``dev.rst``
* Add a reference to ``v1.9.rst`` to the top of the list
#. Check your changes by building the documentation and reviewing
@@ -246,13 +256,6 @@ Post Release Steps
`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``
@@ -268,3 +271,4 @@ 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
diff --git a/docs/src/further_topics/index.rst b/docs/src/further_topics/index.rst
index dc162d6a1e2..81bff2f7641 100644
--- a/docs/src/further_topics/index.rst
+++ b/docs/src/further_topics/index.rst
@@ -13,14 +13,14 @@ 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 `GitHub Documentation Issue`_
+ 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`
-.. _GitHub Documentation Issue: https://github.com/SciTools/iris/issues/new?assignees=&labels=New%3A+Documentation%2C+Type%3A+Documentation&template=documentation.md&title=
.. _SciTools/iris: https://github.com/SciTools/iris
diff --git a/docs/src/further_topics/lenient_maths.rst b/docs/src/further_topics/lenient_maths.rst
index 643bd37e76b..818efe47632 100644
--- a/docs/src/further_topics/lenient_maths.rst
+++ b/docs/src/further_topics/lenient_maths.rst
@@ -84,10 +84,10 @@ represents the output of an low-resolution global atmospheric ``experiment``,
forecast_reference_time 2009-09-09 17:10:00
time 2009-09-09 17:10:00
Attributes:
- Conventions CF-1.5
+ Conventions 'CF-1.5'
STASH m01s00i004
- experiment-id RT3 50
- source Data from Met Office Unified Model 7.04
+ experiment-id 'RT3 50'
+ source 'Data from Met Office Unified Model 7.04'
Consider also the following :class:`~iris.cube.Cube`, which has the same global
spatial extent, and acts as a ``control``,
@@ -103,9 +103,9 @@ spatial extent, and acts as a ``control``,
model_level_number 1
time 2009-09-09 17:10:00
Attributes:
- Conventions CF-1.7
+ Conventions 'CF-1.7'
STASH m01s00i004
- source Data from Met Office Unified Model 7.04
+ source 'Data from Met Office Unified Model 7.04'
Now let's subtract these cubes in order to calculate a simple ``difference``,
@@ -129,8 +129,8 @@ Now let's subtract these cubes in order to calculate a simple ``difference``,
forecast_reference_time 2009-09-09 17:10:00
time 2009-09-09 17:10:00
Attributes:
- experiment-id RT3 50
- source Data from Met Office Unified Model 7.04
+ experiment-id 'RT3 50'
+ source 'Data from Met Office Unified Model 7.04'
Note that, cube maths automatically takes care of broadcasting the
dimensionality of the ``control`` up to that of the ``experiment``, in order to
@@ -218,7 +218,7 @@ time perform **strict** cube maths instead,
Scalar coordinates:
time 2009-09-09 17:10:00
Attributes:
- source Data from Met Office Unified Model 7.04
+ source 'Data from Met Office Unified Model 7.04'
Although the numerical result of this strict cube maths operation is identical,
it is not as rich in metadata as the :ref:`lenient alternative `.
diff --git a/docs/src/further_topics/metadata.rst b/docs/src/further_topics/metadata.rst
index 79e9c164a0d..1b81f7055c2 100644
--- a/docs/src/further_topics/metadata.rst
+++ b/docs/src/further_topics/metadata.rst
@@ -38,8 +38,8 @@ Collectively, the aforementioned classes will be known here as the Iris
.. hint::
If there are any `CF Conventions`_ metadata missing from Iris that you
- care about, then please let us know by raising a `GitHub Issue`_ on
- `SciTools/iris`_
+ care about, then please let us know by raising a :issue:`GitHub Issue`
+ on `SciTools/iris`_
Common Metadata
@@ -120,10 +120,10 @@ For example, given the following :class:`~iris.cube.Cube`,
Cell methods:
mean time (6 hour)
Attributes:
- Conventions CF-1.5
- Model scenario A1B
+ Conventions 'CF-1.5'
+ Model scenario 'A1B'
STASH m01s03i236
- source Data from Met Office Unified Model 6.05
+ source 'Data from Met Office Unified Model 6.05'
We can easily get all of the associated metadata of the :class:`~iris.cube.Cube`
using the ``metadata`` property:
@@ -990,7 +990,6 @@ values. All other metadata members will be left unaltered.
.. _CF Conventions: https://cfconventions.org/
.. _Cell Measures: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#cell-measures
.. _Flags: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#flags
-.. _GitHub Issue: https://github.com/SciTools/iris/issues/new/choose
.. _mapping: https://docs.python.org/3/glossary.html#term-mapping
.. _namedtuple: https://docs.python.org/3/library/collections.html#collections.namedtuple
.. _namedtuple._make: https://docs.python.org/3/library/collections.html#collections.somenamedtuple._make
diff --git a/docs/src/further_topics/ugrid/data_model.rst b/docs/src/further_topics/ugrid/data_model.rst
new file mode 100644
index 00000000000..4a2f64f6279
--- /dev/null
+++ b/docs/src/further_topics/ugrid/data_model.rst
@@ -0,0 +1,566 @@
+.. include:: ../../common_links.inc
+
+.. _ugrid model:
+
+The Mesh Data Model
+*******************
+
+.. important::
+
+ This page is intended to summarise the essentials that Iris users need
+ to know about meshes. For exhaustive details on UGRID itself:
+ `visit the official UGRID conventions site`__.
+
+Evolution, not revolution
+=========================
+Mesh support has been designed wherever possible to fit within the existing
+Iris model. Meshes concern only the spatial geography of data, and can
+optionally be limited to just the horizontal geography (e.g. X and Y). Other
+dimensions such as time or ensemble member (and often vertical levels)
+retain their familiar structured format.
+
+The UGRID conventions themselves are designed as an addition to the existing CF
+conventions, which are at the core of Iris' philosophy.
+
+What's Different?
+=================
+
+The mesh format represents data's geography using an **unstructured
+mesh**. This has significant pros and cons when compared to a structured grid.
+
+.. contents::
+ :local:
+
+The Detail
+----------
+..
+ The diagram images are SVG's, so editable by any graphical software
+ (e.g. Inkscape). They were originally made in MS PowerPoint.
+
+ Uses the IBM Colour Blind Palette (see
+ http://ibm-design-language.eu-de.mybluemix.net/design/language/resources/color-library
+ )
+
+Structured Grids (the old world)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Assigning data to locations using a structured grid is essentially an act of
+matching coordinate arrays to each dimension of the data array. The data can
+also be represented as an area (instead of a point) by including a bounds array
+for each coordinate array. :numref:`data_structured_grid` visualises an
+example.
+
+.. _data_structured_grid:
+.. figure:: images/data_structured_grid.svg
+ :alt: Diagram of how data is represented on a structured grid
+ :align: right
+ :width: 1280
+
+ Data on a structured grid.
+
+ 1D coordinate arrays (pink circles) are combined to construct a structured
+ grid of points (pink crosses). 2D bounds arrays (blue circles) can also be
+ used to describe the 1D boundaries (blue lines) at either side of each
+ rank of points; each point therefore having four bounds (x+y, upper+lower),
+ together describing a quadrilateral area around that point. Data from the
+ 2D data array (orange circles) can be assigned to these point locations
+ (orange diamonds) or area locations (orange quads) by matching the relative
+ positions in the data array to the relative spatial positions - see the
+ black outlined shapes as examples of this in action.
+
+Unstructured Meshes (the new world)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A mesh is made up of different types of **element**:
+
+.. list-table::
+ :widths: 15, 15, 70
+
+ * - 0D
+ - ``node``
+ - The 'core' of the mesh. A point position in space, constructed from
+ 2 or 3 coordinates (2D or 3D space).
+ * - 1D
+ - ``edge``
+ - Constructed by connecting 2 nodes.
+ * - 2D
+ - ``face``
+ - Constructed by connecting 3 or more nodes.
+ * - 3D
+ - ``volume``
+ - Constructed by connecting 4 or more nodes (which must each have 3
+ coordinates - 3D space).
+
+Every node in the mesh is defined by indexing the 1-dimensional X and Y (and
+optionally Z) coordinate arrays (the ``node_coordinates``) - e.g.
+``(x[3], y[3])`` gives the position of the fourth node. Note that this means
+each node has its own coordinates, independent of every other node.
+
+Any higher dimensional element - an edge/face/volume - is described by a
+sequence of the indices of the nodes that make up that element. E.g. a
+triangular face made from connecting the first, third and fourth nodes:
+``[0, 2, 3]``. These 1D sequences combine into a 2D array enumerating **all**
+the elements of that type - edge/face/volume - called a **connectivity**.
+E.g. we could make a mesh of 4 nodes, with 2 triangles described using this
+``face_node_connectivity``: ``[[0, 2, 3], [3, 2, 1]]`` (note the shared nodes).
+
+.. note:: More on Connectivities:
+
+ * The element type described by a connectivity is known as its
+ **location**; ``edge`` in ``edge_node_connectivity``.
+ * According to the UGRID conventions, the nodes in a face should be
+ listed in "anti-clockwise order from above".
+ * Connectivities also exist to connect the higher dimensional elements,
+ e.g. ``face_edge_connectivity``. These are optional conveniences to
+ speed up certain operations and will not be discussed here.
+
+.. important::
+
+ **Meshes are unstructured**. The mesh elements - represented in the
+ coordinate and connectivity arrays detailed above - are enumerated
+ along a single **unstructured dimension**. An element's position along
+ this dimension has nothing to do with its spatial position.
+
+A data variable associated with a mesh has a **location** of either ``node``,
+``edge``, ``face`` or ``volume``. The data is stored in a 1D array with one
+datum per element, matched to its element by matching the datum index with the
+coordinate or connectivity index along the **unstructured dimension**. So for
+an example data array called ``foo``:
+``foo[3]`` would be at position ``(x[3], y[3])`` if it were node-located, or at
+``faces[3]`` if it were face-located. :numref:`data_ugrid_mesh` visualises an
+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
+ :width: 1280
+
+ Data on an unstructured mesh
+
+ 1D coordinate arrays (pink circles) describe node positions in space (pink
+ crosses). A 2D connectivity array (blue circles) describes faces by
+ connecting four nodes - by referencing their indices - into a face outline
+ (blue outlines on the map). Data from the 1D data array (orange circles)
+ can be assigned to these node locations (orange diamonds) or face locations
+ (orange quads) by matching the indices in the data array to the indices in
+ the coordinate arrays (for nodes) or connectivity array (for faces). See
+ the black outlined shapes as examples of index matching in action, and the
+ black stippled shapes to demonstrate that relative array position confers
+ no relative spatial information.
+
+----
+
+The mesh model also supports edges/faces/volumes having associated 'centre'
+coordinates - to allow point data to be assigned to these elements. 'Centre' is
+just a convenience term - the points can exist anywhere within their respective
+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
+ :width: 1280
+
+ Data can be assigned to mesh edge/face/volume 'centres'
+
+ 1D *node* coordinate arrays (pink circles) describe node positions in
+ space (pink crosses). A 2D connectivity array (blue circles) describes
+ faces by connecting four nodes into a face outline (blue outlines on the
+ map). Further 1D *face* coordinate arrays (pink circles) describe a
+ 'centre' point position (pink stars) for each face enumerated in the
+ connectivity array.
+
+Mesh Flexibility
+++++++++++++++++
+Above we have seen how one could replicate data on a structured grid using
+a mesh instead. But the utility of a mesh is the extra flexibility it offers.
+Here are the main examples:
+
+Every node is completely independent - every one can have unique X andY (and Z) coordinate values. See :numref:`ugrid_node_independence`.
+
+.. _ugrid_node_independence:
+.. figure:: images/ugrid_node_independence.svg
+ :alt: Diagram demonstrating the independence of each mesh node
+ :align: right
+ :width: 300
+
+ Every mesh node is completely independent
+
+ The same array shape and structure used to describe the node positions
+ (pink crosses) in a regular grid (left-hand maps) is equally able to
+ describe **any** position for these nodes (e.g. the right-hand maps),
+ simply by changing the array values. The quadrilateral faces (blue
+ outlines) can therefore be given any quadrilateral shape by re-positioning
+ their constituent nodes.
+
+Faces and volumes can have variable node counts, i.e. different numbers of
+sides. This is achieved by masking the unused 'slots' in the connectivity
+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
+ :width: 300
+
+ Mesh faces can have different node counts (using masking)
+
+ The 2D connectivity array (blue circles) describes faces by connecting
+ nodes (pink crosses) to make up a face (blue outlines). The faces can use
+ different numbers of nodes by shaping the connectivity array to accommodate
+ the face with the most nodes, then masking unused node 'slots'
+ (black circles) for faces with fewer nodes than the maximum.
+
+Data can be assigned to lines (edges) just as easily as points (nodes) or
+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
+ :width: 300
+
+ Data can be assigned to mesh edges
+
+ The 2D connectivity array (blue circles) describes edges by connecting 2
+ nodes (pink crosses) to make up an edge (blue lines). Data can be assigned
+ to the edges (orange lines) by matching the indices of the 1D data array
+ (not shown) to the indices in the connectivity array.
+
+.. _ugrid implications:
+
+What does this mean?
+--------------------
+Meshes can represent much more varied spatial arrangements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The highly specific way of recording position (geometry) and shape
+(topology) allows meshes to represent essentially **any** spatial arrangement
+of data. There are therefore many new applications that aren't possible using a
+structured grid, including:
+
+* `The UK Met Office's LFRic cubed-sphere `_
+* `Oceanic model outputs `_
+
+.. todo:
+ a third example!
+
+Mesh 'payload' is much larger than with structured grids
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Coordinates are recorded per-node, and connectivities are recorded per-element.
+This is opposed to a structured grid, where a single coordinate value is shared
+by every data point/area along that line.
+
+For example: representing the surface of a cubed-sphere using a mesh leads to
+coordinates and connectivities being **~8 times larger than the data itself**,
+as opposed to a small fraction of the data size when dividing a spherical
+surface using a structured grid of longitudes and latitudes.
+
+This further increases the emphasis on lazy loading and processing of data
+using packages such as Dask.
+
+.. note::
+
+ The large, 1D data arrays associated with meshes are a very different
+ shape to what Iris users and developers are used to. It is suspected
+ that optimal performance will need new chunking strategies, but at time
+ of writing (``Jan 2022``) experience is still limited.
+
+.. todo:
+ Revisit when we have more information.
+
+Spatial operations on mesh data are more complex
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Detail: :doc:`operations`
+
+Indexing a mesh data array cannot be used for:
+
+#. Region selection
+#. Neighbour identification
+
+This is because - unlike with a structured data array - relative position in
+a mesh's 1-dimensional data arrays has no relation to relative position in
+space. We must instead perform specialised operations using the information in
+the mesh's connectivities, or by translating the mesh into a format designed
+for mesh analysis such as VTK.
+
+Such calculations can still be optimised to avoid them slowing workflows, but
+the important take-away here is that **adaptation is needed when working mesh
+data**.
+
+
+How Iris Represents This
+========================
+
+..
+ Include API links to the various classes
+
+ Include Cube/Mesh printout(s)
+
+.. seealso::
+
+ Remember this is a prose summary. Precise documentation is at:
+ :mod:`iris.experimental.ugrid`.
+
+.. note::
+
+ At time of writing (``Jan 2022``), neither 3D meshes nor 3D elements
+ (volumes) are supported.
+
+The Basics
+----------
+The Iris :class:`~iris.cube.Cube` has several new members:
+
+* | :attr:`~iris.cube.Cube.mesh`
+ | The :class:`iris.experimental.ugrid.Mesh` that describes the
+ :class:`~iris.cube.Cube`\'s horizontal geography.
+* | :attr:`~iris.cube.Cube.location`
+ | ``node``/``edge``/``face`` - the mesh element type with which this
+ :class:`~iris.cube.Cube`\'s :attr:`~iris.cube.Cube.data` is associated.
+* | :meth:`~iris.cube.Cube.mesh_dim`
+ | The :class:`~iris.cube.Cube`\'s **unstructured dimension** - the one that
+ indexes over the horizontal :attr:`~iris.cube.Cube.data` positions.
+
+These members will all be ``None`` for a :class:`~iris.cube.Cube` with no
+associated :class:`~iris.experimental.ugrid.Mesh`.
+
+This :class:`~iris.cube.Cube`\'s unstructured dimension has multiple attached
+:class:`iris.experimental.ugrid.MeshCoord`\s (one for each axis e.g.
+``x``/``y``), which can be used to infer the points and bounds of any index on
+the :class:`~iris.cube.Cube`\'s unstructured dimension.
+
+.. testsetup:: ugrid_summaries
+
+ import numpy as np
+
+ from iris.coords import AuxCoord, DimCoord
+ from iris.cube import Cube
+ from iris.experimental.ugrid import Connectivity, Mesh
+
+ node_x = AuxCoord(
+ points=[0.0, 5.0, 0.0, 5.0, 8.0],
+ standard_name="longitude",
+ units="degrees_east",
+ )
+ node_y = AuxCoord(
+ points=[3.0, 3.0, 0.0, 0.0, 0.0],
+ standard_name="latitude",
+ units="degrees_north",
+ )
+
+ edge_node_c = Connectivity(
+ indices=[[0, 1], [0, 2], [1, 3], [1, 4], [2, 3], [3, 4]],
+ cf_role="edge_node_connectivity",
+ )
+
+ face_indices = np.ma.masked_equal([[0, 1, 3, 2], [1, 4, 3, 999]], 999)
+ face_node_c = Connectivity(
+ indices=face_indices, cf_role="face_node_connectivity"
+ )
+
+ def centre_coords(conn):
+ indexing = np.ma.filled(conn.indices, 0)
+ x, y = [
+ AuxCoord(
+ node_coord.points[indexing].mean(axis=conn.connected_axis),
+ node_coord.standard_name,
+ units=node_coord.units,
+ )
+ for node_coord in (node_x, node_y)
+ ]
+ return [(x, "x"), (y, "y")]
+
+ my_mesh = Mesh(
+ long_name="my_mesh",
+ topology_dimension=2,
+ node_coords_and_axes=[(node_x, "x"), (node_y, "y")],
+ connectivities=[edge_node_c, face_node_c],
+ edge_coords_and_axes=centre_coords(edge_node_c),
+ face_coords_and_axes=centre_coords(face_node_c),
+ )
+
+ vertical_levels = DimCoord([0, 1, 2], "height")
+
+ def location_cube(conn):
+ location = conn.location
+ mesh_coord_x, mesh_coord_y = my_mesh.to_MeshCoords(location)
+ data_shape = (conn.shape[conn.location_axis], len(vertical_levels.points))
+ data_array = np.arange(np.prod(data_shape)).reshape(data_shape)
+
+ return Cube(
+ data=data_array,
+ long_name=f"{location}_data",
+ units="K",
+ dim_coords_and_dims=[(vertical_levels, 1)],
+ aux_coords_and_dims=[(mesh_coord_x, 0), (mesh_coord_y, 0)],
+ )
+
+ edge_cube = location_cube(edge_node_c)
+ face_cube = location_cube(face_node_c)
+
+.. doctest:: ugrid_summaries
+
+ >>> print(edge_cube)
+ edge_data / (K) (-- : 6; height: 3)
+ Dimension coordinates:
+ height - x
+ Mesh coordinates:
+ latitude x -
+ longitude x -
+
+ >>> print(edge_cube.location)
+ edge
+
+ >>> print(edge_cube.mesh_dim())
+ 0
+
+ >>> print(edge_cube.mesh.summary(shorten=True))
+
+
+The Detail
+----------
+How UGRID information is stored
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* | :class:`iris.experimental.ugrid.Mesh`
+ | Contains all information about the mesh.
+ | Includes:
+
+ * | :attr:`~iris.experimental.ugrid.Mesh.topology_dimension`
+ | The maximum dimensionality of shape (1D=edge, 2D=face) supported
+ by this :class:`~iris.experimental.ugrid.Mesh`. Determines which
+ :class:`~iris.experimental.ugrid.Connectivity`\s are required/optional
+ (see below).
+
+ * 1-3 collections of :class:`iris.coords.AuxCoord`\s:
+
+ * | **Required**: :attr:`~iris.experimental.ugrid.Mesh.node_coords`
+ | The nodes that are the basis for the mesh.
+ * | Optional: :attr:`~iris.experimental.ugrid.Mesh.edge_coords`,
+ :attr:`~iris.experimental.ugrid.Mesh.face_coords`
+ | For indicating the 'centres' of the edges/faces.
+ | **NOTE:** generating a :class:`~iris.experimental.ugrid.MeshCoord` from
+ a :class:`~iris.experimental.ugrid.Mesh` currently (``Jan 2022``)
+ requires centre coordinates for the given ``location``; to be rectified
+ in future.
+
+ * 1 or more :class:`iris.experimental.ugrid.Connectivity`\s:
+
+ * | **Required for 1D (edge) elements**:
+ :attr:`~iris.experimental.ugrid.Mesh.edge_node_connectivity`
+ | Define the edges by connecting nodes.
+ * | **Required for 2D (face) elements**:
+ :attr:`~iris.experimental.ugrid.Mesh.face_node_connectivity`
+ | Define the faces by connecting nodes.
+ * Optional: any other connectivity type. See
+ :attr:`iris.experimental.ugrid.mesh.Connectivity.UGRID_CF_ROLES` for the
+ full list of types.
+
+.. doctest:: ugrid_summaries
+
+ >>> print(edge_cube.mesh)
+ Mesh : 'my_mesh'
+ topology_dimension: 2
+ node
+ node_dimension: 'Mesh2d_node'
+ node coordinates
+
+
+ edge
+ edge_dimension: 'Mesh2d_edge'
+ edge_node_connectivity:
+ edge coordinates
+
+
+ face
+ face_dimension: 'Mesh2d_face'
+ face_node_connectivity:
+ face coordinates
+
+
+ long_name: 'my_mesh'
+
+* | :class:`iris.experimental.ugrid.MeshCoord`
+ | Described in detail in `MeshCoords`_.
+ | Stores the following information:
+
+ * | :attr:`~iris.experimental.ugrid.MeshCoord.mesh`
+ | The :class:`~iris.experimental.ugrid.Mesh` associated with this
+ :class:`~iris.experimental.ugrid.MeshCoord`. This determines the
+ :attr:`~iris.cube.Cube.mesh` attribute of any :class:`~iris.cube.Cube`
+ this :class:`~iris.experimental.ugrid.MeshCoord` is attached to (see
+ `The Basics`_)
+
+ * | :attr:`~iris.experimental.ugrid.MeshCoord.location`
+ | ``node``/``edge``/``face`` - the element detailed by this
+ :class:`~iris.experimental.ugrid.MeshCoord`. This determines the
+ :attr:`~iris.cube.Cube.location` attribute of any
+ :class:`~iris.cube.Cube` this
+ :class:`~iris.experimental.ugrid.MeshCoord` is attached to (see
+ `The Basics`_).
+
+.. _ugrid MeshCoords:
+
+MeshCoords
+~~~~~~~~~~
+Links a :class:`~iris.cube.Cube` to a :class:`~iris.experimental.ugrid.Mesh` by
+attaching to the :class:`~iris.cube.Cube`\'s unstructured dimension, in the
+same way that all :class:`~iris.coords.Coord`\s attach to
+:class:`~iris.cube.Cube` dimensions. This allows a single
+:class:`~iris.cube.Cube` to have a combination of unstructured and structured
+dimensions (e.g. horizontal mesh plus vertical levels and a time series),
+using the same logic for every dimension.
+
+:class:`~iris.experimental.ugrid.MeshCoord`\s are instantiated using a given
+:class:`~iris.experimental.ugrid.Mesh`, ``location``
+("node"/"edge"/"face") and ``axis``. The process interprets the
+:class:`~iris.experimental.ugrid.Mesh`\'s
+:attr:`~iris.experimental.ugrid.Mesh.node_coords` and if appropriate the
+:attr:`~iris.experimental.ugrid.Mesh.edge_node_connectivity`/
+:attr:`~iris.experimental.ugrid.Mesh.face_node_connectivity` and
+:attr:`~iris.experimental.ugrid.Mesh.edge_coords`/
+:attr:`~iris.experimental.ugrid.Mesh.face_coords`
+to produce a :class:`~iris.coords.Coord`
+:attr:`~iris.coords.Coord.points` and :attr:`~iris.coords.Coord.bounds`
+representation of all the :class:`~iris.experimental.ugrid.Mesh`\'s
+nodes/edges/faces for the given axis.
+
+The method :meth:`iris.experimental.ugrid.Mesh.to_MeshCoords` is available to
+create a :class:`~iris.experimental.ugrid.MeshCoord` for
+every axis represented by that :class:`~iris.experimental.ugrid.Mesh`,
+given only the ``location`` argument
+
+.. doctest:: ugrid_summaries
+
+ >>> for coord in edge_cube.coords(mesh_coords=True):
+ ... print(coord)
+ MeshCoord : latitude / (degrees_north)
+ mesh:
+ location: 'edge'
+ points: [3. , 1.5, 1.5, 1.5, 0. , 0. ]
+ bounds: [
+ [3., 3.],
+ [3., 0.],
+ [3., 0.],
+ [3., 0.],
+ [0., 0.],
+ [0., 0.]]
+ shape: (6,) bounds(6, 2)
+ dtype: float64
+ standard_name: 'latitude'
+ axis: 'y'
+ MeshCoord : longitude / (degrees_east)
+ mesh:
+ location: 'edge'
+ points: [2.5, 0. , 5. , 6.5, 2.5, 6.5]
+ bounds: [
+ [0., 5.],
+ [0., 0.],
+ [5., 5.],
+ [5., 8.],
+ [0., 5.],
+ [5., 8.]]
+ shape: (6,) bounds(6, 2)
+ dtype: float64
+ standard_name: 'longitude'
+ axis: 'x'
+
+
+__ CF-UGRID_
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/data_structured_grid.svg b/docs/src/further_topics/ugrid/images/data_structured_grid.svg
new file mode 100644
index 00000000000..2f3a1ce342a
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/data_structured_grid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/data_ugrid_mesh.svg b/docs/src/further_topics/ugrid/images/data_ugrid_mesh.svg
new file mode 100644
index 00000000000..ab7302346b7
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/data_ugrid_mesh.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/geovistalogo.svg b/docs/src/further_topics/ugrid/images/geovistalogo.svg
new file mode 100644
index 00000000000..4c68f0ee3ff
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/geovistalogo.svg
@@ -0,0 +1,573 @@
+
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/iris-esmf-regrid.svg b/docs/src/further_topics/ugrid/images/iris-esmf-regrid.svg
new file mode 100644
index 00000000000..e70a9386a7f
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/iris-esmf-regrid.svg
@@ -0,0 +1,93 @@
+
+
+
+
diff --git a/docs/src/further_topics/ugrid/images/plotting_basic.png b/docs/src/further_topics/ugrid/images/plotting_basic.png
new file mode 100644
index 00000000000..ba2b0b3329d
Binary files /dev/null and b/docs/src/further_topics/ugrid/images/plotting_basic.png differ
diff --git a/docs/src/further_topics/ugrid/images/plotting_global.png b/docs/src/further_topics/ugrid/images/plotting_global.png
new file mode 100644
index 00000000000..62fb56d9749
Binary files /dev/null and b/docs/src/further_topics/ugrid/images/plotting_global.png differ
diff --git a/docs/src/further_topics/ugrid/images/ugrid_edge_data.svg b/docs/src/further_topics/ugrid/images/ugrid_edge_data.svg
new file mode 100644
index 00000000000..374ef573880
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/ugrid_edge_data.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/ugrid_element_centres.svg b/docs/src/further_topics/ugrid/images/ugrid_element_centres.svg
new file mode 100644
index 00000000000..13b885d6005
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/ugrid_element_centres.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/ugrid_node_independence.svg b/docs/src/further_topics/ugrid/images/ugrid_node_independence.svg
new file mode 100644
index 00000000000..ba72c42ffaf
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/ugrid_node_independence.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/images/ugrid_variable_faces.svg b/docs/src/further_topics/ugrid/images/ugrid_variable_faces.svg
new file mode 100644
index 00000000000..378978abc39
--- /dev/null
+++ b/docs/src/further_topics/ugrid/images/ugrid_variable_faces.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/further_topics/ugrid/index.rst b/docs/src/further_topics/ugrid/index.rst
new file mode 100644
index 00000000000..81ba24428a9
--- /dev/null
+++ b/docs/src/further_topics/ugrid/index.rst
@@ -0,0 +1,54 @@
+.. include:: ../../common_links.inc
+
+.. _ugrid:
+
+Mesh Support
+************
+
+Iris includes specialised handling of mesh-located data (as opposed to
+grid-located data). Iris and its :ref:`partner packages ` are
+designed to make working with mesh-located data as simple as possible, with new
+capabilities being added all the time. More detail is in this section and in
+the :mod:`iris.experimental.ugrid` API documentation.
+
+This mesh support is based on the `CF-UGRID Conventions`__; UGRID-conformant
+meshes + data can be loaded from a file into Iris' data model, and meshes +
+data represented in Iris' data model can be saved as a UGRID-conformant file.
+
+----
+
+Meshes are different
+ Mesh-located data is fundamentally different to grid-located data.
+ Many of Iris' existing operations need adapting before they can work with
+ mesh-located data, and in some cases entirely new concepts are needed.
+ **Read the detail in these pages before jumping into your own code.**
+Iris' mesh support is experimental
+ This is a rapidly evolving part of the codebase at time of writing
+ (``Jan 2022``), as we continually expand the operations that work with mesh
+ data. **Be prepared for breaking changes even in minor releases.**
+:ref:`Get involved! `
+ We know meshes are an exciting new area for much of Earth science, so we hope
+ there are a lot of you with new files/ideas/wishlists, and we'd love to hear
+ more 🙂.
+
+----
+
+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.
+
+..
+ Need an actual TOC to get Sphinx working properly, but have hidden it in
+ favour of the custom bullets above.
+
+.. toctree::
+ :hidden:
+ :maxdepth: 1
+
+ data_model
+ partner_packages
+ operations
+
+__ CF-UGRID_
diff --git a/docs/src/further_topics/ugrid/operations.rst b/docs/src/further_topics/ugrid/operations.rst
new file mode 100644
index 00000000000..f96e3e406c9
--- /dev/null
+++ b/docs/src/further_topics/ugrid/operations.rst
@@ -0,0 +1,995 @@
+.. _ugrid operations:
+
+Working with Mesh Data
+**********************
+
+.. note:: Several of the operations below rely on the optional dependencies
+ mentioned in :doc:`partner_packages`.
+
+Operations Summary
+------------------
+.. list-table::
+ :align: left
+ :widths: 35, 75
+
+ * - `Making a Mesh`_
+ - |tagline: making a mesh|
+ * - `Making a Cube`_
+ - |tagline: making a cube|
+ * - `Save`_
+ - |tagline: save|
+ * - `Load`_
+ - |tagline: load|
+ * - `Plotting`_
+ - |tagline: plotting|
+ * - `Region Extraction`_
+ - |tagline: region extraction|
+ * - `Regridding`_
+ - |tagline: regridding|
+ * - `Equality`_
+ - |tagline: equality|
+ * - `Combining Cubes`_
+ - |tagline: combining cubes|
+ * - `Arithmetic`_
+ - |tagline: arithmetic|
+
+..
+ Below: use demo code over prose wherever workable. Headings aren't an
+ exhaustive list (can you think of any other popular operations?).
+
+Making a Mesh
+-------------
+.. |tagline: making a mesh| replace:: |new|
+
+.. rubric:: |tagline: making a mesh|
+
+**Already have a file?** Consider skipping to `Load`_.
+
+Creating Iris objects from scratch is a highly useful skill for testing code
+and improving understanding of how Iris works. This knowledge will likely prove
+particularly useful when converting data into the Iris mesh data model from
+structured formats and non-UGRID mesh formats.
+
+The objects created in this example will be used where possible in the
+subsequent example operations on this page.
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> import numpy as np
+
+ >>> from iris.coords import AuxCoord
+ >>> from iris.experimental.ugrid import Connectivity, Mesh
+
+ # Going to create the following mesh
+ # (node indices are shown to aid understanding):
+ #
+ # 0----1
+ # | |\
+ # | + |+\
+ # 2----3--4
+
+ >>> node_x = AuxCoord(
+ ... points=[0.0, 5.0, 0.0, 5.0, 8.0],
+ ... standard_name="longitude",
+ ... units="degrees_east",
+ ... long_name="node_x_coordinates",
+ ... )
+ >>> node_y = AuxCoord(points=[3.0, 3.0, 0.0, 0.0, 0.0], standard_name="latitude")
+
+ >>> face_x = AuxCoord([2.0, 6.0], "longitude")
+ >>> face_y = AuxCoord([1.0, 1.0], "latitude")
+
+ >>> edge_node_c = Connectivity(
+ ... indices=[[0, 1], [0, 2], [1, 3], [1, 4], [2, 3], [3, 4]],
+ ... cf_role="edge_node_connectivity",
+ ... attributes={"demo": "Supports every standard CF property"},
+ ... )
+
+ # Create some dead-centre edge coordinates.
+ >>> edge_x, edge_y = [
+ ... AuxCoord(
+ ... node_coord.points[edge_node_c.indices_by_location()].mean(axis=1),
+ ... node_coord.standard_name,
+ ... )
+ ... for node_coord in (node_x, node_y)
+ ... ]
+
+ >>> face_indices = np.ma.masked_equal([[0, 1, 3, 2], [1, 4, 3, 999]], 999)
+ >>> face_node_c = Connectivity(
+ ... indices=face_indices, cf_role="face_node_connectivity"
+ ... )
+
+ >>> my_mesh = Mesh(
+ ... long_name="my_mesh",
+ ... topology_dimension=2, # Supports 2D (face) elements.
+ ... node_coords_and_axes=[(node_x, "x"), (node_y, "y")],
+ ... connectivities=[edge_node_c, face_node_c],
+ ... edge_coords_and_axes=[(edge_x, "x"), (edge_y, "y")],
+ ... face_coords_and_axes=[(face_x, "x"), (face_y, "y")],
+ ... )
+
+ >>> print(my_mesh)
+ Mesh : 'my_mesh'
+ topology_dimension: 2
+ node
+ node_dimension: 'Mesh2d_node'
+ node coordinates
+
+
+ edge
+ edge_dimension: 'Mesh2d_edge'
+ edge_node_connectivity:
+ edge coordinates
+
+
+ face
+ face_dimension: 'Mesh2d_face'
+ face_node_connectivity:
+ face coordinates
+
+
+ long_name: 'my_mesh'
+
+
+.. _making a cube:
+
+Making a Cube (with a Mesh)
+---------------------------
+.. |tagline: making a cube| replace:: |unchanged|
+
+.. rubric:: |tagline: making a cube|
+
+Creating a :class:`~iris.cube.Cube` is unchanged; the
+:class:`~iris.experimental.ugrid.Mesh` is linked via a
+:class:`~iris.experimental.ugrid.MeshCoord` (see :ref:`ugrid MeshCoords`):
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> import numpy as np
+
+ >>> from iris.coords import DimCoord
+ >>> from iris.cube import Cube, CubeList
+
+ >>> vertical_levels = DimCoord([0, 1, 2], "height")
+
+ >>> my_cubelist = CubeList()
+ >>> for conn in (edge_node_c, face_node_c):
+ ... location = conn.location
+ ... mesh_coord_x, mesh_coord_y = my_mesh.to_MeshCoords(location)
+ ... data_shape = (len(conn.indices_by_location()), len(vertical_levels.points))
+ ... data_array = np.arange(np.prod(data_shape)).reshape(data_shape)
+ ...
+ ... my_cubelist.append(
+ ... Cube(
+ ... data=data_array,
+ ... long_name=f"{location}_data",
+ ... units="K",
+ ... dim_coords_and_dims=[(vertical_levels, 1)],
+ ... aux_coords_and_dims=[(mesh_coord_x, 0), (mesh_coord_y, 0)],
+ ... )
+ ... )
+
+ >>> print(my_cubelist)
+ 0: edge_data / (K) (-- : 6; height: 3)
+ 1: face_data / (K) (-- : 2; height: 3)
+
+ >>> for cube in my_cubelist:
+ ... print(f"{cube.name()}: {cube.mesh.name()}, {cube.location}")
+ edge_data: my_mesh, edge
+ face_data: my_mesh, face
+
+ >>> print(my_cubelist.extract_cube("edge_data"))
+ edge_data / (K) (-- : 6; height: 3)
+ Dimension coordinates:
+ height - x
+ Mesh coordinates:
+ latitude x -
+ longitude x -
+
+
+Save
+----
+.. |tagline: save| replace:: |unchanged|
+
+.. rubric:: |tagline: save|
+
+.. note:: UGRID saving support is limited to the NetCDF file format.
+
+The Iris saving process automatically detects if the :class:`~iris.cube.Cube`
+has an associated :class:`~iris.experimental.ugrid.Mesh` and automatically
+saves the file in a UGRID-conformant format:
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> from subprocess import run
+
+ >>> from iris import save
+
+ >>> cubelist_path = "my_cubelist.nc"
+ >>> save(my_cubelist, cubelist_path)
+
+ >>> ncdump_result = run(["ncdump", "-h", cubelist_path], capture_output=True)
+ >>> print(ncdump_result.stdout.decode().replace("\t", " "))
+ netcdf my_cubelist {
+ dimensions:
+ Mesh2d_node = 5 ;
+ Mesh2d_edge = 6 ;
+ Mesh2d_face = 2 ;
+ height = 3 ;
+ my_mesh_face_N_nodes = 4 ;
+ my_mesh_edge_N_nodes = 2 ;
+ variables:
+ int my_mesh ;
+ my_mesh:cf_role = "mesh_topology" ;
+ my_mesh:topology_dimension = 2 ;
+ my_mesh:long_name = "my_mesh" ;
+ my_mesh:node_coordinates = "longitude latitude" ;
+ my_mesh:edge_coordinates = "longitude_0 latitude_0" ;
+ my_mesh:face_coordinates = "longitude_1 latitude_1" ;
+ my_mesh:face_node_connectivity = "mesh2d_face" ;
+ my_mesh:edge_node_connectivity = "mesh2d_edge" ;
+ double longitude(Mesh2d_node) ;
+ longitude:units = "degrees_east" ;
+ longitude:standard_name = "longitude" ;
+ longitude:long_name = "node_x_coordinates" ;
+ double latitude(Mesh2d_node) ;
+ latitude:standard_name = "latitude" ;
+ double longitude_0(Mesh2d_edge) ;
+ longitude_0:standard_name = "longitude" ;
+ double latitude_0(Mesh2d_edge) ;
+ latitude_0:standard_name = "latitude" ;
+ double longitude_1(Mesh2d_face) ;
+ longitude_1:standard_name = "longitude" ;
+ double latitude_1(Mesh2d_face) ;
+ latitude_1:standard_name = "latitude" ;
+ int64 mesh2d_face(Mesh2d_face, my_mesh_face_N_nodes) ;
+ mesh2d_face:_FillValue = -1LL ;
+ mesh2d_face:cf_role = "face_node_connectivity" ;
+ mesh2d_face:start_index = 0LL ;
+ int64 mesh2d_edge(Mesh2d_edge, my_mesh_edge_N_nodes) ;
+ mesh2d_edge:demo = "Supports every standard CF property" ;
+ mesh2d_edge:cf_role = "edge_node_connectivity" ;
+ mesh2d_edge:start_index = 0LL ;
+ int64 edge_data(Mesh2d_edge, height) ;
+ edge_data:long_name = "edge_data" ;
+ edge_data:units = "K" ;
+ edge_data:mesh = "my_mesh" ;
+ edge_data:location = "edge" ;
+ int64 height(height) ;
+ height:standard_name = "height" ;
+ int64 face_data(Mesh2d_face, height) ;
+ face_data:long_name = "face_data" ;
+ face_data:units = "K" ;
+ face_data:mesh = "my_mesh" ;
+ face_data:location = "face" ;
+
+ // global attributes:
+ :Conventions = "CF-1.7" ;
+ }
+
+
+The :func:`iris.experimental.ugrid.save_mesh` function allows
+:class:`~iris.experimental.ugrid.Mesh`\es to be saved to file without
+associated :class:`~iris.cube.Cube`\s:
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> from subprocess import run
+
+ >>> from iris.experimental.ugrid import save_mesh
+
+ >>> mesh_path = "my_mesh.nc"
+ >>> save_mesh(my_mesh, mesh_path)
+
+ >>> ncdump_result = run(["ncdump", "-h", mesh_path], capture_output=True)
+ >>> print(ncdump_result.stdout.decode().replace("\t", " "))
+ netcdf my_mesh {
+ dimensions:
+ Mesh2d_node = 5 ;
+ Mesh2d_edge = 6 ;
+ Mesh2d_face = 2 ;
+ my_mesh_face_N_nodes = 4 ;
+ my_mesh_edge_N_nodes = 2 ;
+ variables:
+ int my_mesh ;
+ my_mesh:cf_role = "mesh_topology" ;
+ my_mesh:topology_dimension = 2 ;
+ my_mesh:long_name = "my_mesh" ;
+ my_mesh:node_coordinates = "longitude latitude" ;
+ my_mesh:edge_coordinates = "longitude_0 latitude_0" ;
+ my_mesh:face_coordinates = "longitude_1 latitude_1" ;
+ my_mesh:face_node_connectivity = "mesh2d_face" ;
+ my_mesh:edge_node_connectivity = "mesh2d_edge" ;
+ double longitude(Mesh2d_node) ;
+ longitude:units = "degrees_east" ;
+ longitude:standard_name = "longitude" ;
+ longitude:long_name = "node_x_coordinates" ;
+ double latitude(Mesh2d_node) ;
+ latitude:standard_name = "latitude" ;
+ double longitude_0(Mesh2d_edge) ;
+ longitude_0:standard_name = "longitude" ;
+ double latitude_0(Mesh2d_edge) ;
+ latitude_0:standard_name = "latitude" ;
+ double longitude_1(Mesh2d_face) ;
+ longitude_1:standard_name = "longitude" ;
+ double latitude_1(Mesh2d_face) ;
+ latitude_1:standard_name = "latitude" ;
+ int64 mesh2d_face(Mesh2d_face, my_mesh_face_N_nodes) ;
+ mesh2d_face:_FillValue = -1LL ;
+ mesh2d_face:cf_role = "face_node_connectivity" ;
+ mesh2d_face:start_index = 0LL ;
+ int64 mesh2d_edge(Mesh2d_edge, my_mesh_edge_N_nodes) ;
+ mesh2d_edge:demo = "Supports every standard CF property" ;
+ mesh2d_edge:cf_role = "edge_node_connectivity" ;
+ mesh2d_edge:start_index = 0LL ;
+
+ // global attributes:
+ :Conventions = "CF-1.7" ;
+ }
+
+
+Load
+----
+.. |tagline: load| replace:: |different| - UGRID parsing is opt-in
+
+.. rubric:: |tagline: load|
+
+.. note:: UGRID loading support is limited to the NetCDF file format.
+
+While Iris' UGRID support remains :mod:`~iris.experimental`, parsing UGRID when
+loading a file remains **optional**. To load UGRID data from a file into the
+Iris mesh data model, use the
+:const:`iris.experimental.ugrid.PARSE_UGRID_ON_LOAD` context manager:
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> from iris import load
+ >>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
+
+ >>> with PARSE_UGRID_ON_LOAD.context():
+ ... loaded_cubelist = load(cubelist_path)
+
+ # Sort CubeList to ensure consistent result.
+ >>> loaded_cubelist.sort(key=lambda cube: cube.name())
+ >>> print(loaded_cubelist)
+ 0: edge_data / (K) (-- : 6; height: 3)
+ 1: face_data / (K) (-- : 2; height: 3)
+
+All the existing loading functionality still operates on UGRID-compliant
+data - :class:`~iris.Constraint`\s, callbacks, :func:`~iris.load_cube`
+etcetera:
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> from iris import Constraint, load_cube
+
+ >>> with PARSE_UGRID_ON_LOAD.context():
+ ... ground_cubelist = load(cubelist_path, Constraint(height=0))
+ ... face_cube = load_cube(cubelist_path, "face_data")
+
+ # Sort CubeList to ensure consistent result.
+ >>> ground_cubelist.sort(key=lambda cube: cube.name())
+ >>> print(ground_cubelist)
+ 0: edge_data / (K) (-- : 6)
+ 1: face_data / (K) (-- : 2)
+
+ >>> print(face_cube)
+ face_data / (K) (-- : 2; height: 3)
+ Dimension coordinates:
+ height - x
+ Mesh coordinates:
+ latitude x -
+ longitude x -
+ Attributes:
+ Conventions 'CF-1.7'
+
+.. note::
+
+ We recommend caution if constraining on coordinates associated with a
+ :class:`~iris.experimental.ugrid.Mesh`. An individual coordinate value
+ might not be shared by any other data points, and using a coordinate range
+ will demand notably higher performance given the size of the dimension
+ versus structured grids
+ (:ref:`see the data model detail `).
+
+The :func:`iris.experimental.ugrid.load_mesh` and
+:func:`~iris.experimental.ugrid.load_meshes` functions allow only
+:class:`~iris.experimental.ugrid.Mesh`\es to be loaded from a file without
+creating any associated :class:`~iris.cube.Cube`\s:
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> from iris.experimental.ugrid import load_mesh
+
+ >>> with PARSE_UGRID_ON_LOAD.context():
+ ... loaded_mesh = load_mesh(cubelist_path)
+
+ >>> print(loaded_mesh)
+ Mesh : 'my_mesh'
+ topology_dimension: 2
+ node
+ node_dimension: 'Mesh2d_node'
+ node coordinates
+ shape(5,)>
+ shape(5,)>
+ edge
+ edge_dimension: 'Mesh2d_edge'
+ edge_node_connectivity: shape(6, 2)>
+ edge coordinates
+ shape(6,)>
+ shape(6,)>
+ face
+ face_dimension: 'Mesh2d_face'
+ face_node_connectivity: shape(2, 4)>
+ face coordinates
+ shape(2,)>
+ shape(2,)>
+ long_name: 'my_mesh'
+ var_name: 'my_mesh'
+
+Plotting
+--------
+.. |tagline: plotting| replace:: |different| - plot with GeoVista
+
+.. rubric:: |tagline: plotting|
+
+The Cartopy-Matplotlib combination is not optimised for displaying the high
+number of irregular shapes associated with meshes. Thankfully mesh
+visualisation is already popular in many other fields (e.g. CGI, gaming,
+SEM microscopy), so there is a wealth of tooling available, which
+:ref:`ugrid geovista` harnesses for cartographic plotting.
+
+GeoVista's default behaviour is to convert lat-lon information into full XYZ
+coordinates so the data is visualised on the surface of a 3D globe. The plots
+are interactive by default, so it's easy to explore the data in detail.
+
+2D projections have also been demonstrated in proofs of concept, and will
+be added to API in the near future.
+
+This first example uses GeoVista to plot the ``face_cube`` that we created
+earlier:
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> from geovista import GeoPlotter, Transform
+ >>> from geovista.common import to_xyz
+
+
+ # We'll re-use this to plot some real global data later.
+ >>> def cube_faces_to_polydata(cube):
+ ... lons, lats = cube.mesh.node_coords
+ ... face_node = cube.mesh.face_node_connectivity
+ ... indices = face_node.indices_by_location()
+ ...
+ ... mesh = Transform.from_unstructured(
+ ... lons.points,
+ ... lats.points,
+ ... indices,
+ ... data=cube.data,
+ ... name=f"{cube.name()} / {cube.units}",
+ ... start_index=face_node.start_index,
+ ... )
+ ... return mesh
+
+ >>> print(face_cube)
+ face_data / (K) (-- : 2; height: 3)
+ Dimension coordinates:
+ height - x
+ Mesh coordinates:
+ latitude x -
+ longitude x -
+ Attributes:
+ Conventions 'CF-1.7'
+
+ # Convert our mesh+data to a PolyData object.
+ # Just plotting a single height level.
+ >>> face_polydata = cube_faces_to_polydata(face_cube[:, 0])
+ >>> print(face_polydata)
+ PolyData (0x7ff4861ff4c0)
+ N Cells: 2
+ N Points: 5
+ X Bounds: 9.903e-01, 1.000e+00
+ Y Bounds: 0.000e+00, 1.392e-01
+ Z Bounds: 6.123e-17, 5.234e-02
+ N Arrays: 2
+
+ # Create the GeoVista plotter and add our mesh+data to it.
+ >>> my_plotter = GeoPlotter()
+ >>> my_plotter.add_coastlines(color="black")
+ >>> my_plotter.add_base_layer(color="grey")
+ >>> my_plotter.add_mesh(face_polydata)
+
+ # Centre the camera on the data.
+ >>> camera_region = to_xyz(
+ ... face_cube.coord("longitude").points,
+ ... face_cube.coord("latitude").points,
+ ... radius=3,
+ ... )
+ >>> camera_pos = camera_region.mean(axis=0)
+ >>> my_plotter.camera.position = camera_pos
+
+ >>> my_plotter.show()
+
+ .. image:: images/plotting_basic.png
+ :alt: A GeoVista plot of the basic example Mesh.
+
+ This artificial data makes West Africa rather chilly!
+
+Here's another example using a global cubed-sphere data set:
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> from iris import load_cube
+ >>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
+
+ # Demonstrating with a global data set.
+ # You could also download this file from github.com/SciTools/iris-test-data.
+ >>> from iris.tests import get_data_path
+ >>> file_path = get_data_path(
+ ... [
+ ... "NetCDF",
+ ... "unstructured_grid",
+ ... "lfric_surface_mean.nc",
+ ... ]
+ ... )
+ >>> with PARSE_UGRID_ON_LOAD.context():
+ ... global_cube = load_cube(file_path, "tstar_sea")
+ >>> print(global_cube)
+ sea_surface_temperature / (K) (-- : 1; -- : 13824)
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Auxiliary coordinates:
+ time x -
+ Cell methods:
+ mean time (300 s)
+ mean time_counter
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 1 d
+ name lfric_surface
+ online_operation average
+ timeStamp 2020-Feb-07 16:23:14 GMT
+ title Created by xios
+ uuid 489bcef5-3d1c-4529-be42-4ab5f8c8497b
+
+ >>> global_polydata = cube_faces_to_polydata(global_cube)
+ >>> print(global_polydata)
+ PolyData (0x7f761b536160)
+ N Cells: 13824
+ N Points: 13826
+ X Bounds: -1.000e+00, 1.000e+00
+ Y Bounds: -1.000e+00, 1.000e+00
+ Z Bounds: -1.000e+00, 1.000e+00
+ N Arrays: 2
+
+ >>> my_plotter = GeoPlotter()
+ >>> my_plotter.add_coastlines()
+ >>> my_plotter.add_mesh(global_polydata, show_edges=True)
+
+ >>> my_plotter.show()
+
+ .. image:: images/plotting_global.png
+ :alt: A GeoVista plot of a global sea surface temperature Mesh.
+
+Region Extraction
+-----------------
+.. |tagline: region extraction| replace:: |different| - use GeoVista for mesh analysis
+
+.. rubric:: |tagline: region extraction|
+
+As described in :doc:`data_model`, indexing for a range along a
+:class:`~iris.cube.Cube`\'s :meth:`~iris.cube.Cube.mesh_dim` will not provide
+a contiguous region, since **position on the unstructured dimension is
+unrelated to spatial position**. This means that subsetted
+:class:`~iris.experimental.ugrid.MeshCoord`\s cannot be reliably interpreted
+as intended, and subsetting a :class:`~iris.experimental.ugrid.MeshCoord` is
+therefore set to return an :class:`~iris.coords.AuxCoord` instead - breaking
+the link between :class:`~iris.cube.Cube` and
+:class:`~iris.experimental.ugrid.Mesh`:
+
+.. dropdown:: :opticon:`code`
+
+ .. doctest:: ugrid_operations
+
+ >>> edge_cube = my_cubelist.extract_cube("edge_data")
+ >>> print(edge_cube)
+ edge_data / (K) (-- : 6; height: 3)
+ Dimension coordinates:
+ height - x
+ Mesh coordinates:
+ latitude x -
+ longitude x -
+
+ # Sub-setted MeshCoords have become AuxCoords.
+ >>> print(edge_cube[:-1])
+ edge_data / (K) (-- : 5; height: 3)
+ Dimension coordinates:
+ height - x
+ Auxiliary coordinates:
+ latitude x -
+ longitude x -
+
+Extracting a region therefore requires extra steps - to determine the spatial
+position of the data points before they can be analysed as inside/outside the
+selected region. The recommended way to do this is using tools provided by
+:ref:`ugrid geovista`, which is optimised for performant mesh analysis.
+
+This approach centres around using :meth:`geovista.geodesic.BBox.enclosed` to
+get the subset of the original mesh that is inside the
+:class:`~geovista.geodesic.BBox`. This subset :class:`pyvista.PolyData` object
+includes the original indices of each datapoint - the ``vtkOriginalCellIds``
+array, which can be used to index the original :class:`~iris.cube.Cube`. Since
+we **know** that this subset :class:`~iris.cube.Cube` represents a regional
+mesh, we then reconstruct a :class:`~iris.experimental.ugrid.Mesh` from the
+:class:`~iris.cube.Cube`\'s :attr:`~iris.cube.Cube.aux_coords` using
+:meth:`iris.experimental.ugrid.Mesh.from_coords`:
+
+..
+ Not using doctest here as want to keep GeoVista as optional dependency.
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> from geovista import Transform
+ >>> from geovista.geodesic import BBox
+ >>> from iris import load_cube
+ >>> from iris.experimental.ugrid import Mesh, PARSE_UGRID_ON_LOAD
+
+ # Need a larger dataset to demonstrate this operation.
+ # You could also download this file from github.com/SciTools/iris-test-data.
+ >>> from iris.tests import get_data_path
+ >>> file_path = get_data_path(
+ ... [
+ ... "NetCDF",
+ ... "unstructured_grid",
+ ... "lfric_ngvat_2D_72t_face_half_levels_main_conv_rain.nc",
+ ... ]
+ ... )
+
+ >>> with PARSE_UGRID_ON_LOAD.context():
+ ... global_cube = load_cube(file_path, "conv_rain")
+ >>> print(global_cube)
+ surface_convective_rainfall_rate / (kg m-2 s-1) (-- : 72; -- : 864)
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Auxiliary coordinates:
+ time x -
+ Cell methods:
+ point time
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 300 s
+ name lfric_ngvat_2D_72t_face_half_levels_main_conv_rain
+ online_operation instant
+ timeStamp 2020-Oct-18 21:18:35 GMT
+ title Created by xios
+ uuid b3dc0fb4-9828-4663-a5ac-2a5763280159
+
+ # Convert the Mesh to a GeoVista PolyData object.
+ >>> lons, lats = global_cube.mesh.node_coords
+ >>> face_node = global_cube.mesh.face_node_connectivity
+ >>> indices = face_node.indices_by_location()
+ >>> global_polydata = Transform.from_unstructured(
+ ... lons.points, lats.points, indices, start_index=face_node.start_index
+ ... )
+
+ # Define a region of 4 corners connected by great circles.
+ # Specialised sub-classes of BBox are also available e.g. panel/wedge.
+ >>> region = BBox(lons=[0, 70, 70, 0], lats=[-25, -25, 45, 45])
+ # 'Apply' the region to the PolyData object.
+ >>> region_polydata = region.enclosed(global_polydata, preference="center")
+ # Get the remaining face indices, to use for indexing the Cube.
+ >>> indices = region_polydata["vtkOriginalCellIds"]
+
+ >>> print(type(indices))
+
+ # 101 is smaller than the original 864.
+ >>> print(len(indices))
+ 101
+ >>> print(indices[:10])
+ [ 6 7 8 9 10 11 18 19 20 21]
+
+ # Use the face indices to subset the global cube.
+ >>> region_cube = global_cube[:, indices]
+
+ # In this case we **know** the indices correspond to a contiguous
+ # region, so we will convert the sub-setted Cube back into a
+ # Cube-with-Mesh.
+ >>> new_mesh = Mesh.from_coords(*region_cube.coords(dimensions=1))
+ >>> new_mesh_coords = new_mesh.to_MeshCoords(global_cube.location)
+ >>> for coord in new_mesh_coords:
+ ... region_cube.remove_coord(coord.name())
+ ... region_cube.add_aux_coord(coord, 1)
+
+ # A Mesh-Cube with a subset (101) of the original 864 faces.
+ >>> print(region_cube)
+ surface_convective_rainfall_rate / (kg m-2 s-1) (-- : 72; -- : 101)
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Auxiliary coordinates:
+ time x -
+ Cell methods:
+ point time
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 300 s
+ name lfric_ngvat_2D_72t_face_half_levels_main_conv_rain
+ online_operation instant
+ timeStamp 2020-Oct-18 21:18:35 GMT
+ title Created by xios
+ uuid b3dc0fb4-9828-4663-a5ac-2a5763280159
+
+Regridding
+----------
+.. |tagline: regridding| replace:: |different| - use iris-esmf-regrid for mesh regridders
+
+.. rubric:: |tagline: regridding|
+
+Regridding to or from a mesh requires different logic than Iris' existing
+regridders, which are designed for structured grids. For this we recommend
+ESMF's powerful regridding tools, which integrate with Iris' mesh data model
+via the :ref:`ugrid iris-esmf-regrid` package.
+
+.. todo: inter-sphinx links when available.
+
+Regridding is achieved via the
+:class:`esmf_regrid.experimental.unstructured_scheme.MeshToGridESMFRegridder`
+and
+:class:`~esmf_regrid.experimental.unstructured_scheme.GridToMeshESMFRegridder`
+classes. Regridding from a source :class:`~iris.cube.Cube` to a target
+:class:`~iris.cube.Cube` involves initialising and then calling one of these
+classes. Initialising is done by passing in the source and target
+:class:`~iris.cube.Cube` as arguments. The regridder is then called by passing
+the source :class:`~iris.cube.Cube` as an argument. We can demonstrate this
+with the
+:class:`~esmf_regrid.experimental.unstructured_scheme.MeshToGridESMFRegridder`:
+
+..
+ Not using doctest here as want to keep iris-esmf-regrid as optional dependency.
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ >>> from esmf_regrid.experimental.unstructured_scheme import MeshToGridESMFRegridder
+ >>> from iris import load, load_cube
+ >>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
+
+ # You could also download these files from github.com/SciTools/iris-test-data.
+ >>> from iris.tests import get_data_path
+ >>> mesh_file = get_data_path(
+ ... ["NetCDF", "unstructured_grid", "lfric_surface_mean.nc"]
+ ... )
+ >>> grid_file = get_data_path(
+ ... ["NetCDF", "regrid", "regrid_template_global_latlon.nc"]
+ ... )
+
+ # Load a list of cubes defined on the same Mesh.
+ >>> with PARSE_UGRID_ON_LOAD.context():
+ ... mesh_cubes = load(mesh_file)
+
+ # Extract a specific cube.
+ >>> mesh_cube1 = mesh_cubes.extract_cube("sea_surface_temperature")
+ >>> print(mesh_cube1)
+ sea_surface_temperature / (K) (-- : 1; -- : 13824)
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Auxiliary coordinates:
+ time x -
+ Cell methods:
+ mean time (300 s)
+ mean time_counter
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 1 d
+ name lfric_surface
+ online_operation average
+ timeStamp 2020-Feb-07 16:23:14 GMT
+ title Created by xios
+ uuid 489bcef5-3d1c-4529-be42-4ab5f8c8497b
+
+ # Load the target grid.
+ >>> sample_grid = load_cube(grid_file)
+ >>> print(sample_grid)
+ sample_grid / (unknown) (latitude: 180; longitude: 360)
+ Dimension coordinates:
+ latitude x -
+ longitude - x
+ Attributes:
+ Conventions 'CF-1.7'
+
+ # Initialise the regridder.
+ >>> rg = MeshToGridESMFRegridder(mesh_cube1, sample_grid)
+
+ # Regrid the mesh cube cube.
+ >>> result1 = rg(mesh_cube1)
+ >>> print(result1)
+ sea_surface_temperature / (K) (-- : 1; latitude: 180; longitude: 360)
+ Dimension coordinates:
+ latitude - x -
+ longitude - - x
+ Auxiliary coordinates:
+ time x - -
+ Cell methods:
+ mean time (300 s)
+ mean time_counter
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 1 d
+ name lfric_surface
+ online_operation average
+ timeStamp 2020-Feb-07 16:23:14 GMT
+ title Created by xios
+ uuid 489bcef5-3d1c-4529-be42-4ab5f8c8497b
+
+.. note::
+
+ **All** :class:`~iris.cube.Cube` :attr:`~iris.cube.Cube.attributes` are
+ retained when regridding, so watch out for any attributes that reference
+ the format (there are several in these examples) - you may want to manually
+ remove them to avoid later confusion.
+
+The initialisation process is computationally expensive so we use caching to
+improve performance. Once a regridder has been initialised, it can be used on
+any :class:`~iris.cube.Cube` which has been defined on the same
+:class:`~iris.experimental.ugrid.Mesh` (or on the same **grid** in the case of
+:class:`~esmf_regrid.experimental.unstructured_scheme.GridToMeshESMFRegridder`).
+Since calling a regridder is usually a lot faster than initialising, reusing
+regridders can save a lot of time. We can demonstrate the reuse of the
+previously initialised regridder:
+
+.. dropdown:: :opticon:`code`
+
+ .. code-block:: python
+
+ # Extract a different cube defined on te same Mesh.
+ >>> mesh_cube2 = mesh_cubes.extract_cube("precipitation_flux")
+ >>> print(mesh_cube2)
+ precipitation_flux / (kg m-2 s-1) (-- : 1; -- : 13824)
+ Mesh coordinates:
+ latitude - x
+ longitude - x
+ Auxiliary coordinates:
+ time x -
+ Cell methods:
+ mean time (300 s)
+ mean time_counter
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 1 d
+ name lfric_surface
+ online_operation average
+ timeStamp 2020-Feb-07 16:23:14 GMT
+ title Created by xios
+ uuid 489bcef5-3d1c-4529-be42-4ab5f8c8497b
+
+ # Regrid the new mesh cube using the same regridder.
+ >>> result2 = rg(mesh_cube2)
+ >>> print(result2)
+ precipitation_flux / (kg m-2 s-1) (-- : 1; latitude: 180; longitude: 360)
+ Dimension coordinates:
+ latitude - x -
+ longitude - - x
+ Auxiliary coordinates:
+ time x - -
+ Cell methods:
+ mean time (300 s)
+ mean time_counter
+ Attributes:
+ Conventions UGRID
+ description Created by xios
+ interval_operation 300 s
+ interval_write 1 d
+ name lfric_surface
+ online_operation average
+ timeStamp 2020-Feb-07 16:23:14 GMT
+ title Created by xios
+ uuid 489bcef5-3d1c-4529-be42-4ab5f8c8497b
+
+Support also exists for saving and loading previously initialised regridders -
+:func:`esmf_regrid.experimental.io.save_regridder` and
+:func:`~esmf_regrid.experimental.io.load_regridder` - so that they can be
+re-used by future scripts.
+
+Equality
+--------
+.. |tagline: equality| replace:: |unchanged|
+
+.. rubric:: |tagline: equality|
+
+:class:`~iris.experimental.ugrid.Mesh` comparison is supported, and comparing
+two ':class:`~iris.experimental.ugrid.Mesh`-:class:`~iris.cube.Cube`\s' will
+include a comparison of the respective
+:class:`~iris.experimental.ugrid.Mesh`\es, with no extra action needed by the
+user.
+
+.. note::
+
+ Keep an eye on memory demand when comparing large
+ :class:`~iris.experimental.ugrid.Mesh`\es, but note that
+ :class:`~iris.experimental.ugrid.Mesh`\ equality is enabled for lazy
+ processing (:doc:`/userguide/real_and_lazy_data`), so if the
+ :class:`~iris.experimental.ugrid.Mesh`\es being compared are lazy the
+ process will use less memory than their total size.
+
+Combining Cubes
+---------------
+.. |tagline: combining cubes| replace:: |pending|
+
+.. rubric:: |tagline: combining cubes|
+
+Merging or concatenating :class:`~iris.cube.Cube`\s (described in
+:doc:`/userguide/merge_and_concat`) with two different
+:class:`~iris.experimental.ugrid.Mesh`\es is not possible - a
+:class:`~iris.cube.Cube` must be associated with just a single
+:class:`~iris.experimental.ugrid.Mesh`, and merge/concatenate are not yet
+capable of combining multiple :class:`~iris.experimental.ugrid.Mesh`\es into
+one.
+
+:class:`~iris.cube.Cube`\s that include
+:class:`~iris.experimental.ugrid.MeshCoord`\s can still be merged/concatenated
+on dimensions other than the :meth:`~iris.cube.Cube.mesh_dim`, since such
+:class:`~iris.cube.Cube`\s will by definition share the same
+:class:`~iris.experimental.ugrid.Mesh`.
+
+.. seealso::
+
+ You may wish to investigate
+ :func:`iris.experimental.ugrid.recombine_submeshes`, which can be used
+ for a very specific type of :class:`~iris.experimental.ugrid.Mesh`
+ combination not detailed here.
+
+Arithmetic
+----------
+.. |tagline: arithmetic| replace:: |pending|
+
+.. 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.
+
+
+.. todo:
+ Enumerate other popular operations that aren't yet possible
+ (and are they planned soon?)
+
+.. |new| replace:: ✨ New
+.. |unchanged| replace:: ♻️ Unchanged
+.. |different| replace:: ⚠️ Different
+.. |pending| replace:: 🚧 Support Pending
\ 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
new file mode 100644
index 00000000000..8e36f4ffc2d
--- /dev/null
+++ b/docs/src/further_topics/ugrid/partner_packages.rst
@@ -0,0 +1,100 @@
+.. _ugrid partners:
+
+Iris' Mesh Partner Packages
+****************************
+Python is an easy to use language and has formed a very strong collaborative
+scientific community, which is why Iris is written in Python. *Performant*
+Python relies on calls down to low level languages like C, which is ideal for
+structured grid work since
+they can be directly represented as NumPy arrays. This is more difficult when
+working with unstructured meshes where extra steps are needed to determine data
+position (:ref:`see the data model detail `), and we need
+to find ways of again passing the operations down to more optimised languages.
+
+The Iris team are therefore developing 'wrapper' packages, which make it quick
+and easy to analyse Iris mesh data via some popular Python packages that use
+powerful tools under the hood, working in C and other languages.
+
+These solutions have been placed in their own 'partner packages' for several
+reasons:
+
+* Can be useful to others who are not using Iris.
+
+ * Everyone working with multi-dimensional geographic datasets shares common
+ problems that need solving.
+ * Wider user base = stronger community = better solutions.
+
+* Only some Iris users will need them - they are **optional** Iris dependencies.
+
+ * They introduce a lot of new API.
+ * They introduce new large dependencies that take time to install and need
+ disk space.
+
+Below you can learn more about the partner packages and how they are useful.
+Specifics of what operations would require their installation can be found in:
+:doc:`operations`.
+
+.. important:: **Experimental**
+
+ As with Iris' mesh support, these packages are still in the
+ experimental stages. They would love your feedback, but as immature
+ packages their API, documentation, test coverage and CI are still
+ 'under construction'.
+
+
+.. _`ugrid geovista`:
+
+`GeoVista`_
+===========
+.. image:: images/geovistalogo.svg
+ :width: 300
+ :class: no-scaled-link
+
+.. rubric:: "Cartographic rendering and mesh analytics powered by `PyVista`_"
+
+PyVista is described as "VTK for humans" - VTK is a very powerful toolkit for
+working with meshes, and PyVista brings that power into the Python ecosystem.
+GeoVista in turn makes it easy to use PyVista specifically for cartographic
+work, designed from the start with the Iris
+:class:`~iris.experimental.ugrid.Mesh` in mind.
+
+Applications
+------------
+* Interactively plot mesh data:
+
+ * On a 3D globe.
+ * On your favourite projection.
+
+* Extract a specific region from a mesh.
+* Combine multiple meshes into one.
+
+.. _`ugrid iris-esmf-regrid`:
+
+`iris-esmf-regrid`_
+===================
+.. image:: images/iris-esmf-regrid.svg
+ :width: 300
+ :class: no-scaled-link
+
+.. rubric:: "A collection of structured and unstructured ESMF regridding schemes for Iris"
+
+ESMF provide a sophisticated, performant regridding utility that supports a
+variety of regridding types with both structured grids and unstructured meshes,
+and this also has a flexible Python interface - ESMPy. iris-esmf-regrid takes
+advantage of having a specific use-case - regridding Iris
+:class:`~iris.cube.Cube`\s - to provide ESMPy-Iris wrappers that make the
+process as easy as possible, with highly optimised performance.
+
+Applications
+------------
+* Regrid structured to unstructured.
+* Regrid unstructured to structured.
+* Regrid with dask integration, computing in parallel and maintaining data
+ laziness.
+* | Save a prepared regridder for re-use in subsequent runs.
+ | Regridders can even be re-used on sources with different masks - a
+ significant efficiency gain.
+
+.. _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/index.rst b/docs/src/index.rst
index 7518f948d88..d6270d60cc9 100644
--- a/docs/src/index.rst
+++ b/docs/src/index.rst
@@ -98,6 +98,15 @@ For **Iris 2.4** and earlier documentation please see the
generated/gallery/index
+.. toctree::
+ :maxdepth: 1
+ :caption: What's New in Iris
+ :hidden:
+
+ whatsnew/latest
+ Archive
+
+
.. toctree::
:maxdepth: 1
:caption: User Guide
@@ -131,6 +140,7 @@ For **Iris 2.4** and earlier documentation please see the
further_topics/metadata
further_topics/lenient_metadata
further_topics/lenient_maths
+ further_topics/ugrid/index
.. toctree::
@@ -153,7 +163,6 @@ For **Iris 2.4** and earlier documentation please see the
:hidden:
generated/api/iris
- whatsnew/index
techpapers/index
copyright
votable_issues
diff --git a/docs/src/installing.rst b/docs/src/installing.rst
index e358bb42c98..37a8942ab38 100644
--- a/docs/src/installing.rst
+++ b/docs/src/installing.rst
@@ -85,10 +85,12 @@ local copy of Iris::
conda env create --force --file=requirements/ci/iris.yml
conda activate iris-dev
-The ``--force`` option is used when creating the environment, this is optional
-and will force the any existing ``iris-dev`` conda environment to be deleted
-first if present. This is useful when rebuilding your environment due to a
-change in requirements.
+.. note::
+
+ The ``--force`` option, used when creating the environment, first removes
+ any previously existing ``iris-dev`` environment of the same name. This is
+ particularly useful when rebuilding your environment due to a change in
+ requirements.
The ``requirements/ci/iris.yml`` file defines the Iris development conda
environment *name* and all the relevant *top level* `conda-forge` package
diff --git a/docs/src/userguide/cube_maths.rst b/docs/src/userguide/cube_maths.rst
index 78490cd749d..e8a1744a44f 100644
--- a/docs/src/userguide/cube_maths.rst
+++ b/docs/src/userguide/cube_maths.rst
@@ -63,9 +63,9 @@ but with the data representing their difference:
forecast_reference_time 1859-09-01 06:00:00
height 1.5 m
Attributes:
- Conventions CF-1.5
- Model scenario E1
- source Data from Met Office Unified Model 6.05
+ Conventions 'CF-1.5'
+ Model scenario 'E1'
+ source 'Data from Met Office Unified Model 6.05'
.. note::
diff --git a/docs/src/userguide/cube_statistics.rst b/docs/src/userguide/cube_statistics.rst
index ac66ff4e53b..980f1e132f4 100644
--- a/docs/src/userguide/cube_statistics.rst
+++ b/docs/src/userguide/cube_statistics.rst
@@ -53,8 +53,8 @@ For instance, suppose we have a cube:
forecast_reference_time 2009-11-19 04:00:00
Attributes:
STASH m01s00i004
- source Data from Met Office Unified Model
- um_version 7.3
+ source 'Data from Met Office Unified Model'
+ um_version '7.3'
In this case we have a 4 dimensional cube;
@@ -84,8 +84,8 @@ we can pass the coordinate name and the aggregation definition to the
mean model_level_number
Attributes:
STASH m01s00i004
- source Data from Met Office Unified Model
- um_version 7.3
+ source 'Data from Met Office Unified Model'
+ um_version '7.3'
Similarly other analysis operators such as ``MAX``, ``MIN`` and ``STD_DEV``
@@ -143,8 +143,8 @@ These areas can now be passed to the ``collapsed`` method as weights:
mean grid_longitude, grid_latitude
Attributes:
STASH m01s00i004
- source Data from Met Office Unified Model
- um_version 7.3
+ source 'Data from Met Office Unified Model'
+ um_version '7.3'
Several examples of area averaging exist in the gallery which may be of interest,
including an example on taking a :ref:`global area-weighted mean
@@ -229,7 +229,7 @@ Printing this cube now shows that two extra coordinates exist on the cube:
Cell methods:
mean month, year
Attributes:
- Conventions CF-1.5
+ Conventions 'CF-1.5'
STASH m01s00i024
diff --git a/docs/src/userguide/interpolation_and_regridding.rst b/docs/src/userguide/interpolation_and_regridding.rst
index 5573c4aa8ee..f590485606b 100644
--- a/docs/src/userguide/interpolation_and_regridding.rst
+++ b/docs/src/userguide/interpolation_and_regridding.rst
@@ -79,7 +79,7 @@ Let's take the air temperature cube we've seen previously:
mean over years time
Attributes:
STASH m01s16i203
- source Data from Met Office Unified Model
+ source 'Data from Met Office Unified Model'
We can interpolate specific values from the coordinates of the cube:
@@ -98,7 +98,7 @@ We can interpolate specific values from the coordinates of the cube:
mean over years time
Attributes:
STASH m01s16i203
- source Data from Met Office Unified Model
+ source 'Data from Met Office Unified Model'
As we can see, the resulting cube is scalar and has longitude and latitude coordinates with
the values defined in our sample points.
diff --git a/docs/src/userguide/iris_cubes.rst b/docs/src/userguide/iris_cubes.rst
index 64a9bfd8229..d13dee369c1 100644
--- a/docs/src/userguide/iris_cubes.rst
+++ b/docs/src/userguide/iris_cubes.rst
@@ -172,8 +172,8 @@ output as this is the quickest way of inspecting the contents of a cube. Here is
forecast_reference_time 2009-11-19 04:00:00
Attributes:
STASH m01s00i004
- source Data from Met Office Unified Model
- um_version 7.3
+ source 'Data from Met Office Unified Model'
+ um_version '7.3'
Using this output we can deduce that:
diff --git a/docs/src/userguide/loading_iris_cubes.rst b/docs/src/userguide/loading_iris_cubes.rst
index ec459dbbdf3..fb938975e8b 100644
--- a/docs/src/userguide/loading_iris_cubes.rst
+++ b/docs/src/userguide/loading_iris_cubes.rst
@@ -100,8 +100,8 @@ list indexing can be used:
forecast_reference_time 2009-11-19 04:00:00
Attributes:
STASH m01s00i004
- source Data from Met Office Unified Model
- um_version 7.3
+ source 'Data from Met Office Unified Model'
+ um_version '7.3'
Notice that the result of printing a **cube** is a little more verbose than
it was when printing a **list of cubes**. In addition to the very short summary
@@ -304,13 +304,21 @@ for ease of calendar-based testing.
>>> cube_all = iris.load_cube(filename, 'air_potential_temperature')
>>> print('All times :\n' + str(cube_all.coord('time')))
All times :
- DimCoord([2009-11-19 10:00:00, 2009-11-19 11:00:00, 2009-11-19 12:00:00], standard_name='time', calendar='gregorian')
+ 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([2009-11-19 11:00:00], standard_name='time', calendar='gregorian')
+ 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
@@ -335,7 +343,11 @@ The previous constraint example can now be written as:
>>> print(iris.load_cube(
... iris.sample_data_path('uk_hires.pp'),
... 'air_potential_temperature' & the_11th_hour).coord('time'))
- DimCoord([2009-11-19 11:00:00], standard_name='time', calendar='gregorian')
+ 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
@@ -355,10 +367,13 @@ day of every week for many years:
:options: +NORMALIZE_WHITESPACE, +ELLIPSIS
>>> print(long_ts.coord('time'))
- DimCoord([2007-04-09 00:00:00, 2007-04-16 00:00:00, 2007-04-23 00:00:00,
- ...
- 2010-02-01 00:00:00, 2010-02-08 00:00:00, 2010-02-15 00:00:00],
- standard_name='time', calendar='gregorian')
+ 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.
@@ -371,9 +386,13 @@ Given two dates in datetime format, we can select all points between them.
... 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([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],
- standard_name='time', calendar='gregorian')
+ 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.
@@ -387,9 +406,13 @@ objects.
... 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([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],
- standard_name='time', calendar='gregorian')
+ 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
@@ -402,13 +425,19 @@ PartialDateTime this becomes simple:
... time=lambda cell: PartialDateTime(month=7, day=15) <= cell < PartialDateTime(month=8, day=25))
>>> within_st_swithuns = long_ts.extract(st_swithuns_daterange)
...
- >>> print(within_st_swithuns.coord('time'))
- DimCoord([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], standard_name='time', calendar='gregorian')
+ >>> # 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.
diff --git a/docs/src/userguide/navigating_a_cube.rst b/docs/src/userguide/navigating_a_cube.rst
index 74b47b258e1..c5924a61c65 100644
--- a/docs/src/userguide/navigating_a_cube.rst
+++ b/docs/src/userguide/navigating_a_cube.rst
@@ -33,9 +33,9 @@ We have already seen a basic string representation of a cube when printing:
forecast_reference_time 2006-06-15 00:00:00
time 2006-06-15 00:00:00
Attributes:
- Conventions CF-1.5
+ Conventions 'CF-1.5'
STASH m01s16i222
- source Data from Met Office Unified Model 6.01
+ source 'Data from Met Office Unified Model 6.01'
This representation is equivalent to passing the cube to the :func:`str` function. This function can be used on
@@ -169,9 +169,9 @@ We can add and remove coordinates via :func:`Cube.add_dim_coord>> # Save a cube list to a PP file, appending to the contents of the file
>>> # if it already exists
>>> iris.save(cubes, "myfile.pp", append=True)
+
>>> # Save a cube to netCDF, defaults to NETCDF4 file format
>>> iris.save(cubes[0], "myfile.nc")
>>> # Save a cube list to netCDF, using the NETCDF3_CLASSIC storage option
@@ -73,6 +74,12 @@ See
for more details on supported arguments for the individual savers.
+.. note::
+
+ The existence of a keyword argument for one saver does not guarantee the
+ same works for all savers. For example, it isn't possible to pass an
+ ``append`` keyword argument to the netCDF saver (see :ref:`netcdf_save`).
+
Customising the Save Process
----------------------------
@@ -102,6 +109,7 @@ Similarly a PP field may need to be written out with a specific value for LBEXP.
yield field
iris.fileformats.pp.save_fields(tweaked_fields(cubes[0]), '/tmp/app.pp')
+.. _netcdf_save:
NetCDF
^^^^^^
diff --git a/docs/src/userguide/subsetting_a_cube.rst b/docs/src/userguide/subsetting_a_cube.rst
index 1c68cafb8d5..5112d9689ad 100644
--- a/docs/src/userguide/subsetting_a_cube.rst
+++ b/docs/src/userguide/subsetting_a_cube.rst
@@ -30,7 +30,7 @@ A subset of a cube can be "extracted" from a multi-dimensional cube in order to
Scalar coordinates:
grid_latitude 0.0 degrees
Attributes:
- Conventions CF-1.5
+ Conventions 'CF-1.5'
In this example we start with a 3 dimensional cube, with dimensions of ``height``, ``grid_latitude`` and ``grid_longitude``,
@@ -97,8 +97,8 @@ same way as loading with constraints:
time 2009-11-19 10:00:00
Attributes:
STASH m01s00i004
- source Data from Met Office Unified Model
- um_version 7.3
+ source 'Data from Met Office Unified Model'
+ um_version '7.3'
Cube Iteration
diff --git a/docs/src/whatsnew/1.4.rst b/docs/src/whatsnew/1.4.rst
index 858f985ec6e..989198296ce 100644
--- a/docs/src/whatsnew/1.4.rst
+++ b/docs/src/whatsnew/1.4.rst
@@ -182,8 +182,7 @@ Cubes With no Vertical Coord can now be Exported to GRIB
--------------------------------------------------------
Iris can now export cubes with no vertical coord to GRIB.
-The solution is still under discussion: See
-https://github.com/SciTools/iris/issues/519.
+The solution is still under discussion: See :issue:`519`.
.. _simple_cfg:
diff --git a/docs/src/whatsnew/3.0.rst b/docs/src/whatsnew/3.0.rst
index 77458c70e93..771a6029542 100644
--- a/docs/src/whatsnew/3.0.rst
+++ b/docs/src/whatsnew/3.0.rst
@@ -35,8 +35,8 @@ This document explains the changes made to Iris for this release
:ref:`incompatible changes ` and
:ref:`deprecations `.
- And finally, get in touch with us on `GitHub`_ if you have any issues or
- feature requests for improving Iris. Enjoy!
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
v3.0.1 (27 Jan 2021)
@@ -617,7 +617,6 @@ v3.0.4 (22 July 2021)
.. _xxHash: https://github.com/Cyan4973/xxHash
.. _PyKE: https://pypi.org/project/scitools-pyke/
.. _@owena11: https://github.com/owena11
-.. _GitHub: https://github.com/SciTools/iris/issues/new/choose
.. _readthedocs: https://readthedocs.org/
.. _CF Conventions and Metadata: https://cfconventions.org/
.. _flake8: https://flake8.pycqa.org/en/stable/
diff --git a/docs/src/whatsnew/3.1.rst b/docs/src/whatsnew/3.1.rst
index 165e20d9bc2..bd046a0a24c 100644
--- a/docs/src/whatsnew/3.1.rst
+++ b/docs/src/whatsnew/3.1.rst
@@ -25,8 +25,8 @@ This document explains the changes made to Iris for this release
* Multiple improvements to developer guide documentation.
See entries in the :ref:`"Documentation" section `, below.
- And finally, get in touch with us on `GitHub`_ if you have any issues or
- feature requests for improving Iris. Enjoy!
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
📢 Announcements
@@ -315,7 +315,6 @@ This document explains the changes made to Iris for this release
.. _blacken-docs: https://github.com/asottile/blacken-docs
.. _conda-lock: https://github.com/conda-incubator/conda-lock
.. _deprecated numpy 1.20 aliases for builtin types: https://numpy.org/doc/1.20/release/1.20.0-notes.html#using-the-aliases-of-builtin-types-like-np-int-is-deprecated
-.. _GitHub: https://github.com/SciTools/iris/issues/new/choose
.. _Met Office: https://www.metoffice.gov.uk/
.. _numpy: https://numpy.org/doc/stable/release/1.20.0-notes.html
.. |pre-commit.ci| image:: https://results.pre-commit.ci/badge/github/SciTools/iris/main.svg
diff --git a/docs/src/whatsnew/3.2.rst b/docs/src/whatsnew/3.2.rst
new file mode 100644
index 00000000000..ef3764daa5a
--- /dev/null
+++ b/docs/src/whatsnew/3.2.rst
@@ -0,0 +1,384 @@
+.. 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!
+
+
+📢 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
+.. _@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
+.. _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
diff --git a/docs/src/whatsnew/dev.rst b/docs/src/whatsnew/dev.rst
new file mode 100644
index 00000000000..b9d5989bfc5
--- /dev/null
+++ b/docs/src/whatsnew/dev.rst
@@ -0,0 +1,94 @@
+.. include:: ../common_links.inc
+
+|iris_version| |build_date| [unreleased]
+****************************************
+
+This document explains the changes made to Iris for this release
+(:doc:`View all changes `.)
+
+
+.. dropdown:: :opticon:`report` |iris_version| 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:
+
+ * N/A
+
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
+
+
+📢 Announcements
+================
+
+#. N/A
+
+
+✨ Features
+===========
+
+#. `@wjbenfold`_ added support for ``false_easting`` and ``false_northing`` to
+ :class:`~iris.coord_system.Mercator`. (:issue:`3107`, :pull:`4524`)
+
+
+🐛 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`)
+
+
+💣 Incompatible Changes
+=======================
+
+#. N/A
+
+
+🚀 Performance Enhancements
+===========================
+
+#. N/A
+
+
+🔥 Deprecations
+===============
+
+#. N/A
+
+
+🔗 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`)
+
+
+📚 Documentation
+================
+
+#. N/A
+
+
+💼 Internal
+===========
+
+#. N/A
+
+
+.. comment
+ Whatsnew author names (@github name) in alphabetical order. Note that,
+ core dev names are automatically included by the common_links.inc:
+
+
+
+
+.. comment
+ Whatsnew resources in alphabetical order:
+
+
diff --git a/docs/src/whatsnew/latest.rst.template b/docs/src/whatsnew/dev.rst.template
similarity index 83%
rename from docs/src/whatsnew/latest.rst.template
rename to docs/src/whatsnew/dev.rst.template
index ced07780692..1b36d3f0b01 100644
--- a/docs/src/whatsnew/latest.rst.template
+++ b/docs/src/whatsnew/dev.rst.template
@@ -18,13 +18,13 @@ This document explains the changes made to Iris for this release
* N/A
- And finally, get in touch with us on `GitHub`_ if you have any issues or
- feature requests for improving Iris. Enjoy!
+ And finally, get in touch with us on :issue:`GitHub` if you have
+ any issues or feature requests for improving Iris. Enjoy!
NOTE: section below is a template for bugfix patches
====================================================
- (Please remove this section when creating an initial 'latest.rst')
+ (Please remove this section when creating an initial 'dev.rst')
v3.X.X (DD MMM YYYY)
====================
@@ -41,7 +41,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')
+ (Please remove this section when creating an initial 'dev.rst')
@@ -109,4 +109,4 @@ NOTE: section above is a template for bugfix patches
.. comment
Whatsnew resources in alphabetical order:
-.. _GitHub: https://github.com/SciTools/iris/issues/new/choose
+
diff --git a/docs/src/whatsnew/index.rst b/docs/src/whatsnew/index.rst
index fabb0564843..7e0829da5b5 100644
--- a/docs/src/whatsnew/index.rst
+++ b/docs/src/whatsnew/index.rst
@@ -10,7 +10,8 @@ Iris versions.
.. toctree::
:maxdepth: 1
- latest.rst
+ dev.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
deleted file mode 100644
index 2787e0044f4..00000000000
--- a/docs/src/whatsnew/latest.rst
+++ /dev/null
@@ -1,289 +0,0 @@
-.. include:: ../common_links.inc
-
-|iris_version| |build_date| [unreleased]
-****************************************
-
-This document explains the changes made to Iris for this release
-(:doc:`View all changes `.)
-
-
-.. dropdown:: :opticon:`report` |iris_version| 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 `UGRID`_ meshes which can now be loaded and attached
- to a cube.
-
- And finally, get in touch with us on `GitHub`_ if you have any issues or
- feature requests for improving Iris. Enjoy!
-
-
-📢 Announcements
-================
-
-#. Welcome to `@wjbenfold`_, `@tinyendian`_, `@larsbarring`_, `@akuhnregnier`_,
- `@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 unstructured meshes, as described by `UGRID`_. 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 `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 meshes to netcdf files, using the
- `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
- `UGRID`_ 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`)
-
-
-🐛 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`)
-
-
-💣 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`)
-
-
-🔥 Deprecations
-===============
-
-#. 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`)
-
-
-📚 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`)
-
-
-💼 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
-.. _@larsbarring: https://github.com/larsbarring
-.. _@pdearnshaw: https://github.com/pdearnshaw
-.. _@tinyendian: https://github.com/tinyendian
-
-.. comment
- Whatsnew resources in alphabetical order:
-
-.. _GitHub: https://github.com/SciTools/iris/issues/new/choose
-.. _NEP-29: https://numpy.org/neps/nep-0029-deprecation_policy.html
-.. _UGRID: http://ugrid-conventions.github.io/ugrid-conventions/
-.. _sort-all: https://github.com/aio-libs/sort-all
-.. _faster documentation building: https://docs.readthedocs.io/en/stable/guides/conda.html#making-builds-faster-with-mamba
diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst
new file mode 120000
index 00000000000..56aebe92dd4
--- /dev/null
+++ b/docs/src/whatsnew/latest.rst
@@ -0,0 +1 @@
+dev.rst
\ No newline at end of file
diff --git a/etc/cf-standard-name-table.xml b/etc/cf-standard-name-table.xml
index 5a19f8d5b1b..bd761681927 100644
--- a/etc/cf-standard-name-table.xml
+++ b/etc/cf-standard-name-table.xml
@@ -1,7 +1,7 @@
- 77
- 2021-01-19T13:38:50Z
+ 78
+ 2021-09-21T11:55:06ZCentre for Environmental Data Analysissupport@ceda.ac.uk
@@ -489,6 +489,13 @@
+
+ m2 s-2
+
+
+ One-half the scalar product of the air velocity and vorticity vectors, where vorticity refers to the standard name atmosphere_upward_absolute_vorticity. Helicity is proportional to the strength of the flow, the amount of vertical wind shear, and the amount of turning in the flow.
+
+
m2 s-135
@@ -2467,7 +2474,7 @@
1
- The "beam_consistency_indicator" is the degree to which the magnitudes of a collection (ensemble) of acoustic signals from multiple underwater acoustic transceivers relate to each other. It is used as a data quality assessment parameter in ADCP (acoustic doppler current profiler) instruments and is frequently referred to as "correlation magnitude". Convention is that the larger the value, the higher the signal to noise ratio and therefore the better the quality of the current vector measurements; the maximum value of the indicator is 128.
+ The "beam_consistency_indicator" is the degree to which the received acoustic pulse is correlated with the transmitted pulse. It is used as a data quality assessment parameter in ADCP (acoustic doppler current profiler) instruments and is frequently referred to as "correlation magnitude". Convention is that the larger the value, the higher the signal to noise ratio and therefore the better the quality of the current vector measurements; the maximum value of the indicator is 128.
@@ -2491,11 +2498,11 @@
The specification of a physical process by the phrase due_to_process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. Altitude is the (geometric) height above the geoid, which is the reference geopotential surface. The geoid is similar to mean sea level. "Bedrock" is the solid Earth surface beneath land ice, ocean water or soil. The zero of bedrock altitude change is arbitrary. Isostatic adjustment is the vertical movement of the lithosphere due to changing surface ice and water loads.
-
+
- "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. The quantity with standard name biological_taxon_identifier is the machine-readable identifier for the taxon registration in either WoRMS (the AphiaID) or ITIS (the taxonomic serial number or TSN), including namespace. The namespace strings are 'aphia:' or 'tsn:'. For example, Calanus finmarchicus is encoded as either 'aphia:104464' or 'tsn:85272'. For the marine domain WoRMS has more complete coverage and so aphia Ids are preferred. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. The quantity with standard name biological_taxon_lsid is the machine-readable identifier based on a taxon registration system using the syntax convention specified for the Life Science Identifier (LSID) - urn:lsid:<Authority>:<Namespace>:<ObjectID>[:<Version>]. This includes the reference classification in the element and these are restricted by the LSID governance. It is strongly recommended in CF that the authority chosen is World Register of Marine Species (WoRMS) for oceanographic data and Integrated Taxonomic Information System (ITIS) for freshwater and terrestrial data. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables. This identifier is a narrower equivalent to the scientificNameID field in the Darwin Core Standard.
@@ -2687,6 +2694,13 @@
"Amount" means mass per unit area. Zero change in land ice amount is an arbitrary level. "Land ice" means glaciers, ice-caps and ice-sheets resting on bedrock and also includes ice-shelves.
+
+ kg
+
+
+ Zero change in land ice mass is an arbitrary level. "Land ice" means glaciers, ice-caps and ice-sheets resting on bedrock and also includes ice-shelves. The horizontal domain over which the quantity is calculated is described by the associated coordinate variables and coordinate bounds or by a coordinate variable or scalar coordinate variable with the standard name of "region" supplied according to section 6.1.1 of the CF conventions.
+
+
kg m-2
@@ -2922,7 +2936,7 @@
m-3
- "Colony forming unit" means an estimate of the viable bacterial or fungal numbers determined by counting colonies grown from a sample. "Number concentration" means the number of particles or other specified objects per unit volume. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "Colony forming unit" means an estimate of the viable bacterial or fungal numbers determined by counting colonies grown from a sample. "Number concentration" means the number of particles or other specified objects per unit volume. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
@@ -3079,6 +3093,13 @@
Depth is the vertical distance below the surface.
+
+ m
+
+
+ The phrase depth_at_base_of_unfrozen_ground is the instantaneous depth of the downward penetration of thaw from the ground surface at a given time. Permafrost is soil or rock that has remained at a temperature at or below zero degrees Celsius throughout the seasonal cycle for two or more consecutive years. The maximum measurable depth_at_base_of_unfrozen_ground value as recorded at the end of a thawing season corresponds to the permafrost_active_layer_thickness.
+
+
m
@@ -3142,6 +3163,13 @@
"Aerosol" means the system of suspended liquid or solid particles in air (except cloud droplets) and their carrier gas, the air itself. "Ambient_aerosol" means that the aerosol is measured or modelled at the ambient state of pressure, temperature and relative humidity that exists in its immediate environment. "Ambient aerosol particles" are aerosol particles that have taken up ambient water through hygroscopic growth. The extent of hygroscopic growth depends on the relative humidity and the composition of the particles. To specify the relative humidity and temperature at which the quantity described by the standard name applies, provide scalar coordinate variables with standard names of "relative_humidity" and "air_temperature".
+
+ K
+
+
+ Sea surface temperature is usually abbreviated as "SST". It is the temperature of sea water near the surface (including the part under sea-ice, if any), not the skin or interface temperature, whose standard names are sea_surface_skin_temperature and surface_temperature, respectively. For the temperature of sea water at a particular depth or layer, a data variable of "sea_water_temperature" with a vertical coordinate axis should be used. Air temperature is the bulk temperature of the air, not the surface (skin) temperature.
+
+
Pa
@@ -3723,6 +3751,13 @@
A velocity is a vector quantity. "Eastward" indicates a vector component which is positive when directed eastward (negative westward). Flood water is water that covers land which is normally not covered by water.
+
+ m s-1
+
+
+ A velocity is a vector quantity. "Eastward" indicates a vector component which is positive when directed eastward (negative westward). Friction velocity is a reference wind velocity derived from the relationship between air density and downward stress and is usually applied at a level close to the surface where stress is assumed to independent of height and approximately proportional to the square of mean velocity.
+
+
m s-1
@@ -4577,6 +4612,13 @@
"Area fraction" is the fraction of a grid cell's horizontal area that has some characteristic of interest. It is evaluated as the area of interest divided by the grid cell area. It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction. "Layer" means any layer with upper and lower boundaries that have constant values in some vertical coordinate. There must be a vertical coordinate variable indicating the extent of the layer(s). If the layers are model layers, the vertical coordinate can be "model_level_number", but it is recommended to specify a physical coordinate (in a scalar or auxiliary coordinate variable) as well. Standard names also exist for high, medium and low cloud types. Standard names referring only to "cloud_area_fraction" should be used for quantities for the whole atmosphere column. Cloud area fraction is also called "cloud amount" and "cloud cover".
+
+ 1
+
+
+ ice_volume_in_frozen_ground_in_excess_of_pore_volume_in_unfrozen_ground_expressed_as_fraction_of_frozen_ground_volume represents the fractional amount of "excess ice" in frozen ground. Excess ice is the volume of ice in the ground which exceeds the total pore volume that the ground would have under natural unfrozen conditions. Due to the presence of ground ice, the total water content of a frozen soil may exceed that corresponding to its normally consolidated state when unfrozen. As a result, upon thawing, a soil containing excess ice will settle under its own weight until it attains its consolidated state. Reference: van Everdingen, R. O. editor 1998: Multi-language glossary of permafrost and related ground ice terms. International Permafrost Association.
+
+
m3 s-1
@@ -4588,7 +4630,7 @@
m s-1
- Sea water velocity is a vector quantity that is the speed at which water travels in a specified direction. The "indicative error" is an estimate of the quality of a sea water velocity profile measured using an ADCP (acoustic doppler current profiler). It is determined by differencing duplicate error velocity measurements made using different pairs of beams. The parameter is frequently referred to as the "error velocity".
+ Sea water velocity is a vector quantity that is the speed at which water travels in a specified direction. The "indicative error" is an estimate of the quality of a sea water velocity profile measured using an ADCP (acoustic doppler current profiler). It is determined by the difference between the vertical velocity calculated from two 3-beam solutions. The parameter is frequently referred to as the "error velocity".
@@ -7671,6 +7713,13 @@
"Content" indicates a quantity per unit area.
+
+ J Kg-1
+
+
+ The lightning_potential_index measures the potential for charge generation and separation that leads to lightning flashes in convective thunderstorms. It is derived from the model simulated grid-scale updraft velocity and the mass mixing-ratios of liquid water, cloud ice, snow, and graupel.
+
+
J
@@ -8081,21 +8130,21 @@
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 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. Mass concentration of biota expressed as carbon is also referred to as "carbon biomass". "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "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 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. Mass concentration of biota expressed as carbon is also referred to as "carbon biomass". "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.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 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. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables. 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.
+ "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 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. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables. 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.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 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. Mass concentration of biota expressed as nitrogen is also referred to as "nitrogen biomass". "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "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 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. Mass concentration of biota expressed as nitrogen is also referred to as "nitrogen biomass". "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
@@ -9449,6 +9498,13 @@
Mass fraction is used in the construction mass_fraction_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'. 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 which gives the green pigment and a side chain whose structure varies. Chlorophyll-a is the most commonly occurring form of natural chlorophyll.
+
+ 1
+
+
+ "Mass fraction" is used in the construction "mass_fraction_of_X_in_Y", where X is a material constituent of Y. It is evaluated as the mass of X divided by the mass of Y (including X). It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction. Grain-size class distribution is based on the Udden-Wentworth scale.
+
+
1
@@ -9610,6 +9666,13 @@
Mass fraction is used in the construction mass_fraction_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). Graupel consists of heavily rimed snow particles, often called snow pellets; often indistinguishable from very small soft hail except when the size convention that hail must have a diameter greater than 5 mm is adopted. Reference: American Meteorological Society Glossary http://glossary.ametsoc.org/wiki/Graupel. There are also separate standard names for hail. Standard names for "graupel_and_hail" should be used to describe data produced by models that do not distinguish between hail and graupel.
+
+ 1
+
+
+ "Mass fraction" is used in the construction "mass_fraction_of_X_in_Y'', where X is a material constituent of Y. It is evaluated as the mass of X divided by the mass of Y (including X). It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction. Grain-size class distribution is based on the Udden-Wentworth scale.
+
+
1
@@ -9918,6 +9981,13 @@
"Mass fraction" is used in the construction "mass_fraction_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 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 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. "Noy" describes a family of chemical species. The family usually includes atomic nitrogen (N), nitrogen monoxide (NO), nitrogen dioxide (NO2), dinitrogen pentoxide (N2O5), nitric acid (HNO3), peroxynitric acid (HNO4), bromine nitrate (BrONO2) , chlorine nitrate (ClONO2) and organic nitrates (most notably peroxyacetyl nitrate, sometimes referred to as PAN, (CH3COO2NO2)). 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.
+
+ 1
+
+
+ "Mass fraction" is used in the construction "mass_fraction_of_X_in_Y", where X is a material constituent of Y. It is evaluated as the mass of X divided by the mass of Y (including X). It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction.
+
+
1
@@ -10191,6 +10261,13 @@
The quantity with standard name mass_fraction_of_rainfall_falling_onto_surface_snow is the mass of rainfall falling onto snow as a fraction of the mass of rainfall falling within the area of interest. Surface snow refers to the snow on the solid ground or on surface ice cover, but excludes, for example, falling snowflakes and snow on plants. The surface called "surface" means the lower boundary of the atmosphere. Unless indicated in the cell_methods attribute, a quantity is assumed to apply to the whole area of each horizontal grid box.
+
+ 1
+
+
+ "Mass fraction" is used in the construction "mass_fraction_of_X_in_Y'', where X is a material constituent of Y. It is evaluated as the mass of X divided by the mass of Y (including X). It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction. Grain-size class distribution is based on the Udden-Wentworth scale.
+
+
1
@@ -10219,6 +10296,13 @@
"Mass fraction" is used in the construction "mass_fraction_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 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". Shallow convective cloud is nonprecipitating cumulus cloud with a cloud top below 3000m above the surface produced by the convection schemes in an atmosphere model. Some atmosphere models differentiate between shallow and deep convection. "Cloud liquid water" refers to the liquid phase of cloud water. A diameter of 0.2 mm has been suggested as an upper limit to the size of drops that shall be regarded as cloud drops; larger drops fall rapidly enough so that only very strong updrafts can sustain them. Any such division is somewhat arbitrary, and active cumulus clouds sometimes contain cloud drops much larger than this. Reference: AMS Glossary http://glossary.ametsoc.org/wiki/Cloud_drop.
+
+ 1
+
+
+ "Mass fraction" is used in the construction "mass_fraction_of_X_in_Y'', where X is a material constituent of Y. It is evaluated as the mass of X divided by the mass of Y (including X). It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction. Grain-size class distribution is based on the Udden-Wentworth scale.
+
+
1
@@ -10755,14 +10839,14 @@
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. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "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. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.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. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "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. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
@@ -12648,6 +12732,13 @@
The construction "moles_of_X_per_unit_mass_in_Y" is also called "molality" 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 of CFC11 is CFCl3. The IUPAC name for CFC11 is trichloro(fluoro)methane.
+
+ mol kg-1
+
+
+ The construction "moles_of_X_per_unit_mass_in_Y" is also called "molality" 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 inorganic carbon" describes a family of chemical species in solution, including carbon dioxide, carbonic acid and the carbonate and bicarbonate anions. "Dissolved inorganic carbon" is the term used in standard names for all species belonging to the family 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.
+
+
mol kg-1
@@ -13054,6 +13145,13 @@
A velocity is a vector quantity. "Northward" indicates a vector component which is positive when directed northward (negative southward). Flood water is water that covers land which is normally not covered by water.
+
+ m s-1
+
+
+ A velocity is a vector quantity. "Northward" indicates a vector component which is positive when directed northward (negative southward). Friction velocity is a reference wind velocity derived from the relationship between air density and downward stress and is usually applied at a level close to the surface where stress is assumed to independent of height and approximately proportional to the square of mean velocity.
+
+
W m-2
@@ -13345,7 +13443,7 @@
m-3
- "Number concentration" means the number of particles or other specified objects per unit volume. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_identifier to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
+ "Number concentration" means the number of particles or other specified objects per unit volume. "Biological taxon" is a name or other label identifying an organism or a group of organisms as belonging to a unit of classification in a hierarchical taxonomy. There must be an auxiliary coordinate variable with standard name biological_taxon_name to identify the taxon in human readable format and optionally an auxiliary coordinate variable with standard name biological_taxon_lsid to provide a machine-readable identifier. See Section 6.1.2 of the CF convention (version 1.8 or later) for information about biological taxon auxiliary coordinate variables.
@@ -13436,21 +13534,21 @@
1
- Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".
+ Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".1
- Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".
+ Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".1
- The construction lwe_thickness_of_X_amount or _content means the vertical extent of a layer of liquid water having the same mass per unit area. "Precipitation" in the earth's atmosphere means precipitation of water in all phases. The abbreviation "lwe" means liquid water equivalent. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".
+ The construction lwe_thickness_of_X_amount or _content means the vertical extent of a layer of liquid water having the same mass per unit area. "Precipitation" in the earth's atmosphere means precipitation of water in all phases. The abbreviation "lwe" means liquid water equivalent. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".
@@ -13464,7 +13562,7 @@
1
- Wind is defined as a two-dimensional (horizontal) air velocity vector, with no vertical component. (Vertical motion in the atmosphere has the standard name upward_air_velocity.) The wind speed is the magnitude of the wind velocity. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".
+ Wind is defined as a two-dimensional (horizontal) air velocity vector, with no vertical component. (Vertical motion in the atmosphere has the standard name upward_air_velocity.) The wind speed is the magnitude of the wind velocity. A variable whose standard name has the form number_of_days_with_X_below|above_threshold is a count of the number of days on which the condition X_below|above_threshold is satisfied. It must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_methods entry for within days which describes the processing of quantity X before the threshold is applied. A number_of_days is an extensive quantity in time, and the cell_methods entry for over days should be "sum".
@@ -17359,6 +17457,13 @@
The "reaction rate" is the rate at which the reactants of a chemical reaction form the products. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. The rate of "hydroxyl radical destruction due to reaction with nmvoc" is the nmvoc reactivity with regard to reactions with OH. It is the weighted sum of the reactivity of all individual nmvoc species with OH. The chemical formula for the hydroxyl radical is OH. In chemistry, a "radical" is a highly reactive, and therefore short lived, species. The abbreviation "nmvoc" means non methane volatile organic compounds; "nmvoc" is the term used in standard names to describe the group of chemical species having this classification 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.
+
+ 1
+
+
+ The phrase "ratio_of_X_to_Y" means X/Y. "X_volume" means the volume occupied by X within the grid cell. Pore volume is the volume of the porosity of the ground under natural, unfrozen conditions. This is often known as "ice saturation index".
+
+
K s-1
@@ -17391,7 +17496,7 @@
1
- Realization is used to label a dimension that can be thought of asa statistical sample, e.g., labelling members of a model ensemble.
+ Realization is used to label a dimension that can be thought of as a statistical sample, e.g., labelling members of a model ensemble.
@@ -17597,6 +17702,13 @@
The sea_floor_depth_below_sea_surface is the vertical distance between the sea surface and the seabed as measured at a given point in space including the variance caused by tides and possibly waves.
+
+ m
+
+
+ The average size of grains (also known as particles) in a sediment sample.
+
+
1
@@ -17681,6 +17793,13 @@
The term sea_ice_extent means the total area of all grid cells in which the sea ice area fraction equals or exceeds a threshold, often chosen to be 15 per cent. The threshold must be specified by supplying a coordinate variable or scalar coordinate variable with the standard name of sea_ice_area_fraction. The horizontal domain over which sea ice extent is calculated is described by the associated coordinate variables and coordinate bounds or by a coordinate variable or scalar coordinate variable with the standard name of "region" supplied according to section 6.1.1 of the CF conventions. "Sea ice" means all ice floating in the sea which has formed from freezing sea water, rather than by other processes such as calving of land ice to form icebergs.
+
+ m
+
+
+ "Sea ice" means all ice floating in the sea which has formed from freezing sea water, rather than by other processes such as calving of land ice to form icebergs. An ice floe is a flat expanse of sea ice, generally taken to be less than 10 km across. ice_floe_diameter corresponds to the diameter of a circle with the same area as the ice floe.
+
+
m
@@ -17856,6 +17975,20 @@
Sea surface density is the density of sea water near the surface (including the part under sea-ice, if any).
+
+ Pa
+
+
+ The surface called "sea surface" means the upper boundary of the ocean. "Surface stress" means the shear stress (force per unit area) exerted at the surface. A downward stress is a downward flux of momentum. Over large bodies of water, surface stress can drive near-surface currents. "Downward" indicates a vector component which is positive when directed downward (negative upward). "Eastward" indicates a vector component which is positive when directed northward (negative southward). "Downward eastward" indicates the ZX component of a tensor. A downward eastward stress is a downward flux of eastward momentum, which accelerates the lower medium eastward and the upper medium westward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. The phrase "dissipation_of_sea_surface_waves" means the stress associated with sea surface waves dissipation processes such as whitecapping.
+
+
+
+ Pa
+
+
+ The surface called "sea surface" means the upper boundary of the ocean. "Surface stress" means the shear stress (force per unit area) exerted at the surface. A downward stress is a downward flux of momentum. Over large bodies of water, surface stress can drive near-surface currents. "Downward" indicates a vector component which is positive when directed downward (negative upward). "Northward" indicates a vector component which is positive when directed northward (negative southward). "Downward northward" indicates the ZY component of a tensor. A downward northward stress is a downward flux of northward momentum, which accelerates the lower medium northward and the upper medium southward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. The phrase "dissipation_of_sea_surface_waves" means the stress associated with sea surface waves dissipation processes such as whitecapping.
+
+
K
@@ -18367,6 +18500,13 @@
Wave slope describes an aspect of sea surface wave geometry related to sea surface roughness. Mean square slope describes a derivation over multiple waves within a sea-state, for example calculated from moments of the wave directional spectrum. The phrase "y_slope" indicates that slope values are derived from vector components along the grid y-axis.
+
+ m-1
+
+
+ The wave directional spectrum can be written as a five dimensional function S(t,x,y,k,theta) where t is time, x and y are horizontal coordinates (such as longitude and latitude), k is wavenumber and theta is direction. S has the standard name sea_surface_wave_directional_variance_spectral_density. S can be integrated over direction to give S1= integral(S dtheta) and this quantity has the standard name sea_surface_wave_variance_spectral_density. Wavenumber is the number of oscillations of a wave per unit distance. Wavenumber moments, M(n) of S1 can then be calculated as follows: M(n) = integral(S1 k^n dk), where k^n is k to the power of n. The mean wavenumber, k(1), is calculated as the ratio M(1)/M(0).
+
+
s
@@ -18451,6 +18591,27 @@
Sea surface wave variance spectral density is the variance of wave amplitude within a range of wave frequency.
+
+ 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.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
degree
@@ -19088,6 +19249,13 @@
"Content" indicates a quantity per unit area. The "soil content" of a quantity refers to the vertical integral from the surface down to the bottom of the soil model. For the content between specified levels in the soil, standard names including content_of_soil_layer are used. Soil carbon is returned to the atmosphere as the organic matter decays. The decay process takes varying amounts of time depending on the composition of the organic matter, the temperature and the availability of moisture. A carbon "soil pool" means the carbon contained in organic matter which has a characteristic period over which it decays and releases carbon into the atmosphere. "Slow soil pool" refers to the decay of organic matter in soil with a characteristic period of more than a hundred years under reference climate conditions of a temperature of 20 degrees Celsius and no water limitations.
+
+ 1
+
+
+ "Area fraction" is the fraction of a grid cell's horizontal area that has some characteristic of interest. It is evaluated as the area of interest divided by the grid cell area. It may be expressed as a fraction, a percentage, or any other dimensionless representation of a fraction. Snow "viewable from above" refers to the snow on objects or the ground as viewed from above, which excludes, for example, falling snow flakes and snow obscured by a canopy, vegetative cover, or other features resting on the surface.
+
+
kg m-2
@@ -19225,7 +19393,7 @@
K85
- Soil temperature is the bulk temperature of the soil, not the surface (skin) temperature. "Soil" means the near-surface layer where plants sink their roots. For subsurface temperatures that extend beneath the soil layer or in areas where there is no surface soil layer, the standard name solid_earth_subsurface_temperature should be used.
+ Soil temperature is the bulk temperature of the soil, not the surface (skin) temperature. "Soil" means the near-surface layer where plants sink their roots. For subsurface temperatures that extend beneath the soil layer or in areas where there is no surface soil layer, the standard name temperature_in_ground should be used.
@@ -19249,6 +19417,13 @@
A variable with the standard name of soil_type contains strings which indicate the character of the soil e.g. clay. These strings have not yet been standardised. Alternatively, the data variable may contain integers which can be translated to strings using flag_values and flag_meanings attributes.
+
+ 1
+
+
+ soil_water_ph is the measure of acidity of soil moisture, defined as the negative logarithm of the concentration of dissolved hydrogen ions in soil water.
+
+
degree
@@ -19284,13 +19459,6 @@
Solar zenith angle is the the angle between the line of sight to the sun and the local vertical.
-
- K
-
-
- The quantity with standard name solid_earth_subsurface_temperature is the temperature at any depth (or in a layer) of the "solid" earth, excluding surficial snow and ice (but not permafrost or soil). For temperatures in surface lying snow and ice, the more specific standard names temperature_in_surface_snow and land_ice_temperature should be used. For temperatures measured or modelled specifically in the soil layer (the near-surface layer where plants sink their roots) the standard name soil_temperature should be used.
-
-
kg m-2 s-1
@@ -19410,6 +19578,13 @@
"specific" means per unit mass. Potential energy is the sum of the gravitational potential energy relative to the geoid and the centripetal potential energy. (The geopotential is the specific potential energy.)
+
+ J kg-1 K-1
+
+
+ Thermal capacity, or heat capacity, is the amount of heat energy required to increase the temperature of 1 kg of material by 1 K. It is a property of the material.
+
+
J kg-1 K-1
@@ -19470,28 +19645,28 @@
day
- Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".
+ Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".day
- Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".
+ Air temperature is the bulk temperature of the air, not the surface (skin) temperature. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".day
- "Amount" means mass per unit area. "Precipitation" in the earth's atmosphere means precipitation of water in all phases. The construction lwe_thickness_of_X_amount or _content means the vertical extent of a layer of liquid water having the same mass per unit area. The abbreviation "lwe" means liquid water equivalent. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".
+ "Amount" means mass per unit area. "Precipitation" in the earth's atmosphere means precipitation of water in all phases. The construction lwe_thickness_of_X_amount or _content means the vertical extent of a layer of liquid water having the same mass per unit area. The abbreviation "lwe" means liquid water equivalent. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".day
- "Amount" means mass per unit area. "Precipitation" in the earth's atmosphere means precipitation of water in all phases.The construction lwe_thickness_of_X_amount or _content means the vertical extent of a layer of liquid water having the same mass per unit area. The abbreviation "lwe" means liquid water equivalent. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the a standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".
+ "Amount" means mass per unit area. "Precipitation" in the earth's atmosphere means precipitation of water in all phases.The construction lwe_thickness_of_X_amount or _content means the vertical extent of a layer of liquid water having the same mass per unit area. The abbreviation "lwe" means liquid water equivalent. A spell is the number of consecutive days on which the condition X_below|above_threshold is satisfied. A variable whose standard name has the form spell_length_of_days_with_X_below|above_threshold must have a coordinate variable or scalar coordinate variable with the standard name of X to supply the threshold(s). It must have a climatological time variable, and a cell_method entry for within days which describes the processing of quantity X before the threshold is applied. A spell_length_of_days is an intensive quantity in time, and the cell_methods entry for over days can be any of the methods listed in Appendix E appropriate for intensive quantities e.g. "maximum", "minimum" or "mean".
@@ -19627,6 +19802,13 @@
"Sea surface height" is a time-varying quantity. The steric change in sea surface height is the change in height that a water column of standard temperature zero degrees Celsius and practical salinity S=35.0 would undergo when its temperature and salinity are changed to the observed values. The sum of the quantities with standard names thermosteric_change_in_sea_surface_height and halosteric_change_in_sea_surface_height is the total steric change in the water column height, which has the standard name of steric_change_in_sea_surface_height. The sum of the quantities with standard names sea_water_mass_per_unit_area_expressed_as_thickness and steric_change_in_sea_surface_height is the total thickness of the sea water column.
+
+ m s-1
+
+
+ Storm motion speed is defined as a two dimensional velocity vector, with no vertical component. (Vertical motion in the atmosphere has the standard name upward_air_velocity.) It is defined as the average speed of a supercell, and the direction the storm will move from. It is not dependent on the orientation of the ground-relative winds. Storm motion speed generally follows the methodology outlined in Bunkers et al. (2000).
+
+
1
@@ -19928,6 +20110,20 @@
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). "Eastward" indicates a vector component which is positive when directed eastward (negative westward). "Downward eastward" indicates the ZX component of a tensor. A downward eastward stress is a downward flux of eastward momentum, which accelerates the lower medium eastward and the upper medium westward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Boundary layer mixing" means turbulent motions that transport heat, water, momentum and chemical constituents within the atmospheric boundary layer and affect exchanges between the surface and the atmosphere. The atmospheric boundary layer is typically characterised by a well-mixed sub-cloud layer of order 500 metres, and by a more extended conditionally unstable layer with boundary-layer clouds up to 2 km. (Reference: IPCC Third Assessment Report, Working Group 1: The Scientific Basis, 7.2.2.3, https://archive.ipcc.ch/ipccreports/tar/wg1/273.htm).
+
+ Pa
+
+
+ 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). "Eastward" indicates a vector component which is positive when directed northward (negative southward). "Downward eastward" indicates the ZX component of a tensor. A downward eastward stress is a downward flux of eastward momentum, which accelerates the lower medium eastward and the upper medium westward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Viscosity" means the stress associated with viscous effects at the sea surface and is equivalent to the turbulent stress just outside the viscous sublayer.
+
+
+
+ Pa
+
+
+ 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). "Eastward" indicates a vector component which is positive when directed northward (negative southward). "Downward eastward" indicates the ZX component of a tensor. A downward eastward stress is a downward flux of eastward momentum, which accelerates the lower medium eastward and the upper medium westward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Sea surface waves" means the stress associated with form drag over sea surface waves.
+
+
W m-2
@@ -20068,6 +20264,20 @@
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). "Northward" indicates a vector component which is positive when directed northward (negative southward). "Downward northward" indicates the ZY component of a tensor. A downward northward stress is a downward flux of northward momentum, which accelerates the lower medium northward and the upper medium southward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Boundary layer mixing" means turbulent motions that transport heat, water, momentum and chemical constituents within the atmospheric boundary layer and affect exchanges between the surface and the atmosphere. The atmospheric boundary layer is typically characterised by a well-mixed sub-cloud layer of order 500 metres, and by a more extended conditionally unstable layer with boundary-layer clouds up to 2 km. (Reference: IPCC Third Assessment Report, Working Group 1: The Scientific Basis, 7.2.2.3, https://archive.ipcc.ch/ipccreports/tar/wg1/273.htm).
+
+ Pa
+
+
+ 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). "Northward" indicates a vector component which is positive when directed northward (negative southward). "Downward northward" indicates the ZY component of a tensor. A downward northward stress is a downward flux of northward momentum, which accelerates the lower medium northward and the upper medium southward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Viscosity" means the stress associated with viscous effects at the sea surface and is equivalent to the turbulent stress just outside the viscous sublayer.
+
+
+
+ Pa
+
+
+ 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). "Northward" indicates a vector component which is positive when directed northward (negative southward). "Downward northward" indicates the ZY component of a tensor. A downward northward stress is a downward flux of northward momentum, which accelerates the lower medium northward and the upper medium southward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Sea surface waves" means the stress associated with form drag over sea surface waves.
+
+
W m-2
@@ -23323,6 +23533,13 @@
The surface called "surface" means the lower boundary of the atmosphere. "anomaly" means difference from climatology. The surface temperature is the (skin) temperature at the interface, not the bulk temperature of the medium above or below.
+
+ Pa
+
+
+ The surface called "surface" means the lower boundary of the atmosphere. "Surface stress" means the shear stress (force per unit area) exerted at the surface. An upward stress is an upward flux of momentum into the atmosphere. "Upward" indicates a vector component which is positive when directed upward (negative downward). "Eastward" indicates a vector component which is positive when directed northward (negative southward). "Upward eastward" indicates the ZX component of a tensor. An upward eastward stress is an upward flux of eastward momentum, which accelerates the upper medium eastward and the lower medium westward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Sea surface waves" means the stress associated with oscillatory motions of a wavy sea surface.
+
+
W m-2
@@ -23596,6 +23813,13 @@
The surface called "surface" means the lower boundary of the atmosphere. "Upward" indicates a vector component which is positive when directed upward (negative downward). In accordance with common usage in geophysical disciplines, "flux" implies per unit area, called "flux density" in physics. The chemical formula for dimethyl sulfide is (CH3)2S. Dimethyl sulfide is sometimes referred to as DMS.
+
+ Pa
+
+
+ The surface called "surface" means the lower boundary of the atmosphere. "Surface stress" means the shear stress (force per unit area) exerted at the surface. An upward stress is an upward flux of momentum into the atmosphere. "Upward" indicates a vector component which is positive when directed upward (negative downward). "Northward" indicates a vector component which is positive when directed northward (negative southward). "Upward northward" indicates the ZY component of a tensor. An upward northward stress is an upward flux of northward momentum, which accelerates the upper medium northward and the lower medium southward. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "Sea surface waves" means the stress associated with oscillatory motions of a wavy sea surface.
+
+
W m-2122 E146
@@ -23799,6 +24023,13 @@
The quantity with standard name temperature_flux_due_to_runoff_expressed_as_heat_flux_into_sea_water is the heat carried by the transfer of water into the liquid ocean by the process of runoff. This quantity additionally includes melt water from sea ice and icebergs. It is calculated relative to the heat that would be transported by runoff water entering the sea at zero degrees Celsius. It is calculated as the product QrunoffCpTrunoff, where Q runoff is the mass flux of liquid runoff entering the sea water (kg m-2 s-1), Cp is the specific heat capacity of water, and Trunoff is the temperature in degrees Celsius of the runoff water. In accordance with common usage in geophysical disciplines, "flux" implies per unit area, called "flux density" in physics. The specification of a physical process by the phrase "due_to_" process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. Runoff is the liquid water which drains from land. If not specified, "runoff" refers to the sum of surface runoff and subsurface drainage.
+
+ K
+
+
+ The temperature at any given depth (or in a layer) below the surface of the ground, excluding surficial snow and ice (but not permafrost or soil). For temperatures in surface lying snow and ice, the more specific standard names temperature_in_surface_snow and land_ice_temperature should be used. For temperatures measured or modelled specifically for the soil layer (the near-surface layer where plants sink their roots) the standard name soil_temperature should be used.
+
+
KE238
@@ -28041,6 +28272,13 @@
The specification of a physical process by the phrase due_to_process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "tendency_of_X" means derivative of X with respect to time. "Content" indicates a quantity per unit area. "Layer" means any layer with upper and lower boundaries that have constant values in some vertical coordinate. There must be a vertical coordinate variable indicating the extent of the layer(s). If the layers are model layers, the vertical coordinate can be model_level_number, but it is recommended to specify a physical coordinate (in a scalar or auxiliary coordinate variable) as well.
+
+ kg s-1
+
+
+ The phrase "tendency_of_X" means derivative of X with respect to time. "Land ice" means glaciers, ice-caps and ice-sheets resting on bedrock and also includes ice-shelves. The horizontal domain over which the quantity is calculated is described by the associated coordinate variables and coordinate bounds or by a coordinate variable or scalar coordinate variable with the standard name of "region" supplied according to section 6.1.1 of the CF conventions.
+
+
kg s-1
@@ -29623,6 +29861,13 @@
The specification of a physical process by the phrase due_to_process means that the quantity named is a single term in a sum of terms which together compose the general quantity named by omitting the phrase. "tendency_of_X" means derivative of X with respect to time. Speed is the magnitude of velocity. Wind is defined as a two-dimensional (horizontal) air velocity vector, with no vertical component. (Vertical motion in the atmosphere has the standard name upward_air_velocity.) The wind speed is the magnitude of the wind velocity.
+
+ W m-1 K-1
+
+
+ Thermal conductivity is the constant k in the formula q = -k grad T where q is the heat transfer per unit time per unit area of a surface normal to the direction of transfer and grad T is the temperature gradient. Thermal conductivity is a property of the material.
+
+
J m-2
@@ -31227,14 +31472,110 @@
-
- integral_wrt_time_of_surface_downward_northward_stress
+
+ biological_taxon_lsid
+
+
+
+ temperature_in_ground
+
+
+
+ surface_snow_density
+
+
+
+ soot_content_of_surface_snow
+
+
+
+ liquid_water_content_of_surface_snow
+
+
+
+ surface_snow_thickness
+
+
+
+ thermal_energy_content_of_surface_snow
+
+
+
+ temperature_in_surface_snowintegral_wrt_time_of_surface_downward_eastward_stress
+
+ integral_wrt_time_of_surface_downward_northward_stress
+
+
+
+ tendency_of_atmosphere_mass_content_of_water_vapor_due_to_sublimation_of_surface_snow_and_ice
+
+
+
+ atmosphere_upward_absolute_vorticity
+
+
+
+ atmosphere_upward_relative_vorticity
+
+
+
+ area_type
+
+
+
+ area_type
+
+
+
+ iron_growth_limitation_of_diazotrophic_phytoplankton
+
+
+
+ growth_limitation_of_diazotrophic_phytoplankton_due_to_solar_irradiance
+
+
+
+ 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
+
+
+
+ mass_fraction_of_liquid_precipitation_in_air
+
+
+
+ mass_fraction_of_liquid_precipitation_in_air
+
+
+
+ mass_concentration_of_diazotrophic_phytoplankton_expressed_as_chlorophyll_in_sea_water
+
+
+
+ air_pseudo_equivalent_potential_temperature
+
+
+
+ tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_melting_to_cloud_liquid_water
+
+
+
+ tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_heterogeneous_nucleation_from_cloud_liquid_water
+
+
+
+ tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_riming_from_cloud_liquid_water
+
+
nitrogen_growth_limitation_of_diazotrophic_phytoplankton
@@ -31263,42 +31604,6 @@
effective_radius_of_cloud_liquid_water_particles_at_liquid_water_cloud_top
-
- 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
-
-
northward_heat_flux_in_air_due_to_eddy_advection
@@ -31355,72 +31660,56 @@
atmosphere_mass_content_of_cloud_liquid_water
-
- 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
+
+ mass_fraction_of_sulfate_dry_aerosol_particles_in_air
-
- sea_water_velocity_from_direction
+
+ mass_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
-
- thickness_of_stratiform_snowfall_amount
+
+ mass_fraction_of_ammonium_dry_aerosol_particles_in_air
-
- optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles
+
+ tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_shallow_convection
-
- optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles
+
+ tendency_of_mass_content_of_water_vapor_in_atmosphere_layer
-
- lwe_thickness_of_stratiform_snowfall_amount
+
+ mass_content_of_cloud_ice_in_atmosphere_layer
-
- equivalent_thickness_at_stp_of_atmosphere_ozone_content
+
+ mass_concentration_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air
-
- atmosphere_optical_thickness_due_to_water_in_ambient_aerosol_particles
+
+ mass_concentration_of_mercury_dry_aerosol_particles_in_air
-
- atmosphere_optical_thickness_due_to_dust_dry_aerosol_particles
+
+ mass_concentration_of_coarse_mode_ambient_aerosol_particles_in_air
-
- atmosphere_optical_thickness_due_to_dust_ambient_aerosol_particles
+
+ sea_water_velocity_to_direction
-
- atmosphere_optical_thickness_due_to_ambient_aerosol_particles
+
+ sea_water_velocity_to_direction
-
- atmosphere_optical_thickness_due_to_ambient_aerosol_particles
+
+ gross_primary_productivity_of_biomass_expressed_as_carbon
-
- atmosphere_net_upward_convective_mass_flux
+
+ eastward_water_vapor_flux_in_air
@@ -31435,94 +31724,6 @@
tendency_of_atmosphere_mass_content_of_water_vapor_due_to_advection
-
- thermal_energy_content_of_surface_snow
-
-
-
- liquid_water_content_of_surface_snow
-
-
-
- temperature_in_surface_snow
-
-
-
- tendency_of_atmosphere_mass_content_of_water_vapor_due_to_sublimation_of_surface_snow_and_ice
-
-
-
- surface_snow_thickness
-
-
-
- surface_snow_density
-
-
-
- soot_content_of_surface_snow
-
-
-
- atmosphere_upward_absolute_vorticity
-
-
-
- atmosphere_upward_relative_vorticity
-
-
-
- area_type
-
-
-
- area_type
-
-
-
- iron_growth_limitation_of_diazotrophic_phytoplankton
-
-
-
- growth_limitation_of_diazotrophic_phytoplankton_due_to_solar_irradiance
-
-
-
- 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
-
-
-
- mass_fraction_of_liquid_precipitation_in_air
-
-
-
- mass_fraction_of_liquid_precipitation_in_air
-
-
-
- mass_concentration_of_diazotrophic_phytoplankton_expressed_as_chlorophyll_in_sea_water
-
-
-
- air_pseudo_equivalent_potential_temperature
-
-
-
- tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_melting_to_cloud_liquid_water
-
-
-
- tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_heterogeneous_nucleation_from_cloud_liquid_water
-
-
-
- tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_riming_from_cloud_liquid_water
-
-
tendency_of_atmosphere_mass_content_of_water_vapor
@@ -31611,256 +31812,68 @@
atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles
-
- 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
-
-
-
- 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
-
-
-
- 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
-
-
-
- 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
-
-
-
- diameter_of_ambient_aerosol_particles
-
-
-
- effective_radius_of_stratiform_cloud_ice_particles
-
-
-
- effective_radius_of_convective_cloud_ice_particles
-
-
-
- effective_radius_of_stratiform_cloud_graupel_particles
-
-
-
- effective_radius_of_stratiform_cloud_rain_particles
-
-
-
- effective_radius_of_convective_cloud_snow_particles
-
-
-
- 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_content_of_cloud_liquid_water_in_atmosphere_layer
-
- mass_concentration_of_mercury_dry_aerosol_particles_in_air
+
+ air_equivalent_potential_temperature
-
- product_of_eastward_wind_and_lagrangian_tendency_of_air_pressure
+
+ number_concentration_of_stratiform_cloud_liquid_water_particles_at_stratiform_liquid_water_cloud_top
-
- carbon_mass_flux_into_litter_and_soil_due_to_anthropogenic_land_use_or_land_cover_change
+
+ number_concentration_of_convective_cloud_liquid_water_particles_at_convective_liquid_water_cloud_top
-
- stratiform_cloud_area_fraction
+
+ wave_frequency
-
- mass_fraction_of_mercury_dry_aerosol_particles_in_air
+
+ upward_eastward_momentum_flux_in_air_due_to_nonorographic_eastward_gravity_waves
-
- atmosphere_moles_of_hcc140a
+
+ tendency_of_troposphere_moles_of_carbon_monoxide
-
- floating_ice_shelf_area_fraction
+
+ tendency_of_atmosphere_moles_of_sulfate_dry_aerosol_particles
-
- atmosphere_moles_of_carbon_tetrachloride
+
+ tendency_of_atmosphere_mass_content_of_nitrate_dry_aerosol_particles_due_to_dry_deposition
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_miscellaneous_phytoplankton
+
+ tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_waste_treatment_and_disposal
-
- mole_fraction_of_inorganic_bromine_in_air
+
+ tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_savanna_and_grassland_fires
-
- water_vapor_saturation_deficit_in_air
+
+ 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_elemental_carbon_dry_aerosol_particles_due_to_emission_from_agricultural_waste_burning
+
+ tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_land_transport
-
- tendency_of_atmosphere_moles_of_carbon_tetrachloride
+
+ tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_forest_fires
-
- tendency_of_atmosphere_moles_of_carbon_monoxide
+
+ 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_nitrogen_compounds_expressed_as_nitrogen_due_to_wet_deposition
+
+ tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition
@@ -32015,104 +32028,152 @@
tendency_of_atmosphere_moles_of_cfc11
-
- mole_concentration_of_phytoplankton_expressed_as_nitrogen_in_sea_water
+
+ moles_of_cfc11_per_unit_mass_in_sea_water
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_due_to_nitrate_utilization
+
+ atmosphere_moles_of_cfc11
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_picophytoplankton
+
+ tendency_of_atmosphere_moles_of_hcc140a
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_phytoplankton
+
+ effective_radius_of_convective_cloud_rain_particles
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diatoms
+
+ tendency_of_troposphere_moles_of_hcc140a
-
- net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_calcareous_phytoplankton
+
+ tendency_of_middle_atmosphere_moles_of_hcc140a
-
- mole_concentration_of_diatoms_expressed_as_nitrogen_in_sea_water
+
+ tendency_of_troposphere_moles_of_hcfc22
-
- tendency_of_mole_concentration_of_dissolved_inorganic_phosphorus_in_sea_water_due_to_biological_processes
+
+ tendency_of_atmosphere_moles_of_hcfc22
-
- tendency_of_mole_concentration_of_dissolved_inorganic_silicon_in_sea_water_due_to_biological_processes
+
+ atmosphere_moles_of_hcfc22
-
- tendency_of_atmosphere_mole_concentration_of_carbon_monoxide_due_to_chemical_destruction
+
+ tendency_of_atmosphere_number_content_of_aerosol_particles_due_to_turbulent_deposition
-
- volume_extinction_coefficient_in_air_due_to_ambient_aerosol_particles
+
+ lagrangian_tendency_of_atmosphere_sigma_coordinate
-
- platform_name
+
+ lagrangian_tendency_of_atmosphere_sigma_coordinate
-
- platform_id
+
+ diameter_of_ambient_aerosol_particles
-
- platform_pitch
+
+ effective_radius_of_stratiform_cloud_ice_particles
-
- tendency_of_specific_humidity_due_to_stratiform_precipitation
+
+ effective_radius_of_convective_cloud_ice_particles
-
- tendency_of_air_temperature_due_to_stratiform_precipitation
+
+ effective_radius_of_stratiform_cloud_graupel_particles
-
- water_evaporation_amount_from_canopy
+
+ effective_radius_of_stratiform_cloud_rain_particles
-
- tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_turbulent_deposition
+
+ effective_radius_of_convective_cloud_snow_particles
-
- tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_gravitational_settling
+
+ product_of_eastward_wind_and_lagrangian_tendency_of_air_pressure
-
- tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_emission
+
+ carbon_mass_flux_into_litter_and_soil_due_to_anthropogenic_land_use_or_land_cover_change
-
- atmosphere_mass_content_of_cloud_ice
+
+ stratiform_cloud_area_fraction
-
- stratiform_precipitation_amount
+
+ sea_water_velocity_from_direction
-
- tendency_of_atmosphere_moles_of_nitrous_oxide
+
+ thickness_of_stratiform_snowfall_amount
-
- tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_dry_deposition
+
+ optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles
-
- atmosphere_mass_content_of_convective_cloud_condensed_water
+
+ optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles
+
+
+
+ lwe_thickness_of_stratiform_snowfall_amount
+
+
+
+ equivalent_thickness_at_stp_of_atmosphere_ozone_content
+
+
+
+ atmosphere_optical_thickness_due_to_water_in_ambient_aerosol_particles
+
+
+
+ atmosphere_optical_thickness_due_to_dust_dry_aerosol_particles
+
+
+
+ atmosphere_optical_thickness_due_to_dust_ambient_aerosol_particles
+
+
+
+ atmosphere_optical_thickness_due_to_ambient_aerosol_particles
+
+
+
+ atmosphere_optical_thickness_due_to_ambient_aerosol_particles
+
+
+
+ atmosphere_net_upward_convective_mass_flux
+
+
+
+ mass_fraction_of_mercury_dry_aerosol_particles_in_air
+
+
+
+ atmosphere_moles_of_hcc140a
+
+
+
+ floating_ice_shelf_area_fraction
+
+
+
+ atmosphere_moles_of_carbon_tetrachloride
@@ -32127,12 +32188,144 @@
mole_fraction_of_noy_expressed_as_nitrogen_in_air
-
- tendency_of_atmosphere_moles_of_methane
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_miscellaneous_phytoplankton
-
- rate_of_hydroxyl_radical_destruction_due_to_reaction_with_nmvoc
+
+ mole_fraction_of_inorganic_bromine_in_air
+
+
+
+ water_vapor_saturation_deficit_in_air
+
+
+
+ tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_agricultural_waste_burning
+
+
+
+ tendency_of_atmosphere_moles_of_carbon_tetrachloride
+
+
+
+ tendency_of_atmosphere_moles_of_carbon_monoxide
+
+
+
+ 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_mass_content_of_nitrogen_compounds_expressed_as_nitrogen_due_to_wet_deposition
+
+
+
+ mole_concentration_of_phytoplankton_expressed_as_nitrogen_in_sea_water
+
+
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_due_to_nitrate_utilization
+
+
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_picophytoplankton
+
+
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_phytoplankton
+
+
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diatoms
+
+
+
+ net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_calcareous_phytoplankton
+
+
+
+ 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_atmosphere_mole_concentration_of_carbon_monoxide_due_to_chemical_destruction
+
+
+
+ volume_extinction_coefficient_in_air_due_to_ambient_aerosol_particles
+
+
+
+ atmosphere_mass_content_of_convective_cloud_condensed_water
@@ -32207,6 +32400,78 @@
lwe_thickness_of_stratiform_precipitation_amount
+
+ tendency_of_atmosphere_moles_of_methane
+
+
+
+ rate_of_hydroxyl_radical_destruction_due_to_reaction_with_nmvoc
+
+
+
+ magnitude_of_sea_ice_displacement
+
+
+
+ surface_downwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+
+
+ surface_downwelling_radiative_flux_per_unit_wavelength_in_air
+
+
+
+ surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+
+
+ surface_downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+
+
+ surface_downwelling_photon_flux_per_unit_wavelength_in_sea_water
+
+
+
+ surface_downwelling_longwave_flux_in_air
+
+
+
+ integral_wrt_time_of_surface_downwelling_shortwave_flux_in_air
+
+
+
+ integral_wrt_time_of_surface_downwelling_longwave_flux_in_air
+
+
+
+ downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+
+
+ downwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+
+
+ downwelling_radiative_flux_per_unit_wavelength_in_air
+
+
+
+ downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+
+
+ downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+
+
+ downwelling_radiance_per_unit_wavelength_in_air
+
+
+
+ downwelling_photon_radiance_per_unit_wavelength_in_sea_water
+
+
surface_upwelling_shortwave_flux_in_air_assuming_clear_sky
@@ -32263,26 +32528,6 @@
surface_upwelling_radiance_per_unit_wavelength_in_air_reflected_by_sea_water
-
- surface_water_evaporation_flux
-
-
-
- water_evapotranspiration_flux
-
-
-
- water_volume_transport_into_sea_water_from_rivers
-
-
-
- stratiform_graupel_flux
-
-
-
- toa_outgoing_shortwave_flux_assuming_clear_sky_and_no_aerosol
-
-
wood_debris_mass_content_of_carbon
@@ -32311,18 +32556,6 @@
volume_scattering_coefficient_of_radiative_flux_in_air_due_to_ambient_aerosol_particles
-
- platform_yaw
-
-
-
- platform_roll
-
-
-
- water_vapor_partial_pressure_in_air
-
-
volume_scattering_coefficient_of_radiative_flux_in_air_due_to_dried_aerosol_particles
@@ -32339,68 +32572,68 @@
integral_wrt_height_of_product_of_eastward_wind_and_specific_humidity
-
- magnitude_of_sea_ice_displacement
+
+ platform_yaw
-
- surface_downwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+ platform_roll
-
- surface_downwelling_radiative_flux_per_unit_wavelength_in_air
+
+ water_vapor_partial_pressure_in_air
-
- surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+ platform_name
-
- surface_downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ platform_id
-
- surface_downwelling_photon_flux_per_unit_wavelength_in_sea_water
+
+ platform_pitch
-
- surface_downwelling_longwave_flux_in_air
+
+ tendency_of_specific_humidity_due_to_stratiform_precipitation
-
- integral_wrt_time_of_surface_downwelling_shortwave_flux_in_air
+
+ tendency_of_air_temperature_due_to_stratiform_precipitation
-
- integral_wrt_time_of_surface_downwelling_longwave_flux_in_air
+
+ water_evaporation_amount_from_canopy
-
- downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_turbulent_deposition
-
- downwelling_radiative_flux_per_unit_wavelength_in_sea_water
+
+ tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_gravitational_settling
-
- downwelling_radiative_flux_per_unit_wavelength_in_air
+
+ tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_emission
-
- downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol
+
+ atmosphere_mass_content_of_cloud_ice
-
- downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water
+
+ stratiform_precipitation_amount
-
- downwelling_radiance_per_unit_wavelength_in_air
+
+ tendency_of_atmosphere_moles_of_nitrous_oxide
-
- downwelling_photon_radiance_per_unit_wavelength_in_sea_water
+
+ tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_dry_deposition
@@ -32507,6 +32740,26 @@
lwe_stratiform_precipitation_rate
+
+ surface_water_evaporation_flux
+
+
+
+ water_evapotranspiration_flux
+
+
+
+ water_volume_transport_into_sea_water_from_rivers
+
+
+
+ stratiform_graupel_flux
+
+
+
+ toa_outgoing_shortwave_flux_assuming_clear_sky_and_no_aerosol
+
+
ocean_y_overturning_mass_streamfunction_due_to_parameterized_eddy_advection
@@ -32535,6 +32788,94 @@
tendency_of_sea_water_salinity_due_to_parameterized_eddy_advection
+
+ integral_wrt_time_of_surface_net_downward_shortwave_flux
+
+
+
+ tendency_of_ocean_eddy_kinetic_energy_content_due_to_parameterized_eddy_advection
+
+
+
+ sea_water_y_velocity_due_to_parameterized_mesoscale_eddies
+
+
+
+ ocean_tracer_biharmonic_diffusivity_due_to_parameterized_mesoscale_eddy_advection
+
+
+
+ eastward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
+
+
+
+ northward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
+
+
+
+ ocean_heat_y_transport_due_to_parameterized_eddy_advection
+
+
+
+ ocean_meridional_overturning_mass_streamfunction_due_to_parameterized_eddy_advection
+
+
+
+ ocean_mass_y_transport_due_to_advection_and_parameterized_eddy_advection
+
+
+
+ ocean_mass_x_transport_due_to_advection_and_parameterized_eddy_advection
+
+
+
+ ocean_heat_x_transport_due_to_parameterized_eddy_advection
+
+
+
+ northward_ocean_freshwater_transport_due_to_parameterized_eddy_advection
+
+
+
+ northward_ocean_salt_transport_due_to_parameterized_eddy_advection
+
+
+
+ integral_wrt_time_of_toa_outgoing_longwave_flux
+
+
+
+ integral_wrt_time_of_toa_net_downward_shortwave_flux
+
+
+
+ integral_wrt_time_of_surface_net_downward_longwave_flux
+
+
+
+ integral_wrt_time_of_surface_downward_sensible_heat_flux
+
+
+
+ integral_wrt_time_of_surface_downward_latent_heat_flux
+
+
+
+ integral_wrt_time_of_air_temperature_excess
+
+
+
+ integral_wrt_time_of_air_temperature_deficit
+
+
+
+ tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_wet_deposition
+
+
+
+ tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_dry_deposition
+
+
atmosphere_absorption_optical_thickness_due_to_sulfate_ambient_aerosol_particles
@@ -32711,392 +33052,392 @@
surface_geostrophic_sea_water_x_velocity_assuming_mean_sea_level_for_geoid
-
- tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_emission
+
+ air_pressure_at_mean_sea_level
-
- tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_dry_deposition
+
+ sea_floor_depth_below_mean_sea_level
-
- tendency_of_sea_surface_height_above_mean_sea_level
+
+ ocean_mixed_layer_thickness_defined_by_vertical_tracer_diffusivity_deficit
-
- mass_fraction_of_pm10_ambient_aerosol_particles_in_air
+
+ sea_surface_wind_wave_mean_period
-
- mass_fraction_of_pm10_ambient_aerosol_particles_in_air
+
+ sea_surface_wave_mean_period
-
- mass_concentration_of_pm10_ambient_aerosol_particles_in_air
+
+ sea_surface_swell_wave_mean_period
-
- atmosphere_optical_thickness_due_to_pm10_ambient_aerosol_particles
+
+ sea_surface_wind_wave_to_direction
-
- surface_geostrophic_eastward_sea_water_velocity
+
+ sea_surface_swell_wave_to_direction
-
- mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air
+
+ mass_content_of_water_in_soil_layer
-
- mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air
+
+ mass_content_of_water_in_soil
-
- mass_concentration_of_pm2p5_ambient_aerosol_particles_in_air
+
+ sea_surface_wind_wave_significant_height
-
- atmosphere_optical_thickness_due_to_pm2p5_ambient_aerosol_particles
+
+ sea_surface_swell_wave_significant_height
-
- mass_fraction_of_pm1_ambient_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition
-
- mass_fraction_of_pm1_ambient_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition
+
+ tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_emission
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition
+
+ atmosphere_optical_thickness_due_to_particulate_organic_matter_ambient_aerosol_particles
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling
+
+ mass_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling
+
+ atmosphere_mass_content_of_water_in_ambient_aerosol_particles
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition
+
+ tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_residential_and_commercial_combustion
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition
+
+ tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_wet_deposition
-
- mass_concentration_of_pm1_ambient_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_dry_deposition
-
- atmosphere_optical_thickness_due_to_pm1_ambient_aerosol_particles
+
+ mass_fraction_of_nitrate_dry_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition
+
+ mass_concentration_of_sulfate_dry_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition
+
+ mass_fraction_of_water_in_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_wet_deposition
+
+ mass_fraction_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_wet_deposition
+
+ tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_industrial_processes_and_combustion
-
- tendency_of_atmosphere_mass_content_of_pm10_sea_salt_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_energy_production_and_distribution
-
- mass_fraction_of_sea_salt_dry_aerosol_particles_in_air
+
+ mass_concentration_of_sulfate_ambient_aerosol_particles_in_air
-
- mass_fraction_of_sea_salt_dry_aerosol_particles_in_air
+
+ mass_concentration_of_sulfate_ambient_aerosol_particles_in_air
-
- mass_concentration_of_sea_salt_dry_aerosol_particles_in_air
+
+ mass_concentration_of_dust_dry_aerosol_particles_in_air
-
- mass_concentration_of_sea_salt_dry_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_emission
-
- atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles
+
+ tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition
-
- atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles
+
+ mass_fraction_of_primary_particulate_organic_matter_dry_aerosol_particles_in_air
-
- atmosphere_mass_content_of_sea_salt_dry_aerosol_particles
+
+ mass_fraction_of_particulate_organic_matter_dry_aerosol_particles_in_air
-
- atmosphere_mass_content_of_sea_salt_dry_aerosol_particles
+
+ number_concentration_of_coarse_mode_ambient_aerosol_particles_in_air
-
- air_pressure_at_mean_sea_level
+
+ sea_surface_wave_significant_height
-
- sea_floor_depth_below_mean_sea_level
+
+ tendency_of_atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles
-
- ocean_mixed_layer_thickness_defined_by_vertical_tracer_diffusivity_deficit
+
+ tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_dry_deposition
-
- sea_surface_wind_wave_mean_period
+
+ tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_wet_deposition
-
- sea_surface_wave_mean_period
+
+ number_concentration_of_nucleation_mode_ambient_aerosol_particles_in_air
-
- sea_surface_swell_wave_mean_period
+
+ number_concentration_of_ambient_aerosol_particles_in_air
-
- sea_surface_wind_wave_to_direction
+
+ mole_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
-
- sea_surface_swell_wave_to_direction
+
+ mass_fraction_of_dust_dry_aerosol_particles_in_air
-
- mass_content_of_water_in_soil_layer
+
+ mass_concentration_of_water_in_ambient_aerosol_particles_in_air
-
- mass_content_of_water_in_soil
+
+ mass_concentration_of_nitrate_dry_aerosol_particles_in_air
-
- sea_surface_wind_wave_significant_height
+
+ mass_concentration_of_particulate_organic_matter_dry_aerosol_particles_in_air
-
- sea_surface_swell_wave_significant_height
+
+ mass_concentration_of_ammonium_dry_aerosol_particles_in_air
-
- integral_wrt_time_of_surface_net_downward_shortwave_flux
+
+ atmosphere_mass_content_of_sulfate_ambient_aerosol_particles
-
- tendency_of_ocean_eddy_kinetic_energy_content_due_to_parameterized_eddy_advection
+
+ atmosphere_mass_content_of_sulfate_ambient_aerosol_particles
-
- sea_water_y_velocity_due_to_parameterized_mesoscale_eddies
+
+ atmosphere_mass_content_of_dust_dry_aerosol_particles
-
- ocean_tracer_biharmonic_diffusivity_due_to_parameterized_mesoscale_eddy_advection
+
+ atmosphere_absorption_optical_thickness_due_to_ambient_aerosol_particles
-
- eastward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
+
+ atmosphere_mass_content_of_sulfate_dry_aerosol_particles
-
- northward_sea_water_velocity_due_to_parameterized_mesoscale_eddies
+
+ tendency_of_atmosphere_mass_content_of_water_vapor_due_to_turbulence
-
- ocean_heat_y_transport_due_to_parameterized_eddy_advection
+
+ surface_upward_mole_flux_of_carbon_dioxide
-
- ocean_meridional_overturning_mass_streamfunction_due_to_parameterized_eddy_advection
+
+ surface_downward_mole_flux_of_carbon_dioxide
-
- ocean_mass_y_transport_due_to_advection_and_parameterized_eddy_advection
+
+ atmosphere_mass_content_of_cloud_condensed_water
-
- ocean_mass_x_transport_due_to_advection_and_parameterized_eddy_advection
+
+ northward_water_vapor_flux_in_air
-
- ocean_heat_x_transport_due_to_parameterized_eddy_advection
+
+ lwe_stratiform_snowfall_rate
-
- northward_ocean_freshwater_transport_due_to_parameterized_eddy_advection
+
+ stratiform_snowfall_amount
-
- northward_ocean_salt_transport_due_to_parameterized_eddy_advection
+
+ stratiform_rainfall_rate
-
- integral_wrt_time_of_toa_outgoing_longwave_flux
+
+ stratiform_rainfall_flux
-
- integral_wrt_time_of_toa_net_downward_shortwave_flux
+
+ stratiform_rainfall_amount
-
- integral_wrt_time_of_surface_net_downward_longwave_flux
+
+ tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_emission
-
- integral_wrt_time_of_surface_downward_sensible_heat_flux
+
+ tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_dry_deposition
-
- integral_wrt_time_of_surface_downward_latent_heat_flux
+
+ tendency_of_sea_surface_height_above_mean_sea_level
-
- integral_wrt_time_of_air_temperature_excess
+
+ mass_fraction_of_pm10_ambient_aerosol_particles_in_air
-
- integral_wrt_time_of_air_temperature_deficit
+
+ mass_fraction_of_pm10_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_wet_deposition
+
+ mass_concentration_of_pm10_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_dry_deposition
+
+ atmosphere_optical_thickness_due_to_pm10_ambient_aerosol_particles
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition
+
+ surface_geostrophic_eastward_sea_water_velocity
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition
+
+ mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_emission
+
+ mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air
-
- atmosphere_optical_thickness_due_to_particulate_organic_matter_ambient_aerosol_particles
+
+ mass_concentration_of_pm2p5_ambient_aerosol_particles_in_air
-
- mass_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
+
+ atmosphere_optical_thickness_due_to_pm2p5_ambient_aerosol_particles
-
- atmosphere_mass_content_of_water_in_ambient_aerosol_particles
+
+ mass_fraction_of_pm1_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_residential_and_commercial_combustion
+
+ mass_fraction_of_pm1_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_wet_deposition
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition
-
- tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_dry_deposition
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition
-
- mass_fraction_of_nitrate_dry_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling
-
- mass_concentration_of_sulfate_dry_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling
-
- mass_fraction_of_water_in_ambient_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition
-
- mass_fraction_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_industrial_processes_and_combustion
+
+ mass_concentration_of_pm1_ambient_aerosol_particles_in_air
-
- tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_energy_production_and_distribution
+
+ atmosphere_optical_thickness_due_to_pm1_ambient_aerosol_particles
-
- mass_concentration_of_sulfate_ambient_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition
-
- mass_concentration_of_sulfate_ambient_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition
-
- mass_concentration_of_dust_dry_aerosol_particles_in_air
+
+ tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_wet_deposition
-
- tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_emission
+
+ tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_wet_deposition
-
- tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition
+
+ tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_dry_deposition
-
- mass_fraction_of_primary_particulate_organic_matter_dry_aerosol_particles_in_air
+
+ mass_fraction_of_sea_salt_dry_aerosol_particles_in_air
-
- mass_fraction_of_particulate_organic_matter_dry_aerosol_particles_in_air
+
+ mass_fraction_of_sea_salt_dry_aerosol_particles_in_air
-
- number_concentration_of_coarse_mode_ambient_aerosol_particles_in_air
+
+ mass_concentration_of_sea_salt_dry_aerosol_particles_in_air
-
- mass_concentration_of_primary_particulate_organic_matter_dry_aerosol_particles_in_air
+
+ mass_concentration_of_sea_salt_dry_aerosol_particles_in_air
-
- atmosphere_mass_content_of_ammonium_dry_aerosol_particles
+
+ atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles
-
- stratiform_rainfall_rate
+
+ atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles
-
- stratiform_rainfall_flux
+
+ atmosphere_mass_content_of_sea_salt_dry_aerosol_particles
-
- stratiform_rainfall_amount
+
+ atmosphere_mass_content_of_sea_salt_dry_aerosol_particles
@@ -33139,22 +33480,6 @@
upward_eastward_momentum_flux_in_air_due_to_nonorographic_westward_gravity_waves
-
- mass_fraction_of_ozone_in_air
-
-
-
- mass_fraction_of_convective_cloud_condensed_water_in_air
-
-
-
- sea_surface_swell_wave_period
-
-
-
- surface_drag_coefficient_in_air
-
-
specific_gravitational_potential_energy
@@ -33175,6 +33500,14 @@
isotropic_longwave_radiance_in_air
+
+ mass_concentration_of_primary_particulate_organic_matter_dry_aerosol_particles_in_air
+
+
+
+ atmosphere_mass_content_of_ammonium_dry_aerosol_particles
+
+
stratiform_snowfall_flux
@@ -33183,108 +33516,120 @@
thickness_of_stratiform_rainfall_amount
-
- sea_surface_wave_significant_height
+
+ sea_surface_wind_wave_period
-
- tendency_of_atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles
+
+ omnidirectional_spherical_irradiance_per_unit_wavelength_in_sea_water
-
- tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_dry_deposition
+
+ tendency_of_middle_atmosphere_moles_of_molecular_hydrogen
-
- tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_wet_deposition
+
+ tendency_of_middle_atmosphere_moles_of_methyl_chloride
-
- number_concentration_of_nucleation_mode_ambient_aerosol_particles_in_air
+
+ tendency_of_middle_atmosphere_moles_of_methane
-
- number_concentration_of_ambient_aerosol_particles_in_air
+
+ sea_water_y_velocity
-
- mole_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air
+
+ sea_water_x_velocity
-
- mass_fraction_of_dust_dry_aerosol_particles_in_air
+
+ mole_fraction_of_hypochlorous_acid_in_air
-
- mass_concentration_of_water_in_ambient_aerosol_particles_in_air
+
+ tendency_of_troposphere_moles_of_molecular_hydrogen
-
- mass_concentration_of_nitrate_dry_aerosol_particles_in_air
+
+ tendency_of_troposphere_moles_of_methyl_chloride
-
- mass_concentration_of_particulate_organic_matter_dry_aerosol_particles_in_air
+
+ mass_content_of_water_vapor_in_atmosphere_layer
-
- mass_concentration_of_ammonium_dry_aerosol_particles_in_air
+
+ mass_content_of_water_in_atmosphere_layer
-
- atmosphere_mass_content_of_sulfate_ambient_aerosol_particles
+
+ tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_turbulence
-
- atmosphere_mass_content_of_sulfate_ambient_aerosol_particles
+
+ tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_deep_convection
-
- atmosphere_mass_content_of_dust_dry_aerosol_particles
+
+ tendency_of_troposphere_moles_of_methyl_bromide
-
- atmosphere_absorption_optical_thickness_due_to_ambient_aerosol_particles
+
+ tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_convection
-
- atmosphere_mass_content_of_sulfate_dry_aerosol_particles
+
+ tendency_of_atmosphere_mass_content_of_water_vapor_due_to_shallow_convection
-
- tendency_of_atmosphere_mass_content_of_water_vapor_due_to_turbulence
+
+