diff --git a/.git_archival.txt b/.git_archival.txt new file mode 100644 index 0000000000..3994ec0a83 --- /dev/null +++ b/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true)$ +ref-names: $Format:%D$ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..82bf71c1c5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.git_archival.txt export-subst \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 500a2183d2..84af305034 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,3 +4,6 @@ contact_links: - name: 💬 Iris GitHub Discussions url: https://github.com/SciTools/iris/discussions about: Engage with the Iris community to discuss your issue + - name: ❓ Usage Question + url: https://github.com/SciTools/iris/discussions/categories/q-a + about: Raise a question about how to use Iris in the Q&A section of Discussions diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 9ebc7a4c45..c0baabe572 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -6,6 +6,12 @@ on: schedule: # Runs every day at 23:00. - cron: "0 23 * * *" + workflow_dispatch: + inputs: + first_commit: + description: "Argument to be passed to the overnight benchmark script." + required: false + type: string jobs: benchmark: @@ -15,7 +21,7 @@ jobs: env: IRIS_TEST_DATA_LOC_PATH: benchmarks IRIS_TEST_DATA_PATH: benchmarks/iris-test-data - IRIS_TEST_DATA_VERSION: "2.14" + IRIS_TEST_DATA_VERSION: "2.15" # Lets us manually bump the cache to rebuild ENV_CACHE_BUILD: "0" TEST_DATA_CACHE_BUILD: "2" @@ -64,7 +70,12 @@ jobs: - 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) + first_commit=${{ inputs.first_commit }} + if [ "$first_commit" == "" ] + then + first_commit=$(git log --after="$(date -d "1 day ago" +"%Y-%m-%d") 23:00:00" --pretty=format:"%h" | tail -n 1) + fi + if [ "$first_commit" != "" ] then nox --session="benchmarks(overnight)" -- $first_commit diff --git a/.github/workflows/ci-docs-tests.yml b/.github/workflows/ci-docs-tests.yml deleted file mode 100644 index c2e3fcfcf8..0000000000 --- a/.github/workflows/ci-docs-tests.yml +++ /dev/null @@ -1,129 +0,0 @@ -# reference: -# - https://github.com/actions/cache -# - https://github.com/actions/checkout -# - https://github.com/marketplace/actions/setup-miniconda - -name: ci-docs-tests - -on: - push: - branches: - - "main" - - "v*x" - tags: - - "v*" - pull_request: - branches: - - "*" - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - tests: - name: "${{ matrix.session }} ${{ matrix.os }} py${{ matrix.python-version }}" - - runs-on: ${{ matrix.os }} - - defaults: - run: - shell: bash -l {0} - - strategy: - fail-fast: false - matrix: - os: ["ubuntu-latest"] - python-version: ["3.8"] - session: ["doctest", "gallery", "linkcheck"] - - env: - IRIS_TEST_DATA_VERSION: "2.14" - ENV_NAME: "ci-docs-tests" - - steps: - - name: "checkout" - uses: actions/checkout@v3 - - - name: "environment configure" - env: - # Maximum cache period (in weeks) before forcing a cache refresh. - CACHE_WEEKS: 2 - run: | - echo "CACHE_PERIOD=$(date +%Y).$(expr $(date +%U) / ${CACHE_WEEKS})" >> ${GITHUB_ENV} - echo "LOCK_FILE=requirements/ci/nox.lock/py$(echo ${{ matrix.python-version }} | tr -d '.')-linux-64.lock" >> ${GITHUB_ENV} - - - name: "data cache" - uses: ./.github/workflows/composite/iris-data-cache - with: - cache_build: 1 - env_name: ${{ env.ENV_NAME }} - version: ${{ env.IRIS_TEST_DATA_VERSION }} - - - name: "conda package cache" - uses: ./.github/workflows/composite/conda-pkg-cache - with: - cache_build: 1 - cache_period: ${{ env.CACHE_PERIOD }} - env_name: ${{ env.ENV_NAME }} - - - name: "conda install" - uses: conda-incubator/setup-miniconda@v2 - with: - miniforge-version: latest - channels: conda-forge,defaults - activate-environment: ${{ env.ENV_NAME }} - auto-update-conda: false - use-only-tar-bz2: true - - - name: "conda environment cache" - uses: ./.github/workflows/composite/conda-env-cache - with: - cache_build: 1 - cache_period: ${{ env.CACHE_PERIOD }} - env_name: ${{ env.ENV_NAME }} - install_packages: "cartopy nox pip" - - - name: "conda info" - run: | - conda info - conda list - - - name: "cartopy cache" - uses: ./.github/workflows/composite/cartopy-cache - with: - cache_build: 1 - cache_period: ${{ env.CACHE_PERIOD }} - env_name: ${{ env.ENV_NAME }} - - - name: "nox cache" - uses: ./.github/workflows/composite/nox-cache - with: - cache_build: 1 - env_name: ${{ env.ENV_NAME }} - lock_file: ${{ env.LOCK_FILE }} - - # TODO: drop use of site.cfg and explicit use of mplrc - - name: "iris configure" - env: - SITE_CFG: lib/iris/etc/site.cfg - MPL_RC: ${HOME}/.config/matplotlib/matplotlibrc - run: | - mkdir -p $(dirname ${SITE_CFG}) - echo ${SITE_CFG} - echo "[Resources]" >> ${SITE_CFG} - echo "test_data_dir = ${HOME}/iris-test-data/test_data" >> ${SITE_CFG} - echo "doc_dir = ${GITHUB_WORKSPACE}/docs" >> ${SITE_CFG} - cat ${SITE_CFG} - mkdir -p $(dirname ${MPL_RC}) - echo ${MPL_RC} - echo "backend : agg" >> ${MPL_RC} - echo "image.cmap : viridis" >> ${MPL_RC} - cat ${MPL_RC} - - - name: "iris ${{ matrix.session }}" - env: - PY_VER: ${{ matrix.python-version }} - run: | - nox --session ${{ matrix.session }} -- --verbose diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 18cb1f5e21..270046164e 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -3,7 +3,7 @@ # - https://github.com/actions/checkout # - https://github.com/marketplace/actions/setup-miniconda -name: ci-tests +name: ci-tests on: push: @@ -23,7 +23,7 @@ concurrency: jobs: tests: - name: "${{ matrix.session }} ${{ matrix.os }} py${{ matrix.python-version }}" + name: "${{ matrix.session }} (py${{ matrix.python-version }} ${{ matrix.os }})" runs-on: ${{ matrix.os }} @@ -35,11 +35,18 @@ jobs: fail-fast: false matrix: os: ["ubuntu-latest"] - python-version: ["3.8"] - session: ["tests"] + python-version: ["3.10"] + session: ["tests", "doctest", "gallery", "linkcheck"] + include: + - os: "ubuntu-latest" + python-version: "3.9" + session: "tests" + - os: "ubuntu-latest" + python-version: "3.8" + session: "tests" env: - IRIS_TEST_DATA_VERSION: "2.14" + IRIS_TEST_DATA_VERSION: "2.17" ENV_NAME: "ci-tests" steps: @@ -57,14 +64,14 @@ jobs: - name: "data cache" uses: ./.github/workflows/composite/iris-data-cache with: - cache_build: 1 + cache_build: 0 env_name: ${{ env.ENV_NAME }} version: ${{ env.IRIS_TEST_DATA_VERSION }} - name: "conda package cache" uses: ./.github/workflows/composite/conda-pkg-cache with: - cache_build: 1 + cache_build: 0 cache_period: ${{ env.CACHE_PERIOD }} env_name: ${{ env.ENV_NAME }} @@ -80,7 +87,7 @@ jobs: - name: "conda environment cache" uses: ./.github/workflows/composite/conda-env-cache with: - cache_build: 1 + cache_build: 0 cache_period: ${{ env.CACHE_PERIOD }} env_name: ${{ env.ENV_NAME }} install_packages: "cartopy nox pip" @@ -93,14 +100,14 @@ jobs: - name: "cartopy cache" uses: ./.github/workflows/composite/cartopy-cache with: - cache_build: 1 + cache_build: 0 cache_period: ${{ env.CACHE_PERIOD }} env_name: ${{ env.ENV_NAME }} - name: "nox cache" uses: ./.github/workflows/composite/nox-cache with: - cache_build: 1 + cache_build: 0 env_name: ${{ env.ENV_NAME }} lock_file: ${{ env.LOCK_FILE }} @@ -108,6 +115,7 @@ jobs: - name: "iris configure" env: SITE_CFG: lib/iris/etc/site.cfg + MPL_RC: ${HOME}/.config/matplotlib/matplotlibrc run: | mkdir -p $(dirname ${SITE_CFG}) echo ${SITE_CFG} @@ -115,6 +123,11 @@ jobs: echo "test_data_dir = ${HOME}/iris-test-data/test_data" >> ${SITE_CFG} echo "doc_dir = ${GITHUB_WORKSPACE}/docs" >> ${SITE_CFG} cat ${SITE_CFG} + mkdir -p $(dirname ${MPL_RC}) + echo ${MPL_RC} + echo "backend : agg" >> ${MPL_RC} + echo "image.cmap : viridis" >> ${MPL_RC} + cat ${MPL_RC} - name: "iris ${{ matrix.session }}" env: diff --git a/.github/workflows/ci-wheels.yml b/.github/workflows/ci-wheels.yml new file mode 100644 index 0000000000..a00833b118 --- /dev/null +++ b/.github/workflows/ci-wheels.yml @@ -0,0 +1,166 @@ +# Reference: +# - https://github.com/actions/checkout +# - https://github.com/actions/download-artifact +# - https://github.com/actions/upload-artifact +# - https://github.com/pypa/build +# - https://github.com/pypa/gh-action-pypi-publish +# - https://test.pypi.org/help/#apitoken + +name: ci-wheels + +on: + pull_request: + + push: + tags: + - "v*" + branches-ignore: + - "auto-update-lockfiles" + - "pre-commit-ci-update-config" + - "dependabot/*" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: "build sdist & wheel" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: "building" + shell: bash + run: | + # require build with explicit --sdist and --wheel in order to + # get correct version associated with sdist and bdist artifacts + pipx run build --sdist --wheel + + - uses: actions/upload-artifact@v3 + with: + name: pypi-artifacts + path: ${{ github.workspace }}/dist/* + + test-wheel: + needs: build + name: "test wheel (py${{ matrix.python-version }})" + runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10"] + session: ["wheel"] + env: + ENV_NAME: "ci-wheels" + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/download-artifact@v3 + with: + name: pypi-artifacts + path: ${{ github.workspace }}/dist + + - name: "environment configure" + env: + # Maximum cache period (in weeks) before forcing a cache refresh. + CACHE_WEEKS: 2 + run: | + echo "CACHE_PERIOD=$(date +%Y).$(expr $(date +%U) / ${CACHE_WEEKS})" >> ${GITHUB_ENV} + echo "LOCK_FILE=requirements/ci/nox.lock/py$(echo ${{ matrix.python-version }} | tr -d '.')-linux-64.lock" >> ${GITHUB_ENV} + + - name: "conda package cache" + uses: ./.github/workflows/composite/conda-pkg-cache + with: + cache_build: 0 + cache_period: ${{ env.CACHE_PERIOD }} + env_name: ${{ env.ENV_NAME }} + + - name: "conda install" + uses: conda-incubator/setup-miniconda@v2 + with: + miniforge-version: latest + channels: conda-forge,defaults + activate-environment: ${{ env.ENV_NAME }} + auto-update-conda: false + use-only-tar-bz2: true + + - name: "conda environment cache" + uses: ./.github/workflows/composite/conda-env-cache + with: + cache_build: 0 + cache_period: ${{ env.CACHE_PERIOD }} + env_name: ${{ env.ENV_NAME }} + install_packages: "nox pip" + + - name: "nox cache" + uses: ./.github/workflows/composite/nox-cache + with: + cache_build: 0 + env_name: ${{ env.ENV_NAME }} + lock_file: ${{ env.LOCK_FILE }} + + - name: "nox install and test wheel" + env: + PY_VER: ${{ matrix.python-version }} + run: | + nox --session ${{ matrix.session }} -- --verbose + + show-artifacts: + needs: build + name: "show artifacts" + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v3 + with: + name: pypi-artifacts + path: ${{ github.workspace }}/dist + + - shell: bash + run: | + ls -l ${{ github.workspace }}/dist + + publish-artifacts-test-pypi: + needs: test-wheel + name: "publish to test.pypi" + runs-on: ubuntu-latest + # upload to Test PyPI for every commit on main branch + if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' + steps: + - uses: actions/download-artifact@v3 + with: + name: pypi-artifacts + path: ${{ github.workspace }}/dist + + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + skip_existing: true + print_hash: true + + publish-artifacts-pypi: + needs: test-wheel + name: "publish to pypi" + runs-on: ubuntu-latest + # upload to PyPI for every tag starting with 'v' + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') + steps: + - uses: actions/download-artifact@v3 + with: + name: pypi-artifacts + path: ${{ github.workspace }}/dist + + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + print_hash: true diff --git a/.github/workflows/refresh-lockfiles.yml b/.github/workflows/refresh-lockfiles.yml index e817131c5e..a45cccfeab 100644 --- a/.github/workflows/refresh-lockfiles.yml +++ b/.github/workflows/refresh-lockfiles.yml @@ -33,7 +33,7 @@ jobs: steps: - uses: actions/checkout@v3 - id: get_py - run: echo "::set-output name=matrix::$(ls -1 requirements/ci/py??.yml | xargs -n1 basename | sed 's/....$//' | jq -cnR '[inputs]')" + run: echo "::set-output name=matrix::$(ls -1 requirements/ci/py*.yml | xargs -n1 basename | sed 's/....$//' | jq -cnR '[inputs]')" gen_lockfiles: # this is a matrix job: it splits to create new lockfiles for each @@ -48,11 +48,13 @@ jobs: steps: - uses: actions/checkout@v3 - - name: install conda-lock + - name: install requirements run: | source $CONDA/bin/activate base - conda install -y -c conda-forge conda-lock + conda install -y -c conda-forge conda-libmamba-solver conda-lock - name: generate lockfile + env: + CONDA_EXPERIMENTAL_SOLVER: libmamba run: | $CONDA/bin/conda-lock lock -k explicit -p linux-64 -f requirements/ci/${{matrix.python}}.yml mv conda-linux-64.lock ${{matrix.python}}-linux-64.lock @@ -89,7 +91,7 @@ jobs: - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 + uses: peter-evans/create-pull-request@671dc9c9e0c2d73f07fa45a3eb0220e1622f0c5f with: token: ${{ steps.generate-token.outputs.token }} commit-message: Updated environment lockfiles diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 008fe56deb..c65f37284f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,7 +14,7 @@ jobs: if: "github.repository == 'SciTools/iris'" runs-on: ubuntu-latest steps: - - uses: actions/stale@v5 + - uses: actions/stale@v6 with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 1791caf3f3..512fbab231 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ *.py[co] +# setuptools-scm +_version.py + # Environment file which should be autogenerated *conda_requirements.txt* @@ -55,6 +58,9 @@ lib/iris/tests/results/imagerepo.lock /.idea *.cover +# vscode files +.vscode + # Auto generated documentation files docs/src/_build/* docs/src/generated diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c2563497de..b7746edb43 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ minimum_pre_commit_version: 1.21.0 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.3.0 hooks: # Prevent giant files from being committed. - id: check-added-large-files @@ -29,14 +29,14 @@ repos: - id: no-commit-to-branch - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.10.0 hooks: - id: black pass_filenames: false args: [--config=./pyproject.toml, .] - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 5.0.4 hooks: - id: flake8 types: [file, python] diff --git a/.readthedocs.yml b/.readthedocs.yml index 63c4798050..95f828a873 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,6 +4,19 @@ build: os: ubuntu-20.04 tools: python: mambaforge-4.10 + jobs: + post_checkout: + # The SciTools/iris repository is shallow i.e., has a .git/shallow, + # therefore complete the repository with a full history in order + # to allow setuptools-scm to correctly auto-discover the version. + - git fetch --unshallow + - git fetch --all + # Need to stash the local changes that Read the Docs makes so that + # setuptools_scm can generate the correct Iris version. + pre_install: + - git stash + post_install: + - git stash pop conda: environment: requirements/ci/readthedocs.yml diff --git a/MANIFEST.in b/MANIFEST.in index 52492b17b2..ad28df9c7c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,15 +1,13 @@ # Top-level files include CHANGES COPYING COPYING.LESSER +prune .github +exclude .gitignore -# Files from setup.py package_data that are not automatically added to source distributions -recursive-include lib/iris/tests/results *.cml *.cdl *.txt *.xml *.json -recursive-include lib/iris/etc * -include lib/iris/tests/stock/file_headers/* - +# Files required for conda package management recursive-include requirements * -# File required to build docs -recursive-include docs Makefile *.js *.png *.py *.rst +# Files required to build docs +recursive-include docs * prune docs/src/_build prune docs/src/generated prune docs/gallery_tests @@ -18,6 +16,5 @@ prune docs/gallery_tests include tools/generate_std_names.py include etc/cf-standard-name-table.xml -global-exclude *.pyc -global-exclude __pycache__ -global-exclude iris_image_test_output +global-exclude *.py[cod] +global-exclude __pycache__ \ No newline at end of file diff --git a/README.md b/README.md index 1217cd9b38..ac2781f469 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,6 @@ ci-tests - -ci-docs-tests Documentation Status diff --git a/benchmarks/benchmarks/experimental/ugrid/regions_combine.py b/benchmarks/benchmarks/experimental/ugrid/regions_combine.py index 8ebf210416..3b2d77a80a 100644 --- a/benchmarks/benchmarks/experimental/ugrid/regions_combine.py +++ b/benchmarks/benchmarks/experimental/ugrid/regions_combine.py @@ -11,8 +11,7 @@ * 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. Aim for benchmark time ~20x - that of the minimal benchmark. + run-time that scale with data size. """ import os diff --git a/benchmarks/benchmarks/generate_data/__init__.py b/benchmarks/benchmarks/generate_data/__init__.py index 78b971d9de..52a5aceca8 100644 --- a/benchmarks/benchmarks/generate_data/__init__.py +++ b/benchmarks/benchmarks/generate_data/__init__.py @@ -113,7 +113,7 @@ def load_realised(): file loading, but some benchmarks are only meaningful if starting with real arrays. """ - from iris.fileformats.netcdf import _get_cf_var_data as pre_patched + from iris.fileformats.netcdf.loader import _get_cf_var_data as pre_patched def patched(cf_var, filename): return as_concrete_data(pre_patched(cf_var, filename)) diff --git a/benchmarks/benchmarks/import_iris.py b/benchmarks/benchmarks/import_iris.py index ad54c23122..fc32ac289b 100644 --- a/benchmarks/benchmarks/import_iris.py +++ b/benchmarks/benchmarks/import_iris.py @@ -5,10 +5,30 @@ # licensing details. from importlib import import_module, reload +################ +# Prepare info for reset_colormaps: + +# Import and capture colormaps. +from matplotlib import colormaps # isort:skip + +_COLORMAPS_ORIG = set(colormaps) + +# Import iris.palette, which modifies colormaps. +import iris.palette + +# Derive which colormaps have been added by iris.palette. +_COLORMAPS_MOD = set(colormaps) +COLORMAPS_EXTRA = _COLORMAPS_MOD - _COLORMAPS_ORIG + +# Touch iris.palette to prevent linters complaining. +_ = iris.palette + +################ + class Iris: @staticmethod - def _import(module_name): + def _import(module_name, reset_colormaps=False): """ Have experimented with adding sleep() commands into the imported modules. The results reveal: @@ -25,6 +45,13 @@ def _import(module_name): and the repetitions are therefore no faster than the first run. """ mod = import_module(module_name) + + if reset_colormaps: + # Needed because reload() will attempt to register new colormaps a + # second time, which errors by default. + for cm_name in COLORMAPS_EXTRA: + colormaps.unregister(cm_name) + reload(mod) def time_iris(self): @@ -205,7 +232,7 @@ def time_iterate(self): self._import("iris.iterate") def time_palette(self): - self._import("iris.palette") + self._import("iris.palette", reset_colormaps=True) def time_plot(self): self._import("iris.plot") diff --git a/benchmarks/benchmarks/load/ugrid.py b/benchmarks/benchmarks/load/ugrid.py index 8227a4c5a0..350a78e128 100644 --- a/benchmarks/benchmarks/load/ugrid.py +++ b/benchmarks/benchmarks/load/ugrid.py @@ -10,8 +10,7 @@ * 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. Aim for benchmark time ~20x - that of the minimal benchmark. + run-time that scale with data size. """ @@ -39,7 +38,7 @@ def load_mesh(*args, **kwargs): class BasicLoading: - params = [1, int(4.1e6)] + params = [1, int(2e5)] param_names = ["number of faces"] def setup_common(self, **kwargs): @@ -58,6 +57,9 @@ def time_load_mesh(self, *args): class BasicLoadingTime(BasicLoading): """Same as BasicLoading, but scaling over a time series - an unlimited dimension.""" + # NOTE iris#4834 - careful how big the time dimension is (time dimension + # is UNLIMITED). + param_names = ["number of time steps"] def setup(self, *args): @@ -75,7 +77,7 @@ class DataRealisation: warmup_time = 0.0 timeout = 300.0 - params = [1, int(4e6)] + params = [1, int(2e5)] param_names = ["number of faces"] def setup_common(self, **kwargs): @@ -102,7 +104,7 @@ def setup(self, *args): class Callback: - params = [1, int(4.5e6)] + params = [1, int(2e5)] param_names = ["number of faces"] def setup_common(self, **kwargs): diff --git a/benchmarks/benchmarks/save.py b/benchmarks/benchmarks/save.py index bb1d2d8c82..3551c72528 100644 --- a/benchmarks/benchmarks/save.py +++ b/benchmarks/benchmarks/save.py @@ -10,8 +10,7 @@ * 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. Aim for benchmark time ~20x - that of the minimal benchmark. + run-time that scale with data size. """ from iris import save diff --git a/docs/Makefile b/docs/Makefile index 44c89206d2..47f3e740fa 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -55,8 +55,8 @@ linkcheck: echo "Running linkcheck in $$i..."; \ (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) linkcheck); done -gallerytest: - @echo - @echo "Running \"gallery\" tests..." - @echo - python -m unittest discover -v -t . +show: + @for i in $(SUBDIRS); do \ + echo "Running show in $$i..."; \ + (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) show); done + diff --git a/docs/gallery_code/general/plot_custom_file_loading.py b/docs/gallery_code/general/plot_custom_file_loading.py index 025f395789..4b817aea66 100644 --- a/docs/gallery_code/general/plot_custom_file_loading.py +++ b/docs/gallery_code/general/plot_custom_file_loading.py @@ -57,7 +57,7 @@ import datetime -from cf_units import CALENDAR_GREGORIAN, Unit +from cf_units import CALENDAR_STANDARD, Unit import matplotlib.pyplot as plt import numpy as np @@ -225,7 +225,7 @@ def NAME_to_cube(filenames, callback): # define the time unit and use it to serialise the datetime for the # time coordinate - time_unit = Unit("hours since epoch", calendar=CALENDAR_GREGORIAN) + time_unit = Unit("hours since epoch", calendar=CALENDAR_STANDARD) time_coord = icoords.AuxCoord( time_unit.date2num(field_headings["time"]), standard_name="time", diff --git a/docs/gallery_code/general/plot_zonal_means.py b/docs/gallery_code/general/plot_zonal_means.py new file mode 100644 index 0000000000..08a9578e63 --- /dev/null +++ b/docs/gallery_code/general/plot_zonal_means.py @@ -0,0 +1,89 @@ +""" +Zonal Mean Diagram of Air Temperature +===================================== +This example demonstrates aligning a linear plot and a cartographic plot using Matplotlib. +""" + +import cartopy.crs as ccrs +import matplotlib.pyplot as plt +from mpl_toolkits.axes_grid1 import make_axes_locatable +import numpy as np + +import iris +from iris.analysis import MEAN +import iris.plot as iplt +import iris.quickplot as qplt + + +def main(): + + # Loads air_temp.pp and "collapses" longitude into a single, average value. + fname = iris.sample_data_path("air_temp.pp") + temperature = iris.load_cube(fname) + collapsed_temp = temperature.collapsed("longitude", MEAN) + + # Set y-axes with -90 and 90 limits and steps of 15 per tick. + start, stop, step = -90, 90, 15 + yticks = np.arange(start, stop + step, step) + ylim = [start, stop] + + # Plot "temperature" on a cartographic plot and set the ticks and titles + # on the axes. + fig = plt.figure(figsize=[12, 4]) + + ax1 = fig.add_subplot(111, projection=ccrs.PlateCarree()) + im = iplt.contourf(temperature, cmap="RdYlBu_r") + ax1.coastlines() + ax1.gridlines() + ax1.set_xticks([-180, -90, 0, 90, 180]) + ax1.set_yticks(yticks) + ax1.set_title("Air Temperature") + ax1.set_ylabel(f"Latitude / {temperature.coord('latitude').units}") + ax1.set_xlabel(f"Longitude / {temperature.coord('longitude').units}") + ax1.set_ylim(*ylim) + + # Create a Matplotlib AxesDivider object to allow alignment of other + # Axes objects. + divider = make_axes_locatable(ax1) + + # Gives the air temperature bar size, colour and a title. + ax2 = divider.new_vertical( + size="5%", pad=0.5, axes_class=plt.Axes, pack_start=True + ) # creates 2nd axis + fig.add_axes(ax2) + cbar = plt.colorbar( + im, cax=ax2, orientation="horizontal" + ) # puts colour bar on second axis + cbar.ax.set_xlabel(f"{temperature.units}") # labels colour bar + + # Plot "collapsed_temp" on the mean graph and set the ticks and titles + # on the axes. + ax3 = divider.new_horizontal( + size="30%", pad=0.4, axes_class=plt.Axes + ) # create 3rd axis + fig.add_axes(ax3) + qplt.plot( + collapsed_temp, collapsed_temp.coord("latitude") + ) # plots temperature collapsed over longitude against latitude + ax3.axhline(0, color="k", linewidth=0.5) + + # Creates zonal mean details + ax3.set_title("Zonal Mean") + ax3.yaxis.set_label_position("right") + ax3.yaxis.tick_right() + ax3.set_yticks(yticks) + ax3.grid() + + # Round each tick for the third ax to the nearest 20 (ready for use). + data_max = collapsed_temp.data.max() + x_max = data_max - data_max % -20 + data_min = collapsed_temp.data.min() + x_min = data_min - data_min % 20 + ax3.set_xlim(x_min, x_max) + ax3.set_ylim(*ylim) + + plt.show() + + +if __name__ == "__main__": + main() diff --git a/docs/gallery_tests/conftest.py b/docs/gallery_tests/conftest.py new file mode 100644 index 0000000000..a218b305a2 --- /dev/null +++ b/docs/gallery_tests/conftest.py @@ -0,0 +1,67 @@ +# 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. + +"""Pytest fixtures for the gallery tests.""" + +import pathlib + +import matplotlib.pyplot as plt +import pytest + +import iris + +CURRENT_DIR = pathlib.Path(__file__).resolve() +GALLERY_DIR = CURRENT_DIR.parents[1] / "gallery_code" + + +@pytest.fixture +def image_setup_teardown(): + """ + Setup and teardown fixture. + + Ensures all figures are closed before and after test to prevent one test + polluting another if it fails with a figure unclosed. + + """ + plt.close("all") + yield + plt.close("all") + + +@pytest.fixture +def import_patches(monkeypatch): + """ + Replace plt.show() with a function that does nothing, also add all the + gallery examples to sys.path. + + """ + + def no_show(): + pass + + monkeypatch.setattr(plt, "show", no_show) + + for example_dir in GALLERY_DIR.iterdir(): + if example_dir.is_dir(): + monkeypatch.syspath_prepend(example_dir) + + yield + + +@pytest.fixture +def iris_future_defaults(): + """ + Create a fixture which resets all the iris.FUTURE settings to the defaults, + as otherwise changes made in one test can affect subsequent ones. + + """ + # Run with all default settings in iris.FUTURE. + default_future_kwargs = iris.Future().__dict__.copy() + for dead_option in iris.Future.deprecated_options: + # Avoid a warning when setting these ! + del default_future_kwargs[dead_option] + with iris.FUTURE.context(**default_future_kwargs): + yield diff --git a/docs/gallery_tests/gallerytest_util.py b/docs/gallery_tests/gallerytest_util.py deleted file mode 100644 index eb2736f194..0000000000 --- a/docs/gallery_tests/gallerytest_util.py +++ /dev/null @@ -1,86 +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. - -""" -Provides context managers which are fundamental to the ability -to run the gallery tests. - -""" - -import contextlib -import os.path -import sys -import warnings - -import matplotlib.pyplot as plt - -import iris -from iris._deprecation import IrisDeprecation -import iris.plot as iplt -import iris.quickplot as qplt - -GALLERY_DIRECTORY = os.path.join( - os.path.dirname(os.path.dirname(__file__)), "gallery_code" -) -GALLERY_DIRECTORIES = [ - os.path.join(GALLERY_DIRECTORY, the_dir) - for the_dir in os.listdir(GALLERY_DIRECTORY) -] - - -@contextlib.contextmanager -def add_gallery_to_path(): - """ - Creates a context manager which can be used to add the iris gallery - to the PYTHONPATH. The gallery entries are only importable throughout the lifetime - of this context manager. - - """ - orig_sys_path = sys.path - sys.path = sys.path[:] - sys.path += GALLERY_DIRECTORIES - yield - sys.path = orig_sys_path - - -@contextlib.contextmanager -def show_replaced_by_check_graphic(test_case): - """ - Creates a context manager which can be used to replace the functionality - of matplotlib.pyplot.show with a function which calls the check_graphic - method on the given test_case (iris.tests.IrisTest.check_graphic). - - """ - - def replacement_show(): - # form a closure on test_case and tolerance - test_case.check_graphic() - - orig_show = plt.show - plt.show = iplt.show = qplt.show = replacement_show - yield - plt.show = iplt.show = qplt.show = orig_show - - -@contextlib.contextmanager -def fail_any_deprecation_warnings(): - """ - Create a context in which any deprecation warning will cause an error. - - The context also resets all the iris.FUTURE settings to the defaults, as - otherwise changes made in one test can affect subsequent ones. - - """ - with warnings.catch_warnings(): - # Detect and error all and any Iris deprecation warnings. - warnings.simplefilter("error", IrisDeprecation) - # Run with all default settings in iris.FUTURE. - default_future_kwargs = iris.Future().__dict__.copy() - for dead_option in iris.Future.deprecated_options: - # Avoid a warning when setting these ! - del default_future_kwargs[dead_option] - with iris.FUTURE.context(**default_future_kwargs): - yield diff --git a/docs/gallery_tests/test_gallery_examples.py b/docs/gallery_tests/test_gallery_examples.py new file mode 100644 index 0000000000..0d0793a7da --- /dev/null +++ b/docs/gallery_tests/test_gallery_examples.py @@ -0,0 +1,44 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the LGPL license. +# See COPYING and COPYING.LESSER in the root of the repository for full +# licensing details. + +import importlib + +import matplotlib.pyplot as plt +import pytest + +from iris.tests import _RESULT_PATH +from iris.tests.graphics import check_graphic + +from .conftest import GALLERY_DIR + + +def gallery_examples(): + """Generator to yield all current gallery examples.""" + + for example_file in GALLERY_DIR.glob("*/plot*.py"): + yield example_file.stem + + +@pytest.mark.filterwarnings("error::iris.IrisDeprecation") +@pytest.mark.parametrize("example", gallery_examples()) +def test_plot_example( + example, + image_setup_teardown, + import_patches, + iris_future_defaults, +): + """Test that all figures from example code match KGO.""" + + module = importlib.import_module(example) + + # Run example. + module.main() + # Loop through open figures and set each to be the current figure so check_graphic + # will find it. + for fig_num in plt.get_fignums(): + plt.figure(fig_num) + image_id = f"gallery_tests.test_{example}.{fig_num - 1}" + check_graphic(image_id, _RESULT_PATH) diff --git a/docs/gallery_tests/test_plot_COP_1d.py b/docs/gallery_tests/test_plot_COP_1d.py deleted file mode 100644 index 9771e10fb1..0000000000 --- a/docs/gallery_tests/test_plot_COP_1d.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestCOP1DPlot(tests.GraphicsTest): - """Test the COP_1d_plot gallery code.""" - - def test_plot_COP_1d(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_COP_1d - with show_replaced_by_check_graphic(self): - plot_COP_1d.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_COP_maps.py b/docs/gallery_tests/test_plot_COP_maps.py deleted file mode 100644 index a01e12527f..0000000000 --- a/docs/gallery_tests/test_plot_COP_maps.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestCOPMaps(tests.GraphicsTest): - """Test the COP_maps gallery code.""" - - def test_plot_cop_maps(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_COP_maps - with show_replaced_by_check_graphic(self): - plot_COP_maps.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_SOI_filtering.py b/docs/gallery_tests/test_plot_SOI_filtering.py deleted file mode 100644 index 1da731122a..0000000000 --- a/docs/gallery_tests/test_plot_SOI_filtering.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestSOIFiltering(tests.GraphicsTest): - """Test the SOI_filtering gallery code.""" - - def test_plot_soi_filtering(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_SOI_filtering - with show_replaced_by_check_graphic(self): - plot_SOI_filtering.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_TEC.py b/docs/gallery_tests/test_plot_TEC.py deleted file mode 100644 index cfc1fb8eec..0000000000 --- a/docs/gallery_tests/test_plot_TEC.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestTEC(tests.GraphicsTest): - """Test the TEC gallery code.""" - - def test_plot_TEC(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_TEC - with show_replaced_by_check_graphic(self): - plot_TEC.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_anomaly_log_colouring.py b/docs/gallery_tests/test_plot_anomaly_log_colouring.py deleted file mode 100644 index 41f76cc774..0000000000 --- a/docs/gallery_tests/test_plot_anomaly_log_colouring.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestAnomalyLogColouring(tests.GraphicsTest): - """Test the anomaly colouring gallery code.""" - - def test_plot_anomaly_log_colouring(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_anomaly_log_colouring - with show_replaced_by_check_graphic(self): - plot_anomaly_log_colouring.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_atlantic_profiles.py b/docs/gallery_tests/test_plot_atlantic_profiles.py deleted file mode 100644 index fdcb5fb1d1..0000000000 --- a/docs/gallery_tests/test_plot_atlantic_profiles.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestAtlanticProfiles(tests.GraphicsTest): - """Test the atlantic_profiles gallery code.""" - - def test_plot_atlantic_profiles(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_atlantic_profiles - with show_replaced_by_check_graphic(self): - plot_atlantic_profiles.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_coriolis.py b/docs/gallery_tests/test_plot_coriolis.py deleted file mode 100644 index 2e4cea8a74..0000000000 --- a/docs/gallery_tests/test_plot_coriolis.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. - -import iris.tests as tests - -from . import gallerytest_util - -with gallerytest_util.add_gallery_to_path(): - import plot_coriolis - - -class TestCoriolisPlot(tests.GraphicsTest): - """Test the Coriolis Plot gallery code.""" - - def test_plot_coriolis(self): - with gallerytest_util.show_replaced_by_check_graphic(self): - plot_coriolis.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_cross_section.py b/docs/gallery_tests/test_plot_cross_section.py deleted file mode 100644 index b0878d10bc..0000000000 --- a/docs/gallery_tests/test_plot_cross_section.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestCrossSection(tests.GraphicsTest): - """Test the cross_section gallery code.""" - - def test_plot_cross_section(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_cross_section - with show_replaced_by_check_graphic(self): - plot_cross_section.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_custom_aggregation.py b/docs/gallery_tests/test_plot_custom_aggregation.py deleted file mode 100644 index 9d0a40dd3c..0000000000 --- a/docs/gallery_tests/test_plot_custom_aggregation.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestCustomAggregation(tests.GraphicsTest): - """Test the custom aggregation gallery code.""" - - def test_plot_custom_aggregation(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_custom_aggregation - with show_replaced_by_check_graphic(self): - plot_custom_aggregation.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_custom_file_loading.py b/docs/gallery_tests/test_plot_custom_file_loading.py deleted file mode 100644 index 4d0d603a22..0000000000 --- a/docs/gallery_tests/test_plot_custom_file_loading.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestCustomFileLoading(tests.GraphicsTest): - """Test the custom_file_loading gallery code.""" - - def test_plot_custom_file_loading(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_custom_file_loading - with show_replaced_by_check_graphic(self): - plot_custom_file_loading.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_deriving_phenomena.py b/docs/gallery_tests/test_plot_deriving_phenomena.py deleted file mode 100644 index ef2f8cec87..0000000000 --- a/docs/gallery_tests/test_plot_deriving_phenomena.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestDerivingPhenomena(tests.GraphicsTest): - """Test the deriving_phenomena gallery code.""" - - def test_plot_deriving_phenomena(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_deriving_phenomena - with show_replaced_by_check_graphic(self): - plot_deriving_phenomena.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_global_map.py b/docs/gallery_tests/test_plot_global_map.py deleted file mode 100644 index 16f769deae..0000000000 --- a/docs/gallery_tests/test_plot_global_map.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestGlobalMap(tests.GraphicsTest): - """Test the global_map gallery code.""" - - def test_plot_global_map(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_global_map - with show_replaced_by_check_graphic(self): - plot_global_map.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_hovmoller.py b/docs/gallery_tests/test_plot_hovmoller.py deleted file mode 100644 index 29c0e72e05..0000000000 --- a/docs/gallery_tests/test_plot_hovmoller.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestGlobalMap(tests.GraphicsTest): - """Test the hovmoller gallery code.""" - - def test_plot_hovmoller(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_hovmoller - with show_replaced_by_check_graphic(self): - plot_hovmoller.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_inset.py b/docs/gallery_tests/test_plot_inset.py deleted file mode 100644 index 739e0a3224..0000000000 --- a/docs/gallery_tests/test_plot_inset.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. - -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestInsetPlot(tests.GraphicsTest): - """Test the inset plot gallery code.""" - - def test_plot_inset(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_inset - with show_replaced_by_check_graphic(self): - plot_inset.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_lagged_ensemble.py b/docs/gallery_tests/test_plot_lagged_ensemble.py deleted file mode 100644 index f0a0201613..0000000000 --- a/docs/gallery_tests/test_plot_lagged_ensemble.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestLaggedEnsemble(tests.GraphicsTest): - """Test the lagged ensemble gallery code.""" - - def test_plot_lagged_ensemble(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_lagged_ensemble - with show_replaced_by_check_graphic(self): - plot_lagged_ensemble.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_lineplot_with_legend.py b/docs/gallery_tests/test_plot_lineplot_with_legend.py deleted file mode 100644 index 5677667026..0000000000 --- a/docs/gallery_tests/test_plot_lineplot_with_legend.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestLineplotWithLegend(tests.GraphicsTest): - """Test the lineplot_with_legend gallery code.""" - - def test_plot_lineplot_with_legend(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_lineplot_with_legend - with show_replaced_by_check_graphic(self): - plot_lineplot_with_legend.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_load_nemo.py b/docs/gallery_tests/test_plot_load_nemo.py deleted file mode 100644 index f250dc46b4..0000000000 --- a/docs/gallery_tests/test_plot_load_nemo.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestLoadNemo(tests.GraphicsTest): - """Test the load_nemo gallery code.""" - - def test_plot_load_nemo(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_load_nemo - with show_replaced_by_check_graphic(self): - plot_load_nemo.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_orca_projection.py b/docs/gallery_tests/test_plot_orca_projection.py deleted file mode 100644 index c4058c996e..0000000000 --- a/docs/gallery_tests/test_plot_orca_projection.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestOrcaProjection(tests.GraphicsTest): - """Test the orca projection gallery code.""" - - def test_plot_orca_projection(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_orca_projection - with show_replaced_by_check_graphic(self): - plot_orca_projection.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_polar_stereo.py b/docs/gallery_tests/test_plot_polar_stereo.py deleted file mode 100644 index 4d32ee5830..0000000000 --- a/docs/gallery_tests/test_plot_polar_stereo.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestPolarStereo(tests.GraphicsTest): - """Test the polar_stereo gallery code.""" - - def test_plot_polar_stereo(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_polar_stereo - with show_replaced_by_check_graphic(self): - plot_polar_stereo.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_polynomial_fit.py b/docs/gallery_tests/test_plot_polynomial_fit.py deleted file mode 100644 index b522dcf43c..0000000000 --- a/docs/gallery_tests/test_plot_polynomial_fit.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestPolynomialFit(tests.GraphicsTest): - """Test the polynomial_fit gallery code.""" - - def test_plot_polynomial_fit(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_polynomial_fit - with show_replaced_by_check_graphic(self): - plot_polynomial_fit.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_projections_and_annotations.py b/docs/gallery_tests/test_plot_projections_and_annotations.py deleted file mode 100644 index 1c24202251..0000000000 --- a/docs/gallery_tests/test_plot_projections_and_annotations.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestProjectionsAndAnnotations(tests.GraphicsTest): - """Test the atlantic_profiles gallery code.""" - - def test_plot_projections_and_annotations(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_projections_and_annotations - with show_replaced_by_check_graphic(self): - plot_projections_and_annotations.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_rotated_pole_mapping.py b/docs/gallery_tests/test_plot_rotated_pole_mapping.py deleted file mode 100644 index cd9b04fc66..0000000000 --- a/docs/gallery_tests/test_plot_rotated_pole_mapping.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestRotatedPoleMapping(tests.GraphicsTest): - """Test the rotated_pole_mapping gallery code.""" - - def test_plot_rotated_pole_mapping(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_rotated_pole_mapping - with show_replaced_by_check_graphic(self): - plot_rotated_pole_mapping.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_wind_barbs.py b/docs/gallery_tests/test_plot_wind_barbs.py deleted file mode 100644 index 6003860a5e..0000000000 --- a/docs/gallery_tests/test_plot_wind_barbs.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestWindBarbs(tests.GraphicsTest): - """Test the wind_barbs example code.""" - - def test_wind_barbs(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_wind_barbs - with show_replaced_by_check_graphic(self): - plot_wind_barbs.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/gallery_tests/test_plot_wind_speed.py b/docs/gallery_tests/test_plot_wind_speed.py deleted file mode 100644 index ebaf97adbe..0000000000 --- a/docs/gallery_tests/test_plot_wind_speed.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the LGPL license. -# See COPYING and COPYING.LESSER in the root of the repository for full -# licensing details. - -# Import Iris tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests - -from .gallerytest_util import ( - add_gallery_to_path, - fail_any_deprecation_warnings, - show_replaced_by_check_graphic, -) - - -class TestWindSpeed(tests.GraphicsTest): - """Test the wind_speed gallery code.""" - - def test_plot_wind_speed(self): - with fail_any_deprecation_warnings(): - with add_gallery_to_path(): - import plot_wind_speed - with show_replaced_by_check_graphic(self): - plot_wind_speed.main() - - -if __name__ == "__main__": - tests.main() diff --git a/docs/src/Makefile b/docs/src/Makefile index c693a2c900..37c2e9e3e6 100644 --- a/docs/src/Makefile +++ b/docs/src/Makefile @@ -16,7 +16,7 @@ PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -.PHONY: help clean html html-noplot dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest +.PHONY: help clean html html-noplot dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest show help: @echo "Please use \`make ' where is one of" @@ -36,6 +36,7 @@ help: @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " show to open the built documentation in the default browser" clean: -rm -rf $(BUILDDIR) @@ -153,3 +154,6 @@ doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." + +show: + @python -c "import webbrowser; webbrowser.open_new_tab('file://$(shell pwd)/$(BUILDDIR)/html/index.html')" \ No newline at end of file diff --git a/docs/src/_templates/custom_sidebar_logo_version.html b/docs/src/_templates/custom_sidebar_logo_version.html index 48bbe604a0..c9d9ac6e2e 100644 --- a/docs/src/_templates/custom_sidebar_logo_version.html +++ b/docs/src/_templates/custom_sidebar_logo_version.html @@ -1,20 +1,26 @@ {% if on_rtd %} {% if rtd_version == 'latest' %} - + {% elif rtd_version == 'stable' %} - + + + {% elif rtd_version_type == 'tag' %} + {# Covers builds for specific tags, including RC's. #} + + {% else %} - - + {# Anything else build by RTD will be the HEAD of an activated branch #} + + {% endif %} {%- else %} {# not on rtd #} - - + + {%- endif %} diff --git a/docs/src/common_links.inc b/docs/src/common_links.inc index 7ae2463ca9..ec7e1efd6d 100644 --- a/docs/src/common_links.inc +++ b/docs/src/common_links.inc @@ -53,6 +53,7 @@ .. _@cpelley: https://github.com/cpelley .. _@djkirkham: https://github.com/djkirkham .. _@DPeterK: https://github.com/DPeterK +.. _@ESadek-MO: https://github.com/ESadek-MO .. _@esc24: https://github.com/esc24 .. _@jamesp: https://github.com/jamesp .. _@jonseddon: https://github.com/jonseddon diff --git a/docs/src/conf.py b/docs/src/conf.py index 4fe2513bb1..33864c4658 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -20,15 +20,16 @@ # ---------------------------------------------------------------------------- import datetime +from importlib.metadata import version as get_version import ntpath import os from pathlib import Path import re +from subprocess import run import sys +from urllib.parse import quote import warnings -import iris - # function to write useful output to stdout, prefixing the source. def autolog(message): @@ -43,11 +44,21 @@ def autolog(message): # This is the rtd reference to the version, such as: latest, stable, v3.0.1 etc rtd_version = os.environ.get("READTHEDOCS_VERSION") +if rtd_version is not None: + # Make rtd_version safe for use in shields.io badges. + rtd_version = rtd_version.replace("_", "__") + rtd_version = rtd_version.replace("-", "--") + rtd_version = quote(rtd_version) + +# branch, tag, external (for pull request builds), or unknown. +rtd_version_type = os.environ.get("READTHEDOCS_VERSION_TYPE") # For local testing purposes we can force being on RTD and the version # on_rtd = True # useful for testing # rtd_version = "latest" # useful for testing # rtd_version = "stable" # useful for testing +# rtd_version_type = "tag" # useful for testing +# rtd_version = "my_branch" # useful for testing if on_rtd: autolog("Build running on READTHEDOCS server") @@ -85,21 +96,11 @@ def autolog(message): author = "Iris Developers" # The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. - -# The short X.Y version. -if iris.__version__ == "dev": - version = "dev" -else: - # major.minor.patch-dev -> major.minor.patch - version = ".".join(iris.__version__.split("-")[0].split(".")[:3]) - -# The full version, including alpha/beta/rc tags. -release = iris.__version__ - -autolog("Iris Version = {}".format(version)) -autolog("Iris Release = {}".format(release)) +# |version|, also used in various other places throughout the built documents. +version = get_version("scitools-iris") +release = version +autolog(f"Iris Version = {version}") +autolog(f"Iris Release = {release}") # -- General configuration --------------------------------------------------- @@ -233,6 +234,7 @@ def _dotv(version): "numpy": ("https://numpy.org/doc/stable/", None), "python": ("https://docs.python.org/3/", None), "scipy": ("https://docs.scipy.org/doc/scipy/", None), + "pandas": ("https://pandas.pydata.org/docs/", None), } # The name of the Pygments (syntax highlighting) style to use. @@ -310,6 +312,9 @@ def _dotv(version): "show_toc_level": 1, } +rev_parse = run(["git", "rev-parse", "--short", "HEAD"], capture_output=True) +commit_sha = rev_parse.stdout.decode().strip() + html_context = { # pydata_theme "github_repo": "iris", @@ -319,9 +324,11 @@ def _dotv(version): # custom "on_rtd": on_rtd, "rtd_version": rtd_version, + "rtd_version_type": rtd_version_type, "version": version, "copyright_years": copyright_years, "python_version": build_python_version, + "commit_sha": commit_sha, } # Add any paths that contain custom static files (such as style sheets) here, @@ -376,6 +383,11 @@ def _dotv(version): "ignore_pattern": r"__init__\.py", # force gallery building, unless overridden (see src/Makefile) "plot_gallery": "'True'", + # force re-registering of nc-time-axis with matplotlib for each example, + # required for sphinx-gallery>=0.11.0 + "reset_modules": ( + lambda gallery_conf, fname: sys.modules.pop("nc_time_axis", None), + ), } # ----------------------------------------------------------------------------- diff --git a/docs/src/developers_guide/contributing_documentation_full.rst b/docs/src/developers_guide/contributing_documentation_full.rst index 46f9c563d1..41314e80ac 100755 --- a/docs/src/developers_guide/contributing_documentation_full.rst +++ b/docs/src/developers_guide/contributing_documentation_full.rst @@ -61,7 +61,10 @@ If you wish to run a full clean build you can run:: make clean make html -This is useful for a final test before committing your changes. +This is useful for a final test before committing your changes. Having built +the documentation, you can view them in your default browser via:: + + make show .. note:: In order to preserve a clean build for the html, all **warnings** have been promoted to be **errors** to ensure they are addressed. @@ -72,14 +75,20 @@ This is useful for a final test before committing your changes. Testing ~~~~~~~ -There are a ways to test various aspects of the documentation. The -``make`` commands shown below can be run in the ``docs`` or -``docs/src`` directory. +There are various ways to test aspects of the documentation. Each :ref:`contributing.documentation.gallery` entry has a corresponding test. -To run the tests:: +To run all the gallery tests:: + + pytest -v docs/gallery_tests/test_gallery_examples.py + +To run a test for a single gallery example, use the ``pytest -k`` option for +pattern matching, e.g.:: + + pytest -v -k plot_coriolis docs/gallery_tests/test_gallery_examples.py - make gallerytest +The ``make`` commands shown below can be run in the ``docs`` or ``docs/src`` +directory. Many documentation pages includes python code itself that can be run to ensure it is still valid or to demonstrate examples. To ensure these tests pass @@ -147,7 +156,7 @@ can exclude the module from the API documentation. Add the entry to the Gallery ~~~~~~~ -The Iris :ref:`sphx_glr_generated_gallery` uses a sphinx extension named +The Iris :ref:`gallery_index` uses a sphinx extension named `sphinx-gallery `_ that auto generates reStructuredText (rst) files based upon a gallery source directory that abides directory and filename convention. diff --git a/docs/src/developers_guide/contributing_running_tests.rst b/docs/src/developers_guide/contributing_running_tests.rst index b9b89b3336..f60cedba05 100644 --- a/docs/src/developers_guide/contributing_running_tests.rst +++ b/docs/src/developers_guide/contributing_running_tests.rst @@ -5,13 +5,22 @@ Running the Tests ***************** -Using setuptools for Testing Iris -================================= +There are two options for running the tests: -.. warning:: The `setuptools`_ ``test`` command was deprecated in `v41.5.0`_. See :ref:`using nox`. +* Use an environment you created yourself. This requires more manual steps to + set up, but gives you more flexibility. For example, you can run a subset of + the tests or use ``python`` interactively to investigate any issues. See + :ref:`test manual env`. -A prerequisite of running the tests is to have the Python environment -setup. For more information on this see :ref:`installing_from_source`. +* Use ``nox``. This will automatically generate an environment and run test + sessions consistent with our GitHub continuous integration. See :ref:`using nox`. + +.. _test manual env: + +Testing Iris in a Manually Created Environment +============================================== + +To create a suitable environment for running the tests, see :ref:`installing_from_source`. Many Iris tests will use data that may be defined in the test itself, however this is not always the case as sometimes example files may be used. Due to @@ -32,74 +41,69 @@ The example command below uses ``~/projects`` as the parent directory:: git clone git@github.com:SciTools/iris-test-data.git export OVERRIDE_TEST_DATA_REPOSITORY=~/projects/iris-test-data/test_data -All the Iris tests may be run from the root ``iris`` project directory via:: - - python setup.py test - -You can also run a specific test, the example below runs the tests for -mapping:: - - cd lib/iris/tests - python test_mapping.py - -When running the test directly as above you can view the command line options -using the commands ``python test_mapping.py -h`` or -``python test_mapping.py --help``. - -.. tip:: A useful command line option to use is ``-d``. This will display - matplotlib_ figures as the tests are run. For example:: - - python test_mapping.py -d +All the Iris tests may be run from the root ``iris`` project directory using +``pytest``. For example:: - You can also use the ``-d`` command line option when running all - the tests but this will take a while to run and will require the - manual closing of each of the figures for the tests to continue. + pytest -n 2 -The output from running the tests is verbose as it will run ~5000 separate -tests. Below is a trimmed example of the output:: +will run the tests across two processes. For more options, use the command +``pytest -h``. Below is a trimmed example of the output:: - running test - Running test suite(s): default + ============================= test session starts ============================== + platform linux -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0 + rootdir: /path/to/git/clone/iris, configfile: pyproject.toml, testpaths: lib/iris + plugins: xdist-2.5.0, forked-1.4.0 + gw0 I / gw1 I + gw0 [6361] / gw1 [6361] - Running test discovery on iris.tests with 2 processors. - test_circular_subset (iris.tests.experimental.regrid.test_regrid_area_weighted_rectilinear_src_and_grid.TestAreaWeightedRegrid) ... ok - test_cross_section (iris.tests.experimental.regrid.test_regrid_area_weighted_rectilinear_src_and_grid.TestAreaWeightedRegrid) ... ok - test_different_cs (iris.tests.experimental.regrid.test_regrid_area_weighted_rectilinear_src_and_grid.TestAreaWeightedRegrid) ... ok + ........................................................................ [ 1%] + ........................................................................ [ 2%] + ........................................................................ [ 3%] ... + .......................ssssssssssssssssss............................... [ 99%] + ........................ [100%] + =============================== warnings summary =============================== ... - test_ellipsoid (iris.tests.unit.experimental.raster.test_export_geotiff.TestProjection) ... SKIP: Test requires 'gdal'. - test_no_ellipsoid (iris.tests.unit.experimental.raster.test_export_geotiff.TestProjection) ... SKIP: Test requires 'gdal'. + -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html + =========================== short test summary info ============================ + SKIPPED [1] lib/iris/tests/experimental/test_raster.py:152: Test requires 'gdal'. + SKIPPED [1] lib/iris/tests/experimental/test_raster.py:155: Test requires 'gdal'. ... - ... - test_slice (iris.tests.test_util.TestAsCompatibleShape) ... ok - test_slice_and_transpose (iris.tests.test_util.TestAsCompatibleShape) ... ok - test_transpose (iris.tests.test_util.TestAsCompatibleShape) ... ok - - ---------------------------------------------------------------------- - Ran 4762 tests in 238.649s - - OK (SKIP=22) + ========= 6340 passed, 21 skipped, 1659 warnings in 193.57s (0:03:13) ========== There may be some tests that have been **skipped**. This is due to a Python decorator being present in the test script that will intentionally skip a test if a certain condition is not met. In the example output above there are -**22** skipped tests, at the point in time when this was run this was primarily -due to an experimental dependency not being present. - +**21** skipped tests. At the point in time when this was run this was due to an +experimental dependency not being present. .. tip:: The most common reason for tests to be skipped is when the directory for the ``iris-test-data`` has not been set which would shows output such as:: - test_coord_coord_map (iris.tests.test_plot.Test1dScatter) ... SKIP: Test(s) require external data. - test_coord_coord (iris.tests.test_plot.Test1dScatter) ... SKIP: Test(s) require external data. - test_coord_cube (iris.tests.test_plot.Test1dScatter) ... SKIP: Test(s) require external data. - + SKIPPED [1] lib/iris/tests/unit/fileformats/test_rules.py:157: Test(s) require external data. + SKIPPED [1] lib/iris/tests/unit/fileformats/pp/test__interpret_field.py:97: Test(s) require external data. + SKIPPED [1] lib/iris/tests/unit/util/test_demote_dim_coord_to_aux_coord.py:29: Test(s) require external data. + All Python decorators that skip tests will be defined in ``lib/iris/tests/__init__.py`` with a function name with a prefix of ``skip_``. +You can also run a specific test module. The example below runs the tests for +mapping:: + + cd lib/iris/tests + python test_mapping.py + +When running the test directly as above you can view the command line options +using the commands ``python test_mapping.py -h`` or +``python test_mapping.py --help``. + +.. tip:: A useful command line option to use is ``-d``. This will display + matplotlib_ figures as the tests are run. For example:: + + python test_mapping.py -d .. _using nox: diff --git a/docs/src/developers_guide/github_app.rst b/docs/src/developers_guide/github_app.rst index 338166fd76..402cfe0c75 100644 --- a/docs/src/developers_guide/github_app.rst +++ b/docs/src/developers_guide/github_app.rst @@ -8,6 +8,15 @@ Token GitHub App This section of the documentation is applicable only to GitHub `SciTools`_ Organisation **owners** and **administrators**. +.. note:: + + The ``iris-actions`` GitHub App has been rebranded with the more generic + name ``scitools-ci``, as the app can be used for any `SciTools`_ repository, + not just ``iris`` specifically. + + All of the following instructions are still applicable. + + This section describes how to create, configure, install and use our `SciTools`_ GitHub App for generating tokens for use with *GitHub Actions* (GHA). @@ -269,4 +278,4 @@ to generate a token for use with the `create-pull-request`_ GHA: .. _conda-lock: https://github.com/conda-incubator/conda-lock .. _create-pull-request: https://github.com/peter-evans/create-pull-request .. _github-app-token: https://github.com/tibdex/github-app-token -.. _refresh-lockfiles: https://github.com/SciTools/iris/blob/main/.github/workflows/refresh-lockfiles.yml \ No newline at end of file +.. _refresh-lockfiles: https://github.com/SciTools/iris/blob/main/.github/workflows/refresh-lockfiles.yml diff --git a/docs/src/developers_guide/release.rst b/docs/src/developers_guide/release.rst index b2de9106a2..de7aa6c719 100644 --- a/docs/src/developers_guide/release.rst +++ b/docs/src/developers_guide/release.rst @@ -100,12 +100,14 @@ Steps to achieve this can be found in the :ref:`iris_development_releases_steps` The Release ----------- -The final steps of the release are to change the version string ``__version__`` -in the source of :literal:`iris.__init__.py` and ensure the release date and details +The final steps of the release are to ensure that the release date and details are correct in the relevant ``whatsnew`` page within the documentation. -Once all checks are complete, the release is cut by the creation of a new tag -in the ``SciTools/iris`` repository. +There is no need to update the ``iris.__version__``, as this is managed +automatically by `setuptools-scm`_. + +Once all checks are complete, the release is published on GitHub by +creating a new tag in the ``SciTools/iris`` repository. Update conda-forge @@ -121,6 +123,14 @@ conda package on the `conda-forge Anaconda channel`_. Update PyPI ----------- +.. note:: + + As part of our Continuous-Integration (CI), the building and publishing of + PyPI artifacts is now automated by a dedicated GitHub Action. + + The following instructions **no longer** require to be performed manually, + but remain part of the documentation for reference purposes only. + Update the `scitools-iris`_ project on PyPI with the latest Iris release. To do this perform the following steps. @@ -179,14 +189,14 @@ For further details on how to test Iris, see :ref:`developer_running_tests`. Merge Back ---------- -After the release is cut, the changes from the release branch should be merged +After the release is published, the changes from the release branch should be merged back onto the ``SciTools/iris`` ``main`` branch. To achieve this, first cut a local branch from the latest ``main`` branch, and `git merge` the :literal:`.x` release branch into it. Ensure that the -``iris.__version__``, ``docs/src/whatsnew/index.rst``, -and ``docs/src/whatsnew/latest.rst`` are correct, before committing these changes -and then proposing a pull-request on the ``main`` branch of ``SciTools/iris``. +``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``. Point Releases @@ -199,6 +209,11 @@ branch, and then released by tagging ``v1.9.1``. New features shall not be included in a point release, these are for bug fixes. +``whatsnew`` entries should be added to the existing +``docs/src/whatsnew/v1.9.rst`` file in a new ``v1.9.1`` section. A template for +this bugfix patches section can be found in the +``docs/src/whatsnew/latest.rst.template`` file. + A point release does not require a release candidate, but the rest of the release process is to be followed, including the merge back of changes into ``main``. @@ -214,17 +229,14 @@ These steps assume a release for ``1.9.0`` is to be created. Release Steps ~~~~~~~~~~~~~ -#. Create the release feature branch ``v1.9.x`` on `SciTools/iris`_. - The only exception is for a point/bugfix release, as it should already exist -#. Update the ``iris.__init__.py`` version string e.g., to ``1.9.0`` #. Update the ``whatsnew`` for the release: * Use ``git`` to rename ``docs/src/whatsnew/latest.rst`` to the release version file ``v1.9.rst`` - * Update ``docs/src/whatsnews/index.rst`` to rename ``latest.rst`` in the - include statement and toctree. * Use ``git`` to delete the ``docs/src/whatsnew/latest.rst.template`` file * In ``v1.9.rst`` remove the ``[unreleased]`` caption from the page title. + Replace this with ``[release candidate]`` for the release candidate and + remove this for the actual release. Note that, the Iris version and release date are updated automatically when the documentation is built * Review the file for correctness @@ -243,6 +255,9 @@ Release Steps #. Once all the above steps are complete, the release is cut, using the :guilabel:`Draft a new release` button on the `Iris release page `_ + and targeting the release branch if it exists +#. Create the release feature branch ``v1.9.x`` on `SciTools/iris`_ if it doesn't + already exist. For point/bugfix releases use the branch which already exists Post Release Steps @@ -250,17 +265,18 @@ Post Release Steps #. Check the documentation has built on `Read The Docs`_. The build is triggered by any commit to ``main``. Additionally check that the versions - available in the pop out menu in the bottom left corner include the new + available in the pop out menu in the bottom right corner include the new release version. If it is not present you will need to configure the versions available in the **admin** dashboard in `Read The Docs`_. #. Review the `Active Versions`_ for the ``scitools-iris`` project on `Read The Docs`_ to ensure that the appropriate versions are ``Active`` and/or ``Hidden``. To do this ``Edit`` the appropriate version e.g., see `Editing v3.0.0rc0`_ (must be logged into Read the Docs). -#. Make a new ``latest.rst`` from ``latest.rst.template`` and update the include - statement and the toctree in ``index.rst`` to point at the new +#. Merge back to ``main``. This should be done after all releases, including + the release candidate, and also after major changes to the release branch. +#. On main, make a new ``latest.rst`` from ``latest.rst.template`` and update + the include statement and the toctree in ``index.rst`` to point at the new ``latest.rst``. -#. Merge back to ``main`` .. _SciTools/iris: https://github.com/SciTools/iris @@ -274,4 +290,5 @@ Post Release Steps .. _rc_iris: https://anaconda.org/conda-forge/iris/labels .. _Generating Distribution Archives: https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives .. _Packaging Your Project: https://packaging.python.org/guides/distributing-packages-using-setuptools/#packaging-your-project -.. _latest CF standard names: http://cfconventions.org/standard-names.html \ No newline at end of file +.. _latest CF standard names: http://cfconventions.org/standard-names.html +.. _setuptools-scm: https://github.com/pypa/setuptools_scm diff --git a/docs/src/developers_guide/testing_tools.rst b/docs/src/developers_guide/testing_tools.rst index f4faee084f..dd628d37fc 100755 --- a/docs/src/developers_guide/testing_tools.rst +++ b/docs/src/developers_guide/testing_tools.rst @@ -24,8 +24,7 @@ Custom assertions ================= :class:`iris.tests.IrisTest` supports a variety of custom unittest-style -assertions, such as :meth:`~iris.tests.IrisTest_nometa.assertStringEqual`, -:meth:`~iris.tests.IrisTest_nometa.assertArrayEqual`, +assertions, such as :meth:`~iris.tests.IrisTest_nometa.assertArrayEqual`, :meth:`~iris.tests.IrisTest_nometa.assertArrayAlmostEqual`. .. _create-missing: diff --git a/docs/src/further_topics/ugrid/images/orca_grid.png b/docs/src/further_topics/ugrid/images/orca_grid.png new file mode 100644 index 0000000000..6676e84fbb Binary files /dev/null and b/docs/src/further_topics/ugrid/images/orca_grid.png differ diff --git a/docs/src/further_topics/ugrid/other_meshes.rst b/docs/src/further_topics/ugrid/other_meshes.rst index e6f477624e..38abeeca03 100644 --- a/docs/src/further_topics/ugrid/other_meshes.rst +++ b/docs/src/further_topics/ugrid/other_meshes.rst @@ -221,5 +221,140 @@ as the **nodes** when creating the Iris + +.. _ORCA_example: + +`NEMO`_ data on ORCA tripolar grid +---------------------------------- +.. figure:: images/orca_grid.png + :width: 300 + :alt: Plot of ORCA-gridded data from NEMO. + +NEMO can use various grids, but is frequently used with ORCA type grids. +ORCA grids store global data in 2-dimensional ny * nx arrays. All cells are +four-sided. The grids are based on tri-polar layouts, but X and Y spacings are +irregular and not given by any defined functional forms. + +* arrays (ny, nx) of face-located data variables +* arrays (ny, nx) of X+Y face centre coordinates +* arrays (ny, nx, 4) of X+Y face corner coordinates + (all faces are quadrilaterals) + +For simplicity, we treat each face corner as an independent node, and use a face-node +connectivity which simply lists the nodes in sequence, +i.e. [[0, 1, 2, 3], [4, 5, 6, 7], ...]. + +.. Note:: + This is the simplest solution, but produces approx 4x more nodes than + necessary, since the coordinate bounds contain many duplicate locations. + Removing the duplicates is quite easy, but often not necessary. + +To make an unstructured cube, the data must be 'flattened' to convert the given X and Y +dimensions into a single mesh dimension. Since Iris cubes don't support a "reshape" or +"flatten" operations, we create a new cube from the flattened data. + +.. dropdown:: :opticon:`code` + + .. code-block:: python + + >>> import numpy as np + >>> import iris + >>> from iris.coords import AuxCoord, CellMeasure + >>> from iris.cube import Cube + >>> from iris.experimental.ugrid.mesh import Mesh, Connectivity + + + >>> filepath = iris.sample_data_path('orca2_votemper.nc') + >>> cube = iris.load_cube(filepath) + >>> print(cube) + sea_water_potential_temperature / (degC) (-- : 148; -- : 180) + Auxiliary coordinates: + latitude x x + longitude x x + Scalar coordinates: + depth 4.999938 m, bound=(0.0, 10.0) m + time 0001-01-01 12:00:00 + Cell methods: + mean time + Attributes: + Conventions 'CF-1.5' + + + >>> co_x = cube.coord("longitude") + >>> co_y = cube.coord("latitude") + >>> ny, nx = co_x.shape + >>> n_faces = ny * nx + + >>> # Create face coords from flattened face-points + >>> face_x_co = AuxCoord(co_x.points.flatten()) + >>> face_y_co = AuxCoord(co_y.points.flatten()) + >>> assert face_x_co.shape == (n_faces,) + >>> face_x_co.metadata = co_x.metadata + >>> face_y_co.metadata = co_y.metadata + + >>> # Create node coordinates from bound points. + >>> n_nodes = n_faces * 4 + >>> node_x_co = AuxCoord(co_x.bounds.flatten()) + >>> node_y_co = AuxCoord(co_y.bounds.flatten()) + >>> assert node_x_co.shape == (n_nodes,) + >>> node_x_co.metadata = co_x.metadata + >>> node_y_co.metadata = co_y.metadata + + >>> # Create a face-node Connectivity matching the order of nodes in the bounds array + >>> face_node_inds = np.arange(n_nodes).reshape((n_faces, 4)) + >>> face_nodes_conn = Connectivity( + ... indices=face_node_inds, + ... cf_role='face_node_connectivity', + ... long_name='face_inds', units='1', + ... ) + + >>> # Create a mesh object. + >>> mesh = Mesh( + ... topology_dimension=2, + ... node_coords_and_axes=[(node_x_co, 'x'), (node_y_co, 'y')], + ... connectivities=face_nodes_conn, + ... face_coords_and_axes=[(face_x_co, 'x'), (face_y_co, 'y')] + ... ) + >>> print(mesh) + Mesh : 'unknown' + topology_dimension: 2 + node + node_dimension: 'Mesh2d_node' + node coordinates + + + face + face_dimension: 'Mesh2d_face' + face_node_connectivity: + face coordinates + + + + + >>> # Create an unstructured version of the input with flattened data + >>> meshcube = Cube(cube.core_data().flatten()) + >>> meshcube.metadata = cube.metadata + + >>> # Attach the mesh by adding the mesh 'face' MeshCoords into the cube + >>> mesh_dim = meshcube.ndim - 1 + >>> for co in mesh.to_MeshCoords('face'): + ... meshcube.add_aux_coord(co, mesh_dim) + ... + + >>> print(meshcube) + sea_water_potential_temperature / (degC) (-- : 26640) + Mesh coordinates: + latitude x + longitude x + Mesh: + name unknown + location face + Cell methods: + mean time + Attributes: + Conventions 'CF-1.5' + + .. _WAVEWATCH III: https://github.com/NOAA-EMC/WW3 .. _FESOM 1.4: https://fesom.de/models/fesom14/ +.. _NEMO: https://www.nemo-ocean.eu/ \ No newline at end of file diff --git a/docs/src/installing.rst b/docs/src/installing.rst index 33b15610fa..6a2d2f6131 100644 --- a/docs/src/installing.rst +++ b/docs/src/installing.rst @@ -119,9 +119,9 @@ Running the Tests To ensure your setup is configured correctly you can run the test suite using the command:: - python setup.py test + pytest -For more information see :ref:`developer_running_tests`. +For more information see :ref:`test manual env`. Custom Site Configuration diff --git a/docs/src/techpapers/um_files_loading.rst b/docs/src/techpapers/um_files_loading.rst index 72d34962ce..f8c94cab08 100644 --- a/docs/src/techpapers/um_files_loading.rst +++ b/docs/src/techpapers/um_files_loading.rst @@ -350,7 +350,7 @@ information is contained in the :attr:`~iris.coords.Coord.units` property. always 1st Jan 1970 (times before this are represented as negative values). The units.calendar property of time coordinates is set from the lowest decimal -digit of LBTIM, known as LBTIM.IC. Note that the non-gregorian calendars (e.g. +digit of LBTIM, known as LBTIM.IC. Note that the non-standard calendars (e.g. 360-day 'model' calendar) are defined in CF, not udunits. There are a number of different time encoding methods used in UM data, but the diff --git a/docs/src/userguide/glossary.rst b/docs/src/userguide/glossary.rst new file mode 100644 index 0000000000..818ef0c7ad --- /dev/null +++ b/docs/src/userguide/glossary.rst @@ -0,0 +1,210 @@ +.. _glossary: + +Glossary +============= + +.. glossary:: + + Cartopy + A python package for producing maps, and other geospatial data. + Allows plotting on these maps, over a range of projections. + + | **Related:** :term:`Matplotlib` + | **More information:** `CartoPy Site `_ + | + + CF Conventions + Rules for storing meteorological Climate and Forecast data in + :term:`NetCDF Format` files, defining a standard metadata format to + describe what the data is. + This also forms the data model which iris is based on. + + | **Related:** :term:`NetCDF Format` + | **More information:** `CF Conventions `_ + | + + Coordinate + A container for data points, comes in three main flavours. + + - Dimensional Coordinate - + A coordinate that describes a single data dimension of a cube. + They can only contain numerical values, in a sorted order (ascending + or descending). + - Auxiliary Coordinate - + A coordinate that can map to multiple data dimensions. Can + contain any type of data. + - Scalar Coordinate - + A coordinate that is not mapped to any data dimension, instead + representing the cube as a whole. + + | **Related:** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + Cube + Cubes are the main method of storing data in Iris. A cube can consist of: + + - Array of :term:`Phenomenon` Data (Required) + - :term:`Coordinates ` + - :term:`Standard Name` + - :term:`Long Name` + - :term:`Unit` + - :term:`Cell Methods ` + - :term:`Coordinate Factories ` + + | **Related:** :term:`NumPy` + | **More information:** :doc:`iris_cubes` + | + + Cell Method + A cell method represents that a cube's data has been derived from + a past statistical operation, such as a + MEAN or SUM operation. + + | **Related:** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + Coordinate Factory + A coordinate factory derives coordinates (sometimes referred to as + derived coordinates) from the values of existing coordinates. + E.g. A hybrid height factory might use "height above sea level" + and "height at ground level" coordinate data to calculate a + "height above ground level" coordinate. + + | **Related:** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + + Dask + A data analytics python library. Iris predominantly uses Dask Arrays; + a collection of NumPy-esque arrays. The data is operated in batches, + so that not all data is in RAM at once. + + | **Related:** :term:`Lazy Data` **|** :term:`NumPy` + | **More information:** :doc:`real_and_lazy_data` + | + + Fields File (FF) Format + A meteorological file format, the output of the Unified Model. + + | **Related:** :term:`GRIB Format` + **|** :term:`Post Processing (PP) Format` **|** :term:`NetCDF Format` + | **More information:** `Unified Model `_ + | + + GRIB Format + A WMO-standard meteorological file format. + + | **Related:** :term:`Fields File (FF) Format` + **|** :term:`Post Processing (PP) Format` **|** :term:`NetCDF Format` + | **More information:** `GRIB 1 User Guide `_ + **|** `GRIB 2 User Guide.pdf `_ + | + + Lazy Data + Data stored in hard drive, and then temporarily loaded into RAM in + batches when needed. Allows of less memory usage and faster performance, + thanks to parallel processing. + + | **Related:** :term:`Dask` **|** :term:`Real Data` + | **More information:** :doc:`real_and_lazy_data` + | + + Long Name + A name describing a :term:`phenomenon`, not limited to the + the same restraints as :term:`standard name`. + + | **Related:** :term:`Standard Name` **|** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + Matplotlib + A python package for plotting and projecting data in a wide variety + of formats. + + | **Related:** :term:`CartoPy` **|** :term:`NumPy` + | **More information:** `Matplotlib `_ + | + + Metadata + The information which describes a phenomenon. + Within Iris specifically, all information which + distinguishes one phenomenon from another, + e.g. :term:`units ` or :term:`Cell Methods ` + + | **Related:** :term:`Phenomenon` **|** :term:`Cube` + | **More information:** :doc:`../further_topics/metadata` + | + + NetCDF Format + A flexible file format for storing multi-dimensional array-like data. + When Iris loads this format, it also especially recognises and interprets data + encoded according to the :term:`CF Conventions`. + + | **Related:** :term:`Fields File (FF) Format` + **|** :term:`GRIB Format` **|** :term:`Post Processing (PP) Format` + | **More information:** `NetCDF-4 Python Git `_ + | + + NumPy + A mathematical Python library, predominantly based around + multi-dimensional arrays. + + | **Related:** :term:`Dask` **|** :term:`Cube` + **|** :term:`Xarray` + | **More information:** `NumPy.org `_ + | + + Phenomenon + The primary data which is measured, usually within a cube, e.g. + air temperature. + + | **Related:** :term:`Metadata` + **|** :term:`Standard Name` **|** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + Post Processing (PP) Format + A meteorological file format, created from a post processed + :term:`Fields File (FF) Format`. + + | **Related:** :term:`GRIB Format` **|** :term:`NetCDF Format` + | **More information:** `PP Wikipedia Page `_ + | + + Real Data + Data that has been loaded into RAM, as opposed to sitting + on the hard drive. + + | **Related:** :term:`Lazy Data` **|** :term:`NumPy` + | **More information:** :doc:`real_and_lazy_data` + | + + Standard Name + A name describing a :term:`phenomenon`, one from a fixed list + defined at `CF Standard Names `_. + + | **Related:** :term:`Long Name` **|** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + Unit + The unit with which the :term:`phenomenon` is measured e.g. m / sec. + + | **Related:** :term:`Cube` + | **More information:** :doc:`iris_cubes` + | + + Xarray + A python library for sophisticated labelled multi-dimensional operations. + Has a broader scope than Iris - it is not focused on meteorological data. + + | **Related:** :term:`NumPy` + | **More information:** `Xarray Documentation `_ + | + +---- + +`To top `_ diff --git a/docs/src/userguide/index.rst b/docs/src/userguide/index.rst index 08923e7662..fdd0c4d03e 100644 --- a/docs/src/userguide/index.rst +++ b/docs/src/userguide/index.rst @@ -35,6 +35,7 @@ they may serve as a useful reference for future exploration. cube_maths citation code_maintenance + glossary .. toctree:: diff --git a/docs/src/userguide/subsetting_a_cube.rst b/docs/src/userguide/subsetting_a_cube.rst index 6523ab1cd7..c4f55490af 100644 --- a/docs/src/userguide/subsetting_a_cube.rst +++ b/docs/src/userguide/subsetting_a_cube.rst @@ -172,7 +172,7 @@ objects 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 : time / (hours since 1970-01-01 00:00:00, gregorian calendar) + DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [2009-11-19 10:00:00, 2009-11-19 11:00:00, 2009-11-19 12:00:00] shape: (3,) dtype: float64 @@ -182,7 +182,7 @@ objects for ease of calendar-based testing. >>> cube_11 = cube_all.extract(hour_11) >>> print('Selected times :\n' + str(cube_11.coord('time'))) Selected times : - DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar) + DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [2009-11-19 11:00:00] shape: (1,) dtype: float64 @@ -210,7 +210,7 @@ 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 : time / (hours since 1970-01-01 00:00:00, gregorian calendar) + DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [2009-11-19 11:00:00] shape: (1,) dtype: float64 @@ -234,7 +234,7 @@ day of every week for many years: :options: +NORMALIZE_WHITESPACE, +ELLIPSIS >>> print(long_ts.coord('time')) - DimCoord : time / (days since 2007-04-09, gregorian calendar) + DimCoord : time / (days since 2007-04-09, standard calendar) points: [ 2007-04-09 00:00:00, 2007-04-16 00:00:00, ..., 2010-02-08 00:00:00, 2010-02-15 00:00:00] @@ -255,7 +255,7 @@ we constrain that coord using :class:`iris.cube.Cube.extract` ... time=lambda cell: d1 <= cell.point < d2) >>> within_st_swithuns_07 = long_ts.extract(st_swithuns_daterange_07) >>> print(within_st_swithuns_07.coord('time')) - DimCoord : time / (days since 2007-04-09, gregorian calendar) + DimCoord : time / (days since 2007-04-09, standard calendar) points: [ 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00, 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00] @@ -275,7 +275,7 @@ 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 : time / (days since 2007-04-09, gregorian calendar) + DimCoord : time / (days since 2007-04-09, standard calendar) points: [ 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00, 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00] @@ -296,7 +296,7 @@ PartialDateTime this becomes simple: ... >>> # 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) + DimCoord : time / (days since 2007-04-09, standard calendar) points: [ 2007-07-16 00:00:00, 2007-07-23 00:00:00, 2007-07-30 00:00:00, 2007-08-06 00:00:00, 2007-08-13 00:00:00, 2007-08-20 00:00:00, diff --git a/docs/src/whatsnew/3.3.rst b/docs/src/whatsnew/3.3.rst new file mode 100644 index 0000000000..c2e47f298a --- /dev/null +++ b/docs/src/whatsnew/3.3.rst @@ -0,0 +1,373 @@ +.. include:: ../common_links.inc + +v3.3 (1 Sep 2022) +***************** + +This document explains the changes made to Iris for this release +(:doc:`View all changes `.) + + +.. dropdown:: :opticon:`report` v3.3.0 Release Highlights + :container: + shadow + :title: text-primary text-center font-weight-bold + :body: bg-light + :animate: fade-in + :open: + + The highlights for this minor release of Iris include: + + * We've added support for datums, loading them from NetCDF when the + :obj:`iris.FUTURE.datum_support` flag is set. + * We've greatly improved the speed of linear interpolation. + * We've added the function :func:`iris.pandas.as_cubes` for richer + conversion from Pandas. + * We've improved the functionality of :func:`iris.util.mask_cube`. + * We've improved the functionality and performance of the + :obj:`iris.analysis.PERCENTILE` aggregator. + * We've completed implementation of our :ref:`contributing.benchmarks` + infrastructure. + + And finally, get in touch with us on :issue:`GitHub` if you have + any issues or feature requests for improving Iris. Enjoy! + + +v3.3.1 (29 Sep 2022) +==================== + +.. dropdown:: :opticon:`alert` v3.3.1 Patches + :container: + shadow + :title: text-primary text-center font-weight-bold + :body: bg-light + :animate: fade-in + + The patches in this release of Iris include: + + #. `@pp-mo`_ fixed the Jupyter notebook display of :class:`~iris.cube.CubeList`. + (:issue:`4973`, :pull:`4976`) + + #. `@pp-mo`_ fixed a bug in NAME loaders where data with no associated statistic would + load as a cube with invalid cell-methods, which cannot be printed or saved to netcdf. + (:issue:`3288`, :pull:`4933`) + + #. `@pp-mo`_ ensured that :data:`iris.cube.Cube.cell_methods` must always be an iterable + of :class:`iris.coords.CellMethod` objects (:pull:`4933`). + + #. `@trexfeathers`_ advanced the Cartopy pin to ``>=0.21``, as Cartopy's + change to default Transverse Mercator projection affects an Iris test. + See `SciTools/cartopy@fcb784d`_ and `SciTools/cartopy@8860a81`_ for more + details. (:pull:`4992`) + + #. `@trexfeathers`_ introduced the ``netcdf4!=1.6.1`` pin to avoid a + problem with segfaults. (:pull:`4992`) + + +📢 Announcements +================ + +#. Welcome to `@krikru`_ who made their first contribution to Iris 🎉 + + +✨ Features +=========== + +#. `@schlunma`_ added weighted aggregation over "group coordinates": + :meth:`~iris.cube.Cube.aggregated_by` now accepts the keyword `weights` if a + :class:`~iris.analysis.WeightedAggregator` is used. (:issue:`4581`, + :pull:`4589`) + +#. `@wjbenfold`_ added support for ``false_easting`` and ``false_northing`` to + :class:`~iris.coord_systems.Mercator`. (:issue:`3107`, :pull:`4524`) + +#. `@rcomer`_ and `@wjbenfold`_ (reviewer) implemented lazy aggregation for the + :obj:`iris.analysis.PERCENTILE` aggregator. (:pull:`3901`) + +#. `@pp-mo`_ fixed cube arithmetic operation for cubes with meshes. + (:issue:`4454`, :pull:`4651`) + +#. `@wjbenfold`_ added support for CF-compliant treatment of + ``standard_parallel`` and ``scale_factor_at_projection_origin`` to + :class:`~iris.coord_systems.Mercator`. (:issue:`3844`, :pull:`4609`) + +#. `@wjbenfold`_ added support datums associated with coordinate systems (e.g. + :class:`~iris.coord_systems.GeogCS` other subclasses of + :class:`~iris.coord_systems.CoordSystem`). Loading of datum information from + a netCDF file only happens when the :obj:`iris.FUTURE.datum_support` flag is + set. (:issue:`4619`, :pull:`4704`) + +#. `@wjbenfold`_ and `@stephenworsley`_ (reviewer) added a maximum run length + aggregator (:class:`~iris.analysis.MAX_RUN`). (:pull:`4676`) + +#. `@wjbenfold`_ and `@rcomer`_ (reviewer) added a ``climatological`` keyword to + :meth:`~iris.cube.Cube.aggregated_by` that causes the climatological flag to + be set and the point for each cell to equal its first bound, thereby + preserving the time of year. (:issue:`1422`, :issue:`4098`, :issue:`4665`, + :pull:`4723`) + +#. `@wjbenfold`_ and `@pp-mo`_ (reviewer) implemented the + :class:`~iris.coord_systems.PolarStereographic` CRS. (:issue:`4770`, + :pull:`4773`) + +#. `@rcomer`_ and `@wjbenfold`_ (reviewer) enabled passing of the + :func:`numpy.percentile` keywords through the :obj:`~iris.analysis.PERCENTILE` + aggregator. (:pull:`4791`) + +#. `@wjbenfold`_ and `@bjlittle`_ (reviewer) implemented + :func:`iris.plot.fill_between` and :func:`iris.quickplot.fill_between`. + (:issue:`3493`, :pull:`4647`) + +#. `@rcomer`_ and `@bjlittle`_ (reviewer) re-wrote :func:`iris.util.mask_cube` + to provide lazy evaluation and greater flexibility with respect to input types. + (:issue:`3936`, :pull:`4889`) + +#. `@stephenworsley`_ and `@lbdreyer`_ added a new kwarg ``expand_extras`` to + :func:`iris.util.new_axis` which can be used to specify instances of + :class:`~iris.coords.AuxCoord`, :class:`~iris.coords.CellMeasure` and + :class:`~iris.coords.AncillaryVariable` which should also be expanded to map + to the new axis. (:pull:`4896`) + +#. `@stephenworsley`_ updated to the latest CF Standard Names Table ``v79`` + (19 March 2022). (:pull:`4910`) + +#. `@trexfeathers`_ and `@lbdreyer`_ (reviewer) added + :func:`iris.pandas.as_cubes`, which provides richer conversion from + Pandas :class:`~pandas.Series` / :class:`~pandas.DataFrame`\s to one or more + :class:`~iris.cube.Cube`\s. This includes: n-dimensional datasets, + :class:`~iris.coords.AuxCoord`\s, :class:`~iris.coords.CellMeasure`\s, + :class:`~iris.coords.AncillaryVariable`\s, and multi-dimensional + coordinates. (:pull:`4890`) + + +🐛 Bugs Fixed +============= + +#. `@rcomer`_ reverted part of the change from :pull:`3906` so that + :func:`iris.plot.plot` no longer defaults to placing a "Y" coordinate (e.g. + latitude) on the y-axis of the plot. (:issue:`4493`, :pull:`4601`) + +#. `@rcomer`_ enabled passing of scalar objects to :func:`~iris.plot.plot` and + :func:`~iris.plot.scatter`. (:pull:`4616`) + +#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.aggregated_by` with `mdtol` for 1D + cubes where an aggregated section is entirely masked, reported at + :issue:`3190`. (:pull:`4246`) + +#. `@rcomer`_ ensured that a :class:`matplotlib.axes.Axes`'s position is preserved + when Iris replaces it with a :class:`cartopy.mpl.geoaxes.GeoAxes`, fixing + :issue:`1157`. (:pull:`4273`) + +#. `@rcomer`_ fixed :meth:`~iris.coords.Coord.nearest_neighbour_index` for edge + cases where the requested point is float and the coordinate has integer + bounds, reported at :issue:`2969`. (:pull:`4245`) + +#. `@rcomer`_ modified bounds setting on :obj:`~iris.coords.DimCoord` instances + so that the order of the cell bounds is automatically reversed + to match the coordinate's direction if necessary. This is consistent with + the `Bounds for 1-D coordinate variables` subsection of the `Cell Boundaries`_ + section of the CF Conventions and ensures that contiguity is preserved if a + coordinate's direction is reversed. (:issue:`3249`, :issue:`423`, + :issue:`4078`, :issue:`3756`, :pull:`4466`) + +#. `@wjbenfold`_ and `@evertrol`_ prevented an ``AttributeError`` being logged + to ``stderr`` when a :class:`~iris.fileformats.cf.CFReader` that fails to + initialise is garbage collected. (:issue:`3312`, :pull:`4646`) + +#. `@wjbenfold`_ fixed plotting of circular coordinates to extend kwarg arrays + as well as the data. (:issue:`466`, :pull:`4649`) + +#. `@wjbenfold`_ and `@rcomer`_ (reviewer) corrected the axis on which masking + is applied when an aggregator adds a trailing dimension. (:pull:`4755`) + +#. `@rcomer`_ and `@pp-mo`_ ensured that all methods to create or modify a + :class:`iris.cube.CubeList` check that it only contains cubes. According to + code comments, this was supposedly already the case, but there were several bugs + and loopholes. (:issue:`1897`, :pull:`4767`) + +#. `@rcomer`_ modified cube arithmetic to handle mismatches in the cube's data + array type. This prevents masks being lost in some cases and therefore + resolves :issue:`2987`. (:pull:`3790`) + +#. `@krikru`_ and `@rcomer`_ updated :mod:`iris.quickplot` such that the + colorbar is added to the correct ``axes`` when specified as a keyword + argument to a plotting routine. Otherwise, by default the colorbar will be + added to the current axes of the current figure. (:pull:`4894`) + +#. `@rcomer`_ and `@bjlittle`_ (reviewer) modified :func:`iris.util.mask_cube` so it + either works in place or returns a new cube (:issue:`3717`, :pull:`4889`) + + +💣 Incompatible Changes +======================= + +#. `@rcomer`_ and `@bjlittle`_ (reviewer) updated Iris's calendar handling to be + consistent with ``cf-units`` version 3.1. In line with the `Calendar`_ + section in version 1.9 of the CF Conventions, we now use "standard" rather + than the deprecated "gregorian" label for the default calendar. Units may + still be instantiated with ``calendar="gregorian"`` but their calendar + attribute will be silently changed to "standard". This may cause failures in + code that explicitly checks the calendar attribute. (:pull:`4847`) + + +🚀 Performance +============== + +#. `@wjbenfold`_ added caching to the calculation of the points array in a + :class:`~iris.coords.DimCoord` created using + :meth:`~iris.coords.DimCoord.from_regular`. (:pull:`4698`) + +#. `@wjbenfold`_ introduced caching in :func:`_lazy_data._optimum_chunksize` and + :func:`iris.fileformats.pp_load_rules._epoch_date_hours` to reduce time spent + repeating calculations. (:pull:`4716`) + +#. `@pp-mo`_ made :meth:`~iris.cube.Cube.add_aux_factory` faster. + (:pull:`4718`) + +#. `@wjbenfold`_ and `@rcomer`_ (reviewer) permitted the fast percentile + aggregation method to be used on masked data when the missing data tolerance + is set to 0. (:issue:`4735`, :pull:`4755`) + +#. `@wjbenfold`_ improved the speed of linear interpolation using + :meth:`iris.analysis.trajectory.interpolate` (:pull:`4366`) + +#. NumPy ``v1.23`` behaviour changes mean that + :func:`iris.experimental.ugrid.utils.recombine_submeshes` now uses ~3x as + much memory; testing shows a ~16-million point mesh will now use ~600MB. + Investigated by `@pp-mo`_ and `@trexfeathers`_. (:issue:`4845`) + + +🔥 Deprecations +=============== + +#. `@trexfeathers`_ and `@lbdreyer`_ (reviewer) deprecated + :func:`iris.pandas.as_cube` in favour of the new + :func:`iris.pandas.as_cubes` - see `✨ Features`_ for more details. + (:pull:`4890`) + + +🔗 Dependencies +=============== + +#. `@rcomer`_ introduced the ``nc-time-axis >=1.4`` minimum pin, reflecting that + we no longer use the deprecated :class:`nc_time_axis.CalendarDateTime` + when plotting against time coordinates. (:pull:`4584`) + +#. `@wjbenfold`_ and `@bjlittle`_ (reviewer) unpinned ``pillow``. (:pull:`4826`) + +#. `@rcomer`_ introduced the ``cf-units >=3.1`` minimum pin, reflecting the + alignment of calendar behaviour in the two packages (see Incompatible Changes). + (:pull:`4847`) + +#. `@bjlittle`_ introduced the ``sphinx-gallery >=0.11.0`` minimum pin. + (:pull:`4885`) + +#. `@trexfeathers`_ updated the install process to work with setuptools + ``>=v64``, making ``v64`` the minimum compatible version. (:pull:`4903`) + +#. `@stephenworsley`_ and `@trexfeathers`_ introduced the ``shapely !=1.8.3`` + pin, avoiding a bug caused by its interaction with cartopy. + (:pull:`4911`, :pull:`4917`) + + +📚 Documentation +================ + +#. `@tkknight`_ added a page to show the issues that have been voted for. See + :ref:`voted_issues_top`. (:issue:`3307`, :pull:`4617`) + +#. `@wjbenfold`_ added a note about fixing proxy URLs in lockfiles generated + because dependencies have changed. (:pull:`4666`) + +#. `@lbdreyer`_ moved most of the User Guide's :class:`iris.Constraint` examples + from :ref:`loading_iris_cubes` to :ref:`cube_extraction` and added an + example of constraining on bounded time. (:pull:`4656`) + +#. `@tkknight`_ adopted the `PyData Sphinx Theme`_ for the documentation. + (:discussion:`4344`, :pull:`4661`) + +#. `@tkknight`_ updated our developers guidance to show our intent to adopt + numpydoc strings and fixed some API documentation rendering. + See :ref:`docstrings`. (:issue:`4657`, :pull:`4689`) + +#. `@trexfeathers`_ and `@lbdreyer`_ added a page with examples of converting + various mesh formats into the Iris Mesh Data Model. (:pull:`4739`) + +#. `@rcomer`_ updated the "Load a Time Series of Data From the NEMO Model" + gallery example. (:pull:`4741`) + +#. `@wjbenfold`_ added developer documentation to highlight some of the + utilities offered by :class:`iris.IrisTest` and how to update CML and other + output files. (:issue:`4544`, :pull:`4600`) + +#. `@trexfeathers`_ and `@abooton`_ modernised the Iris logo to be SVG format. + (:pull:`3935`) + + +💼 Internal +=========== + +#. `@trexfeathers`_ and `@pp-mo`_ finished implementing a mature benchmarking + infrastructure (see :ref:`contributing.benchmarks`), building on 2 hard + years of lessons learned 🎉. (:pull:`4477`, :pull:`4562`, :pull:`4571`, + :pull:`4583`, :pull:`4621`) + +#. `@wjbenfold`_ used the aforementioned benchmarking infrastructure to + introduce deep (large 3rd dimension) loading and realisation benchmarks. + (:pull:`4654`) + +#. `@wjbenfold`_ made :func:`iris.tests.stock.simple_1d` respect the + ``with_bounds`` argument. (:pull:`4658`) + +#. `@lbdreyer`_ replaced `nose`_ with `pytest`_ as Iris' test runner. + (:pull:`4734`) + +#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) migrated to GitHub Actions + for Continuous-Integration. (:pull:`4503`) + +#. `@pp-mo`_ made tests run certain linux executables from the Python env, + specifically ncdump and ncgen. These could otherwise fail when run in IDEs + such as PyCharm and Eclipse, which don't automatically include the Python env + bin in the system PATH. + (:pull:`4794`) + +#. `@trexfeathers`_ and `@pp-mo`_ improved generation of stock NetCDF files. + (:pull:`4827`, :pull:`4836`) + +#. `@rcomer`_ removed some now redundant testing functions. (:pull:`4838`, + :pull:`4878`) + +#. `@bjlittle`_ and `@jamesp`_ (reviewer) and `@lbdreyer`_ (reviewer) extended + the GitHub Continuous-Integration to cover testing on ``py38``, ``py39``, + and ``py310``. (:pull:`4840`) + +#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) adopted `setuptools-scm`_ for + automated ``iris`` package versioning. (:pull:`4841`) + +#. `@bjlittle`_ and `@trexfeathers`_ (reviewer) added building, testing and + publishing of ``iris`` PyPI ``sdist`` and binary ``wheels`` as part of + our GitHub Continuous-Integration. (:pull:`4849`) + +#. `@rcomer`_ and `@wjbenfold`_ (reviewer) used ``pytest`` parametrization to + streamline the gallery test code. (:pull:`4792`) + +#. `@trexfeathers`_ improved settings to better working with + ``setuptools_scm``. (:pull:`4925`) + + +.. comment + Whatsnew author names (@github name) in alphabetical order. Note that, + core dev names are automatically included by the common_links.inc: + +.. _@evertrol: https://github.com/evertrol +.. _@krikru: https://github.com/krikru + + +.. comment + Whatsnew resources in alphabetical order: + +.. _Calendar: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#calendar +.. _Cell Boundaries: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#cell-boundaries +.. _nose: https://nose.readthedocs.io +.. _PyData Sphinx Theme: https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html +.. _pytest: https://docs.pytest.org +.. _setuptools-scm: https://github.com/pypa/setuptools_scm +.. _SciTools/cartopy@fcb784d: https://github.com/SciTools/cartopy/commit/fcb784daa65d95ed9a74b02ca292801c02bc4108 +.. _SciTools/cartopy@8860a81: https://github.com/SciTools/cartopy/commit/8860a8186d4dc62478e74c83f3b2b3e8f791372e diff --git a/docs/src/whatsnew/index.rst b/docs/src/whatsnew/index.rst index 78c0134463..8cff21f32f 100644 --- a/docs/src/whatsnew/index.rst +++ b/docs/src/whatsnew/index.rst @@ -12,6 +12,7 @@ What's New in Iris :hidden: latest.rst + 3.3.rst 3.2.rst 3.1.rst 3.0.rst diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 0e4d51ffec..b44e740724 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -14,7 +14,7 @@ This document explains the changes made to Iris for this release :animate: fade-in :open: - The highlights for this minor release of Iris include: + The highlights for this major/minor release of Iris include: * N/A @@ -25,108 +25,43 @@ This document explains the changes made to Iris for this release 📢 Announcements ================ -#. N/A +#. Welcome to `@ESadek-MO`_ and `@TTV-Intrepid`_ who made their first contributions to Iris 🎉 ✨ Features =========== -#. `@schlunma`_ added weighted aggregation over "group coordinates": - :meth:`~iris.cube.Cube.aggregated_by` now accepts the keyword `weights` if a - :class:`~iris.analysis.WeightedAggregator` is used. (:issue:`4581`, - :pull:`4589`) - -#. `@wjbenfold`_ added support for ``false_easting`` and ``false_northing`` to - :class:`~iris.coord_systems.Mercator`. (:issue:`3107`, :pull:`4524`) - -#. `@rcomer`_ and `@wjbenfold`_ (reviewer) implemented lazy aggregation for the - :obj:`iris.analysis.PERCENTILE` aggregator. (:pull:`3901`) - -#. `@pp-mo`_ fixed cube arithmetic operation for cubes with meshes. - (:issue:`4454`, :pull:`4651`) - -#. `@wjbenfold`_ added support for CF-compliant treatment of - ``standard_parallel`` and ``scale_factor_at_projection_origin`` to - :class:`~iris.coord_systems.Mercator`. (:issue:`3844`, :pull:`4609`) - -#. `@wjbenfold`_ added support datums associated with coordinate systems (e.g. - :class:`~iris.coord_systems.GeogCS` other subclasses of - :class:`~iris.coord_systems.CoordSystem`). Loading of datum information from - a netCDF file only happens when the :obj:`iris.FUTURE.datum_support` flag is - set. (:issue:`4619`, :pull:`4704`) - -#. `@wjbenfold`_ and `@stephenworsley`_ (reviewer) added a maximum run length - aggregator (:class:`~iris.analysis.MAX_RUN`). (:pull:`4676`) - -#. `@wjbenfold`_ and `@rcomer`_ (reviewer) added a ``climatological`` keyword to - :meth:`~iris.cube.Cube.aggregated_by` that causes the climatological flag to - be set and the point for each cell to equal its first bound, thereby - preserving the time of year. (:issue:`1422`, :issue:`4098`, :issue:`4665`, - :pull:`4723`) +#. `@ESadek-MO`_ edited :func:`~iris.io.expand_filespecs` to allow expansion of + non-existing paths, and added expansion functionality to :func:`~iris.io.save`. + (:issue:`4772`, :pull:`4913`) -#. `@wjbenfold`_ and `@pp-mo`_ (reviewer) implemented the - :class:`~iris.coord_systems.PolarStereographic` CRS. (:issue:`4770`, - :pull:`4773`) - -#. `@rcomer`_ and `@wjbenfold`_ (reviewer) enabled passing of the - :func:`numpy.percentile` keywords through the :obj:`~iris.analysis.PERCENTILE` - aggregator. (:pull:`4791`) - -#. `@wjbenfold`_ and `@bjlittle`_ (reviewer) implemented - :func:`iris.plot.fill_between` and :func:`iris.quickplot.fill_between`. - (:issue:`3493`, :pull:`4647`) +#. `@trexfeathers`_ and `Julian Heming`_ added new mappings between CF + standard names and UK Met Office LBFC codes. (:pull:`4859`) 🐛 Bugs Fixed ============= -#. `@rcomer`_ reverted part of the change from :pull:`3906` so that - :func:`iris.plot.plot` no longer defaults to placing a "Y" coordinate (e.g. - latitude) on the y-axis of the plot. (:issue:`4493`, :pull:`4601`) - -#. `@rcomer`_ enabled passing of scalar objects to :func:`~iris.plot.plot` and - :func:`~iris.plot.scatter`. (:pull:`4616`) - -#. `@rcomer`_ fixed :meth:`~iris.cube.Cube.aggregated_by` with `mdtol` for 1D - cubes where an aggregated section is entirely masked, reported at - :issue:`3190`. (:pull:`4246`) - -#. `@rcomer`_ ensured that a :class:`matplotlib.axes.Axes`'s position is preserved - when Iris replaces it with a :class:`cartopy.mpl.geoaxes.GeoAxes`, fixing - :issue:`1157`. (:pull:`4273`) - -#. `@rcomer`_ fixed :meth:`~iris.coords.Coord.nearest_neighbour_index` for edge - cases where the requested point is float and the coordinate has integer - bounds, reported at :issue:`2969`. (:pull:`4245`) - -#. `@rcomer`_ modified bounds setting on :obj:`~iris.coords.DimCoord` instances - so that the order of the cell bounds is automatically reversed - to match the coordinate's direction if necessary. This is consistent with - the `Bounds for 1-D coordinate variables` subsection of the `Cell Boundaries`_ - section of the CF Conventions and ensures that contiguity is preserved if a - coordinate's direction is reversed. (:issue:`3249`, :issue:`423`, - :issue:`4078`, :issue:`3756`, :pull:`4466`) - -#. `@wjbenfold`_ and `@evertrol`_ prevented an ``AttributeError`` being logged - to ``stderr`` when a :class:`~iris.fileformats.cf.CFReader` that fails to - initialise is garbage collected. (:issue:`3312`, :pull:`4646`) +#. `@rcomer`_ and `@pp-mo`_ (reviewer) factored masking into the returned + sum-of-weights calculation from :obj:`~iris.analysis.SUM`. (:pull:`4905`) -#. `@stephenworsley`_ aligned the behaviour of :obj:`~iris.coords.Cell` equality - to match :obj:`~iris.coords.Coord` equality with respect to NaN values. - Two NaN valued Cells are now considered equal. This fixes :issue:`4681` and - causes NaN valued scalar coordinates to be able to merge be preserved during - cube merging. (:pull:`4701`) +#. `@schlunma`_ fixed a bug which prevented using + :meth:`iris.cube.Cube.collapsed` on coordinates whose number of bounds + differs from 0 or 2. This enables the use of this method on mesh + coordinates. (:issue:`4672`, :pull:`4870`) -#. `@wjbenfold`_ fixed plotting of circular coordinates to extend kwarg arrays - as well as the data. (:issue:`466`, :pull:`4649`) +#. `@bjlittle`_ and `@lbdreyer`_ (reviewer) fixed the building of the CF + Standard Names module ``iris.std_names`` for the ``setup.py`` commands + ``develop`` and ``std_names``. (:issue:`4951`, :pull:`4952`) -#. `@wjbenfold`_ and `@rcomer`_ (reviewer) corrected the axis on which masking - is applied when an aggregator adds a trailing dimension. (:pull:`4755`) +#. `@lbdreyer`_ and `@pp-mo`_ (reviewer) fixed the cube print out such that + scalar ancillary variables are displayed in a dedicated section rather than + being added to the vector ancillary variables section. Further, ancillary + variables and cell measures that map to a cube dimension of length 1 are now + included in the respective vector sections. (:pull:`4945`) -#. `@rcomer`_ and `@pp-mo`_ ensured that all methods to create or modify a - :class:`iris.cube.CubeList` check that it only contains cubes. According to - code comments, this was supposedly already the case, but there were several bugs - and loopholes. (:issue:`1897`, :pull:`4767`) +#. `@rcomer`_ removed some old redundant code that prevented determining the + order of time cells. (:issue:`4697`, :pull:`4729`) 💣 Incompatible Changes @@ -138,25 +73,18 @@ This document explains the changes made to Iris for this release 🚀 Performance Enhancements =========================== -#. `@wjbenfold`_ added caching to the calculation of the points array in a - :class:`~iris.coords.DimCoord` created using - :meth:`~iris.coords.DimCoord.from_regular`. (:pull:`4698`) - -#. `@wjbenfold`_ introduced caching in :func:`_lazy_data._optimum_chunksize` and - :func:`iris.fileformats.pp_load_rules._epoch_date_hours` to reduce time spent - repeating calculations. (:pull:`4716`) - -#. `@pp-mo`_ made :meth:`~iris.cube.Cube.add_aux_factory` faster. - (:pull:`4718`) - -#. `@wjbenfold`_ and `@rcomer`_ (reviewer) permitted the fast percentile - aggregation method to be used on masked data when the missing data tolerance - is set to 0. (:issue:`4735`, :pull:`4755`) - -#. `@wjbenfold`_ improved the speed of linear interpolation using - :meth:`iris.analysis.trajectory.interpolate` (:pull:`4366`) +#. `@rcomer`_ and `@pp-mo`_ (reviewer) increased aggregation speed for + :obj:`~iris.analysis.SUM`, :obj:`~iris.analysis.COUNT` and + :obj:`~iris.analysis.PROPORTION` on real data. (:pull:`4905`) +#. `@bouweandela`_ made :meth:`iris.coords.Coord.cells` faster for time + coordinates. This also affects :meth:`iris.cube.Cube.extract`, + :meth:`iris.cube.Cube.subset`, and :meth:`iris.coords.Coord.intersect`. + (:pull:`4969`) +#. `@bouweandela`_ improved the speed of :meth:`iris.cube.Cube.subset` / + :meth:`iris.coords.Coord.intersect`. + (:pull:`4955`) 🔥 Deprecations =============== @@ -167,86 +95,72 @@ This document explains the changes made to Iris for this release 🔗 Dependencies =============== -#. `@rcomer`_ introduced the ``nc-time-axis >=1.4`` minimum pin, reflecting that - we no longer use the deprecated :class:`nc_time_axis.CalendarDateTime` - when plotting against time coordinates. (:pull:`4584`) - -#. `@wjbenfold`_ and `@bjlittle`_ (reviewer) unpinned ``pillow``. (:pull:`4826`) - - -📚 Documentation -================ - -#. `@tkknight`_ added a page to show the issues that have been voted for. See - :ref:`voted_issues_top`. (:issue:`3307`, :pull:`4617`) - -#. `@wjbenfold`_ added a note about fixing proxy URLs in lockfiles generated - because dependencies have changed. (:pull:`4666`) - -#. `@lbdreyer`_ moved most of the User Guide's :class:`iris.Constraint` examples - from :ref:`loading_iris_cubes` to :ref:`cube_extraction` and added an - example of constraining on bounded time. (:pull:`4656`) +#. `@rcomer`_ introduced the ``dask >=2.26`` minimum pin, so that Iris can benefit + from Dask's support for `NEP13`_ and `NEP18`_. (:pull:`4905`) -#. `@tkknight`_ adopted the `PyData Sphinx Theme`_ for the documentation. - (:discussion:`4344`, :pull:`4661`) +#. `@trexfeathers`_ advanced the Cartopy pin to ``>=0.21``, as Cartopy's + change to default Transverse Mercator projection affects an Iris test. + See `SciTools/cartopy@fcb784d`_ and `SciTools/cartopy@8860a81`_ for more + details. + (:pull:`4968`) -#. `@tkknight`_ updated our developers guidance to show our intent to adopt - numpydoc strings and fixed some API documentation rendering. - See :ref:`docstrings`. (:issue:`4657`, :pull:`4689`) +#. `@trexfeathers`_ introduced the ``netcdf4!=1.6.1`` pin to avoid a problem + with segfaults. (:pull:`4968`) -#. `@trexfeathers`_ added a page with examples of converting various mesh - formats into the Iris Mesh Data Model. (:pull:`4739`) +#. `@trexfeathers`_ updated the Matplotlib colormap registration in + :mod:`iris.palette` in response to a deprecation warning. Using the new + Matplotlib API also means a ``matplotlib>=3.5`` pin. (:pull:`4998`) -#. `@rcomer`_ updated the "Load a Time Series of Data From the NEMO Model" - gallery example. (:pull:`4741`) -#. `@wjbenfold`_ added developer documentation to highlight some of the - utilities offered by :class:`iris.IrisTest` and how to update CML and other - output files. (:issue:`4544`, :pull:`4600`) +📚 Documentation +================ -#. `@trexfeathers`_ and `@abooton`_ modernised the Iris logo to be SVG format. - (:pull:`3935`) +#. `@ESadek-MO`_, `@TTV-Intrepid`_ and `@trexfeathers`_ added a gallery example for zonal + means plotted parallel to a cartographic plot. (:pull:`4871`) +#. `@Esadek-MO`_ added a key-terms :ref:`glossary` page into the user guide. (:pull:`4902`) +#. `@pp-mo`_ added a :ref:`code example ` + for converting ORCA-gridded data to an unstructured cube. (:pull:`5013`) 💼 Internal =========== -#. `@trexfeathers`_ and `@pp-mo`_ finished implementing a mature benchmarking - infrastructure (see :ref:`contributing.benchmarks`), building on 2 hard - years of lessons learned 🎉. (:pull:`4477`, :pull:`4562`, :pull:`4571`, - :pull:`4583`, :pull:`4621`) +#. `@rcomer`_ removed the obsolete ``setUpClass`` method from Iris testing. + (:pull:`4927`) -#. `@wjbenfold`_ used the aforementioned benchmarking infrastructure to - introduce deep (large 3rd dimension) loading and realisation benchmarks. - (:pull:`4654`) +#. `@bjlittle`_ and `@lbdreyer`_ (reviewer) removed support for + ``python setup.py test``, which is a deprecated approach to executing + package tests, see `pypa/setuptools#1684`_. Also performed assorted + ``setup.py`` script hygiene. (:pull:`4948`, :pull:`4949`, :pull:`4950`) -#. `@wjbenfold`_ made :func:`iris.tests.stock.simple_1d` respect the - ``with_bounds`` argument. (:pull:`4658`) +#. `@pp-mo`_ split the module :mod:`iris.fileformats.netcdf` into separate + :mod:`~iris.fileformats.netcdf.loader` and :mod:`~iris.fileformats.netcdf.saver` + submodules, just to make the code easier to handle. -#. `@bjlittle`_ migrated to GitHub Actions for Continuous-Integration. - (:pull:`4503`) +#. `@trexfeathers`_ adapted the benchmark for importing :mod:`iris.palette` to + cope with new colormap behaviour in Matplotlib `v3.6`. (:pull:`4998`) -#. `@pp-mo`_ made tests run certain linux executables from the Python env, - specifically ncdump and ncgen. These could otherwise fail when run in IDEs - such as PyCharm and Eclipse, which don't automatically include the Python env - bin in the system PATH. - (:pull:`4794`) - -#. `@trexfeathers`_ and `@pp-mo`_ fixed the CDL headers for - :mod:`iris.tests.stock.netcdf` to allow generation of NetCDF-4 files with an - unlimited time dimension. - (:pull:`4827`) +#. `@rcomer`_ removed a now redundant workaround for an old matplotlib bug, + highlighted by :issue:`4090`. (:pull:`4999`) +#. `@rcomer`_ added the ``show`` option to the documentation Makefiles, as a + convenient way for contributors to view their built documentation. + (:pull:`5000`) .. comment Whatsnew author names (@github name) in alphabetical order. Note that, core dev names are automatically included by the common_links.inc: -.. _@evertrol: https://github.com/evertrol +.. _@TTV-Intrepid: https://github.com/TTV-Intrepid +.. _Julian Heming: https://www.metoffice.gov.uk/research/people/julian-heming + .. comment Whatsnew resources in alphabetical order: -.. _Cell Boundaries: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#cell-boundaries -.. _PyData Sphinx Theme: https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html +.. _NEP13: https://numpy.org/neps/nep-0013-ufunc-overrides.html +.. _NEP18: https://numpy.org/neps/nep-0018-array-function-protocol.html +.. _pypa/setuptools#1684: https://github.com/pypa/setuptools/issues/1684 +.. _SciTools/cartopy@fcb784d: https://github.com/SciTools/cartopy/commit/fcb784daa65d95ed9a74b02ca292801c02bc4108 +.. _SciTools/cartopy@8860a81: https://github.com/SciTools/cartopy/commit/8860a8186d4dc62478e74c83f3b2b3e8f791372e diff --git a/docs/src/whatsnew/latest.rst.template b/docs/src/whatsnew/latest.rst.template index 1b36d3f0b0..661ee47f50 100644 --- a/docs/src/whatsnew/latest.rst.template +++ b/docs/src/whatsnew/latest.rst.template @@ -24,7 +24,7 @@ This document explains the changes made to Iris for this release NOTE: section below is a template for bugfix patches ==================================================== - (Please remove this section when creating an initial 'dev.rst') + (Please remove this section when creating an initial 'latest.rst') v3.X.X (DD MMM YYYY) ==================== @@ -41,8 +41,8 @@ v3.X.X (DD MMM YYYY) NOTE: section above is a template for bugfix patches ==================================================== - (Please remove this section when creating an initial 'dev.rst') - + (Please remove this section when creating an initial 'latest.rst') + 📢 Announcements diff --git a/etc/cf-standard-name-table.xml b/etc/cf-standard-name-table.xml index bd76168192..9c5fcd9cf0 100644 --- a/etc/cf-standard-name-table.xml +++ b/etc/cf-standard-name-table.xml @@ -1,7 +1,7 @@ - 78 - 2021-09-21T11:55:06Z + 79 + 2022-03-19T15:25:54Z Centre for Environmental Data Analysis support@ceda.ac.uk @@ -8014,6 +8014,20 @@ The phrase "magnitude_of_X" means magnitude of a vector X. The surface called "surface" means the lower boundary of the atmosphere. "Surface stress" means the shear stress (force per unit area) exerted by the wind at the surface. A downward stress is a downward flux of momentum. Over large bodies of water, wind stress can drive near-surface currents. "Downward" indicates a vector component which is positive when directed downward (negative upward). + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of 19’-butanoyloxyfucoxanthin is C46H64O8. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/BUTAXXXX/1/. + + + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of 19'-hexanoyloxyfucoxanthin is C48H68O8. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/HEXAXXXX/2/. + + kg m-3 @@ -8028,6 +8042,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for aceto-nitrile is CH3CN. The IUPAC name for aceto-nitrile is ethanenitrile. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ATPXZZDZ/2/. + + kg m-3 @@ -8042,6 +8063,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. Alkenes are unsaturated hydrocarbons as they contain chemical double bonds between adjacent carbon atoms. Alkenes contain only hydrogen and carbon combined in the general proportions C(n)H(2n); "alkenes" is the term used in standard names to describe the group of chemical species having this common structure that are represented within a given model. The list of individual species that are included in a quantity having a group chemical standard name can vary between models. Where possible, the data variable should be accompanied by a complete description of the species represented, for example, by using a comment attribute. Standard names exist for some individual alkene species, e.g., ethene and propene. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of alpha-carotene is C40H56. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/BECAXXP1/2/. + + kg m-3 @@ -8112,6 +8140,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for benzene is C6H6. Benzene is the simplest aromatic hydrocarbon and has a ring structure consisting of six carbon atoms joined by alternating single and double chemical bonds. Each carbon atom is additionally bonded to one hydrogen atom. There are standard names that refer to aromatic_compounds as a group, as well as those for individual species. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of beta-carotene is C40H56. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/BBCAXXP1/2/. + + kg m-3 @@ -8217,6 +8252,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula of carbon tetrachloride is CCl4. The IUPAC name for carbon tetrachloride is tetrachloromethane. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Carotene" refers to the sum of all forms of the carotenoid pigment carotene. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CAROXXXX/1/. + + kg m-3 @@ -8287,6 +8329,41 @@ 'Mass concentration' means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. Chlorophyll-a is the most commonly occurring form of natural chlorophyll. The chemical formula of chlorophyll-a is C55H72O5N4Mg. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CHLBXXPX/2/. + + + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. Chlorophyll c1c2 (sometimes written c1-c2 or c1+c2) means the sum of chlorophyll c1 and chlorophyll c2. The chemical formula of chlorophyll c1 is C35H30MgN4O5, and chlorophyll c2 is C35H28MgN4O5. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CHLC12PX/3/. + + + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. The chemical formula of chlorophyll c3 is C36H44MgN4O7. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/CHLC03PX/2/. + + + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Chlorophylls are the green pigments found in most plants, algae and cyanobacteria; their presence is essential for photosynthesis to take place. There are several different forms of chlorophyll that occur naturally. All contain a chlorin ring (chemical formula C20H16N4) which gives the green pigment and a side chain whose structure varies. The naturally occurring forms of chlorophyll contain between 35 and 55 carbon atoms. Chlorophyll-c means chlorophyll c1+c2+c3. The chemical formula of chlorophyll c1 is C35H30MgN4O5, and chlorophyll c2 is C35H28MgN4O5. The chemical formula of chlorophyll c3 is C36H44MgN4O7. + + + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of chlorophyllide-a is C35H34MgN4O5. + + kg m-3 @@ -8322,6 +8399,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. Condensed water means liquid and ice. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of diadinoxanthin is C40H54O3. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/DIADXXXX/2/. + + kg m-3 @@ -8378,6 +8462,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for dinitrogen pentoxide is N2O5. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". + + kg m-3 @@ -8455,6 +8546,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for formic acid is HCOOH. The IUPAC name for formic acid is methanoic acid. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of fucoxanthin is C42H58O6. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/FUCXZZZZ/2/. + + kg m-3 @@ -8637,6 +8735,13 @@ Mass concentration means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The mass concentration of liquid water takes into account all cloud droplets and liquid precipitation regardless of drop size or fall speed. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of lutein is C40H56O2. + + kg m-3 @@ -8707,6 +8812,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for molecular hydrogen is H2. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". + + kg m-3 @@ -8833,6 +8945,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Aerosol" means the system of suspended liquid or solid particles in air (except cloud droplets) and their carrier gas, the air itself. Aerosol takes up ambient water (a process known as hygroscopic growth) depending on the relative humidity and the composition of the aerosol. "Dry aerosol particles" means aerosol particles without any water uptake. The term "particulate_organic_matter_dry_aerosol" means all particulate organic matter dry aerosol except elemental carbon. It is the sum of primary_particulate_organic_matter_dry_aerosol and secondary_particulate_organic_matter_dry_aerosol. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/PERDXXXX/2/. + + kg m-3 @@ -8861,6 +8980,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. It means the ratio of the mass of X to the mass of Y (including X). A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Petroleum hydrocarbons are compounds containing just carbon and hydrogen originating from the fossil fuel crude oil. + + kg m-3 + + + Concentration of phaeopigment per unit volume of the water body, where the filtration size or collection method is unspecified (equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/. "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Phaeopigments are a group of non-photosynthetic pigments that are the degradation product of algal chlorophyll pigments. Phaeopigments contain phaeophytin, which fluoresces in response to excitation light, and phaeophorbide, which is colorless and does not fluoresce (source: https://academic.oup.com/plankt/article/24/11/1221/1505482). Phaeopigment concentration commonly increases during the development phase of marine phytoplankton blooms, and declines in the post bloom stage (source: https://www.sciencedirect.com/science/article/pii/0967063793901018). + + kg m-3 @@ -8931,6 +9057,13 @@ Mass concentration means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Aerosol" means the system of suspended liquid or solid particles in air (except cloud droplets) and their carrier gas, the air itself. Aerosol particles take up ambient water (a process known as hygroscopic growth) depending on the relative humidity and the composition of the particles. "Dry aerosol particles" means aerosol particles without any water uptake. "Pm2p5 aerosol" means atmospheric particulate compounds with an aerodynamic diameter of less than or equal to 2.5 micrometers. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of prasinoxanthin is C40H56O4. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/PXAPXXXX/2/. + + kg m-3 @@ -9036,6 +9169,13 @@ "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula for toluene is C6H5CH3. Toluene has the same structure as benzene, except that one of the hydrogen atoms is replaced by a methyl group. The IUPAC name for toluene is methylbenzene. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of violaxanthin is C40H56O4. + + kg m-3 @@ -9064,6 +9204,13 @@ Mass concentration means mass per unit volume and is used in the construction mass_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for xylene is C6H4C2H6. In chemistry, xylene is a generic term for a group of three isomers of dimethylbenzene. The IUPAC names for the isomers are 1,2-dimethylbenzene, 1,3-dimethylbenzene and 1,4-dimethylbenzene. Xylene is an aromatic hydrocarbon. There are standard names that refer to aromatic_compounds as a group, as well as those for individual species. + + kg m-3 + + + "Mass concentration" means mass per unit volume and is used in the construction "mass_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The chemical formula of zeaxanthin is C40H56O2. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ZEAXXXXX/2/. + + kg m-3 @@ -10737,6 +10884,13 @@ Mole concentration means number of moles per unit volume, also called "molarity", and is used in the construction mole_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for aceto-nitrile is CH3CN. The IUPAC name for aceto-nitrile is ethanenitrile. + + mol m-3 + + + "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ATPXZZDZ/2/. + + mol m-3 @@ -11185,6 +11339,13 @@ Mole concentration means number of moles per unit volume, also called "molarity", and is used in the construction mole_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The concentration of any chemical species, whether particulate or dissolved, may vary with depth in the ocean. A depth profile may go through one or more local minima in concentration. The mole_concentration_of_molecular_oxygen_in_sea_water_at_shallowest_local_minimum_in_vertical_profile is the mole concentration of oxygen at the local minimum in the concentration profile that occurs closest to the sea surface. The chemical formula for molecular oxygen is O2. + + mol m-3 + + + "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Dissolved nitrogen" means the sum of all nitrogen in solution: inorganic nitrogen (nitrite, nitrate and ammonium) plus nitrogen in carbon compounds. + + mol m-3 @@ -11199,6 +11360,20 @@ "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Dissolved organic nitrogen" describes the nitrogen held in carbon compounds in solution. These are mostly generated by plankton excretion and decay. + + mol m-3 + + + "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical or biological species denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". "Organic phosphorus" means phosphorus in carbon compounds. The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/ORGPDSZZ/4/. + + + + mol m-3 + + + "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". Phosphorus means phosphorus in all chemical forms, commonly referred to as "total phosphorus". The equivalent term in the NERC P01 Parameter Usage Vocabulary may be found at http://vocab.nerc.ac.uk/collection/P01/current/TPHSDSZZ/6/. + + mol m-3 @@ -11626,6 +11801,13 @@ Mole concentration means number of moles per unit volume, also called "molarity", and is used in the construction mole_concentration_of_X_in_Y, where X is a material constituent of Y. A chemical species denoted by X may be described by a single term such as 'nitrogen' or a phrase such as 'nox_expressed_as_nitrogen'. The chemical formula for ozone is O3. + + mol m-3 + + + "Mole concentration" means number of moles per unit volume, also called "molarity", and is used in the construction "mole_concentration_of_X_in_Y", where X is a material constituent of Y. A chemical species or biological group denoted by X may be described by a single term such as "nitrogen" or a phrase such as "nox_expressed_as_nitrogen". The phrase "expressed_as" is used in the construction "A_expressed_as_B", where B is a chemical constituent of A. It means that the quantity indicated by the standard name is calculated solely with respect to the B contained in A, neglecting all other chemical constituents of A. + + mol m-3 @@ -18595,21 +18777,21 @@ Pa - "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xx" indicates the component of the tensor along the grid x_ axis. + "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xx" indicates the component of the tensor along the grid x_ axis. Pa - "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xy" indicates the lateral contributions to x_ and y_ components of the tensor. + "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "xy" indicates the lateral contributions to x_ and y_ components of the tensor. Pa - "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "yy" indicates the component of the tensor along the grid y_ axis. + "Sea surface wave radiation stress" describes the excess momentum flux caused by sea surface waves. Radiation stresses behave as a second-order tensor. "yy" indicates the component of the tensor along the grid y_ axis. @@ -31472,16 +31654,12 @@ - - biological_taxon_lsid - - temperature_in_ground - - surface_snow_density + + biological_taxon_lsid @@ -31516,14 +31694,18 @@ tendency_of_atmosphere_mass_content_of_water_vapor_due_to_sublimation_of_surface_snow_and_ice - - atmosphere_upward_absolute_vorticity + + surface_snow_density atmosphere_upward_relative_vorticity + + atmosphere_upward_absolute_vorticity + + area_type @@ -31532,34 +31714,46 @@ area_type - - iron_growth_limitation_of_diazotrophic_phytoplankton + + mass_fraction_of_liquid_precipitation_in_air - - growth_limitation_of_diazotrophic_phytoplankton_due_to_solar_irradiance + + mass_fraction_of_liquid_precipitation_in_air tendency_of_mole_concentration_of_particulate_organic_matter_expressed_as_carbon_in_sea_water_due_to_net_primary_production_by_diazotrophic_phytoplankton - - mole_concentration_of_diazotrophic_phytoplankton_expressed_as_carbon_in_sea_water + + nitrogen_growth_limitation_of_diazotrophic_phytoplankton - - mass_fraction_of_liquid_precipitation_in_air + + net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton - - mass_fraction_of_liquid_precipitation_in_air + + net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton + + + + mole_concentration_of_diazotrophic_phytoplankton_expressed_as_carbon_in_sea_water mass_concentration_of_diazotrophic_phytoplankton_expressed_as_chlorophyll_in_sea_water + + iron_growth_limitation_of_diazotrophic_phytoplankton + + + + growth_limitation_of_diazotrophic_phytoplankton_due_to_solar_irradiance + + air_pseudo_equivalent_potential_temperature @@ -31576,64 +31770,300 @@ tendency_of_mass_fraction_of_stratiform_cloud_ice_in_air_due_to_riming_from_cloud_liquid_water - - nitrogen_growth_limitation_of_diazotrophic_phytoplankton + + sea_water_velocity_from_direction - - net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton + + sea_water_velocity_to_direction - - net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_diazotrophic_phytoplankton + + sea_water_velocity_to_direction - - air_pseudo_equivalent_temperature + + integral_wrt_depth_of_product_of_salinity_and_sea_water_density - - air_equivalent_temperature + + integral_wrt_depth_of_product_of_conservative_temperature_and_sea_water_density - - atmosphere_mass_content_of_convective_cloud_liquid_water + + integral_wrt_depth_of_product_of_potential_temperature_and_sea_water_density - - effective_radius_of_cloud_liquid_water_particles_at_liquid_water_cloud_top + + volume_fraction_of_condensed_water_in_soil_at_wilting_point - - northward_heat_flux_in_air_due_to_eddy_advection + + volume_fraction_of_condensed_water_in_soil_at_field_capacity - - northward_eliassen_palm_flux_in_air + + volume_fraction_of_condensed_water_in_soil_at_critical_point - - net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_wood + + volume_fraction_of_condensed_water_in_soil - - net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_leaves + + product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity - - net_primary_productivity_of_biomass_expressed_as_carbon + + product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity - - mole_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air + + product_of_lagrangian_tendency_of_air_pressure_and_geopotential_height - - mole_concentration_of_microzooplankton_expressed_as_nitrogen_in_sea_water + + product_of_lagrangian_tendency_of_air_pressure_and_air_temperature - - mole_concentration_of_mesozooplankton_expressed_as_nitrogen_in_sea_water + + product_of_lagrangian_tendency_of_air_pressure_and_air_temperature + + + + tendency_of_sea_water_salinity_expressed_as_salt_content_due_to_parameterized_dianeutral_mixing + + + + tendency_of_sea_water_potential_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing + + + + tendency_of_sea_water_conservative_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing + + + + effective_radius_of_stratiform_cloud_snow_particles + + + + tendency_of_atmosphere_moles_of_cfc11 + + + + moles_of_cfc11_per_unit_mass_in_sea_water + + + + atmosphere_moles_of_cfc11 + + + + tendency_of_atmosphere_moles_of_cfc113 + + + + atmosphere_moles_of_cfc113 + + + + tendency_of_atmosphere_moles_of_cfc114 + + + + atmosphere_moles_of_cfc114 + + + + tendency_of_atmosphere_moles_of_cfc115 + + + + atmosphere_moles_of_cfc115 + + + + tendency_of_atmosphere_moles_of_cfc12 + + + + atmosphere_moles_of_cfc12 + + + + tendency_of_atmosphere_moles_of_halon1202 + + + + atmosphere_moles_of_halon1202 + + + + tendency_of_atmosphere_moles_of_halon1211 + + + + atmosphere_moles_of_halon1211 + + + + tendency_of_atmosphere_moles_of_halon1301 + + + + atmosphere_moles_of_halon1301 + + + + tendency_of_atmosphere_moles_of_halon2402 + + + + atmosphere_moles_of_halon2402 + + + + tendency_of_atmosphere_moles_of_hcc140a + + + + atmosphere_moles_of_hcc140a + + + + tendency_of_troposphere_moles_of_hcc140a + + + + tendency_of_middle_atmosphere_moles_of_hcc140a + + + + tendency_of_troposphere_moles_of_hcfc22 + + + + tendency_of_atmosphere_moles_of_hcfc22 + + + + atmosphere_moles_of_hcfc22 + + + + tendency_of_atmosphere_number_content_of_aerosol_particles_due_to_turbulent_deposition + + + + lagrangian_tendency_of_atmosphere_sigma_coordinate + + + + lagrangian_tendency_of_atmosphere_sigma_coordinate + + + + electrical_mobility_diameter_of_ambient_aerosol_particles + + + + diameter_of_ambient_aerosol_particles + + + + mass_concentration_of_biomass_burning_dry_aerosol_particles_in_air + + + + effective_radius_of_stratiform_cloud_rain_particles + + + + effective_radius_of_stratiform_cloud_ice_particles + + + + effective_radius_of_stratiform_cloud_graupel_particles + + + + effective_radius_of_convective_cloud_snow_particles + + + + effective_radius_of_convective_cloud_rain_particles + + + + effective_radius_of_convective_cloud_ice_particles + + + + histogram_of_backscattering_ratio_in_air_over_height_above_reference_ellipsoid + + + + backscattering_ratio_in_air + + + + product_of_northward_wind_and_lagrangian_tendency_of_air_pressure + + + + product_of_eastward_wind_and_lagrangian_tendency_of_air_pressure + + + + carbon_mass_flux_into_litter_and_soil_due_to_anthropogenic_land_use_or_land_cover_change + + + + floating_ice_shelf_area_fraction + + + + atmosphere_moles_of_carbon_tetrachloride + + + + mole_fraction_of_methylglyoxal_in_air + + + + mole_fraction_of_dichlorine_peroxide_in_air + + + + atmosphere_mass_content_of_convective_cloud_liquid_water + + + + effective_radius_of_cloud_liquid_water_particles_at_liquid_water_cloud_top + + + + air_equivalent_temperature + + + + air_pseudo_equivalent_temperature + + + + mass_content_of_cloud_liquid_water_in_atmosphere_layer + + + + air_equivalent_potential_temperature + + + + number_concentration_of_stratiform_cloud_liquid_water_particles_at_stratiform_liquid_water_cloud_top + + + + number_concentration_of_convective_cloud_liquid_water_particles_at_convective_liquid_water_cloud_top @@ -31660,360 +32090,104 @@ atmosphere_mass_content_of_cloud_liquid_water - - mass_fraction_of_sulfate_dry_aerosol_particles_in_air - - - - mass_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air - - - - mass_fraction_of_ammonium_dry_aerosol_particles_in_air - - - - tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_shallow_convection - - - - tendency_of_mass_content_of_water_vapor_in_atmosphere_layer - - - - mass_content_of_cloud_ice_in_atmosphere_layer - - - - mass_concentration_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air - - - - mass_concentration_of_mercury_dry_aerosol_particles_in_air - - - - mass_concentration_of_coarse_mode_ambient_aerosol_particles_in_air - - - - sea_water_velocity_to_direction - - - - sea_water_velocity_to_direction - - - - gross_primary_productivity_of_biomass_expressed_as_carbon - - - - eastward_water_vapor_flux_in_air - - - - atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles - - - - tendency_of_middle_atmosphere_moles_of_carbon_monoxide - - - - tendency_of_atmosphere_mass_content_of_water_vapor_due_to_advection - - - - tendency_of_atmosphere_mass_content_of_water_vapor - - - - lwe_thickness_of_atmosphere_mass_content_of_water_vapor - - - - change_over_time_in_atmosphere_mass_content_of_water_due_to_advection - - - - change_over_time_in_atmosphere_mass_content_of_water_due_to_advection - - - - atmosphere_mass_content_of_water_vapor - - - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_gravitational_settling - - - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_gravitational_settling - - - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_dry_deposition - - - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_dry_deposition - - - - tendency_of_middle_atmosphere_moles_of_methyl_bromide - - - - atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur - - - - atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur - - - - atmosphere_mass_content_of_sulfate - - - - atmosphere_mass_content_of_sulfate - - - - tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition - - - - tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production - - - - tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production - - - - tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition - - - - atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles - - - - tendency_of_atmosphere_mass_content_of_water_vapor_due_to_deep_convection - - - - tendency_of_atmosphere_mass_content_of_water_vapor_due_to_convection - - - - atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles - - - - mass_content_of_cloud_liquid_water_in_atmosphere_layer - - - - air_equivalent_potential_temperature - - - - number_concentration_of_stratiform_cloud_liquid_water_particles_at_stratiform_liquid_water_cloud_top - - - - number_concentration_of_convective_cloud_liquid_water_particles_at_convective_liquid_water_cloud_top - - - - wave_frequency - - - - upward_eastward_momentum_flux_in_air_due_to_nonorographic_eastward_gravity_waves - - - - tendency_of_troposphere_moles_of_carbon_monoxide - - - - tendency_of_atmosphere_moles_of_sulfate_dry_aerosol_particles - - - - tendency_of_atmosphere_mass_content_of_nitrate_dry_aerosol_particles_due_to_dry_deposition - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_waste_treatment_and_disposal - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_savanna_and_grassland_fires - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_maritime_transport - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_land_transport - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_forest_fires - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_agricultural_waste_burning - - - - tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_turbulent_deposition - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production_and_emission - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production_and_emission - - - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_gravitational_settling + + mole_fraction_of_noy_expressed_as_nitrogen_in_air - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition + + tendency_of_atmosphere_moles_of_methane - - atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles + + rate_of_hydroxyl_radical_destruction_due_to_reaction_with_nmvoc - - integral_wrt_depth_of_product_of_conservative_temperature_and_sea_water_density + + net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_miscellaneous_phytoplankton - - integral_wrt_depth_of_product_of_salinity_and_sea_water_density + + mole_fraction_of_inorganic_bromine_in_air - - tendency_of_atmosphere_moles_of_methyl_bromide + + water_vapor_saturation_deficit_in_air - - integral_wrt_depth_of_product_of_potential_temperature_and_sea_water_density + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_agricultural_waste_burning - - atmosphere_moles_of_methyl_bromide + + tendency_of_atmosphere_moles_of_carbon_tetrachloride - - product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity + + tendency_of_atmosphere_moles_of_carbon_monoxide - - product_of_lagrangian_tendency_of_air_pressure_and_specific_humidity + + platform_yaw - - tendency_of_sea_water_potential_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing + + platform_pitch - - tendency_of_sea_water_conservative_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing + + platform_roll - - volume_fraction_of_condensed_water_in_soil_at_wilting_point + + tendency_of_specific_humidity_due_to_stratiform_precipitation - - volume_fraction_of_condensed_water_in_soil_at_field_capacity + + tendency_of_air_temperature_due_to_stratiform_precipitation - - volume_fraction_of_condensed_water_in_soil_at_critical_point + + stratiform_precipitation_flux - - volume_fraction_of_condensed_water_in_soil + + stratiform_precipitation_amount - - product_of_lagrangian_tendency_of_air_pressure_and_geopotential_height + + lwe_thickness_of_stratiform_precipitation_amount - - product_of_lagrangian_tendency_of_air_pressure_and_air_temperature + + lwe_stratiform_precipitation_rate - - product_of_lagrangian_tendency_of_air_pressure_and_air_temperature + + water_evaporation_amount_from_canopy - - tendency_of_sea_water_salinity_expressed_as_salt_content_due_to_parameterized_dianeutral_mixing + + water_evaporation_flux_from_canopy - - atmosphere_moles_of_methane + + precipitation_flux_onto_canopy - - electrical_mobility_diameter_of_ambient_aerosol_particles + + outgoing_water_volume_transport_along_river_channel - - histogram_of_backscattering_ratio_in_air_over_height_above_reference_ellipsoid + + tendency_of_sea_ice_amount_due_to_conversion_of_snow_to_sea_ice tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_emission - - effective_radius_of_stratiform_cloud_snow_particles - - - - mass_concentration_of_biomass_burning_dry_aerosol_particles_in_air - - - - atmosphere_mass_content_of_nitric_acid_trihydrate_ambient_aerosol_particles - - - - atmosphere_mass_content_of_nitrate_dry_aerosol_particles - - - - atmosphere_mass_content_of_mercury_dry_aerosol_particles - - - - backscattering_ratio_in_air - - - - product_of_northward_wind_and_lagrangian_tendency_of_air_pressure + + mass_fraction_of_mercury_dry_aerosol_particles_in_air @@ -32024,256 +32198,224 @@ tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_wet_deposition - - tendency_of_atmosphere_moles_of_cfc11 - - - - moles_of_cfc11_per_unit_mass_in_sea_water - - - - atmosphere_moles_of_cfc11 - - - - tendency_of_atmosphere_moles_of_hcc140a - - - - effective_radius_of_convective_cloud_rain_particles - - - - tendency_of_troposphere_moles_of_hcc140a - - - - tendency_of_middle_atmosphere_moles_of_hcc140a - - - - tendency_of_troposphere_moles_of_hcfc22 - - - - tendency_of_atmosphere_moles_of_hcfc22 + + stratiform_cloud_area_fraction - - atmosphere_moles_of_hcfc22 + + magnitude_of_sea_ice_displacement - - tendency_of_atmosphere_number_content_of_aerosol_particles_due_to_turbulent_deposition + + surface_downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water - - lagrangian_tendency_of_atmosphere_sigma_coordinate + + surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol - - lagrangian_tendency_of_atmosphere_sigma_coordinate + + surface_downwelling_shortwave_flux_in_air_assuming_clear_sky - - diameter_of_ambient_aerosol_particles + + surface_downwelling_shortwave_flux_in_air - - effective_radius_of_stratiform_cloud_ice_particles + + surface_downwelling_radiative_flux_per_unit_wavelength_in_sea_water - - effective_radius_of_convective_cloud_ice_particles + + surface_downwelling_radiative_flux_per_unit_wavelength_in_air - - effective_radius_of_stratiform_cloud_graupel_particles + + surface_downwelling_radiance_per_unit_wavelength_in_sea_water - - effective_radius_of_stratiform_cloud_rain_particles + + surface_downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water - - effective_radius_of_convective_cloud_snow_particles + + surface_downwelling_photon_radiance_per_unit_wavelength_in_sea_water - - product_of_eastward_wind_and_lagrangian_tendency_of_air_pressure + + surface_downwelling_photon_flux_per_unit_wavelength_in_sea_water - - carbon_mass_flux_into_litter_and_soil_due_to_anthropogenic_land_use_or_land_cover_change + + surface_downwelling_longwave_flux_in_air - - stratiform_cloud_area_fraction + + integral_wrt_time_of_surface_downwelling_shortwave_flux_in_air - - sea_water_velocity_from_direction + + integral_wrt_time_of_surface_downwelling_longwave_flux_in_air - - thickness_of_stratiform_snowfall_amount + + downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water - - optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles + + downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol - - optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles + + downwelling_radiative_flux_per_unit_wavelength_in_sea_water - - lwe_thickness_of_stratiform_snowfall_amount + + downwelling_radiative_flux_per_unit_wavelength_in_air - - equivalent_thickness_at_stp_of_atmosphere_ozone_content + + downwelling_radiance_per_unit_wavelength_in_sea_water - - atmosphere_optical_thickness_due_to_water_in_ambient_aerosol_particles + + downwelling_radiance_per_unit_wavelength_in_air - - atmosphere_optical_thickness_due_to_dust_dry_aerosol_particles + + downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water - - atmosphere_optical_thickness_due_to_dust_ambient_aerosol_particles + + downwelling_photon_radiance_per_unit_wavelength_in_sea_water - - atmosphere_optical_thickness_due_to_ambient_aerosol_particles + + downwelling_photon_flux_per_unit_wavelength_in_sea_water - - atmosphere_optical_thickness_due_to_ambient_aerosol_particles + + surface_upwelling_shortwave_flux_in_air_assuming_clear_sky - - atmosphere_net_upward_convective_mass_flux + + surface_upwelling_longwave_flux_in_air_assuming_clear_sky - - mass_fraction_of_mercury_dry_aerosol_particles_in_air + + upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol - - atmosphere_moles_of_hcc140a + + upwelling_radiative_flux_per_unit_wavelength_in_sea_water - - floating_ice_shelf_area_fraction + + upwelling_radiative_flux_per_unit_wavelength_in_air - - atmosphere_moles_of_carbon_tetrachloride + + upwelling_radiance_per_unit_wavelength_in_air - - mole_fraction_of_methylglyoxal_in_air + + surface_upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol - - mole_fraction_of_dichlorine_peroxide_in_air + + surface_upwelling_shortwave_flux_in_air - - mole_fraction_of_noy_expressed_as_nitrogen_in_air + + surface_upwelling_radiative_flux_per_unit_wavelength_in_sea_water - - net_primary_mole_productivity_of_biomass_expressed_as_carbon_by_miscellaneous_phytoplankton + + surface_upwelling_radiative_flux_per_unit_wavelength_in_air - - mole_fraction_of_inorganic_bromine_in_air + + surface_upwelling_radiance_per_unit_wavelength_in_sea_water - - water_vapor_saturation_deficit_in_air + + volume_scattering_coefficient_of_radiative_flux_in_air_due_to_ambient_aerosol_particles - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_agricultural_waste_burning + + volume_scattering_coefficient_of_radiative_flux_in_air_due_to_dried_aerosol_particles - - tendency_of_atmosphere_moles_of_carbon_tetrachloride + + soil_mass_content_of_carbon - - tendency_of_atmosphere_moles_of_carbon_monoxide + + slow_soil_pool_mass_content_of_carbon - - tendency_of_atmosphere_moles_of_cfc113 + + root_mass_content_of_carbon - - atmosphere_moles_of_cfc113 + + miscellaneous_living_matter_mass_content_of_carbon - - tendency_of_atmosphere_moles_of_cfc114 + + fast_soil_pool_mass_content_of_carbon - - atmosphere_moles_of_cfc114 + + medium_soil_pool_mass_content_of_carbon - - tendency_of_atmosphere_moles_of_cfc115 + + leaf_mass_content_of_carbon - - atmosphere_moles_of_cfc115 + + carbon_mass_content_of_forestry_and_agricultural_products - - tendency_of_atmosphere_moles_of_cfc12 + + carbon_mass_content_of_forestry_and_agricultural_products - - atmosphere_moles_of_cfc12 + + surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration_for_biomass_maintenance - - tendency_of_atmosphere_moles_of_halon1202 + + surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration_for_biomass_growth - - atmosphere_moles_of_halon1202 + + surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration - - tendency_of_atmosphere_moles_of_halon1211 + + surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_respiration_in_soil - - atmosphere_moles_of_halon1211 + + surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_heterotrophic_respiration - - tendency_of_atmosphere_moles_of_halon1301 + + northward_transformed_eulerian_mean_air_velocity - - atmosphere_moles_of_halon1301 + + eastward_transformed_eulerian_mean_air_velocity - - tendency_of_atmosphere_moles_of_halon2402 + + surface_litter_mass_content_of_carbon - - atmosphere_moles_of_halon2402 + + litter_mass_content_of_carbon @@ -32308,14 +32450,14 @@ mole_concentration_of_diatoms_expressed_as_nitrogen_in_sea_water - - tendency_of_mole_concentration_of_dissolved_inorganic_phosphorus_in_sea_water_due_to_biological_processes - - tendency_of_mole_concentration_of_dissolved_inorganic_silicon_in_sea_water_due_to_biological_processes + + tendency_of_mole_concentration_of_dissolved_inorganic_phosphorus_in_sea_water_due_to_biological_processes + + tendency_of_atmosphere_mole_concentration_of_carbon_monoxide_due_to_chemical_destruction @@ -32324,56 +32466,64 @@ volume_extinction_coefficient_in_air_due_to_ambient_aerosol_particles - - atmosphere_mass_content_of_convective_cloud_condensed_water + + water_vapor_partial_pressure_in_air - - water_evaporation_flux_from_canopy + + platform_name - - precipitation_flux_onto_canopy + + platform_id - - surface_downwelling_shortwave_flux_in_air_assuming_clear_sky + + mass_flux_of_carbon_into_litter_from_vegetation - - surface_downwelling_radiance_per_unit_wavelength_in_sea_water + + subsurface_litter_mass_content_of_carbon - - upwelling_radiative_flux_per_unit_wavelength_in_sea_water + + stem_mass_content_of_carbon - - downwelling_photon_flux_per_unit_wavelength_in_sea_water + + mole_concentration_of_dissolved_inorganic_14C_in_sea_water - - downwelling_radiance_per_unit_wavelength_in_sea_water + + surface_downward_mass_flux_of_14C_dioxide_abiotic_analogue_expressed_as_carbon - - surface_downwelling_photon_radiance_per_unit_wavelength_in_sea_water + + surface_downward_mass_flux_of_13C_dioxide_abiotic_analogue_expressed_as_13C - - surface_downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water + + mole_concentration_of_dissolved_inorganic_13C_in_sea_water - - surface_upwelling_radiative_flux_per_unit_wavelength_in_sea_water + + surface_upwelling_radiance_per_unit_wavelength_in_air_reflected_by_sea_water - - surface_downwelling_shortwave_flux_in_air + + surface_upwelling_radiance_per_unit_wavelength_in_air_emerging_from_sea_water - - tendency_of_sea_ice_amount_due_to_conversion_of_snow_to_sea_ice + + surface_upwelling_radiance_per_unit_wavelength_in_air + + + + surface_upwelling_longwave_flux_in_air + + + + incoming_water_volume_transport_along_river_channel @@ -32392,792 +32542,820 @@ sea_ice_temperature_expressed_as_heat_content - - outgoing_water_volume_transport_along_river_channel + + water_evapotranspiration_flux - - lwe_thickness_of_stratiform_precipitation_amount + + surface_water_evaporation_flux - - tendency_of_atmosphere_moles_of_methane + + water_volume_transport_into_sea_water_from_rivers - - rate_of_hydroxyl_radical_destruction_due_to_reaction_with_nmvoc + + stratiform_graupel_flux - - magnitude_of_sea_ice_displacement + + wood_debris_mass_content_of_carbon - - surface_downwelling_radiative_flux_per_unit_wavelength_in_sea_water + + toa_outgoing_shortwave_flux_assuming_clear_sky_and_no_aerosol - - surface_downwelling_radiative_flux_per_unit_wavelength_in_air + + water_flux_into_sea_water_from_rivers - - surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol + + integral_wrt_height_of_product_of_northward_wind_and_specific_humidity - - surface_downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water + + integral_wrt_height_of_product_of_eastward_wind_and_specific_humidity - - surface_downwelling_photon_flux_per_unit_wavelength_in_sea_water + + integral_wrt_depth_of_sea_water_temperature - - surface_downwelling_longwave_flux_in_air + + integral_wrt_depth_of_sea_water_temperature - - integral_wrt_time_of_surface_downwelling_shortwave_flux_in_air + + integral_wrt_depth_of_sea_water_temperature - - integral_wrt_time_of_surface_downwelling_longwave_flux_in_air + + integral_wrt_depth_of_sea_water_temperature - - downwelling_spherical_irradiance_per_unit_wavelength_in_sea_water + + integral_wrt_depth_of_sea_water_practical_salinity - - downwelling_radiative_flux_per_unit_wavelength_in_sea_water + + northward_ocean_heat_transport_due_to_parameterized_eddy_advection - - downwelling_radiative_flux_per_unit_wavelength_in_air + + tendency_of_ocean_eddy_kinetic_energy_content_due_to_parameterized_eddy_advection - - downwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol + + ocean_tracer_laplacian_diffusivity_due_to_parameterized_mesoscale_eddy_advection - - downwelling_photon_spherical_irradiance_per_unit_wavelength_in_sea_water + + ocean_tracer_biharmonic_diffusivity_due_to_parameterized_mesoscale_eddy_advection - - downwelling_radiance_per_unit_wavelength_in_air + + upward_sea_water_velocity_due_to_parameterized_mesoscale_eddies - - downwelling_photon_radiance_per_unit_wavelength_in_sea_water + + sea_water_y_velocity_due_to_parameterized_mesoscale_eddies - - surface_upwelling_shortwave_flux_in_air_assuming_clear_sky + + sea_water_x_velocity_due_to_parameterized_mesoscale_eddies - - surface_upwelling_longwave_flux_in_air_assuming_clear_sky + + eastward_sea_water_velocity_due_to_parameterized_mesoscale_eddies - - upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol + + northward_sea_water_velocity_due_to_parameterized_mesoscale_eddies - - upwelling_radiative_flux_per_unit_wavelength_in_air + + tendency_of_sea_water_temperature_due_to_parameterized_eddy_advection - - upwelling_radiance_per_unit_wavelength_in_air + + tendency_of_sea_water_salinity_due_to_parameterized_eddy_advection - - surface_upwelling_shortwave_flux_in_air_assuming_clear_sky_and_no_aerosol + + ocean_y_overturning_mass_streamfunction_due_to_parameterized_eddy_advection - - surface_upwelling_shortwave_flux_in_air + + ocean_meridional_overturning_mass_streamfunction_due_to_parameterized_eddy_advection - - surface_upwelling_radiance_per_unit_wavelength_in_sea_water + + ocean_mass_y_transport_due_to_advection_and_parameterized_eddy_advection - - incoming_water_volume_transport_along_river_channel + + ocean_mass_x_transport_due_to_advection_and_parameterized_eddy_advection - - surface_upwelling_longwave_flux_in_air + + ocean_heat_y_transport_due_to_parameterized_eddy_advection - - surface_upwelling_radiance_per_unit_wavelength_in_air_emerging_from_sea_water + + ocean_heat_x_transport_due_to_parameterized_eddy_advection - - surface_upwelling_radiative_flux_per_unit_wavelength_in_air + + northward_ocean_salt_transport_due_to_parameterized_eddy_advection - - surface_upwelling_radiance_per_unit_wavelength_in_air + + northward_ocean_freshwater_transport_due_to_parameterized_eddy_advection - - surface_upwelling_radiance_per_unit_wavelength_in_air_reflected_by_sea_water + + integral_wrt_time_of_toa_outgoing_longwave_flux - - wood_debris_mass_content_of_carbon + + integral_wrt_time_of_toa_net_downward_shortwave_flux - - water_flux_into_sea_water_from_rivers + + integral_wrt_time_of_surface_net_downward_shortwave_flux - - integral_wrt_depth_of_sea_water_temperature + + integral_wrt_time_of_surface_net_downward_longwave_flux - - integral_wrt_depth_of_sea_water_temperature + + integral_wrt_time_of_surface_downward_sensible_heat_flux - - integral_wrt_depth_of_sea_water_temperature + + integral_wrt_time_of_surface_downward_latent_heat_flux - - integral_wrt_depth_of_sea_water_temperature + + integral_wrt_time_of_air_temperature_excess - - volume_scattering_coefficient_of_radiative_flux_in_air_due_to_ambient_aerosol_particles + + integral_wrt_time_of_air_temperature_deficit - - volume_scattering_coefficient_of_radiative_flux_in_air_due_to_dried_aerosol_particles + + tendency_of_mass_concentration_of_elemental_carbon_dry_aerosol_particles_in_air_due_to_emission_from_aviation - - integral_wrt_height_of_product_of_northward_wind_and_specific_humidity + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_wet_deposition - - integral_wrt_depth_of_sea_water_practical_salinity + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_turbulent_deposition - - integral_wrt_height_of_product_of_eastward_wind_and_specific_humidity + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_gravitational_settling - - platform_yaw + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_waste_treatment_and_disposal - - platform_roll + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_savanna_and_grassland_fires - - water_vapor_partial_pressure_in_air + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_residential_and_commercial_combustion - - platform_name + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_maritime_transport - - platform_id + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_land_transport - - platform_pitch + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_industrial_processes_and_combustion - - tendency_of_specific_humidity_due_to_stratiform_precipitation + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_forest_fires - - tendency_of_air_temperature_due_to_stratiform_precipitation + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_energy_production_and_distribution - - water_evaporation_amount_from_canopy + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission - - tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_turbulent_deposition + + tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_gravitational_settling + + mass_fraction_of_elemental_carbon_dry_aerosol_particles_in_air - - tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_emission + + atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles - - atmosphere_mass_content_of_cloud_ice + + mass_concentration_of_elemental_carbon_dry_aerosol_particles_in_air - - stratiform_precipitation_amount + + lagrangian_tendency_of_air_pressure - - tendency_of_atmosphere_moles_of_nitrous_oxide + + lagrangian_tendency_of_air_pressure - - tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_dry_deposition + + air_pressure_at_mean_sea_level - - medium_soil_pool_mass_content_of_carbon + + sea_floor_depth_below_geoid - - surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration + + sea_surface_height_above_geoid - - surface_downward_mass_flux_of_14C_dioxide_abiotic_analogue_expressed_as_carbon + + sea_surface_height_above_geoid - - mole_concentration_of_dissolved_inorganic_13C_in_sea_water + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_emission - - surface_litter_mass_content_of_carbon + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_emission - - surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_heterotrophic_respiration + + atmosphere_absorption_optical_thickness_due_to_sea_salt_ambient_aerosol_particles - - fast_soil_pool_mass_content_of_carbon + + atmosphere_absorption_optical_thickness_due_to_sea_salt_ambient_aerosol_particles - - soil_mass_content_of_carbon + + tendency_of_atmosphere_mass_content_of_nitrogen_compounds_expressed_as_nitrogen_due_to_deposition - - slow_soil_pool_mass_content_of_carbon + + tendency_of_atmosphere_mass_content_of_nitrogen_compounds_expressed_as_nitrogen_due_to_dry_deposition - - root_mass_content_of_carbon + + surface_geostrophic_eastward_sea_water_velocity - - miscellaneous_living_matter_mass_content_of_carbon + + surface_geostrophic_northward_sea_water_velocity - - carbon_mass_content_of_forestry_and_agricultural_products + + tendency_of_sea_surface_height_above_mean_sea_level + + + + surface_geostrophic_sea_water_y_velocity_assuming_mean_sea_level_for_geoid + + + + surface_geostrophic_sea_water_x_velocity_assuming_mean_sea_level_for_geoid + + + + surface_geostrophic_northward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + + + surface_geostrophic_northward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + + + surface_geostrophic_eastward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + + + surface_geostrophic_eastward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + + + sea_surface_height_above_mean_sea_level - - carbon_mass_content_of_forestry_and_agricultural_products + + sea_surface_height_above_mean_sea_level - - surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration_for_biomass_maintenance + + sea_floor_depth_below_mean_sea_level - - surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_plant_respiration_for_biomass_growth + + mass_fraction_of_pm10_ambient_aerosol_particles_in_air - - surface_upward_mass_flux_of_carbon_dioxide_expressed_as_carbon_due_to_respiration_in_soil + + mass_fraction_of_pm10_ambient_aerosol_particles_in_air - - northward_transformed_eulerian_mean_air_velocity + + mass_concentration_of_pm10_ambient_aerosol_particles_in_air - - eastward_transformed_eulerian_mean_air_velocity + + atmosphere_optical_thickness_due_to_pm10_ambient_aerosol_particles - - mass_flux_of_carbon_into_litter_from_vegetation + + mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air - - subsurface_litter_mass_content_of_carbon + + mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air - - litter_mass_content_of_carbon + + mass_concentration_of_pm2p5_ambient_aerosol_particles_in_air - - stem_mass_content_of_carbon + + atmosphere_optical_thickness_due_to_pm2p5_ambient_aerosol_particles - - mole_concentration_of_dissolved_inorganic_14C_in_sea_water + + mass_fraction_of_pm1_ambient_aerosol_particles_in_air - - surface_downward_mass_flux_of_13C_dioxide_abiotic_analogue_expressed_as_13C + + mass_fraction_of_pm1_ambient_aerosol_particles_in_air - - stratiform_precipitation_flux + + mass_concentration_of_pm1_ambient_aerosol_particles_in_air - - lwe_stratiform_precipitation_rate + + atmosphere_optical_thickness_due_to_pm1_ambient_aerosol_particles - - surface_water_evaporation_flux + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition - - water_evapotranspiration_flux + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition - - water_volume_transport_into_sea_water_from_rivers + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition - - stratiform_graupel_flux + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition - - toa_outgoing_shortwave_flux_assuming_clear_sky_and_no_aerosol + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling - - ocean_y_overturning_mass_streamfunction_due_to_parameterized_eddy_advection + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling - - ocean_tracer_laplacian_diffusivity_due_to_parameterized_mesoscale_eddy_advection + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition - - sea_water_x_velocity_due_to_parameterized_mesoscale_eddies + + tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_sea_water_temperature_due_to_parameterized_eddy_advection + + tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_wet_deposition - - northward_ocean_heat_transport_due_to_parameterized_eddy_advection + + tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_wet_deposition - - upward_sea_water_velocity_due_to_parameterized_mesoscale_eddies + + tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_emission - - tendency_of_sea_water_salinity_due_to_parameterized_eddy_advection + + tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_dry_deposition - - integral_wrt_time_of_surface_net_downward_shortwave_flux + + mass_fraction_of_sea_salt_dry_aerosol_particles_in_air - - tendency_of_ocean_eddy_kinetic_energy_content_due_to_parameterized_eddy_advection + + mass_fraction_of_sea_salt_dry_aerosol_particles_in_air - - sea_water_y_velocity_due_to_parameterized_mesoscale_eddies + + mass_concentration_of_sea_salt_dry_aerosol_particles_in_air - - ocean_tracer_biharmonic_diffusivity_due_to_parameterized_mesoscale_eddy_advection + + mass_concentration_of_sea_salt_dry_aerosol_particles_in_air - - eastward_sea_water_velocity_due_to_parameterized_mesoscale_eddies + + atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles - - northward_sea_water_velocity_due_to_parameterized_mesoscale_eddies + + atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles - - ocean_heat_y_transport_due_to_parameterized_eddy_advection + + atmosphere_mass_content_of_sea_salt_dry_aerosol_particles - - ocean_meridional_overturning_mass_streamfunction_due_to_parameterized_eddy_advection + + atmosphere_mass_content_of_sea_salt_dry_aerosol_particles - - ocean_mass_y_transport_due_to_advection_and_parameterized_eddy_advection + + ocean_mixed_layer_thickness_defined_by_vertical_tracer_diffusivity_deficit - - ocean_mass_x_transport_due_to_advection_and_parameterized_eddy_advection + + sea_surface_swell_wave_mean_period - - ocean_heat_x_transport_due_to_parameterized_eddy_advection + + sea_surface_wind_wave_mean_period - - northward_ocean_freshwater_transport_due_to_parameterized_eddy_advection + + sea_surface_wave_mean_period - - northward_ocean_salt_transport_due_to_parameterized_eddy_advection + + sea_surface_wind_wave_to_direction - - integral_wrt_time_of_toa_outgoing_longwave_flux + + sea_surface_swell_wave_to_direction - - integral_wrt_time_of_toa_net_downward_shortwave_flux + + mass_content_of_water_in_soil - - integral_wrt_time_of_surface_net_downward_longwave_flux + + mass_content_of_water_in_soil_layer - - integral_wrt_time_of_surface_downward_sensible_heat_flux + + sea_surface_wave_significant_height - - integral_wrt_time_of_surface_downward_latent_heat_flux + + sea_surface_wind_wave_significant_height - - integral_wrt_time_of_air_temperature_excess + + sea_surface_swell_wave_significant_height - - integral_wrt_time_of_air_temperature_deficit + + tendency_of_atmosphere_moles_of_sulfate_dry_aerosol_particles - - tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_wet_deposition + + tendency_of_atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles - - tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_dry_deposition + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition - - atmosphere_absorption_optical_thickness_due_to_sulfate_ambient_aerosol_particles + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition - - atmosphere_absorption_optical_thickness_due_to_particulate_organic_matter_ambient_aerosol_particles + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_gravitational_settling - - atmosphere_absorption_optical_thickness_due_to_dust_ambient_aerosol_particles + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_gravitational_settling - - angstrom_exponent_of_ambient_aerosol_in_air + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_dry_deposition - - atmosphere_convective_available_potential_energy + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_dry_deposition - - atmosphere_convective_available_potential_energy + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_mass_concentration_of_elemental_carbon_dry_aerosol_particles_in_air_due_to_emission_from_aviation + + tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_wet_deposition + + tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_turbulent_deposition + + tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_gravitational_settling + + tendency_of_atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_waste_treatment_and_disposal + + tendency_of_atmosphere_mass_content_of_nitrate_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_savanna_and_grassland_fires + + tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_wet_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_residential_and_commercial_combustion + + tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_maritime_transport + + tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_wet_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_land_transport + + tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_turbulent_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_industrial_processes_and_combustion + + tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_gravitational_settling - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_forest_fires + + tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission_from_energy_production_and_distribution + + tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_wet_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_emission + + tendency_of_atmosphere_mass_content_of_ammonium_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles_due_to_dry_deposition + + optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles - - mass_fraction_of_elemental_carbon_dry_aerosol_particles_in_air + + optical_thickness_of_atmosphere_layer_due_to_ambient_aerosol_particles - - atmosphere_mass_content_of_elemental_carbon_dry_aerosol_particles + + number_concentration_of_nucleation_mode_ambient_aerosol_particles_in_air - - mass_concentration_of_elemental_carbon_dry_aerosol_particles_in_air + + number_concentration_of_coarse_mode_ambient_aerosol_particles_in_air - - lagrangian_tendency_of_air_pressure + + number_concentration_of_ambient_aerosol_particles_in_air - - lagrangian_tendency_of_air_pressure + + mole_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air - - sea_surface_height_above_geoid + + mole_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air - - sea_surface_height_above_geoid + + mass_fraction_of_water_in_ambient_aerosol_particles_in_air - - surface_geostrophic_eastward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + mass_fraction_of_sulfate_dry_aerosol_particles_in_air - - surface_geostrophic_eastward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + mass_fraction_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air - - sea_surface_height_above_mean_sea_level + + mass_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air - - sea_surface_height_above_mean_sea_level + + mass_fraction_of_nitrate_dry_aerosol_particles_in_air - - surface_geostrophic_northward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + mass_fraction_of_dust_dry_aerosol_particles_in_air - - surface_geostrophic_northward_sea_water_velocity_assuming_mean_sea_level_for_geoid + + mass_fraction_of_ammonium_dry_aerosol_particles_in_air - - surface_geostrophic_sea_water_y_velocity_assuming_mean_sea_level_for_geoid + + mass_concentration_of_water_in_ambient_aerosol_particles_in_air - - sea_floor_depth_below_geoid + + mass_concentration_of_sulfate_dry_aerosol_particles_in_air - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_emission + + mass_concentration_of_sulfate_ambient_aerosol_particles_in_air - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_emission + + mass_concentration_of_sulfate_ambient_aerosol_particles_in_air - - atmosphere_absorption_optical_thickness_due_to_sea_salt_ambient_aerosol_particles + + mass_concentration_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air - - atmosphere_absorption_optical_thickness_due_to_sea_salt_ambient_aerosol_particles + + mass_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air - - tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_emission + + mass_concentration_of_nitrate_dry_aerosol_particles_in_air - - tendency_of_atmosphere_mass_content_of_nitrogen_compounds_expressed_as_nitrogen_due_to_deposition + + mass_concentration_of_mercury_dry_aerosol_particles_in_air - - tendency_of_atmosphere_mass_content_of_nitrogen_compounds_expressed_as_nitrogen_due_to_dry_deposition + + atmosphere_optical_thickness_due_to_water_in_ambient_aerosol_particles - - surface_geostrophic_northward_sea_water_velocity + + mass_concentration_of_particulate_organic_matter_dry_aerosol_particles_in_air - - surface_geostrophic_sea_water_x_velocity_assuming_mean_sea_level_for_geoid + + mass_concentration_of_primary_particulate_organic_matter_dry_aerosol_particles_in_air - - air_pressure_at_mean_sea_level + + atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur - - sea_floor_depth_below_mean_sea_level + + atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur - - ocean_mixed_layer_thickness_defined_by_vertical_tracer_diffusivity_deficit + + mass_concentration_of_ammonium_dry_aerosol_particles_in_air - - sea_surface_wind_wave_mean_period + + mass_concentration_of_coarse_mode_ambient_aerosol_particles_in_air - - sea_surface_wave_mean_period + + mass_concentration_of_dust_dry_aerosol_particles_in_air - - sea_surface_swell_wave_mean_period + + atmosphere_optical_thickness_due_to_particulate_organic_matter_ambient_aerosol_particles - - sea_surface_wind_wave_to_direction + + atmosphere_optical_thickness_due_to_dust_dry_aerosol_particles - - sea_surface_swell_wave_to_direction + + atmosphere_optical_thickness_due_to_dust_ambient_aerosol_particles - - mass_content_of_water_in_soil_layer + + atmosphere_optical_thickness_due_to_ambient_aerosol_particles - - mass_content_of_water_in_soil + + atmosphere_optical_thickness_due_to_ambient_aerosol_particles - - sea_surface_wind_wave_significant_height + + atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles - - sea_surface_swell_wave_significant_height + + atmosphere_mass_content_of_water_in_ambient_aerosol_particles - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition + + atmosphere_mass_content_of_sulfate_dry_aerosol_particles - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_expressed_as_sulfur_due_to_turbulent_deposition + + atmosphere_mass_content_of_sulfate_ambient_aerosol_particles - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_emission + + atmosphere_mass_content_of_sulfate_ambient_aerosol_particles - - atmosphere_optical_thickness_due_to_particulate_organic_matter_ambient_aerosol_particles + + atmosphere_mass_content_of_secondary_particulate_organic_matter_dry_aerosol_particles - - mass_concentration_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air + + atmosphere_mass_content_of_nitric_acid_trihydrate_ambient_aerosol_particles - - atmosphere_mass_content_of_water_in_ambient_aerosol_particles + + atmosphere_mass_content_of_nitrate_dry_aerosol_particles - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_residential_and_commercial_combustion + + atmosphere_mass_content_of_mercury_dry_aerosol_particles - - tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_wet_deposition + + atmosphere_mass_content_of_dust_dry_aerosol_particles - - tendency_of_atmosphere_mass_content_of_mercury_dry_aerosol_particles_due_to_dry_deposition + + atmosphere_mass_content_of_ammonium_dry_aerosol_particles - - mass_fraction_of_nitrate_dry_aerosol_particles_in_air + + atmosphere_absorption_optical_thickness_due_to_sulfate_ambient_aerosol_particles - - mass_concentration_of_sulfate_dry_aerosol_particles_in_air + + atmosphere_absorption_optical_thickness_due_to_particulate_organic_matter_ambient_aerosol_particles - - mass_fraction_of_water_in_ambient_aerosol_particles_in_air + + atmosphere_absorption_optical_thickness_due_to_dust_ambient_aerosol_particles - - mass_fraction_of_secondary_particulate_organic_matter_dry_aerosol_particles_in_air + + angstrom_exponent_of_ambient_aerosol_in_air - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_industrial_processes_and_combustion + + atmosphere_absorption_optical_thickness_due_to_ambient_aerosol_particles - - tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_energy_production_and_distribution + + tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition - - mass_concentration_of_sulfate_ambient_aerosol_particles_in_air + + tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition - - mass_concentration_of_sulfate_ambient_aerosol_particles_in_air + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_wet_deposition - - mass_concentration_of_dust_dry_aerosol_particles_in_air + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_turbulent_deposition - - tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_emission + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_gravitational_settling - - tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_dry_deposition @@ -33188,528 +33366,532 @@ mass_fraction_of_particulate_organic_matter_dry_aerosol_particles_in_air - - number_concentration_of_coarse_mode_ambient_aerosol_particles_in_air + + atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles - - sea_surface_wave_significant_height + + atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles - - tendency_of_atmosphere_moles_of_nitric_acid_trihydrate_ambient_aerosol_particles + + tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_emission + + + + tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_dry_deposition - - tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_dry_deposition + + net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_wood - - tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_wet_deposition + + net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_roots - - number_concentration_of_nucleation_mode_ambient_aerosol_particles_in_air + + net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_leaves - - number_concentration_of_ambient_aerosol_particles_in_air + + net_primary_productivity_of_biomass_expressed_as_carbon - - mole_fraction_of_nitric_acid_trihydrate_ambient_aerosol_particles_in_air + + gross_primary_productivity_of_biomass_expressed_as_carbon - - mass_fraction_of_dust_dry_aerosol_particles_in_air + + atmosphere_convective_available_potential_energy - - mass_concentration_of_water_in_ambient_aerosol_particles_in_air + + atmosphere_convective_available_potential_energy - - mass_concentration_of_nitrate_dry_aerosol_particles_in_air + + mass_concentration_of_chlorophyll_in_sea_water - - mass_concentration_of_particulate_organic_matter_dry_aerosol_particles_in_air + + mass_concentration_of_chlorophyll_in_sea_water - - mass_concentration_of_ammonium_dry_aerosol_particles_in_air + + omnidirectional_spherical_irradiance_per_unit_wavelength_in_sea_water - - atmosphere_mass_content_of_sulfate_ambient_aerosol_particles + + isotropic_radiance_per_unit_wavelength_in_air - - atmosphere_mass_content_of_sulfate_ambient_aerosol_particles + + isotropic_radiance_per_unit_wavelength_in_air - - atmosphere_mass_content_of_dust_dry_aerosol_particles + + land_ice_lwe_surface_specific_mass_balance_rate - - atmosphere_absorption_optical_thickness_due_to_ambient_aerosol_particles + + land_ice_surface_specific_mass_balance_rate - - atmosphere_mass_content_of_sulfate_dry_aerosol_particles + + tendency_of_atmosphere_mass_content_of_water_vapor_due_to_advection - - tendency_of_atmosphere_mass_content_of_water_vapor_due_to_turbulence + + equivalent_thickness_at_stp_of_atmosphere_ozone_content - - surface_upward_mole_flux_of_carbon_dioxide + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_industrial_processes_and_combustion - - surface_downward_mole_flux_of_carbon_dioxide + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_forest_fires - - atmosphere_mass_content_of_cloud_condensed_water + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production_and_emission - - northward_water_vapor_flux_in_air + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_due_to_net_chemical_production_and_emission - - lwe_stratiform_snowfall_rate + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_maritime_transport - - stratiform_snowfall_amount + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_energy_production_and_distribution - - stratiform_rainfall_rate + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_agricultural_waste_burning - - stratiform_rainfall_flux + + tendency_of_atmosphere_mass_content_of_particulate_organic_matter_dry_aerosol_particles_expressed_as_carbon_due_to_emission_from_land_transport - - stratiform_rainfall_amount + + tendency_of_atmosphere_mass_content_of_primary_particulate_organic_matter_dry_aerosol_particles_due_to_emission - - tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_emission + + 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_pm2p5_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_waste_treatment_and_disposal - - tendency_of_sea_surface_height_above_mean_sea_level + + 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_pm10_ambient_aerosol_particles_in_air + + tendency_of_atmosphere_mass_content_of_dust_dry_aerosol_particles_due_to_emission - - mass_fraction_of_pm10_ambient_aerosol_particles_in_air + + tendency_of_atmosphere_mass_content_of_sulfate_dry_aerosol_particles_due_to_emission - - mass_concentration_of_pm10_ambient_aerosol_particles_in_air + + tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_turbulence - - atmosphere_optical_thickness_due_to_pm10_ambient_aerosol_particles + + tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_shallow_convection - - surface_geostrophic_eastward_sea_water_velocity + + tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_deep_convection - - mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air + + atmosphere_net_upward_convective_mass_flux - - mass_fraction_of_pm2p5_ambient_aerosol_particles_in_air + + tendency_of_troposphere_moles_of_molecular_hydrogen - - mass_concentration_of_pm2p5_ambient_aerosol_particles_in_air + + tendency_of_troposphere_moles_of_methyl_chloride - - atmosphere_optical_thickness_due_to_pm2p5_ambient_aerosol_particles + + tendency_of_troposphere_moles_of_methyl_bromide - - mass_fraction_of_pm1_ambient_aerosol_particles_in_air + + tendency_of_troposphere_moles_of_methane - - mass_fraction_of_pm1_ambient_aerosol_particles_in_air + + tendency_of_troposphere_moles_of_carbon_monoxide - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition + + tendency_of_middle_atmosphere_moles_of_molecular_hydrogen - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_wet_deposition + + tendency_of_middle_atmosphere_moles_of_methyl_chloride - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling + + tendency_of_middle_atmosphere_moles_of_methyl_bromide - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_gravitational_settling + + tendency_of_middle_atmosphere_moles_of_methane - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition + + tendency_of_middle_atmosphere_moles_of_carbon_monoxide - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_turbulent_deposition + + tendency_of_atmosphere_moles_of_nitrous_oxide - - mass_concentration_of_pm1_ambient_aerosol_particles_in_air + + tendency_of_atmosphere_moles_of_molecular_hydrogen - - atmosphere_optical_thickness_due_to_pm1_ambient_aerosol_particles + + tendency_of_atmosphere_moles_of_methyl_chloride - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition + + tendency_of_atmosphere_moles_of_methyl_bromide - - tendency_of_atmosphere_mass_content_of_sea_salt_dry_aerosol_particles_due_to_dry_deposition + + y_wind - - tendency_of_atmosphere_mass_content_of_pm2p5_sea_salt_dry_aerosol_particles_due_to_wet_deposition + + x_wind - - tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_wet_deposition + + sea_water_y_velocity - - tendency_of_atmosphere_mass_content_of_pm10_sea_salt_dry_aerosol_particles_due_to_dry_deposition + + sea_water_x_velocity - - mass_fraction_of_sea_salt_dry_aerosol_particles_in_air + + mole_concentration_of_organic_detritus_expressed_as_silicon_in_sea_water - - mass_fraction_of_sea_salt_dry_aerosol_particles_in_air + + mole_concentration_of_organic_detritus_expressed_as_nitrogen_in_sea_water - - mass_concentration_of_sea_salt_dry_aerosol_particles_in_air + + mole_concentration_of_microzooplankton_expressed_as_nitrogen_in_sea_water - - mass_concentration_of_sea_salt_dry_aerosol_particles_in_air + + mole_concentration_of_mesozooplankton_expressed_as_nitrogen_in_sea_water - - atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles + + atmosphere_moles_of_nitrous_oxide - - atmosphere_optical_thickness_due_to_sea_salt_ambient_aerosol_particles + + atmosphere_moles_of_molecular_hydrogen - - atmosphere_mass_content_of_sea_salt_dry_aerosol_particles + + atmosphere_moles_of_methyl_chloride - - atmosphere_mass_content_of_sea_salt_dry_aerosol_particles + + atmosphere_moles_of_methyl_bromide - - surface_upward_sensible_heat_flux + + atmosphere_moles_of_methane - - surface_temperature + + atmosphere_moles_of_carbon_monoxide - - surface_temperature + + tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_convection - - surface_temperature + + tendency_of_mass_content_of_water_vapor_in_atmosphere_layer - - surface_net_downward_radiative_flux + + tendency_of_atmosphere_mass_content_of_water_vapor_due_to_turbulence - - wind_mixing_energy_flux_into_sea_water + + tendency_of_atmosphere_mass_content_of_water_vapor_due_to_shallow_convection - - water_flux_into_sea_water + + tendency_of_atmosphere_mass_content_of_water_vapor_due_to_deep_convection - - upward_eliassen_palm_flux_in_air + + tendency_of_atmosphere_mass_content_of_water_vapor_due_to_convection - - upward_eastward_momentum_flux_in_air_due_to_orographic_gravity_waves + + tendency_of_atmosphere_mass_content_of_water_vapor - - upward_eastward_momentum_flux_in_air_due_to_nonorographic_westward_gravity_waves + + tendency_of_atmosphere_mass_content_of_water_due_to_advection - - specific_gravitational_potential_energy + + mass_content_of_water_vapor_in_atmosphere_layer - - product_of_northward_wind_and_specific_humidity + + mass_content_of_water_in_atmosphere_layer - - mole_fraction_of_ozone_in_air + + mass_content_of_cloud_ice_in_atmosphere_layer - - isotropic_shortwave_radiance_in_air + + mass_content_of_cloud_condensed_water_in_atmosphere_layer - - isotropic_longwave_radiance_in_air + + lwe_thickness_of_atmosphere_mass_content_of_water_vapor - - mass_concentration_of_primary_particulate_organic_matter_dry_aerosol_particles_in_air + + change_over_time_in_atmosphere_mass_content_of_water_due_to_advection - - atmosphere_mass_content_of_ammonium_dry_aerosol_particles + + change_over_time_in_atmosphere_mass_content_of_water_due_to_advection - - stratiform_snowfall_flux + + atmosphere_mass_content_of_sulfate - - thickness_of_stratiform_rainfall_amount + + atmosphere_mass_content_of_sulfate - - sea_surface_wind_wave_period + + surface_upward_mole_flux_of_carbon_dioxide - - omnidirectional_spherical_irradiance_per_unit_wavelength_in_sea_water + + surface_downward_mole_flux_of_carbon_dioxide - - tendency_of_middle_atmosphere_moles_of_molecular_hydrogen + + atmosphere_mass_content_of_water_vapor - - tendency_of_middle_atmosphere_moles_of_methyl_chloride + + atmosphere_mass_content_of_convective_cloud_condensed_water - - tendency_of_middle_atmosphere_moles_of_methane + + atmosphere_mass_content_of_cloud_ice - - sea_water_y_velocity + + atmosphere_mass_content_of_cloud_condensed_water - - sea_water_x_velocity + + thickness_of_stratiform_snowfall_amount - - mole_fraction_of_hypochlorous_acid_in_air + + thickness_of_stratiform_rainfall_amount - - tendency_of_troposphere_moles_of_molecular_hydrogen + + stratiform_snowfall_flux - - tendency_of_troposphere_moles_of_methyl_chloride + + stratiform_snowfall_amount - - mass_content_of_water_vapor_in_atmosphere_layer + + stratiform_rainfall_rate - - mass_content_of_water_in_atmosphere_layer + + stratiform_rainfall_flux - - tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_turbulence + + stratiform_rainfall_amount - - tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_deep_convection + + northward_water_vapor_flux_in_air - - tendency_of_troposphere_moles_of_methyl_bromide + + lwe_thickness_of_stratiform_snowfall_amount - - tendency_of_mass_content_of_water_vapor_in_atmosphere_layer_due_to_convection + + lwe_stratiform_snowfall_rate - - tendency_of_atmosphere_mass_content_of_water_vapor_due_to_shallow_convection + + kinetic_energy_dissipation_in_atmosphere_boundary_layer - - radiation_wavelength + + eastward_water_vapor_flux_in_air - - tendency_of_troposphere_moles_of_methane + + surface_upward_sensible_heat_flux - - tendency_of_atmosphere_mass_content_of_water_due_to_advection + + surface_temperature - - mole_fraction_of_chlorine_monoxide_in_air + + surface_temperature - - mole_fraction_of_chlorine_dioxide_in_air + + surface_temperature - - mass_fraction_of_ozone_in_air + + surface_net_downward_radiative_flux - - mass_fraction_of_convective_cloud_condensed_water_in_air + + mole_fraction_of_hypochlorous_acid_in_air - - sea_surface_swell_wave_period + + mole_fraction_of_chlorine_monoxide_in_air - - surface_drag_coefficient_in_air + + mole_fraction_of_chlorine_dioxide_in_air - - mass_content_of_cloud_condensed_water_in_atmosphere_layer + + wind_mixing_energy_flux_into_sea_water - - mole_concentration_of_organic_detritus_expressed_as_silicon_in_sea_water + + water_flux_into_sea_water - - mole_concentration_of_organic_detritus_expressed_as_nitrogen_in_sea_water + + upward_eastward_momentum_flux_in_air_due_to_orographic_gravity_waves - - y_wind + + upward_eastward_momentum_flux_in_air_due_to_nonorographic_westward_gravity_waves - - kinetic_energy_dissipation_in_atmosphere_boundary_layer + + upward_eastward_momentum_flux_in_air_due_to_nonorographic_eastward_gravity_waves - - mass_concentration_of_suspended_matter_in_sea_water + + upward_eliassen_palm_flux_in_air - - x_wind + + northward_heat_flux_in_air_due_to_eddy_advection - - isotropic_radiance_per_unit_wavelength_in_air + + northward_eliassen_palm_flux_in_air - - isotropic_radiance_per_unit_wavelength_in_air + + wave_frequency - - atmosphere_moles_of_nitrous_oxide + + sea_surface_wind_wave_period - - atmosphere_moles_of_molecular_hydrogen + + sea_surface_swell_wave_period - - net_primary_productivity_of_biomass_expressed_as_carbon_accumulated_in_roots + + mass_concentration_of_suspended_matter_in_sea_water - - atmosphere_moles_of_methyl_chloride + + surface_drag_coefficient_in_air - - land_ice_surface_specific_mass_balance_rate + + surface_drag_coefficient_for_momentum_in_air - - land_ice_lwe_surface_specific_mass_balance_rate + + surface_drag_coefficient_for_heat_in_air - - tendency_of_atmosphere_moles_of_molecular_hydrogen + + specific_gravitational_potential_energy - - atmosphere_moles_of_carbon_monoxide + + radiation_wavelength - - tendency_of_atmosphere_moles_of_methyl_chloride + + product_of_northward_wind_and_specific_humidity - - surface_drag_coefficient_for_momentum_in_air + + mole_fraction_of_ozone_in_air - - surface_drag_coefficient_for_heat_in_air + + isotropic_shortwave_radiance_in_air - - leaf_mass_content_of_carbon + + isotropic_longwave_radiance_in_air - - mass_concentration_of_chlorophyll_in_sea_water + + mass_fraction_of_ozone_in_air - - mass_concentration_of_chlorophyll_in_sea_water + + mass_fraction_of_convective_cloud_condensed_water_in_air diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index 7442ff1173..b944f9b22f 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -97,19 +97,23 @@ def callback(cube, field, filename): import threading import iris._constraints -from iris._deprecation import IrisDeprecation, warn_deprecated import iris.config import iris.io +from ._deprecation import IrisDeprecation, warn_deprecated + +try: + from ._version import version as __version__ # noqa: F401 +except ModuleNotFoundError: + __version__ = "unknown" + + try: import iris_sample_data except ImportError: iris_sample_data = None -# Iris revision. -__version__ = "3.3.dev0" - # Restrict the names imported when using "from iris import *" __all__ = [ "AttributeConstraint", diff --git a/lib/iris/_representation/cube_printout.py b/lib/iris/_representation/cube_printout.py index b0b569512d..ea32fc5126 100644 --- a/lib/iris/_representation/cube_printout.py +++ b/lib/iris/_representation/cube_printout.py @@ -260,7 +260,10 @@ def add_scalar_row(name, value=""): elif title in ("attributes:", "cell methods:", "mesh:"): for title, value in zip(sect.names, sect.values): add_scalar_row(title, value) - elif title == "scalar cell measures:": + elif title in ( + "scalar ancillary variables:", + "scalar cell measures:", + ): # These are just strings: nothing in the 'value' column. for name in sect.contents: add_scalar_row(name) diff --git a/lib/iris/_representation/cube_summary.py b/lib/iris/_representation/cube_summary.py index 885de9acf3..6b0d4cf0f3 100644 --- a/lib/iris/_representation/cube_summary.py +++ b/lib/iris/_representation/cube_summary.py @@ -219,6 +219,12 @@ def __init__(self, title, cell_measures): self.contents = [cm.name() for cm in cell_measures] +class ScalarAncillaryVariableSection(Section): + def __init__(self, title, ancillary_variables): + self.title = title + self.contents = [av.name() for av in ancillary_variables] + + class AttributeSection(Section): def __init__(self, title, attributes): self.title = title @@ -274,7 +280,7 @@ class CubeSummary: """ - def __init__(self, cube, shorten=False, name_padding=35): + def __init__(self, cube, name_padding=35): self.header = FullHeader(cube, name_padding) # Cache the derived coords so we can rely on consistent @@ -314,13 +320,23 @@ def __init__(self, cube, shorten=False, name_padding=35): if id(coord) not in scalar_coord_ids ] - # cell measures - vector_cell_measures = [ - cm for cm in cube.cell_measures() if cm.shape != (1,) - ] - # Ancillary Variables - vector_ancillary_variables = [av for av in cube.ancillary_variables()] + vector_ancillary_variables = [] + scalar_ancillary_variables = [] + for av, av_dims in cube._ancillary_variables_and_dims: + if av_dims: + vector_ancillary_variables.append(av) + else: + scalar_ancillary_variables.append(av) + + # Cell Measures + vector_cell_measures = [] + scalar_cell_measures = [] + for cm, cm_dims in cube._cell_measures_and_dims: + if cm_dims: + vector_cell_measures.append(cm) + else: + scalar_cell_measures.append(cm) # Sort scalar coordinates by name. scalar_coords.sort(key=lambda coord: coord.name()) @@ -334,9 +350,6 @@ def __init__(self, cube, shorten=False, name_padding=35): vector_derived_coords.sort( key=lambda coord: (cube.coord_dims(coord), coord.name()) ) - scalar_cell_measures = [ - cm for cm in cube.cell_measures() if cm.shape == (1,) - ] self.vector_sections = {} @@ -369,6 +382,11 @@ def add_scalar_section(section_class, title, *args): "Scalar cell measures:", scalar_cell_measures, ) + add_scalar_section( + ScalarAncillaryVariableSection, + "Scalar ancillary variables:", + scalar_ancillary_variables, + ) add_scalar_section( CellMethodSection, "Cell methods:", cube.cell_methods ) diff --git a/lib/iris/analysis/__init__.py b/lib/iris/analysis/__init__.py index 25697266fa..11810f2901 100644 --- a/lib/iris/analysis/__init__.py +++ b/lib/iris/analysis/__init__.py @@ -1499,18 +1499,21 @@ def _weighted_percentile( return result -@_build_dask_mdtol_function -def _lazy_count(array, **kwargs): - array = iris._lazy_data.as_lazy_data(array) +def _count(array, **kwargs): + """ + Counts the number of points along the axis that satisfy the condition + specified by ``function``. Uses Dask's support for NEP13/18 to work as + either a lazy or a real function. + + """ func = kwargs.pop("function", None) if not callable(func): emsg = "function must be a callable. Got {}." raise TypeError(emsg.format(type(func))) - return da.sum(func(array), **kwargs) + return np.sum(func(array), **kwargs) def _proportion(array, function, axis, **kwargs): - count = iris._lazy_data.non_lazy(_lazy_count) # if the incoming array is masked use that to count the total number of # values if ma.isMaskedArray(array): @@ -1521,7 +1524,7 @@ def _proportion(array, function, axis, **kwargs): # case pass the array shape instead of the mask: total_non_masked = array.shape[axis] else: - total_non_masked = count( + total_non_masked = _count( array.mask, axis=axis, function=np.logical_not, **kwargs ) total_non_masked = ma.masked_equal(total_non_masked, 0) @@ -1534,7 +1537,7 @@ def _proportion(array, function, axis, **kwargs): # a dtype for its data that is different to the dtype of the fill-value, # which can cause issues outside this function. # Reference - tests/unit/analyis/test_PROPORTION.py Test_masked.test_ma - numerator = count(array, axis=axis, function=function, **kwargs) + numerator = _count(array, axis=axis, function=function, **kwargs) result = ma.asarray(numerator / total_non_masked) return result @@ -1604,23 +1607,33 @@ def _lazy_rms(array, axis, **kwargs): return da.sqrt(da.mean(array**2, axis=axis, **kwargs)) -@_build_dask_mdtol_function -def _lazy_sum(array, **kwargs): - array = iris._lazy_data.as_lazy_data(array) - # weighted or scaled sum +def _sum(array, **kwargs): + """ + Weighted or scaled sum. Uses Dask's support for NEP13/18 to work as either + a lazy or a real function. + + """ axis_in = kwargs.get("axis", None) weights_in = kwargs.pop("weights", None) returned_in = kwargs.pop("returned", False) if weights_in is not None: - wsum = da.sum(weights_in * array, **kwargs) + wsum = np.sum(weights_in * array, **kwargs) else: - wsum = da.sum(array, **kwargs) + wsum = np.sum(array, **kwargs) if returned_in: + al = da if iris._lazy_data.is_lazy_data(array) else np if weights_in is None: - weights = iris._lazy_data.as_lazy_data(np.ones_like(array)) + weights = al.ones_like(array) + if al is da: + # Dask version of ones_like does not preserve masks. See dask#9301. + weights = da.ma.masked_array( + weights, da.ma.getmaskarray(array) + ) else: - weights = weights_in - rvalue = (wsum, da.sum(weights, axis=axis_in)) + weights = al.ma.masked_array( + weights_in, mask=al.ma.getmaskarray(array) + ) + rvalue = (wsum, np.sum(weights, axis=axis_in)) else: rvalue = wsum return rvalue @@ -1740,9 +1753,9 @@ def interp_order(length): # COUNT = Aggregator( "count", - iris._lazy_data.non_lazy(_lazy_count), + _count, units_func=lambda units: 1, - lazy_func=_lazy_count, + lazy_func=_build_dask_mdtol_function(_count), ) """ An :class:`~iris.analysis.Aggregator` instance that counts the number @@ -1975,31 +1988,29 @@ def interp_order(length): A :class:`~iris.analysis.PercentileAggregator` instance that calculates the percentile over a :class:`~iris.cube.Cube`, as computed by :func:`scipy.stats.mstats.mquantiles` (default) or :func:`numpy.percentile` (if -fast_percentile_method is True). +``fast_percentile_method`` is True). -**Required** kwargs associated with the use of this aggregator: +Parameters +---------- percent : float or sequence of floats Percentile rank/s at which to extract value/s. -Additional kwargs associated with the use of this aggregator: - -alphap : float +alphap : float, default=1 Plotting positions parameter, see :func:`scipy.stats.mstats.mquantiles`. - Defaults to 1. -betap : float +betap : float, default=1 Plotting positions parameter, see :func:`scipy.stats.mstats.mquantiles`. - Defaults to 1. -fast_percentile_method : bool +fast_percentile_method : bool, default=False When set to True, uses :func:`numpy.percentile` method as a faster alternative to the :func:`scipy.stats.mstats.mquantiles` method. An exception is raised if the data are masked and the missing data tolerance - is not 0. Defaults to False. + is not 0. -kwargs : dict, optional +**kwargs : dict, optional Passed to :func:`scipy.stats.mstats.mquantiles` or :func:`numpy.percentile`. -**For example**: +Example +------- To compute the 10th and 90th percentile over *time*:: @@ -2116,8 +2127,8 @@ def interp_order(length): SUM = WeightedAggregator( "sum", - iris._lazy_data.non_lazy(_lazy_sum), - lazy_func=_build_dask_mdtol_function(_lazy_sum), + _sum, + lazy_func=_build_dask_mdtol_function(_sum), ) """ An :class:`~iris.analysis.Aggregator` instance that calculates diff --git a/lib/iris/analysis/cartography.py b/lib/iris/analysis/cartography.py index 44129ff175..f38e48354d 100644 --- a/lib/iris/analysis/cartography.py +++ b/lib/iris/analysis/cartography.py @@ -1008,8 +1008,8 @@ def _transform_distance_vectors_tolerance_mask( u_one_t, v_zero_t = _transform_distance_vectors(ones, zeros, ds, dx2, dy2) u_zero_t, v_one_t = _transform_distance_vectors(zeros, ones, ds, dx2, dy2) # Squared magnitudes should be equal to one within acceptable tolerance. - # A value of atol=2e-3 is used, which corresponds to a change in magnitude - # of approximately 0.1%. + # A value of atol=2e-3 is used, which masks any magnitude changes >0.5% + # (approx percentage - based on experimenting). sqmag_1_0 = u_one_t**2 + v_zero_t**2 sqmag_0_1 = u_zero_t**2 + v_one_t**2 mask = np.logical_not( diff --git a/lib/iris/analysis/maths.py b/lib/iris/analysis/maths.py index 1cbc90cc60..468847bca2 100644 --- a/lib/iris/analysis/maths.py +++ b/lib/iris/analysis/maths.py @@ -774,6 +774,7 @@ def _binary_op_common( new_dtype=None, dim=None, in_place=False, + sanitise_metadata=True, ): """ Function which shares common code between binary operations. @@ -792,6 +793,8 @@ def _binary_op_common( coordinate that is not found in `cube` in_place - whether or not to apply the operation in place to `cube` and `cube.data` + sanitise_metadata - whether or not to remove metadata using + _sanitise_metadata function """ from iris.cube import Cube @@ -837,6 +840,20 @@ def unary_func(lhs): raise TypeError(emsg) return data + if in_place and not cube.has_lazy_data(): + # In-place arithmetic doesn't work if array type of LHS is less complex + # than RHS. + if iris._lazy_data.is_lazy_data(rhs): + cube.data = cube.lazy_data() + elif ma.is_masked(rhs) and not isinstance(cube.data, ma.MaskedArray): + cube.data = ma.array(cube.data) + + elif isinstance( + cube.core_data(), ma.MaskedArray + ) and iris._lazy_data.is_lazy_data(rhs): + # Workaround for #2987. numpy#15200 discusses the general problem. + cube = cube.copy(cube.lazy_data()) + result = _math_op_common( cube, unary_func, @@ -844,13 +861,15 @@ def unary_func(lhs): new_dtype=new_dtype, in_place=in_place, skeleton_cube=skeleton_cube, + sanitise_metadata=sanitise_metadata, ) if isinstance(other, Cube): # Insert the resultant data from the maths operation # within the resolved cube. result = resolver.cube(result.core_data(), in_place=in_place) - _sanitise_metadata(result, new_unit) + if sanitise_metadata: + _sanitise_metadata(result, new_unit) return result @@ -932,6 +951,7 @@ def _math_op_common( new_dtype=None, in_place=False, skeleton_cube=False, + sanitise_metadata=True, ): from iris.cube import Cube @@ -965,7 +985,8 @@ def _math_op_common( ): new_cube.data = ma.masked_array(0, 1, dtype=new_dtype) - _sanitise_metadata(new_cube, new_unit) + if sanitise_metadata: + _sanitise_metadata(new_cube, new_unit) return new_cube diff --git a/lib/iris/common/metadata.py b/lib/iris/common/metadata.py index cb5f53f5f4..8ec39bb4b1 100644 --- a/lib/iris/common/metadata.py +++ b/lib/iris/common/metadata.py @@ -44,8 +44,6 @@ # https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_data_set_components.html#object_name -from ..util import guess_coord_axis - _TOKEN_PARSE = re.compile(r"""^[a-zA-Z0-9][\w\.\+\-@]*$""") # Configure the logger. @@ -1413,6 +1411,8 @@ def metadata_filter( to only those that matched the given criteria. """ + from ..util import guess_coord_axis + name = None obj = None diff --git a/lib/iris/coords.py b/lib/iris/coords.py index d176a0bb20..cfcdcd92a0 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -18,7 +18,6 @@ import warnings import zlib -import cftime import dask.array as da import numpy as np import numpy.ma as ma @@ -1345,7 +1344,14 @@ def __add__(self, mod): return Cell(point, bound) def __hash__(self): - return super().__hash__() + # See __eq__ for the definition of when two cells are equal. + if self.bound is None: + return hash(self.point) + bound = self.bound + rbound = bound[::-1] + if rbound < bound: + bound = rbound + return hash((self.point, bound)) def __eq__(self, other): """ @@ -1353,27 +1359,14 @@ def __eq__(self, other): compared. """ - - def nan_equality(x, y): - return ( - isinstance(x, (float, np.number)) - and np.isnan(x) - and isinstance(y, (float, np.number)) - and np.isnan(y) - ) - if isinstance(other, (int, float, np.number)) or hasattr( other, "timetuple" ): if self.bound is not None: return self.contains_point(other) - elif nan_equality(self.point, other): - return True else: return self.point == other elif isinstance(other, Cell): - if nan_equality(self.point, other.point): - return True return (self.point == other.point) and ( self.bound == other.bound or self.bound == other.bound[::-1] ) @@ -1424,16 +1417,6 @@ def __common_cmp__(self, other, operator_method): ): raise ValueError("Unexpected operator_method") - # Prevent silent errors resulting from missing cftime - # behaviour. - if isinstance(other, cftime.datetime) or ( - isinstance(self.point, cftime.datetime) - and not isinstance(other, iris.time.PartialDateTime) - ): - raise TypeError( - "Cannot determine the order of " "cftime.datetime objects" - ) - if isinstance(other, Cell): # Cell vs Cell comparison for providing a strict sort order if self.bound is None: @@ -1498,19 +1481,7 @@ def __common_cmp__(self, other, operator_method): else: me = max(self.bound) - # Work around to handle cftime.datetime comparison, which - # doesn't return NotImplemented on failure in some versions of the - # library - try: - result = operator_method(me, other) - except TypeError: - rop = { - operator.lt: operator.gt, - operator.gt: operator.lt, - operator.le: operator.ge, - operator.ge: operator.le, - }[operator_method] - result = rop(other, me) + result = operator_method(me, other) return result @@ -1908,7 +1879,22 @@ def cells(self): ... """ - return _CellIterator(self) + if self.ndim != 1: + raise iris.exceptions.CoordinateMultiDimError(self) + + points = self.points + bounds = self.bounds + if self.units.is_time_reference(): + points = self.units.num2date(points) + if self.has_bounds(): + bounds = self.units.num2date(bounds) + + if self.has_bounds(): + for point, bound in zip(points, bounds): + yield Cell(point, bound) + else: + for point in points: + yield Cell(point) def _sanity_check_bounds(self): if self.ndim == 1: @@ -2228,12 +2214,24 @@ def serialize(x): "Metadata may not be fully descriptive for {!r}." ) warnings.warn(msg.format(self.name())) - elif not self.is_contiguous(): - msg = ( - "Collapsing a non-contiguous coordinate. " - "Metadata may not be fully descriptive for {!r}." - ) - warnings.warn(msg.format(self.name())) + else: + try: + self._sanity_check_bounds() + except ValueError as exc: + msg = ( + "Cannot check if coordinate is contiguous: {} " + "Metadata may not be fully descriptive for {!r}. " + "Ignoring bounds." + ) + warnings.warn(msg.format(str(exc), self.name())) + self.bounds = None + else: + if not self.is_contiguous(): + msg = ( + "Collapsing a non-contiguous coordinate. " + "Metadata may not be fully descriptive for {!r}." + ) + warnings.warn(msg.format(self.name())) if self.has_bounds(): item = self.core_bounds() @@ -2383,18 +2381,16 @@ def intersect(self, other, return_indices=False): ) raise ValueError(msg) - # Cache self.cells for speed. We can also use the index operation on a - # list conveniently. - self_cells = [cell for cell in self.cells()] + # Cache self.cells for speed. We can also use the dict for fast index + # lookup. + self_cells = {cell: idx for idx, cell in enumerate(self.cells())} # Maintain a list of indices on self for which cells exist in both self # and other. self_intersect_indices = [] for cell in other.cells(): - try: - self_intersect_indices.append(self_cells.index(cell)) - except ValueError: - pass + if cell in self_cells: + self_intersect_indices.append(self_cells[cell]) if return_indices is False and self_intersect_indices == []: raise ValueError( @@ -3138,22 +3134,6 @@ def xml_element(self, doc): return cellMethod_xml_element -# See Coord.cells() for the description/context. -class _CellIterator(Iterator): - def __init__(self, coord): - self._coord = coord - if coord.ndim != 1: - raise iris.exceptions.CoordinateMultiDimError(coord) - self._indices = iter(range(coord.shape[0])) - - def __next__(self): - # NB. When self._indices runs out it will raise StopIteration for us. - i = next(self._indices) - return self._coord.cell(i) - - next = __next__ - - # See ExplicitCoord._group() for the description/context. class _GroupIterator(Iterator): def __init__(self, points): diff --git a/lib/iris/cube.py b/lib/iris/cube.py index e3bacf08fc..9779558506 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -185,6 +185,12 @@ def _assert_is_cube(obj): ) raise ValueError(msg) + def _repr_html_(self): + from iris.experimental.representation import CubeListRepresentation + + representer = CubeListRepresentation(self) + return representer.repr_html() + # TODO #370 Which operators need overloads? def __add__(self, other): @@ -1012,6 +1018,30 @@ def _names(self): """ return self._metadata_manager._names + def _dimensional_metadata(self, name_or_dimensional_metadata): + """ + Return a single _DimensionalMetadata instance that matches the given + name_or_dimensional_metadata. If one is not found, raise an error. + + """ + found_item = None + for cube_method in [ + self.coord, + self.cell_measure, + self.ancillary_variable, + ]: + try: + found_item = cube_method(name_or_dimensional_metadata) + if found_item: + break + except KeyError: + pass + if not found_item: + raise KeyError( + f"{name_or_dimensional_metadata} was not found in {self}." + ) + return found_item + def is_compatible(self, other, ignore=None): """ Return whether the cube is compatible with another. @@ -2269,10 +2299,23 @@ def cell_methods(self): return self._metadata_manager.cell_methods @cell_methods.setter - def cell_methods(self, cell_methods): - self._metadata_manager.cell_methods = ( - tuple(cell_methods) if cell_methods else tuple() - ) + def cell_methods(self, cell_methods: Iterable): + if not cell_methods: + # For backwards compatibility: Empty or null value is equivalent to (). + cell_methods = () + else: + # Can supply any iterable, which is converted (copied) to a tuple. + cell_methods = tuple(cell_methods) + for cell_method in cell_methods: + # All contents should be CellMethods. Requiring class membership is + # somewhat non-Pythonic, but simple, and not a problem for now. + if not isinstance(cell_method, iris.coords.CellMethod): + msg = ( + f"Cube.cell_methods assigned value includes {cell_method}, " + "which is not an iris.coords.CellMethod." + ) + raise ValueError(msg) + self._metadata_manager.cell_methods = cell_methods def core_data(self): """ @@ -4431,7 +4474,7 @@ def interpolate(self, sample_points, scheme, collapse_scalar=True): air_potential_temperature / (K) \ (time: 3; model_level_number: 7; grid_latitude: 204; grid_longitude: 187) >>> print(cube.coord('time')) - DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar) + DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [2009-11-19 10:00:00, 2009-11-19 11:00:00, 2009-11-19 12:00:00] shape: (3,) dtype: float64 @@ -4444,7 +4487,7 @@ def interpolate(self, sample_points, scheme, collapse_scalar=True): air_potential_temperature / (K) \ (model_level_number: 7; grid_latitude: 204; grid_longitude: 187) >>> print(result.coord('time')) - DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar) + DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [2009-11-19 10:30:00] shape: (1,) dtype: float64 @@ -4459,7 +4502,7 @@ def interpolate(self, sample_points, scheme, collapse_scalar=True): air_potential_temperature / (K) \ (model_level_number: 7; grid_latitude: 204; grid_longitude: 187) >>> print(result2.coord('time')) - DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar) + DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [2009-11-19 10:30:00] shape: (1,) dtype: float64 diff --git a/lib/iris/experimental/ugrid/load.py b/lib/iris/experimental/ugrid/load.py index 6c802e00d4..a522d91313 100644 --- a/lib/iris/experimental/ugrid/load.py +++ b/lib/iris/experimental/ugrid/load.py @@ -8,8 +8,7 @@ Extensions to Iris' NetCDF loading to allow the construction of :class:`~iris.experimental.ugrid.mesh.Mesh`\\ es from UGRID data in the file. -Eventual destination: :mod:`iris.fileformats.netcdf` (plan to split that module -into ``load`` and ``save`` in future). +Eventual destination: :mod:`iris.fileformats.netcdf`. """ from contextlib import contextmanager @@ -19,8 +18,8 @@ from ...config import get_logger from ...coords import AuxCoord -from ...fileformats import netcdf from ...fileformats._nc_load_rules.helpers import get_attr_units, get_names +from ...fileformats.netcdf import loader as nc_loader from ...io import decode_uri, expand_filespecs from ...util import guess_coord_axis from .cf import ( @@ -202,7 +201,7 @@ def load_meshes(uris, var_name=None): else: handling_format_spec = FORMAT_AGENT.get_spec(source, None) - if handling_format_spec.handler == netcdf.load_cubes: + if handling_format_spec.handler == nc_loader.load_cubes: valid_sources.append(source) else: message = f"Ignoring non-NetCDF file: {source}" @@ -239,7 +238,7 @@ def _build_aux_coord(coord_var, file_path): assert isinstance(coord_var, CFUGridAuxiliaryCoordinateVariable) attributes = {} attr_units = get_attr_units(coord_var, attributes) - points_data = netcdf._get_cf_var_data(coord_var, file_path) + points_data = nc_loader._get_cf_var_data(coord_var, file_path) # Bounds will not be loaded: # Bounds may be present, but the UGRID conventions state this would @@ -293,7 +292,7 @@ def _build_connectivity(connectivity_var, file_path, element_dims): assert isinstance(connectivity_var, CFUGridConnectivityVariable) attributes = {} attr_units = get_attr_units(connectivity_var, attributes) - indices_data = netcdf._get_cf_var_data(connectivity_var, file_path) + indices_data = nc_loader._get_cf_var_data(connectivity_var, file_path) cf_role = connectivity_var.cf_role start_index = connectivity_var.start_index @@ -462,7 +461,7 @@ def _build_mesh(cf, mesh_var, file_path): ) mesh_elements = filter(None, mesh_elements) for iris_object in mesh_elements: - netcdf._add_unused_attributes( + nc_loader._add_unused_attributes( iris_object, cf.cf_group[iris_object.var_name] ) diff --git a/lib/iris/experimental/ugrid/save.py b/lib/iris/experimental/ugrid/save.py index 8a5934b939..3c42137905 100644 --- a/lib/iris/experimental/ugrid/save.py +++ b/lib/iris/experimental/ugrid/save.py @@ -8,8 +8,7 @@ Extensions to Iris' NetCDF saving to allow :class:`~iris.experimental.ugrid.mesh.Mesh` saving in UGRID format. -Eventual destination: :mod:`iris.fileformats.netcdf` (plan to split that module -into ``load`` and ``save`` in future). +Eventual destination: :mod:`iris.fileformats.netcdf`. """ from collections.abc import Iterable diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index d50d3f324a..c075a659ac 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -31,9 +31,9 @@ import iris.fileformats.netcdf from iris.fileformats.netcdf import ( UnknownCellMethodWarning, - _get_cf_var_data, parse_cell_methods, ) +from iris.fileformats.netcdf.loader import _get_cf_var_data import iris.std_names import iris.util diff --git a/lib/iris/fileformats/name_loaders.py b/lib/iris/fileformats/name_loaders.py index 34e88aff80..d15a3717d0 100644 --- a/lib/iris/fileformats/name_loaders.py +++ b/lib/iris/fileformats/name_loaders.py @@ -456,7 +456,7 @@ def _generate_cubes( # Define the time unit and use it to serialise the datetime for # the time coordinate. time_unit = cf_units.Unit( - "hours since epoch", calendar=cf_units.CALENDAR_GREGORIAN + "hours since epoch", calendar=cf_units.CALENDAR_STANDARD ) # Build time, height, latitude and longitude coordinates. @@ -571,7 +571,9 @@ def _generate_cubes( cube.attributes[key] = value if cell_methods is not None: - cube.add_cell_method(cell_methods[i]) + cell_method = cell_methods[i] + if cell_method is not None: + cube.add_cell_method(cell_method) yield cube @@ -610,7 +612,7 @@ def _build_cell_methods(av_or_ints, coord): cell_method = None msg = "Unknown {} statistic: {!r}. Unable to create cell method." warnings.warn(msg.format(coord, av_or_int)) - cell_methods.append(cell_method) + cell_methods.append(cell_method) # NOTE: this can be a None return cell_methods @@ -1212,7 +1214,7 @@ def load_NAMEIII_trajectory(filename): """ time_unit = cf_units.Unit( - "hours since epoch", calendar=cf_units.CALENDAR_GREGORIAN + "hours since epoch", calendar=cf_units.CALENDAR_STANDARD ) with open(filename, "r") as infile: diff --git a/lib/iris/fileformats/netcdf/__init__.py b/lib/iris/fileformats/netcdf/__init__.py new file mode 100644 index 0000000000..505e173b0b --- /dev/null +++ b/lib/iris/fileformats/netcdf/__init__.py @@ -0,0 +1,49 @@ +# 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. +""" +Module to support the loading and saving of NetCDF files, also using the CF conventions +for metadata interpretation. + +See : `NetCDF User's Guide `_ +and `netCDF4 python module `_. + +Also : `CF Conventions `_. + +""" +import iris.config + +# Note: *must* be done before importing from submodules, as they also use this ! +logger = iris.config.get_logger(__name__) + +from .loader import DEBUG, NetCDFDataProxy, load_cubes +from .saver import ( + CF_CONVENTIONS_VERSION, + MESH_ELEMENTS, + SPATIO_TEMPORAL_AXES, + CFNameCoordMap, + Saver, + UnknownCellMethodWarning, + parse_cell_methods, + save, +) + +# Export all public elements from the loader and saver submodules. +# NOTE: the separation is purely for neatness and developer convenience; from +# the user point of view, it is still all one module. +__all__ = ( + "CFNameCoordMap", + "CF_CONVENTIONS_VERSION", + "DEBUG", + "MESH_ELEMENTS", + "NetCDFDataProxy", + "SPATIO_TEMPORAL_AXES", + "Saver", + "UnknownCellMethodWarning", + "load_cubes", + "logger", + "parse_cell_methods", + "save", +) diff --git a/lib/iris/fileformats/netcdf/loader.py b/lib/iris/fileformats/netcdf/loader.py new file mode 100644 index 0000000000..95f394c70d --- /dev/null +++ b/lib/iris/fileformats/netcdf/loader.py @@ -0,0 +1,594 @@ +# 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. +""" +Module to support the loading of Iris cubes from NetCDF files, also using the CF +conventions for metadata interpretation. + +See : `NetCDF User's Guide `_ +and `netCDF4 python module `_. + +Also : `CF Conventions `_. + +""" +import warnings + +import netCDF4 +import numpy as np + +from iris._lazy_data import as_lazy_data +from iris.aux_factory import ( + AtmosphereSigmaFactory, + HybridHeightFactory, + HybridPressureFactory, + OceanSFactory, + OceanSg1Factory, + OceanSg2Factory, + OceanSigmaFactory, + OceanSigmaZFactory, +) +import iris.config +import iris.coord_systems +import iris.coords +import iris.exceptions +import iris.fileformats.cf +from iris.fileformats.netcdf.saver import _CF_ATTRS +import iris.io +import iris.util + +# Show actions activation statistics. +DEBUG = False + +# Get the logger : shared logger for all in 'iris.fileformats.netcdf'. +from . import logger + + +def _actions_engine(): + # Return an 'actions engine', which provides a pyke-rules-like interface to + # the core cf translation code. + # Deferred import to avoid circularity. + import iris.fileformats._nc_load_rules.engine as nc_actions_engine + + engine = nc_actions_engine.Engine() + return engine + + +class NetCDFDataProxy: + """A reference to the data payload of a single NetCDF file variable.""" + + __slots__ = ("shape", "dtype", "path", "variable_name", "fill_value") + + def __init__(self, shape, dtype, path, variable_name, fill_value): + self.shape = shape + self.dtype = dtype + self.path = path + self.variable_name = variable_name + self.fill_value = fill_value + + @property + def ndim(self): + return len(self.shape) + + def __getitem__(self, keys): + dataset = netCDF4.Dataset(self.path) + try: + variable = dataset.variables[self.variable_name] + # Get the NetCDF variable data and slice. + var = variable[keys] + finally: + dataset.close() + return np.asanyarray(var) + + def __repr__(self): + fmt = ( + "<{self.__class__.__name__} shape={self.shape}" + " dtype={self.dtype!r} path={self.path!r}" + " variable_name={self.variable_name!r}>" + ) + return fmt.format(self=self) + + def __getstate__(self): + return {attr: getattr(self, attr) for attr in self.__slots__} + + def __setstate__(self, state): + for key, value in state.items(): + setattr(self, key, value) + + +def _assert_case_specific_facts(engine, cf, cf_group): + # Initialise a data store for built cube elements. + # This is used to patch element attributes *not* setup by the actions + # process, after the actions code has run. + engine.cube_parts["coordinates"] = [] + engine.cube_parts["cell_measures"] = [] + engine.cube_parts["ancillary_variables"] = [] + + # Assert facts for CF coordinates. + for cf_name in cf_group.coordinates.keys(): + engine.add_case_specific_fact("coordinate", (cf_name,)) + + # Assert facts for CF auxiliary coordinates. + for cf_name in cf_group.auxiliary_coordinates.keys(): + engine.add_case_specific_fact("auxiliary_coordinate", (cf_name,)) + + # Assert facts for CF cell measures. + for cf_name in cf_group.cell_measures.keys(): + engine.add_case_specific_fact("cell_measure", (cf_name,)) + + # Assert facts for CF ancillary variables. + for cf_name in cf_group.ancillary_variables.keys(): + engine.add_case_specific_fact("ancillary_variable", (cf_name,)) + + # Assert facts for CF grid_mappings. + for cf_name in cf_group.grid_mappings.keys(): + engine.add_case_specific_fact("grid_mapping", (cf_name,)) + + # Assert facts for CF labels. + for cf_name in cf_group.labels.keys(): + engine.add_case_specific_fact("label", (cf_name,)) + + # Assert facts for CF formula terms associated with the cf_group + # of the CF data variable. + + # Collect varnames of formula-root variables as we go. + # NOTE: use dictionary keys as an 'OrderedSet' + # - see: https://stackoverflow.com/a/53657523/2615050 + # This is to ensure that we can handle the resulting facts in a definite + # order, as using a 'set' led to indeterminate results. + formula_root = {} + for cf_var in cf.cf_group.formula_terms.values(): + for cf_root, cf_term in cf_var.cf_terms_by_root.items(): + # Only assert this fact if the formula root variable is + # defined in the CF group of the CF data variable. + if cf_root in cf_group: + formula_root[cf_root] = True + engine.add_case_specific_fact( + "formula_term", + (cf_var.cf_name, cf_root, cf_term), + ) + + for cf_root in formula_root.keys(): + engine.add_case_specific_fact("formula_root", (cf_root,)) + + +def _actions_activation_stats(engine, cf_name): + print("-" * 80) + print("CF Data Variable: %r" % cf_name) + + engine.print_stats() + + print("Rules Triggered:") + + for rule in sorted(list(engine.rules_triggered)): + print("\t%s" % rule) + + print("Case Specific Facts:") + kb_facts = engine.get_kb() + + for key in kb_facts.entity_lists.keys(): + for arg in kb_facts.entity_lists[key].case_specific_facts: + print("\t%s%s" % (key, arg)) + + +def _set_attributes(attributes, key, value): + """Set attributes dictionary, converting unicode strings appropriately.""" + + if isinstance(value, str): + try: + attributes[str(key)] = str(value) + except UnicodeEncodeError: + attributes[str(key)] = value + else: + attributes[str(key)] = value + + +def _add_unused_attributes(iris_object, cf_var): + """ + Populate the attributes of a cf element with the "unused" attributes + from the associated CF-netCDF variable. That is, all those that aren't CF + reserved terms. + + """ + + def attribute_predicate(item): + return item[0] not in _CF_ATTRS + + tmpvar = filter(attribute_predicate, cf_var.cf_attrs_unused()) + for attr_name, attr_value in tmpvar: + _set_attributes(iris_object.attributes, attr_name, attr_value) + + +def _get_actual_dtype(cf_var): + # Figure out what the eventual data type will be after any scale/offset + # transforms. + dummy_data = np.zeros(1, dtype=cf_var.dtype) + if hasattr(cf_var, "scale_factor"): + dummy_data = cf_var.scale_factor * dummy_data + if hasattr(cf_var, "add_offset"): + dummy_data = cf_var.add_offset + dummy_data + return dummy_data.dtype + + +def _get_cf_var_data(cf_var, filename): + # Get lazy chunked data out of a cf variable. + dtype = _get_actual_dtype(cf_var) + + # Create cube with deferred data, but no metadata + fill_value = getattr( + cf_var.cf_data, + "_FillValue", + netCDF4.default_fillvals[cf_var.dtype.str[1:]], + ) + proxy = NetCDFDataProxy( + cf_var.shape, dtype, filename, cf_var.cf_name, fill_value + ) + # Get the chunking specified for the variable : this is either a shape, or + # maybe the string "contiguous". + chunks = cf_var.cf_data.chunking() + # In the "contiguous" case, pass chunks=None to 'as_lazy_data'. + if chunks == "contiguous": + chunks = None + return as_lazy_data(proxy, chunks=chunks) + + +class _OrderedAddableList(list): + """ + A custom container object for actions recording. + + Used purely in actions debugging, to accumulate a record of which actions + were activated. + + It replaces a set, so as to preserve the ordering of operations, with + possible repeats, and it also numbers the entries. + + The actions routines invoke an 'add' method, so this effectively replaces + a set.add with a list.append. + + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._n_add = 0 + + def add(self, msg): + self._n_add += 1 + n_add = self._n_add + self.append(f"#{n_add:03d} : {msg}") + + +def _load_cube(engine, cf, cf_var, filename): + from iris.cube import Cube + + """Create the cube associated with the CF-netCDF data variable.""" + data = _get_cf_var_data(cf_var, filename) + cube = Cube(data) + + # Reset the actions engine. + engine.reset() + + # Initialise engine rule processing hooks. + engine.cf_var = cf_var + engine.cube = cube + engine.cube_parts = {} + engine.requires = {} + engine.rules_triggered = _OrderedAddableList() + engine.filename = filename + + # Assert all the case-specific facts. + # This extracts 'facts' specific to this data-variable (aka cube), from + # the info supplied in the CFGroup object. + _assert_case_specific_facts(engine, cf, cf_var.cf_group) + + # Run the actions engine. + # This creates various cube elements and attaches them to the cube. + # It also records various other info on the engine, to be processed later. + engine.activate() + + # Having run the rules, now add the "unused" attributes to each cf element. + def fix_attributes_all_elements(role_name): + elements_and_names = engine.cube_parts.get(role_name, []) + + for iris_object, cf_var_name in elements_and_names: + _add_unused_attributes(iris_object, cf.cf_group[cf_var_name]) + + # Populate the attributes of all coordinates, cell-measures and ancillary-vars. + fix_attributes_all_elements("coordinates") + fix_attributes_all_elements("ancillary_variables") + fix_attributes_all_elements("cell_measures") + + # Also populate attributes of the top-level cube itself. + _add_unused_attributes(cube, cf_var) + + # Work out reference names for all the coords. + names = { + coord.var_name: coord.standard_name or coord.var_name or "unknown" + for coord in cube.coords() + } + + # Add all the cube cell methods. + cube.cell_methods = [ + iris.coords.CellMethod( + method=method.method, + intervals=method.intervals, + comments=method.comments, + coords=[ + names[coord_name] if coord_name in names else coord_name + for coord_name in method.coord_names + ], + ) + for method in cube.cell_methods + ] + + if DEBUG: + # Show activation statistics for this data-var (i.e. cube). + _actions_activation_stats(engine, cf_var.cf_name) + + return cube + + +def _load_aux_factory(engine, cube): + """ + Convert any CF-netCDF dimensionless coordinate to an AuxCoordFactory. + + """ + formula_type = engine.requires.get("formula_type") + if formula_type in [ + "atmosphere_sigma_coordinate", + "atmosphere_hybrid_height_coordinate", + "atmosphere_hybrid_sigma_pressure_coordinate", + "ocean_sigma_z_coordinate", + "ocean_sigma_coordinate", + "ocean_s_coordinate", + "ocean_s_coordinate_g1", + "ocean_s_coordinate_g2", + ]: + + def coord_from_term(term): + # Convert term names to coordinates (via netCDF variable names). + name = engine.requires["formula_terms"].get(term, None) + if name is not None: + for coord, cf_var_name in engine.cube_parts["coordinates"]: + if cf_var_name == name: + return coord + warnings.warn( + "Unable to find coordinate for variable " + "{!r}".format(name) + ) + + if formula_type == "atmosphere_sigma_coordinate": + pressure_at_top = coord_from_term("ptop") + sigma = coord_from_term("sigma") + surface_air_pressure = coord_from_term("ps") + factory = AtmosphereSigmaFactory( + pressure_at_top, sigma, surface_air_pressure + ) + elif formula_type == "atmosphere_hybrid_height_coordinate": + delta = coord_from_term("a") + sigma = coord_from_term("b") + orography = coord_from_term("orog") + factory = HybridHeightFactory(delta, sigma, orography) + elif formula_type == "atmosphere_hybrid_sigma_pressure_coordinate": + # Hybrid pressure has two valid versions of its formula terms: + # "p0: var1 a: var2 b: var3 ps: var4" or + # "ap: var1 b: var2 ps: var3" where "ap = p0 * a" + # Attempt to get the "ap" term. + delta = coord_from_term("ap") + if delta is None: + # The "ap" term is unavailable, so try getting terms "p0" + # and "a" terms in order to derive an "ap" equivalent term. + coord_p0 = coord_from_term("p0") + if coord_p0 is not None: + if coord_p0.shape != (1,): + msg = ( + "Expecting {!r} to be a scalar reference " + "pressure coordinate, got shape {!r}".format( + coord_p0.var_name, coord_p0.shape + ) + ) + raise ValueError(msg) + if coord_p0.has_bounds(): + msg = ( + "Ignoring atmosphere hybrid sigma pressure " + "scalar coordinate {!r} bounds.".format( + coord_p0.name() + ) + ) + warnings.warn(msg) + coord_a = coord_from_term("a") + if coord_a is not None: + if coord_a.units.is_unknown(): + # Be graceful, and promote unknown to dimensionless units. + coord_a.units = "1" + delta = coord_a * coord_p0.points[0] + delta.units = coord_a.units * coord_p0.units + delta.rename("vertical pressure") + delta.var_name = "ap" + cube.add_aux_coord(delta, cube.coord_dims(coord_a)) + + sigma = coord_from_term("b") + surface_air_pressure = coord_from_term("ps") + factory = HybridPressureFactory(delta, sigma, surface_air_pressure) + elif formula_type == "ocean_sigma_z_coordinate": + sigma = coord_from_term("sigma") + eta = coord_from_term("eta") + depth = coord_from_term("depth") + depth_c = coord_from_term("depth_c") + nsigma = coord_from_term("nsigma") + zlev = coord_from_term("zlev") + factory = OceanSigmaZFactory( + sigma, eta, depth, depth_c, nsigma, zlev + ) + elif formula_type == "ocean_sigma_coordinate": + sigma = coord_from_term("sigma") + eta = coord_from_term("eta") + depth = coord_from_term("depth") + factory = OceanSigmaFactory(sigma, eta, depth) + elif formula_type == "ocean_s_coordinate": + s = coord_from_term("s") + eta = coord_from_term("eta") + depth = coord_from_term("depth") + a = coord_from_term("a") + depth_c = coord_from_term("depth_c") + b = coord_from_term("b") + factory = OceanSFactory(s, eta, depth, a, b, depth_c) + elif formula_type == "ocean_s_coordinate_g1": + s = coord_from_term("s") + c = coord_from_term("c") + eta = coord_from_term("eta") + depth = coord_from_term("depth") + depth_c = coord_from_term("depth_c") + factory = OceanSg1Factory(s, c, eta, depth, depth_c) + elif formula_type == "ocean_s_coordinate_g2": + s = coord_from_term("s") + c = coord_from_term("c") + eta = coord_from_term("eta") + depth = coord_from_term("depth") + depth_c = coord_from_term("depth_c") + factory = OceanSg2Factory(s, c, eta, depth, depth_c) + cube.add_aux_factory(factory) + + +def _translate_constraints_to_var_callback(constraints): + """ + Translate load constraints into a simple data-var filter function, if possible. + + Returns: + * function(cf_var:CFDataVariable): --> bool, + or None. + + For now, ONLY handles a single NameConstraint with no 'STASH' component. + + """ + import iris._constraints + + constraints = iris._constraints.list_of_constraints(constraints) + result = None + if len(constraints) == 1: + (constraint,) = constraints + if ( + isinstance(constraint, iris._constraints.NameConstraint) + and constraint.STASH == "none" + ): + # As long as it doesn't use a STASH match, then we can treat it as + # a testing against name properties of cf_var. + # That's just like testing against name properties of a cube, except that they may not all exist. + def inner(cf_datavar): + match = True + for name in constraint._names: + expected = getattr(constraint, name) + if name != "STASH" and expected != "none": + attr_name = "cf_name" if name == "var_name" else name + # Fetch property : N.B. CFVariable caches the property values + # The use of a default here is the only difference from the code in NameConstraint. + if not hasattr(cf_datavar, attr_name): + continue + actual = getattr(cf_datavar, attr_name, "") + if actual != expected: + match = False + break + return match + + result = inner + return result + + +def load_cubes(filenames, callback=None, constraints=None): + """ + Loads cubes from a list of NetCDF filenames/OPeNDAP URLs. + + Args: + + * filenames (string/list): + One or more NetCDF filenames/OPeNDAP URLs to load from. + + Kwargs: + + * callback (callable function): + Function which can be passed on to :func:`iris.io.run_callback`. + + Returns: + Generator of loaded NetCDF :class:`iris.cube.Cube`. + + """ + # TODO: rationalise UGRID/mesh handling once experimental.ugrid is folded + # into standard behaviour. + # Deferred import to avoid circular imports. + from iris.experimental.ugrid.cf import CFUGridReader + from iris.experimental.ugrid.load import ( + PARSE_UGRID_ON_LOAD, + _build_mesh_coords, + _meshes_from_cf, + ) + from iris.io import run_callback + + # Create a low-level data-var filter from the original load constraints, if they are suitable. + var_callback = _translate_constraints_to_var_callback(constraints) + + # Create an actions engine. + engine = _actions_engine() + + if isinstance(filenames, str): + filenames = [filenames] + + for filename in filenames: + # Ingest the netCDF file. + meshes = {} + if PARSE_UGRID_ON_LOAD: + cf = CFUGridReader(filename) + meshes = _meshes_from_cf(cf) + else: + cf = iris.fileformats.cf.CFReader(filename) + + # Process each CF data variable. + data_variables = list(cf.cf_group.data_variables.values()) + list( + cf.cf_group.promoted.values() + ) + for cf_var in data_variables: + if var_callback and not var_callback(cf_var): + # Deliver only selected results. + continue + + # cf_var-specific mesh handling, if a mesh is present. + # Build the mesh_coords *before* loading the cube - avoids + # mesh-related attributes being picked up by + # _add_unused_attributes(). + mesh_name = None + mesh = None + mesh_coords, mesh_dim = [], None + if PARSE_UGRID_ON_LOAD: + mesh_name = getattr(cf_var, "mesh", None) + if mesh_name is not None: + try: + mesh = meshes[mesh_name] + except KeyError: + message = ( + f"File does not contain mesh: '{mesh_name}' - " + f"referenced by variable: '{cf_var.cf_name}' ." + ) + logger.debug(message) + if mesh is not None: + mesh_coords, mesh_dim = _build_mesh_coords(mesh, cf_var) + + cube = _load_cube(engine, cf, cf_var, filename) + + # Attach the mesh (if present) to the cube. + for mesh_coord in mesh_coords: + cube.add_aux_coord(mesh_coord, mesh_dim) + + # Process any associated formula terms and attach + # the corresponding AuxCoordFactory. + try: + _load_aux_factory(engine, cube) + except ValueError as e: + warnings.warn("{}".format(e)) + + # Perform any user registered callback function. + cube = run_callback(callback, cube, cf_var, filename) + + # Callback mechanism may return None, which must not be yielded + if cube is None: + continue + + yield cube diff --git a/lib/iris/fileformats/netcdf.py b/lib/iris/fileformats/netcdf/saver.py similarity index 83% rename from lib/iris/fileformats/netcdf.py rename to lib/iris/fileformats/netcdf/saver.py index 6a7b37a1cc..650c5e3338 100644 --- a/lib/iris/fileformats/netcdf.py +++ b/lib/iris/fileformats/netcdf/saver.py @@ -4,16 +4,16 @@ # See COPYING and COPYING.LESSER in the root of the repository for full # licensing details. """ -Module to support the loading of a NetCDF file into an Iris cube. +Module to support the saving of Iris cubes to a NetCDF file, also using the CF +conventions for metadata interpretation. -See also: `netCDF4 python `_ +See : `NetCDF User's Guide `_ +and `netCDF4 python module `_. -Also refer to document 'NetCDF Climate and Forecast (CF) Metadata Conventions'. +Also : `CF Conventions `_. """ - import collections -import collections.abc from itertools import repeat, zip_longest import os import os.path @@ -28,7 +28,7 @@ import numpy as np import numpy.ma as ma -from iris._lazy_data import _co_realise_lazy_arrays, as_lazy_data, is_lazy_data +from iris._lazy_data import _co_realise_lazy_arrays, is_lazy_data from iris.aux_factory import ( AtmosphereSigmaFactory, HybridHeightFactory, @@ -48,28 +48,17 @@ import iris.io import iris.util -# Show actions activation statistics. -DEBUG = False +# Get the logger : shared logger for all in 'iris.fileformats.netcdf'. +from . import logger -# Configure the logger. -logger = iris.config.get_logger(__name__) +# Avoid warning about unused import. +# We could use an __all__, but we don't want to maintain one here +logger # Standard CML spatio-temporal axis names. SPATIO_TEMPORAL_AXES = ["t", "z", "y", "x"] -# Pass through CF attributes: -# - comment -# - Conventions -# - flag_masks -# - flag_meanings -# - flag_values -# - history -# - institution -# - reference -# - source -# - title -# - positive -# +# The CF-meaningful attributes which may appear on a data variable. _CF_ATTRS = [ "add_offset", "ancillary_variables", @@ -447,555 +436,6 @@ def coord(self, name): return result -def _actions_engine(): - # Return an 'actions engine', which provides a pyke-rules-like interface to - # the core cf translation code. - # Deferred import to avoid circularity. - import iris.fileformats._nc_load_rules.engine as nc_actions_engine - - engine = nc_actions_engine.Engine() - return engine - - -class NetCDFDataProxy: - """A reference to the data payload of a single NetCDF file variable.""" - - __slots__ = ("shape", "dtype", "path", "variable_name", "fill_value") - - def __init__(self, shape, dtype, path, variable_name, fill_value): - self.shape = shape - self.dtype = dtype - self.path = path - self.variable_name = variable_name - self.fill_value = fill_value - - @property - def ndim(self): - return len(self.shape) - - def __getitem__(self, keys): - dataset = netCDF4.Dataset(self.path) - try: - variable = dataset.variables[self.variable_name] - # Get the NetCDF variable data and slice. - var = variable[keys] - finally: - dataset.close() - return np.asanyarray(var) - - def __repr__(self): - fmt = ( - "<{self.__class__.__name__} shape={self.shape}" - " dtype={self.dtype!r} path={self.path!r}" - " variable_name={self.variable_name!r}>" - ) - return fmt.format(self=self) - - def __getstate__(self): - return {attr: getattr(self, attr) for attr in self.__slots__} - - def __setstate__(self, state): - for key, value in state.items(): - setattr(self, key, value) - - -def _assert_case_specific_facts(engine, cf, cf_group): - # Initialise a data store for built cube elements. - # This is used to patch element attributes *not* setup by the actions - # process, after the actions code has run. - engine.cube_parts["coordinates"] = [] - engine.cube_parts["cell_measures"] = [] - engine.cube_parts["ancillary_variables"] = [] - - # Assert facts for CF coordinates. - for cf_name in cf_group.coordinates.keys(): - engine.add_case_specific_fact("coordinate", (cf_name,)) - - # Assert facts for CF auxiliary coordinates. - for cf_name in cf_group.auxiliary_coordinates.keys(): - engine.add_case_specific_fact("auxiliary_coordinate", (cf_name,)) - - # Assert facts for CF cell measures. - for cf_name in cf_group.cell_measures.keys(): - engine.add_case_specific_fact("cell_measure", (cf_name,)) - - # Assert facts for CF ancillary variables. - for cf_name in cf_group.ancillary_variables.keys(): - engine.add_case_specific_fact("ancillary_variable", (cf_name,)) - - # Assert facts for CF grid_mappings. - for cf_name in cf_group.grid_mappings.keys(): - engine.add_case_specific_fact("grid_mapping", (cf_name,)) - - # Assert facts for CF labels. - for cf_name in cf_group.labels.keys(): - engine.add_case_specific_fact("label", (cf_name,)) - - # Assert facts for CF formula terms associated with the cf_group - # of the CF data variable. - - # Collect varnames of formula-root variables as we go. - # NOTE: use dictionary keys as an 'OrderedSet' - # - see: https://stackoverflow.com/a/53657523/2615050 - # This is to ensure that we can handle the resulting facts in a definite - # order, as using a 'set' led to indeterminate results. - formula_root = {} - for cf_var in cf.cf_group.formula_terms.values(): - for cf_root, cf_term in cf_var.cf_terms_by_root.items(): - # Only assert this fact if the formula root variable is - # defined in the CF group of the CF data variable. - if cf_root in cf_group: - formula_root[cf_root] = True - engine.add_case_specific_fact( - "formula_term", - (cf_var.cf_name, cf_root, cf_term), - ) - - for cf_root in formula_root.keys(): - engine.add_case_specific_fact("formula_root", (cf_root,)) - - -def _actions_activation_stats(engine, cf_name): - print("-" * 80) - print("CF Data Variable: %r" % cf_name) - - engine.print_stats() - - print("Rules Triggered:") - - for rule in sorted(list(engine.rules_triggered)): - print("\t%s" % rule) - - print("Case Specific Facts:") - kb_facts = engine.get_kb() - - for key in kb_facts.entity_lists.keys(): - for arg in kb_facts.entity_lists[key].case_specific_facts: - print("\t%s%s" % (key, arg)) - - -def _set_attributes(attributes, key, value): - """Set attributes dictionary, converting unicode strings appropriately.""" - - if isinstance(value, str): - try: - attributes[str(key)] = str(value) - except UnicodeEncodeError: - attributes[str(key)] = value - else: - attributes[str(key)] = value - - -def _add_unused_attributes(iris_object, cf_var): - """ - Populate the attributes of a cf element with the "unused" attributes - from the associated CF-netCDF variable. That is, all those that aren't CF - reserved terms. - - """ - - def attribute_predicate(item): - return item[0] not in _CF_ATTRS - - tmpvar = filter(attribute_predicate, cf_var.cf_attrs_unused()) - for attr_name, attr_value in tmpvar: - _set_attributes(iris_object.attributes, attr_name, attr_value) - - -def _get_actual_dtype(cf_var): - # Figure out what the eventual data type will be after any scale/offset - # transforms. - dummy_data = np.zeros(1, dtype=cf_var.dtype) - if hasattr(cf_var, "scale_factor"): - dummy_data = cf_var.scale_factor * dummy_data - if hasattr(cf_var, "add_offset"): - dummy_data = cf_var.add_offset + dummy_data - return dummy_data.dtype - - -def _get_cf_var_data(cf_var, filename): - # Get lazy chunked data out of a cf variable. - dtype = _get_actual_dtype(cf_var) - - # Create cube with deferred data, but no metadata - fill_value = getattr( - cf_var.cf_data, - "_FillValue", - netCDF4.default_fillvals[cf_var.dtype.str[1:]], - ) - proxy = NetCDFDataProxy( - cf_var.shape, dtype, filename, cf_var.cf_name, fill_value - ) - # Get the chunking specified for the variable : this is either a shape, or - # maybe the string "contiguous". - chunks = cf_var.cf_data.chunking() - # In the "contiguous" case, pass chunks=None to 'as_lazy_data'. - if chunks == "contiguous": - chunks = None - return as_lazy_data(proxy, chunks=chunks) - - -class _OrderedAddableList(list): - """ - A custom container object for actions recording. - - Used purely in actions debugging, to accumulate a record of which actions - were activated. - - It replaces a set, so as to preserve the ordering of operations, with - possible repeats, and it also numbers the entries. - - The actions routines invoke an 'add' method, so this effectively replaces - a set.add with a list.append. - - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._n_add = 0 - - def add(self, msg): - self._n_add += 1 - n_add = self._n_add - self.append(f"#{n_add:03d} : {msg}") - - -def _load_cube(engine, cf, cf_var, filename): - from iris.cube import Cube - - """Create the cube associated with the CF-netCDF data variable.""" - data = _get_cf_var_data(cf_var, filename) - cube = Cube(data) - - # Reset the actions engine. - engine.reset() - - # Initialise engine rule processing hooks. - engine.cf_var = cf_var - engine.cube = cube - engine.cube_parts = {} - engine.requires = {} - engine.rules_triggered = _OrderedAddableList() - engine.filename = filename - - # Assert all the case-specific facts. - # This extracts 'facts' specific to this data-variable (aka cube), from - # the info supplied in the CFGroup object. - _assert_case_specific_facts(engine, cf, cf_var.cf_group) - - # Run the actions engine. - # This creates various cube elements and attaches them to the cube. - # It also records various other info on the engine, to be processed later. - engine.activate() - - # Having run the rules, now add the "unused" attributes to each cf element. - def fix_attributes_all_elements(role_name): - elements_and_names = engine.cube_parts.get(role_name, []) - - for iris_object, cf_var_name in elements_and_names: - _add_unused_attributes(iris_object, cf.cf_group[cf_var_name]) - - # Populate the attributes of all coordinates, cell-measures and ancillary-vars. - fix_attributes_all_elements("coordinates") - fix_attributes_all_elements("ancillary_variables") - fix_attributes_all_elements("cell_measures") - - # Also populate attributes of the top-level cube itself. - _add_unused_attributes(cube, cf_var) - - # Work out reference names for all the coords. - names = { - coord.var_name: coord.standard_name or coord.var_name or "unknown" - for coord in cube.coords() - } - - # Add all the cube cell methods. - cube.cell_methods = [ - iris.coords.CellMethod( - method=method.method, - intervals=method.intervals, - comments=method.comments, - coords=[ - names[coord_name] if coord_name in names else coord_name - for coord_name in method.coord_names - ], - ) - for method in cube.cell_methods - ] - - if DEBUG: - # Show activation statistics for this data-var (i.e. cube). - _actions_activation_stats(engine, cf_var.cf_name) - - return cube - - -def _load_aux_factory(engine, cube): - """ - Convert any CF-netCDF dimensionless coordinate to an AuxCoordFactory. - - """ - formula_type = engine.requires.get("formula_type") - if formula_type in [ - "atmosphere_sigma_coordinate", - "atmosphere_hybrid_height_coordinate", - "atmosphere_hybrid_sigma_pressure_coordinate", - "ocean_sigma_z_coordinate", - "ocean_sigma_coordinate", - "ocean_s_coordinate", - "ocean_s_coordinate_g1", - "ocean_s_coordinate_g2", - ]: - - def coord_from_term(term): - # Convert term names to coordinates (via netCDF variable names). - name = engine.requires["formula_terms"].get(term, None) - if name is not None: - for coord, cf_var_name in engine.cube_parts["coordinates"]: - if cf_var_name == name: - return coord - warnings.warn( - "Unable to find coordinate for variable " - "{!r}".format(name) - ) - - if formula_type == "atmosphere_sigma_coordinate": - pressure_at_top = coord_from_term("ptop") - sigma = coord_from_term("sigma") - surface_air_pressure = coord_from_term("ps") - factory = AtmosphereSigmaFactory( - pressure_at_top, sigma, surface_air_pressure - ) - elif formula_type == "atmosphere_hybrid_height_coordinate": - delta = coord_from_term("a") - sigma = coord_from_term("b") - orography = coord_from_term("orog") - factory = HybridHeightFactory(delta, sigma, orography) - elif formula_type == "atmosphere_hybrid_sigma_pressure_coordinate": - # Hybrid pressure has two valid versions of its formula terms: - # "p0: var1 a: var2 b: var3 ps: var4" or - # "ap: var1 b: var2 ps: var3" where "ap = p0 * a" - # Attempt to get the "ap" term. - delta = coord_from_term("ap") - if delta is None: - # The "ap" term is unavailable, so try getting terms "p0" - # and "a" terms in order to derive an "ap" equivalent term. - coord_p0 = coord_from_term("p0") - if coord_p0 is not None: - if coord_p0.shape != (1,): - msg = ( - "Expecting {!r} to be a scalar reference " - "pressure coordinate, got shape {!r}".format( - coord_p0.var_name, coord_p0.shape - ) - ) - raise ValueError(msg) - if coord_p0.has_bounds(): - msg = ( - "Ignoring atmosphere hybrid sigma pressure " - "scalar coordinate {!r} bounds.".format( - coord_p0.name() - ) - ) - warnings.warn(msg) - coord_a = coord_from_term("a") - if coord_a is not None: - if coord_a.units.is_unknown(): - # Be graceful, and promote unknown to dimensionless units. - coord_a.units = "1" - delta = coord_a * coord_p0.points[0] - delta.units = coord_a.units * coord_p0.units - delta.rename("vertical pressure") - delta.var_name = "ap" - cube.add_aux_coord(delta, cube.coord_dims(coord_a)) - - sigma = coord_from_term("b") - surface_air_pressure = coord_from_term("ps") - factory = HybridPressureFactory(delta, sigma, surface_air_pressure) - elif formula_type == "ocean_sigma_z_coordinate": - sigma = coord_from_term("sigma") - eta = coord_from_term("eta") - depth = coord_from_term("depth") - depth_c = coord_from_term("depth_c") - nsigma = coord_from_term("nsigma") - zlev = coord_from_term("zlev") - factory = OceanSigmaZFactory( - sigma, eta, depth, depth_c, nsigma, zlev - ) - elif formula_type == "ocean_sigma_coordinate": - sigma = coord_from_term("sigma") - eta = coord_from_term("eta") - depth = coord_from_term("depth") - factory = OceanSigmaFactory(sigma, eta, depth) - elif formula_type == "ocean_s_coordinate": - s = coord_from_term("s") - eta = coord_from_term("eta") - depth = coord_from_term("depth") - a = coord_from_term("a") - depth_c = coord_from_term("depth_c") - b = coord_from_term("b") - factory = OceanSFactory(s, eta, depth, a, b, depth_c) - elif formula_type == "ocean_s_coordinate_g1": - s = coord_from_term("s") - c = coord_from_term("c") - eta = coord_from_term("eta") - depth = coord_from_term("depth") - depth_c = coord_from_term("depth_c") - factory = OceanSg1Factory(s, c, eta, depth, depth_c) - elif formula_type == "ocean_s_coordinate_g2": - s = coord_from_term("s") - c = coord_from_term("c") - eta = coord_from_term("eta") - depth = coord_from_term("depth") - depth_c = coord_from_term("depth_c") - factory = OceanSg2Factory(s, c, eta, depth, depth_c) - cube.add_aux_factory(factory) - - -def _translate_constraints_to_var_callback(constraints): - """ - Translate load constraints into a simple data-var filter function, if possible. - - Returns: - * function(cf_var:CFDataVariable): --> bool, - or None. - - For now, ONLY handles a single NameConstraint with no 'STASH' component. - - """ - import iris._constraints - - constraints = iris._constraints.list_of_constraints(constraints) - result = None - if len(constraints) == 1: - (constraint,) = constraints - if ( - isinstance(constraint, iris._constraints.NameConstraint) - and constraint.STASH == "none" - ): - # As long as it doesn't use a STASH match, then we can treat it as - # a testing against name properties of cf_var. - # That's just like testing against name properties of a cube, except that they may not all exist. - def inner(cf_datavar): - match = True - for name in constraint._names: - expected = getattr(constraint, name) - if name != "STASH" and expected != "none": - attr_name = "cf_name" if name == "var_name" else name - # Fetch property : N.B. CFVariable caches the property values - # The use of a default here is the only difference from the code in NameConstraint. - if not hasattr(cf_datavar, attr_name): - continue - actual = getattr(cf_datavar, attr_name, "") - if actual != expected: - match = False - break - return match - - result = inner - return result - - -def load_cubes(filenames, callback=None, constraints=None): - """ - Loads cubes from a list of NetCDF filenames/OPeNDAP URLs. - - Args: - - * filenames (string/list): - One or more NetCDF filenames/OPeNDAP URLs to load from. - - Kwargs: - - * callback (callable function): - Function which can be passed on to :func:`iris.io.run_callback`. - - Returns: - Generator of loaded NetCDF :class:`iris.cube.Cube`. - - """ - # TODO: rationalise UGRID/mesh handling once experimental.ugrid is folded - # into standard behaviour. - # Deferred import to avoid circular imports. - from iris.experimental.ugrid.cf import CFUGridReader - from iris.experimental.ugrid.load import ( - PARSE_UGRID_ON_LOAD, - _build_mesh_coords, - _meshes_from_cf, - ) - from iris.io import run_callback - - # Create a low-level data-var filter from the original load constraints, if they are suitable. - var_callback = _translate_constraints_to_var_callback(constraints) - - # Create an actions engine. - engine = _actions_engine() - - if isinstance(filenames, str): - filenames = [filenames] - - for filename in filenames: - # Ingest the netCDF file. - meshes = {} - if PARSE_UGRID_ON_LOAD: - cf = CFUGridReader(filename) - meshes = _meshes_from_cf(cf) - else: - cf = iris.fileformats.cf.CFReader(filename) - - # Process each CF data variable. - data_variables = list(cf.cf_group.data_variables.values()) + list( - cf.cf_group.promoted.values() - ) - for cf_var in data_variables: - if var_callback and not var_callback(cf_var): - # Deliver only selected results. - continue - - # cf_var-specific mesh handling, if a mesh is present. - # Build the mesh_coords *before* loading the cube - avoids - # mesh-related attributes being picked up by - # _add_unused_attributes(). - mesh_name = None - mesh = None - mesh_coords, mesh_dim = [], None - if PARSE_UGRID_ON_LOAD: - mesh_name = getattr(cf_var, "mesh", None) - if mesh_name is not None: - try: - mesh = meshes[mesh_name] - except KeyError: - message = ( - f"File does not contain mesh: '{mesh_name}' - " - f"referenced by variable: '{cf_var.cf_name}' ." - ) - logger.debug(message) - if mesh is not None: - mesh_coords, mesh_dim = _build_mesh_coords(mesh, cf_var) - - cube = _load_cube(engine, cf, cf_var, filename) - - # Attach the mesh (if present) to the cube. - for mesh_coord in mesh_coords: - cube.add_aux_coord(mesh_coord, mesh_dim) - - # Process any associated formula terms and attach - # the corresponding AuxCoordFactory. - try: - _load_aux_factory(engine, cube) - except ValueError as e: - warnings.warn("{}".format(e)) - - # Perform any user registered callback function. - cube = run_callback(callback, cube, cf_var, filename) - - # Callback mechanism may return None, which must not be yielded - if cube is None: - continue - - yield cube - - def _bytes_if_ascii(string): """ Convert the given string to a byte string (str in py2k, bytes in py3k) @@ -1837,7 +1277,9 @@ def _get_dim_names(self, cube_or_mesh): """ - def record_dimension(names_list, dim_name, length, matching_coords=[]): + def record_dimension( + names_list, dim_name, length, matching_coords=None + ): """ Record a file dimension, its length and associated "coordinates" (which may in fact also be connectivities). @@ -1846,6 +1288,8 @@ def record_dimension(names_list, dim_name, length, matching_coords=[]): matches the earlier finding. """ + if matching_coords is None: + matching_coords = [] if dim_name not in self._existing_dim: self._existing_dim[dim_name] = length else: diff --git a/lib/iris/fileformats/nimrod_load_rules.py b/lib/iris/fileformats/nimrod_load_rules.py index 5d8bb11c48..fd1ccb0e95 100644 --- a/lib/iris/fileformats/nimrod_load_rules.py +++ b/lib/iris/fileformats/nimrod_load_rules.py @@ -24,7 +24,7 @@ NIMROD_DEFAULT = -32767.0 TIME_UNIT = cf_units.Unit( - "seconds since 1970-01-01 00:00:00", calendar=cf_units.CALENDAR_GREGORIAN + "seconds since 1970-01-01 00:00:00", calendar=cf_units.CALENDAR_STANDARD ) diff --git a/lib/iris/fileformats/pp.py b/lib/iris/fileformats/pp.py index e2958382cb..1fb7d4e178 100644 --- a/lib/iris/fileformats/pp.py +++ b/lib/iris/fileformats/pp.py @@ -1066,7 +1066,7 @@ def core_data(self): def calendar(self): """Return the calendar of the field.""" # TODO #577 What calendar to return when ibtim.ic in [0, 3] - calendar = cf_units.CALENDAR_GREGORIAN + calendar = cf_units.CALENDAR_STANDARD if self.lbtim.ic == 2: calendar = cf_units.CALENDAR_360_DAY elif self.lbtim.ic == 4: diff --git a/lib/iris/fileformats/pp_load_rules.py b/lib/iris/fileformats/pp_load_rules.py index c23772f235..ebccec47ee 100644 --- a/lib/iris/fileformats/pp_load_rules.py +++ b/lib/iris/fileformats/pp_load_rules.py @@ -548,7 +548,7 @@ def _epoch_date_hours_internals(epoch_hours_unit, datetime): if m == 0: # Add a 'January', by changing month=0 to 1. m = 1 - if calendar == cf_units.CALENDAR_GREGORIAN: + if calendar == cf_units.CALENDAR_STANDARD: days_offset += 31 elif calendar == cf_units.CALENDAR_360_DAY: days_offset += 30 @@ -561,7 +561,7 @@ def _epoch_date_hours_internals(epoch_hours_unit, datetime): if y == 0: # Add a 'Year 0', by changing year=0 to 1. y = 1 - if calendar == cf_units.CALENDAR_GREGORIAN: + if calendar == cf_units.CALENDAR_STANDARD: days_in_year_0 = 366 elif calendar == cf_units.CALENDAR_360_DAY: days_in_year_0 = 360 diff --git a/lib/iris/fileformats/pp_save_rules.py b/lib/iris/fileformats/pp_save_rules.py index ed156b5a05..e6b3748f9b 100644 --- a/lib/iris/fileformats/pp_save_rules.py +++ b/lib/iris/fileformats/pp_save_rules.py @@ -398,7 +398,7 @@ def _calendar_rules(cube, pp): if time_coord is not None: if time_coord.units.calendar == "360_day": pp.lbtim.ic = 2 - elif time_coord.units.calendar == "gregorian": + elif time_coord.units.calendar == "standard": pp.lbtim.ic = 1 elif time_coord.units.calendar == "365_day": pp.lbtim.ic = 4 diff --git a/lib/iris/fileformats/um_cf_map.py b/lib/iris/fileformats/um_cf_map.py index 8aee67ae3e..9091507668 100644 --- a/lib/iris/fileformats/um_cf_map.py +++ b/lib/iris/fileformats/um_cf_map.py @@ -16,10 +16,12 @@ LBFC_TO_CF = { 5: CFName('atmosphere_boundary_layer_thickness', None, 'm'), 16: CFName('air_temperature', None, 'K'), + 22: CFName('wet_bulb_potential_temperature', None, 'K'), 23: CFName('soil_temperature', None, 'K'), 27: CFName('air_density', None, 'kg m-3'), 36: CFName('land_area_fraction', None, '1'), 37: CFName('sea_ice_area_fraction', None, '1'), + 42: CFName('upward_air_velocity', None, 'm s-1'), 50: CFName('wind_speed', None, 'm s-1'), 56: CFName('x_wind', None, 'm s-1'), 57: CFName('y_wind', None, 'm s-1'), @@ -28,11 +30,16 @@ 83: CFName('potential_vorticity_of_atmosphere_layer', None, 'Pa-1 s-1'), 94: CFName('convective_rainfall_amount', None, 'kg m-2'), 97: CFName('rainfall_flux', None, 'kg m-2 s-1'), + 98: CFName('convective_rainfall_flux', None, 'kg m-2 s-1'), + 99: CFName('stratiform_rainfall_flux', None, 'kg m-2 s-1'), 102: CFName('stratiform_rainfall_amount', None, 'kg m-2'), + 106: CFName('soil_moisture_content', None, 'kg m-2'), 108: CFName('snowfall_flux', None, 'kg m-2 s-1'), 111: CFName('surface_runoff_amount', None, 'kg m-2'), 116: CFName('stratiform_snowfall_amount', None, 'kg m-2'), 117: CFName('convective_snowfall_amount', None, 'kg m-2'), + 118: CFName('stratiform_snowfall_flux', None, 'kg m-2 s-1'), + 119: CFName('convective_snowfall_flux', None, 'kg m-2 s-1'), 122: CFName('moisture_content_of_soil_layer', None, 'kg m-2'), 183: CFName('wind_speed', None, 'm s-1'), 200: CFName('toa_incoming_shortwave_flux', None, 'W m-2'), @@ -1157,7 +1164,9 @@ CFName('cloud_area_fraction_in_atmosphere_layer', None, '1'): 1720, CFName('convective_cloud_area_fraction', None, '1'): 34, CFName('convective_rainfall_amount', None, 'kg m-2'): 94, + CFName('convective_rainfall_flux', None, 'kg m-2 s-1'): 98, CFName('convective_snowfall_amount', None, 'kg m-2'): 117, + CFName('convective_snowfall_flux', None, 'kg m-2 s-1'): 119, CFName('dimensionless_exner_function', None, '1'): 7, CFName('divergence_of_wind', None, 's-1'): 74, CFName('downward_heat_flux_in_sea_ice', None, 'W m-2'): 261, @@ -1203,6 +1212,7 @@ CFName('soil_albedo', None, '1'): 1395, CFName('soil_carbon_content', None, 'kg m-2'): 1397, CFName('soil_hydraulic_conductivity_at_saturation', None, 'm s-1'): 333, + CFName('soil_moisture_content', None, 'kg m-2'): 106, CFName('soil_moisture_content_at_field_capacity', None, 'kg m-2'): 1559, CFName('soil_porosity', None, '1'): 332, CFName('soil_suction_at_saturation', None, 'Pa'): 342, @@ -1212,8 +1222,10 @@ CFName('specific_kinetic_energy_of_air', None, 'm2 s-2'): 60, CFName('stratiform_cloud_area_fraction_in_atmosphere_layer', None, '1'): 220, CFName('stratiform_rainfall_amount', None, 'kg m-2'): 102, + CFName('stratiform_rainfall_flux', None, 'kg m-2 s-1'): 99, CFName('stratiform_rainfall_rate', None, 'kg m-2 s-1'): 99, CFName('stratiform_snowfall_amount', None, 'kg m-2'): 116, + CFName('stratiform_snowfall_flux', None, 'kg m-2 s-1'): 118, CFName('subsurface_runoff_amount', None, 'kg m-2'): 112, CFName('subsurface_runoff_flux', None, 'kg m-2 s-1'): 1533, CFName('surface_albedo_assuming_deep_snow', None, '1'): 328, @@ -1260,6 +1272,7 @@ CFName('volume_fraction_of_condensed_water_in_soil_at_critical_point', None, '1'): 330, CFName('volume_fraction_of_condensed_water_in_soil_at_wilting_point', None, '1'): 329, CFName('water_potential_evaporation_flux', None, 'kg m-2 s-1'): 115, + CFName('wet_bulb_potential_temperature', None, 'K'): 22, CFName('wind_mixing_energy_flux_into_sea_water', None, 'W m-2'): 182, CFName('wind_speed', None, 'm s-1'): 50, CFName('x_wind', None, 'm s-1'): 56, diff --git a/lib/iris/io/__init__.py b/lib/iris/io/__init__.py index 8d5a2e05d2..4659f70ae3 100644 --- a/lib/iris/io/__init__.py +++ b/lib/iris/io/__init__.py @@ -131,20 +131,26 @@ def decode_uri(uri, default="file"): return scheme, part -def expand_filespecs(file_specs): +def expand_filespecs(file_specs, files_expected=True): """ Find all matching file paths from a list of file-specs. - Args: - - * file_specs (iterable of string): - File paths which may contain '~' elements or wildcards. - - Returns: - A well-ordered list of matching absolute file paths. - If any of the file-specs match no existing files, an - exception is raised. - + Parameters + ---------- + file_specs : iterable of str + File paths which may contain ``~`` elements or wildcards. + files_expected : bool, default=True + Whether file is expected to exist (i.e. for load). + + Returns + ------- + list of str + if files_expected is ``True``: + A well-ordered list of matching absolute file paths. + If any of the file-specs match no existing files, an + exception is raised. + if files_expected is ``False``: + A list of expanded file paths. """ # Remove any hostname component - currently unused filenames = [ @@ -154,26 +160,30 @@ def expand_filespecs(file_specs): for fn in file_specs ] - # Try to expand all filenames as globs - glob_expanded = OrderedDict( - [[fn, sorted(glob.glob(fn))] for fn in filenames] - ) - - # If any of the specs expanded to an empty list then raise an error - all_expanded = glob_expanded.values() - - if not all(all_expanded): - msg = "One or more of the files specified did not exist:" - for pattern, expanded in glob_expanded.items(): - if expanded: - msg += '\n - "{}" matched {} file(s)'.format( - pattern, len(expanded) - ) - else: - msg += '\n * "{}" didn\'t match any files'.format(pattern) - raise IOError(msg) + if files_expected: + # Try to expand all filenames as globs + glob_expanded = OrderedDict( + [[fn, sorted(glob.glob(fn))] for fn in filenames] + ) - return [fname for fnames in all_expanded for fname in fnames] + # If any of the specs expanded to an empty list then raise an error + all_expanded = glob_expanded.values() + if not all(all_expanded): + msg = "One or more of the files specified did not exist:" + for pattern, expanded in glob_expanded.items(): + if expanded: + msg += '\n - "{}" matched {} file(s)'.format( + pattern, len(expanded) + ) + else: + msg += '\n * "{}" didn\'t match any files'.format( + pattern + ) + raise IOError(msg) + result = [fname for fnames in all_expanded for fname in fnames] + else: + result = filenames + return result def load_files(filenames, callback, constraints=None): @@ -356,65 +366,64 @@ def save(source, target, saver=None, **kwargs): A custom saver can be provided to the function to write to a different file format. - Args: - - * source: - :class:`iris.cube.Cube`, :class:`iris.cube.CubeList` or - sequence of cubes. - * target: - A filename (or writeable, depending on file format). + Parameters + ---------- + source : :class:`iris.cube.Cube` or :class:`iris.cube.CubeList` + target : str or pathlib.PurePath or io.TextIOWrapper When given a filename or file, Iris can determine the - file format. Filename can be given as a string or - :class:`pathlib.PurePath`. - - Kwargs: - - * saver: - Optional. Specifies the file format to save. + file format. + saver : str or function, optional + Specifies the file format to save. If omitted, Iris will attempt to determine the format. - If a string, this is the recognised filename extension (where the actual filename may not have it). + Otherwise the value is a saver function, of the form: ``my_saver(cube, target)`` plus any custom keywords. It is assumed that a saver will accept an ``append`` keyword - if it's file format can handle multiple cubes. See also + if its file format can handle multiple cubes. See also :func:`iris.io.add_saver`. + **kwargs : dict, optional + All other keywords are passed through to the saver function; see the + relevant saver documentation for more information on keyword arguments. - All other keywords are passed through to the saver function; see the - relevant saver documentation for more information on keyword arguments. - - Examples:: + Warnings + -------- + Saving a cube whose data has been loaded lazily + (if `cube.has_lazy_data()` returns `True`) to the same file it expects + to load data from will cause both the data in-memory and the data on + disk to be lost. - # Save a cube to PP - iris.save(my_cube, "myfile.pp") + .. code-block:: python - # Save a cube list to a PP file, appending to the contents of the file - # if it already exists - iris.save(my_cube_list, "myfile.pp", append=True) + cube = iris.load_cube("somefile.nc") + # The next line causes data loss in 'somefile.nc' and the cube. + iris.save(cube, "somefile.nc") - # Save a cube to netCDF, defaults to NETCDF4 file format - iris.save(my_cube, "myfile.nc") + In general, overwriting a file which is the source for any lazily loaded + data can result in corruption. Users should proceed with caution when + attempting to overwrite an existing file. - # Save a cube list to netCDF, using the NETCDF3_CLASSIC storage option - iris.save(my_cube_list, "myfile.nc", netcdf_format="NETCDF3_CLASSIC") + Examples + -------- + >>> # Setting up + >>> import iris + >>> my_cube = iris.load_cube(iris.sample_data_path('air_temp.pp')) + >>> my_cube_list = iris.load(iris.sample_data_path('space_weather.nc')) - .. warning:: + >>> # Save a cube to PP + >>> iris.save(my_cube, "myfile.pp") - Saving a cube whose data has been loaded lazily - (if `cube.has_lazy_data()` returns `True`) to the same file it expects - to load data from will cause both the data in-memory and the data on - disk to be lost. + >>> # Save a cube list to a PP file, appending to the contents of the file + >>> # if it already exists + >>> iris.save(my_cube_list, "myfile.pp", append=True) - .. code-block:: python + >>> # Save a cube to netCDF, defaults to NETCDF4 file format + >>> iris.save(my_cube, "myfile.nc") - cube = iris.load_cube("somefile.nc") - # The next line causes data loss in 'somefile.nc' and the cube. - iris.save(cube, "somefile.nc") + >>> # Save a cube list to netCDF, using the NETCDF3_CLASSIC storage option + >>> iris.save(my_cube_list, "myfile.nc", netcdf_format="NETCDF3_CLASSIC") - In general, overwriting a file which is the source for any lazily loaded - data can result in corruption. Users should proceed with caution when - attempting to overwrite an existing file. """ from iris.cube import Cube, CubeList @@ -423,6 +432,8 @@ def save(source, target, saver=None, **kwargs): if isinstance(target, pathlib.PurePath): target = str(target) if isinstance(target, str) and saver is None: + # Converts tilde or wildcards to absolute path + (target,) = expand_filespecs([str(target)], False) saver = find_saver(target) elif hasattr(target, "name") and saver is None: saver = find_saver(target.name) diff --git a/lib/iris/palette.py b/lib/iris/palette.py index 626ae4e341..5aa30a6b4e 100644 --- a/lib/iris/palette.py +++ b/lib/iris/palette.py @@ -15,6 +15,7 @@ import re import cf_units +from matplotlib import colormaps as mpl_colormaps import matplotlib.cm as mpl_cm import matplotlib.colors as mpl_colors import numpy as np @@ -337,7 +338,7 @@ def _load_palette(): ) # Register the color map for use. - mpl_cm.register_cmap(cmap=cmap) + mpl_colormaps.register(cmap) # Ensure to load the color map palettes. diff --git a/lib/iris/pandas.py b/lib/iris/pandas.py index 4c421792a7..b00eb3f117 100644 --- a/lib/iris/pandas.py +++ b/lib/iris/pandas.py @@ -11,6 +11,8 @@ """ import datetime +from itertools import chain, combinations +import warnings import cf_units from cf_units import Unit @@ -25,69 +27,146 @@ from pandas.tseries.index import DatetimeIndex # pandas <0.20 import iris -from iris.coords import AuxCoord, DimCoord -from iris.cube import Cube +from iris._deprecation import warn_deprecated +from iris.coords import AncillaryVariable, AuxCoord, CellMeasure, DimCoord +from iris.cube import Cube, CubeList -def _add_iris_coord(cube, name, points, dim, calendar=None): +def _get_dimensional_metadata(name, values, calendar=None, dm_class=None): """ - Add a Coord to a Cube from a Pandas index or columns array. + Create a Coord or other dimensional metadata from a Pandas index or columns array. - If no calendar is specified for a time series, Gregorian is assumed. + If no calendar is specified for a time series, Standard is assumed. """ units = Unit("unknown") if calendar is None: - calendar = cf_units.CALENDAR_GREGORIAN + calendar = cf_units.CALENDAR_STANDARD + + # Getting everything into a single datetime format is hard! + + # Convert out of NumPy's own datetime format. + if np.issubdtype(values.dtype, np.datetime64): + values = pandas.to_datetime(values) - # Convert pandas datetime objects to python datetime obejcts. - if isinstance(points, DatetimeIndex): - points = np.array([i.to_pydatetime() for i in points]) + # Convert pandas datetime objects to python datetime objects. + if isinstance(values, DatetimeIndex): + values = np.array([i.to_pydatetime() for i in values]) # Convert datetime objects to Iris' current datetime representation. - if points.dtype == object: + if values.dtype == object: dt_types = (datetime.datetime, cftime.datetime) - if all([isinstance(i, dt_types) for i in points]): + if all([isinstance(i, dt_types) for i in values]): units = Unit("hours since epoch", calendar=calendar) - points = units.date2num(points) - - points = np.array(points) - if np.issubdtype(points.dtype, np.number) and iris.util.monotonic( - points, strict=True - ): - coord = DimCoord(points, units=units) - coord.rename(name) + values = units.date2num(values) + + values = np.array(values) + + if dm_class is None: + if np.issubdtype(values.dtype, np.number) and iris.util.monotonic( + values, strict=True + ): + dm_class = DimCoord + else: + dm_class = AuxCoord + + instance = dm_class(values, units=units) + if name is not None: + # Use rename() to attempt standard_name but fall back on long_name. + instance.rename(str(name)) + + return instance + + +def _add_iris_coord(cube, name, points, dim, calendar=None): + """ + Add a Coord or other dimensional metadata to a Cube from a Pandas index or columns array. + """ + # Most functionality has been abstracted to _get_dimensional_metadata, + # allowing re-use in as_cube() and as_cubes(). + coord = _get_dimensional_metadata(name, points, calendar) + + if coord.__class__ == DimCoord: cube.add_dim_coord(coord, dim) else: - coord = AuxCoord(points, units=units) - coord.rename(name) cube.add_aux_coord(coord, dim) -def as_cube(pandas_array, copy=True, calendars=None): +def _series_index_unique(pandas_series: pandas.Series): """ - Convert a Pandas array into an Iris cube. + Find an index grouping of a :class:`pandas.Series` that has just one Series value per group. - Args: + Iterates through grouping single index levels, then combinations of 2 + levels, then 3 etcetera, until single :class:`~pandas.Series` values per + group are found. Returns a ``tuple`` of the index levels that group to + produce single values, as soon as one is found. - * pandas_array - A Pandas Series or DataFrame. + Returns ``None`` if no index level combination produces single values. - Kwargs: + """ + unique_number = pandas_series.nunique() + pandas_index = pandas_series.index + levels_range = range(pandas_index.nlevels) + if unique_number == 1: + # Scalar - identical for all indices. + result = () + else: + result = None + levels_combinations = chain( + *[ + combinations(levels_range, levels + 1) + for levels in levels_range + ] + ) + for lc in levels_combinations: + if pandas_series.groupby(level=lc).nunique().max() == 1: + result = lc + # Escape as early as possible - heavy operation. + break + return result + + +def as_cube( + pandas_array, + copy=True, + calendars=None, +): + """ + Convert a Pandas Series/DataFrame into a 1D/2D Iris Cube. + + .. deprecated:: 3.3.0 + + This function is scheduled for removal in a future release, being + replaced by :func:`iris.pandas.as_cubes`, which offers richer + dimensional intelligence. - * copy - Whether to make a copy of the data. - Defaults to True. + Parameters + ---------- + pandas_array : :class:`pandas.Series` or :class:`pandas.DataFrame` + The Pandas object to convert + copy : bool, default=True + Whether to copy `pandas_array`, or to create array views where + possible. Provided in case of memory limit concerns. + calendars : dict, optional + A dict mapping a dimension to a calendar. Required to convert datetime + indices/columns. - * calendars - A dict mapping a dimension to a calendar. - Required to convert datetime indices/columns. + Notes + ----- + This function will copy your data by default. Example usage:: as_cube(series, calendars={0: cf_units.CALENDAR_360_DAY}) - as_cube(data_frame, calendars={1: cf_units.CALENDAR_GREGORIAN}) - - .. note:: This function will copy your data by default. + as_cube(data_frame, calendars={1: cf_units.CALENDAR_STANDARD}) """ + message = ( + "iris.pandas.as_cube has been deprecated, and will be removed in a " + "future release. Please use iris.pandas.as_cubes instead." + ) + warn_deprecated(message) + calendars = calendars or {} if pandas_array.ndim not in [1, 2]: raise ValueError( @@ -116,6 +195,302 @@ def as_cube(pandas_array, copy=True, calendars=None): return cube +def as_cubes( + pandas_structure, + copy=True, + calendars=None, + aux_coord_cols=None, + cell_measure_cols=None, + ancillary_variable_cols=None, +): + """ + Convert a Pandas Series/DataFrame into n-dimensional Iris Cubes, including dimensional metadata. + + The index of `pandas_structure` will be used for generating the + :class:`~iris.cube.Cube` dimension(s) and :class:`~iris.coords.DimCoord`\\ s. + Other dimensional metadata may span multiple dimensions - based on how the + column values vary with the index values. + + Parameters + ---------- + pandas_structure : :class:`pandas.Series` or :class:`pandas.DataFrame` + The Pandas object to convert + copy : bool, default=True + Whether the Cube :attr:`~iris.cube.Cube.data` is a copy of the + `pandas_structure` column, or a view of the same array. Arrays other than + the data (coords etc.) are always copies. This option is provided to + help with memory size concerns. + calendars : dict, optional + Calendar conversions for individual date-time coordinate + columns/index-levels e.g. ``{"my_column": cf_units.CALENDAR_360_DAY}``. + aux_coord_cols, cell_measure_cols, ancillary_variable_cols : list of str, optional + Names of columns to be converted into :class:`~iris.coords.AuxCoord`, + :class:`~iris.coords.CellMeasure` and + :class:`~iris.coords.AncillaryVariable` objects. + + Returns + -------- + :class:`~iris.cube.CubeList` + One :class:`~iris.cube.Cube` for each column not referenced in + `aux_coord_cols`/`cell_measure_cols`/`ancillary_variable_cols`. + + Notes + ----- + A :class:`~pandas.DataFrame` using columns as a second data dimension will + need to be 'melted' before conversion. See the Examples for how. + + Dask ``DataFrame``\\s are not supported. + + Examples + -------- + >>> from iris.pandas import as_cubes + >>> import numpy as np + >>> from pandas import DataFrame, Series + + Converting a simple :class:`~pandas.Series` : + + >>> my_series = Series([300, 301, 302], name="air_temperature") + >>> converted_cubes = as_cubes(my_series) + >>> print(converted_cubes) + 0: air_temperature / (unknown) (unknown: 3) + >>> print(converted_cubes[0]) + air_temperature / (unknown) (unknown: 3) + Dimension coordinates: + unknown x + + A :class:`~pandas.DataFrame`, with a custom index becoming the + :class:`~iris.coords.DimCoord` : + + >>> my_df = DataFrame({ + ... "air_temperature": [300, 301, 302], + ... "longitude": [30, 40, 50] + ... }) + >>> my_df = my_df.set_index("longitude") + >>> converted_cubes = as_cubes(my_df) + >>> print(converted_cubes[0]) + air_temperature / (unknown) (longitude: 3) + Dimension coordinates: + longitude x + + A :class:`~pandas.DataFrame` representing two 3-dimensional datasets, + including a 2-dimensional :class:`~iris.coords.AuxCoord` : + + >>> my_df = DataFrame({ + ... "air_temperature": np.arange(300, 312, 1), + ... "air_pressure": np.arange(1000, 1012, 1), + ... "longitude": [0, 10] * 6, + ... "latitude": [25, 25, 35, 35] * 3, + ... "height": ([0] * 4) + ([100] * 4) + ([200] * 4), + ... "in_region": [True, False, False, False] * 3 + ... }) + >>> print(my_df) + air_temperature air_pressure longitude latitude height in_region + 0 300 1000 0 25 0 True + 1 301 1001 10 25 0 False + 2 302 1002 0 35 0 False + 3 303 1003 10 35 0 False + 4 304 1004 0 25 100 True + 5 305 1005 10 25 100 False + 6 306 1006 0 35 100 False + 7 307 1007 10 35 100 False + 8 308 1008 0 25 200 True + 9 309 1009 10 25 200 False + 10 310 1010 0 35 200 False + 11 311 1011 10 35 200 False + >>> my_df = my_df.set_index(["longitude", "latitude", "height"]) + >>> my_df = my_df.sort_index() + >>> converted_cubes = as_cubes(my_df, aux_coord_cols=["in_region"]) + >>> print(converted_cubes) + 0: air_temperature / (unknown) (longitude: 2; latitude: 2; height: 3) + 1: air_pressure / (unknown) (longitude: 2; latitude: 2; height: 3) + >>> print(converted_cubes[0]) + air_temperature / (unknown) (longitude: 2; latitude: 2; height: 3) + Dimension coordinates: + longitude x - - + latitude - x - + height - - x + Auxiliary coordinates: + in_region x x - + + Pandas uses ``NaN`` rather than masking data. Converted + :class:`~iris.cube.Cube`\\s can be masked in downstream user code : + + >>> my_series = Series([300, np.NaN, 302], name="air_temperature") + >>> converted_cube = as_cubes(my_series)[0] + >>> print(converted_cube.data) + [300. nan 302.] + >>> converted_cube.data = np.ma.masked_invalid(converted_cube.data) + >>> print(converted_cube.data) + [300.0 -- 302.0] + + If the :class:`~pandas.DataFrame` uses columns as a second dimension, + :func:`pandas.melt` should be used to convert the data to the expected + n-dimensional format : + + >>> my_df = DataFrame({ + ... "latitude": [35, 25], + ... 0: [300, 301], + ... 10: [302, 303], + ... }) + >>> print(my_df) + latitude 0 10 + 0 35 300 302 + 1 25 301 303 + >>> my_df = my_df.melt( + ... id_vars=["latitude"], + ... value_vars=[0, 10], + ... var_name="longitude", + ... value_name="air_temperature" + ... ) + >>> print(my_df) + latitude longitude air_temperature + 0 35 0 300 + 1 25 0 301 + 2 35 10 302 + 3 25 10 303 + >>> my_df = my_df.set_index(["latitude", "longitude"]) + >>> my_df = my_df.sort_index() + >>> converted_cube = as_cubes(my_df)[0] + >>> print(converted_cube) + air_temperature / (unknown) (latitude: 2; longitude: 2) + Dimension coordinates: + latitude x - + longitude - x + + """ + if pandas_structure.empty: + return CubeList() + + calendars = calendars or {} + aux_coord_cols = aux_coord_cols or [] + cell_measure_cols = cell_measure_cols or [] + ancillary_variable_cols = ancillary_variable_cols or [] + + is_series = isinstance(pandas_structure, pandas.Series) + + if copy: + pandas_structure = pandas_structure.copy() + + pandas_index = pandas_structure.index + if not pandas_index.is_unique: + message = ( + f"DataFrame index ({pandas_index.names}) is not unique per " + "row; cannot be used for DimCoords." + ) + raise ValueError(message) + + if not pandas_index.is_monotonic: + # Need monotonic index for use in DimCoord(s). + # This function doesn't sort_index itself since that breaks the + # option to return a data view instead of a copy. + message = ( + "Pandas index is not monotonic. Consider using the " + "sort_index() method before passing in." + ) + raise ValueError(message) + + cube_shape = getattr(pandas_index, "levshape", (pandas_index.nunique(),)) + n_rows = len(pandas_structure) + if np.product(cube_shape) > n_rows: + message = ( + f"Not all index values have a corresponding row - {n_rows} rows " + f"cannot be reshaped into {cube_shape}. Consider padding with NaN " + "rows where needed." + ) + raise ValueError(message) + + cube_kwargs = {} + + def format_dimensional_metadata(dm_class_, values_, name_, dimensions_): + # Common convenience to get the right DM in the right format for + # Cube creation. + calendar = calendars.get(name_) + instance = _get_dimensional_metadata( + name_, values_, calendar, dm_class_ + ) + return (instance, dimensions_) + + # DimCoords. + dim_coord_kwarg = [] + for ix, dim_name in enumerate(pandas_index.names): + if hasattr(pandas_index, "levels"): + coord_points = pandas_index.levels[ix] + else: + coord_points = pandas_index + new_dim_coord = format_dimensional_metadata( + DimCoord, coord_points, dim_name, ix + ) + dim_coord_kwarg.append(new_dim_coord) + cube_kwargs["dim_coords_and_dims"] = dim_coord_kwarg + + # Other dimensional metadata. + class_arg_mapping = [ + (AuxCoord, aux_coord_cols, "aux_coords_and_dims"), + (CellMeasure, cell_measure_cols, "cell_measures_and_dims"), + ( + AncillaryVariable, + ancillary_variable_cols, + "ancillary_variables_and_dims", + ), + ] + + if is_series: + columns_ignored = any([len(t[1]) > 0 for t in class_arg_mapping]) + if columns_ignored: + ignored_args = ", ".join([t[2] for t in class_arg_mapping]) + message = f"The input pandas_structure is a Series; ignoring arguments: {ignored_args} ." + warnings.warn(message) + class_arg_mapping = [] + + non_data_names = [] + for dm_class, column_names, kwarg in class_arg_mapping: + class_kwarg = [] + non_data_names.extend(column_names) + for column_name in column_names: + column = pandas_structure[column_name] + + # Should be impossible for None to be returned - would require a + # non-unique index, which we protect against. + dimensions = _series_index_unique(column) + + content = column.to_numpy() + # Remove duplicate entries to get down to the correct dimensions + # for this object. _series_index_unique should have ensured + # that we are indeed removing the duplicates. + shaped = content.reshape(cube_shape) + indices = [0] * len(cube_shape) + for dim in dimensions: + indices[dim] = slice(None) + collapsed = shaped[tuple(indices)] + + new_dm = format_dimensional_metadata( + dm_class, collapsed, column_name, dimensions + ) + class_kwarg.append(new_dm) + + cube_kwargs[kwarg] = class_kwarg + + # Cube creation. + if is_series: + data_series_list = [pandas_structure] + else: + data_series_list = [ + pandas_structure[column_name] + for column_name in pandas_structure.columns + if column_name not in non_data_names + ] + cubes = CubeList() + for data_series in data_series_list: + cube_data = data_series.to_numpy().reshape(cube_shape) + new_cube = Cube(cube_data, **cube_kwargs) + if data_series.name is not None: + # Use rename() to attempt standard_name but fall back on long_name. + new_cube.rename(str(data_series.name)) + cubes.append(new_cube) + + return cubes + + def _as_pandas_coord(coord): """Convert an Iris Coord into a Pandas index or columns array.""" index = coord.points diff --git a/lib/iris/plot.py b/lib/iris/plot.py index 47c63dc173..4acb38b859 100644 --- a/lib/iris/plot.py +++ b/lib/iris/plot.py @@ -587,14 +587,14 @@ def _fixup_dates(coord, values): # Convert coordinate values into tuples of # (year, month, day, hour, min, sec) dates = [coord.units.num2date(val).timetuple()[0:6] for val in values] - if coord.units.calendar == "gregorian": + if coord.units.calendar == "standard": r = [datetime.datetime(*date) for date in dates] else: try: import nc_time_axis # noqa: F401 except ImportError: msg = ( - "Cannot plot against time in a non-gregorian " + "Cannot plot against time in a non-standard " 'calendar, because "nc_time_axis" is not available : ' "Install the package from " "https://github.com/SciTools/nc-time-axis to enable " @@ -1344,11 +1344,6 @@ def outline(cube, coords=None, color="k", linewidth=None, axes=None): axes=axes, ) - # set the _is_stroked property to get a single color grid. - # See https://github.com/matplotlib/matplotlib/issues/1302 - result._is_stroked = False - if hasattr(result, "_wrapped_collection_fix"): - result._wrapped_collection_fix._is_stroked = False return result diff --git a/lib/iris/quickplot.py b/lib/iris/quickplot.py index 14f9e5d2d5..18ed2554a3 100644 --- a/lib/iris/quickplot.py +++ b/lib/iris/quickplot.py @@ -71,7 +71,7 @@ def _label(cube, mode, result=None, ndims=2, coords=None, axes=None): if result is not None: draw_edges = mode == iris.coords.POINT_MODE bar = plt.colorbar( - result, orientation="horizontal", drawedges=draw_edges + result, ax=axes, orientation="horizontal", drawedges=draw_edges ) has_known_units = not ( cube.units.is_unknown() or cube.units.is_no_unit() diff --git a/lib/iris/tests/__init__.py b/lib/iris/tests/__init__.py index 99e2a5604b..4840de8cdb 100644 --- a/lib/iris/tests/__init__.py +++ b/lib/iris/tests/__init__.py @@ -141,16 +141,78 @@ def main(): unittest.main() +def _assert_masked_array(assertion, a, b, strict, **kwargs): + # Compare masks. + a_mask, b_mask = ma.getmaskarray(a), ma.getmaskarray(b) + np.testing.assert_array_equal(a_mask, b_mask) + + if strict: + # Compare all data values. + assertion(a.data, b.data, **kwargs) + else: + # Compare only unmasked data values. + assertion( + ma.compressed(a), + ma.compressed(b), + **kwargs, + ) + + +def assert_masked_array_equal(a, b, strict=False): + """ + Check that masked arrays are equal. This requires the + unmasked values and masks to be identical. + + Args: + + * a, b (array-like): + Two arrays to compare. + + Kwargs: + + * strict (bool): + If True, perform a complete mask and data array equality check. + If False (default), the data array equality considers only unmasked + elements. + + """ + _assert_masked_array(np.testing.assert_array_equal, a, b, strict) + + +def assert_masked_array_almost_equal(a, b, decimal=6, strict=False): + """ + Check that masked arrays are almost equal. This requires the + masks to be identical, and the unmasked values to be almost + equal. + + Args: + + * a, b (array-like): + Two arrays to compare. + + Kwargs: + + * strict (bool): + If True, perform a complete mask and data array equality check. + If False (default), the data array equality considers only unmasked + elements. + + * decimal (int): + Equality tolerance level for + :meth:`numpy.testing.assert_array_almost_equal`, with the meaning + 'abs(desired-actual) < 0.5 * 10**(-decimal)' + + """ + _assert_masked_array( + np.testing.assert_array_almost_equal, a, b, strict, decimal=decimal + ) + + class IrisTest_nometa(unittest.TestCase): """A subclass of unittest.TestCase which provides Iris specific testing functionality.""" _assertion_counts = collections.defaultdict(int) - @classmethod - def setUpClass(cls): - # Ensure that the CF profile if turned-off for testing. - iris.site_configuration["cf_profile"] = None - def _assert_str_same( self, reference_str, @@ -223,25 +285,6 @@ def get_result_path(relative_path): relative_path = os.path.join(*relative_path) return os.path.abspath(os.path.join(_RESULT_PATH, relative_path)) - def assertStringEqual( - self, reference_str, test_str, type_comparison_name="strings" - ): - if reference_str != test_str: - diff = "\n".join( - difflib.unified_diff( - reference_str.splitlines(), - test_str.splitlines(), - "Reference", - "Test result", - "", - "", - 0, - ) - ) - self.fail( - "{} do not match:\n{}".format(type_comparison_name, diff) - ) - def result_path(self, basename=None, ext=""): """ Return the full path to a test result, generated from the \ @@ -560,16 +603,6 @@ def _recordWarningMatches(self, expected_regexp=""): expr = re.compile(expected_regexp) matches.extend(message for message in messages if expr.search(message)) - @contextlib.contextmanager - def assertWarnsRegexp(self, expected_regexp=""): - # Check that a warning is raised matching a given expression. - with self._recordWarningMatches(expected_regexp) as matches: - yield - - msg = "Warning matching '{}' not raised." - msg = msg.format(expected_regexp) - self.assertTrue(matches, msg) - @contextlib.contextmanager def assertLogs(self, logger=None, level=None, msg_regex=None): """ @@ -616,85 +649,14 @@ def assertNoWarningsRegexp(self, expected_regexp=""): msg = msg.format(expected_regexp, matches) self.assertFalse(matches, msg) - def _assertMaskedArray(self, assertion, a, b, strict, **kwargs): - # Define helper function to extract unmasked values as a 1d - # array. - def unmasked_data_as_1d_array(array): - array = ma.asarray(array) - if array.ndim == 0: - if array.mask: - data = np.array([]) - else: - data = np.array([array.data]) - else: - data = array.data[~ma.getmaskarray(array)] - return data - - # Compare masks. This will also check that the array shapes - # match, which is not tested when comparing unmasked values if - # strict is False. - a_mask, b_mask = ma.getmaskarray(a), ma.getmaskarray(b) - np.testing.assert_array_equal(a_mask, b_mask) - - if strict: - assertion(a.data, b.data, **kwargs) - else: - assertion( - unmasked_data_as_1d_array(a), - unmasked_data_as_1d_array(b), - **kwargs, - ) - - def assertMaskedArrayEqual(self, a, b, strict=False): - """ - Check that masked arrays are equal. This requires the - unmasked values and masks to be identical. - - Args: - - * a, b (array-like): - Two arrays to compare. - - Kwargs: - - * strict (bool): - If True, perform a complete mask and data array equality check. - If False (default), the data array equality considers only unmasked - elements. - - """ - self._assertMaskedArray(np.testing.assert_array_equal, a, b, strict) + assertMaskedArrayEqual = staticmethod(assert_masked_array_equal) def assertArrayAlmostEqual(self, a, b, decimal=6): np.testing.assert_array_almost_equal(a, b, decimal=decimal) - def assertMaskedArrayAlmostEqual(self, a, b, decimal=6, strict=False): - """ - Check that masked arrays are almost equal. This requires the - masks to be identical, and the unmasked values to be almost - equal. - - Args: - - * a, b (array-like): - Two arrays to compare. - - Kwargs: - - * strict (bool): - If True, perform a complete mask and data array equality check. - If False (default), the data array equality considers only unmasked - elements. - - * decimal (int): - Equality tolerance level for - :meth:`numpy.testing.assert_array_almost_equal`, with the meaning - 'abs(desired-actual) < 0.5 * 10**(-decimal)' - - """ - self._assertMaskedArray( - np.testing.assert_array_almost_equal, a, b, strict, decimal=decimal - ) + assertMaskedArrayAlmostEqual = staticmethod( + assert_masked_array_almost_equal + ) def assertArrayAllClose(self, a, b, rtol=1.0e-7, atol=1.0e-8, **kwargs): """ diff --git a/lib/iris/tests/graphics/__init__.py b/lib/iris/tests/graphics/__init__.py index 2ef635128e..a083de3934 100755 --- a/lib/iris/tests/graphics/__init__.py +++ b/lib/iris/tests/graphics/__init__.py @@ -57,9 +57,9 @@ _lock = threading.Lock() #: Default perceptual hash size. -_HASH_SIZE = 16 +HASH_SIZE = 16 #: Default maximum perceptual hash hamming distance. -_HAMMING_DISTANCE = 2 +HAMMING_DISTANCE = 2 # Prefix for image test results (that aren't yet verified as good to add to # reference images) RESULT_PREFIX = "result-" @@ -135,7 +135,7 @@ def get_phash(input: Path) -> str: from PIL import Image import imagehash - return imagehash.phash(Image.open(input), hash_size=_HASH_SIZE) + return imagehash.phash(Image.open(input), hash_size=HASH_SIZE) def generate_repo_from_baselines(baseline_image_dir: Path) -> Dict[str, str]: @@ -220,7 +220,7 @@ def _create_missing(phash: str) -> None: # Calculate hamming distance vector for the result hash. distance = expected - phash - if distance > _HAMMING_DISTANCE: + if distance > HAMMING_DISTANCE: if dev_mode: _create_missing(phash) else: diff --git a/lib/iris/tests/graphics/recreate_imagerepo.py b/lib/iris/tests/graphics/recreate_imagerepo.py index 756e48688d..02ddaad2cb 100755 --- a/lib/iris/tests/graphics/recreate_imagerepo.py +++ b/lib/iris/tests/graphics/recreate_imagerepo.py @@ -29,9 +29,9 @@ def update_json(baseline_image_dir: Path, dry_run: bool = False): ) print(msg) else: - for key in set(repo.keys()) | set(suggested_repo.keys()): - old_val = repo.get(key, None) - new_val = suggested_repo.get(key, None) + for key in sorted(set(repo.keys()) | set(suggested_repo.keys())): + old_val = repo.get(key) + new_val = suggested_repo.get(key) if old_val is None: repo[key] = suggested_repo[key] print(key) diff --git a/lib/iris/tests/integration/concatenate/test_concatenate.py b/lib/iris/tests/integration/concatenate/test_concatenate.py index 4e3f453e0a..091ecd4378 100644 --- a/lib/iris/tests/integration/concatenate/test_concatenate.py +++ b/lib/iris/tests/integration/concatenate/test_concatenate.py @@ -33,7 +33,7 @@ def simple_1d_time_cubes(self, reftimes, coords_points): standard_name="air_temperature", units="K", ) - unit = cf_units.Unit(reftime, calendar="gregorian") + unit = cf_units.Unit(reftime, calendar="standard") coord = iris.coords.DimCoord( points=np.array(coord_points, dtype=np.float32), standard_name="time", @@ -68,7 +68,7 @@ def create_cube(self): ) height = iris.coords.AuxCoord([1.5], standard_name="height", units="m") t_unit = cf_units.Unit( - "hours since 1970-01-01 00:00:00", calendar="gregorian" + "hours since 1970-01-01 00:00:00", calendar="standard" ) time = iris.coords.DimCoord([0, 6], standard_name="time", units=t_unit) @@ -113,7 +113,7 @@ def create_cube(self): [1.5], standard_name="height", units="m" ) t_unit = cf_units.Unit( - "hours since 1970-01-01 00:00:00", calendar="gregorian" + "hours since 1970-01-01 00:00:00", calendar="standard" ) time = iris.coords.DimCoord([0, 6], standard_name="time", units=t_unit) @@ -156,7 +156,7 @@ def create_cube(self): [1.5], standard_name="height", units="m" ) t_unit = cf_units.Unit( - "hours since 1970-01-01 00:00:00", calendar="gregorian" + "hours since 1970-01-01 00:00:00", calendar="standard" ) time = iris.coords.DimCoord([0, 6], standard_name="time", units=t_unit) @@ -196,7 +196,7 @@ def setUp(self): # Time coord t_unit = cf_units.Unit( - "hours since 1970-01-01 00:00:00", calendar="gregorian" + "hours since 1970-01-01 00:00:00", calendar="standard" ) t_coord = iris.coords.DimCoord( [0, 6], standard_name="time", units=t_unit diff --git a/lib/iris/tests/integration/experimental/test_regrid_ProjectedUnstructured.py b/lib/iris/tests/integration/experimental/test_regrid_ProjectedUnstructured.py index 1ace02ea8a..742adc8c15 100644 --- a/lib/iris/tests/integration/experimental/test_regrid_ProjectedUnstructured.py +++ b/lib/iris/tests/integration/experimental/test_regrid_ProjectedUnstructured.py @@ -9,6 +9,8 @@ # importing anything else. import iris.tests as tests # isort:skip +import unittest + import cartopy.crs as ccrs from cf_units import Unit import numpy as np @@ -60,6 +62,9 @@ def test_nearest_sinusoidal(self): res[:, 0], (1, 73, 96), 299.99993826, 3.9223839688e-5 ) + @unittest.skip( + "Deprecated API and provenance of reference numbers unknown." + ) def test_nearest_gnomonic_uk_domain(self): crs = ccrs.Gnomonic(central_latitude=60.0) uk_grid = self.global_grid.intersection( diff --git a/lib/iris/tests/integration/merge/test_merge.py b/lib/iris/tests/integration/merge/test_merge.py index 8c221d7201..f5f92a7a7d 100644 --- a/lib/iris/tests/integration/merge/test_merge.py +++ b/lib/iris/tests/integration/merge/test_merge.py @@ -12,9 +12,7 @@ # before importing anything else. import iris.tests as tests # isort:skip -import numpy as np - -from iris.coords import AuxCoord, DimCoord +from iris.coords import DimCoord from iris.cube import Cube, CubeList @@ -35,30 +33,5 @@ def test_form_contiguous_dimcoord(self): self.assertArrayEqual(coord2.bounds, coord1.bounds[::-1, ::-1]) -class TestNaNs(tests.IrisTest): - def test_merge_nan_coords(self): - # Test that nan valued coordinates merge together. - cube1 = Cube(np.ones([3, 4]), "air_temperature", units="K") - coord1 = DimCoord([1, 2, 3], long_name="x") - coord2 = DimCoord([0, 1, 2, 3], long_name="y") - nan_coord1 = AuxCoord(np.nan, long_name="nan1") - nan_coord2 = AuxCoord([np.nan] * 4, long_name="nan2") - cube1.add_dim_coord(coord1, 0) - cube1.add_dim_coord(coord2, 1) - cube1.add_aux_coord(nan_coord1) - cube1.add_aux_coord(nan_coord2, 1) - cubes = CubeList(cube1.slices_over("x")) - cube2 = cubes.merge_cube() - - self.assertArrayEqual( - np.isnan(nan_coord1.points), - np.isnan(cube2.coord("nan1").points), - ) - self.assertArrayEqual( - np.isnan(nan_coord2.points), - np.isnan(cube2.coord("nan2").points), - ) - - if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/integration/plot/test_netcdftime.py b/lib/iris/tests/integration/plot/test_netcdftime.py index 9f0baeda35..d438c09bd5 100644 --- a/lib/iris/tests/integration/plot/test_netcdftime.py +++ b/lib/iris/tests/integration/plot/test_netcdftime.py @@ -4,7 +4,7 @@ # See COPYING and COPYING.LESSER in the root of the repository for full # licensing details. """ -Test plot of time coord with non-gregorian calendar. +Test plot of time coord with non-standard calendar. """ diff --git a/lib/iris/tests/integration/test_netcdf.py b/lib/iris/tests/integration/test_netcdf.py index ca8c4c7697..3feb637bf8 100644 --- a/lib/iris/tests/integration/test_netcdf.py +++ b/lib/iris/tests/integration/test_netcdf.py @@ -599,15 +599,15 @@ def test_load_datum_wkt(self): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertStringEqual(expected, actual) + self.assertMultiLineEqual(expected, actual) def test_no_load_datum_wkt(self): nc_path = tlc.cdl_to_nc(self.datum_wkt_cdl) - with self.assertWarnsRegexp("iris.FUTURE.datum_support"): + with self.assertWarnsRegex(FutureWarning, "iris.FUTURE.datum_support"): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertStringEqual(actual, "unknown") + self.assertMultiLineEqual(actual, "unknown") def test_load_datum_cf_var(self): expected = "OSGB 1936" @@ -616,15 +616,15 @@ def test_load_datum_cf_var(self): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertStringEqual(expected, actual) + self.assertMultiLineEqual(expected, actual) def test_no_load_datum_cf_var(self): nc_path = tlc.cdl_to_nc(self.datum_cf_var_cdl) - with self.assertWarnsRegexp("iris.FUTURE.datum_support"): + with self.assertWarnsRegex(FutureWarning, "iris.FUTURE.datum_support"): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertStringEqual(actual, "unknown") + self.assertMultiLineEqual(actual, "unknown") def test_save_datum(self): expected = "OSGB 1936" @@ -663,7 +663,7 @@ def test_save_datum(self): test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertStringEqual(expected, actual) + self.assertMultiLineEqual(expected, actual) def _get_scale_factor_add_offset(cube, datatype): diff --git a/lib/iris/tests/integration/test_pp.py b/lib/iris/tests/integration/test_pp.py index db2113025d..e654694aa7 100644 --- a/lib/iris/tests/integration/test_pp.py +++ b/lib/iris/tests/integration/test_pp.py @@ -683,7 +683,7 @@ def test_as_pairs(self): class TestSaveLBPROC(tests.IrisTest): def create_cube(self, longitude_coord="longitude"): cube = Cube(np.zeros((2, 3, 4))) - tunit = Unit("days since epoch", calendar="gregorian") + tunit = Unit("days since epoch", calendar="standard") tcoord = DimCoord(np.arange(2), standard_name="time", units=tunit) xcoord = DimCoord( np.arange(3), standard_name=longitude_coord, units="degrees" diff --git a/lib/iris/tests/results/COLPEX/small_colpex_theta_p_alt.cml b/lib/iris/tests/results/COLPEX/small_colpex_theta_p_alt.cml index 5bba278059..da315c36af 100644 --- a/lib/iris/tests/results/COLPEX/small_colpex_theta_p_alt.cml +++ b/lib/iris/tests/results/COLPEX/small_colpex_theta_p_alt.cml @@ -400,7 +400,7 @@ 0.666666666686, 0.833333333314, 1.0]" shape="(6,)" standard_name="forecast_period" units="Unit('hours')" value_type="float64"/> - + + 347926.666667, 347926.833333, 347927.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -923,7 +923,7 @@ 0.666666666686, 0.833333333314, 1.0]" shape="(6,)" standard_name="forecast_period" units="Unit('hours')" value_type="float64"/> - + + 347926.666667, 347926.833333, 347927.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -1057,7 +1057,7 @@ - + + diff --git a/lib/iris/tests/results/FF/air_temperature_1.cml b/lib/iris/tests/results/FF/air_temperature_1.cml index 267aa88d23..043b9acc16 100644 --- a/lib/iris/tests/results/FF/air_temperature_1.cml +++ b/lib/iris/tests/results/FF/air_temperature_1.cml @@ -11,7 +11,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/lib/iris/tests/results/FF/air_temperature_2.cml b/lib/iris/tests/results/FF/air_temperature_2.cml index 307c58fe72..200a80b54a 100644 --- a/lib/iris/tests/results/FF/air_temperature_2.cml +++ b/lib/iris/tests/results/FF/air_temperature_2.cml @@ -11,7 +11,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/lib/iris/tests/results/FF/soil_temperature_1.cml b/lib/iris/tests/results/FF/soil_temperature_1.cml index e555a3f5b9..57303636c1 100644 --- a/lib/iris/tests/results/FF/soil_temperature_1.cml +++ b/lib/iris/tests/results/FF/soil_temperature_1.cml @@ -11,7 +11,7 @@ - + + diff --git a/lib/iris/tests/results/FF/surface_altitude_1.cml b/lib/iris/tests/results/FF/surface_altitude_1.cml index 27cfad3d09..2669624d37 100644 --- a/lib/iris/tests/results/FF/surface_altitude_1.cml +++ b/lib/iris/tests/results/FF/surface_altitude_1.cml @@ -11,7 +11,7 @@ - + + diff --git a/lib/iris/tests/results/abf/load.cml b/lib/iris/tests/results/abf/load.cml index e470cbebf3..e7954ab229 100644 --- a/lib/iris/tests/results/abf/load.cml +++ b/lib/iris/tests/results/abf/load.cml @@ -30,7 +30,7 @@ - + diff --git a/lib/iris/tests/results/analysis/areaweights_original.cml b/lib/iris/tests/results/analysis/areaweights_original.cml index 3c33ef500a..651bb648dd 100644 --- a/lib/iris/tests/results/analysis/areaweights_original.cml +++ b/lib/iris/tests/results/analysis/areaweights_original.cml @@ -10,7 +10,7 @@ - + @@ -26,7 +26,7 @@ - + diff --git a/lib/iris/tests/results/analysis/gmean_latitude.cml b/lib/iris/tests/results/analysis/gmean_latitude.cml index ebe22c54f3..26b7fdc8af 100644 --- a/lib/iris/tests/results/analysis/gmean_latitude.cml +++ b/lib/iris/tests/results/analysis/gmean_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/gmean_latitude_longitude.cml b/lib/iris/tests/results/analysis/gmean_latitude_longitude.cml index 3cd6a93948..94ed36ac88 100644 --- a/lib/iris/tests/results/analysis/gmean_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/gmean_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/gmean_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/gmean_latitude_longitude_1call.cml index cc7b3133e0..1db977312b 100644 --- a/lib/iris/tests/results/analysis/gmean_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/gmean_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/hmean_latitude.cml b/lib/iris/tests/results/analysis/hmean_latitude.cml index d953f0e4d9..70e3fcb540 100644 --- a/lib/iris/tests/results/analysis/hmean_latitude.cml +++ b/lib/iris/tests/results/analysis/hmean_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/hmean_latitude_longitude.cml b/lib/iris/tests/results/analysis/hmean_latitude_longitude.cml index 43700b083c..f762fd643b 100644 --- a/lib/iris/tests/results/analysis/hmean_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/hmean_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/hmean_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/hmean_latitude_longitude_1call.cml index e17383ff64..369dca3203 100644 --- a/lib/iris/tests/results/analysis/hmean_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/hmean_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/max_latitude.cml b/lib/iris/tests/results/analysis/max_latitude.cml index faa54fff8a..89542d27d3 100644 --- a/lib/iris/tests/results/analysis/max_latitude.cml +++ b/lib/iris/tests/results/analysis/max_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/max_latitude_longitude.cml b/lib/iris/tests/results/analysis/max_latitude_longitude.cml index 8437e8f4a1..7d24ca7f14 100644 --- a/lib/iris/tests/results/analysis/max_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/max_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/max_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/max_latitude_longitude_1call.cml index 5b6504dfb1..b4d1e0349c 100644 --- a/lib/iris/tests/results/analysis/max_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/max_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/mean_latitude.cml b/lib/iris/tests/results/analysis/mean_latitude.cml index fcf2ef55be..80921e762d 100644 --- a/lib/iris/tests/results/analysis/mean_latitude.cml +++ b/lib/iris/tests/results/analysis/mean_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/mean_latitude_longitude.cml b/lib/iris/tests/results/analysis/mean_latitude_longitude.cml index 5cb139be1a..6ac9400a3a 100644 --- a/lib/iris/tests/results/analysis/mean_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/mean_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/mean_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/mean_latitude_longitude_1call.cml index 573fa1c694..affcf07c07 100644 --- a/lib/iris/tests/results/analysis/mean_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/mean_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/median_latitude.cml b/lib/iris/tests/results/analysis/median_latitude.cml index 49006c9592..bbf3875688 100644 --- a/lib/iris/tests/results/analysis/median_latitude.cml +++ b/lib/iris/tests/results/analysis/median_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/median_latitude_longitude.cml b/lib/iris/tests/results/analysis/median_latitude_longitude.cml index 49ec42b391..5663f6d65f 100644 --- a/lib/iris/tests/results/analysis/median_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/median_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/median_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/median_latitude_longitude_1call.cml index 036c6bb2f9..c0c0d7c46b 100644 --- a/lib/iris/tests/results/analysis/median_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/median_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/min_latitude.cml b/lib/iris/tests/results/analysis/min_latitude.cml index 34a2dc5548..bf20be30a9 100644 --- a/lib/iris/tests/results/analysis/min_latitude.cml +++ b/lib/iris/tests/results/analysis/min_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/min_latitude_longitude.cml b/lib/iris/tests/results/analysis/min_latitude_longitude.cml index 76c7e96bce..3792645582 100644 --- a/lib/iris/tests/results/analysis/min_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/min_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/min_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/min_latitude_longitude_1call.cml index 6b484eb591..b43231b7e6 100644 --- a/lib/iris/tests/results/analysis/min_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/min_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/original.cml b/lib/iris/tests/results/analysis/original.cml index 23129095b6..414de1b6b5 100644 --- a/lib/iris/tests/results/analysis/original.cml +++ b/lib/iris/tests/results/analysis/original.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/original_common.cml b/lib/iris/tests/results/analysis/original_common.cml index c1759c12bd..bbfa48d7d8 100644 --- a/lib/iris/tests/results/analysis/original_common.cml +++ b/lib/iris/tests/results/analysis/original_common.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/original_hmean.cml b/lib/iris/tests/results/analysis/original_hmean.cml index 952cede1c2..bdc145022c 100644 --- a/lib/iris/tests/results/analysis/original_hmean.cml +++ b/lib/iris/tests/results/analysis/original_hmean.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/linear_masked_altitude.cml b/lib/iris/tests/results/analysis/regrid/linear_masked_altitude.cml index dc1fee2f2b..1ac69490b4 100644 --- a/lib/iris/tests/results/analysis/regrid/linear_masked_altitude.cml +++ b/lib/iris/tests/results/analysis/regrid/linear_masked_altitude.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/linear_partial_overlap.cml b/lib/iris/tests/results/analysis/regrid/linear_partial_overlap.cml index 6fdbe7df00..eb9adb4aef 100644 --- a/lib/iris/tests/results/analysis/regrid/linear_partial_overlap.cml +++ b/lib/iris/tests/results/analysis/regrid/linear_partial_overlap.cml @@ -99,7 +99,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/linear_subset.cml b/lib/iris/tests/results/analysis/regrid/linear_subset.cml index d9b80dd86b..9bd62287fe 100644 --- a/lib/iris/tests/results/analysis/regrid/linear_subset.cml +++ b/lib/iris/tests/results/analysis/regrid/linear_subset.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/linear_subset_masked_1.cml b/lib/iris/tests/results/analysis/regrid/linear_subset_masked_1.cml index d9b80dd86b..9bd62287fe 100644 --- a/lib/iris/tests/results/analysis/regrid/linear_subset_masked_1.cml +++ b/lib/iris/tests/results/analysis/regrid/linear_subset_masked_1.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/linear_subset_masked_2.cml b/lib/iris/tests/results/analysis/regrid/linear_subset_masked_2.cml index d9b80dd86b..9bd62287fe 100644 --- a/lib/iris/tests/results/analysis/regrid/linear_subset_masked_2.cml +++ b/lib/iris/tests/results/analysis/regrid/linear_subset_masked_2.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/nearest_masked_altitude.cml b/lib/iris/tests/results/analysis/regrid/nearest_masked_altitude.cml index b2aec5e891..a1cff2363e 100644 --- a/lib/iris/tests/results/analysis/regrid/nearest_masked_altitude.cml +++ b/lib/iris/tests/results/analysis/regrid/nearest_masked_altitude.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/nearest_partial_overlap.cml b/lib/iris/tests/results/analysis/regrid/nearest_partial_overlap.cml index f6647aa426..98a0b6b805 100644 --- a/lib/iris/tests/results/analysis/regrid/nearest_partial_overlap.cml +++ b/lib/iris/tests/results/analysis/regrid/nearest_partial_overlap.cml @@ -99,7 +99,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/nearest_subset.cml b/lib/iris/tests/results/analysis/regrid/nearest_subset.cml index 7e12c9be60..a704cbecbb 100644 --- a/lib/iris/tests/results/analysis/regrid/nearest_subset.cml +++ b/lib/iris/tests/results/analysis/regrid/nearest_subset.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_1.cml b/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_1.cml index 7e12c9be60..a704cbecbb 100644 --- a/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_1.cml +++ b/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_1.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_2.cml b/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_2.cml index 7e12c9be60..a704cbecbb 100644 --- a/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_2.cml +++ b/lib/iris/tests/results/analysis/regrid/nearest_subset_masked_2.cml @@ -107,7 +107,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/regrid/no_overlap.cml b/lib/iris/tests/results/analysis/regrid/no_overlap.cml index 6aa4d218f8..da2f03f1ee 100644 --- a/lib/iris/tests/results/analysis/regrid/no_overlap.cml +++ b/lib/iris/tests/results/analysis/regrid/no_overlap.cml @@ -99,7 +99,7 @@ + 347921.666667, 347921.833333]" shape="(5,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/rms_latitude.cml b/lib/iris/tests/results/analysis/rms_latitude.cml index e409daed2d..d4b1428fb2 100644 --- a/lib/iris/tests/results/analysis/rms_latitude.cml +++ b/lib/iris/tests/results/analysis/rms_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/rms_latitude_longitude.cml b/lib/iris/tests/results/analysis/rms_latitude_longitude.cml index 9bdc53fbad..4293087847 100644 --- a/lib/iris/tests/results/analysis/rms_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/rms_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/rms_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/rms_latitude_longitude_1call.cml index 89a593d122..9ca1d23b42 100644 --- a/lib/iris/tests/results/analysis/rms_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/rms_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/std_dev_latitude.cml b/lib/iris/tests/results/analysis/std_dev_latitude.cml index 154d5ef587..a45aefeff4 100644 --- a/lib/iris/tests/results/analysis/std_dev_latitude.cml +++ b/lib/iris/tests/results/analysis/std_dev_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/std_dev_latitude_longitude.cml b/lib/iris/tests/results/analysis/std_dev_latitude_longitude.cml index 770ef9a35a..95e8e3694d 100644 --- a/lib/iris/tests/results/analysis/std_dev_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/std_dev_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/std_dev_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/std_dev_latitude_longitude_1call.cml index a5ce049ca5..f91f6005b7 100644 --- a/lib/iris/tests/results/analysis/std_dev_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/std_dev_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/sum_latitude.cml b/lib/iris/tests/results/analysis/sum_latitude.cml index 943aa9312f..fbb8460fd8 100644 --- a/lib/iris/tests/results/analysis/sum_latitude.cml +++ b/lib/iris/tests/results/analysis/sum_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/sum_latitude_longitude.cml b/lib/iris/tests/results/analysis/sum_latitude_longitude.cml index 2eff41339b..cb992f3b9d 100644 --- a/lib/iris/tests/results/analysis/sum_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/sum_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/sum_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/sum_latitude_longitude_1call.cml index a2a46d2ba8..6171dc516b 100644 --- a/lib/iris/tests/results/analysis/sum_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/sum_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/variance_latitude.cml b/lib/iris/tests/results/analysis/variance_latitude.cml index 437587b00d..5b55731396 100644 --- a/lib/iris/tests/results/analysis/variance_latitude.cml +++ b/lib/iris/tests/results/analysis/variance_latitude.cml @@ -11,7 +11,7 @@ - + @@ -27,7 +27,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/variance_latitude_longitude.cml b/lib/iris/tests/results/analysis/variance_latitude_longitude.cml index 391ab8834e..359e40ef8a 100644 --- a/lib/iris/tests/results/analysis/variance_latitude_longitude.cml +++ b/lib/iris/tests/results/analysis/variance_latitude_longitude.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/variance_latitude_longitude_1call.cml b/lib/iris/tests/results/analysis/variance_latitude_longitude_1call.cml index 535468acfc..0345eac77b 100644 --- a/lib/iris/tests/results/analysis/variance_latitude_longitude_1call.cml +++ b/lib/iris/tests/results/analysis/variance_latitude_longitude_1call.cml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ + 319544.0, 319545.0]" shape="(10,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/analysis/weighted_mean_original.cml b/lib/iris/tests/results/analysis/weighted_mean_original.cml index 2df84a8606..a69e633e26 100644 --- a/lib/iris/tests/results/analysis/weighted_mean_original.cml +++ b/lib/iris/tests/results/analysis/weighted_mean_original.cml @@ -10,7 +10,7 @@ - + - + diff --git a/lib/iris/tests/results/categorisation/customcheck.cml b/lib/iris/tests/results/categorisation/customcheck.cml index d6dcc7179d..476a1c56ef 100644 --- a/lib/iris/tests/results/categorisation/customcheck.cml +++ b/lib/iris/tests/results/categorisation/customcheck.cml @@ -19,7 +19,7 @@ + 513, 540, 567, 594]" shape="(23,)" standard_name="time" units="Unit('days since 1970-01-01 00:00:00', calendar='standard')" value_type="int32"/> diff --git a/lib/iris/tests/results/categorisation/quickcheck.cml b/lib/iris/tests/results/categorisation/quickcheck.cml index f64c70350f..b8f3904ad1 100644 --- a/lib/iris/tests/results/categorisation/quickcheck.cml +++ b/lib/iris/tests/results/categorisation/quickcheck.cml @@ -68,7 +68,7 @@ + 513, 540, 567, 594]" shape="(23,)" standard_name="time" units="Unit('days since 1970-01-01 00:00:00', calendar='standard')" value_type="int32"/> diff --git a/lib/iris/tests/results/cdm/extract/lat_eq_10.cml b/lib/iris/tests/results/cdm/extract/lat_eq_10.cml index f10c0be37c..e7213fc7bd 100644 --- a/lib/iris/tests/results/cdm/extract/lat_eq_10.cml +++ b/lib/iris/tests/results/cdm/extract/lat_eq_10.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cdm/extract/lat_gt_10.cml b/lib/iris/tests/results/cdm/extract/lat_gt_10.cml index e0d138f327..3ffbbf89e5 100644 --- a/lib/iris/tests/results/cdm/extract/lat_gt_10.cml +++ b/lib/iris/tests/results/cdm/extract/lat_gt_10.cml @@ -11,7 +11,7 @@ - + - + diff --git a/lib/iris/tests/results/cdm/extract/lat_gt_10_and_lon_ge_10.cml b/lib/iris/tests/results/cdm/extract/lat_gt_10_and_lon_ge_10.cml index 3b435e9ceb..7091aee748 100644 --- a/lib/iris/tests/results/cdm/extract/lat_gt_10_and_lon_ge_10.cml +++ b/lib/iris/tests/results/cdm/extract/lat_gt_10_and_lon_ge_10.cml @@ -11,7 +11,7 @@ - + - + diff --git a/lib/iris/tests/results/cdm/masked_cube.cml b/lib/iris/tests/results/cdm/masked_cube.cml index a38340913e..dcfa8c062f 100644 --- a/lib/iris/tests/results/cdm/masked_cube.cml +++ b/lib/iris/tests/results/cdm/masked_cube.cml @@ -10,7 +10,7 @@ - + + 1000.0, 1006.0]" shape="(8,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/constrained_load/all_10_load_match.cml b/lib/iris/tests/results/constrained_load/all_10_load_match.cml index 6a582f9d67..0712af20fa 100644 --- a/lib/iris/tests/results/constrained_load/all_10_load_match.cml +++ b/lib/iris/tests/results/constrained_load/all_10_load_match.cml @@ -11,7 +11,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -113,7 +113,7 @@ - + @@ -144,7 +144,7 @@ - + @@ -165,7 +165,7 @@ - + - + diff --git a/lib/iris/tests/results/constrained_load/all_ml_10_22_load_match.cml b/lib/iris/tests/results/constrained_load/all_ml_10_22_load_match.cml index 458474f98a..20971021ac 100644 --- a/lib/iris/tests/results/constrained_load/all_ml_10_22_load_match.cml +++ b/lib/iris/tests/results/constrained_load/all_ml_10_22_load_match.cml @@ -11,7 +11,7 @@ - + @@ -43,7 +43,7 @@ [0.222443, 0.177555]]" id="a5c170db" long_name="sigma" points="[0.784571, 0.199878]" shape="(2,)" units="Unit('1')" value_type="float32"/> - + @@ -64,7 +64,7 @@ - + @@ -96,7 +96,7 @@ [0.222443, 0.177555]]" id="a5c170db" long_name="sigma" points="[0.784571, 0.199878]" shape="(2,)" units="Unit('1')" value_type="float32"/> - + @@ -117,7 +117,7 @@ - + @@ -150,7 +150,7 @@ [0.246215, 0.199878]]" id="a5c170db" long_name="sigma" points="[0.803914, 0.222443]" shape="(2,)" units="Unit('1')" value_type="float32"/> - + @@ -171,7 +171,7 @@ - + - + diff --git a/lib/iris/tests/results/constrained_load/attribute_constraint.cml b/lib/iris/tests/results/constrained_load/attribute_constraint.cml index 31714035fa..664dc943bc 100644 --- a/lib/iris/tests/results/constrained_load/attribute_constraint.cml +++ b/lib/iris/tests/results/constrained_load/attribute_constraint.cml @@ -12,7 +12,7 @@ - + @@ -131,7 +131,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_match.cml b/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_match.cml index bbafc31987..44e7d077df 100644 --- a/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_match.cml @@ -11,7 +11,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -115,7 +115,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(11,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_strict.cml index bbafc31987..44e7d077df 100644 --- a/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_10_and_theta_level_gt_30_le_3_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -115,7 +115,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(11,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_10_load_match.cml b/lib/iris/tests/results/constrained_load/theta_10_load_match.cml index 2e5005d042..e2852d0151 100644 --- a/lib/iris/tests/results/constrained_load/theta_10_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_10_load_match.cml @@ -11,7 +11,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/lib/iris/tests/results/constrained_load/theta_10_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_10_load_strict.cml index 2e5005d042..e2852d0151 100644 --- a/lib/iris/tests/results/constrained_load/theta_10_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_10_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/lib/iris/tests/results/constrained_load/theta_and_all_10_load_match.cml b/lib/iris/tests/results/constrained_load/theta_and_all_10_load_match.cml index 40bb37f3ab..772929b0da 100644 --- a/lib/iris/tests/results/constrained_load/theta_and_all_10_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_and_all_10_load_match.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -151,7 +151,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -232,7 +232,7 @@ - + @@ -253,7 +253,7 @@ - + @@ -284,7 +284,7 @@ - + @@ -305,7 +305,7 @@ - + - + diff --git a/lib/iris/tests/results/constrained_load/theta_and_theta_10_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_and_theta_10_load_strict.cml index 03fed4e61b..0e23de090c 100644 --- a/lib/iris/tests/results/constrained_load/theta_and_theta_10_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_and_theta_10_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -151,7 +151,7 @@ - + @@ -181,7 +181,7 @@ - + diff --git a/lib/iris/tests/results/constrained_load/theta_and_theta_load_match.cml b/lib/iris/tests/results/constrained_load/theta_and_theta_load_match.cml index eadbe8f365..a175652c30 100644 --- a/lib/iris/tests/results/constrained_load/theta_and_theta_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_and_theta_load_match.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -151,7 +151,7 @@ - + @@ -270,7 +270,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_and_theta_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_and_theta_load_strict.cml index eadbe8f365..a175652c30 100644 --- a/lib/iris/tests/results/constrained_load/theta_and_theta_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_and_theta_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -151,7 +151,7 @@ - + @@ -270,7 +270,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_match.cml b/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_match.cml index 77534b9b55..0048a742a6 100644 --- a/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_match.cml @@ -11,7 +11,7 @@ - + @@ -64,7 +64,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(11,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_strict.cml index 77534b9b55..0048a742a6 100644 --- a/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_gt_30_le_3_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -64,7 +64,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(11,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_lat_30_load_match.cml b/lib/iris/tests/results/constrained_load/theta_lat_30_load_match.cml index f6727427a1..e24937854d 100644 --- a/lib/iris/tests/results/constrained_load/theta_lat_30_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_lat_30_load_match.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_lat_30_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_lat_30_load_strict.cml index f6727427a1..e24937854d 100644 --- a/lib/iris/tests/results/constrained_load/theta_lat_30_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_lat_30_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_match.cml b/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_match.cml index daef7ba9dc..218bdd6b1c 100644 --- a/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_match.cml @@ -11,7 +11,7 @@ - + - + diff --git a/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_strict.cml index daef7ba9dc..218bdd6b1c 100644 --- a/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_lat_gt_30_load_strict.cml @@ -11,7 +11,7 @@ - + - + diff --git a/lib/iris/tests/results/constrained_load/theta_load_match.cml b/lib/iris/tests/results/constrained_load/theta_load_match.cml index 293e40cc3a..0e5b02be51 100644 --- a/lib/iris/tests/results/constrained_load/theta_load_match.cml +++ b/lib/iris/tests/results/constrained_load/theta_load_match.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/constrained_load/theta_load_strict.cml b/lib/iris/tests/results/constrained_load/theta_load_strict.cml index 293e40cc3a..0e5b02be51 100644 --- a/lib/iris/tests/results/constrained_load/theta_load_strict.cml +++ b/lib/iris/tests/results/constrained_load/theta_load_strict.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/coord_api/str_repr/dim_time_str.txt b/lib/iris/tests/results/coord_api/str_repr/dim_time_str.txt index 6b95b57215..410da3613a 100644 --- a/lib/iris/tests/results/coord_api/str_repr/dim_time_str.txt +++ b/lib/iris/tests/results/coord_api/str_repr/dim_time_str.txt @@ -1,4 +1,4 @@ -DimCoord : time / (hours since 1970-01-01 00:00:00, gregorian calendar) +DimCoord : time / (hours since 1970-01-01 00:00:00, standard calendar) points: [ 2009-09-09 17:10:00, 2009-09-09 17:20:00, 2009-09-09 17:30:00, 2009-09-09 17:40:00, 2009-09-09 17:50:00, 2009-09-09 18:00:00] diff --git a/lib/iris/tests/results/cube_collapsed/latitude_longitude_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/latitude_longitude_dual_stage.cml index 458b9bf908..463339e5bc 100644 --- a/lib/iris/tests/results/cube_collapsed/latitude_longitude_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/latitude_longitude_dual_stage.cml @@ -82,7 +82,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/latitude_longitude_single_stage.cml b/lib/iris/tests/results/cube_collapsed/latitude_longitude_single_stage.cml index a2f12b0b27..a91ea4ce5c 100644 --- a/lib/iris/tests/results/cube_collapsed/latitude_longitude_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/latitude_longitude_single_stage.cml @@ -82,7 +82,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_dual_stage.cml index 60539d5960..f963658910 100644 --- a/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_dual_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_single_stage.cml b/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_single_stage.cml index 466d0dd8cd..195757a417 100644 --- a/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/latitude_model_level_number_single_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/latitude_time_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/latitude_time_dual_stage.cml index 12bf9270d1..c63c260d25 100644 --- a/lib/iris/tests/results/cube_collapsed/latitude_time_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/latitude_time_dual_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/latitude_time_single_stage.cml b/lib/iris/tests/results/cube_collapsed/latitude_time_single_stage.cml index 9d1070140b..d6cc708aa1 100644 --- a/lib/iris/tests/results/cube_collapsed/latitude_time_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/latitude_time_single_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/longitude_latitude_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/longitude_latitude_dual_stage.cml index 4cd9da34f0..23739a1ac5 100644 --- a/lib/iris/tests/results/cube_collapsed/longitude_latitude_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/longitude_latitude_dual_stage.cml @@ -82,7 +82,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/longitude_latitude_single_stage.cml b/lib/iris/tests/results/cube_collapsed/longitude_latitude_single_stage.cml index dd87dc175b..817b855512 100644 --- a/lib/iris/tests/results/cube_collapsed/longitude_latitude_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/longitude_latitude_single_stage.cml @@ -82,7 +82,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_dual_stage.cml index 16ea40c33e..29d59ce111 100644 --- a/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_dual_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_single_stage.cml b/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_single_stage.cml index b01ede7936..e99d57b816 100644 --- a/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/longitude_model_level_number_single_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/longitude_time_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/longitude_time_dual_stage.cml index 8d38bb748c..8e57ec7258 100644 --- a/lib/iris/tests/results/cube_collapsed/longitude_time_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/longitude_time_dual_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/longitude_time_single_stage.cml b/lib/iris/tests/results/cube_collapsed/longitude_time_single_stage.cml index f4589831a8..67b706e0ae 100644 --- a/lib/iris/tests/results/cube_collapsed/longitude_time_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/longitude_time_single_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_dual_stage.cml index 138e0207c7..d9c1b2a35c 100644 --- a/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_dual_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_single_stage.cml b/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_single_stage.cml index 0e2cf8ef23..ceafb3fc67 100644 --- a/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/model_level_number_latitude_single_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_dual_stage.cml index bbc8272c65..e5090a3572 100644 --- a/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_dual_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_single_stage.cml b/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_single_stage.cml index ba5cd7a171..9e8bdebd4a 100644 --- a/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/model_level_number_longitude_single_stage.cml @@ -44,7 +44,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/model_level_number_time_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/model_level_number_time_dual_stage.cml index b835be4057..a4e0cc1445 100644 --- a/lib/iris/tests/results/cube_collapsed/model_level_number_time_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/model_level_number_time_dual_stage.cml @@ -50,7 +50,7 @@ - + diff --git a/lib/iris/tests/results/cube_collapsed/model_level_number_time_single_stage.cml b/lib/iris/tests/results/cube_collapsed/model_level_number_time_single_stage.cml index 93196268e7..d442637062 100644 --- a/lib/iris/tests/results/cube_collapsed/model_level_number_time_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/model_level_number_time_single_stage.cml @@ -50,7 +50,7 @@ - + diff --git a/lib/iris/tests/results/cube_collapsed/original.cml b/lib/iris/tests/results/cube_collapsed/original.cml index 10a81f21d2..4bc6553dba 100644 --- a/lib/iris/tests/results/cube_collapsed/original.cml +++ b/lib/iris/tests/results/cube_collapsed/original.cml @@ -96,7 +96,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_collapsed/time_latitude_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/time_latitude_dual_stage.cml index a4f2cc6084..788d0d8029 100644 --- a/lib/iris/tests/results/cube_collapsed/time_latitude_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/time_latitude_dual_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/time_latitude_single_stage.cml b/lib/iris/tests/results/cube_collapsed/time_latitude_single_stage.cml index 885328a856..b9b74c6b6d 100644 --- a/lib/iris/tests/results/cube_collapsed/time_latitude_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/time_latitude_single_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/time_longitude_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/time_longitude_dual_stage.cml index 273ad909d9..84b4fea150 100644 --- a/lib/iris/tests/results/cube_collapsed/time_longitude_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/time_longitude_dual_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/time_longitude_single_stage.cml b/lib/iris/tests/results/cube_collapsed/time_longitude_single_stage.cml index c2e2993874..128d29a281 100644 --- a/lib/iris/tests/results/cube_collapsed/time_longitude_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/time_longitude_single_stage.cml @@ -88,7 +88,7 @@ 0.0, 0.0]" shape="(70,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_collapsed/time_model_level_number_dual_stage.cml b/lib/iris/tests/results/cube_collapsed/time_model_level_number_dual_stage.cml index 4d6e85f8a8..8c206fe840 100644 --- a/lib/iris/tests/results/cube_collapsed/time_model_level_number_dual_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/time_model_level_number_dual_stage.cml @@ -50,7 +50,7 @@ - + diff --git a/lib/iris/tests/results/cube_collapsed/time_model_level_number_single_stage.cml b/lib/iris/tests/results/cube_collapsed/time_model_level_number_single_stage.cml index 8f7ccf9b8a..08dc52fca2 100644 --- a/lib/iris/tests/results/cube_collapsed/time_model_level_number_single_stage.cml +++ b/lib/iris/tests/results/cube_collapsed/time_model_level_number_single_stage.cml @@ -50,7 +50,7 @@ - + diff --git a/lib/iris/tests/results/cube_collapsed/triple_collapse_lat_ml_pt.cml b/lib/iris/tests/results/cube_collapsed/triple_collapse_lat_ml_pt.cml index 33b35b7eaa..5fae922867 100644 --- a/lib/iris/tests/results/cube_collapsed/triple_collapse_lat_ml_pt.cml +++ b/lib/iris/tests/results/cube_collapsed/triple_collapse_lat_ml_pt.cml @@ -43,7 +43,7 @@ - + diff --git a/lib/iris/tests/results/cube_collapsed/triple_collapse_ml_pt_lon.cml b/lib/iris/tests/results/cube_collapsed/triple_collapse_ml_pt_lon.cml index c3db78bd9e..454bd29a18 100644 --- a/lib/iris/tests/results/cube_collapsed/triple_collapse_ml_pt_lon.cml +++ b/lib/iris/tests/results/cube_collapsed/triple_collapse_ml_pt_lon.cml @@ -43,7 +43,7 @@ - + diff --git a/lib/iris/tests/results/cube_io/pickling/cubelist.cml b/lib/iris/tests/results/cube_io/pickling/cubelist.cml index 6cebe384aa..eb839e36e4 100644 --- a/lib/iris/tests/results/cube_io/pickling/cubelist.cml +++ b/lib/iris/tests/results/cube_io/pickling/cubelist.cml @@ -400,7 +400,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="forecast_reference_time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -528,7 +528,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="forecast_reference_time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_io/pickling/single_cube.cml b/lib/iris/tests/results/cube_io/pickling/single_cube.cml index 2cd3dbb3cb..a025713766 100644 --- a/lib/iris/tests/results/cube_io/pickling/single_cube.cml +++ b/lib/iris/tests/results/cube_io/pickling/single_cube.cml @@ -400,7 +400,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="forecast_reference_time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/cube_io/pickling/theta.cml b/lib/iris/tests/results/cube_io/pickling/theta.cml index 39ee6aecfd..6c69f6ed54 100644 --- a/lib/iris/tests/results/cube_io/pickling/theta.cml +++ b/lib/iris/tests/results/cube_io/pickling/theta.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/cube_io/pp/load/global.cml b/lib/iris/tests/results/cube_io/pp/load/global.cml index 2df84a8606..a69e633e26 100644 --- a/lib/iris/tests/results/cube_io/pp/load/global.cml +++ b/lib/iris/tests/results/cube_io/pp/load/global.cml @@ -10,7 +10,7 @@ - + - + diff --git a/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing1.cml b/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing1.cml index fc387bb663..f674c30121 100644 --- a/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing1.cml +++ b/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing1.cml @@ -11,7 +11,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing2.cml b/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing2.cml index 9e5b5a57db..b1bf424a93 100644 --- a/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing2.cml +++ b/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing2.cml @@ -11,7 +11,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing3.cml b/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing3.cml index 061255bbe4..50fd683cb3 100644 --- a/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing3.cml +++ b/lib/iris/tests/results/cube_slice/real_data_dual_tuple_indexing3.cml @@ -11,7 +11,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/lib/iris/tests/results/cube_slice/real_empty_data_indexing.cml b/lib/iris/tests/results/cube_slice/real_empty_data_indexing.cml index 2f899b333e..1563dce74d 100644 --- a/lib/iris/tests/results/cube_slice/real_empty_data_indexing.cml +++ b/lib/iris/tests/results/cube_slice/real_empty_data_indexing.cml @@ -11,7 +11,7 @@ - + @@ -25,7 +25,7 @@ - + diff --git a/lib/iris/tests/results/cube_to_pp/no_forecast_period.cml b/lib/iris/tests/results/cube_to_pp/no_forecast_period.cml index 1c1e58c02b..5b7d800716 100644 --- a/lib/iris/tests/results/cube_to_pp/no_forecast_period.cml +++ b/lib/iris/tests/results/cube_to_pp/no_forecast_period.cml @@ -3,7 +3,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/lib/iris/tests/results/cube_to_pp/no_forecast_time.cml b/lib/iris/tests/results/cube_to_pp/no_forecast_time.cml index 02d380a097..edf4392d30 100644 --- a/lib/iris/tests/results/cube_to_pp/no_forecast_time.cml +++ b/lib/iris/tests/results/cube_to_pp/no_forecast_time.cml @@ -13,7 +13,7 @@ - + diff --git a/lib/iris/tests/results/derived/column.cml b/lib/iris/tests/results/derived/column.cml index e4402b4e4d..827214dafa 100644 --- a/lib/iris/tests/results/derived/column.cml +++ b/lib/iris/tests/results/derived/column.cml @@ -111,7 +111,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/derived/no_orog.cml b/lib/iris/tests/results/derived/no_orog.cml index ec0ffdd5ff..844373675e 100644 --- a/lib/iris/tests/results/derived/no_orog.cml +++ b/lib/iris/tests/results/derived/no_orog.cml @@ -136,7 +136,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/derived/removed_derived_coord.cml b/lib/iris/tests/results/derived/removed_derived_coord.cml index 12feb2b643..5175d88875 100644 --- a/lib/iris/tests/results/derived/removed_derived_coord.cml +++ b/lib/iris/tests/results/derived/removed_derived_coord.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/derived/removed_orog.cml b/lib/iris/tests/results/derived/removed_orog.cml index 4c30ec69bc..982e38fd1e 100644 --- a/lib/iris/tests/results/derived/removed_orog.cml +++ b/lib/iris/tests/results/derived/removed_orog.cml @@ -122,7 +122,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/derived/removed_sigma.cml b/lib/iris/tests/results/derived/removed_sigma.cml index ea34680b7d..3908c22188 100644 --- a/lib/iris/tests/results/derived/removed_sigma.cml +++ b/lib/iris/tests/results/derived/removed_sigma.cml @@ -462,7 +462,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/derived/transposed.cml b/lib/iris/tests/results/derived/transposed.cml index eef077d774..c44857bd61 100644 --- a/lib/iris/tests/results/derived/transposed.cml +++ b/lib/iris/tests/results/derived/transposed.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/experimental/analysis/interpolate/LinearInterpolator/orthogonal_cube_with_factory.cml b/lib/iris/tests/results/experimental/analysis/interpolate/LinearInterpolator/orthogonal_cube_with_factory.cml index 1bb899c558..c7200d6106 100644 --- a/lib/iris/tests/results/experimental/analysis/interpolate/LinearInterpolator/orthogonal_cube_with_factory.cml +++ b/lib/iris/tests/results/experimental/analysis/interpolate/LinearInterpolator/orthogonal_cube_with_factory.cml @@ -31,7 +31,7 @@ - + diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml index 585657b642..b41c0e48c7 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml @@ -66,7 +66,7 @@ [0.989272, 0.984692]]" id="a5c170db" long_name="sigma" points="[0.999424, 0.997504, 0.99482, 0.991375, 0.987171]" shape="(5,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml index 4e928851fe..8617be9372 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml @@ -60,7 +60,7 @@ [0.989272, 0.984692]]" id="a5c170db" long_name="sigma" points="[0.999424, 0.997504, 0.99482, 0.991375, 0.987171]" shape="(5,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml index 31a753c059..70df0e198d 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml @@ -429,7 +429,7 @@ 218.732, 216.367]]" shape="(16, 21)" standard_name="surface_altitude" units="Unit('m')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml b/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml index be79f3ff57..b863adcf55 100644 --- a/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/2D_1t_face_half_levels.cml @@ -34,7 +34,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml b/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml index 568c835e97..b46908a648 100644 --- a/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/2D_72t_face_half_levels.cml @@ -53,7 +53,7 @@ 16800.0, 17100.0, 17400.0, 17700.0, 18000.0, 18300.0, 18600.0, 18900.0, 19200.0, 19500.0, 19800.0, 20100.0, 20400.0, 20700.0, 21000.0, - 21300.0, 21600.0]" shape="(72,)" standard_name="time" units="Unit('seconds since 2016-01-01 15:00:00', calendar='gregorian')" value_type="float64" var_name="time_instant"> + 21300.0, 21600.0]" shape="(72,)" standard_name="time" units="Unit('seconds since 2016-01-01 15:00:00', calendar='standard')" value_type="float64" var_name="time_instant"> diff --git a/lib/iris/tests/results/experimental/ugrid/3D_1t_face_full_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_1t_face_full_levels.cml index 6d7873daaa..57209e4ba7 100644 --- a/lib/iris/tests/results/experimental/ugrid/3D_1t_face_full_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/3D_1t_face_full_levels.cml @@ -45,7 +45,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml index b664e3cf6f..c260587921 100644 --- a/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/3D_1t_face_half_levels.cml @@ -45,7 +45,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml index b30d443495..e545e05fdc 100644 --- a/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/3D_snow_pseudo_levels.cml @@ -34,7 +34,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml index 157755298d..4eedfc21b3 100644 --- a/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/3D_soil_pseudo_levels.cml @@ -34,7 +34,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml index a9eba1a80d..55155047bb 100644 --- a/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/3D_tile_pseudo_levels.cml @@ -34,7 +34,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml b/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml index e90c048803..fc52fce0b3 100644 --- a/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml +++ b/lib/iris/tests/results/experimental/ugrid/3D_veg_pseudo_levels.cml @@ -34,7 +34,7 @@ -127.321, -135.0]" shape="(864,)" standard_name="longitude" units="Unit('degrees')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/file_load/theta_levels.cml b/lib/iris/tests/results/file_load/theta_levels.cml index b4ae2a4b35..fc708b7949 100644 --- a/lib/iris/tests/results/file_load/theta_levels.cml +++ b/lib/iris/tests/results/file_load/theta_levels.cml @@ -11,7 +11,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -113,7 +113,7 @@ - + @@ -143,7 +143,7 @@ - + @@ -164,7 +164,7 @@ - + @@ -194,7 +194,7 @@ - + @@ -215,7 +215,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -266,7 +266,7 @@ - + @@ -296,7 +296,7 @@ - + @@ -317,7 +317,7 @@ - + @@ -347,7 +347,7 @@ - + @@ -368,7 +368,7 @@ - + @@ -398,7 +398,7 @@ - + @@ -419,7 +419,7 @@ - + @@ -449,7 +449,7 @@ - + @@ -470,7 +470,7 @@ - + @@ -500,7 +500,7 @@ - + @@ -521,7 +521,7 @@ - + @@ -551,7 +551,7 @@ - + @@ -572,7 +572,7 @@ - + @@ -602,7 +602,7 @@ - + @@ -623,7 +623,7 @@ - + @@ -653,7 +653,7 @@ - + @@ -674,7 +674,7 @@ - + @@ -704,7 +704,7 @@ - + @@ -725,7 +725,7 @@ - + @@ -755,7 +755,7 @@ - + @@ -776,7 +776,7 @@ - + @@ -806,7 +806,7 @@ - + @@ -827,7 +827,7 @@ - + @@ -857,7 +857,7 @@ - + @@ -878,7 +878,7 @@ - + @@ -908,7 +908,7 @@ - + @@ -929,7 +929,7 @@ - + @@ -959,7 +959,7 @@ - + @@ -980,7 +980,7 @@ - + @@ -1010,7 +1010,7 @@ - + @@ -1031,7 +1031,7 @@ - + @@ -1061,7 +1061,7 @@ - + @@ -1082,7 +1082,7 @@ - + @@ -1112,7 +1112,7 @@ - + @@ -1133,7 +1133,7 @@ - + @@ -1163,7 +1163,7 @@ - + @@ -1184,7 +1184,7 @@ - + @@ -1214,7 +1214,7 @@ - + @@ -1235,7 +1235,7 @@ - + @@ -1265,7 +1265,7 @@ - + @@ -1286,7 +1286,7 @@ - + @@ -1316,7 +1316,7 @@ - + @@ -1337,7 +1337,7 @@ - + @@ -1367,7 +1367,7 @@ - + @@ -1388,7 +1388,7 @@ - + @@ -1418,7 +1418,7 @@ - + @@ -1439,7 +1439,7 @@ - + @@ -1469,7 +1469,7 @@ - + @@ -1490,7 +1490,7 @@ - + @@ -1520,7 +1520,7 @@ - + @@ -1541,7 +1541,7 @@ - + @@ -1571,7 +1571,7 @@ - + @@ -1592,7 +1592,7 @@ - + @@ -1622,7 +1622,7 @@ - + @@ -1643,7 +1643,7 @@ - + @@ -1673,7 +1673,7 @@ - + @@ -1694,7 +1694,7 @@ - + @@ -1724,7 +1724,7 @@ - + @@ -1745,7 +1745,7 @@ - + @@ -1775,7 +1775,7 @@ - + @@ -1796,7 +1796,7 @@ - + @@ -1826,7 +1826,7 @@ - + @@ -1847,7 +1847,7 @@ - + @@ -1877,7 +1877,7 @@ - + @@ -1898,7 +1898,7 @@ - + @@ -1928,7 +1928,7 @@ - + diff --git a/lib/iris/tests/results/file_load/u_wind_levels.cml b/lib/iris/tests/results/file_load/u_wind_levels.cml index 68a3b45f07..5d1af58f6c 100644 --- a/lib/iris/tests/results/file_load/u_wind_levels.cml +++ b/lib/iris/tests/results/file_load/u_wind_levels.cml @@ -11,7 +11,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -94,7 +94,7 @@ - + @@ -115,7 +115,7 @@ - + @@ -146,7 +146,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -198,7 +198,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -250,7 +250,7 @@ - + @@ -271,7 +271,7 @@ - + @@ -302,7 +302,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -375,7 +375,7 @@ - + @@ -406,7 +406,7 @@ - + @@ -427,7 +427,7 @@ - + @@ -458,7 +458,7 @@ - + @@ -479,7 +479,7 @@ - + @@ -510,7 +510,7 @@ - + @@ -531,7 +531,7 @@ - + @@ -562,7 +562,7 @@ - + @@ -583,7 +583,7 @@ - + @@ -614,7 +614,7 @@ - + @@ -635,7 +635,7 @@ - + @@ -666,7 +666,7 @@ - + @@ -687,7 +687,7 @@ - + @@ -718,7 +718,7 @@ - + @@ -739,7 +739,7 @@ - + @@ -770,7 +770,7 @@ - + @@ -791,7 +791,7 @@ - + @@ -822,7 +822,7 @@ - + @@ -843,7 +843,7 @@ - + @@ -874,7 +874,7 @@ - + @@ -895,7 +895,7 @@ - + @@ -926,7 +926,7 @@ - + @@ -947,7 +947,7 @@ - + @@ -978,7 +978,7 @@ - + @@ -999,7 +999,7 @@ - + @@ -1030,7 +1030,7 @@ - + @@ -1051,7 +1051,7 @@ - + @@ -1082,7 +1082,7 @@ - + @@ -1103,7 +1103,7 @@ - + @@ -1134,7 +1134,7 @@ - + @@ -1155,7 +1155,7 @@ - + @@ -1186,7 +1186,7 @@ - + @@ -1207,7 +1207,7 @@ - + @@ -1238,7 +1238,7 @@ - + @@ -1259,7 +1259,7 @@ - + @@ -1290,7 +1290,7 @@ - + @@ -1311,7 +1311,7 @@ - + @@ -1342,7 +1342,7 @@ - + @@ -1363,7 +1363,7 @@ - + @@ -1394,7 +1394,7 @@ - + @@ -1415,7 +1415,7 @@ - + @@ -1446,7 +1446,7 @@ - + @@ -1467,7 +1467,7 @@ - + @@ -1498,7 +1498,7 @@ - + @@ -1519,7 +1519,7 @@ - + @@ -1550,7 +1550,7 @@ - + @@ -1571,7 +1571,7 @@ - + @@ -1602,7 +1602,7 @@ - + @@ -1623,7 +1623,7 @@ - + @@ -1654,7 +1654,7 @@ - + @@ -1675,7 +1675,7 @@ - + @@ -1706,7 +1706,7 @@ - + @@ -1727,7 +1727,7 @@ - + @@ -1758,7 +1758,7 @@ - + @@ -1779,7 +1779,7 @@ - + @@ -1810,7 +1810,7 @@ - + @@ -1831,7 +1831,7 @@ - + @@ -1862,7 +1862,7 @@ - + @@ -1883,7 +1883,7 @@ - + @@ -1914,7 +1914,7 @@ - + @@ -1935,7 +1935,7 @@ - + @@ -1966,7 +1966,7 @@ - + diff --git a/lib/iris/tests/results/file_load/v_wind_levels.cml b/lib/iris/tests/results/file_load/v_wind_levels.cml index 9ccdade1bd..c7145a7e9e 100644 --- a/lib/iris/tests/results/file_load/v_wind_levels.cml +++ b/lib/iris/tests/results/file_load/v_wind_levels.cml @@ -11,7 +11,7 @@ - + - + @@ -63,7 +63,7 @@ - + - + @@ -115,7 +115,7 @@ - + - + @@ -167,7 +167,7 @@ - + - + @@ -219,7 +219,7 @@ - + - + @@ -271,7 +271,7 @@ - + - + @@ -323,7 +323,7 @@ - + - + @@ -375,7 +375,7 @@ - + - + @@ -427,7 +427,7 @@ - + - + @@ -479,7 +479,7 @@ - + - + @@ -531,7 +531,7 @@ - + - + @@ -583,7 +583,7 @@ - + - + @@ -635,7 +635,7 @@ - + - + @@ -687,7 +687,7 @@ - + - + @@ -739,7 +739,7 @@ - + - + @@ -791,7 +791,7 @@ - + - + @@ -843,7 +843,7 @@ - + - + @@ -895,7 +895,7 @@ - + - + @@ -947,7 +947,7 @@ - + - + @@ -999,7 +999,7 @@ - + - + @@ -1051,7 +1051,7 @@ - + - + @@ -1103,7 +1103,7 @@ - + - + @@ -1155,7 +1155,7 @@ - + - + @@ -1207,7 +1207,7 @@ - + - + @@ -1259,7 +1259,7 @@ - + - + @@ -1311,7 +1311,7 @@ - + - + @@ -1363,7 +1363,7 @@ - + - + @@ -1415,7 +1415,7 @@ - + - + @@ -1467,7 +1467,7 @@ - + - + @@ -1519,7 +1519,7 @@ - + - + @@ -1571,7 +1571,7 @@ - + - + @@ -1623,7 +1623,7 @@ - + - + @@ -1675,7 +1675,7 @@ - + - + @@ -1727,7 +1727,7 @@ - + - + @@ -1779,7 +1779,7 @@ - + - + @@ -1831,7 +1831,7 @@ - + - + @@ -1883,7 +1883,7 @@ - + - + @@ -1935,7 +1935,7 @@ - + - + diff --git a/lib/iris/tests/results/file_load/wind_levels.cml b/lib/iris/tests/results/file_load/wind_levels.cml index 96d821fc1c..33584deec6 100644 --- a/lib/iris/tests/results/file_load/wind_levels.cml +++ b/lib/iris/tests/results/file_load/wind_levels.cml @@ -11,7 +11,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -94,7 +94,7 @@ - + @@ -115,7 +115,7 @@ - + @@ -146,7 +146,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -198,7 +198,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -250,7 +250,7 @@ - + @@ -271,7 +271,7 @@ - + @@ -302,7 +302,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -375,7 +375,7 @@ - + @@ -406,7 +406,7 @@ - + @@ -427,7 +427,7 @@ - + @@ -458,7 +458,7 @@ - + @@ -479,7 +479,7 @@ - + @@ -510,7 +510,7 @@ - + @@ -531,7 +531,7 @@ - + @@ -562,7 +562,7 @@ - + @@ -583,7 +583,7 @@ - + @@ -614,7 +614,7 @@ - + @@ -635,7 +635,7 @@ - + @@ -666,7 +666,7 @@ - + @@ -687,7 +687,7 @@ - + @@ -718,7 +718,7 @@ - + @@ -739,7 +739,7 @@ - + @@ -770,7 +770,7 @@ - + @@ -791,7 +791,7 @@ - + @@ -822,7 +822,7 @@ - + @@ -843,7 +843,7 @@ - + @@ -874,7 +874,7 @@ - + @@ -895,7 +895,7 @@ - + @@ -926,7 +926,7 @@ - + @@ -947,7 +947,7 @@ - + @@ -978,7 +978,7 @@ - + @@ -999,7 +999,7 @@ - + @@ -1030,7 +1030,7 @@ - + @@ -1051,7 +1051,7 @@ - + @@ -1082,7 +1082,7 @@ - + @@ -1103,7 +1103,7 @@ - + @@ -1134,7 +1134,7 @@ - + @@ -1155,7 +1155,7 @@ - + @@ -1186,7 +1186,7 @@ - + @@ -1207,7 +1207,7 @@ - + @@ -1238,7 +1238,7 @@ - + @@ -1259,7 +1259,7 @@ - + @@ -1290,7 +1290,7 @@ - + @@ -1311,7 +1311,7 @@ - + @@ -1342,7 +1342,7 @@ - + @@ -1363,7 +1363,7 @@ - + @@ -1394,7 +1394,7 @@ - + @@ -1415,7 +1415,7 @@ - + @@ -1446,7 +1446,7 @@ - + @@ -1467,7 +1467,7 @@ - + @@ -1498,7 +1498,7 @@ - + @@ -1519,7 +1519,7 @@ - + @@ -1550,7 +1550,7 @@ - + @@ -1571,7 +1571,7 @@ - + @@ -1602,7 +1602,7 @@ - + @@ -1623,7 +1623,7 @@ - + @@ -1654,7 +1654,7 @@ - + @@ -1675,7 +1675,7 @@ - + @@ -1706,7 +1706,7 @@ - + @@ -1727,7 +1727,7 @@ - + @@ -1758,7 +1758,7 @@ - + @@ -1779,7 +1779,7 @@ - + @@ -1810,7 +1810,7 @@ - + @@ -1831,7 +1831,7 @@ - + @@ -1862,7 +1862,7 @@ - + @@ -1883,7 +1883,7 @@ - + @@ -1914,7 +1914,7 @@ - + @@ -1935,7 +1935,7 @@ - + @@ -1966,7 +1966,7 @@ - + @@ -1987,7 +1987,7 @@ - + - + @@ -2039,7 +2039,7 @@ - + - + @@ -2091,7 +2091,7 @@ - + - + @@ -2143,7 +2143,7 @@ - + - + @@ -2195,7 +2195,7 @@ - + - + @@ -2247,7 +2247,7 @@ - + - + @@ -2299,7 +2299,7 @@ - + - + @@ -2351,7 +2351,7 @@ - + - + @@ -2403,7 +2403,7 @@ - + - + @@ -2455,7 +2455,7 @@ - + - + @@ -2507,7 +2507,7 @@ - + - + @@ -2559,7 +2559,7 @@ - + - + @@ -2611,7 +2611,7 @@ - + - + @@ -2663,7 +2663,7 @@ - + - + @@ -2715,7 +2715,7 @@ - + - + @@ -2767,7 +2767,7 @@ - + - + @@ -2819,7 +2819,7 @@ - + - + @@ -2871,7 +2871,7 @@ - + - + @@ -2923,7 +2923,7 @@ - + - + @@ -2975,7 +2975,7 @@ - + - + @@ -3027,7 +3027,7 @@ - + - + @@ -3079,7 +3079,7 @@ - + - + @@ -3131,7 +3131,7 @@ - + - + @@ -3183,7 +3183,7 @@ - + - + @@ -3235,7 +3235,7 @@ - + - + @@ -3287,7 +3287,7 @@ - + - + @@ -3339,7 +3339,7 @@ - + - + @@ -3391,7 +3391,7 @@ - + - + @@ -3443,7 +3443,7 @@ - + - + @@ -3495,7 +3495,7 @@ - + - + @@ -3547,7 +3547,7 @@ - + - + @@ -3599,7 +3599,7 @@ - + - + @@ -3651,7 +3651,7 @@ - + - + @@ -3703,7 +3703,7 @@ - + - + @@ -3755,7 +3755,7 @@ - + - + @@ -3807,7 +3807,7 @@ - + - + @@ -3859,7 +3859,7 @@ - + - + @@ -3911,7 +3911,7 @@ - + - + diff --git a/lib/iris/tests/results/imagerepo.json b/lib/iris/tests/results/imagerepo.json index 28d6f0bb03..e5c2ad863a 100644 --- a/lib/iris/tests/results/imagerepo.json +++ b/lib/iris/tests/results/imagerepo.json @@ -1,39 +1,40 @@ { - "gallery_tests.test_plot_COP_1d.TestCOP1DPlot.test_plot_COP_1d.0": "aefec91c3601249cc9b3336dc4c8cdb31a64c6d997b3c0eccb5932d285e42f33", - "gallery_tests.test_plot_COP_maps.TestCOPMaps.test_plot_cop_maps.0": "ea9130db95668524913e6ac168991f0d956e917ec76396b96a853dcf94696935", - "gallery_tests.test_plot_SOI_filtering.TestSOIFiltering.test_plot_soi_filtering.0": "fa56f295c5e0694a3c17a58d95e8da536233da99984c5af4c6739b4a9a444eb4", - "gallery_tests.test_plot_TEC.TestTEC.test_plot_TEC.0": "e5a761b69a589a4bc46f9e48c65c6631ce61d1ce3982c13739b33193c0ee3f8c", - "gallery_tests.test_plot_anomaly_log_colouring.TestAnomalyLogColouring.test_plot_anomaly_log_colouring.0": "ec4464e384a39b13931a9b1c85696da968d5e6e63e26847bdbd399938d3c5a4c", - "gallery_tests.test_plot_atlantic_profiles.TestAtlanticProfiles.test_plot_atlantic_profiles.0": "97c160f462a88f07203ebc77a1e36707e61f4e38d8f3d08a910597fc877cec58", - "gallery_tests.test_plot_atlantic_profiles.TestAtlanticProfiles.test_plot_atlantic_profiles.1": "eeea64dd6ea8cd99991d1322b3741e2684571cd89995b3131f32a4765ee2a1cc", - "gallery_tests.test_plot_coriolis.TestCoriolisPlot.test_plot_coriolis.0": "e68665de9a699659c1fe99a5896965966996c46e3e19c1da3a652669c51e1a26", - "gallery_tests.test_plot_cross_section.TestCrossSection.test_plot_cross_section.0": "ea91b17b9562e4d1609f5a05856e4ca45a52957e5ea5f13b1bca9dc0b17b1ac1", - "gallery_tests.test_plot_cross_section.TestCrossSection.test_plot_cross_section.1": "ea9521fb956a394068931e93e07e4aa5856cc47e4a91957b1ba55bb5b17a3b81", - "gallery_tests.test_plot_custom_aggregation.TestCustomAggregation.test_plot_custom_aggregation.0": "ee816f81917e907eb03ec73f856f7ac198d070186e90811f1be33ee1a57a6e18", - "gallery_tests.test_plot_custom_file_loading.TestCustomFileLoading.test_plot_custom_file_loading.0": "fa81cb47845e34bc932797436cccc8343f11359b73523746c48c72d9d9b34da5", - "gallery_tests.test_plot_deriving_phenomena.TestDerivingPhenomena.test_plot_deriving_phenomena.0": "ec97681793689768943c97e8926669d186e8c33f6c99c32e6b936c83d33e2c98", - "gallery_tests.test_plot_global_map.TestGlobalMap.test_plot_global_map.0": "fb997b958466846ed13e87467a997a898d66d17e2cc9906684696f99d3162e81", - "gallery_tests.test_plot_hovmoller.TestGlobalMap.test_plot_hovmoller.0": "eeb46cb4934b934bc07e974bc14b38949943c0fe3e94c17f6ea46cb4c07b3f00", - "gallery_tests.test_plot_inset.TestInsetPlot.test_plot_inset.0": "ebff6992b50096ad9267dac4d640949294924cdbc95d4b699d29952dcda46ed4", - "gallery_tests.test_plot_lagged_ensemble.TestLaggedEnsemble.test_plot_lagged_ensemble.0": "bbbb31b1c44e64e4b1579b5b917133cecc61f146c414668eb1119b1bb197ce34", - "gallery_tests.test_plot_lagged_ensemble.TestLaggedEnsemble.test_plot_lagged_ensemble.1": "aafec5e9e5e03e099a07e0f86542db879438261ec3b13ce78d8dc65a92d83d89", - "gallery_tests.test_plot_lineplot_with_legend.TestLineplotWithLegend.test_plot_lineplot_with_legend.0": "eafd9e12a5a061e9925ec716de489e9685078ec981b229e70ddb79219cc3768d", - "gallery_tests.test_plot_load_nemo.TestLoadNemo.test_plot_load_nemo.0": "a3ff34e87f0049496d17c4d9c04fc225d256971392db9f1696df0f16cec00736", - "gallery_tests.test_plot_orca_projection.TestOrcaProjection.test_plot_orca_projection.0": "bb11721a87cce5e4cce79e81d19b3b5e1e1cd3783168e07835853485e65e2e1e", - "gallery_tests.test_plot_orca_projection.TestOrcaProjection.test_plot_orca_projection.1": "e58661969e799659c1f719a6c867359a1996c0773649c09c3e612679c07b3f66", - "gallery_tests.test_plot_orca_projection.TestOrcaProjection.test_plot_orca_projection.2": "a58660ce9e739b31c93d1c89c8df33863783e23b3f11c07f2664366cc8ee3cc1", - "gallery_tests.test_plot_orca_projection.TestOrcaProjection.test_plot_orca_projection.3": "be817a8784dea56cec79817a919e338437a5c1e73fa16c726c4a3e816a1c6b1c", - "gallery_tests.test_plot_polar_stereo.TestPolarStereo.test_plot_polar_stereo.0": "ba1e615ec7e097ad961f9cb190f038e091c2c1e73f07c11f6f386b3cc1793e01", - "gallery_tests.test_plot_polynomial_fit.TestPolynomialFit.test_plot_polynomial_fit.0": "aeffcb34d244348be5a2c96c3a4fc6d0c4b69f2d87294ccb9f1a125684cd7c11", - "gallery_tests.test_plot_projections_and_annotations.TestProjectionsAndAnnotations.test_plot_projections_and_annotations.0": "fa854f19851a30e4cc76cd0bb0f932dca7c665b0c93ccb4b4ed19e9c3721b5c8", - "gallery_tests.test_plot_projections_and_annotations.TestProjectionsAndAnnotations.test_plot_projections_and_annotations.1": "e3856d999c389662734331afcd2d5a7184dba592b9b69b64d26dc29954b185b2", - "gallery_tests.test_plot_rotated_pole_mapping.TestRotatedPoleMapping.test_plot_rotated_pole_mapping.0": "ee46607e97a19781c0de1f81d0bb3e241f20c16f3fc0c1fe3d263d33d06f3e80", - "gallery_tests.test_plot_rotated_pole_mapping.TestRotatedPoleMapping.test_plot_rotated_pole_mapping.1": "ea57685f95a886a1c0de9da090be3e2697e1c0ff3f00c17e6b266c17c07f3f00", - "gallery_tests.test_plot_rotated_pole_mapping.TestRotatedPoleMapping.test_plot_rotated_pole_mapping.2": "ea57685f95a886a1c0de9da090be3e2497e1c0ff3f01c17e6b366c17c07b3f00", - "gallery_tests.test_plot_rotated_pole_mapping.TestRotatedPoleMapping.test_plot_rotated_pole_mapping.3": "fa8172c6857ecd38cb3392ce36c564311931d85ec64e9787719a39993c316e66", - "gallery_tests.test_plot_wind_barbs.TestWindBarbs.test_wind_barbs.0": "e9e161e996169316c1fe9e96c29e36739e13c07c3d61c07f39813929c07f3f01", - "gallery_tests.test_plot_wind_speed.TestWindSpeed.test_plot_wind_speed.0": "e9e960e996169306c1fe9e96c29e36739e03c06c3d61c07f3da139e1c07f3f01", - "gallery_tests.test_plot_wind_speed.TestWindSpeed.test_plot_wind_speed.1": "e9e960e996169306c1ee9f96c29e36739653c06c3d61c07f39a139e1c07f3f01", + "gallery_tests.test_plot_COP_1d.0": "aefec91c3601249cc9b3336dc4c8cdb31a64c6d997b3c0eccb5932d285e42f33", + "gallery_tests.test_plot_COP_maps.0": "ea9130db95668524913e6ac168991f0d956e917ec76396b96a853dcf94696935", + "gallery_tests.test_plot_SOI_filtering.0": "fa56f295c5e0694a3c17a58d95e8da536233da99984c5af4c6739b4a9a444eb4", + "gallery_tests.test_plot_TEC.0": "e5a761b69a589a4bc46f9e48c65c6631ce61d1ce3982c13739b33193c0ee3f8c", + "gallery_tests.test_plot_anomaly_log_colouring.0": "ec4464e384a39b13931a9b1c85696da968d5e6e63e26847bdbd399938d3c5a4c", + "gallery_tests.test_plot_atlantic_profiles.0": "97c160f462a88f07203ebc77a1e36707e61f4e38d8f3d08a910597fc877cec58", + "gallery_tests.test_plot_atlantic_profiles.1": "eeea64dd6ea8cd99991d1322b3741e2684571cd89995b3131f32a4765ee2a1cc", + "gallery_tests.test_plot_coriolis.0": "e68665de9a699659c1fe99a5896965966996c46e3e19c1da3a652669c51e1a26", + "gallery_tests.test_plot_cross_section.0": "ea91b17b9562e4d1609f5a05856e4ca45a52957e5ea5f13b1bca9dc0b17b1ac1", + "gallery_tests.test_plot_cross_section.1": "ea9521fb956a394068931e93e07e4aa5856cc47e4a91957b1ba55bb5b17a3b81", + "gallery_tests.test_plot_custom_aggregation.0": "ee816f81917e907eb03ec73f856f7ac198d070186e90811f1be33ee1a57a6e18", + "gallery_tests.test_plot_custom_file_loading.0": "fa81cb47845e34bc932797436cccc8343f11359b73523746c48c72d9d9b34da5", + "gallery_tests.test_plot_deriving_phenomena.0": "ec97681793689768943c97e8926669d186e8c33f6c99c32e6b936c83d33e2c98", + "gallery_tests.test_plot_global_map.0": "fb997b958466846ed13e87467a997a898d66d17e2cc9906684696f99d3162e81", + "gallery_tests.test_plot_hovmoller.0": "eeb46cb4934b934bc07e974bc14b38949943c0fe3e94c17f6ea46cb4c07b3f00", + "gallery_tests.test_plot_inset.0": "ebff6992b50096ad9267dac4d640949294924cdbc95d4b699d29952dcda46ed4", + "gallery_tests.test_plot_lagged_ensemble.0": "bbbb31b1c44e64e4b1579b5b917133cecc61f146c414668eb1119b1bb197ce34", + "gallery_tests.test_plot_lagged_ensemble.1": "aafec5e9e5e03e099a07e0f86542db879438261ec3b13ce78d8dc65a92d83d89", + "gallery_tests.test_plot_lineplot_with_legend.0": "eafd9e12a5a061e9925ec716de489e9685078ec981b229e70ddb79219cc3768d", + "gallery_tests.test_plot_load_nemo.0": "a3ff34e87f0049496d17c4d9c04fc225d256971392db9f1696df0f16cec00736", + "gallery_tests.test_plot_orca_projection.0": "bb11721a87cce5e4cce79e81d19b3b5e1e1cd3783168e07835853485e65e2e1e", + "gallery_tests.test_plot_orca_projection.1": "e58661969e799659c1f719a6c867359a1996c0773649c09c3e612679c07b3f66", + "gallery_tests.test_plot_orca_projection.2": "a58660ce9e739b31c93d1c89c8df33863783e23b3f11c07f2664366cc8ee3cc1", + "gallery_tests.test_plot_orca_projection.3": "be817a8784dea56cec79817a919e338437a5c1e73fa16c726c4a3e816a1c6b1c", + "gallery_tests.test_plot_polar_stereo.0": "ba1e615ec7e097ad961f9cb190f038e091c2c1e73f07c11f6f386b3cc1793e01", + "gallery_tests.test_plot_polynomial_fit.0": "aeffcb34d244348be5a2c96c3a4fc6d0c4b69f2d87294ccb9f1a125684cd7c11", + "gallery_tests.test_plot_projections_and_annotations.0": "fa854f19851a30e4cc76cd0bb0f932dca7c665b0c93ccb4b4ed19e9c3721b5c8", + "gallery_tests.test_plot_projections_and_annotations.1": "e3856d999c389662734331afcd2d5a7184dba592b9b69b64d26dc29954b185b2", + "gallery_tests.test_plot_rotated_pole_mapping.0": "ee46607e97a19781c0de1f81d0bb3e241f20c16f3fc0c1fe3d263d33d06f3e80", + "gallery_tests.test_plot_rotated_pole_mapping.1": "ea57685f95a886a1c0de9da090be3e2697e1c0ff3f00c17e6b266c17c07f3f00", + "gallery_tests.test_plot_rotated_pole_mapping.2": "ea57685f95a886a1c0de9da090be3e2497e1c0ff3f01c17e6b366c17c07b3f00", + "gallery_tests.test_plot_rotated_pole_mapping.3": "fa8172c6857ecd38cb3392ce36c564311931d85ec64e9787719a39993c316e66", + "gallery_tests.test_plot_wind_barbs.0": "e9e161e996169316c1fe9e96c29e36739e13c07c3d61c07f39813929c07f3f01", + "gallery_tests.test_plot_wind_speed.0": "e9e960e996169306c1fe9e96c29e36739e03c06c3d61c07f3da139e1c07f3f01", + "gallery_tests.test_plot_wind_speed.1": "e9e960e996169306c1ee9f96c29e36739653c06c3d61c07f39a139e1c07f3f01", + "gallery_tests.test_plot_zonal_means.0": "b45b3071c9a4c9a6c69c363cc327cbb3cb9634d8c9e63cf336738c6634d8c384", "iris.tests.experimental.test_animate.IntegrationTest.test_cube_animation.0": "fe81c17e817e3e81817e3e81857e7a817e81c17e7e81c17e7a81817e817e8c2e", "iris.tests.experimental.test_animate.IntegrationTest.test_cube_animation.1": "fe81857e817e7a85817e7a81857e7e817e81917a7e81817e7a81817e817e843e", "iris.tests.experimental.test_animate.IntegrationTest.test_cube_animation.2": "be81817ec17e7a81c17e7e81857e3e803e81817a3e81c17e7a81c17ec97e2c2f", diff --git a/lib/iris/tests/results/integration/climatology/TestClimatology/reference_simpledata.cdl b/lib/iris/tests/results/integration/climatology/TestClimatology/reference_simpledata.cdl index 1f6bc36832..2873f68205 100644 --- a/lib/iris/tests/results/integration/climatology/TestClimatology/reference_simpledata.cdl +++ b/lib/iris/tests/results/integration/climatology/TestClimatology/reference_simpledata.cdl @@ -13,7 +13,7 @@ variables: time:climatology = "time_climatology" ; time:units = "days since 1970-01-01 00:00:00-00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_climatology(time, bnds) ; double latitude(latitude) ; latitude:axis = "Y" ; diff --git a/lib/iris/tests/results/integration/netcdf/TestAtmosphereSigma/save.cdl b/lib/iris/tests/results/integration/netcdf/TestAtmosphereSigma/save.cdl index cfb3143050..762226192c 100644 --- a/lib/iris/tests/results/integration/netcdf/TestAtmosphereSigma/save.cdl +++ b/lib/iris/tests/results/integration/netcdf/TestAtmosphereSigma/save.cdl @@ -21,7 +21,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; int model_level_number(model_level_number) ; model_level_number:axis = "Z" ; model_level_number:units = "1" ; diff --git a/lib/iris/tests/results/integration/netcdf/TestHybridPressure/save.cdl b/lib/iris/tests/results/integration/netcdf/TestHybridPressure/save.cdl index 88c5fc18fe..6fed33430a 100644 --- a/lib/iris/tests/results/integration/netcdf/TestHybridPressure/save.cdl +++ b/lib/iris/tests/results/integration/netcdf/TestHybridPressure/save.cdl @@ -21,7 +21,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; int model_level_number(model_level_number) ; model_level_number:axis = "Z" ; model_level_number:units = "1" ; diff --git a/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_manual.cdl b/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_manual.cdl index 65da679ad0..fece18b1f3 100644 --- a/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_manual.cdl +++ b/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_manual.cdl @@ -32,7 +32,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -41,7 +41,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_signed.cdl b/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_signed.cdl index 65da679ad0..fece18b1f3 100644 --- a/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_signed.cdl +++ b/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_signed.cdl @@ -32,7 +32,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -41,7 +41,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_unsigned.cdl b/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_unsigned.cdl index d7a39d72de..c85ba6aadd 100644 --- a/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_unsigned.cdl +++ b/lib/iris/tests/results/integration/netcdf/TestPackedData/single_packed_unsigned.cdl @@ -32,7 +32,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -41,7 +41,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_and_pressure.cdl b/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_and_pressure.cdl index 5ff22a679b..d813ab98dc 100644 --- a/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_and_pressure.cdl +++ b/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_and_pressure.cdl @@ -21,7 +21,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; int model_level_number(model_level_number) ; model_level_number:axis = "Z" ; model_level_number:units = "1" ; diff --git a/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_cubes.cml b/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_cubes.cml index 4d37f856ad..09d54a1b19 100644 --- a/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_cubes.cml +++ b/lib/iris/tests/results/integration/netcdf/TestSaveMultipleAuxFactories/hybrid_height_cubes.cml @@ -58,7 +58,7 @@ [124, 125, 126, 127, 128, 129]]" shape="(5, 6)" standard_name="surface_altitude" units="Unit('m')" value_type="int64" var_name="surface_altitude"/> - + @@ -122,7 +122,7 @@ [1240, 1250, 1260, 1270, 1280, 1290]]" shape="(5, 6)" units="Unit('m')" value_type="int64" var_name="surface_altitude_0"/> - + diff --git a/lib/iris/tests/results/merge/dec.cml b/lib/iris/tests/results/merge/dec.cml index ea72b506f0..4efd40910f 100644 --- a/lib/iris/tests/results/merge/dec.cml +++ b/lib/iris/tests/results/merge/dec.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -151,7 +151,7 @@ - + @@ -270,7 +270,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -291,7 +291,7 @@ - + @@ -411,7 +411,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + @@ -432,7 +432,7 @@ - + - + diff --git a/lib/iris/tests/results/merge/theta.cml b/lib/iris/tests/results/merge/theta.cml index 293e40cc3a..0e5b02be51 100644 --- a/lib/iris/tests/results/merge/theta.cml +++ b/lib/iris/tests/results/merge/theta.cml @@ -11,7 +11,7 @@ - + @@ -130,7 +130,7 @@ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" shape="(38,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/merge/theta_two_times.cml b/lib/iris/tests/results/merge/theta_two_times.cml index 0dd396e337..d1c9f59ace 100644 --- a/lib/iris/tests/results/merge/theta_two_times.cml +++ b/lib/iris/tests/results/merge/theta_two_times.cml @@ -399,7 +399,7 @@ - + - + diff --git a/lib/iris/tests/results/name/NAMEIII_field.cml b/lib/iris/tests/results/name/NAMEIII_field.cml index 97b3189bba..c419a2760d 100644 --- a/lib/iris/tests/results/name/NAMEIII_field.cml +++ b/lib/iris/tests/results/name/NAMEIII_field.cml @@ -48,7 +48,7 @@ - + @@ -113,7 +113,7 @@ - + @@ -177,7 +177,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -305,7 +305,7 @@ - + diff --git a/lib/iris/tests/results/name/NAMEIII_timeseries.cml b/lib/iris/tests/results/name/NAMEIII_timeseries.cml index c4e70590a2..3776bfc27f 100644 --- a/lib/iris/tests/results/name/NAMEIII_timeseries.cml +++ b/lib/iris/tests/results/name/NAMEIII_timeseries.cml @@ -58,7 +58,7 @@ 358342.0, 358343.0, 358344.0, 358345.0, 358346.0, 358347.0, 358348.0, 358349.0, 358350.0, 358351.0, 358352.0, 358353.0, - 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -129,7 +129,7 @@ 358342.0, 358343.0, 358344.0, 358345.0, 358346.0, 358347.0, 358348.0, 358349.0, 358350.0, 358351.0, 358352.0, 358353.0, - 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -199,7 +199,7 @@ 358342.0, 358343.0, 358344.0, 358345.0, 358346.0, 358347.0, 358348.0, 358349.0, 358350.0, 358351.0, 358352.0, 358353.0, - 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -269,7 +269,7 @@ 358342.0, 358343.0, 358344.0, 358345.0, 358346.0, 358347.0, 358348.0, 358349.0, 358350.0, 358351.0, 358352.0, 358353.0, - 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -339,7 +339,7 @@ 358342.0, 358343.0, 358344.0, 358345.0, 358346.0, 358347.0, 358348.0, 358349.0, 358350.0, 358351.0, 358352.0, 358353.0, - 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 358354.0, 358355.0, 358356.0, 358357.0]" shape="(72,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/name/NAMEIII_trajectory.cml b/lib/iris/tests/results/name/NAMEIII_trajectory.cml index c514d589ca..20a0ec3b82 100644 --- a/lib/iris/tests/results/name/NAMEIII_trajectory.cml +++ b/lib/iris/tests/results/name/NAMEIII_trajectory.cml @@ -16,7 +16,7 @@ - + @@ -39,7 +39,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -106,7 +106,7 @@ - + @@ -129,7 +129,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -151,7 +151,7 @@ - + @@ -174,7 +174,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -196,7 +196,7 @@ - + @@ -219,7 +219,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -241,7 +241,7 @@ - + @@ -264,7 +264,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -286,7 +286,7 @@ - + @@ -309,7 +309,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -331,7 +331,7 @@ - + @@ -354,7 +354,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -376,7 +376,7 @@ - + @@ -399,7 +399,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -421,7 +421,7 @@ - + @@ -444,7 +444,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -466,7 +466,7 @@ - + @@ -489,7 +489,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -511,7 +511,7 @@ - + @@ -534,7 +534,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -556,7 +556,7 @@ - + @@ -579,7 +579,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -601,7 +601,7 @@ - + @@ -624,7 +624,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -646,7 +646,7 @@ - + @@ -669,7 +669,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -691,7 +691,7 @@ - + @@ -714,7 +714,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -736,7 +736,7 @@ - + @@ -759,7 +759,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/name/NAMEIII_trajectory0.cml b/lib/iris/tests/results/name/NAMEIII_trajectory0.cml index 5f10016f39..d337ca9454 100644 --- a/lib/iris/tests/results/name/NAMEIII_trajectory0.cml +++ b/lib/iris/tests/results/name/NAMEIII_trajectory0.cml @@ -16,7 +16,7 @@ - + @@ -39,7 +39,7 @@ + 366886.75, 366887.0]" shape="(836,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/name/NAMEIII_version2.cml b/lib/iris/tests/results/name/NAMEIII_version2.cml index 95b9db7d5b..0ad0c883a2 100644 --- a/lib/iris/tests/results/name/NAMEIII_version2.cml +++ b/lib/iris/tests/results/name/NAMEIII_version2.cml @@ -76,7 +76,7 @@ 402921.0, 402922.0, 402923.0, 402924.0, 402925.0, 402926.0, 402927.0, 402928.0, 402929.0, 402930.0, 402931.0, 402932.0, - 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -158,7 +158,7 @@ 402921.0, 402922.0, 402923.0, 402924.0, 402925.0, 402926.0, 402927.0, 402928.0, 402929.0, 402930.0, 402931.0, 402932.0, - 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -240,7 +240,7 @@ 402921.0, 402922.0, 402923.0, 402924.0, 402925.0, 402926.0, 402927.0, 402928.0, 402929.0, 402930.0, 402931.0, 402932.0, - 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -322,7 +322,7 @@ 402921.0, 402922.0, 402923.0, 402924.0, 402925.0, 402926.0, 402927.0, 402928.0, 402929.0, 402930.0, 402931.0, 402932.0, - 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 402933.0, 402934.0, 402935.0, 402936.0]" shape="(24,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/name/NAMEII_field.cml b/lib/iris/tests/results/name/NAMEII_field.cml index 664669ef62..7d88c06eff 100644 --- a/lib/iris/tests/results/name/NAMEII_field.cml +++ b/lib/iris/tests/results/name/NAMEII_field.cml @@ -51,7 +51,7 @@ - + @@ -112,7 +112,7 @@ - + @@ -166,7 +166,7 @@ - + @@ -227,7 +227,7 @@ - + @@ -288,7 +288,7 @@ - + diff --git a/lib/iris/tests/results/name/NAMEII_field__no_time_averaging.cml b/lib/iris/tests/results/name/NAMEII_field__no_time_averaging.cml new file mode 100644 index 0000000000..9bc2c0d1ac --- /dev/null +++ b/lib/iris/tests/results/name/NAMEII_field__no_time_averaging.cml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/iris/tests/results/name/NAMEII_field__no_time_averaging_0.cml b/lib/iris/tests/results/name/NAMEII_field__no_time_averaging_0.cml new file mode 100644 index 0000000000..8d1ad620d0 --- /dev/null +++ b/lib/iris/tests/results/name/NAMEII_field__no_time_averaging_0.cml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/iris/tests/results/name/NAMEII_timeseries.cml b/lib/iris/tests/results/name/NAMEII_timeseries.cml index 52aaa8b809..39af8a6288 100644 --- a/lib/iris/tests/results/name/NAMEII_timeseries.cml +++ b/lib/iris/tests/results/name/NAMEII_timeseries.cml @@ -36,7 +36,7 @@ [370473.5, 370474.5], [370474.5, 370475.5], [370475.5, 370476.5]]" id="cb784457" points="[370345.0, 370346.0, 370347.0, ..., 370474.0, - 370475.0, 370476.0]" shape="(132,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 370475.0, 370476.0]" shape="(132,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -85,7 +85,7 @@ [370473.5, 370474.5], [370474.5, 370475.5], [370475.5, 370476.5]]" id="cb784457" points="[370345.0, 370346.0, 370347.0, ..., 370474.0, - 370475.0, 370476.0]" shape="(132,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='gregorian')" value_type="float64"/> + 370475.0, 370476.0]" shape="(132,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/aliases.cdl b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/aliases.cdl index e6a18dd2e4..da0d1d10db 100644 --- a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/aliases.cdl +++ b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/aliases.cdl @@ -20,7 +20,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double grid_latitude(grid_latitude) ; grid_latitude:axis = "Y" ; grid_latitude:units = "degrees" ; diff --git a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/flag.cdl b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/flag.cdl index 22ee23e2f6..ef1ef973e2 100644 --- a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/flag.cdl +++ b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/flag.cdl @@ -20,7 +20,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double grid_latitude(grid_latitude) ; grid_latitude:axis = "Y" ; grid_latitude:units = "degrees" ; diff --git a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/fulldims.cdl b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/fulldims.cdl index 50ebd1abc9..1d33942464 100644 --- a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/fulldims.cdl +++ b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/fulldims.cdl @@ -20,7 +20,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double grid_latitude(grid_latitude) ; grid_latitude:axis = "Y" ; grid_latitude:units = "degrees" ; diff --git a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/multiple.cdl b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/multiple.cdl index 9ae68a1112..5a0edc7528 100644 --- a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/multiple.cdl +++ b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/multiple.cdl @@ -20,7 +20,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double grid_latitude(grid_latitude) ; grid_latitude:axis = "Y" ; grid_latitude:units = "degrees" ; diff --git a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/partialdims.cdl b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/partialdims.cdl index 4d54fe36f0..81d32bf80c 100644 --- a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/partialdims.cdl +++ b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/partialdims.cdl @@ -20,7 +20,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double grid_latitude(grid_latitude) ; grid_latitude:axis = "Y" ; grid_latitude:units = "degrees" ; diff --git a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/shared.cdl b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/shared.cdl index 84516e186f..c6b29c5bda 100644 --- a/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/shared.cdl +++ b/lib/iris/tests/results/netcdf/TestNetCDFSave__ancillaries/shared.cdl @@ -20,7 +20,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double grid_latitude(grid_latitude) ; grid_latitude:axis = "Y" ; grid_latitude:units = "degrees" ; diff --git a/lib/iris/tests/results/netcdf/netcdf_cell_methods.cml b/lib/iris/tests/results/netcdf/netcdf_cell_methods.cml index ca4a0eb017..c748853c5c 100644 --- a/lib/iris/tests/results/netcdf/netcdf_cell_methods.cml +++ b/lib/iris/tests/results/netcdf/netcdf_cell_methods.cml @@ -9,7 +9,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -50,7 +50,7 @@ - + @@ -75,7 +75,7 @@ - + @@ -98,7 +98,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -140,7 +140,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -199,7 +199,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -261,7 +261,7 @@ - + @@ -281,7 +281,7 @@ - + @@ -304,7 +304,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -336,7 +336,7 @@ - + @@ -349,7 +349,7 @@ - + @@ -362,7 +362,7 @@ - + @@ -375,7 +375,7 @@ - + @@ -394,7 +394,7 @@ - + @@ -413,7 +413,7 @@ - + @@ -433,7 +433,7 @@ - + @@ -450,7 +450,7 @@ - + @@ -463,7 +463,7 @@ - + @@ -476,7 +476,7 @@ - + @@ -489,7 +489,7 @@ - + @@ -502,7 +502,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_index_0.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_index_0.cml index a11d593684..3847d5a417 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_index_0.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_index_0.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_index_1.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_index_1.cml index 30e6844591..89ee5ac195 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_index_1.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_index_1.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_index_2.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_index_2.cml index 6f9446582a..b3c7709dae 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_index_2.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_index_2.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_mix_0.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_mix_0.cml index 12def7cea4..ea5e42150e 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_mix_0.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_mix_0.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_mix_1.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_mix_1.cml index b20281c53e..b028ee6cf8 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_mix_1.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_mix_1.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_slice_0.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_slice_0.cml index 0d126109cf..76f66e1bc4 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_slice_0.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_slice_0.cml @@ -17,7 +17,7 @@ + 929298, 929304]" shape="(20,)" standard_name="time" units="Unit('hours since 1900-01-01 00:00:0.0', calendar='standard')" value_type="int32" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_slice_1.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_slice_1.cml index 8cfb4a0b5f..133cc4f659 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_slice_1.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_slice_1.cml @@ -15,7 +15,7 @@ + 929226, 929232, 929238, 929244]" shape="(10,)" standard_name="time" units="Unit('hours since 1900-01-01 00:00:0.0', calendar='standard')" value_type="int32" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_slice_2.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_slice_2.cml index 9259a07563..1d7025751e 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_slice_2.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_slice_2.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_0.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_0.cml index 6bc1a094e3..1f5a990bd4 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_0.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_0.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_1.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_1.cml index 0535339c7e..9c32197e56 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_1.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_1.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_2.cml b/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_2.cml index 6a0f9a90bf..100ab1257c 100644 --- a/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_2.cml +++ b/lib/iris/tests/results/netcdf/netcdf_deferred_tuple_2.cml @@ -14,7 +14,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_global_xyt_hires.cml b/lib/iris/tests/results/netcdf/netcdf_global_xyt_hires.cml index bda7f9ed9f..22a4ff1989 100644 --- a/lib/iris/tests/results/netcdf/netcdf_global_xyt_hires.cml +++ b/lib/iris/tests/results/netcdf/netcdf_global_xyt_hires.cml @@ -82,7 +82,7 @@ 71603.5, 71604.5, 71605.5, 71606.5, 71607.5, 71608.5, 71609.5, 71610.5, 71611.5, 71612.5, 71613.5, 71614.5, 71615.5, 71616.5, 71617.5, - 71618.5]" shape="(31,)" standard_name="time" units="Unit('days since 1850-01-01', calendar='gregorian')" value_type="float64" var_name="time"/> + 71618.5]" shape="(31,)" standard_name="time" units="Unit('days since 1850-01-01', calendar='standard')" value_type="float64" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_global_xyt_total.cml b/lib/iris/tests/results/netcdf/netcdf_global_xyt_total.cml index 1204fd0d39..fc6772e5f0 100644 --- a/lib/iris/tests/results/netcdf/netcdf_global_xyt_total.cml +++ b/lib/iris/tests/results/netcdf/netcdf_global_xyt_total.cml @@ -19,7 +19,7 @@ 929262, 929268, 929274, 929280, 929286, 929292, 929298, 929304, 929310, 929316, 929322, 929328, 929334, 929340, 929346, 929352, 929358, 929364, - 929370]" shape="(31,)" standard_name="time" units="Unit('hours since 1900-01-01 00:00:0.0', calendar='gregorian')" value_type="int32" var_name="time"/> + 929370]" shape="(31,)" standard_name="time" units="Unit('hours since 1900-01-01 00:00:0.0', calendar='standard')" value_type="int32" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems.cml b/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems.cml index ac41f4a8b8..9d6b3c1e43 100644 --- a/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems.cml +++ b/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems.cml @@ -20,7 +20,7 @@ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]" shape="(60,)" units="Unit('unknown')" value_type="int32" var_name="levelist"/> - + @@ -46,7 +46,7 @@ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]" shape="(60,)" units="Unit('unknown')" value_type="int32" var_name="levelist"/> - + diff --git a/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_0.cml b/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_0.cml index 4234b5cc84..15ab300757 100644 --- a/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_0.cml +++ b/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_0.cml @@ -20,7 +20,7 @@ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]" shape="(60,)" units="Unit('unknown')" value_type="int32" var_name="levelist"/> - + diff --git a/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_1.cml b/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_1.cml index 17d87a0190..29ff3b9bd9 100644 --- a/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_1.cml +++ b/lib/iris/tests/results/netcdf/netcdf_global_xyzt_gems_iter_1.cml @@ -20,7 +20,7 @@ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]" shape="(60,)" units="Unit('unknown')" value_type="int32" var_name="levelist"/> - + diff --git a/lib/iris/tests/results/netcdf/netcdf_laea.cml b/lib/iris/tests/results/netcdf/netcdf_laea.cml index ad23114038..799f40522b 100644 --- a/lib/iris/tests/results/netcdf/netcdf_laea.cml +++ b/lib/iris/tests/results/netcdf/netcdf_laea.cml @@ -11,7 +11,7 @@ - + @@ -63,7 +63,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_lcc.cml b/lib/iris/tests/results/netcdf/netcdf_lcc.cml index 7ea53e6600..592c33d534 100644 --- a/lib/iris/tests/results/netcdf/netcdf_lcc.cml +++ b/lib/iris/tests/results/netcdf/netcdf_lcc.cml @@ -88,7 +88,7 @@ [273.0, 303.0], [304.0, 333.0], [334.0, 364.0]]" id="1c4a69ce" long_name="time" points="[15.0, 44.5, 74.0, 104.5, 135.0, 165.5, 196.0, - 227.0, 257.5, 288.0, 318.5, 349.0]" shape="(12,)" standard_name="time" units="Unit('days since 2010-01-01 12:00:00', calendar='gregorian')" value_type="float64" var_name="time"/> + 227.0, 257.5, 288.0, 318.5, 349.0]" shape="(12,)" standard_name="time" units="Unit('days since 2010-01-01 12:00:00', calendar='standard')" value_type="float64" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_merc.cml b/lib/iris/tests/results/netcdf/netcdf_merc.cml index 831a8fdaa7..c06a2efe88 100644 --- a/lib/iris/tests/results/netcdf/netcdf_merc.cml +++ b/lib/iris/tests/results/netcdf/netcdf_merc.cml @@ -65,7 +65,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_monotonic.cml b/lib/iris/tests/results/netcdf/netcdf_monotonic.cml index 578b2b6d96..3385ecd6fe 100644 --- a/lib/iris/tests/results/netcdf/netcdf_monotonic.cml +++ b/lib/iris/tests/results/netcdf/netcdf_monotonic.cml @@ -12,7 +12,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -48,7 +48,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_polar.cml b/lib/iris/tests/results/netcdf/netcdf_polar.cml index ef76a61699..15c1a90da9 100644 --- a/lib/iris/tests/results/netcdf/netcdf_polar.cml +++ b/lib/iris/tests/results/netcdf/netcdf_polar.cml @@ -36,7 +36,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_rotated_xyt_precipitation.cml b/lib/iris/tests/results/netcdf/netcdf_rotated_xyt_precipitation.cml index b236a3677d..05e5fe475d 100644 --- a/lib/iris/tests/results/netcdf/netcdf_rotated_xyt_precipitation.cml +++ b/lib/iris/tests/results/netcdf/netcdf_rotated_xyt_precipitation.cml @@ -54,7 +54,7 @@ + [2925.5, 2926.5]]" id="2306ff47" long_name="Julian Day" points="[2922.5, 2923.5, 2924.5, 2925.5]" shape="(4,)" standard_name="time" units="Unit('days since 1950-01-01 00:00:00.0', calendar='standard')" value_type="float32" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_save_hybrid_height.cdl b/lib/iris/tests/results/netcdf/netcdf_save_hybrid_height.cdl index 1863d1ee7d..74a83c9714 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_hybrid_height.cdl +++ b/lib/iris/tests/results/netcdf/netcdf_save_hybrid_height.cdl @@ -22,7 +22,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; int model_level_number(model_level_number) ; model_level_number:axis = "Z" ; model_level_number:units = "1" ; @@ -46,7 +46,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; float level_height(model_level_number) ; level_height:bounds = "level_height_bnds" ; level_height:units = "m" ; diff --git a/lib/iris/tests/results/netcdf/netcdf_save_load_hybrid_height.cml b/lib/iris/tests/results/netcdf/netcdf_save_load_hybrid_height.cml index 8e4a005d44..fbecdf97d3 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_load_hybrid_height.cml +++ b/lib/iris/tests/results/netcdf/netcdf_save_load_hybrid_height.cml @@ -418,7 +418,7 @@ 0.666666666686, 0.833333333314, 1.0]" shape="(6,)" standard_name="forecast_period" units="Unit('hours')" value_type="float64" var_name="forecast_period"/> - + + 347926.666667, 347926.833333, 347927.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_save_load_ndim_auxiliary.cml b/lib/iris/tests/results/netcdf/netcdf_save_load_ndim_auxiliary.cml index 13582b3106..54bcc8a686 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_load_ndim_auxiliary.cml +++ b/lib/iris/tests/results/netcdf/netcdf_save_load_ndim_auxiliary.cml @@ -54,7 +54,7 @@ + [2925.5, 2926.5]]" id="2306ff47" long_name="Julian Day" points="[2922.5, 2923.5, 2924.5, 2925.5]" shape="(4,)" standard_name="time" units="Unit('days since 1950-01-01 00:00:00.0', calendar='standard')" value_type="float32" var_name="time"/> diff --git a/lib/iris/tests/results/netcdf/netcdf_save_ndim_auxiliary.cdl b/lib/iris/tests/results/netcdf/netcdf_save_ndim_auxiliary.cdl index 32d4163d01..f8180d4ea8 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_ndim_auxiliary.cdl +++ b/lib/iris/tests/results/netcdf/netcdf_save_ndim_auxiliary.cdl @@ -22,7 +22,7 @@ variables: time:units = "days since 1950-01-01 00:00:00.0" ; time:standard_name = "time" ; time:long_name = "Julian Day" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; float time_bnds(time, bnds) ; float rlat(rlat) ; rlat:axis = "Y" ; diff --git a/lib/iris/tests/results/netcdf/netcdf_save_realistic_0d.cdl b/lib/iris/tests/results/netcdf/netcdf_save_realistic_0d.cdl index 0e3ae7e715..642e46a905 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_realistic_0d.cdl +++ b/lib/iris/tests/results/netcdf/netcdf_save_realistic_0d.cdl @@ -50,7 +50,7 @@ variables: double time ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; // global attributes: :source = "Iris test case" ; diff --git a/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d.cdl b/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d.cdl index 601ea11719..d49e775024 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d.cdl +++ b/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d.cdl @@ -21,7 +21,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; int model_level_number(model_level_number) ; model_level_number:axis = "Z" ; model_level_number:units = "1" ; diff --git a/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d_no_hybrid.cdl b/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d_no_hybrid.cdl index b86a77aa62..8353df60e9 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d_no_hybrid.cdl +++ b/lib/iris/tests/results/netcdf/netcdf_save_realistic_4d_no_hybrid.cdl @@ -21,7 +21,7 @@ variables: time:axis = "T" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; int model_level_number(model_level_number) ; model_level_number:axis = "Z" ; model_level_number:units = "1" ; diff --git a/lib/iris/tests/results/netcdf/netcdf_save_single.cdl b/lib/iris/tests/results/netcdf/netcdf_save_single.cdl index e45496521c..9847532001 100644 --- a/lib/iris/tests/results/netcdf/netcdf_save_single.cdl +++ b/lib/iris/tests/results/netcdf/netcdf_save_single.cdl @@ -30,7 +30,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -39,7 +39,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/results/netcdf/netcdf_stereo.cml b/lib/iris/tests/results/netcdf/netcdf_stereo.cml index 092cf337b6..fae7ff027b 100644 --- a/lib/iris/tests/results/netcdf/netcdf_stereo.cml +++ b/lib/iris/tests/results/netcdf/netcdf_stereo.cml @@ -66,7 +66,7 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_tmerc_and_climatology.cml b/lib/iris/tests/results/netcdf/netcdf_tmerc_and_climatology.cml index 2d909ba57e..0575c684a9 100644 --- a/lib/iris/tests/results/netcdf/netcdf_tmerc_and_climatology.cml +++ b/lib/iris/tests/results/netcdf/netcdf_tmerc_and_climatology.cml @@ -62,7 +62,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/load_2flds.cml b/lib/iris/tests/results/nimrod/load_2flds.cml index b068657d40..41e92dd48b 100644 --- a/lib/iris/tests/results/nimrod/load_2flds.cml +++ b/lib/iris/tests/results/nimrod/load_2flds.cml @@ -14,7 +14,7 @@ - + - + diff --git a/lib/iris/tests/results/nimrod/period_of_interest.cml b/lib/iris/tests/results/nimrod/period_of_interest.cml index 258e5bcbbc..4c495b212a 100644 --- a/lib/iris/tests/results/nimrod/period_of_interest.cml +++ b/lib/iris/tests/results/nimrod/period_of_interest.cml @@ -3,7 +3,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/probability_fields.cml b/lib/iris/tests/results/nimrod/probability_fields.cml index 7add3e75a4..184d205132 100644 --- a/lib/iris/tests/results/nimrod/probability_fields.cml +++ b/lib/iris/tests/results/nimrod/probability_fields.cml @@ -17,7 +17,7 @@ - + + @@ -62,7 +62,7 @@ - + + @@ -111,7 +111,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -158,7 +158,7 @@ - + @@ -186,7 +186,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -237,7 +237,7 @@ - + @@ -271,7 +271,7 @@ - + @@ -291,7 +291,7 @@ - + @@ -315,7 +315,7 @@ - + @@ -331,7 +331,7 @@ - + @@ -358,7 +358,7 @@ - + @@ -378,7 +378,7 @@ - + @@ -402,7 +402,7 @@ - + @@ -422,7 +422,7 @@ - + @@ -448,7 +448,7 @@ - + @@ -461,7 +461,7 @@ - + @@ -484,7 +484,7 @@ - + @@ -497,7 +497,7 @@ - + @@ -521,7 +521,7 @@ - + @@ -537,7 +537,7 @@ - + @@ -560,7 +560,7 @@ - + @@ -573,7 +573,7 @@ - + @@ -600,7 +600,7 @@ - + @@ -620,7 +620,7 @@ - + @@ -644,7 +644,7 @@ - + @@ -664,7 +664,7 @@ - + @@ -688,7 +688,7 @@ - + @@ -701,7 +701,7 @@ - + @@ -726,7 +726,7 @@ - + @@ -742,7 +742,7 @@ - + @@ -766,7 +766,7 @@ - + @@ -779,7 +779,7 @@ - + @@ -807,7 +807,7 @@ - + @@ -828,7 +828,7 @@ - + @@ -853,7 +853,7 @@ - + @@ -873,7 +873,7 @@ - + @@ -901,7 +901,7 @@ - + @@ -922,7 +922,7 @@ - + @@ -949,7 +949,7 @@ - + @@ -969,7 +969,7 @@ - + @@ -992,7 +992,7 @@ - + @@ -1005,7 +1005,7 @@ - + @@ -1029,7 +1029,7 @@ - + @@ -1042,7 +1042,7 @@ - + @@ -1067,7 +1067,7 @@ - + @@ -1083,7 +1083,7 @@ - + @@ -1110,7 +1110,7 @@ - + @@ -1130,7 +1130,7 @@ - + @@ -1153,7 +1153,7 @@ - + @@ -1166,7 +1166,7 @@ - + @@ -1190,7 +1190,7 @@ - + @@ -1213,7 +1213,7 @@ - + @@ -1236,7 +1236,7 @@ - + @@ -1256,7 +1256,7 @@ - + @@ -1280,7 +1280,7 @@ - + @@ -1303,7 +1303,7 @@ - + @@ -1326,7 +1326,7 @@ - + @@ -1346,7 +1346,7 @@ - + @@ -1369,7 +1369,7 @@ - + @@ -1389,7 +1389,7 @@ - + @@ -1417,7 +1417,7 @@ - + @@ -1444,7 +1444,7 @@ - + @@ -1468,7 +1468,7 @@ - + @@ -1495,7 +1495,7 @@ - + @@ -1518,7 +1518,7 @@ - + @@ -1538,7 +1538,7 @@ - + @@ -1562,7 +1562,7 @@ - + @@ -1585,7 +1585,7 @@ - + @@ -1608,7 +1608,7 @@ - + @@ -1628,7 +1628,7 @@ - + @@ -1656,7 +1656,7 @@ - + @@ -1683,7 +1683,7 @@ - + @@ -1707,7 +1707,7 @@ - + @@ -1734,7 +1734,7 @@ - + @@ -1757,7 +1757,7 @@ - + @@ -1777,7 +1777,7 @@ - + @@ -1800,7 +1800,7 @@ - + @@ -1820,7 +1820,7 @@ - + @@ -1844,7 +1844,7 @@ - + @@ -1867,7 +1867,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_bmr04_precip_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_bmr04_precip_2km.cml index 31518dd321..a6ed9068ca 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_bmr04_precip_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_bmr04_precip_2km.cml @@ -19,7 +19,7 @@ [6300, 7200]]" id="b40ecfd3" points="[7200, 7200]" shape="(2,)" standard_name="forecast_period" units="Unit('second')" value_type="int32"/> - + @@ -36,7 +36,7 @@ + [1580193900, 1580194800]]" id="90a3bd1c" points="[1580194800, 1580194800]" shape="(2,)" standard_name="time" units="Unit('seconds since 1970-01-01 00:00:00', calendar='standard')" value_type="int64"/> diff --git a/lib/iris/tests/results/nimrod/u1096_ng_bsr05_precip_accum60_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_bsr05_precip_accum60_2km.cml index 80cb1834c0..cf3232d548 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_bsr05_precip_accum60_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_bsr05_precip_accum60_2km.cml @@ -18,7 +18,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud3d0060_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud3d0060_2km.cml index 68ec95555c..2aa1576fad 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud3d0060_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud3d0060_2km.cml @@ -17,7 +17,7 @@ - + - + @@ -73,7 +73,7 @@ - + - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud_2km.cml index c6bc6f0419..3dc62cc8e9 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_cloud_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -112,7 +112,7 @@ - + @@ -136,7 +136,7 @@ - + @@ -152,7 +152,7 @@ - + @@ -175,7 +175,7 @@ - + - + @@ -226,7 +226,7 @@ - + @@ -242,7 +242,7 @@ - + @@ -268,7 +268,7 @@ - + @@ -284,7 +284,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml index e6c99f9e50..9be61d489c 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml @@ -24,7 +24,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -102,7 +102,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -141,7 +141,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -208,7 +208,7 @@ - + @@ -231,7 +231,7 @@ - + @@ -247,7 +247,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -286,7 +286,7 @@ - + @@ -309,7 +309,7 @@ - + @@ -328,7 +328,7 @@ - + @@ -351,7 +351,7 @@ - + @@ -370,7 +370,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_convwind_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_convwind_2km.cml index 2f52a93277..734beb7f47 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_convwind_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_convwind_2km.cml @@ -24,7 +24,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -70,7 +70,7 @@ - + @@ -86,7 +86,7 @@ - + @@ -116,7 +116,7 @@ - + @@ -132,7 +132,7 @@ - + @@ -162,7 +162,7 @@ - + @@ -178,7 +178,7 @@ - + @@ -208,7 +208,7 @@ - + @@ -224,7 +224,7 @@ - + @@ -247,7 +247,7 @@ - + @@ -270,7 +270,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_frzlev_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_frzlev_2km.cml index b2b47715a2..56bfecc1b4 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_frzlev_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_frzlev_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -111,7 +111,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -151,7 +151,7 @@ - + @@ -175,7 +175,7 @@ - + @@ -191,7 +191,7 @@ - + @@ -214,7 +214,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -254,7 +254,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -294,7 +294,7 @@ - + @@ -310,7 +310,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_height_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_height_2km.cml index 4fb1371250..2eb83d787b 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_height_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_height_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_precip_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_precip_2km.cml index 59776b5b74..4f4c986a39 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_precip_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_precip_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -113,7 +113,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_precipaccum_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_precipaccum_2km.cml index 0fa98e3bb6..dd6102ea7f 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_precipaccum_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_precipaccum_2km.cml @@ -19,7 +19,7 @@ [6300, 7200]]" id="b40ecfd3" points="[7200, 7200]" shape="(2,)" standard_name="forecast_period" units="Unit('second')" value_type="int32"/> - + @@ -36,7 +36,7 @@ + [1580186700, 1580187600]]" id="90a3bd1c" points="[1580187600, 1580187600]" shape="(2,)" standard_name="time" units="Unit('seconds since 1970-01-01 00:00:00', calendar='standard')" value_type="int64"/> diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_preciptype_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_preciptype_2km.cml index 3fdf646e70..be1e89a53d 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_preciptype_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_preciptype_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -113,7 +113,7 @@ - + @@ -136,7 +136,7 @@ - + @@ -152,7 +152,7 @@ - + @@ -176,7 +176,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -216,7 +216,7 @@ - + @@ -232,7 +232,7 @@ - + @@ -255,7 +255,7 @@ - + @@ -271,7 +271,7 @@ - + @@ -295,7 +295,7 @@ - + @@ -311,7 +311,7 @@ - + @@ -335,7 +335,7 @@ - + @@ -351,7 +351,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_pressure_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_pressure_2km.cml index edb0862676..9a3ff88df8 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_pressure_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_pressure_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiation_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiation_2km.cml index 38f076f232..00bc65f236 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiation_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiation_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -111,7 +111,7 @@ - + @@ -134,7 +134,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -173,7 +173,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -212,7 +212,7 @@ - + @@ -228,7 +228,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -267,7 +267,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiationuv_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiationuv_2km.cml index 35bed38591..b2cf624214 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiationuv_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_radiationuv_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -111,7 +111,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_refl_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_refl_2km.cml index 4411ff9dd5..aaed20394f 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_refl_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_refl_2km.cml @@ -26,7 +26,7 @@ - + @@ -42,7 +42,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml index 8759dac5c7..3a25dc86fc 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml @@ -17,7 +17,7 @@ - + - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity_2km.cml index 9b7e7582d0..fa4ab30a58 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity_2km.cml @@ -17,7 +17,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_snow_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_snow_2km.cml index ce549ab3cd..918a0c7ae5 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_snow_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_snow_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -112,7 +112,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil3d0060_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil3d0060_2km.cml index 9385bfc9ae..3a6c3bf53c 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil3d0060_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil3d0060_2km.cml @@ -24,7 +24,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -70,7 +70,7 @@ - + @@ -86,7 +86,7 @@ - + @@ -116,7 +116,7 @@ - + @@ -132,7 +132,7 @@ - + @@ -162,7 +162,7 @@ - + @@ -178,7 +178,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil_2km.cml index a76971a1ed..eab889a8af 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_soil_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -77,7 +77,7 @@ urban_roof, water]" shape="(10,)" standard_name="soil_type" units="Unit('unknown')" value_type="string"/> - + @@ -100,7 +100,7 @@ - + @@ -121,7 +121,7 @@ urban_roof, water]" shape="(10,)" standard_name="soil_type" units="Unit('unknown')" value_type="string"/> - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_temperature_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_temperature_2km.cml index 09677ff57a..6ff6359046 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_temperature_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_temperature_2km.cml @@ -18,7 +18,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -65,7 +65,7 @@ - + @@ -88,7 +88,7 @@ - + @@ -111,7 +111,7 @@ - + @@ -134,7 +134,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -180,7 +180,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_visibility_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_visibility_2km.cml index 8a0f50700c..037cb5c2b6 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_visibility_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_visibility_2km.cml @@ -17,7 +17,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -86,7 +86,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -132,7 +132,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -178,7 +178,7 @@ - + @@ -201,7 +201,7 @@ - + @@ -224,7 +224,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_wind_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_wind_2km.cml index df2054e8af..5ca9920172 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_wind_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_wind_2km.cml @@ -18,7 +18,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -110,7 +110,7 @@ - + @@ -133,7 +133,7 @@ - + @@ -156,7 +156,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -225,7 +225,7 @@ - + @@ -249,7 +249,7 @@ - + @@ -272,7 +272,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv3d0015_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv3d0015_2km.cml index 331ff59c74..91c40ea6d0 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv3d0015_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv3d0015_2km.cml @@ -17,7 +17,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -86,7 +86,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv_2km.cml index aa14346e2f..3252dbf047 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_winduv_2km.cml @@ -17,7 +17,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -86,7 +86,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek01_cape_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek01_cape_2km.cml index 1756ac0205..d39fa0e367 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek01_cape_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek01_cape_2km.cml @@ -17,7 +17,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -98,7 +98,7 @@ - + @@ -114,7 +114,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -176,7 +176,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -215,7 +215,7 @@ - + @@ -231,7 +231,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek07_precip0540_accum180_18km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek07_precip0540_accum180_18km.cml index f4710dd36d..4a5783ecb3 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek07_precip0540_accum180_18km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek07_precip0540_accum180_18km.cml @@ -18,7 +18,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_umqv_fog_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_umqv_fog_2km.cml index 57756ccc1d..d2c7e72848 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_umqv_fog_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_umqv_fog_2km.cml @@ -17,7 +17,7 @@ - + @@ -37,7 +37,7 @@ - + - + diff --git a/lib/iris/tests/results/pandas/as_cube/series_datetime_gregorian.cml b/lib/iris/tests/results/pandas/as_cube/series_datetime_standard.cml similarity index 86% rename from lib/iris/tests/results/pandas/as_cube/series_datetime_gregorian.cml rename to lib/iris/tests/results/pandas/as_cube/series_datetime_standard.cml index 7e2e6f4166..5cb621d5f3 100644 --- a/lib/iris/tests/results/pandas/as_cube/series_datetime_gregorian.cml +++ b/lib/iris/tests/results/pandas/as_cube/series_datetime_standard.cml @@ -4,7 +4,7 @@ + 300292.067778, 309797.084722]" shape="(5,)" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/pp_load_rules/global.cml b/lib/iris/tests/results/pp_load_rules/global.cml index 2df84a8606..a69e633e26 100644 --- a/lib/iris/tests/results/pp_load_rules/global.cml +++ b/lib/iris/tests/results/pp_load_rules/global.cml @@ -10,7 +10,7 @@ - + - + diff --git a/lib/iris/tests/results/pp_load_rules/lbproc_mean_max_min.cml b/lib/iris/tests/results/pp_load_rules/lbproc_mean_max_min.cml index 9e4b6d31f5..ecf51190c7 100644 --- a/lib/iris/tests/results/pp_load_rules/lbproc_mean_max_min.cml +++ b/lib/iris/tests/results/pp_load_rules/lbproc_mean_max_min.cml @@ -11,7 +11,7 @@ - + @@ -31,7 +31,7 @@ - + @@ -48,7 +48,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -89,7 +89,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -130,7 +130,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -171,7 +171,7 @@ - + @@ -190,7 +190,7 @@ 850.0, 925.0, 950.0, 1000.0]" shape="(28,)" units="Unit('hPa')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/pp_load_rules/rotated_uk.cml b/lib/iris/tests/results/pp_load_rules/rotated_uk.cml index 51b4682ebf..ece399df4e 100644 --- a/lib/iris/tests/results/pp_load_rules/rotated_uk.cml +++ b/lib/iris/tests/results/pp_load_rules/rotated_uk.cml @@ -11,7 +11,7 @@ - + @@ -35,7 +35,7 @@ - + diff --git a/lib/iris/tests/results/stock/realistic_4d.cml b/lib/iris/tests/results/stock/realistic_4d.cml index 88adbc43de..6640c54360 100644 --- a/lib/iris/tests/results/stock/realistic_4d.cml +++ b/lib/iris/tests/results/stock/realistic_4d.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/system/supported_filetype_.grib2.cml b/lib/iris/tests/results/system/supported_filetype_.grib2.cml index f334b13863..5376af2fe1 100644 --- a/lib/iris/tests/results/system/supported_filetype_.grib2.cml +++ b/lib/iris/tests/results/system/supported_filetype_.grib2.cml @@ -9,7 +9,7 @@ - + - + diff --git a/lib/iris/tests/results/system/supported_filetype_.nc.cml b/lib/iris/tests/results/system/supported_filetype_.nc.cml index 595cd287ae..6ad0a3b176 100644 --- a/lib/iris/tests/results/system/supported_filetype_.nc.cml +++ b/lib/iris/tests/results/system/supported_filetype_.nc.cml @@ -36,7 +36,7 @@ - + diff --git a/lib/iris/tests/results/system/supported_filetype_.pp.cml b/lib/iris/tests/results/system/supported_filetype_.pp.cml index 838b9fad50..e457b2921e 100644 --- a/lib/iris/tests/results/system/supported_filetype_.pp.cml +++ b/lib/iris/tests/results/system/supported_filetype_.pp.cml @@ -6,7 +6,7 @@ - + - + diff --git a/lib/iris/tests/results/trajectory/constant_latitude.cml b/lib/iris/tests/results/trajectory/constant_latitude.cml index f07f1a131f..38c208b825 100644 --- a/lib/iris/tests/results/trajectory/constant_latitude.cml +++ b/lib/iris/tests/results/trajectory/constant_latitude.cml @@ -12,7 +12,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="forecast_reference_time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/trajectory/hybrid_height.cml b/lib/iris/tests/results/trajectory/hybrid_height.cml index 63de9366dc..972fa7b330 100644 --- a/lib/iris/tests/results/trajectory/hybrid_height.cml +++ b/lib/iris/tests/results/trajectory/hybrid_height.cml @@ -54,7 +54,7 @@ [124, 125, 126, 127, 128, 129]]" shape="(5, 6)" units="Unit('m')" value_type="int64"/> - + @@ -91,7 +91,7 @@ - + diff --git a/lib/iris/tests/results/trajectory/single_point.cml b/lib/iris/tests/results/trajectory/single_point.cml index a1cf83a03b..64c71e0394 100644 --- a/lib/iris/tests/results/trajectory/single_point.cml +++ b/lib/iris/tests/results/trajectory/single_point.cml @@ -12,7 +12,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="forecast_reference_time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> @@ -88,7 +88,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/trajectory/zigzag.cml b/lib/iris/tests/results/trajectory/zigzag.cml index 3bdb3e9013..8a578c4ab4 100644 --- a/lib/iris/tests/results/trajectory/zigzag.cml +++ b/lib/iris/tests/results/trajectory/zigzag.cml @@ -11,7 +11,7 @@ - + - + diff --git a/lib/iris/tests/results/unit/analysis/cartography/project/TestAll/cube.cml b/lib/iris/tests/results/unit/analysis/cartography/project/TestAll/cube.cml index e2a1ef2ea6..2592307cda 100644 --- a/lib/iris/tests/results/unit/analysis/cartography/project/TestAll/cube.cml +++ b/lib/iris/tests/results/unit/analysis/cartography/project/TestAll/cube.cml @@ -79,7 +79,7 @@ [0.996162, 0.993097]]" id="a5c170db" long_name="sigma" points="[0.999424, 0.997504, 0.99482]" shape="(3,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_all_dims.cml index 9a522e5167..1e74c9bc9c 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_all_dims.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_last_dims.cml index 9a522e5167..1e74c9bc9c 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_last_dims.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_middle_dim.cml index 9a522e5167..1e74c9bc9c 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_middle_dim.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_zeroth_dim.cml index 9a522e5167..1e74c9bc9c 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/collapse_zeroth_dim.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/slice.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/slice.cml index 9a522e5167..1e74c9bc9c 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/slice.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/transposed.cml index 9a522e5167..1e74c9bc9c 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__derived_coords/TestBroadcastingDerived/transposed.cml @@ -498,7 +498,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml index 2db0cc598f..9fc80a0e4d 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_all_dims.cml @@ -113,7 +113,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_last_dims.cml index 2db0cc598f..9fc80a0e4d 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_last_dims.cml @@ -113,7 +113,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_middle_dim.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_middle_dim.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_zeroth_dim.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/collapse_zeroth_dim.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/slice.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/slice.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/slice.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/transposed.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMesh/transposed.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_all_dims.cml index 2db0cc598f..9fc80a0e4d 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_all_dims.cml @@ -113,7 +113,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_last_dims.cml index 2db0cc598f..9fc80a0e4d 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_last_dims.cml @@ -113,7 +113,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_middle_dim.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_middle_dim.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_zeroth_dim.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/collapse_zeroth_dim.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/slice.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/slice.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/slice.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/transposed.cml index 359656f25a..82b7e25aa3 100644 --- a/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/_arith__meshcoords/TestBroadcastingWithMeshAndDerived/transposed.cml @@ -102,7 +102,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_all_dims.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_all_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_last_dims.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_last_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_middle_dim.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_middle_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_zeroth_dim.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/collapse_zeroth_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/slice.cml b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/slice.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/slice.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/transposed.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/add/TestBroadcasting/transposed.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_all_dims.cml index d4a90d37ac..86d7855b1b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_all_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_last_dims.cml index d4a90d37ac..86d7855b1b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_last_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_middle_dim.cml index d4a90d37ac..86d7855b1b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_middle_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_zeroth_dim.cml index d4a90d37ac..86d7855b1b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/collapse_zeroth_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/slice.cml b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/slice.cml index d4a90d37ac..86d7855b1b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/slice.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/transposed.cml index d4a90d37ac..86d7855b1b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/divide/TestBroadcasting/transposed.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_all_dims.cml index 7ae36e51c3..73d6073a4b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_all_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_last_dims.cml index 7ae36e51c3..73d6073a4b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_last_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_middle_dim.cml index 7ae36e51c3..73d6073a4b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_middle_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_zeroth_dim.cml index 7ae36e51c3..73d6073a4b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/collapse_zeroth_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/slice.cml b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/slice.cml index 7ae36e51c3..73d6073a4b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/slice.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/transposed.cml index 7ae36e51c3..73d6073a4b 100644 --- a/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/multiply/TestBroadcasting/transposed.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_all_dims.cml b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_all_dims.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_all_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_all_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_last_dims.cml b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_last_dims.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_last_dims.cml +++ b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_last_dims.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_middle_dim.cml b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_middle_dim.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_middle_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_middle_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_zeroth_dim.cml b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_zeroth_dim.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_zeroth_dim.cml +++ b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/collapse_zeroth_dim.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/slice.cml b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/slice.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/slice.cml +++ b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/slice.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/transposed.cml b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/transposed.cml index bea6795b38..8467544d44 100644 --- a/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/transposed.cml +++ b/lib/iris/tests/results/unit/analysis/maths/subtract/TestBroadcasting/transposed.cml @@ -110,7 +110,7 @@ + 347921.666667, 347921.833333, 347922.0]" shape="(6,)" standard_name="time" units="Unit('hours since 1970-01-01 00:00:00', calendar='standard')" value_type="float64"/> diff --git a/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/with_climatology.cdl b/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/with_climatology.cdl index 3c1033c17e..2159123553 100644 --- a/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/with_climatology.cdl +++ b/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/with_climatology.cdl @@ -13,7 +13,7 @@ variables: time:climatology = "time_climatology" ; time:units = "days since 1970-01-01 00:00:00-00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_climatology(time, bnds) ; double latitude(latitude) ; latitude:axis = "Y" ; diff --git a/lib/iris/tests/results/unit/util/mask_cube/TestCubeMask/mask_cube_2d_create_new_dim.cml b/lib/iris/tests/results/unit/util/mask_cube/TestCubeMask/mask_cube_2d_create_new_dim.cml new file mode 100644 index 0000000000..52aae1eb5e --- /dev/null +++ b/lib/iris/tests/results/unit/util/mask_cube/TestCubeMask/mask_cube_2d_create_new_dim.cml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/lib/iris/tests/results/unit/util/mask_cube/original_cube_full2d_global.cml b/lib/iris/tests/results/unit/util/mask_cube/original_cube_full2d_global.cml new file mode 100644 index 0000000000..abaebd51d6 --- /dev/null +++ b/lib/iris/tests/results/unit/util/mask_cube/original_cube_full2d_global.cml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + diff --git a/lib/iris/tests/results/unit/util/mask_cube/original_cube_simple_1d.cml b/lib/iris/tests/results/unit/util/mask_cube/original_cube_simple_1d.cml new file mode 100644 index 0000000000..bf8902bcb2 --- /dev/null +++ b/lib/iris/tests/results/unit/util/mask_cube/original_cube_simple_1d.cml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/lib/iris/tests/results/unit/util/mask_cube/original_cube_simple_2d.cml b/lib/iris/tests/results/unit/util/mask_cube/original_cube_simple_2d.cml new file mode 100644 index 0000000000..e1760775f9 --- /dev/null +++ b/lib/iris/tests/results/unit/util/mask_cube/original_cube_simple_2d.cml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cml b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cml index 1f9dfb0a14..e7c799f397 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cml +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cml @@ -11,7 +11,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cml b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cml index 06c192f8a4..66cbc7206b 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cml +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cml @@ -11,7 +11,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cml b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cml index 9b654f6c6e..af298945f0 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cml +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cml @@ -12,7 +12,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.000128.1990.12.01.00.00.b.cml b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.000128.1990.12.01.00.00.b.cml index d5d05f15fd..44999e85b7 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.000128.1990.12.01.00.00.b.cml +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.000128.1990.12.01.00.00.b.cml @@ -10,7 +10,7 @@ - + @@ -39,7 +39,7 @@ - + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.004224.1990.12.01.00.00.b.cml b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.004224.1990.12.01.00.00.b.cml index 1f4d8a4b2c..990fa0d7fe 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.004224.1990.12.01.00.00.b.cml +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.004224.1990.12.01.00.00.b.cml @@ -10,7 +10,7 @@ - + @@ -39,7 +39,7 @@ - + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.008320.1990.12.01.00.00.b.cml b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.008320.1990.12.01.00.00.b.cml index 359cba997f..43789498c1 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.008320.1990.12.01.00.00.b.cml +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/from_pp/000003000000.03.236.008320.1990.12.01.00.00.b.cml @@ -11,7 +11,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cdl b/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cdl index 429da0807b..ddbbee5d34 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cdl +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.000128.1990.12.01.00.00.b_0.cdl @@ -31,7 +31,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -40,7 +40,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cdl b/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cdl index 429da0807b..ddbbee5d34 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cdl +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.004224.1990.12.01.00.00.b_0.cdl @@ -31,7 +31,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -40,7 +40,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cdl b/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cdl index f1c94dc834..cb026fd7ae 100644 --- a/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cdl +++ b/lib/iris/tests/results/usecases/pp_to_cf_conversion/to_netcdf/000003000000.03.236.008320.1990.12.01.00.00.b_0.cdl @@ -31,7 +31,7 @@ variables: double forecast_reference_time ; forecast_reference_time:units = "hours since 1970-01-01 00:00:00" ; forecast_reference_time:standard_name = "forecast_reference_time" ; - forecast_reference_time:calendar = "gregorian" ; + forecast_reference_time:calendar = "standard" ; double height ; height:units = "m" ; height:standard_name = "height" ; @@ -40,7 +40,7 @@ variables: time:bounds = "time_bnds" ; time:units = "hours since 1970-01-01 00:00:00" ; time:standard_name = "time" ; - time:calendar = "gregorian" ; + time:calendar = "standard" ; double time_bnds(bnds) ; // global attributes: diff --git a/lib/iris/tests/runner/_runner.py b/lib/iris/tests/runner/_runner.py index 34a1af1e06..bfb2cc2402 100644 --- a/lib/iris/tests/runner/_runner.py +++ b/lib/iris/tests/runner/_runner.py @@ -130,7 +130,6 @@ def run(self): args = [ None, - "-v", f"-n={self.num_processors}", ] diff --git a/lib/iris/tests/stock/__init__.py b/lib/iris/tests/stock/__init__.py index 4310906c79..632dc95e20 100644 --- a/lib/iris/tests/stock/__init__.py +++ b/lib/iris/tests/stock/__init__.py @@ -20,7 +20,13 @@ from iris.coord_systems import GeogCS, RotatedGeogCS import iris.coords import iris.coords as icoords -from iris.coords import AuxCoord, CellMethod, DimCoord +from iris.coords import ( + AncillaryVariable, + AuxCoord, + CellMeasure, + CellMethod, + DimCoord, +) from iris.cube import Cube from ._stock_2d_latlons import ( # noqa @@ -404,6 +410,35 @@ def simple_2d_w_multidim_and_scalars(): return cube +def simple_2d_w_cell_measure_ancil_var(): + """ + Returns a two dimensional cube with a CellMeasure and AncillaryVariable. + + >>> print(simple_2d_w_cell_measure_ancil_var()) + thingness / (1) (bar: 3; foo: 4) + Dimension coordinates: + bar x - + foo - x + Cell measures: + cell_area x x + Ancillary variables: + quality_flag x - + Scalar coordinates: + wibble 1 + + """ + cube = simple_2d() + cube.add_aux_coord(AuxCoord([1], long_name="wibble"), None) + cube.add_ancillary_variable( + AncillaryVariable([1, 2, 3], standard_name="quality_flag"), 0 + ) + cube.add_cell_measure( + CellMeasure(np.arange(12).reshape(3, 4), standard_name="cell_area"), + (0, 1), + ) + return cube + + def hybrid_height(): """ Returns a two-dimensional (Z, X), hybrid-height cube. diff --git a/lib/iris/tests/stock/file_headers/xios_2D_face_half_levels.cdl b/lib/iris/tests/stock/file_headers/xios_2D_face_half_levels.cdl index ba3522b491..1e5522854e 100644 --- a/lib/iris/tests/stock/file_headers/xios_2D_face_half_levels.cdl +++ b/lib/iris/tests/stock/file_headers/xios_2D_face_half_levels.cdl @@ -39,7 +39,7 @@ variables: double time_instant(time_counter) ; time_instant:standard_name = "time" ; time_instant:long_name = "Time axis" ; - time_instant:calendar = "gregorian" ; + time_instant:calendar = "standard" ; time_instant:units = "seconds since 2016-01-01 15:00:00" ; time_instant:time_origin = "2016-01-01 15:00:00" ; time_instant:bounds = "time_instant_bounds" ; @@ -55,8 +55,4 @@ variables: :name = "${DATASET_NAME}" ; // original name = "lfric_ngvat_2D_1t_face_half_levels_main_conv_rain" :Conventions = "UGRID" ; - -// data -data: - time_instant = 0 ; } diff --git a/lib/iris/tests/stock/file_headers/xios_3D_face_full_levels.cdl b/lib/iris/tests/stock/file_headers/xios_3D_face_full_levels.cdl index a87e3055c9..9159bf6e46 100644 --- a/lib/iris/tests/stock/file_headers/xios_3D_face_full_levels.cdl +++ b/lib/iris/tests/stock/file_headers/xios_3D_face_full_levels.cdl @@ -42,7 +42,7 @@ variables: double time_instant(time_counter) ; time_instant:standard_name = "time" ; time_instant:long_name = "Time axis" ; - time_instant:calendar = "gregorian" ; + time_instant:calendar = "standard" ; time_instant:units = "seconds since 2016-01-01 15:00:00" ; time_instant:time_origin = "2016-01-01 15:00:00" ; time_instant:bounds = "time_instant_bounds" ; @@ -58,8 +58,4 @@ variables: :name = "${DATASET_NAME}" ; // original name = "lfric_ngvat_3D_1t_full_level_face_grid_main_u3" :Conventions = "UGRID" ; - -// data -data: - time_instant = 0 ; } diff --git a/lib/iris/tests/stock/file_headers/xios_3D_face_half_levels.cdl b/lib/iris/tests/stock/file_headers/xios_3D_face_half_levels.cdl index f9c9c148dd..f79ae0bdaf 100644 --- a/lib/iris/tests/stock/file_headers/xios_3D_face_half_levels.cdl +++ b/lib/iris/tests/stock/file_headers/xios_3D_face_half_levels.cdl @@ -42,7 +42,7 @@ variables: double time_instant(time_counter) ; time_instant:standard_name = "time" ; time_instant:long_name = "Time axis" ; - time_instant:calendar = "gregorian" ; + time_instant:calendar = "standard" ; time_instant:units = "seconds since 2016-01-01 15:00:00" ; time_instant:time_origin = "2016-01-01 15:00:00" ; time_instant:bounds = "time_instant_bounds" ; @@ -58,8 +58,4 @@ variables: :name = "${DATASET_NAME}" ; // original name = "lfric_ngvat_3D_1t_half_level_face_grid_derived_theta_in_w3" :Conventions = "UGRID" ; - -// data -data: - time_instant = 0 ; } diff --git a/lib/iris/tests/stock/netcdf.py b/lib/iris/tests/stock/netcdf.py index c5ec5ce446..8a448f7d34 100644 --- a/lib/iris/tests/stock/netcdf.py +++ b/lib/iris/tests/stock/netcdf.py @@ -51,13 +51,13 @@ def ncgen_from_cdl( f_out.write(cdl_str) if cdl_path: # Create netcdf from stored CDL file. - call_args = [NCGEN_PATHSTR, cdl_path, "-k4", "-o", nc_path] + call_args = [NCGEN_PATHSTR, cdl_path, "-k3", "-o", nc_path] call_kwargs = {} else: # No CDL file : pipe 'cdl_str' directly into the ncgen program. if not cdl_str: raise ValueError("Must provide either 'cdl_str' or 'cdl_path'.") - call_args = [NCGEN_PATHSTR, "-k4", "-o", nc_path] + call_args = [NCGEN_PATHSTR, "-k3", "-o", nc_path] call_kwargs = dict(input=cdl_str, encoding="ascii") subprocess.run(call_args, check=True, **call_kwargs) diff --git a/lib/iris/tests/system_test.py b/lib/iris/tests/system_test.py index 00cb541e1c..745163b485 100644 --- a/lib/iris/tests/system_test.py +++ b/lib/iris/tests/system_test.py @@ -51,7 +51,7 @@ def horiz_cs(): ) ) hours_since_epoch = cf_units.Unit( - "hours since epoch", cf_units.CALENDAR_GREGORIAN + "hours since epoch", cf_units.CALENDAR_STANDARD ) cm.add_aux_coord( iris.coords.AuxCoord( diff --git a/lib/iris/tests/test_analysis.py b/lib/iris/tests/test_analysis.py index e95978a371..e0a5d0971e 100644 --- a/lib/iris/tests/test_analysis.py +++ b/lib/iris/tests/test_analysis.py @@ -1013,7 +1013,9 @@ def test_max_run_masked(self): # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] - iris.util.mask_cube(cube, np.isin(cube.data, [0, 2, 3, 5, 7, 11])) + iris.util.mask_cube( + cube, np.isin(cube.data, [0, 2, 3, 5, 7, 11]), in_place=True + ) # [[-- 1 -- --] # [ 4 -- 6 --] # [ 8 9 10 --]] diff --git a/lib/iris/tests/test_basic_maths.py b/lib/iris/tests/test_basic_maths.py index 24f2b89442..6c08dc1f9e 100644 --- a/lib/iris/tests/test_basic_maths.py +++ b/lib/iris/tests/test_basic_maths.py @@ -687,12 +687,12 @@ def setUp(self): self.data_1u = np.array([[9, 9, 9], [8, 8, 8]], dtype=np.uint64) self.data_2u = np.array([[3, 3, 3], [2, 2, 2]], dtype=np.uint64) - self.cube_1f = Cube(self.data_1f) - self.cube_2f = Cube(self.data_2f) - self.cube_1i = Cube(self.data_1i) - self.cube_2i = Cube(self.data_2i) - self.cube_1u = Cube(self.data_1u) - self.cube_2u = Cube(self.data_2u) + self.cube_1f = Cube(self.data_1f.copy()) + self.cube_2f = Cube(self.data_2f.copy()) + self.cube_1i = Cube(self.data_1i.copy()) + self.cube_2i = Cube(self.data_2i.copy()) + self.cube_1u = Cube(self.data_1u.copy()) + self.cube_2u = Cube(self.data_2u.copy()) self.ops = (operator.add, operator.sub, operator.mul, operator.truediv) self.iops = ( diff --git a/lib/iris/tests/test_cell.py b/lib/iris/tests/test_cell.py index 03d3fa7d7c..21d2603072 100644 --- a/lib/iris/tests/test_cell.py +++ b/lib/iris/tests/test_cell.py @@ -169,9 +169,35 @@ def test_coord_bounds_cmp(self): self.assertTrue(self.e < 2) def test_cell_cell_cmp(self): + self.e = iris.coords.Cell(1) + self.f = iris.coords.Cell(1) + + self.assertTrue(self.e == self.f) + self.assertEqual(hash(self.e), hash(self.f)) + + self.e = iris.coords.Cell(1) + self.f = iris.coords.Cell(1, [0, 2]) + + self.assertFalse(self.e == self.f) + self.assertNotEqual(hash(self.e), hash(self.f)) + + self.e = iris.coords.Cell(1, [0, 2]) + self.f = iris.coords.Cell(1, [0, 2]) + + self.assertTrue(self.e == self.f) + self.assertEqual(hash(self.e), hash(self.f)) + + self.e = iris.coords.Cell(1, [0, 2]) + self.f = iris.coords.Cell(1, [2, 0]) + + self.assertTrue(self.e == self.f) + self.assertEqual(hash(self.e), hash(self.f)) + self.e = iris.coords.Cell(0.7, [1.1, 1.9]) self.f = iris.coords.Cell(0.8, [1.1, 1.9]) + self.assertFalse(self.e == self.f) + self.assertNotEqual(hash(self.e), hash(self.f)) self.assertFalse(self.e > self.f) self.assertTrue(self.e <= self.f) self.assertTrue(self.f >= self.e) diff --git a/lib/iris/tests/test_cf.py b/lib/iris/tests/test_cf.py index fa5e2a008d..034fb1dbda 100644 --- a/lib/iris/tests/test_cf.py +++ b/lib/iris/tests/test_cf.py @@ -295,7 +295,7 @@ def test_destructor(self): except OSError: pass buf.seek(0) - self.assertStringEqual("", buf.read()) + self.assertMultiLineEqual("", buf.read()) @tests.skip_data diff --git a/lib/iris/tests/test_coord_categorisation.py b/lib/iris/tests/test_coord_categorisation.py index 616da882f5..0206ba66a5 100644 --- a/lib/iris/tests/test_coord_categorisation.py +++ b/lib/iris/tests/test_coord_categorisation.py @@ -52,7 +52,7 @@ def setUp(self): time_coord = iris.coords.DimCoord( day_numbers, standard_name="time", - units=cf_units.Unit("days since epoch", "gregorian"), + units=cf_units.Unit("days since epoch", "standard"), ) cube.add_dim_coord(time_coord, 0) diff --git a/lib/iris/tests/test_coordsystem.py b/lib/iris/tests/test_coordsystem.py index 4497e77903..7cd15297cc 100644 --- a/lib/iris/tests/test_coordsystem.py +++ b/lib/iris/tests/test_coordsystem.py @@ -548,18 +548,18 @@ class Test_Datums(tests.IrisTest): def test_default_none(self): cs = GeogCS(6543210, 6500000) # Arbitrary radii cartopy_crs = cs.as_cartopy_crs() - self.assertStringEqual(cartopy_crs.datum.name, "unknown") + self.assertMultiLineEqual(cartopy_crs.datum.name, "unknown") def test_set_persist(self): cs = GeogCS.from_datum(datum="WGS84") cartopy_crs = cs.as_cartopy_crs() - self.assertStringEqual( + self.assertMultiLineEqual( cartopy_crs.datum.name, "World Geodetic System 1984" ) cs = GeogCS.from_datum(datum="OSGB36") cartopy_crs = cs.as_cartopy_crs() - self.assertStringEqual(cartopy_crs.datum.name, "OSGB 1936") + self.assertMultiLineEqual(cartopy_crs.datum.name, "OSGB 1936") if __name__ == "__main__": diff --git a/lib/iris/tests/test_load.py b/lib/iris/tests/test_load.py index d21b40ee26..4749236abc 100644 --- a/lib/iris/tests/test_load.py +++ b/lib/iris/tests/test_load.py @@ -183,6 +183,7 @@ def new_load_http(passed_urls, *args, **kwargs): finally: iris.io.load_http = orig + @tests.skip_data def test_netCDF_Dataset_call(self): # Check that load_http calls netCDF4.Dataset and supplies the expected URL. diff --git a/lib/iris/tests/test_mapping.py b/lib/iris/tests/test_mapping.py index a71385b5bc..202c319b61 100644 --- a/lib/iris/tests/test_mapping.py +++ b/lib/iris/tests/test_mapping.py @@ -242,12 +242,6 @@ def test_pcolormesh(self): iplt.pcolormesh(self.cube) self.check_graphic() - def test_grid(self): - iplt.pcolormesh(self.cube, facecolors="none", edgecolors="blue") - # the result is a graphic which has coloured edges. This is a mpl bug, - # see https://github.com/matplotlib/matplotlib/issues/1302 - self.check_graphic() - def test_outline(self): iplt.outline(self.cube) self.check_graphic() diff --git a/lib/iris/tests/test_name.py b/lib/iris/tests/test_name.py index 2843673da8..b4e91bafd7 100644 --- a/lib/iris/tests/test_name.py +++ b/lib/iris/tests/test_name.py @@ -8,6 +8,9 @@ # import iris tests first so that some things can be initialised before # importing anything else import iris.tests as tests # isort:skip + +import tempfile + import iris @@ -39,7 +42,7 @@ def test_NAMEIII_version2(self): ) self.assertCMLApproxData(cubes, ("name", "NAMEIII_version2.cml")) - def test_NAMEII_trajectory(self): + def test_NAMEIII_trajectory(self): cubes = iris.load( tests.get_data_path(("NAME", "NAMEIII_trajectory.txt")) ) @@ -48,6 +51,32 @@ def test_NAMEII_trajectory(self): cubes, ("name", "NAMEIII_trajectory.cml"), checksum=False ) + def test_NAMEII__no_time_averaging(self): + cubes = iris.load( + tests.get_data_path(("NAME", "NAMEII_no_time_averaging.txt")) + ) + + # Also check that it saves without error. + # This was previously failing, see https://github.com/SciTools/iris/issues/3288 + with tempfile.TemporaryDirectory() as temp_dirpath: + iris.save(cubes, temp_dirpath + "/tmp.nc") + + self.assertCML( + cubes[0], + ( + "name", + "NAMEII_field__no_time_averaging_0.cml", + ), + ) + self.assertCML( + cubes, + ( + "name", + "NAMEII_field__no_time_averaging.cml", + ), + checksum=False, + ) + if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/test_pandas.py b/lib/iris/tests/test_pandas.py index af62ad23d3..f47df75def 100644 --- a/lib/iris/tests/test_pandas.py +++ b/lib/iris/tests/test_pandas.py @@ -10,12 +10,16 @@ import copy import datetime -import unittest +from termios import IXOFF # noqa: F401 import cf_units import cftime import matplotlib.units import numpy as np +import pytest + +import iris +from iris._deprecation import IrisDeprecation # Importing pandas has the side-effect of messing with the formatters # used by matplotlib for handling dates. @@ -27,13 +31,14 @@ pandas = None matplotlib.units.registry = default_units_registry -skip_pandas = unittest.skipIf( - pandas is None, 'Test(s) require "pandas", ' "which is not available." +skip_pandas = pytest.mark.skipif( + pandas is None, + reason='Test(s) require "pandas", ' "which is not available.", ) if pandas is not None: - from iris.coords import DimCoord - from iris.cube import Cube + from iris.coords import AncillaryVariable, AuxCoord, CellMeasure, DimCoord + from iris.cube import Cube, CubeList import iris.pandas @@ -63,7 +68,7 @@ def test_masked(self): series = iris.pandas.as_series(cube) self.assertArrayEqual(series, cube.data.astype("f").filled(np.nan)) - def test_time_gregorian(self): + def test_time_standard(self): cube = Cube(np.array([0, 1, 2, 3, 4]), long_name="ts") time_coord = DimCoord( [0, 100.1, 200.2, 300.3, 400.4], @@ -80,7 +85,7 @@ def test_time_gregorian(self): ] series = iris.pandas.as_series(cube) self.assertArrayEqual(series, cube.data) - self.assertListEqual(list(series.index), expected_index) + assert list(series.index) == expected_index def test_time_360(self): cube = Cube(np.array([0, 1, 2, 3, 4]), long_name="ts") @@ -107,37 +112,37 @@ def test_copy_true(self): cube = Cube(np.array([0, 1, 2, 3, 4]), long_name="foo") series = iris.pandas.as_series(cube) series[0] = 99 - self.assertEqual(cube.data[0], 0) + assert cube.data[0] == 0 def test_copy_int32_false(self): cube = Cube(np.array([0, 1, 2, 3, 4], dtype=np.int32), long_name="foo") series = iris.pandas.as_series(cube, copy=False) series[0] = 99 - self.assertEqual(cube.data[0], 99) + assert cube.data[0] == 99 def test_copy_int64_false(self): cube = Cube(np.array([0, 1, 2, 3, 4], dtype=np.int32), long_name="foo") series = iris.pandas.as_series(cube, copy=False) series[0] = 99 - self.assertEqual(cube.data[0], 99) + assert cube.data[0] == 99 def test_copy_float_false(self): cube = Cube(np.array([0, 1, 2, 3.3, 4]), long_name="foo") series = iris.pandas.as_series(cube, copy=False) series[0] = 99 - self.assertEqual(cube.data[0], 99) + assert cube.data[0] == 99 def test_copy_masked_true(self): data = np.ma.MaskedArray([0, 1, 2, 3, 4], mask=[0, 1, 0, 1, 0]) cube = Cube(data, long_name="foo") series = iris.pandas.as_series(cube) series[0] = 99 - self.assertEqual(cube.data[0], 0) + assert cube.data[0] == 0 def test_copy_masked_false(self): data = np.ma.MaskedArray([0, 1, 2, 3, 4], mask=[0, 1, 0, 1, 0]) cube = Cube(data, long_name="foo") - with self.assertRaises(ValueError): + with pytest.raises(ValueError): _ = iris.pandas.as_series(cube, copy=False) @@ -210,7 +215,7 @@ def test_masked(self): self.assertArrayEqual(data_frame.index, expected_index) self.assertArrayEqual(data_frame.columns, expected_columns) - def test_time_gregorian(self): + def test_time_standard(self): cube = Cube( np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]), long_name="ts" ) @@ -230,8 +235,8 @@ def test_time_gregorian(self): ) for day_offset in day_offsets ] - self.assertTrue(all(data_frame.columns == timestamps)) - self.assertTrue(all(data_frame.index == [0, 1])) + assert all(data_frame.columns == timestamps) + assert all(data_frame.index == [0, 1]) def test_time_360(self): cube = Cube( @@ -261,7 +266,7 @@ def test_copy_true(self): ) data_frame = iris.pandas.as_data_frame(cube) data_frame[0][0] = 99 - self.assertEqual(cube.data[0, 0], 0) + assert cube.data[0, 0] == 0 def test_copy_int32_false(self): cube = Cube( @@ -270,7 +275,7 @@ def test_copy_int32_false(self): ) data_frame = iris.pandas.as_data_frame(cube, copy=False) data_frame[0][0] = 99 - self.assertEqual(cube.data[0, 0], 99) + assert cube.data[0, 0] == 99 def test_copy_int64_false(self): cube = Cube( @@ -279,7 +284,7 @@ def test_copy_int64_false(self): ) data_frame = iris.pandas.as_data_frame(cube, copy=False) data_frame[0][0] = 99 - self.assertEqual(cube.data[0, 0], 99) + assert cube.data[0, 0] == 99 def test_copy_float_false(self): cube = Cube( @@ -287,7 +292,7 @@ def test_copy_float_false(self): ) data_frame = iris.pandas.as_data_frame(cube, copy=False) data_frame[0][0] = 99 - self.assertEqual(cube.data[0, 0], 99) + assert cube.data[0, 0] == 99 def test_copy_masked_true(self): data = np.ma.MaskedArray( @@ -297,7 +302,7 @@ def test_copy_masked_true(self): cube = Cube(data, long_name="foo") data_frame = iris.pandas.as_data_frame(cube) data_frame[0][0] = 99 - self.assertEqual(cube.data[0, 0], 0) + assert cube.data[0, 0] == 0 def test_copy_masked_false(self): data = np.ma.MaskedArray( @@ -305,7 +310,7 @@ def test_copy_masked_false(self): mask=[[0, 1, 0, 1, 0], [1, 0, 1, 0, 1]], ) cube = Cube(data, long_name="foo") - with self.assertRaises(ValueError): + with pytest.raises(ValueError): _ = iris.pandas.as_data_frame(cube, copy=False) def test_copy_false_with_cube_view(self): @@ -313,10 +318,13 @@ def test_copy_false_with_cube_view(self): cube = Cube(data[:], long_name="foo") data_frame = iris.pandas.as_data_frame(cube, copy=False) data_frame[0][0] = 99 - self.assertEqual(cube.data[0, 0], 99) + assert cube.data[0, 0] == 99 @skip_pandas +@pytest.mark.filterwarnings( + "ignore:.*as_cube has been deprecated.*:iris._deprecation.IrisDeprecation" +) class TestSeriesAsCube(tests.IrisTest): def test_series_simple(self): series = pandas.Series([0, 1, 2, 3, 4], index=[5, 6, 7, 8, 9]) @@ -348,7 +356,7 @@ def test_series_masked(self): tests.get_result_path(("pandas", "as_cube", "series_masked.cml")), ) - def test_series_datetime_gregorian(self): + def test_series_datetime_standard(self): series = pandas.Series( [0, 1, 2, 3, 4], index=[ @@ -362,7 +370,7 @@ def test_series_datetime_gregorian(self): self.assertCML( iris.pandas.as_cube(series), tests.get_result_path( - ("pandas", "as_cube", "series_datetime_gregorian.cml") + ("pandas", "as_cube", "series_datetime_standard.cml") ), ) @@ -390,16 +398,19 @@ def test_copy_true(self): series = pandas.Series([0, 1, 2, 3, 4], index=[5, 6, 7, 8, 9]) cube = iris.pandas.as_cube(series) cube.data[0] = 99 - self.assertEqual(series[5], 0) + assert series[5] == 0 def test_copy_false(self): series = pandas.Series([0, 1, 2, 3, 4], index=[5, 6, 7, 8, 9]) cube = iris.pandas.as_cube(series, copy=False) cube.data[0] = 99 - self.assertEqual(series[5], 99) + assert series[5] == 99 @skip_pandas +@pytest.mark.filterwarnings( + "ignore:.*as_cube has been deprecated.*:iris._deprecation.IrisDeprecation" +) class TestDataFrameAsCube(tests.IrisTest): def test_data_frame_simple(self): data_frame = pandas.DataFrame( @@ -471,7 +482,7 @@ def test_data_frame_cftime_360(self): ), ) - def test_data_frame_datetime_gregorian(self): + def test_data_frame_datetime_standard(self): data_frame = pandas.DataFrame( [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], index=[ @@ -483,7 +494,7 @@ def test_data_frame_datetime_gregorian(self): self.assertCML( iris.pandas.as_cube(data_frame), tests.get_result_path( - ("pandas", "as_cube", "data_frame_datetime_gregorian.cml") + ("pandas", "as_cube", "data_frame_datetime_standard.cml") ), ) @@ -491,13 +502,461 @@ def test_copy_true(self): data_frame = pandas.DataFrame([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) cube = iris.pandas.as_cube(data_frame) cube.data[0, 0] = 99 - self.assertEqual(data_frame[0][0], 0) + assert data_frame[0][0] == 0 def test_copy_false(self): data_frame = pandas.DataFrame([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) cube = iris.pandas.as_cube(data_frame, copy=False) cube.data[0, 0] = 99 - self.assertEqual(data_frame[0][0], 99) + assert data_frame[0][0] == 99 + + +@skip_pandas +class TestFutureAndDeprecation(tests.IrisTest): + def test_deprecation_warning(self): + data_frame = pandas.DataFrame([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) + with pytest.warns( + IrisDeprecation, match="as_cube has been deprecated" + ): + _ = iris.pandas.as_cube(data_frame) + + # Tests for FUTURE are expected when as_dataframe() is made n-dimensional. + + +@skip_pandas +class TestPandasAsCubes(tests.IrisTest): + @staticmethod + def _create_pandas(index_levels=0, is_series=False): + index_length = 3 + + index_names = [f"index_{i}" for i in range(index_levels)] + index_values = [ + np.arange(index_length) * 10 * (i + 1) for i in range(index_levels) + ] + + if index_levels == 1: + index = pandas.Index(index_values[0], name=index_names[0]) + data_length = index_length + elif index_levels > 1: + index = pandas.MultiIndex.from_product( + index_values, names=index_names + ) + data_length = index.nunique() + else: + index = None + data_length = index_length + + data = np.arange(data_length) * 10 + + if is_series: + class_ = pandas.Series + else: + class_ = pandas.DataFrame + + return class_(data, index=index) + + def test_1d_no_index(self): + df = self._create_pandas() + result = iris.pandas.as_cubes(df) + + expected_coord = DimCoord(df.index.values) + expected_cube = Cube( + data=df[0].values, + long_name=str(df[0].name), + dim_coords_and_dims=[(expected_coord, 0)], + ) + assert result == [expected_cube] + + def test_1d_with_index(self): + df = self._create_pandas(index_levels=1) + result = iris.pandas.as_cubes(df) + + expected_coord = DimCoord(df.index.values, long_name=df.index.name) + (result_cube,) = result + assert result_cube.dim_coords == (expected_coord,) + + def test_1d_series_no_index(self): + series = self._create_pandas(is_series=True) + result = iris.pandas.as_cubes(series) + + expected_coord = DimCoord(series.index.values) + expected_cube = Cube( + data=series.values, dim_coords_and_dims=[(expected_coord, 0)] + ) + assert result == [expected_cube] + + def test_1d_series_with_index(self): + series = self._create_pandas(index_levels=1, is_series=True) + result = iris.pandas.as_cubes(series) + + expected_coord = DimCoord( + series.index.values, long_name=series.index.name + ) + (result_cube,) = result + assert result_cube.dim_coords == (expected_coord,) + + def test_3d(self): + df = self._create_pandas(index_levels=3) + result = iris.pandas.as_cubes(df) + + expected_coords = [ + DimCoord(level.values, long_name=level.name) + for level in df.index.levels + ] + (result_cube,) = result + assert result_cube.dim_coords == tuple(expected_coords) + + def test_3d_series(self): + series = self._create_pandas(index_levels=3, is_series=True) + result = iris.pandas.as_cubes(series) + + expected_coords = [ + DimCoord(level.values, long_name=level.name) + for level in series.index.levels + ] + (result_cube,) = result + assert result_cube.dim_coords == tuple(expected_coords) + + def test_non_unique_index(self): + df = self._create_pandas(index_levels=1) + new_index = df.index.values + new_index[1] = new_index[0] + df.set_index(new_index) + + with pytest.raises(ValueError, match="not unique per row"): + _ = iris.pandas.as_cubes(df) + + def test_non_monotonic_index(self): + df = self._create_pandas(index_levels=1) + new_index = df.index.values + new_index[:2] = new_index[1::-1] + df.set_index(new_index) + + with pytest.raises(ValueError, match="not monotonic"): + _ = iris.pandas.as_cubes(df) + + def test_missing_rows(self): + df = self._create_pandas(index_levels=2) + df = df[:-1] + + with pytest.raises( + ValueError, match="Not all index values have a corresponding row" + ): + _ = iris.pandas.as_cubes(df) + + def test_aux_coord(self): + df = self._create_pandas() + coord_name = "foo" + df[coord_name] = df.index.values + result = iris.pandas.as_cubes(df, aux_coord_cols=[coord_name]) + + expected_aux_coord = AuxCoord( + df[coord_name].values, long_name=coord_name + ) + (result_cube,) = result + assert result_cube.aux_coords == (expected_aux_coord,) + + def test_cell_measure(self): + df = self._create_pandas() + coord_name = "foo" + df[coord_name] = df.index.values + result = iris.pandas.as_cubes(df, cell_measure_cols=[coord_name]) + + expected_cm = CellMeasure(df[coord_name].values, long_name=coord_name) + (result_cube,) = result + assert result_cube.cell_measures() == [expected_cm] + + def test_ancillary_variable(self): + df = self._create_pandas() + coord_name = "foo" + df[coord_name] = df.index.values + result = iris.pandas.as_cubes(df, ancillary_variable_cols=[coord_name]) + + expected_av = AncillaryVariable( + df[coord_name].values, long_name=coord_name + ) + (result_cube,) = result + assert result_cube.ancillary_variables() == [expected_av] + + def test_3d_with_2d_coord(self): + df = self._create_pandas(index_levels=3) + coord_shape = df.index.levshape[:2] + coord_values = np.arange(np.product(coord_shape)) + coord_name = "foo" + df[coord_name] = coord_values.repeat(df.index.levshape[-1]) + result = iris.pandas.as_cubes(df, aux_coord_cols=[coord_name]) + + expected_points = coord_values.reshape(coord_shape) + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + self.assertArrayEqual(result_coord.points, expected_points) + assert result_coord.cube_dims(result_cube) == (0, 1) + + def test_coord_varies_all_indices(self): + df = self._create_pandas(index_levels=3) + coord_shape = df.index.levshape + coord_values = np.arange(np.product(coord_shape)) + coord_name = "foo" + df[coord_name] = coord_values + result = iris.pandas.as_cubes(df, aux_coord_cols=[coord_name]) + + expected_points = coord_values.reshape(coord_shape) + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + self.assertArrayEqual(result_coord.points, expected_points) + assert result_coord.cube_dims(result_cube) == (0, 1, 2) + + def test_category_coord(self): + # Something that varies on a dimension, but doesn't change with every + # increment. + df = self._create_pandas(index_levels=2) + coord_shape = df.index.levshape + coord_values = np.arange(np.product(coord_shape)) + coord_name = "foo" + + # Create a repeating value along a dimension. + step = coord_shape[-1] + coord_values[1::step] = coord_values[::step] + + df[coord_name] = coord_values + result = iris.pandas.as_cubes(df, aux_coord_cols=[coord_name]) + + expected_points = coord_values.reshape(coord_shape) + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + self.assertArrayEqual(result_coord.points, expected_points) + assert result_coord.cube_dims(result_cube) == (0, 1) + + def test_scalar_coord(self): + df = self._create_pandas() + coord_values = np.ones(len(df)) + coord_name = "foo" + df[coord_name] = coord_values + result = iris.pandas.as_cubes(df, aux_coord_cols=[coord_name]) + + expected_points = np.unique(coord_values) + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + self.assertArrayEqual(result_coord.points, expected_points) + assert result_coord.cube_dims(result_cube) == tuple() + + def test_multi_phenom(self): + df = self._create_pandas() + new_name = "new_phenom" + df[new_name] = df[0] + result = iris.pandas.as_cubes(df) + + # Note the shared coord object between both Cubes. + expected_coord = DimCoord(df.index.values) + expected_cube_kwargs = dict(dim_coords_and_dims=[(expected_coord, 0)]) + + expected_cube_0 = Cube( + data=df[0].values, + long_name=str(df[0].name), + **expected_cube_kwargs, + ) + expected_cube_1 = Cube( + data=df[new_name].values, + long_name=new_name, + **expected_cube_kwargs, + ) + assert result == [expected_cube_0, expected_cube_1] + + def test_empty_series(self): + series = pandas.Series(dtype=object) + result = iris.pandas.as_cubes(series) + + assert result == CubeList() + + def test_empty_dataframe(self): + df = pandas.DataFrame() + result = iris.pandas.as_cubes(df) + + assert result == CubeList() + + def test_no_phenom(self): + df = self._create_pandas() + # Specify the only column as an AuxCoord. + result = iris.pandas.as_cubes(df, aux_coord_cols=[0]) + + assert result == CubeList() + + def test_standard_name_phenom(self): + # long_name behaviour is tested in test_1d_no_index. + df = self._create_pandas() + new_name = "air_temperature" + df = df.rename(columns={0: new_name}) + result = iris.pandas.as_cubes(df) + + (result_cube,) = result + assert result_cube.standard_name == new_name + + def test_standard_name_coord(self): + # long_name behaviour is tested in test_1d_with_index. + df = self._create_pandas() + new_name = "longitude" + df.index.names = [new_name] + result = iris.pandas.as_cubes(df) + + (result_cube,) = result + result_coord = result_cube.coord(dim_coords=True) + assert result_coord.standard_name == new_name + + def test_dtype_preserved_phenom(self): + df = self._create_pandas() + df = df.astype("int32") + result = iris.pandas.as_cubes(df) + + (result_cube,) = result + assert result_cube.dtype == np.int32 + + def test_preserve_dim_order(self): + new_order = ["index_1", "index_0", "index_2"] + + df = self._create_pandas(index_levels=3) + df = df.reset_index() + df = df.set_index(new_order) + df = df.sort_index() + result = iris.pandas.as_cubes(df) + + (result_cube,) = result + dim_order = [c.name() for c in result_cube.dim_coords] + assert dim_order == new_order + + def test_dtype_preserved_coord(self): + df = self._create_pandas() + new_index = df.index.astype("float64") + df.index = new_index + result = iris.pandas.as_cubes(df) + + (result_cube,) = result + result_coord = result_cube.coord(dim_coords=True) + assert result_coord.dtype == np.float64 + + def test_string_phenom(self): + # Strings can be uniquely troublesome. + df = self._create_pandas() + new_values = [str(v) for v in df[0]] + df[0] = new_values + result = iris.pandas.as_cubes(df) + + (result_cube,) = result + self.assertArrayEqual(result_cube.data, new_values) + + def test_string_coord(self): + # Strings can be uniquely troublesome. + # Must test using an AuxCoord since strings cannot be DimCoords. + df = self._create_pandas() + new_points = [str(v) for v in df.index.values] + coord_name = "foo" + df[coord_name] = new_points + result = iris.pandas.as_cubes(df, aux_coord_cols=[coord_name]) + + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + self.assertArrayEqual(result_coord.points, new_points) + + def test_series_with_col_args(self): + series = self._create_pandas(is_series=True) + with pytest.warns(Warning, match="is a Series; ignoring"): + _ = iris.pandas.as_cubes(series, aux_coord_cols=["some_column"]) + + def test_phenom_view(self): + df = self._create_pandas() + result = iris.pandas.as_cubes(df, copy=False) + + # Modify AFTER creating the Cube(s). + df[0][0] += 1 + + (result_cube,) = result + assert result_cube.data[0] == df[0][0] + + def test_phenom_copy(self): + df = self._create_pandas() + result = iris.pandas.as_cubes(df) + + # Modify AFTER creating the Cube(s). + df[0][0] += 1 + + (result_cube,) = result + assert result_cube.data[0] != df[0][0] + + def test_coord_never_view(self): + # Using AuxCoord - DimCoords and Pandas indices are immutable. + df = self._create_pandas() + coord_name = "foo" + df[coord_name] = df.index.values + result = iris.pandas.as_cubes( + df, copy=False, aux_coord_cols=[coord_name] + ) + + # Modify AFTER creating the Cube(s). + df[coord_name][0] += 1 + + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + assert result_coord.points[0] != df[coord_name][0] + + def _test_dates_common(self, mode=None, alt_calendar=False): + df = self._create_pandas() + kwargs = dict(pandas_structure=df) + coord_name = "dates" + + if alt_calendar: + calendar = cf_units.CALENDAR_360_DAY + # Only pass this when non-default. + kwargs["calendars"] = {coord_name: calendar} + expected_points = [8640, 8641, 8642] + else: + calendar = cf_units.CALENDAR_STANDARD + expected_points = [8760, 8761, 8762] + expected_units = cf_units.Unit( + "hours since 1970-01-01 00:00:00", calendar=calendar + ) + + datetime_args = [(1971, 1, 1, i, 0, 0) for i in df.index.values] + if mode == "index": + values = [datetime.datetime(*a) for a in datetime_args] + df.index = pandas.Index(values, name=coord_name) + elif mode == "numpy": + values = [datetime.datetime(*a) for a in datetime_args] + df[coord_name] = values + kwargs["aux_coord_cols"] = [coord_name] + elif mode == "cftime": + values = [ + cftime.datetime(*a, calendar=calendar) for a in datetime_args + ] + df[coord_name] = values + kwargs["aux_coord_cols"] = [coord_name] + else: + raise ValueError("mode needs to be set") + + result = iris.pandas.as_cubes(**kwargs) + + (result_cube,) = result + result_coord = result_cube.coord(coord_name) + assert result_coord.units == expected_units + self.assertArrayEqual(result_coord.points, expected_points) + + def test_datetime_index(self): + self._test_dates_common(mode="index") + + def test_datetime_index_calendar(self): + self._test_dates_common(mode="index", alt_calendar=True) + + def test_numpy_datetime_coord(self): + # NumPy format is what happens if a Python datetime is assigned to a + # Pandas column. + self._test_dates_common(mode="numpy") + + def test_numpy_datetime_coord_calendar(self): + self._test_dates_common(mode="numpy", alt_calendar=True) + + def test_cftime_coord(self): + self._test_dates_common(mode="cftime") + + def test_cftime_coord_calendar(self): + self._test_dates_common(mode="cftime", alt_calendar=True) if __name__ == "__main__": diff --git a/lib/iris/tests/test_plot.py b/lib/iris/tests/test_plot.py index 0c47bd6d3a..77aea2b6b6 100644 --- a/lib/iris/tests/test_plot.py +++ b/lib/iris/tests/test_plot.py @@ -342,6 +342,8 @@ def test_circular_changes(self): self.check_graphic() +@tests.skip_data +@tests.skip_plot class Test1dFillBetween(tests.GraphicsTest): def setUp(self): super().setUp() diff --git a/lib/iris/tests/test_quickplot.py b/lib/iris/tests/test_quickplot.py index dec71a99ac..06f170c666 100644 --- a/lib/iris/tests/test_quickplot.py +++ b/lib/iris/tests/test_quickplot.py @@ -247,5 +247,39 @@ def test_not_reference_time_units(self): self.check_graphic() +@tests.skip_data +@tests.skip_plot +class TestSubplotColorbar(tests.IrisTest): + def setUp(self): + theta = _load_theta() + coords = ["model_level_number", "grid_longitude"] + self.data = next(theta.slices(coords)) + spec = (1, 1, 1) + self.figure1 = plt.figure() + self.axes1 = self.figure1.add_subplot(*spec) + self.figure2 = plt.figure() + self.axes2 = self.figure2.add_subplot(*spec) + + def _check(self, mappable, figure, axes): + self.assertIs(mappable.axes, axes) + self.assertIs(mappable.colorbar.mappable, mappable) + self.assertIs(mappable.colorbar.ax.get_figure(), figure) + + def test_with_axes1(self): + # plot using the first figure subplot axes (explicit) + mappable = qplt.contourf(self.data, axes=self.axes1) + self._check(mappable, self.figure1, self.axes1) + + def test_with_axes2(self): + # plot using the second figure subplot axes (explicit) + mappable = qplt.contourf(self.data, axes=self.axes2) + self._check(mappable, self.figure2, self.axes2) + + def test_without_axes__default(self): + # plot using the second/last figure subplot axes (default) + mappable = qplt.contourf(self.data) + self._check(mappable, self.figure2, self.axes2) + + if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/unit/analysis/cartography/test_rotate_winds.py b/lib/iris/tests/unit/analysis/cartography/test_rotate_winds.py index 7bd8fdb597..7952b3bb46 100644 --- a/lib/iris/tests/unit/analysis/cartography/test_rotate_winds.py +++ b/lib/iris/tests/unit/analysis/cartography/test_rotate_winds.py @@ -16,6 +16,7 @@ import cartopy.crs as ccrs import numpy as np import numpy.ma as ma +import pytest from iris.analysis.cartography import rotate_winds, unrotate_pole import iris.coord_systems @@ -410,7 +411,11 @@ def test_transposed(self): class TestMasking(tests.IrisTest): def test_rotated_to_osgb(self): # Rotated Pole data with large extent. - x = np.linspace(311.9, 391.1, 10) + # A 'correct' answer is not known for this test; it is therefore + # written as a 'benchmark' style test - a change in behaviour will + # cause a test failure, requiring developers to approve/reject the + # new behaviour. + x = np.linspace(221.9, 301.1, 10) y = np.linspace(-23.6, 24.8, 8) u, v = uv_cubes(x, y) ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB()) @@ -422,14 +427,14 @@ def test_rotated_to_osgb(self): # Snapshot of mask with fixed tolerance of atol=2e-3 expected_mask = np.array( [ - [1, 1, 1, 0, 0, 0, 0, 0, 0, 1], - [1, 1, 1, 0, 0, 0, 0, 0, 0, 1], - [1, 1, 1, 1, 0, 0, 0, 0, 1, 1], - [1, 1, 1, 1, 0, 0, 0, 0, 1, 1], - [1, 1, 1, 1, 0, 0, 0, 0, 1, 1], - [1, 1, 1, 1, 1, 0, 0, 1, 1, 1], - [1, 1, 1, 1, 1, 0, 0, 1, 1, 1], - [1, 1, 1, 1, 1, 0, 0, 1, 1, 1], + [0, 0, 0, 1, 1, 1, 0, 0, 0, 1], + [0, 0, 0, 0, 1, 1, 1, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 0, 0, 0], + [0, 1, 1, 1, 0, 1, 1, 1, 0, 0], + [0, 1, 0, 0, 0, 0, 1, 1, 1, 0], ], np.bool_, ) @@ -443,7 +448,7 @@ def test_rotated_to_osgb(self): # Calculate percentage error (note there are no zero magnitudes # so we can divide safely). anom = 100.0 * np.abs(res_mag - expected_mag) / expected_mag - self.assertTrue(anom[~ut.data.mask].max() < 0.1) + assert anom[~ut.data.mask].max() == pytest.approx(0.3227935) def test_rotated_to_unrotated(self): # Suffiently accurate so that no mask is introduced. diff --git a/lib/iris/tests/unit/analysis/maths/__init__.py b/lib/iris/tests/unit/analysis/maths/__init__.py index 521c65a7eb..311da8a0e6 100644 --- a/lib/iris/tests/unit/analysis/maths/__init__.py +++ b/lib/iris/tests/unit/analysis/maths/__init__.py @@ -12,6 +12,7 @@ from abc import ABCMeta, abstractmethod import operator +import dask.array as da import numpy as np from numpy import ma @@ -201,18 +202,22 @@ def cube_func(self): # I.E. 'iris.analysis.maths.xx'. pass - def _test_partial_mask(self, in_place): + def _test_partial_mask(self, in_place, second_lazy=False): # Helper method for masked data tests. dat_a = ma.array([2.0, 2.0, 2.0, 2.0], mask=[1, 0, 1, 0]) dat_b = ma.array([2.0, 2.0, 2.0, 2.0], mask=[1, 1, 0, 0]) + if second_lazy: + cube_b = Cube(da.from_array(dat_b)) + else: + cube_b = Cube(dat_b) + cube_a = Cube(dat_a) - cube_b = Cube(dat_b) - com = self.data_op(dat_b, dat_a) - res = self.cube_func(cube_b, cube_a, in_place=in_place) + com = self.data_op(dat_a, dat_b) + res = self.cube_func(cube_a, cube_b, in_place=in_place) - return com, res, cube_b + return com, res, cube_a def test_partial_mask_in_place(self): # Cube in_place arithmetic operation. @@ -221,13 +226,38 @@ def test_partial_mask_in_place(self): self.assertMaskedArrayEqual(com, res.data, strict=True) self.assertIs(res, orig_cube) + def test_partial_mask_second_lazy_in_place(self): + # Only second cube has lazy data. + com, res, orig_cube = self._test_partial_mask(True, second_lazy=True) + self.assertMaskedArrayEqual(com, res.data, strict=True) + self.assertIs(res, orig_cube) + def test_partial_mask_not_in_place(self): # Cube arithmetic not an in_place operation. com, res, orig_cube = self._test_partial_mask(False) - self.assertMaskedArrayEqual(com, res.data) + self.assertMaskedArrayEqual(com, res.data, strict=True) self.assertIsNot(res, orig_cube) + def test_partial_mask_second_lazy_not_in_place(self): + # Only second cube has lazy data. + com, res, orig_cube = self._test_partial_mask(False, second_lazy=True) + self.assertMaskedArrayEqual(com, res.data, strict=True) + self.assertIsNot(res, orig_cube) + + def test_in_place_introduces_mask(self): + # If second cube is masked, result should also be masked. + data1 = np.arange(4, dtype=np.float) + data2 = ma.array([2.0, 2.0, 2.0, 2.0], mask=[1, 1, 0, 0]) + cube1 = Cube(data1) + cube2 = Cube(data2) + + com = self.data_op(data1, data2) + res = self.cube_func(cube1, cube2, in_place=True) + + self.assertMaskedArrayEqual(com, res.data, strict=True) + self.assertIs(res, cube1) + class CubeArithmeticCoordsTest(tests.IrisTest): # This class sets up pairs of cubes to test iris' ability to reject diff --git a/lib/iris/tests/unit/analysis/test_SUM.py b/lib/iris/tests/unit/analysis/test_SUM.py index dd2dcf9f9c..64699b442f 100644 --- a/lib/iris/tests/unit/analysis/test_SUM.py +++ b/lib/iris/tests/unit/analysis/test_SUM.py @@ -9,6 +9,7 @@ # importing anything else. import iris.tests as tests # isort:skip +import dask.array as da import numpy as np import numpy.ma as ma @@ -91,6 +92,16 @@ def test_weights_and_returned(self): self.assertArrayEqual(data, [14, 9, 11, 13, 15]) self.assertArrayEqual(weights, [4, 2, 2, 2, 2]) + def test_masked_weights_and_returned(self): + array = ma.array( + self.cube_2d.data, mask=[[0, 0, 1, 0, 0], [0, 0, 0, 1, 0]] + ) + data, weights = SUM.aggregate( + array, axis=0, weights=self.weights, returned=True + ) + self.assertArrayEqual(data, [14, 9, 8, 4, 15]) + self.assertArrayEqual(weights, [4, 2, 1, 1, 2]) + class Test_lazy_weights_and_returned(tests.IrisTest): def setUp(self): @@ -128,6 +139,17 @@ def test_weights_and_returned(self): self.assertArrayEqual(lazy_data.compute(), [14, 9, 11, 13, 15]) self.assertArrayEqual(weights, [4, 2, 2, 2, 2]) + def test_masked_weights_and_returned(self): + array = da.ma.masked_array( + self.cube_2d.lazy_data(), mask=[[0, 0, 1, 0, 0], [0, 0, 0, 1, 0]] + ) + lazy_data, weights = SUM.lazy_aggregate( + array, axis=0, weights=self.weights, returned=True + ) + self.assertTrue(is_lazy_data(lazy_data)) + self.assertArrayEqual(lazy_data.compute(), [14, 9, 8, 4, 15]) + self.assertArrayEqual(weights, [4, 2, 1, 1, 2]) + class Test_aggregate_shape(tests.IrisTest): def test(self): diff --git a/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py b/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py index efcbde8965..4ffeb7a67a 100644 --- a/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py +++ b/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py @@ -51,7 +51,7 @@ def _members(self): self.assertEqual(self.names(Metadata.__mro__), expected) emsg = ( "Can't instantiate abstract class .* with abstract " - "methods _members" + "method.* _members" ) with self.assertRaisesRegex(TypeError, emsg): _ = Metadata() diff --git a/lib/iris/tests/unit/concatenate/test__CubeSignature.py b/lib/iris/tests/unit/concatenate/test__CubeSignature.py index b3870a7901..cc20cdfa1f 100644 --- a/lib/iris/tests/unit/concatenate/test__CubeSignature.py +++ b/lib/iris/tests/unit/concatenate/test__CubeSignature.py @@ -24,7 +24,7 @@ def setUp(self): data = np.arange(nt, dtype=np.float32) cube = Cube(data, standard_name="air_temperature", units="K") # Temporal coordinate. - t_units = Unit("hours since 1970-01-01 00:00:00", calendar="gregorian") + t_units = Unit("hours since 1970-01-01 00:00:00", calendar="standard") t_coord = DimCoord( points=np.arange(nt), standard_name="time", units=t_units ) diff --git a/lib/iris/tests/unit/concatenate/test_concatenate.py b/lib/iris/tests/unit/concatenate/test_concatenate.py index 2af568f077..96d13d7d15 100644 --- a/lib/iris/tests/unit/concatenate/test_concatenate.py +++ b/lib/iris/tests/unit/concatenate/test_concatenate.py @@ -30,7 +30,7 @@ def simple_1d_time_cubes(self, reftimes, coords_points): standard_name="air_temperature", units="K", ) - unit = cf_units.Unit(reftime, calendar="gregorian") + unit = cf_units.Unit(reftime, calendar="standard") coord = iris.coords.DimCoord( points=np.array(coord_points, dtype=np.float32), standard_name="time", @@ -58,7 +58,7 @@ def setUp(self): cube = iris.cube.Cube(data, standard_name="air_temperature", units="K") # Time coord t_unit = cf_units.Unit( - "hours since 1970-01-01 00:00:00", calendar="gregorian" + "hours since 1970-01-01 00:00:00", calendar="standard" ) t_coord = iris.coords.DimCoord( points=np.arange(2, dtype=np.float32), diff --git a/lib/iris/tests/unit/coord_categorisation/test_add_hour.py b/lib/iris/tests/unit/coord_categorisation/test_add_hour.py index 86230c84b9..418ac72557 100644 --- a/lib/iris/tests/unit/coord_categorisation/test_add_hour.py +++ b/lib/iris/tests/unit/coord_categorisation/test_add_hour.py @@ -32,7 +32,7 @@ def setUp(self): time_coord = iris.coords.DimCoord( hour_numbers, standard_name="time", - units=cf_units.Unit("hours since epoch", "gregorian"), + units=cf_units.Unit("hours since epoch", "standard"), ) cube.add_dim_coord(time_coord, 0) diff --git a/lib/iris/tests/unit/coords/test_AncillaryVariable.py b/lib/iris/tests/unit/coords/test_AncillaryVariable.py index 4d520ac414..75b6250449 100644 --- a/lib/iris/tests/unit/coords/test_AncillaryVariable.py +++ b/lib/iris/tests/unit/coords/test_AncillaryVariable.py @@ -458,7 +458,7 @@ def test_time_values(self): [ ( "AncillaryVariable : time of previous valid detection / " - "(hours since 1970-01-01 01:00, gregorian calendar)" + "(hours since 1970-01-01 01:00, standard calendar)" ), ( " data: [1970-01-01 03:00:00, 1970-01-01 06:00:00, " diff --git a/lib/iris/tests/unit/coords/test_Cell.py b/lib/iris/tests/unit/coords/test_Cell.py index a161d7df9a..81370bd0de 100644 --- a/lib/iris/tests/unit/coords/test_Cell.py +++ b/lib/iris/tests/unit/coords/test_Cell.py @@ -30,33 +30,6 @@ def assert_raises_on_comparison(self, cell, other, exception_type, regexp): with self.assertRaisesRegex(exception_type, regexp): cell >= other - def test_cftime_cell(self): - # Check that cell comparison when the cell contains - # cftime.datetime objects raises an exception otherwise - # this will fall back to id comparison producing unreliable - # results. - cell = Cell(cftime.datetime(2010, 3, 21)) - dt = mock.Mock(timetuple=mock.Mock()) - self.assert_raises_on_comparison( - cell, dt, TypeError, "determine the order of cftime" - ) - self.assert_raises_on_comparison( - cell, 23, TypeError, "determine the order of cftime" - ) - self.assert_raises_on_comparison( - cell, "hello", TypeError, "Unexpected type.*str" - ) - - def test_cftime_other(self): - # Check that cell comparison to a cftime.datetime object - # raises an exception otherwise this will fall back to id comparison - # producing unreliable results. - dt = cftime.datetime(2010, 3, 21) - cell = Cell(mock.Mock(timetuple=mock.Mock())) - self.assert_raises_on_comparison( - cell, dt, TypeError, "determine the order of cftime" - ) - def test_PartialDateTime_bounded_cell(self): # Check that bounded comparisions to a PartialDateTime # raise an exception. These are not supported as they @@ -85,10 +58,9 @@ def test_PartialDateTime_unbounded_cell(self): def test_datetime_unbounded_cell(self): # Check that cell comparison works with datetimes. dt = datetime.datetime(2000, 6, 15) - cell = Cell(datetime.datetime(2000, 1, 1)) - # Note the absence of the inverse of these - # e.g. self.assertGreater(dt, cell). - # See http://bugs.python.org/issue8005 + cell = Cell(cftime.datetime(2000, 1, 1)) + self.assertGreater(dt, cell) + self.assertGreaterEqual(dt, cell) self.assertLess(cell, dt) self.assertLessEqual(cell, dt) @@ -146,14 +118,6 @@ def test_PartialDateTime_other(self): self.assertNotEqual(cell, PartialDateTime(month=3, hour=12)) self.assertNotEqual(cell, PartialDateTime(month=4)) - def test_nan_other(self): - # Check that nans satisfy equality. - cell1 = Cell(np.nan) - cell2 = Cell(np.nan) - self.assertEqual(cell1, np.nan) - self.assertEqual(np.nan, cell1) - self.assertEqual(cell1, cell2) - class Test_contains_point(tests.IrisTest): def test_datetimelike_bounded_cell(self): diff --git a/lib/iris/tests/unit/coords/test_Coord.py b/lib/iris/tests/unit/coords/test_Coord.py index 5f707f91db..dca6ed3c1b 100644 --- a/lib/iris/tests/unit/coords/test_Coord.py +++ b/lib/iris/tests/unit/coords/test_Coord.py @@ -332,7 +332,8 @@ def test_dim_1d(self): ) for units in ["unknown", "no_unit", 1, "K"]: coord.units = units - collapsed_coord = coord.collapsed() + with self.assertNoWarningsRegexp(): + collapsed_coord = coord.collapsed() self.assertArrayEqual( collapsed_coord.points, np.mean(coord.points) ) @@ -474,6 +475,98 @@ def test_lazy_nd_points_and_bounds(self): self.assertArrayEqual(collapsed_coord.points, da.array([55])) self.assertArrayEqual(collapsed_coord.bounds, da.array([[-2, 112]])) + def test_numeric_nd_multidim_bounds_warning(self): + self.setupTestArrays((3, 4)) + coord = AuxCoord(self.pts_real, bounds=self.bds_real, long_name="y") + + msg = ( + "Collapsing a multi-dimensional coordinate. " + "Metadata may not be fully descriptive for 'y'." + ) + with self.assertWarnsRegex(UserWarning, msg): + coord.collapsed() + + def test_lazy_nd_multidim_bounds_warning(self): + self.setupTestArrays((3, 4)) + coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy, long_name="y") + + msg = ( + "Collapsing a multi-dimensional coordinate. " + "Metadata may not be fully descriptive for 'y'." + ) + with self.assertWarnsRegex(UserWarning, msg): + coord.collapsed() + + def test_numeric_nd_noncontiguous_bounds_warning(self): + self.setupTestArrays((3)) + coord = AuxCoord(self.pts_real, bounds=self.bds_real, long_name="y") + + msg = ( + "Collapsing a non-contiguous coordinate. " + "Metadata may not be fully descriptive for 'y'." + ) + with self.assertWarnsRegex(UserWarning, msg): + coord.collapsed() + + def test_lazy_nd_noncontiguous_bounds_warning(self): + self.setupTestArrays((3)) + coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy, long_name="y") + + msg = ( + "Collapsing a non-contiguous coordinate. " + "Metadata may not be fully descriptive for 'y'." + ) + with self.assertWarnsRegex(UserWarning, msg): + coord.collapsed() + + def test_numeric_3_bounds(self): + + points = np.array([2.0, 6.0, 4.0]) + bounds = np.array([[1.0, 0.0, 3.0], [5.0, 4.0, 7.0], [3.0, 2.0, 5.0]]) + + coord = AuxCoord(points, bounds=bounds, long_name="x") + + msg = ( + r"Cannot check if coordinate is contiguous: Invalid operation for " + r"'x', with 3 bound\(s\). Contiguous bounds are only defined for " + r"1D coordinates with 2 bounds. Metadata may not be fully " + r"descriptive for 'x'. Ignoring bounds." + ) + with self.assertWarnsRegex(UserWarning, msg): + collapsed_coord = coord.collapsed() + + self.assertFalse(collapsed_coord.has_lazy_points()) + self.assertFalse(collapsed_coord.has_lazy_bounds()) + + self.assertArrayAlmostEqual(collapsed_coord.points, np.array([4.0])) + self.assertArrayAlmostEqual( + collapsed_coord.bounds, np.array([[2.0, 6.0]]) + ) + + def test_lazy_3_bounds(self): + + points = da.arange(3) * 2.0 + bounds = da.arange(3 * 3).reshape(3, 3) + + coord = AuxCoord(points, bounds=bounds, long_name="x") + + msg = ( + r"Cannot check if coordinate is contiguous: Invalid operation for " + r"'x', with 3 bound\(s\). Contiguous bounds are only defined for " + r"1D coordinates with 2 bounds. Metadata may not be fully " + r"descriptive for 'x'. Ignoring bounds." + ) + with self.assertWarnsRegex(UserWarning, msg): + collapsed_coord = coord.collapsed() + + self.assertTrue(collapsed_coord.has_lazy_points()) + self.assertTrue(collapsed_coord.has_lazy_bounds()) + + self.assertArrayAlmostEqual(collapsed_coord.points, da.array([2.0])) + self.assertArrayAlmostEqual( + collapsed_coord.bounds, da.array([[0.0, 4.0]]) + ) + class Test_is_compatible(tests.IrisTest): def setUp(self): @@ -890,7 +983,7 @@ def test_short_time_interval(self): ) expected = "\n".join( [ - "DimCoord : time / (days since 1970-01-01, gregorian calendar)", + "DimCoord : time / (days since 1970-01-01, standard calendar)", " points: [1970-01-06 00:00:00]", " shape: (1,)", " dtype: int64", @@ -907,7 +1000,7 @@ def test_short_time_interval__bounded(self): coord.guess_bounds() expected = "\n".join( [ - "DimCoord : time / (days since 1970-01-01, gregorian calendar)", + "DimCoord : time / (days since 1970-01-01, standard calendar)", " points: [1970-01-06 00:00:00, 1970-01-07 00:00:00]", " bounds: [", " [1970-01-05 12:00:00, 1970-01-06 12:00:00],", @@ -926,7 +1019,7 @@ def test_long_time_interval(self): ) expected = "\n".join( [ - "DimCoord : time / (years since 1970-01-01, gregorian calendar)", + "DimCoord : time / (years since 1970-01-01, standard calendar)", " points: [5]", " shape: (1,)", " dtype: int64", @@ -943,7 +1036,7 @@ def test_long_time_interval__bounded(self): coord.guess_bounds() expected = "\n".join( [ - "DimCoord : time / (years since 1970-01-01, gregorian calendar)", + "DimCoord : time / (years since 1970-01-01, standard calendar)", " points: [5, 6]", " bounds: [", " [4.5, 5.5],", @@ -1064,7 +1157,7 @@ class Test___init____abstractmethod(tests.IrisTest): def test(self): emsg = ( "Can't instantiate abstract class Coord with abstract" - " methods __init__" + " method.* __init__" ) with self.assertRaisesRegex(TypeError, emsg): _ = Coord(points=[0, 1]) diff --git a/lib/iris/tests/unit/coords/test__DimensionalMetadata.py b/lib/iris/tests/unit/coords/test__DimensionalMetadata.py index fd10a6f264..f9316ff92c 100644 --- a/lib/iris/tests/unit/coords/test__DimensionalMetadata.py +++ b/lib/iris/tests/unit/coords/test__DimensionalMetadata.py @@ -511,7 +511,7 @@ def test_onepoint_toolong_placeholder(self): result = self.coord_representations(shape=(2,), dates=True) expected = [ "", - "AuxCoord : x / (days since 1970-03-5, gregorian calendar)", + "AuxCoord : x / (days since 1970-03-5, standard calendar)", " points: [1970-03-05 00:00:00, 1970-03-06 00:00:00]", " shape: (2,)", " dtype: float64", @@ -540,7 +540,7 @@ def test_dates_scalar(self): ), ( "AuxCoord : time / (hours since 2025-03-23 01:00:00, " - "gregorian calendar)" + "standard calendar)" ), " points: [2025-03-23 01:00:00]", " shape: (1,)", @@ -553,7 +553,7 @@ def test_dates_bounds(self): result = self.coord_representations(dates=True, bounded=True) expected = [ "", - "AuxCoord : x / (days since 1970-03-5, gregorian calendar)", + "AuxCoord : x / (days since 1970-03-5, standard calendar)", " points: [", " 1970-03-05 00:00:00, 1970-03-06 00:00:00,", " 1970-03-07 00:00:00, 1970-03-08 00:00:00,", @@ -574,7 +574,7 @@ def test_dates_masked(self): result = self.coord_representations(dates=True, masked=True) expected = [ "", - "AuxCoord : x / (days since 1970-03-5, gregorian calendar)", + "AuxCoord : x / (days since 1970-03-5, standard calendar)", " points: [", " 1970-03-05 00:00:00, -- ,", " 1970-03-07 00:00:00, 1970-03-08 00:00:00,", @@ -749,7 +749,7 @@ def test_climatological(self): ), ( "DimCoord : time / (days since 1970-01-01 00:00:00-00, " - "gregorian calendar)" + "standard calendar)" ), " points: [2001-01-10 00:00:00]", " bounds: [[2001-01-10 00:00:00, 2011-01-10 00:00:00]]", @@ -1054,7 +1054,7 @@ def test_convert_dates(self): coord = self.sample_coord(dates=True) result = coord.summary() expected = [ - "AuxCoord : x / (days since 1970-03-5, gregorian calendar)", + "AuxCoord : x / (days since 1970-03-5, standard calendar)", " points: [", ( " 1970-03-05 00:00:00, 1970-03-06 00:00:00, " @@ -1069,7 +1069,7 @@ def test_convert_dates(self): result = coord.summary(convert_dates=False) expected = [ - "AuxCoord : x / (days since 1970-03-5, gregorian calendar)", + "AuxCoord : x / (days since 1970-03-5, standard calendar)", " points: [0., 1., 2., 3., 4.]", " shape: (5,)", " dtype: float64", diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index ea4a200c5c..62c719aab9 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -9,12 +9,14 @@ # importing anything else. import iris.tests as tests # isort:skip +from collections import namedtuple from itertools import permutations from unittest import mock from cf_units import Unit import numpy as np import numpy.ma as ma +import pytest from iris._lazy_data import as_lazy_data import iris.analysis @@ -564,6 +566,67 @@ def test_no_lat_weighted_aggregator_mixed(self): self._assert_nowarn_collapse_without_weight(coords, warn) +class Test_collapsed_coord_with_3_bounds(tests.IrisTest): + def setUp(self): + self.cube = Cube([1, 2]) + + bounds = [[0.0, 1.0, 2.0], [2.0, 3.0, 4.0]] + lat = AuxCoord([1.0, 2.0], bounds=bounds, standard_name="latitude") + lon = AuxCoord([1.0, 2.0], bounds=bounds, standard_name="longitude") + + self.cube.add_aux_coord(lat, 0) + self.cube.add_aux_coord(lon, 0) + + def _assert_warn_cannot_check_contiguity(self, warn): + # Ensure that warning is raised. + for coord in ["latitude", "longitude"]: + msg = ( + f"Cannot check if coordinate is contiguous: Invalid " + f"operation for '{coord}', with 3 bound(s). Contiguous " + f"bounds are only defined for 1D coordinates with 2 " + f"bounds. Metadata may not be fully descriptive for " + f"'{coord}'. Ignoring bounds." + ) + self.assertIn(mock.call(msg), warn.call_args_list) + + def _assert_cube_as_expected(self, cube): + """Ensure that cube data and coordiantes are as expected.""" + self.assertArrayEqual(cube.data, np.array(3)) + + lat = cube.coord("latitude") + self.assertArrayAlmostEqual(lat.points, np.array([1.5])) + self.assertArrayAlmostEqual(lat.bounds, np.array([[1.0, 2.0]])) + + lon = cube.coord("longitude") + self.assertArrayAlmostEqual(lon.points, np.array([1.5])) + self.assertArrayAlmostEqual(lon.bounds, np.array([[1.0, 2.0]])) + + def test_collapsed_lat_with_3_bounds(self): + """Collapse latitude with 3 bounds.""" + with mock.patch("warnings.warn") as warn: + collapsed_cube = self.cube.collapsed("latitude", iris.analysis.SUM) + self._assert_warn_cannot_check_contiguity(warn) + self._assert_cube_as_expected(collapsed_cube) + + def test_collapsed_lon_with_3_bounds(self): + """Collapse longitude with 3 bounds.""" + with mock.patch("warnings.warn") as warn: + collapsed_cube = self.cube.collapsed( + "longitude", iris.analysis.SUM + ) + self._assert_warn_cannot_check_contiguity(warn) + self._assert_cube_as_expected(collapsed_cube) + + def test_collapsed_lat_lon_with_3_bounds(self): + """Collapse latitude and longitude with 3 bounds.""" + with mock.patch("warnings.warn") as warn: + collapsed_cube = self.cube.collapsed( + ["latitude", "longitude"], iris.analysis.SUM + ) + self._assert_warn_cannot_check_contiguity(warn) + self._assert_cube_as_expected(collapsed_cube) + + class Test_summary(tests.IrisTest): def setUp(self): self.cube = Cube(0) @@ -2875,5 +2938,255 @@ def test_cell_method_correct_order(self): self.assertTrue(cube1 == cube2) +@pytest.fixture +def simplecube(): + return stock.simple_2d_w_cell_measure_ancil_var() + + +class Test__dimensional_metadata: + """ + Tests for the "Cube._dimensional_data" method. + + NOTE: test could all be static methods, but that adds a line to each definition. + """ + + def test_not_found(self, simplecube): + with pytest.raises(KeyError, match="was not found in"): + simplecube._dimensional_metadata("grid_latitude") + + def test_dim_coord_name_found(self, simplecube): + res = simplecube._dimensional_metadata("bar") + assert res == simplecube.coord("bar") + + def test_dim_coord_instance_found(self, simplecube): + res = simplecube._dimensional_metadata(simplecube.coord("bar")) + assert res == simplecube.coord("bar") + + def test_aux_coord_name_found(self, simplecube): + res = simplecube._dimensional_metadata("wibble") + assert res == simplecube.coord("wibble") + + def test_aux_coord_instance_found(self, simplecube): + res = simplecube._dimensional_metadata(simplecube.coord("wibble")) + assert res == simplecube.coord("wibble") + + def test_cell_measure_name_found(self, simplecube): + res = simplecube._dimensional_metadata("cell_area") + assert res == simplecube.cell_measure("cell_area") + + def test_cell_measure_instance_found(self, simplecube): + res = simplecube._dimensional_metadata( + simplecube.cell_measure("cell_area") + ) + assert res == simplecube.cell_measure("cell_area") + + def test_ancillary_var_name_found(self, simplecube): + res = simplecube._dimensional_metadata("quality_flag") + assert res == simplecube.ancillary_variable("quality_flag") + + def test_ancillary_var_instance_found(self, simplecube): + res = simplecube._dimensional_metadata( + simplecube.ancillary_variable("quality_flag") + ) + assert res == simplecube.ancillary_variable("quality_flag") + + def test_two_with_same_name(self, simplecube): + # If a cube has two _DimensionalMetadata objects with the same name, the + # current behaviour results in _dimensional_metadata returning the first + # one it finds. + simplecube.cell_measure("cell_area").rename("wibble") + res = simplecube._dimensional_metadata("wibble") + assert res == simplecube.coord("wibble") + + def test_two_with_same_name_specify_instance(self, simplecube): + # The cube has two _DimensionalMetadata objects with the same name so + # we specify the _DimensionalMetadata instance to ensure it returns the + # correct one. + simplecube.cell_measure("cell_area").rename("wibble") + res = simplecube._dimensional_metadata( + simplecube.cell_measure("wibble") + ) + assert res == simplecube.cell_measure("wibble") + + +class TestReprs: + """ + Confirm that str(cube), repr(cube) and cube.summary() work by creating a fresh + :class:`iris._representation.cube_printout.CubePrinter` object, and using it + in the expected ways. + + Notes + ----- + This only tests code connectivity. The functionality is tested elsewhere, in + `iris.tests.unit._representation.cube_printout.test_CubePrintout`. + """ + + # Note: logically this could be a staticmethod, but that seems to upset Pytest + @pytest.fixture + def patched_cubeprinter(self): + target = "iris._representation.cube_printout.CubePrinter" + instance_mock = mock.MagicMock( + to_string=mock.MagicMock( + return_value="" + ) # NB this must return a string + ) + with mock.patch(target, return_value=instance_mock) as class_mock: + yield class_mock, instance_mock + + @staticmethod + def _check_expected_effects( + simplecube, patched_cubeprinter, oneline, padding + ): + class_mock, instance_mock = patched_cubeprinter + assert class_mock.call_args_list == [ + # "CubePrinter()" was called exactly once, with the cube as arg + mock.call(simplecube) + ] + assert instance_mock.to_string.call_args_list == [ + # "CubePrinter(cube).to_string()" was called exactly once, with these args + mock.call(oneline=oneline, name_padding=padding) + ] + + def test_str_effects(self, simplecube, patched_cubeprinter): + str(simplecube) + self._check_expected_effects( + simplecube, patched_cubeprinter, oneline=False, padding=35 + ) + + def test_repr_effects(self, simplecube, patched_cubeprinter): + repr(simplecube) + self._check_expected_effects( + simplecube, patched_cubeprinter, oneline=True, padding=1 + ) + + def test_summary_effects(self, simplecube, patched_cubeprinter): + simplecube.summary( + shorten=mock.sentinel.oneliner, name_padding=mock.sentinel.padding + ) + self._check_expected_effects( + simplecube, + patched_cubeprinter, + oneline=mock.sentinel.oneliner, + padding=mock.sentinel.padding, + ) + + +class TestHtmlRepr: + """ + Confirm that Cube._repr_html_() creates a fresh + :class:`iris.experimental.representation.CubeRepresentation` object, and uses it + in the expected way. + + Notes + ----- + This only tests code connectivity. The functionality is tested elsewhere, in + `iris.tests.unit.experimental.representation.test_CubeRepresentation`. + """ + + # Note: logically this could be a staticmethod, but that seems to upset Pytest + @pytest.fixture + def patched_cubehtml(self): + target = "iris.experimental.representation.CubeRepresentation" + instance_mock = mock.MagicMock( + repr_html=mock.MagicMock( + return_value="" + ) # NB this must return a string + ) + with mock.patch(target, return_value=instance_mock) as class_mock: + yield class_mock, instance_mock + + @staticmethod + def test__repr_html__effects(simplecube, patched_cubehtml): + simplecube._repr_html_() + + class_mock, instance_mock = patched_cubehtml + assert class_mock.call_args_list == [ + # "CubeRepresentation()" was called exactly once, with the cube as arg + mock.call(simplecube) + ] + assert instance_mock.repr_html.call_args_list == [ + # "CubeRepresentation(cube).repr_html()" was called exactly once, with no args + mock.call() + ] + + +class Test__cell_methods: + @pytest.fixture(autouse=True) + def cell_measures_testdata(self): + self.cube = Cube([0]) + self.cm = CellMethod("mean", "time", "6hr") + self.cm2 = CellMethod("max", "latitude", "4hr") + + def test_none(self): + assert self.cube.cell_methods == () + + def test_one(self): + cube = Cube([0], cell_methods=[self.cm]) + expected = (self.cm,) + assert expected == cube.cell_methods + + def test_empty_assigns(self): + testargs = [(), [], {}, 0, 0.0, False, None] + results = [] + for arg in testargs: + cube = self.cube.copy() + cube.cell_methods = arg # assign test object + results.append(cube.cell_methods) # capture what is read back + expected_results = [()] * len(testargs) + assert expected_results == results + + def test_single_assigns(self): + cms = (self.cm, self.cm2) + # Any type of iterable ought to work + # But N.B. *not* testing sets, as order is not stable + testargs = [cms, list(cms), {cm: 1 for cm in cms}] + results = [] + for arg in testargs: + cube = self.cube.copy() + cube.cell_methods = arg # assign test object + results.append(cube.cell_methods) # capture what is read back + expected_results = [cms] * len(testargs) + assert expected_results == results + + def test_fail_assign_noniterable(self): + test_object = object() + with pytest.raises(TypeError, match="not iterable"): + self.cube.cell_methods = test_object + + def test_fail_create_noniterable(self): + test_object = object() + with pytest.raises(TypeError, match="not iterable"): + Cube([0], cell_methods=test_object) + + def test_fail_assign_noncellmethod(self): + test_object = object() + with pytest.raises(ValueError, match="not an iris.coords.CellMethod"): + self.cube.cell_methods = (test_object,) + + def test_fail_create_noncellmethod(self): + test_object = object() + with pytest.raises(ValueError, match="not an iris.coords.CellMethod"): + Cube([0], cell_methods=[test_object]) + + def test_assign_derivedcellmethod(self): + class DerivedCellMethod(CellMethod): + pass + + test_object = DerivedCellMethod("mean", "time", "6hr") + cms = (test_object,) + self.cube.cell_methods = (test_object,) + assert cms == self.cube.cell_methods + + def test_fail_assign_duckcellmethod(self): + # Can't currently assign a "duck-typed" CellMethod replacement, since + # implementation requires class membership (boo!) + DuckCellMethod = namedtuple("DuckCellMethod", CellMethod._names) + test_object = DuckCellMethod( + *CellMethod._names + ) # fill props with value==name + with pytest.raises(ValueError, match="not an iris.coords.CellMethod"): + self.cube.cell_methods = (test_object,) + + if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/unit/cube/test_CubeList.py b/lib/iris/tests/unit/cube/test_CubeList.py index 771b214fe4..86457d3888 100644 --- a/lib/iris/tests/unit/cube/test_CubeList.py +++ b/lib/iris/tests/unit/cube/test_CubeList.py @@ -48,7 +48,7 @@ def test_fail(self): class Test_concatenate_cube(tests.IrisTest): def setUp(self): self.units = Unit( - "days since 1970-01-01 00:00:00", calendar="gregorian" + "days since 1970-01-01 00:00:00", calendar="standard" ) self.cube1 = Cube([1, 2, 3], "air_temperature", units="K") self.cube1.add_dim_coord( @@ -64,7 +64,7 @@ def test_pass(self): self.assertIsInstance(result, Cube) def test_fail(self): - units = Unit("days since 1970-01-02 00:00:00", calendar="gregorian") + units = Unit("days since 1970-01-02 00:00:00", calendar="standard") cube2 = Cube([1, 2, 3], "air_temperature", units="K") cube2.add_dim_coord(DimCoord([0, 1, 2], "time", units=units), 0) with self.assertRaises(iris.exceptions.ConcatenateError): @@ -735,5 +735,36 @@ def test_copy(self): self.assertIsInstance(self.copied_cube_list, iris.cube.CubeList) +class TestHtmlRepr: + """ + Confirm that Cubelist._repr_html_() creates a fresh + :class:`iris.experimental.representation.CubeListRepresentation` object, and uses + it in the expected way. + + Notes + ----- + This only tests code connectivity. The functionality is tested elsewhere, at + `iris.tests.unit.experimental.representation.test_CubeListRepresentation` + """ + + @staticmethod + def test__repr_html_(): + test_cubelist = CubeList([]) + + target = "iris.experimental.representation.CubeListRepresentation" + with mock.patch(target) as class_mock: + # Exercise the function-under-test. + test_cubelist._repr_html_() + + assert class_mock.call_args_list == [ + # "CubeListRepresentation()" was called exactly once, with the cubelist as arg + mock.call(test_cubelist) + ] + assert class_mock.return_value.repr_html.call_args_list == [ + # "CubeListRepresentation(cubelist).repr_html()" was called exactly once, with no args + mock.call() + ] + + if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/unit/experimental/representation/test_CubeRepresentation.py b/lib/iris/tests/unit/experimental/representation/test_CubeRepresentation.py index 99f7e7f2dd..e6b1425110 100644 --- a/lib/iris/tests/unit/experimental/representation/test_CubeRepresentation.py +++ b/lib/iris/tests/unit/experimental/representation/test_CubeRepresentation.py @@ -28,7 +28,7 @@ def setUp(self): def test_cube_attributes(self): self.assertEqual(id(self.cube), self.representer.cube_id) - self.assertStringEqual(str(self.cube), self.representer.cube_str) + self.assertMultiLineEqual(str(self.cube), self.representer.cube_str) def test__heading_contents(self): content = set(self.representer.sections_data.values()) diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py index 7bcb451d95..0cc3d09426 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py @@ -15,7 +15,7 @@ import iris.fileformats._nc_load_rules.engine from iris.fileformats.cf import CFReader import iris.fileformats.netcdf -from iris.fileformats.netcdf import _load_cube +from iris.fileformats.netcdf.loader import _load_cube from iris.tests.stock.netcdf import ncgen_from_cdl """ @@ -83,11 +83,11 @@ def load_cube_from_cdl(self, cdl_string, cdl_path, nc_path): # Grab a data variable : FOR NOW always grab the 'phenom' variable. cf_var = cf.cf_group.data_variables["phenom"] - engine = iris.fileformats.netcdf._actions_engine() + engine = iris.fileformats.netcdf.loader._actions_engine() # If debug enabled, switch on the activation summary debug output. # Use 'patch' so it is restored after the test. - self.patch("iris.fileformats.netcdf.DEBUG", self.debug) + self.patch("iris.fileformats.netcdf.loader.DEBUG", self.debug) with warnings.catch_warnings(): warnings.filterwarnings( @@ -117,7 +117,7 @@ def load_cube_from_cdl(self, cdl_string, cdl_path, nc_path): # Always returns a single cube. return cube - def run_testcase(self, warning=None, **testcase_kwargs): + def run_testcase(self, warning_regex=None, **testcase_kwargs): """ Run a testcase with chosen options, returning a test cube. @@ -133,10 +133,10 @@ def run_testcase(self, warning=None, **testcase_kwargs): print(cdl_string) print("------\n") - if warning is None: + if warning_regex is None: context = self.assertNoWarningsRegexp() else: - context = self.assertWarnsRegexp(warning) + context = self.assertWarnsRegex(UserWarning, warning_regex) with context: cube = self.load_cube_from_cdl(cdl_string, cdl_path, nc_path) diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py index a56ef5e754..a367e7709c 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py @@ -407,7 +407,9 @@ def test_latlon_bad_gridmapping_varname(self): # Notes: # * behaviours all the same as 'test_bad_gridmapping_nameproperty' warning = "Missing.*grid mapping variable 'grid'" - result = self.run_testcase(warning=warning, gridmapvar_name="grid_2") + result = self.run_testcase( + warning_regex=warning, gridmapvar_name="grid_2" + ) self.check_result(result, cube_no_cs=True) def test_latlon_bad_latlon_unit(self): @@ -633,7 +635,7 @@ def test_mapping__mismatch__latlon_coords_missing_system(self): # * coords built : lat + lon, with no coord-system (see above) warning = "Missing.*grid mapping variable 'grid'" result = self.run_testcase( - warning=warning, + warning_regex=warning, gridmapvar_name="moved", xco_name="longitude", xco_units="degrees_east", @@ -690,7 +692,7 @@ def test_mapping__mismatch__rotated_coords_missing_system(self): # * coords built : rotated lat + lon, with no coord-system (see above) warning = "Missing.*grid mapping variable 'grid'" result = self.run_testcase( - warning=warning, + warning_regex=warning, gridmapvar_name="moved", xco_name="grid_longitude", xco_units="degrees", @@ -752,7 +754,7 @@ def test_mapping__mismatch__nonll_coords_missing_system(self): # * effectively, just like previous 2 cases warning = "Missing.*grid mapping variable 'grid'" result = self.run_testcase( - warning=warning, + warning_regex=warning, gridmapvar_name="moved", xco_name="projection_x", xco_units="m", @@ -872,7 +874,9 @@ def test_nondim_lats(self): # * in terms of rule triggering, this is not distinct from the # "normal" case : but latitude is now created as an aux-coord. warning = "must be.* monotonic" - result = self.run_testcase(warning=warning, yco_values=[0.0, 0.0]) + result = self.run_testcase( + warning_regex=warning, yco_values=[0.0, 0.0] + ) self.check_result(result, yco_is_aux=True) diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py index 3413090a3d..d962fc2758 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py @@ -207,7 +207,7 @@ def test_unrecognised_verticaltype(self): result = self.run_testcase( formula_root_name="unknown", term_names=["a", "b"], - warning="Ignored formula of unrecognised type: 'unknown'.", + warning_regex="Ignored formula of unrecognised type: 'unknown'.", ) # Check that it picks up the terms, but *not* the factory root coord, # which is simply discarded. @@ -226,7 +226,7 @@ def test_two_formulae(self): extra_type = "ocean_sigma_coordinate" result = self.run_testcase( - extra_formula_type=extra_type, warning=warning + extra_formula_type=extra_type, warning_regex=warning ) # NOTE: FOR NOW, check expected behaviour : only one factory will be # built, but there are coordinates (terms) for both types. diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py index 47760aadcb..59ffa30684 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py @@ -313,7 +313,7 @@ def test_dim_nonmonotonic(self): # 002 : fc_provides_coordinate_(time[[_period]]) # 003 : fc_build_coordinate_(time[[_period]]) msg = "Failed to create.* dimension coordinate" - result = self.run_testcase(values_all_zero=True, warning=msg) + result = self.run_testcase(values_all_zero=True, warning_regex=msg) self.check_result(result, "aux") def test_dim_fails_typeident(self): diff --git a/lib/iris/tests/unit/fileformats/netcdf/loader/__init__.py b/lib/iris/tests/unit/fileformats/netcdf/loader/__init__.py new file mode 100644 index 0000000000..7c2ae96158 --- /dev/null +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/__init__.py @@ -0,0 +1,6 @@ +# 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. +"""Unit tests for the :mod:`iris.fileformats.netcdf.loader` module.""" diff --git a/lib/iris/tests/unit/fileformats/netcdf/test__get_cf_var_data.py b/lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py similarity index 97% rename from lib/iris/tests/unit/fileformats/netcdf/test__get_cf_var_data.py rename to lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py index 1bf39591d2..054c8e2db1 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test__get_cf_var_data.py +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py @@ -16,7 +16,7 @@ from iris._lazy_data import _optimum_chunksize import iris.fileformats.cf -from iris.fileformats.netcdf import _get_cf_var_data +from iris.fileformats.netcdf.loader import _get_cf_var_data class Test__get_cf_var_data(tests.IrisTest): diff --git a/lib/iris/tests/unit/fileformats/netcdf/test__load_aux_factory.py b/lib/iris/tests/unit/fileformats/netcdf/loader/test__load_aux_factory.py similarity index 99% rename from lib/iris/tests/unit/fileformats/netcdf/test__load_aux_factory.py rename to lib/iris/tests/unit/fileformats/netcdf/loader/test__load_aux_factory.py index eb9da6b5d6..841935cc81 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test__load_aux_factory.py +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/test__load_aux_factory.py @@ -16,7 +16,7 @@ from iris.coords import DimCoord from iris.cube import Cube -from iris.fileformats.netcdf import _load_aux_factory +from iris.fileformats.netcdf.loader import _load_aux_factory class TestAtmosphereHybridSigmaPressureCoordinate(tests.IrisTest): diff --git a/lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py b/lib/iris/tests/unit/fileformats/netcdf/loader/test__load_cube.py similarity index 96% rename from lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py rename to lib/iris/tests/unit/fileformats/netcdf/loader/test__load_cube.py index 0e98eec916..6e28a2f8e4 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/test__load_cube.py @@ -15,7 +15,7 @@ from iris.coords import DimCoord import iris.fileformats.cf -from iris.fileformats.netcdf import _load_cube +from iris.fileformats.netcdf.loader import _load_cube class TestCoordAttributes(tests.IrisTest): @@ -28,7 +28,7 @@ def _patcher(engine, cf, cf_group): engine.cube_parts["coordinates"] = coordinates def setUp(self): - this = "iris.fileformats.netcdf._assert_case_specific_facts" + this = "iris.fileformats.netcdf.loader._assert_case_specific_facts" patch = mock.patch(this, side_effect=self._patcher) patch.start() self.addCleanup(patch.stop) @@ -112,7 +112,7 @@ def test_flag_pass_thru_multi(self): class TestCubeAttributes(tests.IrisTest): def setUp(self): - this = "iris.fileformats.netcdf._assert_case_specific_facts" + this = "iris.fileformats.netcdf.loader._assert_case_specific_facts" patch = mock.patch(this) patch.start() self.addCleanup(patch.stop) diff --git a/lib/iris/tests/unit/fileformats/netcdf/test__translate_constraints_to_var_callback.py b/lib/iris/tests/unit/fileformats/netcdf/loader/test__translate_constraints_to_var_callback.py similarity index 97% rename from lib/iris/tests/unit/fileformats/netcdf/test__translate_constraints_to_var_callback.py rename to lib/iris/tests/unit/fileformats/netcdf/loader/test__translate_constraints_to_var_callback.py index fb08ffda2b..77bb0d3950 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test__translate_constraints_to_var_callback.py +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/test__translate_constraints_to_var_callback.py @@ -13,7 +13,9 @@ import iris from iris.fileformats.cf import CFDataVariable -from iris.fileformats.netcdf import _translate_constraints_to_var_callback +from iris.fileformats.netcdf.loader import ( + _translate_constraints_to_var_callback, +) # import iris tests first so that some things can be initialised before # importing anything else diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/__init__.py b/lib/iris/tests/unit/fileformats/netcdf/saver/__init__.py new file mode 100644 index 0000000000..a68d5fc5d0 --- /dev/null +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/__init__.py @@ -0,0 +1,6 @@ +# 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. +"""Unit tests for the :mod:`iris.fileformats.netcdf.saver` module.""" diff --git a/lib/iris/tests/unit/fileformats/netcdf/test__FillValueMaskCheckAndStoreTarget.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test__FillValueMaskCheckAndStoreTarget.py similarity index 97% rename from lib/iris/tests/unit/fileformats/netcdf/test__FillValueMaskCheckAndStoreTarget.py rename to lib/iris/tests/unit/fileformats/netcdf/saver/test__FillValueMaskCheckAndStoreTarget.py index 01ba7ff38d..77209efafc 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test__FillValueMaskCheckAndStoreTarget.py +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/test__FillValueMaskCheckAndStoreTarget.py @@ -17,7 +17,7 @@ import numpy as np -from iris.fileformats.netcdf import _FillValueMaskCheckAndStoreTarget +from iris.fileformats.netcdf.saver import _FillValueMaskCheckAndStoreTarget class Test__FillValueMaskCheckAndStoreTarget(tests.IrisTest): diff --git a/lib/iris/tests/unit/fileformats/netcdf/test_Saver.py b/lib/iris/tests/unit/fileformats/netcdf/test_Saver.py index 37bcee7da2..174a46fdb7 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test_Saver.py +++ b/lib/iris/tests/unit/fileformats/netcdf/test_Saver.py @@ -203,7 +203,7 @@ def test_big_endian(self): def test_zlib(self): cube = self._simple_cube(">f4") - api = self.patch("iris.fileformats.netcdf.netCDF4") + api = self.patch("iris.fileformats.netcdf.saver.netCDF4") # Define mocked default fill values to prevent deprecation warning (#4374). api.default_fillvals = collections.defaultdict(lambda: -99.0) with Saver("/dummy/path", "NETCDF4") as saver: @@ -549,8 +549,9 @@ def test_contains_fill_value_passed(self): # Test that a warning is raised if the data contains the fill value. cube = self._make_cube(">f4") fill_value = 1 - with self.assertWarnsRegexp( - "contains unmasked data points equal to the fill-value" + with self.assertWarnsRegex( + UserWarning, + "contains unmasked data points equal to the fill-value", ): with self._netCDF_var(cube, fill_value=fill_value): pass @@ -560,8 +561,9 @@ def test_contains_fill_value_byte(self): # when it is of a byte type. cube = self._make_cube(">i1") fill_value = 1 - with self.assertWarnsRegexp( - "contains unmasked data points equal to the fill-value" + with self.assertWarnsRegex( + UserWarning, + "contains unmasked data points equal to the fill-value", ): with self._netCDF_var(cube, fill_value=fill_value): pass @@ -571,8 +573,9 @@ def test_contains_default_fill_value(self): # value if no fill_value argument is supplied. cube = self._make_cube(">f4") cube.data[0, 0] = nc.default_fillvals["f4"] - with self.assertWarnsRegexp( - "contains unmasked data points equal to the fill-value" + with self.assertWarnsRegex( + UserWarning, + "contains unmasked data points equal to the fill-value", ): with self._netCDF_var(cube): pass diff --git a/lib/iris/tests/unit/fileformats/netcdf/test_Saver__ugrid.py b/lib/iris/tests/unit/fileformats/netcdf/test_Saver__ugrid.py index a914dd3314..575c852ece 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test_Saver__ugrid.py +++ b/lib/iris/tests/unit/fileformats/netcdf/test_Saver__ugrid.py @@ -575,6 +575,7 @@ def test_nonmesh_dim(self): self.assertEqual(data_props["mesh"], mesh_name) self.assertEqual(data_props["location"], "face") + @tests.skip_data def test_nonmesh_hybrid_dim(self): # Check a case with a hybrid non-mesh dimension cube = realistic_4d() diff --git a/lib/iris/tests/unit/fileformats/netcdf/test_save.py b/lib/iris/tests/unit/fileformats/netcdf/test_save.py index 669a3c4137..030edbfce2 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test_save.py +++ b/lib/iris/tests/unit/fileformats/netcdf/test_save.py @@ -143,7 +143,7 @@ def test_None(self): # Test that when no fill_value argument is passed, the fill_value # argument to Saver.write is None or not present. cubes = self._make_cubes() - with mock.patch("iris.fileformats.netcdf.Saver") as Saver: + with mock.patch("iris.fileformats.netcdf.saver.Saver") as Saver: save(cubes, "dummy.nc") # Get the Saver.write mock @@ -161,7 +161,7 @@ def test_single(self): # that value is passed to each call to Saver.write cubes = self._make_cubes() fill_value = 12345.0 - with mock.patch("iris.fileformats.netcdf.Saver") as Saver: + with mock.patch("iris.fileformats.netcdf.saver.Saver") as Saver: save(cubes, "dummy.nc", fill_value=fill_value) # Get the Saver.write mock @@ -178,7 +178,7 @@ def test_multiple(self): # each element is passed to separate calls to Saver.write cubes = self._make_cubes() fill_values = [123.0, 456.0, 789.0] - with mock.patch("iris.fileformats.netcdf.Saver") as Saver: + with mock.patch("iris.fileformats.netcdf.saver.Saver") as Saver: save(cubes, "dummy.nc", fill_value=fill_values) # Get the Saver.write mock @@ -195,7 +195,7 @@ def test_single_string(self): # that value is passed to calls to Saver.write cube = Cube(["abc", "def", "hij"]) fill_value = "xyz" - with mock.patch("iris.fileformats.netcdf.Saver") as Saver: + with mock.patch("iris.fileformats.netcdf.saver.Saver") as Saver: save(cube, "dummy.nc", fill_value=fill_value) # Get the Saver.write mock @@ -211,7 +211,7 @@ def test_multi_wrong_length(self): # is passed as the fill_value argument, an error is raised cubes = self._make_cubes() fill_values = [1.0, 2.0, 3.0, 4.0] - with mock.patch("iris.fileformats.netcdf.Saver"): + with mock.patch("iris.fileformats.netcdf.saver.Saver"): with self.assertRaises(ValueError): save(cubes, "dummy.nc", fill_value=fill_values) diff --git a/lib/iris/tests/unit/fileformats/pp/test_PPField.py b/lib/iris/tests/unit/fileformats/pp/test_PPField.py index 266c26aa59..5e2bbcaa2c 100644 --- a/lib/iris/tests/unit/fileformats/pp/test_PPField.py +++ b/lib/iris/tests/unit/fileformats/pp/test_PPField.py @@ -92,7 +92,7 @@ def field_checksum(data): data_64 = np.linspace(0, 1, num=10, endpoint=False).reshape(2, 5) checksum_32 = field_checksum(data_64.astype(">f4")) msg = "Downcasting array precision from float64 to float32 for save." - with self.assertWarnsRegexp(msg): + with self.assertWarnsRegex(UserWarning, msg): checksum_64 = field_checksum(data_64.astype(">f8")) self.assertEqual(checksum_32, checksum_64) @@ -105,7 +105,7 @@ def test_masked_mdi_value_warning(self): [1.0, field.bmdi, 3.0], dtype=np.float32 ) msg = "PPField data contains unmasked points" - with self.assertWarnsRegexp(msg): + with self.assertWarnsRegex(UserWarning, msg): with self.temp_filename(".pp") as temp_filename: with open(temp_filename, "wb") as pp_file: field.save(pp_file) @@ -117,7 +117,7 @@ def test_unmasked_mdi_value_warning(self): # Make float32 data, as float64 default produces an extra warning. field.data = np.array([1.0, field.bmdi, 3.0], dtype=np.float32) msg = "PPField data contains unmasked points" - with self.assertWarnsRegexp(msg): + with self.assertWarnsRegex(UserWarning, msg): with self.temp_filename(".pp") as temp_filename: with open(temp_filename, "wb") as pp_file: field.save(pp_file) @@ -143,7 +143,7 @@ class Test_calendar(tests.IrisTest): def test_greg(self): field = DummyPPField() field.lbtim = SplittableInt(1, {"ia": 2, "ib": 1, "ic": 0}) - self.assertEqual(field.calendar, "gregorian") + self.assertEqual(field.calendar, "standard") def test_360(self): field = DummyPPField() diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py index 2aae32b1ae..cf147e5928 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py @@ -13,7 +13,7 @@ # importing anything else. import iris.tests as tests # isort:skip -from cf_units import CALENDAR_360_DAY, CALENDAR_GREGORIAN, Unit +from cf_units import CALENDAR_360_DAY, CALENDAR_STANDARD, Unit from cftime import datetime as nc_datetime import numpy as np @@ -38,7 +38,7 @@ def _lbcode(value=None, ix=None, iy=None): return result -_EPOCH_HOURS_UNIT = Unit("hours since epoch", calendar=CALENDAR_GREGORIAN) +_EPOCH_HOURS_UNIT = Unit("hours since epoch", calendar=CALENDAR_STANDARD) _HOURS_UNIT = Unit("hours") diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py index 2877d6ea89..2c5d672e14 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py @@ -28,9 +28,9 @@ # -class TestEpochHours__gregorian(tests.IrisTest): +class TestEpochHours__standard(tests.IrisTest): def setUp(self): - self.calendar = cf_units.CALENDAR_GREGORIAN + self.calendar = cf_units.CALENDAR_STANDARD self.hrs_unit = Unit("hours since epoch", calendar=self.calendar) def test_1970_1_1(self): diff --git a/lib/iris/tests/unit/io/test_expand_filespecs.py b/lib/iris/tests/unit/io/test_expand_filespecs.py index c28e4f9b2e..8720478153 100644 --- a/lib/iris/tests/unit/io/test_expand_filespecs.py +++ b/lib/iris/tests/unit/io/test_expand_filespecs.py @@ -10,6 +10,7 @@ import iris.tests as tests # isort:skip import os +from pathlib import Path import shutil import tempfile import textwrap @@ -94,7 +95,30 @@ def test_files_and_none(self): .format(self.tmpdir) ) - self.assertStringEqual(str(err.exception), expected) + self.assertMultiLineEqual(str(err.exception), expected) + + def test_false_bool_absolute(self): + tempdir = self.tmpdir + msg = os.path.join(tempdir, "no_exist.txt") + (result,) = iio.expand_filespecs([msg], False) + self.assertEqual(result, msg) + + def test_false_bool_home(self): + # ensure that not only does files_expected not error, + # but that the path is still expanded from a ~ + msg = str(Path().home() / "no_exist.txt") + (result,) = iio.expand_filespecs(["~/no_exist.txt"], False) + self.assertEqual(result, msg) + + def test_false_bool_relative(self): + cwd = os.getcwd() + try: + os.chdir(self.tmpdir) + item_out = iio.expand_filespecs(["no_exist.txt"], False) + item_in = [os.path.join(self.tmpdir, "no_exist.txt")] + self.assertEqual(item_out, item_in) + finally: + os.chdir(cwd) if __name__ == "__main__": diff --git a/lib/iris/tests/unit/io/test_save.py b/lib/iris/tests/unit/io/test_save.py index b92e26f2d1..623cf417f2 100755 --- a/lib/iris/tests/unit/io/test_save.py +++ b/lib/iris/tests/unit/io/test_save.py @@ -26,6 +26,12 @@ def test_pathlib_save(self): "iris.io.find_saver", return_value=(lambda *args, **kwargs: None) ) + def replace_expand(file_specs, files_expected=True): + return file_specs + + # does not expand filepaths due to patch + self.patch("iris.io.expand_filespecs", replace_expand) + test_variants = [ ("string", "string"), (Path("string/string"), "string/string"), diff --git a/lib/iris/tests/unit/plot/test__fixup_dates.py b/lib/iris/tests/unit/plot/test__fixup_dates.py index 1ad5c87691..0abef01e41 100644 --- a/lib/iris/tests/unit/plot/test__fixup_dates.py +++ b/lib/iris/tests/unit/plot/test__fixup_dates.py @@ -19,8 +19,8 @@ class Test(tests.IrisTest): - def test_gregorian_calendar(self): - unit = Unit("hours since 2000-04-13 00:00:00", calendar="gregorian") + def test_standard_calendar(self): + unit = Unit("hours since 2000-04-13 00:00:00", calendar="standard") coord = AuxCoord([1, 3, 6], "time", units=unit) result = _fixup_dates(coord, coord.points) self.assertIsInstance(result[0], datetime.datetime) @@ -31,8 +31,8 @@ def test_gregorian_calendar(self): ] self.assertArrayEqual(result, expected) - def test_gregorian_calendar_sub_second(self): - unit = Unit("seconds since 2000-04-13 00:00:00", calendar="gregorian") + def test_standard_calendar_sub_second(self): + unit = Unit("seconds since 2000-04-13 00:00:00", calendar="standard") coord = AuxCoord([1, 1.25, 1.5], "time", units=unit) result = _fixup_dates(coord, coord.points) self.assertIsInstance(result[0], datetime.datetime) diff --git a/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py b/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py index ff42acf566..21fc8efa73 100644 --- a/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py +++ b/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py @@ -349,6 +349,20 @@ def test_section_vector_ancils(self): ] self.assertEqual(rep, expected) + def test_section_vector_ancils_length_1(self): + # Check ancillary variables that map to a cube dimension of length 1 + # are not interpreted as scalar ancillary variables. + cube = Cube(np.zeros((1, 3)), long_name="name", units=1) + cube.add_ancillary_variable(AncillaryVariable([0], long_name="av1"), 0) + + rep = cube_replines(cube) + expected = [ + "name / (1) (-- : 1; -- : 3)", + " Ancillary variables:", + " av1 x -", + ] + self.assertEqual(rep, expected) + def test_section_vector_cell_measures(self): cube = Cube(np.zeros((2, 3)), long_name="name", units=1) cube.add_cell_measure(CellMeasure([0, 1, 2], long_name="cm"), 1) @@ -361,6 +375,20 @@ def test_section_vector_cell_measures(self): ] self.assertEqual(rep, expected) + def test_section_vector_cell_measures_length_1(self): + # Check cell measures that map to a cube dimension of length 1 are not + # interpreted as scalar cell measures. + cube = Cube(np.zeros((2, 1)), long_name="name", units=1) + cube.add_cell_measure(CellMeasure([0], long_name="cm"), 1) + + rep = cube_replines(cube) + expected = [ + "name / (1) (-- : 2; -- : 1)", + " Cell measures:", + " cm - x", + ] + self.assertEqual(rep, expected) + def test_section_scalar_coords(self): # incl points + bounds # TODO: ought to incorporate coord-based summary @@ -424,8 +452,8 @@ def test_section_scalar_ancillaries(self): rep = cube_replines(cube) expected = [ "name / (1) (-- : 2; -- : 3)", - " Ancillary variables:", - " av - -", + " Scalar ancillary variables:", + " av", ] self.assertEqual(rep, expected) diff --git a/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py b/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py index 8314c5c9ae..bcf31a016f 100644 --- a/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py +++ b/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py @@ -75,6 +75,7 @@ def test_blank_cube(self): "Mesh:", "Scalar coordinates:", "Scalar cell measures:", + "Scalar ancillary variables:", "Cell methods:", "Attributes:", ] @@ -222,7 +223,7 @@ def test_scalar_cube(self): self.assertTrue( all(sect.is_empty() for sect in rep.vector_sections.values()) ) - self.assertEqual(len(rep.scalar_sections), 5) + self.assertEqual(len(rep.scalar_sections), 6) self.assertEqual( len(rep.scalar_sections["Scalar coordinates:"].contents), 1 ) diff --git a/lib/iris/tests/unit/test_Future.py b/lib/iris/tests/unit/test_Future.py index dddc752b6f..f0c161b0c4 100644 --- a/lib/iris/tests/unit/test_Future.py +++ b/lib/iris/tests/unit/test_Future.py @@ -12,6 +12,7 @@ import warnings from iris import Future +import iris._deprecation def patched_future(value=False, deprecated=False, error=False): @@ -45,7 +46,7 @@ def test_valid_setting(self): def test_deprecated_warning(self): future = patched_future(deprecated=True, error=False) msg = "'Future' property 'example_future_flag' is deprecated" - with self.assertWarnsRegexp(msg): + with self.assertWarnsRegex(iris._deprecation.IrisDeprecation, msg): future.example_future_flag = False def test_deprecated_error(self): diff --git a/lib/iris/tests/unit/util/test__mask_array.py b/lib/iris/tests/unit/util/test__mask_array.py new file mode 100644 index 0000000000..91a5aca1b4 --- /dev/null +++ b/lib/iris/tests/unit/util/test__mask_array.py @@ -0,0 +1,173 @@ +# 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. +"""Test function :func:`iris.util._mask_array""" + +import dask.array as da +import numpy as np +import numpy.ma as ma +import pytest + +import iris._lazy_data +from iris.tests import assert_masked_array_equal +from iris.util import _mask_array + +# Set up some arrays to use through the tests. +array_1d = np.arange(4) +masked_arr_1d = ma.array(np.arange(4), mask=[1, 0, 0, 1]) +array_2by3 = np.arange(6).reshape(2, 3) + +# Any masked points on the mask itself should be ignored. So result with mask_1d +# and masked_mask_1d should be the same. +mask_1d = np.array([0, 1, 0, 1]) +masked_mask_1d = ma.array([0, 1, 1, 1], mask=[0, 0, 1, 0]) + +# Expected output depends whether input array is masked or not. +expected1 = ma.array(array_1d, mask=mask_1d) +expected2 = ma.array(array_1d, mask=[1, 1, 0, 1]) +array_choices = [(array_1d, expected1), (masked_arr_1d, expected2)] + + +@pytest.mark.parametrize( + "mask", [mask_1d, masked_mask_1d], ids=["plain-mask", "masked-mask"] +) +@pytest.mark.parametrize("lazy_mask", [False, True], ids=["real", "lazy"]) +@pytest.mark.parametrize( + "array, expected", array_choices, ids=["plain-array", "masked-array"] +) +@pytest.mark.parametrize("lazy_array", [False, True], ids=["real", "lazy"]) +def test_1d_not_in_place(array, mask, expected, lazy_array, lazy_mask): + """ + Basic test for expected behaviour when working not in place with various + array types for input. + + """ + if lazy_array: + array = iris._lazy_data.as_lazy_data(array) + + if lazy_mask: + mask = iris._lazy_data.as_lazy_data(mask) + + result = _mask_array(array, mask) + assert result is not array + + if lazy_array or lazy_mask: + assert iris._lazy_data.is_lazy_data(result) + result = iris._lazy_data.as_concrete_data(result) + + assert_masked_array_equal(expected, result) + + +# 1D in place tests. + + +def test_plain_array_in_place(): + """ + Test we get an informative error when trying to add a mask to a plain numpy + array. + + """ + arr = array_1d + mask = None + with pytest.raises( + TypeError, match="Cannot apply a mask in-place to a plain numpy array." + ): + _mask_array(arr, mask, in_place=True) + + +def test_masked_array_lazy_mask_in_place(): + """ + Test we get an informative error when trying to apply a lazy mask in-place + to a non-lazy array. + + """ + arr = masked_arr_1d + mask = da.from_array([0, 1, 0, 1]) + with pytest.raises( + TypeError, match="Cannot apply lazy mask in-place to a non-lazy array." + ): + _mask_array(arr, mask, in_place=True) + + +@pytest.mark.parametrize( + "mask", [mask_1d, masked_mask_1d], ids=["plain-mask", "masked-mask"] +) +def test_real_masked_array_in_place(mask): + """ + Check expected behaviour for applying masks in-place to a masked array. + + """ + arr = masked_arr_1d.copy() + result = _mask_array(arr, mask, in_place=True) + assert_masked_array_equal(arr, expected2) + # Resolve uses returned value regardless of whether we're working in_place. + assert result is arr + + +def test_lazy_array_in_place(): + """ + Test that in place flag is ignored for lazy arrays, and result is the same + as the not in_place case. + + """ + arr = da.from_array(np.arange(4)) + mask = np.array([0, 1, 0, 1]) + expected_computed = ma.array(range(4), mask=[0, 1, 0, 1]) + # in_place is ignored for lazy array as this is handled by _math_op_common. + result = _mask_array(arr, mask, in_place=True) + assert iris._lazy_data.is_lazy_data(result) + assert_masked_array_equal(result.compute(), expected_computed) + assert result is not arr + + +# Broadcasting tests. + +IN_PLACE_PARAMETRIZE = pytest.mark.parametrize( + "in_place", [False, True], ids=["not-in-place", "in-place"] +) + + +@IN_PLACE_PARAMETRIZE +def test_trailing_mask(in_place): + array = ma.array(array_2by3.copy()) + mask = np.array([0, 1, 0]) + expected = ma.array(array_2by3, mask=[[0, 1, 0], [0, 1, 0]]) + result = _mask_array(array, mask, in_place=in_place) + assert_masked_array_equal(result, expected) + assert result is array if in_place else result is not array + + +@IN_PLACE_PARAMETRIZE +def test_leading_mask(in_place): + arr = ma.masked_array(array_2by3.copy(), mask=[[0, 0, 0], [0, 0, 1]]) + mask = np.array([1, 0]).reshape(2, 1) + expected = ma.array(arr.data, mask=[[1, 1, 1], [0, 0, 1]]) + result = _mask_array(arr, mask, in_place=in_place) + assert_masked_array_equal(result, expected) + assert result is arr if in_place else result is not arr + + +def test_lazy_trailing_mask(): + arr = da.ma.masked_array(array_2by3, mask=[[0, 1, 1], [0, 0, 0]]) + mask = np.array([0, 1, 0]) + expected_computed = ma.array(array_2by3, mask=[[0, 1, 1], [0, 1, 0]]) + result = _mask_array(arr, mask, in_place=False) + assert iris._lazy_data.is_lazy_data(result) + assert_masked_array_equal(result.compute(), expected_computed) + assert result is not arr + + +def test_lazy_leading_mask(): + arr = da.from_array(array_2by3) + mask = da.from_array([0, 1]).reshape(2, 1) + expected_computed = ma.array(array_2by3, mask=[[0, 0, 0], [1, 1, 1]]) + result = _mask_array(arr, mask, in_place=False) + assert iris._lazy_data.is_lazy_data(result) + assert_masked_array_equal(result.compute(), expected_computed) + assert result is not arr + + +if __name__ == "__main__": + pytest.main([__file__]) diff --git a/lib/iris/tests/unit/util/test_mask_cube.py b/lib/iris/tests/unit/util/test_mask_cube.py index 2d5aaa21f1..0123d0cca5 100644 --- a/lib/iris/tests/unit/util/test_mask_cube.py +++ b/lib/iris/tests/unit/util/test_mask_cube.py @@ -9,13 +9,19 @@ # importing anything else. import iris.tests as tests # isort:skip +import pathlib + +import dask.array as da import numpy as np import numpy.ma as ma from iris.tests.stock import ( make_bounds_discontiguous_at_point, sample_2d_latlons, + simple_1d, + simple_2d, ) +import iris.util from iris.util import mask_cube @@ -23,15 +29,32 @@ def full2d_global(): return sample_2d_latlons(transformed=True) -@tests.skip_data -class Test(tests.IrisTest): +class MaskCubeMixin: + def assertOriginalMetadata(self, cube, func): + """ + Check metadata matches that of input cube. func is a string indicating + which function created the original cube. + + """ + reference_dir = pathlib.Path("unit/util/mask_cube") + reference_fname = reference_dir / f"original_cube_{func}.cml" + self.assertCML( + cube, + reference_filename=str(reference_fname), + checksum=False, + ) + + +class TestArrayMask(tests.IrisTest, MaskCubeMixin): + """Tests with mask specified as numpy array.""" + def setUp(self): # Set up a 2d cube with a masked discontiguity to test masking # of 2-dimensional cubes self.cube_2d = full2d_global() make_bounds_discontiguous_at_point(self.cube_2d, 3, 3) - def test_mask_cube_2d(self): + def test_mask_cube_2d_in_place(self): # This tests the masking of a 2d data array cube = self.cube_2d discontiguity_array = ma.getmaskarray(cube.data).copy() @@ -40,9 +63,132 @@ def test_mask_cube_2d(self): # Remove mask so that we can pass an unmasked data set to # mask_discontiguities, and check that it masks the correct point by # comparing with masked data - cube.data.mask = ma.nomask - returned = mask_cube(cube, discontiguity_array) - self.assertTrue(np.all(expected.data.mask == returned.data.mask)) + cube.data = cube.data.data + returned = mask_cube(cube, discontiguity_array, in_place=True) + np.testing.assert_array_equal(expected.data.mask, cube.data.mask) + self.assertOriginalMetadata(cube, "full2d_global") + self.assertIs(returned, None) + + def test_mask_cube_2d_not_in_place(self): + # This tests the masking of a 2d data array + cube = self.cube_2d + discontiguity_array = ma.getmaskarray(cube.data).copy() + expected = cube.copy() + + # Remove mask so that we can pass an unmasked data set to + # mask_discontiguities, and check that it masks the correct point by + # comparing with masked data + cube.data = cube.data.data + returned = mask_cube(cube, discontiguity_array, in_place=False) + np.testing.assert_array_equal(expected.data.mask, returned.data.mask) + self.assertOriginalMetadata(returned, "full2d_global") + self.assertFalse(ma.is_masked(cube.data)) + + def test_mask_cube_lazy_in_place_broadcast(self): + cube = simple_2d() + cube.data = cube.lazy_data() + mask = [0, 1, 1, 0] + returned = mask_cube(cube, mask, in_place=True) + self.assertTrue(cube.has_lazy_data()) + # Touch the data so lazyness status doesn't affect CML check. + cube.data + self.assertOriginalMetadata(cube, "simple_2d") + for subcube in cube.slices("foo"): + # Mask should have been broadcast across "bar" dimension. + np.testing.assert_array_equal(subcube.data.mask, mask) + self.assertIs(returned, None) + + +class TestCoordMask(tests.IrisTest, MaskCubeMixin): + """Tests with mask specified as a Coord.""" + + def setUp(self): + self.cube = simple_2d() + + def test_mask_cube_2d_first_dim(self): + mask_coord = iris.coords.AuxCoord([0, 1, 0], long_name="mask", units=1) + self.cube.add_aux_coord(mask_coord, 0) + + returned = mask_cube(self.cube, mask_coord, in_place=False) + # Remove extra coord so we can check against original metadata. + returned.remove_coord(mask_coord) + self.assertOriginalMetadata(returned, "simple_2d") + for subcube in returned.slices("bar"): + # Mask should have been broadcast across "foo" dimension. + np.testing.assert_array_equal(subcube.data.mask, mask_coord.points) + + def test_mask_cube_2d_second_dim(self): + mask_coord = iris.coords.AuxCoord( + [0, 0, 1, 1], long_name="mask", units=1 + ) + returned = mask_cube(self.cube, mask_coord, in_place=False, dim=1) + self.assertOriginalMetadata(returned, "simple_2d") + for subcube in returned.slices("foo"): + # Mask should have been broadcast across "bar" dimension. + np.testing.assert_array_equal(subcube.data.mask, mask_coord.points) + + +class TestCubeMask(tests.IrisTest, MaskCubeMixin): + """Tests with mask specified as a Cube.""" + + def setUp(self): + self.cube = simple_2d() + + def test_mask_cube_2d_first_dim_not_in_place(self): + mask = iris.cube.Cube([0, 1, 0], long_name="mask", units=1) + mask.add_dim_coord(self.cube.coord("bar"), 0) + + returned = mask_cube(self.cube, mask, in_place=False) + self.assertOriginalMetadata(returned, "simple_2d") + for subcube in returned.slices("bar"): + # Mask should have been broadcast across 'foo' dimension. + np.testing.assert_array_equal(subcube.data.mask, mask.data) + + def test_mask_cube_2d_first_dim_in_place(self): + mask = iris.cube.Cube([0, 1, 0], long_name="mask", units=1) + mask.add_dim_coord(self.cube.coord("bar"), 0) + + returned = mask_cube(self.cube, mask, in_place=True) + self.assertOriginalMetadata(self.cube, "simple_2d") + for subcube in self.cube.slices("bar"): + # Mask should have been broadcast across 'foo' dimension. + np.testing.assert_array_equal(subcube.data.mask, mask.data) + self.assertIs(returned, None) + + def test_mask_cube_2d_create_new_dim(self): + mask = iris.cube.Cube( + [[0, 1, 0], [0, 0, 1]], long_name="mask", units=1 + ) + + broadcast_coord = iris.coords.DimCoord([1, 2], long_name="baz") + mask.add_dim_coord(broadcast_coord, 0) + mask.add_dim_coord(self.cube.coord("bar"), 1) + + # Create length-1 dimension to enable broadcasting. + self.cube.add_aux_coord(broadcast_coord[0]) + cube = iris.util.new_axis(self.cube, "baz") + + returned = mask_cube(cube, mask, in_place=False) + self.assertCML(cube, checksum=False) + + for subcube in returned.slices_over("baz"): + # Underlying data should have been broadcast across 'baz' dimension. + np.testing.assert_array_equal(subcube.data, self.cube.data) + + for subcube in returned.slices_over("foo"): + # Mask should have been broadcast across 'foo' dimension. + np.testing.assert_array_equal(subcube.data.mask, mask.data) + + def test_mask_cube_1d_lazy_mask_in_place(self): + cube = simple_1d() + mask = cube.copy(da.from_array([0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1])) + returned = mask_cube(cube, mask, in_place=True) + self.assertIs(returned, None) + self.assertTrue(cube.has_lazy_data()) + # Touch the data so lazyness status doesn't interfere with CML check. + cube.data + self.assertOriginalMetadata(cube, "simple_1d") + np.testing.assert_array_equal(cube.data.mask, mask.data) if __name__ == "__main__": diff --git a/lib/iris/tests/unit/util/test_new_axis.py b/lib/iris/tests/unit/util/test_new_axis.py index 74b59cc7ec..d81f2c40d7 100644 --- a/lib/iris/tests/unit/util/test_new_axis.py +++ b/lib/iris/tests/unit/util/test_new_axis.py @@ -7,95 +7,131 @@ # Import iris.tests first so that some things can be initialised before # importing anything else. -import iris.tests as tests # isort:skip +# isort: off +import iris.tests as tests # noqa + +# isort: on import copy -import unittest import numpy as np +import pytest import iris from iris._lazy_data import as_lazy_data +from iris.coords import AncillaryVariable, AuxCoord, CellMeasure, DimCoord +from iris.cube import Cube import iris.tests.stock as stock from iris.util import new_axis -class Test(tests.IrisTest): - def setUp(self): - self.data = np.array([[1, 2], [1, 2]]) - self.cube = iris.cube.Cube(self.data) - lat = iris.coords.DimCoord([1, 2], standard_name="latitude") - lon = iris.coords.DimCoord([1, 2], standard_name="longitude") - +class Test: + @pytest.fixture + def stock_cube(self): + cube = stock.simple_2d_w_cell_measure_ancil_var() time = iris.coords.DimCoord([1], standard_name="time") - wibble = iris.coords.AuxCoord([1], long_name="wibble") - - self.cube.add_dim_coord(lat, 0) - self.cube.add_dim_coord(lon, 1) - self.cube.add_aux_coord(time, None) - self.cube.add_aux_coord(wibble, None) - - self.coords = {"lat": lat, "lon": lon, "time": time, "wibble": wibble} + cube.add_aux_coord(time, None) + cube.coord("wibble").bounds = np.array([0, 2]).reshape((1, 2)) + return cube def _assert_cube_notis(self, cube_a, cube_b): + assert cube_a.metadata is not cube_b.metadata + for coord_a, coord_b in zip(cube_a.coords(), cube_b.coords()): - self.assertIsNot(coord_a, coord_b) + assert coord_a is not coord_b + + for av_a, av_b in zip( + cube_a.ancillary_variables(), cube_b.ancillary_variables() + ): + assert av_a is not av_b - self.assertIsNot(cube_a.metadata, cube_b.metadata) + for cm_a, cm_b in zip(cube_a.cell_measures(), cube_b.cell_measures()): + assert cm_a is not cm_b for factory_a, factory_b in zip( cube_a.aux_factories, cube_b.aux_factories ): - self.assertIsNot(factory_a, factory_b) + assert factory_a is not factory_b - def test_no_coord(self): + def test_promote_no_coord(self, stock_cube): # Providing no coordinate to promote. - res = new_axis(self.cube) - com = iris.cube.Cube(self.data[None]) - com.add_dim_coord(self.coords["lat"].copy(), 1) - com.add_dim_coord(self.coords["lon"].copy(), 2) - com.add_aux_coord(self.coords["time"].copy(), None) - com.add_aux_coord(self.coords["wibble"].copy(), None) + result = new_axis(stock_cube) + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), None) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), None) + expected.add_ancillary_variable( + stock_cube.ancillary_variable("quality_flag"), 1 + ) + expected.add_cell_measure(stock_cube.cell_measure("cell_area"), (1, 2)) - self.assertEqual(res, com) - self._assert_cube_notis(res, self.cube) + assert result == expected + self._assert_cube_notis(result, stock_cube) - def test_scalar_dimcoord(self): + def test_promote_scalar_dimcoord(self, stock_cube): # Providing a scalar coordinate to promote. - res = new_axis(self.cube, "time") - com = iris.cube.Cube(self.data[None]) - com.add_dim_coord(self.coords["lat"].copy(), 1) - com.add_dim_coord(self.coords["lon"].copy(), 2) - com.add_aux_coord(self.coords["time"].copy(), 0) - com.add_aux_coord(self.coords["wibble"].copy(), None) + result = new_axis(stock_cube, "time") + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), 0) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), None) + expected.add_ancillary_variable( + stock_cube.ancillary_variable("quality_flag"), 1 + ) + expected.add_cell_measure(stock_cube.cell_measure("cell_area"), (1, 2)) - self.assertEqual(res, com) - self._assert_cube_notis(res, self.cube) + assert result == expected + # Explicitly check time has been made a cube dim coord as cube equality + # does not check this. + assert result.coord("time") in [ + item[0] for item in result._dim_coords_and_dims + ] + self._assert_cube_notis(result, stock_cube) - def test_scalar_auxcoord(self): + def test_promote_scalar_auxcoord(self, stock_cube): # Providing a scalar coordinate to promote. - res = new_axis(self.cube, "wibble") - com = iris.cube.Cube(self.data[None]) - com.add_dim_coord(self.coords["lat"].copy(), 1) - com.add_dim_coord(self.coords["lon"].copy(), 2) - com.add_aux_coord(self.coords["time"].copy(), None) - com.add_aux_coord(self.coords["wibble"].copy(), 0) + result = new_axis(stock_cube, "wibble") + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), None) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), 0) + expected.add_ancillary_variable( + stock_cube.ancillary_variable("quality_flag"), 1 + ) + expected.add_cell_measure(stock_cube.cell_measure("cell_area"), (1, 2)) + + assert result == expected + # Explicitly check wibble has been made a cube dim coord as cube + # equality does not check this. + assert result.coord("wibble") in [ + item[0] for item in result._dim_coords_and_dims + ] + self._assert_cube_notis(result, stock_cube) - self.assertEqual(res, com) - self._assert_cube_notis(res, self.cube) + def test_promote_non_scalar(self, stock_cube): + # Provide a dimensional coordinate which is not scalar + with pytest.raises(ValueError, match="is not a scalar coordinate."): + new_axis(stock_cube, "foo") def test_maint_factory(self): # Ensure that aux factory persists. data = np.arange(12, dtype="i8").reshape((3, 4)) - orography = iris.coords.AuxCoord( + orography = AuxCoord( [10, 25, 50, 5], standard_name="surface_altitude", units="m" ) - model_level = iris.coords.AuxCoord( - [2, 1, 0], standard_name="model_level_number" - ) + model_level = AuxCoord([2, 1, 0], standard_name="model_level_number") - level_height = iris.coords.DimCoord( + level_height = DimCoord( [100, 50, 10], long_name="level_height", units="m", @@ -103,7 +139,7 @@ def test_maint_factory(self): bounds=[[150, 75], [75, 20], [20, 0]], ) - sigma = iris.coords.AuxCoord( + sigma = AuxCoord( [0.8, 0.9, 0.95], long_name="sigma", bounds=[[0.7, 0.85], [0.85, 0.97], [0.97, 1.0]], @@ -113,7 +149,7 @@ def test_maint_factory(self): level_height, sigma, orography ) - cube = iris.cube.Cube( + cube = Cube( data, standard_name="air_temperature", units="K", @@ -122,7 +158,7 @@ def test_maint_factory(self): aux_factories=[hybrid_height], ) - com = iris.cube.Cube( + com = Cube( data[None], standard_name="air_temperature", units="K", @@ -136,7 +172,7 @@ def test_maint_factory(self): ) res = new_axis(cube) - self.assertEqual(res, com) + assert res == com self._assert_cube_notis(res, cube) # Check that factory dependencies are actual coords within the cube. @@ -145,23 +181,14 @@ def test_maint_factory(self): deps = factory.dependencies for dep_name, dep_coord in deps.items(): coord_name = dep_coord.name() - msg = ( - "Factory dependency {!r} is a coord named {!r}, " - "but it is *not* the coord of that name in the new cube." - ) - self.assertIs( - dep_coord, - res.coord(coord_name), - msg.format(dep_name, coord_name), - ) - - def test_lazy_data(self): - cube = iris.cube.Cube(as_lazy_data(self.data)) - cube.add_aux_coord(iris.coords.DimCoord([1], standard_name="time")) - res = new_axis(cube, "time") - self.assertTrue(cube.has_lazy_data()) - self.assertTrue(res.has_lazy_data()) - self.assertEqual(res.shape, (1,) + cube.shape) + assert dep_coord is res.coord(coord_name) + + def test_lazy_cube_data(self, stock_cube): + stock_cube.data = as_lazy_data(stock_cube.data) + res = new_axis(stock_cube) + assert stock_cube.has_lazy_data() + assert res.has_lazy_data() + assert res.shape == (1,) + stock_cube.shape def test_masked_unit_array(self): cube = stock.simple_3d_mask() @@ -170,8 +197,114 @@ def test_masked_unit_array(self): test_cube = new_axis(test_cube, "latitude") data_shape = test_cube.data.shape mask_shape = test_cube.data.mask.shape - self.assertEqual(data_shape, mask_shape) + assert data_shape == mask_shape + + def test_expand_scalar_coord(self, stock_cube): + result = new_axis(stock_cube, "time", expand_extras=["wibble"]) + + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), 0) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), 0) + expected.add_ancillary_variable( + stock_cube.ancillary_variable("quality_flag"), 1 + ) + expected.add_cell_measure(stock_cube.cell_measure("cell_area"), (1, 2)) + + assert result == expected + self._assert_cube_notis(result, stock_cube) + + def test_expand_scalar_coord_lazy_points(self, stock_cube): + stock_cube.coord("wibble").points = as_lazy_data( + stock_cube.coord("wibble").points + ) + result = new_axis(stock_cube, "time", expand_extras=["wibble"]) + assert stock_cube.coord("wibble").has_lazy_points() + assert result.coord("wibble").has_lazy_points() + assert ( + result.coord("wibble").points.shape + == stock_cube.coord("wibble").points.shape + ) + + def test_expand_scalar_coord_lazy_bounds(self, stock_cube): + stock_cube.coord("wibble").bounds = as_lazy_data(np.array([[0, 2]])) + result = new_axis(stock_cube, "time", expand_extras=["wibble"]) + assert stock_cube.coord("wibble").has_lazy_bounds() + assert result.coord("wibble").has_lazy_bounds() + assert ( + result.coord("wibble").bounds.shape + == stock_cube.coord("wibble").bounds.shape + ) + + def test_expand_cell_measure(self, stock_cube): + result = new_axis(stock_cube, "time", expand_extras=["cell_area"]) + + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), 0) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), None) + expected.add_ancillary_variable( + stock_cube.ancillary_variable("quality_flag"), 1 + ) + + expected_cm = CellMeasure( + stock_cube.cell_measure("cell_area").data[None], + standard_name="cell_area", + ) + expected.add_cell_measure(expected_cm, (0, 1, 2)) + assert result == expected + self._assert_cube_notis(result, stock_cube) + + def test_expand_ancil_var(self, stock_cube): + result = new_axis(stock_cube, "time", expand_extras=["quality_flag"]) + + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), 0) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), None) + expected.add_cell_measure(stock_cube.cell_measure("cell_area"), (1, 2)) + + expected_av = AncillaryVariable( + stock_cube.ancillary_variable("quality_flag").data[None], + standard_name="quality_flag", + ) + + expected.add_ancillary_variable(expected_av, (0, 1)) + + assert result == expected + self._assert_cube_notis(result, stock_cube) + + def test_expand_multiple(self, stock_cube): + result = new_axis( + stock_cube, "time", expand_extras=["wibble", "cell_area"] + ) + + expected = iris.cube.Cube( + stock_cube.data[None], long_name="thingness", units="1" + ) + expected.add_dim_coord(stock_cube.coord("bar").copy(), 1) + expected.add_dim_coord(stock_cube.coord("foo").copy(), 2) + expected.add_aux_coord(stock_cube.coord("time").copy(), 0) + expected.add_aux_coord(stock_cube.coord("wibble").copy(), 0) + expected.add_ancillary_variable( + stock_cube.ancillary_variable("quality_flag"), 1 + ) + + expected_cm = CellMeasure( + stock_cube.cell_measure("cell_area").data[None], + standard_name="cell_area", + ) + expected.add_cell_measure(expected_cm, (0, 1, 2)) -if __name__ == "__main__": - unittest.main() + assert result == expected + self._assert_cube_notis(result, stock_cube) diff --git a/lib/iris/tests/unit/util/test_unify_time_units.py b/lib/iris/tests/unit/util/test_unify_time_units.py index 16dc7054f3..daf71890b1 100644 --- a/lib/iris/tests/unit/util/test_unify_time_units.py +++ b/lib/iris/tests/unit/util/test_unify_time_units.py @@ -20,7 +20,7 @@ class Test(tests.IrisTest): - def simple_1d_time_cubes(self, calendar="gregorian"): + def simple_1d_time_cubes(self, calendar="standard"): coord_points = [1, 2, 3, 4, 5] data_points = [273, 275, 278, 277, 274] reftimes = [ @@ -92,7 +92,7 @@ def test_time_coord_only_in_some_cubes(self): def test_multiple_time_coords_in_cube(self): cube0, cube1 = self.simple_1d_time_cubes() units = cf_units.Unit( - "days since 1980-05-02 00:00:00", calendar="gregorian" + "days since 1980-05-02 00:00:00", calendar="standard" ) aux_coord = iris.coords.AuxCoord( 72, standard_name="forecast_reference_time", units=units diff --git a/lib/iris/util.py b/lib/iris/util.py index ded72d0f23..3d82ea68c5 100644 --- a/lib/iris/util.py +++ b/lib/iris/util.py @@ -24,6 +24,8 @@ from iris._deprecation import warn_deprecated from iris._lazy_data import as_concrete_data, is_lazy_data +from iris.common import SERVICES +from iris.common.lenient import _lenient_client import iris.exceptions @@ -1094,7 +1096,7 @@ def format_array(arr): return result -def new_axis(src_cube, scalar_coord=None): +def new_axis(src_cube, scalar_coord=None, expand_extras=()): """ Create a new axis as the leading dimension of the cube, promoting a scalar coordinate if specified. @@ -1109,9 +1111,16 @@ def new_axis(src_cube, scalar_coord=None): * scalar_coord (:class:`iris.coord.Coord` or 'string') Scalar coordinate to promote to a dimension coordinate. + * expand_extras (iterable) + Auxiliary coordinates, ancillary variables and cell measures which will + be expanded so that they map to the new dimension as well as the + existing dimensions. + Returns: A new :class:`iris.cube.Cube` instance with one extra leading dimension - (length 1). + (length 1). Chosen auxiliary coordinates, cell measures and ancillary + variables will also be given an additional dimension, associated with + the leading dimension of the cube. For example:: @@ -1120,40 +1129,83 @@ def new_axis(src_cube, scalar_coord=None): >>> ncube = iris.util.new_axis(cube, 'time') >>> ncube.shape (1, 360, 360) - """ - from iris.coords import DimCoord - from iris.cube import Cube + + def _reshape_data_array(data_manager): + # Indexing numpy arrays requires loading deferred data here returning a + # copy of the data with a new leading dimension. + # If the data of the source cube (or values of the dimensional metadata + # object) is a Masked Constant, it is changed here to a Masked Array to + # allow the mask to gain an extra dimension with the data. + if data_manager.has_lazy_data(): + new_data = data_manager.lazy_data()[None] + else: + if isinstance(data_manager.data, ma.core.MaskedConstant): + new_data = ma.array([np.nan], mask=[True]) + else: + new_data = data_manager.data[None] + return new_data + + def _handle_dimensional_metadata( + cube, dm_item, cube_add_method, expand_extras + ): + cube_dims = dm_item.cube_dims(cube) + if dm_item in expand_extras: + if cube_dims == (): + new_dm_item, new_dims = dm_item.copy(), 0 + else: + new_dims = np.concatenate([(0,), np.array(cube_dims) + 1]) + new_values = _reshape_data_array(dm_item._values_dm) + kwargs = dm_item.metadata._asdict() + new_dm_item = dm_item.__class__(new_values, **kwargs) + try: + if dm_item.has_bounds(): + new_dm_item.bounds = _reshape_data_array( + dm_item._bounds_dm + ) + except AttributeError: + pass + else: + new_dims = np.array(cube_dims) + 1 + new_dm_item = dm_item.copy() + + cube_add_method(new_dm_item, new_dims) if scalar_coord is not None: scalar_coord = src_cube.coord(scalar_coord) + if not scalar_coord.shape == (1,): + emsg = scalar_coord.name() + "is not a scalar coordinate." + raise ValueError(emsg) - # Indexing numpy arrays requires loading deferred data here returning a - # copy of the data with a new leading dimension. - # If the source cube is a Masked Constant, it is changed here to a Masked - # Array to allow the mask to gain an extra dimension with the data. - if src_cube.has_lazy_data(): - new_cube = Cube(src_cube.lazy_data()[None]) - else: - if isinstance(src_cube.data, ma.core.MaskedConstant): - new_data = ma.array([np.nan], mask=[True]) - else: - new_data = src_cube.data[None] - new_cube = Cube(new_data) + expand_extras = [ + src_cube._dimensional_metadata(item) for item in expand_extras + ] + new_cube = iris.cube.Cube(_reshape_data_array(src_cube._data_manager)) new_cube.metadata = src_cube.metadata + for coord in src_cube.dim_coords: + coord_dims = np.array(src_cube.coord_dims(coord)) + 1 + new_cube.add_dim_coord(coord.copy(), coord_dims) + for coord in src_cube.aux_coords: if scalar_coord and scalar_coord == coord: - dim_coord = DimCoord.from_coord(coord) + dim_coord = iris.coords.DimCoord.from_coord(coord) new_cube.add_dim_coord(dim_coord, 0) else: - dims = np.array(src_cube.coord_dims(coord)) + 1 - new_cube.add_aux_coord(coord.copy(), dims) + _handle_dimensional_metadata( + src_cube, coord, new_cube.add_aux_coord, expand_extras + ) - for coord in src_cube.dim_coords: - coord_dims = np.array(src_cube.coord_dims(coord)) + 1 - new_cube.add_dim_coord(coord.copy(), coord_dims) + for cm in src_cube.cell_measures(): + _handle_dimensional_metadata( + src_cube, cm, new_cube.add_cell_measure, expand_extras + ) + + for av in src_cube.ancillary_variables(): + _handle_dimensional_metadata( + src_cube, av, new_cube.add_ancillary_variable, expand_extras + ) nonderived_coords = src_cube.dim_coords + src_cube.aux_coords coord_mapping = { @@ -1754,29 +1806,123 @@ def find_discontiguities(cube, rel_tol=1e-5, abs_tol=1e-8): return bad_points_boolean -def mask_cube(cube, points_to_mask): +def _mask_array(array, points_to_mask, in_place=False): """ - Masks any cells in the data array which correspond to cells marked `True` - in the `points_to_mask` array. + Apply masking to array where points_to_mask is True/non-zero. Designed to + work with iris.analysis.maths._binary_op_common so array and points_to_mask + will be broadcastable to each other. array and points_to_mask may be numpy + or dask types (or one of each). - Args: + If array is lazy then in_place is ignored: _math_op_common will use the + returned value regardless of in_place, so we do not need to implement it + here. If in_place is True then array must be a np.ma.MaskedArray or dask + array (must be a dask array if points_to_mask is lazy). - * cube (`iris.cube.Cube`): - A 2-dimensional instance of :class:`iris.cube.Cube`. + """ + # Decide which array library to use. + if is_lazy_data(points_to_mask) or is_lazy_data(array): + al = da + if not is_lazy_data(array) and in_place: + # Non-lazy array and lazy mask should not come up for in_place + # case, due to _binary_op_common handling added at #3790. + raise TypeError( + "Cannot apply lazy mask in-place to a non-lazy array." + ) + in_place = False + + elif in_place and not isinstance(array, ma.MaskedArray): + raise TypeError("Cannot apply a mask in-place to a plain numpy array.") + else: + al = np - * points_to_mask (`numpy.ndarray` of bool): - A 2d boolean array of Truth values representing points to mask in the - x and y arrays of the cube. + points_to_mask = points_to_mask.astype(bool) - Returns: + # Treat any masked points on our mask as False. + points_to_mask = al.ma.filled(points_to_mask, False) + + # Get broadcasted views of the arrays. Note that broadcast_arrays does not + # preserve masks, so we need to explicitly handle any exising mask on array. + array_mask = al.ma.getmaskarray(array) + + array_data, array_mask, points_to_mask = al.broadcast_arrays( + array, array_mask, points_to_mask + ) + + new_mask = al.logical_or(array_mask, points_to_mask) - * result (`iris.cube.Cube`): - A cube whose data array is masked at points specified by input array. + if in_place: + array.mask = new_mask + result = array # Resolve uses returned value even if working in place. + else: + # Return a new, independent array. + result = al.ma.masked_array(array_data.copy(), mask=new_mask) + return result + + +@_lenient_client(services=SERVICES) +def mask_cube(cube, points_to_mask, in_place=False, dim=None): """ - cube.data = ma.masked_array(cube.data) - cube.data[points_to_mask] = ma.masked - return cube + Masks any cells in the cube's data array which correspond to cells marked + ``True`` (or non zero) in ``points_to_mask``. ``points_to_mask`` may be + specified as a :class:`numpy.ndarray`, :class:`iris.coords.Coord` or + :class:`iris.cube.Cube`, following the same broadcasting approach as cube + arithmetic (see :ref:`cube maths`). + + Parameters + ---------- + + cube : iris.cube.Cube + Cube containing data that requires masking. + + points_to_mask : numpy.ndarray, iris.coords.Coord or iris.cube.Cube + Specifies booleans (or ones and zeros) indicating which points will be masked. + + in_place : bool, default=False + If `True`, masking is applied to the input cube. Otherwise a copy is masked + and returned. + + dim : int, optional + If `points_to_mask` is a coord which does not exist on the cube, specify the + dimension to which it should be mapped. + + Returns + ------- + + iris.cube.Cube + A cube whose data array is masked at points specified by ``points_to_mask``. + + Notes + ----- + + If either ``cube`` or ``points_to_mask`` is lazy, the result will be lazy. + + """ + if in_place and not cube.has_lazy_data(): + # Ensure cube data is masked type so we can work on it in-place. + cube.data = ma.asanyarray(cube.data) + mask_function = functools.partial(_mask_array, in_place=True) + else: + mask_function = _mask_array + + input_metadata = cube.metadata + result = iris.analysis.maths._binary_op_common( + mask_function, + "mask", + cube, + points_to_mask, + cube.units, + in_place=in_place, + dim=dim, + sanitise_metadata=False, + ) + + # Resolve combines the metadata from the two operands, but we want to + # preserve the metadata from the (first) input cube. + result.metadata = input_metadata + + if not in_place: + return result def equalise_attributes(cubes): diff --git a/noxfile.py b/noxfile.py index 2b1df8fb00..8aabf862fb 100755 --- a/noxfile.py +++ b/noxfile.py @@ -271,6 +271,36 @@ def linkcheck(session: nox.sessions.Session): ) +@nox.session(python=PY_VER, venv_backend="conda") +def wheel(session: nox.sessions.Session): + """ + Perform iris local wheel install and import test. + + Parameters + ---------- + session: object + A `nox.sessions.Session` object. + + """ + prepare_venv(session) + session.cd("dist") + fname = list(Path(".").glob("scitools_iris-*.whl")) + if len(fname) == 0: + raise ValueError("Cannot find wheel to install.") + if len(fname) > 1: + emsg = ( + f"Expected to find 1 wheel to install, found {len(fname)} instead." + ) + raise ValueError(emsg) + session.install(fname[0].name) + session.run( + "python", + "-c", + "import iris; print(f'{iris.__version__=}')", + external=True, + ) + + @nox.session @nox.parametrize( "run_type", diff --git a/pyproject.toml b/pyproject.toml index 26e6ae727a..bdb8a431e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,17 @@ [build-system] # Defined by PEP 518 requires = [ - "setuptools>=40.8.0", + "setuptools>=64", + "setuptools_scm[toml]>=7.0", "wheel", ] # Defined by PEP 517 build-backend = "setuptools.build_meta" +[tool.setuptools_scm] +write_to = "lib/iris/_version.py" +local_scheme = "dirty-tag" +version_scheme = "release-branch-semver" [tool.black] line-length = 79 @@ -37,3 +42,7 @@ extend_skip = [ ] skip_gitignore = "True" verbose = "False" + +[tool.pytest.ini_options] +addopts = "-ra" +testpaths = "lib/iris" diff --git a/requirements/ci/iris.yml b/requirements/ci/iris.yml index a76932b56e..1e473d36d5 120000 --- a/requirements/ci/iris.yml +++ b/requirements/ci/iris.yml @@ -1 +1 @@ -py38.yml \ No newline at end of file +py310.yml \ No newline at end of file diff --git a/requirements/ci/nox.lock/py310-linux-64.lock b/requirements/ci/nox.lock/py310-linux-64.lock new file mode 100644 index 0000000000..e60113c475 --- /dev/null +++ b/requirements/ci/nox.lock/py310-linux-64.lock @@ -0,0 +1,259 @@ +# Generated by conda-lock. +# platform: linux-64 +# input_hash: 5bb7d18990d558bee14aa553199bb8ef5e346b16214bf8df00042789e3f420e8 +@EXPLICIT +https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.9.24-ha878542_0.tar.bz2#41e4e87062433e283696cf384f952ef6 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-hab24e00_0.tar.bz2#19410c3df09dfb12d1206132a1d357c5 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.36.1-hea4e1c9_2.tar.bz2#bd4f2e711b39af170e7ff15163fe87ee +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.1.0-hdcd56e2_16.tar.bz2#b02605b875559ff99f04351fd5040760 +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.1.0-ha89aaad_16.tar.bz2#6f5ba041a41eb102a1027d9e68731be7 +https://conda.anaconda.org/conda-forge/linux-64/mpi-1.0-mpich.tar.bz2#c1fcff3417b5a22bbc4cf6e8c23648cf +https://conda.anaconda.org/conda-forge/noarch/tzdata-2022d-h191b570_0.tar.bz2#456b5b1d99e7a9654b331bcd82e71042 +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-12.1.0-h69a702a_16.tar.bz2#6bf15e29a20f614b18ae89368260d0a2 +https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.1.0-h8d9b700_16.tar.bz2#f013cf7749536ce43d82afbffdf499ab +https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.1.0-h8d9b700_16.tar.bz2#4f05bc9844f7c101e6e147dab3c88d5c +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.7.2-h166bdaf_0.tar.bz2#4a826cd983be6c8fff07a64b6d2079e7 +https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 +https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.18.1-h7f98852_0.tar.bz2#f26ef8098fab1f719c91eb760d63381a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.4.9-h27087fc_0.tar.bz2#493ac8b2503a949aebe33d99ea0c284f +https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_105.tar.bz2#9d3e01547ba04a57372beee01158096f +https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.11.0-h27087fc_0.tar.bz2#a583d0bc9a85c48e8b07a588d1ac8a80 +https://conda.anaconda.org/conda-forge/linux-64/gettext-0.19.8.1-h27087fc_1009.tar.bz2#17f91dc8bb7a259b02be5bfb2cd2395f +https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h36c2ea0_2.tar.bz2#626e68ae9cc5912d6adb79d318cf962d +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 +https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed +https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 +https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 +https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f +https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.0.9-h166bdaf_7.tar.bz2#f82dc1c78bcf73583f2656433ce2933c +https://conda.anaconda.org/conda-forge/linux-64/libdb-6.2.32-h9c3ff4c_0.tar.bz2#3f3258d8f841fbac63b36b75bdac1afd +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.14-h166bdaf_0.tar.bz2#fc84a0446e4e4fb882e78d786cfb9734 +https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h516909a_1.tar.bz2#6f8720dff19e17ce5d48cfe7f3d2f0a3 +https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 +https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d +https://conda.anaconda.org/conda-forge/linux-64/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d +https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 +https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 +https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f +https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.6-h9c3ff4c_1008.tar.bz2#16e143a1ed4b4fd169536373957f6fee +https://conda.anaconda.org/conda-forge/linux-64/libudev1-249-h166bdaf_4.tar.bz2#dc075ff6fcb46b3d3c7652e543d5f334 +https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.12-h166bdaf_4.tar.bz2#6a2e5b333ba57ce7eec61e90260cbb79 +https://conda.anaconda.org/conda-forge/linux-64/mpich-4.0.2-h846660c_100.tar.bz2#36a36fe04b932d4b327e7e81c5c43696 +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.32-h9c3ff4c_1.tar.bz2#29ded371806431b0499aaee146abfc3e +https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1q-h166bdaf_0.tar.bz2#07acc367c7fc8b716770cd5b36d31717 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 +https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 +https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h7f98852_1002.tar.bz2#1e15f6ad85a7d743a2ac68dae6c82b98 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 +https://conda.anaconda.org/conda-forge/linux-64/xxhash-0.8.0-h7f98852_3.tar.bz2#52402c791f35e414e704b7a113f99605 +https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 +https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae +https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h9772cbc_4.tar.bz2#dd3e1941dd06f64cb88647d2f7ff8aaa +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b +https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_7.tar.bz2#37a460703214d0d1b421e2a47eb5e6d0 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_7.tar.bz2#785a9296ea478eb78c47593c4da6550f +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.65-ha37c62d_0.tar.bz2#2c1c43f5442731b58e070bcee45a86ec +https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 +https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h9b69904_4.tar.bz2#390026683aef81db27ff1b8570ca1336 +https://conda.anaconda.org/conda-forge/linux-64/libflac-1.3.4-h27087fc_0.tar.bz2#620e52e160fd09eb8772dedd46bb19ef +https://conda.anaconda.org/conda-forge/linux-64/libllvm14-14.0.6-he0ac6c6_0.tar.bz2#f5759f0c80708fbf9c4836c0cb46d0fe +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-hdcd2b5c_1.tar.bz2#6fe9e31c2b8d0b022626ccac13e6ca3c +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.38-h753d276_0.tar.bz2#575078de1d3a3114b3ce131bd1508d0c +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.39.4-h753d276_0.tar.bz2#978924c298fc2215f129e8171bbea688 +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-haa6b8db_3.tar.bz2#89acee135f0809a18a1f4537390aa2dd +https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.2-h4c7fe37_1.tar.bz2#d543c0192b13a1d0236367d3fb1e022c +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.9.2-hc869a4a_1.tar.bz2#7a268cf1386d271e576e35ae82149ef2 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.30-haf5c9bc_1.tar.bz2#62b588b2a313ac3d9c2ead767baa3b5d +https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.37-hc3806b6_1.tar.bz2#dfd26f27a9d5de96cec1d007b9aeb964 +https://conda.anaconda.org/conda-forge/linux-64/portaudio-19.6.0-h8e90077_6.tar.bz2#2935b98de57e1f261ef8253655a8eb80 +https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-hc3e0081_0.tar.bz2#d4c341e0379c31e9e781d4f204726867 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.12-h166bdaf_4.tar.bz2#995cc7813221edbc25a3db15357599a0 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_7.tar.bz2#1699c1211d56a23c66047524cd76796e +https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_0.tar.bz2#4e54cbfc47b8c74c2ecc1e7730d8edce +https://conda.anaconda.org/conda-forge/linux-64/krb5-1.19.3-h3790be6_0.tar.bz2#7d862b05445123144bec92cb1acc8ef8 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-14.0.6-default_h3a83d3e_0.tar.bz2#cdbd49e0ab5c5a6c522acb8271977d4c +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.0-h7a41b64_0.tar.bz2#fe768553d0fe619bb9704e3c79c0ee2e +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad +https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.0.31-h9c3ff4c_1.tar.bz2#fc4b6d93da04731db7601f2a1b1dc96a +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.4.0-h55922b4_4.tar.bz2#901791f0ec7cddc8714e76e273013a91 +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.30-h28c427c_1.tar.bz2#0bd292db365c83624316efc2764d9f16 +https://conda.anaconda.org/conda-forge/linux-64/python-3.10.6-h582c2e5_0_cpython.tar.bz2#6f009f92084e84884d1dff862b85eb00 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.39.4-h4ff8645_0.tar.bz2#643c271de2dd23ecbd107284426cebc2 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h166bdaf_0.tar.bz2#0a8e20a8aef954390b9481a527421a8c +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.7.2-h7f98852_0.tar.bz2#12a61e640b8894504326aadafccbb790 +https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.12-py_0.tar.bz2#2489a97287f90176ecdc3ca982b4b0a0 +https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.36.0-h3371d22_4.tar.bz2#661e1ed5d92552785d9f8c781ce68685 +https://conda.anaconda.org/conda-forge/noarch/attrs-22.1.0-pyh71513ae_1.tar.bz2#6d3ccbc56256204925bfa8378722792f +https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_7.tar.bz2#3889dec08a472eb0f423e5609c76bde1 +https://conda.anaconda.org/conda-forge/noarch/certifi-2022.9.24-pyhd8ed1ab_0.tar.bz2#f66309b099374af91369e67e84af397d +https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2#ebb5f5f7dc4f1a3780ef7ea7738db08c +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.0-pyhd8ed1ab_0.tar.bz2#a6cf47b09786423200d7982d1faa19eb +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.5-pyhd8ed1ab_0.tar.bz2#c267da48ce208905d7d976d49dfd9433 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb +https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.5-pyhd8ed1ab_0.tar.bz2#f15c3912378a07726093cc94d1e13251 +https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.8.0-pyhd8ed1ab_0.tar.bz2#10f0218dbd493ab2e5dc6759ddea4526 +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.0-hc2a2eb6_1.tar.bz2#139ace7da04f011abbd531cb2a9840ee +https://conda.anaconda.org/conda-forge/noarch/fsspec-2022.8.2-pyhd8ed1ab_0.tar.bz2#140dc6615896e7d4be1059a63370be93 +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.8-hff1cb4f_1.tar.bz2#a61c6312192e7c9de71548a6706a21e6 +https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.0-h6239696_0.tar.bz2#d2db078274532eeab50a06d65172a3c4 +https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h64030ff_2.tar.bz2#112eb9b5b93f0c02e59aea4fd1967363 +https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed +https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-1.1.1-pyh9f0ad1d_0.tar.bz2#39161f81cc5e5ca45b8226fbb06c6905 +https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_0.tar.bz2#18ee9c07cf945a33f92caf1ee3d23ad9 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.18-h8c3723f_1003.tar.bz2#9cb956b6605cfc7d8ee1b15e96bd88ba +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.12-hddcbb42_0.tar.bz2#797117394a4aa588de6d741b06fad80f +https://conda.anaconda.org/conda-forge/linux-64/libclang-14.0.6-default_h2e3cab8_0.tar.bz2#eb70548da697e50cefa7ba939d57d001 +https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h3e49a29_2.tar.bz2#3b88f1d0fe2580594d58d7e44d664617 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.85.0-h7bff187_0.tar.bz2#054fb5981fdbe031caeb612b71d85f84 +https://conda.anaconda.org/conda-forge/linux-64/libpq-14.5-hd77ab85_0.tar.bz2#d3126b425a04ed2360da1e651cef1b2d +https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.2.4-h522a892_0.tar.bz2#802e43f480122a85ae6a34c1909f8f98 +https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 +https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.78-h2350873_0.tar.bz2#ab3df39f96742e6f1a9878b09274c1dc +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-h7d73246_1.tar.bz2#a11b4df9271a8d7917686725aa04c8f2 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.2-pyhd8ed1ab_1.tar.bz2#2fb3f88922e7aec26ba652fcdfe13950 +https://conda.anaconda.org/conda-forge/noarch/ply-3.11-py_1.tar.bz2#7205635cd71531943440fbfe3b6b5727 +https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054 +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc +https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.1-pyhd8ed1ab_0.tar.bz2#92a889dc236a5197612bc85bee6d7174 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.10-2_cp310.tar.bz2#9e7160cd0d865e98f6803f1fe15c8b61 +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.4-pyhd8ed1ab_0.tar.bz2#fc0dcaf9761d042fb8ac9128ce03fddb +https://conda.anaconda.org/conda-forge/noarch/setuptools-65.4.1-pyhd8ed1ab_0.tar.bz2#d61d9f25af23c24002e659b854c6f5ae +https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e +https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.3.2.post1-pyhd8ed1ab_0.tar.bz2#146f4541d643d48fc8a75cacf69f03ae +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.2-py_0.tar.bz2#20b2eaeaeea4ef9a9a0d99770620fd09 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.2-py_0.tar.bz2#68e01cac9d38d0e717cd5c87bc3d2cc9 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd8ed1ab_0.tar.bz2#77dad82eb9c8c1525ff7953e0756d708 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-py_0.tar.bz2#67cd9d9c0382d37479b4d306c369a2d4 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.3-py_0.tar.bz2#d01180388e6d1838c3e1ad029590aa7a +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd8ed1ab_2.tar.bz2#9ff55a0901cf952f05c654394de76bf7 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 +https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a +https://conda.anaconda.org/conda-forge/noarch/wheel-0.37.1-pyhd8ed1ab_0.tar.bz2#1ca02aaf78d9c70d9a81a3bed5752022 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h7f98852_1.tar.bz2#536cc5db4d0a3ba0630541aec064b5e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb +https://conda.anaconda.org/conda-forge/noarch/zipp-3.8.1-pyhd8ed1ab_0.tar.bz2#a3508a0c850745b875de88aea4c40cc5 +https://conda.anaconda.org/conda-forge/linux-64/antlr-python-runtime-4.7.2-py310hff52083_1003.tar.bz2#8324f8fff866055d4b32eb25e091fe31 +https://conda.anaconda.org/conda-forge/noarch/babel-2.10.3-pyhd8ed1ab_0.tar.bz2#72f1c6d03109d7a70087bc1d029a8eda +https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.11.1-pyha770c72_0.tar.bz2#eeec8814bd97b2681f708bb127478d7d +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py310h255011f_0.tar.bz2#3e4b55b02998782f8ca9ceaaa4f5ada9 +https://conda.anaconda.org/conda-forge/linux-64/curl-7.85.0-h7bff187_0.tar.bz2#a8ac96d6b09b8ed5b0ac6563901e2195 +https://conda.anaconda.org/conda-forge/linux-64/docutils-0.17.1-py310hff52083_2.tar.bz2#1cdb74e021e4e0b703a8c2f7cc57d798 +https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.0-h6239696_0.tar.bz2#60e6c8c867cdac0fc5f52fbbdfd7a057 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.12.2-mpi_mpich_h08b82f9_0.tar.bz2#de601caacbaa828d845f758e07e3b85e +https://conda.anaconda.org/conda-forge/linux-64/importlib-metadata-4.11.4-py310hff52083_0.tar.bz2#8ea386e64531f1ecf4a5765181579e7e +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py310hbf28c38_0.tar.bz2#8dc3e2dce8fa122f8df4f3739d1f771b +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h18fbbfe_3.tar.bz2#ea9758cf553476ddf75c789fdd239dc5 +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.1-py310h5764c6d_1.tar.bz2#ec5a727504409ad1380fc2a84f83d002 +https://conda.anaconda.org/conda-forge/linux-64/mpi4py-3.1.3-py310h37cc914_2.tar.bz2#0211369f253eedce9e570b4f0e5a981a +https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.7.0-pyhd8ed1ab_0.tar.bz2#fbe1182f650c04513046d6894046cd6c +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.23.3-py310h53a5b5f_0.tar.bz2#0a60ccaed9ad236cc7463322fe742eb6 +https://conda.anaconda.org/conda-forge/noarch/packaging-21.3-pyhd8ed1ab_0.tar.bz2#71f1ab2de48613876becddd496371c85 +https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#af8c82d121e63082926062d61d9abb54 +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.2.0-py310hbd86126_2.tar.bz2#443272de4234f6df4a78f50105edc741 +https://conda.anaconda.org/conda-forge/noarch/pip-22.2.2-pyhd8ed1ab_0.tar.bz2#0b43abe4d3ee93e82742d37def53a836 +https://conda.anaconda.org/conda-forge/linux-64/pluggy-1.0.0-py310hff52083_3.tar.bz2#97f9a22577338f91a94dfac5c1a65a50 +https://conda.anaconda.org/conda-forge/noarch/pockets-0.9.1-py_0.tar.bz2#1b52f0c42e8077e5a33e00fe72269364 +https://conda.anaconda.org/conda-forge/linux-64/proj-9.1.0-h93bde94_0.tar.bz2#255c7204dda39747c3ba380d28b026d7 +https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.2-py310h5764c6d_0.tar.bz2#6ac13c26fe4f9d8d6b38657664c37fd3 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-14.0-h0868958_9.tar.bz2#5bca71f0cf9b86ec58dd9d6216a3ffaf +https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 +https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.0.0-py310h5764c6d_1.tar.bz2#b6f54b7c4177a745d5e6e4319282253a +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0-py310h5764c6d_4.tar.bz2#505dcf6be997e732d7a33831950dc3cf +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py310h5764c6d_0.tar.bz2#c42dcb37acd84b3ca197f03f57ef927d +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026 +https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-14.0.0-py310h5764c6d_1.tar.bz2#791689ce9e578e2e83b635974af61743 +https://conda.anaconda.org/conda-forge/linux-64/virtualenv-20.16.5-py310hff52083_0.tar.bz2#e572565848d8d19e74983f4d122734a8 +https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py310h5764c6d_1004.tar.bz2#6499bb11b7feffb63b26847fc9181319 +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.2-py310hde88566_0.tar.bz2#6290f1bc763ed75a42aaea29384f9858 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.5-py310hbf28c38_0.tar.bz2#85565efb2bf44e8a5782e7c418d30cfe +https://conda.anaconda.org/conda-forge/linux-64/cryptography-38.0.1-py310h597c629_0.tar.bz2#890771047730c6fa66a8926f0ca9bd13 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2022.9.2-pyhd8ed1ab_0.tar.bz2#9993f51a02fc8338837421211b53ab19 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.37.4-py310h5764c6d_0.tar.bz2#46eb2017ab2148b1f28334b07510f0e5 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.20.3-hd4edc92_2.tar.bz2#153cfb02fb8be7dd7cabcbcb58a63053 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-5.2.0-hf9f4e7c_0.tar.bz2#3c5f4fbd64c7254fbe246ca9d87863b6 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.8.1-mpi_mpich_h06c54e2_4.tar.bz2#491803a7356c6a668a84d71f491c4014 +https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.2.0-py310hde88566_1007.tar.bz2#c2ec7c118184ddfd855fc3698d1c8e63 +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.0-py310h769672d_0.tar.bz2#06efc4b5f4b418b78de14d1db4a65cad +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.4.0-py310hb1338dc_1.tar.bz2#0ad6207e9d553c67984a5b0b06bbd2a3 +https://conda.anaconda.org/conda-forge/linux-64/pytest-7.1.3-py310hff52083_0.tar.bz2#18ef27d620d67af2feef22acfd42cf4a +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.2.post0-py310hde88566_2.tar.bz2#a282f30e2e1efa1f210817597e144762 +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.3.0-py310hde88566_1.tar.bz2#cbfce984f85c64401e3d4fedf4bc4247 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.9.1-py310hdfbd76f_0.tar.bz2#bfb55d07ad9d15d2f2f8e59afcbcf578 +https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-7.0.5-pyhd8ed1ab_0.tar.bz2#743074b7a216807886f7e8f6d497cceb +https://conda.anaconda.org/conda-forge/linux-64/shapely-1.8.4-py310h5e49deb_0.tar.bz2#2f2c225d04e99ff99d6d3a86692ce968 +https://conda.anaconda.org/conda-forge/linux-64/sip-6.6.2-py310hd8f1fbe_0.tar.bz2#3d311837eadeb8137fca02bdb5a9751f +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-napoleon-0.7-py_0.tar.bz2#0bc25ff6f2e34af63ded59692df5f749 +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py310hbf28c38_2.tar.bz2#46784478afa27e33b9d5f017c4deb49d +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.1.1-py310hde88566_0.tar.bz2#49790458218da5f86068f32e3938d334 +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.20.3-h57caac4_2.tar.bz2#58838c4ca7d1a5948f5cdcbb8170d753 +https://conda.anaconda.org/conda-forge/noarch/identify-2.5.6-pyhd8ed1ab_0.tar.bz2#8c3563a8e310ea9a727f07caa0341ec2 +https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.0-py310h8d5ebf3_0.tar.bz2#001fdef689e7cbcbbce6d5a6ebee90b6 +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.0-mpi_mpich_hd09bd1e_1.tar.bz2#0b69750bb937cab0db14f6bcef6fd787 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.0-nompi_py310h55e1e36_102.tar.bz2#588d5bd8f16287b766c509ef173b892d +https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.11-h382ae3d_0.tar.bz2#509e3f89508398070d3bf7769d9e8b03 +https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.0.0-pyhd8ed1ab_1.tar.bz2#2e7e3630919d29c8216bfa2cd643d79e +https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py310hd8f1fbe_0.tar.bz2#9e3db99607d6f9285b7348c2af28a095 +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_0.tar.bz2#95286e05a617de9ebfe3246cecbfb72f +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.21.0-py310hcda3f9e_0.tar.bz2#3e81d6afa50895d6dee115ac5d34c2ea +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.2.0-mpi_mpich_h5a1934d_102.tar.bz2#bb8bdfa5e3e9e3f6ec861f05cd2ad441 +https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h90689f9_2.tar.bz2#957a0255ab58aaf394a91725d73ab422 +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.54.4-h7abd40a_0.tar.bz2#921e53675ed5ea352f022b79abab076a +https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 +https://conda.anaconda.org/conda-forge/linux-64/pre-commit-2.20.0-py310hff52083_0.tar.bz2#5af49a9342d50006017b897698921f43 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-hc525480_0.tar.bz2#abd0f27f5e84cd0d5ae14d22b08795d7 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.11-pyhd8ed1ab_0.tar.bz2#0738978569b10669bdef41c671252dd1 +https://conda.anaconda.org/conda-forge/linux-64/esmpy-8.2.0-mpi_mpich_py310hd9c82d4_101.tar.bz2#0333d51ee594be40f50b157ac6f27b5a +https://conda.anaconda.org/conda-forge/linux-64/graphviz-6.0.1-h5abf519_0.tar.bz2#123c55da3e9ea8664f73c70e13ef08c2 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py310h29803b5_0.tar.bz2#b5fb5328cae86d0b1591fc4894e68238 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.0-py310hff52083_0.tar.bz2#2db9d22cc226ef79d9cd87fc958c2b04 +https://conda.anaconda.org/conda-forge/noarch/sphinx-4.5.0-pyh6c4a22f_0.tar.bz2#46b38d88c4270ff9ba78a89c83c66345 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.8.1-pyhd8ed1ab_0.tar.bz2#7d8390ec71225ea9841b276552fdffba +https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.0-pyhd8ed1ab_0.tar.bz2#4c969cdd5191306c269490f7ff236d9c +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.11.1-pyhd8ed1ab_0.tar.bz2#729254314a5d178eefca50acbc2687b8 +https://conda.anaconda.org/conda-forge/noarch/sphinx-panels-0.6.0-pyhd8ed1ab_0.tar.bz2#6eec6480601f5d15babf9c3b3987f34a diff --git a/requirements/ci/nox.lock/py38-linux-64.lock b/requirements/ci/nox.lock/py38-linux-64.lock index e3604c3ea8..d6301a12b7 100644 --- a/requirements/ci/nox.lock/py38-linux-64.lock +++ b/requirements/ci/nox.lock/py38-linux-64.lock @@ -1,9 +1,9 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 1cd97f6f80cce9e7fa719a886fb090579568d5909bfcac6cb42a820ad562dad3 +# input_hash: a434c868ae6df31789fd61bd87bd1c2bc217fccf612eabfe62832dbf48266923 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.6.15-ha878542_0.tar.bz2#c320890f77fd1d617fa876e0982002c2 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.9.24-ha878542_0.tar.bz2#41e4e87062433e283696cf384f952ef6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb @@ -18,42 +18,41 @@ https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.1.0-h8d9b700_16.tar.b https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.1.0-h8d9b700_16.tar.bz2#4f05bc9844f7c101e6e147dab3c88d5c -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.6.1-h7f98852_0.tar.bz2#0347ce6a34f8b55b544b141432c6d4c7 -https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_0.tar.bz2#ec47e97c8e0b27dcadbebc4d17764548 +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.7.2-h166bdaf_0.tar.bz2#4a826cd983be6c8fff07a64b6d2079e7 +https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54 https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.18.1-h7f98852_0.tar.bz2#f26ef8098fab1f719c91eb760d63381a -https://conda.anaconda.org/conda-forge/linux-64/expat-2.4.8-h27087fc_0.tar.bz2#e1b07832504eeba765d648389cc387a9 -https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_h77c792f_102.tar.bz2#208f18b1d596b50c6a92a12b30ebe31f +https://conda.anaconda.org/conda-forge/linux-64/expat-2.4.9-h27087fc_0.tar.bz2#493ac8b2503a949aebe33d99ea0c284f +https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_105.tar.bz2#9d3e01547ba04a57372beee01158096f https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 -https://conda.anaconda.org/conda-forge/linux-64/geos-3.10.3-h27087fc_0.tar.bz2#d11cf000ee8b976b5ce3b425477b5689 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.11.0-h27087fc_0.tar.bz2#a583d0bc9a85c48e8b07a588d1ac8a80 +https://conda.anaconda.org/conda-forge/linux-64/gettext-0.19.8.1-h27087fc_1009.tar.bz2#17f91dc8bb7a259b02be5bfb2cd2395f https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h36c2ea0_2.tar.bz2#626e68ae9cc5912d6adb79d318cf962d https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_1.tar.bz2#4828c7f7208321cfbede4880463f4930 +https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 -https://conda.anaconda.org/conda-forge/linux-64/lerc-3.0-h9c3ff4c_0.tar.bz2#7fcefde484980d23f0ec24c11e314d2e +https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.0.9-h166bdaf_7.tar.bz2#f82dc1c78bcf73583f2656433ce2933c https://conda.anaconda.org/conda-forge/linux-64/libdb-6.2.32-h9c3ff4c_0.tar.bz2#3f3258d8f841fbac63b36b75bdac1afd -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.12-h166bdaf_0.tar.bz2#d56e3db8fa642fb383f18f5be35eeef2 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.14-h166bdaf_0.tar.bz2#fc84a0446e4e4fb882e78d786cfb9734 https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h516909a_1.tar.bz2#6f8720dff19e17ce5d48cfe7f3d2f0a3 https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 -https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.16-h516909a_0.tar.bz2#5c0f338a513a2943c659ae619fca9211 +https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d https://conda.anaconda.org/conda-forge/linux-64/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.20-pthreads_h78a6416_0.tar.bz2#9b6d0781953c9e353faee494336cc229 +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.6-h9c3ff4c_1008.tar.bz2#16e143a1ed4b4fd169536373957f6fee https://conda.anaconda.org/conda-forge/linux-64/libudev1-249-h166bdaf_4.tar.bz2#dc075ff6fcb46b3d3c7652e543d5f334 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.2-h7f98852_1.tar.bz2#46cf26ecc8775a0aab300ea1821aaa3c -https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.12-h166bdaf_1.tar.bz2#58eaff4f91891978af3625e7bbf958af -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.3-h9c3ff4c_1.tar.bz2#fbe97e8fa6f275d7c76a09e795adc3e6 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.12-h166bdaf_4.tar.bz2#6a2e5b333ba57ce7eec61e90260cbb79 https://conda.anaconda.org/conda-forge/linux-64/mpich-4.0.2-h846660c_100.tar.bz2#36a36fe04b932d4b327e7e81c5c43696 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 https://conda.anaconda.org/conda-forge/linux-64/nspr-4.32-h9c3ff4c_1.tar.bz2#29ded371806431b0499aaee146abfc3e -https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1p-h166bdaf_0.tar.bz2#995e819f901ee0c4411e4f50d9b31a82 -https://conda.anaconda.org/conda-forge/linux-64/pcre-8.45-h9c3ff4c_0.tar.bz2#c05d1820a6d34ff07aaaab7a9b7eddaa +https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1q-h166bdaf_0.tar.bz2#07acc367c7fc8b716770cd5b36d31717 https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a @@ -64,42 +63,46 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852 https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h7f98852_1002.tar.bz2#1e15f6ad85a7d743a2ac68dae6c82b98 https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xxhash-0.8.0-h7f98852_3.tar.bz2#52402c791f35e414e704b7a113f99605 -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.5-h516909a_1.tar.bz2#33f601066901f3e1a85af3522a8113f9 +https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.19.8.1-h73d1719_1008.tar.bz2#af49250eca8e139378f8ff0ae9e57251 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-15_linux64_openblas.tar.bz2#04eb983975a1be3e57d6d667414cd774 +https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h9772cbc_4.tar.bz2#dd3e1941dd06f64cb88647d2f7ff8aaa +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_7.tar.bz2#37a460703214d0d1b421e2a47eb5e6d0 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_7.tar.bz2#785a9296ea478eb78c47593c4da6550f -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.64-ha37c62d_0.tar.bz2#5896fbd58d0376df8556a4aba1ce4f71 +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.65-ha37c62d_0.tar.bz2#2c1c43f5442731b58e070bcee45a86ec https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h9b69904_4.tar.bz2#390026683aef81db27ff1b8570ca1336 -https://conda.anaconda.org/conda-forge/linux-64/libllvm14-14.0.5-he0ac6c6_0.tar.bz2#63fbbbc5bd02f007a88ef7c4b58e9a62 +https://conda.anaconda.org/conda-forge/linux-64/libflac-1.3.4-h27087fc_0.tar.bz2#620e52e160fd09eb8772dedd46bb19ef +https://conda.anaconda.org/conda-forge/linux-64/libllvm14-14.0.6-he0ac6c6_0.tar.bz2#f5759f0c80708fbf9c4836c0cb46d0fe +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-hdcd2b5c_1.tar.bz2#6fe9e31c2b8d0b022626ccac13e6ca3c +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.38-h753d276_0.tar.bz2#575078de1d3a3114b3ce131bd1508d0c +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.39.4-h753d276_0.tar.bz2#978924c298fc2215f129e8171bbea688 +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-haa6b8db_3.tar.bz2#89acee135f0809a18a1f4537390aa2dd https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.29-haf5c9bc_1.tar.bz2#c01640c8bad562720d6caff0402dbd96 -https://conda.anaconda.org/conda-forge/linux-64/portaudio-19.6.0-h57a0ea0_5.tar.bz2#5469312a373f481c05c380897fd7c923 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.2-h4c7fe37_1.tar.bz2#d543c0192b13a1d0236367d3fb1e022c +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.9.2-hc869a4a_1.tar.bz2#7a268cf1386d271e576e35ae82149ef2 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.30-haf5c9bc_1.tar.bz2#62b588b2a313ac3d9c2ead767baa3b5d +https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.37-hc3806b6_1.tar.bz2#dfd26f27a9d5de96cec1d007b9aeb964 +https://conda.anaconda.org/conda-forge/linux-64/portaudio-19.6.0-h8e90077_6.tar.bz2#2935b98de57e1f261ef8253655a8eb80 https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-hc3e0081_0.tar.bz2#d4c341e0379c31e9e781d4f204726867 https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.12-h166bdaf_1.tar.bz2#e4b67f2b4096807cd7d836227c026a43 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h8a70e8d_1.tar.bz2#3db63b53bb194dbaa7dc3d8833e98da2 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.12-h166bdaf_4.tar.bz2#995cc7813221edbc25a3db15357599a0 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_7.tar.bz2#1699c1211d56a23c66047524cd76796e -https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h10796ff_3.tar.bz2#21a8d66dc17f065023b33145c42652fe +https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_0.tar.bz2#4e54cbfc47b8c74c2ecc1e7730d8edce https://conda.anaconda.org/conda-forge/linux-64/krb5-1.19.3-h3790be6_0.tar.bz2#7d862b05445123144bec92cb1acc8ef8 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-15_linux64_openblas.tar.bz2#f45968428e445fd0c6472b561145812a -https://conda.anaconda.org/conda-forge/linux-64/libclang13-14.0.5-default_h3a83d3e_0.tar.bz2#493aec1de0f0e09e921eff6206cafff6 -https://conda.anaconda.org/conda-forge/linux-64/libflac-1.3.4-h27087fc_0.tar.bz2#620e52e160fd09eb8772dedd46bb19ef -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.70.2-h174f98d_4.tar.bz2#d44314ffae96b17657fbf3f8e47b04fc -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-15_linux64_openblas.tar.bz2#b7078220384b8bf8db1a45e66412ac4f -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-h727a467_0.tar.bz2#a22567abfea169ff8048506b1ca9b230 -https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.37-h21135ba_2.tar.bz2#b6acf807307d033d4b7e758b4f44b036 -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-ha56f1ee_2.tar.bz2#6ab4eaa11ff01801cffca0a27489dc04 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.4.0-hc85c160_1.tar.bz2#151f9fae3ab50f039c8735e47770aa2d -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.9.14-h22db469_0.tar.bz2#7d623237b73d93dd856b5dd0f5fedd6b -https://conda.anaconda.org/conda-forge/linux-64/libzip-1.8.0-h4de3113_1.tar.bz2#175a746a43d42c053b91aa765fbc197d -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.29-h28c427c_1.tar.bz2#36dbdbf505b131c7e79a3857f3537185 -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.38.5-h4ff8645_0.tar.bz2#a1448f0c31baec3946d2dcf09f905c9e +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-14.0.6-default_h3a83d3e_0.tar.bz2#cdbd49e0ab5c5a6c522acb8271977d4c +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.0-h7a41b64_0.tar.bz2#fe768553d0fe619bb9704e3c79c0ee2e +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad +https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.0.31-h9c3ff4c_1.tar.bz2#fc4b6d93da04731db7601f2a1b1dc96a +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.4.0-h55922b4_4.tar.bz2#901791f0ec7cddc8714e76e273013a91 +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.30-h28c427c_1.tar.bz2#0bd292db365c83624316efc2764d9f16 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.39.4-h4ff8645_0.tar.bz2#643c271de2dd23ecbd107284426cebc2 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 @@ -108,57 +111,61 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.7.2-h7f98852_0.tar https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.36.0-h3371d22_4.tar.bz2#661e1ed5d92552785d9f8c781ce68685 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_7.tar.bz2#3889dec08a472eb0f423e5609c76bde1 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/linux-64/freetype-2.10.4-h0708190_1.tar.bz2#4a06f2ac2e5bfae7b6b245171c3f07aa -https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.8-hff1cb4f_0.tar.bz2#908fc30f89e27817d835b45f865536d7 -https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.70.2-h780b84a_4.tar.bz2#c66c6df8ef582a3b78702201b1eb8e94 +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.0-hc2a2eb6_1.tar.bz2#139ace7da04f011abbd531cb2a9840ee +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.8-hff1cb4f_1.tar.bz2#a61c6312192e7c9de71548a6706a21e6 +https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.0-h6239696_0.tar.bz2#d2db078274532eeab50a06d65172a3c4 https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h64030ff_2.tar.bz2#112eb9b5b93f0c02e59aea4fd1967363 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.18-h8c3723f_1003.tar.bz2#9cb956b6605cfc7d8ee1b15e96bd88ba https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.12-hddcbb42_0.tar.bz2#797117394a4aa588de6d741b06fad80f -https://conda.anaconda.org/conda-forge/linux-64/libclang-14.0.5-default_h2e3cab8_0.tar.bz2#8b1cd508fcf54a5c8c5766c549272b6e -https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hf5a7f15_1.tar.bz2#005557d6df00af70e438bcd532ce2304 -https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.83.1-h7bff187_0.tar.bz2#d0c278476dba3b29ee13203784672ab1 -https://conda.anaconda.org/conda-forge/linux-64/libpq-14.4-hd77ab85_0.tar.bz2#7024df220bd8680192d4bad4024122d1 -https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.0.31-h9c3ff4c_1.tar.bz2#fc4b6d93da04731db7601f2a1b1dc96a -https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.2.2-h3452ae3_0.tar.bz2#c363665b4aabe56aae4f8981cff5b153 -https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b +https://conda.anaconda.org/conda-forge/linux-64/libclang-14.0.6-default_h2e3cab8_0.tar.bz2#eb70548da697e50cefa7ba939d57d001 +https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h3e49a29_2.tar.bz2#3b88f1d0fe2580594d58d7e44d664617 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.85.0-h7bff187_0.tar.bz2#054fb5981fdbe031caeb612b71d85f84 +https://conda.anaconda.org/conda-forge/linux-64/libpq-14.5-hd77ab85_0.tar.bz2#d3126b425a04ed2360da1e651cef1b2d +https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.2.4-h522a892_0.tar.bz2#802e43f480122a85ae6a34c1909f8f98 https://conda.anaconda.org/conda-forge/linux-64/nss-3.78-h2350873_0.tar.bz2#ab3df39f96742e6f1a9878b09274c1dc -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.4.0-hb52868f_1.tar.bz2#b7ad78ad2e9ee155f59e6428406ee824 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-h7d73246_1.tar.bz2#a11b4df9271a8d7917686725aa04c8f2 https://conda.anaconda.org/conda-forge/linux-64/python-3.8.13-h582c2e5_0_cpython.tar.bz2#8ec74710472994e2411a8020fa8589ce https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h7f98852_1.tar.bz2#536cc5db4d0a3ba0630541aec064b5e4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.12-py_0.tar.bz2#2489a97287f90176ecdc3ca982b4b0a0 -https://conda.anaconda.org/conda-forge/noarch/attrs-21.4.0-pyhd8ed1ab_0.tar.bz2#f70280205d7044c8b8358c8de3190e5d +https://conda.anaconda.org/conda-forge/noarch/attrs-22.1.0-pyh71513ae_1.tar.bz2#6d3ccbc56256204925bfa8378722792f +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 +https://conda.anaconda.org/conda-forge/noarch/certifi-2022.9.24-pyhd8ed1ab_0.tar.bz2#f66309b099374af91369e67e84af397d https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2#ebb5f5f7dc4f1a3780ef7ea7738db08c -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.0.12-pyhd8ed1ab_0.tar.bz2#1f5b32dabae0f1893ae3283dac7f799e -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.1.0-pyhd8ed1ab_0.tar.bz2#f7551a8a008dfad2b7ac9662dd124614 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.0-pyhd8ed1ab_0.tar.bz2#a6cf47b09786423200d7982d1faa19eb https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.5-pyhd8ed1ab_0.tar.bz2#c267da48ce208905d7d976d49dfd9433 -https://conda.anaconda.org/conda-forge/linux-64/curl-7.83.1-h7bff187_0.tar.bz2#ba33b9995f5e691e4f439422d6efafc7 +https://conda.anaconda.org/conda-forge/linux-64/curl-7.85.0-h7bff187_0.tar.bz2#a8ac96d6b09b8ed5b0ac6563901e2195 https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb -https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.4-pyhd8ed1ab_0.tar.bz2#7b50d840543d9cdae100e91582c33035 +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.5-pyhd8ed1ab_0.tar.bz2#f15c3912378a07726093cc94d1e13251 https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.7.1-pyhd8ed1ab_0.tar.bz2#7556872687250e0ea038eb503da3c44b -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.0-h8e229c2_0.tar.bz2#f314f79031fec74adc9bff50fbaffd89 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2022.5.0-pyhd8ed1ab_0.tar.bz2#db4ffc615663c66a9cc0869ce4d1092b -https://conda.anaconda.org/conda-forge/linux-64/glib-2.70.2-h780b84a_4.tar.bz2#977c857d773389a51442ad3a716c0480 -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.12.1-mpi_mpich_h08b82f9_4.tar.bz2#975d5635b158c1b3c5c795f9d0a430a1 -https://conda.anaconda.org/conda-forge/noarch/idna-3.3-pyhd8ed1ab_0.tar.bz2#40b50b8b030f5f2f22085c062ed013dd -https://conda.anaconda.org/conda-forge/noarch/imagesize-1.3.0-pyhd8ed1ab_0.tar.bz2#be807e7606fff9436e5e700f6bffb7c6 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.8.0-pyhd8ed1ab_0.tar.bz2#10f0218dbd493ab2e5dc6759ddea4526 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2022.8.2-pyhd8ed1ab_0.tar.bz2#140dc6615896e7d4be1059a63370be93 +https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.0-h6239696_0.tar.bz2#60e6c8c867cdac0fc5f52fbbdfd7a057 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.12.2-mpi_mpich_h08b82f9_0.tar.bz2#de601caacbaa828d845f758e07e3b85e +https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed +https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-1.1.1-pyh9f0ad1d_0.tar.bz2#39161f81cc5e5ca45b8226fbb06c6905 https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_0.tar.bz2#18ee9c07cf945a33f92caf1ee3d23ad9 -https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.18-h8c3723f_1002.tar.bz2#7b3f287fcb7683f67b3d953b79f412ea +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h18fbbfe_3.tar.bz2#ea9758cf553476ddf75c789fdd239dc5 https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.1-pyhd8ed1ab_0.tar.bz2#d5df87964a39f67c46a5448f4e78d9b6 -https://conda.anaconda.org/conda-forge/linux-64/proj-9.0.1-h93bde94_0.tar.bz2#42d593cd1b23a43d7ac7edd9a2e84fa9 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.2-pyhd8ed1ab_1.tar.bz2#2fb3f88922e7aec26ba652fcdfe13950 +https://conda.anaconda.org/conda-forge/noarch/ply-3.11-py_1.tar.bz2#7205635cd71531943440fbfe3b6b5727 +https://conda.anaconda.org/conda-forge/linux-64/proj-9.1.0-h93bde94_0.tar.bz2#255c7204dda39747c3ba380d28b026d7 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-14.0-h0868958_9.tar.bz2#5bca71f0cf9b86ec58dd9d6216a3ffaf https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc -https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.0-pyhd8ed1ab_0.tar.bz2#0158f62cae46ad1fb77c522c4e7ecc90 +https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.1-pyhd8ed1ab_0.tar.bz2#92a889dc236a5197612bc85bee6d7174 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.8-2_cp38.tar.bz2#bfbb29d517281e78ac53e48d21e6e860 -https://conda.anaconda.org/conda-forge/noarch/pytz-2022.1-pyhd8ed1ab_0.tar.bz2#b87d66d6d3991d988fb31510c95a9267 +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.4-pyhd8ed1ab_0.tar.bz2#fc0dcaf9761d042fb8ac9128ce03fddb +https://conda.anaconda.org/conda-forge/noarch/setuptools-65.4.1-pyhd8ed1ab_0.tar.bz2#d61d9f25af23c24002e659b854c6f5ae https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e -https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.3.1-pyhd8ed1ab_0.tar.bz2#d821b295c4bd18ad27e1e19543a5784a +https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.3.2.post1-pyhd8ed1ab_0.tar.bz2#146f4541d643d48fc8a75cacf69f03ae https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.2-py_0.tar.bz2#20b2eaeaeea4ef9a9a0d99770620fd09 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.2-py_0.tar.bz2#68e01cac9d38d0e717cd5c87bc3d2cc9 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd8ed1ab_0.tar.bz2#77dad82eb9c8c1525ff7953e0756d708 @@ -167,87 +174,85 @@ https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.3-py_0.ta https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd8ed1ab_2.tar.bz2#9ff55a0901cf952f05c654394de76bf7 https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 -https://conda.anaconda.org/conda-forge/noarch/toolz-0.11.2-pyhd8ed1ab_0.tar.bz2#f348d1590550371edfac5ed3c1d44f7e +https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a https://conda.anaconda.org/conda-forge/noarch/wheel-0.37.1-pyhd8ed1ab_0.tar.bz2#1ca02aaf78d9c70d9a81a3bed5752022 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.8.0-pyhd8ed1ab_0.tar.bz2#050b94cf4a8c760656e51d2d44e4632c +https://conda.anaconda.org/conda-forge/noarch/zipp-3.8.1-pyhd8ed1ab_0.tar.bz2#a3508a0c850745b875de88aea4c40cc5 https://conda.anaconda.org/conda-forge/linux-64/antlr-python-runtime-4.7.2-py38h578d9bd_1003.tar.bz2#db8b471d9a764f561a129f94ea215c0a https://conda.anaconda.org/conda-forge/noarch/babel-2.10.3-pyhd8ed1ab_0.tar.bz2#72f1c6d03109d7a70087bc1d029a8eda https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.11.1-pyha770c72_0.tar.bz2#eeec8814bd97b2681f708bb127478d7d -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1011.tar.bz2#0b53c7f7af13244374ef7226bac3f843 -https://conda.anaconda.org/conda-forge/linux-64/certifi-2022.6.15-py38h578d9bd_0.tar.bz2#1f4339b25d1030cfbf4ee0b06690bbce -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.0-py38h3931269_0.tar.bz2#9c491a90ae11d08ca97326a0ed876f3a -https://conda.anaconda.org/conda-forge/linux-64/docutils-0.16-py38h578d9bd_3.tar.bz2#a7866449fb9e5e4008a02df276549d34 -https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.20.3-hd4edc92_0.tar.bz2#94cb81ffdce328f80c87ac9b01244632 +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py38h4a40e3a_0.tar.bz2#a970d201055ec06a75db83bf25447eb2 +https://conda.anaconda.org/conda-forge/linux-64/docutils-0.17.1-py38h578d9bd_2.tar.bz2#affd6b87adb2b0c98da0e3ad274349be +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.20.3-hd4edc92_2.tar.bz2#153cfb02fb8be7dd7cabcbcb58a63053 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-5.2.0-hf9f4e7c_0.tar.bz2#3c5f4fbd64c7254fbe246ca9d87863b6 https://conda.anaconda.org/conda-forge/linux-64/importlib-metadata-4.11.4-py38h578d9bd_0.tar.bz2#037225c33a50e99c5d4f86fac90f6de8 -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.3-py38h43d8883_0.tar.bz2#0719de23a2c5aa0b4db25ee34394e8f3 -https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h18fbbfe_3.tar.bz2#ea9758cf553476ddf75c789fdd239dc5 -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.8.1-mpi_mpich_hcdf9059_2.tar.bz2#7c035ca8a06010c4d9730c428d1a5969 +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py38h43d8883_0.tar.bz2#ae54c61918e1cbd280b8587ed6219258 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.8.1-mpi_mpich_h06c54e2_4.tar.bz2#491803a7356c6a668a84d71f491c4014 https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.1-py38h0a891b7_1.tar.bz2#20d003ad5f584e212c299f64cac46c05 -https://conda.anaconda.org/conda-forge/linux-64/mpi4py-3.1.3-py38h97ac3a3_1.tar.bz2#7a65afac627e81e2d4c1fef44409dbf5 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.23.0-py38h3a7f9d9_0.tar.bz2#bde7c584b811ef5aec0dd2204e502334 +https://conda.anaconda.org/conda-forge/linux-64/mpi4py-3.1.3-py38h97ac3a3_2.tar.bz2#fccce86e5fc8183bf2658ac9bfc535b4 +https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.7.0-pyhd8ed1ab_0.tar.bz2#fbe1182f650c04513046d6894046cd6c +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.23.3-py38h3a7f9d9_0.tar.bz2#83ba913fc1174925d4e862eccb53db59 https://conda.anaconda.org/conda-forge/noarch/packaging-21.3-pyhd8ed1ab_0.tar.bz2#71f1ab2de48613876becddd496371c85 -https://conda.anaconda.org/conda-forge/noarch/partd-1.2.0-pyhd8ed1ab_0.tar.bz2#0c32f563d7f22e3a34c95cad8cc95651 -https://conda.anaconda.org/conda-forge/linux-64/pillow-9.1.1-py38h0ee0e06_1.tar.bz2#cd653a4a951ca80adb96ff6cd3b36883 +https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#af8c82d121e63082926062d61d9abb54 +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.2.0-py38ha3b2c9c_2.tar.bz2#a077cc2bb9d854074b1cf4607252da7a +https://conda.anaconda.org/conda-forge/noarch/pip-22.2.2-pyhd8ed1ab_0.tar.bz2#0b43abe4d3ee93e82742d37def53a836 https://conda.anaconda.org/conda-forge/linux-64/pluggy-1.0.0-py38h578d9bd_3.tar.bz2#6ce4ce3d4490a56eb33b52c179609193 https://conda.anaconda.org/conda-forge/noarch/pockets-0.9.1-py_0.tar.bz2#1b52f0c42e8077e5a33e00fe72269364 -https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.1-py38h0a891b7_0.tar.bz2#e3908bd184030e7f4a3d837959ebf6d7 -https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-14.0-h7f54b18_8.tar.bz2#f9dbcfbb942ec9a3c0249cb71da5c7d1 -https://conda.anaconda.org/conda-forge/linux-64/pysocks-1.7.1-py38h578d9bd_5.tar.bz2#11113c7e50bb81f30762fe8325f305e1 +https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.2-py38h0a891b7_0.tar.bz2#907a39b6d7443f770ed755885694f864 +https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.4.0-py38hd7890fc_1.tar.bz2#f851bb08c85122fd0e1f66d2072ebf0b https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.0.0-py38h0a891b7_1.tar.bz2#69fc64e4f4c13abe0b8df699ddaa1051 https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0-py38h0a891b7_4.tar.bz2#ba24ff01bb38c5cd5be54b45ef685db3 -https://conda.anaconda.org/conda-forge/linux-64/setuptools-62.6.0-py38h578d9bd_0.tar.bz2#4dbffb6d975f26cd71fb27aa20fc4761 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.1-py38h0a891b7_3.tar.bz2#d9e2836a4a46935f84b858462d54a7c3 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py38h0a891b7_0.tar.bz2#acd276486a0067bee3098590f0952a0f +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026 https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-14.0.0-py38h0a891b7_1.tar.bz2#83df0e9e3faffc295f12607438691465 -https://conda.anaconda.org/conda-forge/linux-64/virtualenv-20.14.1-py38h578d9bd_0.tar.bz2#41427ff3fd8d35e5ab1cdcec4d94ea6b +https://conda.anaconda.org/conda-forge/linux-64/virtualenv-20.16.5-py38h578d9bd_0.tar.bz2#b2247bb2492e261c25fabbbb2c7a23b5 https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py38h0a891b7_1004.tar.bz2#9fcaaca218dcfeb8da806d4fd4824aa0 -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.0-py38h71d37f0_1.tar.bz2#16d4a68061bf898fa4126cf213ebb14e -https://conda.anaconda.org/conda-forge/linux-64/cryptography-37.0.2-py38h2b5fc30_0.tar.bz2#bcc387154aae535f8b4f84822621b5f7 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2022.6.1-pyhd8ed1ab_0.tar.bz2#69655c7e78034d4293130f5a5ecf7421 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.33.3-py38h0a891b7_0.tar.bz2#fd11badf5b3f7d738cc983cb2c75946e -https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.20.3-hf6a322e_0.tar.bz2#6ea2ce6265c3207876ef2369b7479f08 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-4.3.0-hf9f4e7c_0.tar.bz2#2a9c6660562d7e3fdeda0f0159e1046d +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.2-py38h26c90d9_0.tar.bz2#df081ec90a13f53fe522c8e876d3f0cf +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.5-py38h43d8883_0.tar.bz2#0650a251fd701bbe5ac44e74cf632af8 +https://conda.anaconda.org/conda-forge/linux-64/cryptography-38.0.1-py38h2b5fc30_0.tar.bz2#692d3e8efeb7f290daafa660ec7f1154 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2022.9.2-pyhd8ed1ab_0.tar.bz2#9993f51a02fc8338837421211b53ab19 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.37.4-py38h0a891b7_0.tar.bz2#401adaccd86738f95a247d2007d925cf +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.20.3-h57caac4_2.tar.bz2#58838c4ca7d1a5948f5cdcbb8170d753 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37 https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.2.0-py38h71d37f0_1007.tar.bz2#c8d3d8f137f8af7b1daca318131223b1 -https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.5.4-mpi_mpich_h1364a43_0.tar.bz2#b6ba4f487ef9fd5d353ff277df06d133 -https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.6.0-pyhd8ed1ab_0.tar.bz2#0941325bf48969e2b3b19d0951740950 -https://conda.anaconda.org/conda-forge/linux-64/pandas-1.4.3-py38h47df419_0.tar.bz2#91c5ac3f8f0e55a946be7b9ce489abfe -https://conda.anaconda.org/conda-forge/noarch/pip-22.1.2-pyhd8ed1ab_0.tar.bz2#d29185c662a424f8bea1103270b85c96 -https://conda.anaconda.org/conda-forge/noarch/pygments-2.12.0-pyhd8ed1ab_0.tar.bz2#cb27e2ded147e5bcc7eafc1c6d343cb3 -https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.3.1-py38he1635e7_1.tar.bz2#3907607e23c3e18202960fc4217baa0a -https://conda.anaconda.org/conda-forge/linux-64/pytest-7.1.2-py38h578d9bd_0.tar.bz2#626d2b8f96c8c3d20198e6bd84d1cfb7 +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.0-mpi_mpich_hd09bd1e_1.tar.bz2#0b69750bb937cab0db14f6bcef6fd787 +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.0-py38h8f669ce_0.tar.bz2#f91da48c62c91659da28bd95559c75ff +https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.11-h382ae3d_0.tar.bz2#509e3f89508398070d3bf7769d9e8b03 +https://conda.anaconda.org/conda-forge/linux-64/pytest-7.1.3-py38h578d9bd_0.tar.bz2#1fdabff56623511910fef3b418ff07a2 https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.2.post0-py38h71d37f0_2.tar.bz2#cdef2f7b0e263e338016da4b77ae4c0b https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.3.0-py38h71d37f0_1.tar.bz2#704f1776af689de568514b0ff9dd0fbe -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.8.1-py38h1ee437e_0.tar.bz2#a0a8bc19d491ec659a534c9a11cf74a0 -https://conda.anaconda.org/conda-forge/linux-64/shapely-1.8.2-py38h928055b_2.tar.bz2#09810d4eb86812673f88a1f396fe1bdf -https://conda.anaconda.org/conda-forge/linux-64/sip-6.5.1-py38h709712a_2.tar.bz2#8ff0cdb63842c29388a34a6af7b5ce6f +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.9.1-py38hea3f02b_0.tar.bz2#b232edb409c6a79e5921b3591c56b716 +https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-7.0.5-pyhd8ed1ab_0.tar.bz2#743074b7a216807886f7e8f6d497cceb +https://conda.anaconda.org/conda-forge/linux-64/shapely-1.8.4-py38h3b45516_0.tar.bz2#d8621497bcc7b369ef9cce25d5a58aeb +https://conda.anaconda.org/conda-forge/linux-64/sip-6.6.2-py38hfa26641_0.tar.bz2#b869c6b54a02c92fac8b10c0d9b32e43 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-napoleon-0.7-py_0.tar.bz2#0bc25ff6f2e34af63ded59692df5f749 https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py38h43d8883_2.tar.bz2#3f6ce81c7d28563fe2af763d9ff43e62 -https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.0.1-py38h6c62de6_2.tar.bz2#350322b046c129e5802b79358a1343f7 -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.2.0-mpi_mpich_h4975321_100.tar.bz2#56f5c650937b1667ad0a557a0dff3bc4 -https://conda.anaconda.org/conda-forge/noarch/identify-2.5.1-pyhd8ed1ab_0.tar.bz2#6f41e3056fcd3061fbc2b49b3309fe0c -https://conda.anaconda.org/conda-forge/noarch/imagehash-4.2.1-pyhd8ed1ab_0.tar.bz2#01cc8698b6e1a124dc4f585516c27643 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.5.2-py38h826bfd8_0.tar.bz2#107af20136422bcabf9f1195f6262117 -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.5.8-nompi_py38h2823cc8_101.tar.bz2#1dfe1cdee4532c72f893955259eb3de9 -https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.7-hbd2fdc8_0.tar.bz2#1cff4bab8ed133d59b7c22fe7bf09263 -https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.0.0-pyhd8ed1ab_0.tar.bz2#1d7e241dfaf5475e893d4b824bb71b44 -https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.9.0-py38hfa26641_1.tar.bz2#40f4eeb2cb0f0ab25d0640f5f7a34de8 +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.1.1-py38h71d37f0_0.tar.bz2#b9e7f6f7509496a4a62906d02dfe3128 +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.2.0-mpi_mpich_h5a1934d_102.tar.bz2#bb8bdfa5e3e9e3f6ec861f05cd2ad441 +https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h90689f9_2.tar.bz2#957a0255ab58aaf394a91725d73ab422 +https://conda.anaconda.org/conda-forge/noarch/identify-2.5.6-pyhd8ed1ab_0.tar.bz2#8c3563a8e310ea9a727f07caa0341ec2 +https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.54.4-h7abd40a_0.tar.bz2#921e53675ed5ea352f022b79abab076a +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.0-py38hb021067_0.tar.bz2#315ee5c0fbee508e739ddfac2bf8f600 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.0-nompi_py38h2a9f00d_102.tar.bz2#533ae5db3e2367d71a7890efb0aa3cdc +https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.0.0-pyhd8ed1ab_1.tar.bz2#2e7e3630919d29c8216bfa2cd643d79e +https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py38hfa26641_0.tar.bz2#6ddbd9abb62e70243702c006b81c63e4 https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_0.tar.bz2#95286e05a617de9ebfe3246cecbfb72f -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.4-ha5833f6_2.tar.bz2#dd3aa6715b9e9efaf842febf18ce4261 -https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.20.2-py38hb3c56ba_6.tar.bz2#9ec1f7a5fe50f16f5103845db2ebd6d8 +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-hc525480_0.tar.bz2#abd0f27f5e84cd0d5ae14d22b08795d7 +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.21.0-py38h606536b_0.tar.bz2#38fc3704565e44fb9fcdfaded03eee76 https://conda.anaconda.org/conda-forge/linux-64/esmpy-8.2.0-mpi_mpich_py38h9147699_101.tar.bz2#5a9de1dec507b6614150a77d1aabf257 -https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h90689f9_2.tar.bz2#957a0255ab58aaf394a91725d73ab422 -https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.54.3-h7abd40a_0.tar.bz2#02b82b1dc4e876242900dcaff109e697 +https://conda.anaconda.org/conda-forge/linux-64/graphviz-6.0.1-h5abf519_0.tar.bz2#123c55da3e9ea8664f73c70e13ef08c2 https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 -https://conda.anaconda.org/conda-forge/linux-64/pre-commit-2.19.0-py38h578d9bd_0.tar.bz2#aa6a241a741c27c9560fd3cebb3f43ce -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.4-py38h7492b6b_1.tar.bz2#7a78a346ffd3297790b81cce35d32083 +https://conda.anaconda.org/conda-forge/linux-64/pre-commit-2.20.0-py38h578d9bd_0.tar.bz2#ac8aa845f1177901eecf1518997ea0a1 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py38h7492b6b_0.tar.bz2#59ece9f652baf50ee6b842db833896ae https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.9-pyhd8ed1ab_0.tar.bz2#0ea179ee251aa7100807c35bc0252693 -https://conda.anaconda.org/conda-forge/linux-64/graphviz-4.0.0-h5abf519_0.tar.bz2#970a4e3632a3c2f27f1860600f2f5fb5 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.5.2-py38h578d9bd_0.tar.bz2#b15039e7f67b5f91c35f9b6d27c2775c -https://conda.anaconda.org/conda-forge/noarch/requests-2.28.0-pyhd8ed1ab_0.tar.bz2#80c4854bb29f39f202819c4d4294d7c5 +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.11-pyhd8ed1ab_0.tar.bz2#0738978569b10669bdef41c671252dd1 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.0-py38h578d9bd_0.tar.bz2#602eb908e81892115c1405c9d99abd56 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 https://conda.anaconda.org/conda-forge/noarch/sphinx-4.5.0-pyh6c4a22f_0.tar.bz2#46b38d88c4270ff9ba78a89c83c66345 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.8.1-pyhd8ed1ab_0.tar.bz2#7d8390ec71225ea9841b276552fdffba https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.0-pyhd8ed1ab_0.tar.bz2#4c969cdd5191306c269490f7ff236d9c -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.10.1-pyhd8ed1ab_0.tar.bz2#4918585fe5e5341740f7e63c61743efb +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.11.1-pyhd8ed1ab_0.tar.bz2#729254314a5d178eefca50acbc2687b8 https://conda.anaconda.org/conda-forge/noarch/sphinx-panels-0.6.0-pyhd8ed1ab_0.tar.bz2#6eec6480601f5d15babf9c3b3987f34a diff --git a/requirements/ci/nox.lock/py39-linux-64.lock b/requirements/ci/nox.lock/py39-linux-64.lock new file mode 100644 index 0000000000..76de50e763 --- /dev/null +++ b/requirements/ci/nox.lock/py39-linux-64.lock @@ -0,0 +1,259 @@ +# Generated by conda-lock. +# platform: linux-64 +# input_hash: 52411479c54ecfa70b3c975c0d86da72b762d12fce2a094c134e69adca9f3f48 +@EXPLICIT +https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.9.24-ha878542_0.tar.bz2#41e4e87062433e283696cf384f952ef6 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-hab24e00_0.tar.bz2#19410c3df09dfb12d1206132a1d357c5 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.36.1-hea4e1c9_2.tar.bz2#bd4f2e711b39af170e7ff15163fe87ee +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.1.0-hdcd56e2_16.tar.bz2#b02605b875559ff99f04351fd5040760 +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.1.0-ha89aaad_16.tar.bz2#6f5ba041a41eb102a1027d9e68731be7 +https://conda.anaconda.org/conda-forge/linux-64/mpi-1.0-mpich.tar.bz2#c1fcff3417b5a22bbc4cf6e8c23648cf +https://conda.anaconda.org/conda-forge/noarch/tzdata-2022d-h191b570_0.tar.bz2#456b5b1d99e7a9654b331bcd82e71042 +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-12.1.0-h69a702a_16.tar.bz2#6bf15e29a20f614b18ae89368260d0a2 +https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.1.0-h8d9b700_16.tar.bz2#f013cf7749536ce43d82afbffdf499ab +https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.1.0-h8d9b700_16.tar.bz2#4f05bc9844f7c101e6e147dab3c88d5c +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.7.2-h166bdaf_0.tar.bz2#4a826cd983be6c8fff07a64b6d2079e7 +https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 +https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.18.1-h7f98852_0.tar.bz2#f26ef8098fab1f719c91eb760d63381a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.4.9-h27087fc_0.tar.bz2#493ac8b2503a949aebe33d99ea0c284f +https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf0379b8_105.tar.bz2#9d3e01547ba04a57372beee01158096f +https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.11.0-h27087fc_0.tar.bz2#a583d0bc9a85c48e8b07a588d1ac8a80 +https://conda.anaconda.org/conda-forge/linux-64/gettext-0.19.8.1-h27087fc_1009.tar.bz2#17f91dc8bb7a259b02be5bfb2cd2395f +https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h36c2ea0_2.tar.bz2#626e68ae9cc5912d6adb79d318cf962d +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 +https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed +https://conda.anaconda.org/conda-forge/linux-64/jpeg-9e-h166bdaf_2.tar.bz2#ee8b844357a0946870901c7c6f418268 +https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 +https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f +https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.0.9-h166bdaf_7.tar.bz2#f82dc1c78bcf73583f2656433ce2933c +https://conda.anaconda.org/conda-forge/linux-64/libdb-6.2.32-h9c3ff4c_0.tar.bz2#3f3258d8f841fbac63b36b75bdac1afd +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.14-h166bdaf_0.tar.bz2#fc84a0446e4e4fb882e78d786cfb9734 +https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h516909a_1.tar.bz2#6f8720dff19e17ce5d48cfe7f3d2f0a3 +https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 +https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-h166bdaf_0.tar.bz2#b62b52da46c39ee2bc3c162ac7f1804d +https://conda.anaconda.org/conda-forge/linux-64/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d +https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.0-h7f98852_0.tar.bz2#39b1328babf85c7c3a61636d9cd50206 +https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.21-pthreads_h78a6416_3.tar.bz2#8c5963a49b6035c40646a763293fbb35 +https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f +https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.6-h9c3ff4c_1008.tar.bz2#16e143a1ed4b4fd169536373957f6fee +https://conda.anaconda.org/conda-forge/linux-64/libudev1-249-h166bdaf_4.tar.bz2#dc075ff6fcb46b3d3c7652e543d5f334 +https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.4-h166bdaf_0.tar.bz2#ac2ccf7323d21f2994e4d1f5da664f37 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.12-h166bdaf_4.tar.bz2#6a2e5b333ba57ce7eec61e90260cbb79 +https://conda.anaconda.org/conda-forge/linux-64/mpich-4.0.2-h846660c_100.tar.bz2#36a36fe04b932d4b327e7e81c5c43696 +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238 +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.32-h9c3ff4c_1.tar.bz2#29ded371806431b0499aaee146abfc3e +https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1q-h166bdaf_0.tar.bz2#07acc367c7fc8b716770cd5b36d31717 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.40.0-h36c2ea0_0.tar.bz2#660e72c82f2e75a6b3fe6a6e75c79f19 +https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 +https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h7f98852_1002.tar.bz2#1e15f6ad85a7d743a2ac68dae6c82b98 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 +https://conda.anaconda.org/conda-forge/linux-64/xxhash-0.8.0-h7f98852_3.tar.bz2#52402c791f35e414e704b7a113f99605 +https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 +https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae +https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h9772cbc_4.tar.bz2#dd3e1941dd06f64cb88647d2f7ff8aaa +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b +https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_7.tar.bz2#37a460703214d0d1b421e2a47eb5e6d0 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_7.tar.bz2#785a9296ea478eb78c47593c4da6550f +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.65-ha37c62d_0.tar.bz2#2c1c43f5442731b58e070bcee45a86ec +https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 +https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.10-h9b69904_4.tar.bz2#390026683aef81db27ff1b8570ca1336 +https://conda.anaconda.org/conda-forge/linux-64/libflac-1.3.4-h27087fc_0.tar.bz2#620e52e160fd09eb8772dedd46bb19ef +https://conda.anaconda.org/conda-forge/linux-64/libllvm14-14.0.6-he0ac6c6_0.tar.bz2#f5759f0c80708fbf9c4836c0cb46d0fe +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-hdcd2b5c_1.tar.bz2#6fe9e31c2b8d0b022626ccac13e6ca3c +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.38-h753d276_0.tar.bz2#575078de1d3a3114b3ce131bd1508d0c +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.39.4-h753d276_0.tar.bz2#978924c298fc2215f129e8171bbea688 +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-haa6b8db_3.tar.bz2#89acee135f0809a18a1f4537390aa2dd +https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1004.tar.bz2#b3653fdc58d03face9724f602218a904 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.2-h4c7fe37_1.tar.bz2#d543c0192b13a1d0236367d3fb1e022c +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.9.2-hc869a4a_1.tar.bz2#7a268cf1386d271e576e35ae82149ef2 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.30-haf5c9bc_1.tar.bz2#62b588b2a313ac3d9c2ead767baa3b5d +https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.37-hc3806b6_1.tar.bz2#dfd26f27a9d5de96cec1d007b9aeb964 +https://conda.anaconda.org/conda-forge/linux-64/portaudio-19.6.0-h8e90077_6.tar.bz2#2935b98de57e1f261ef8253655a8eb80 +https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-hc3e0081_0.tar.bz2#d4c341e0379c31e9e781d4f204726867 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.12-h166bdaf_4.tar.bz2#995cc7813221edbc25a3db15357599a0 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74 +https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_7.tar.bz2#1699c1211d56a23c66047524cd76796e +https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-hca18f0e_0.tar.bz2#4e54cbfc47b8c74c2ecc1e7730d8edce +https://conda.anaconda.org/conda-forge/linux-64/krb5-1.19.3-h3790be6_0.tar.bz2#7d862b05445123144bec92cb1acc8ef8 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_openblas.tar.bz2#20bae26d0a1db73f758fc3754cab4719 +https://conda.anaconda.org/conda-forge/linux-64/libclang13-14.0.6-default_h3a83d3e_0.tar.bz2#cdbd49e0ab5c5a6c522acb8271977d4c +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.0-h7a41b64_0.tar.bz2#fe768553d0fe619bb9704e3c79c0ee2e +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad +https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.0.31-h9c3ff4c_1.tar.bz2#fc4b6d93da04731db7601f2a1b1dc96a +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.4.0-h55922b4_4.tar.bz2#901791f0ec7cddc8714e76e273013a91 +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.0.3-he3ba5ed_0.tar.bz2#f9dbabc7e01c459ed7a1d1d64b206e9b +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.30-h28c427c_1.tar.bz2#0bd292db365c83624316efc2764d9f16 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.39.4-h4ff8645_0.tar.bz2#643c271de2dd23ecbd107284426cebc2 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-h166bdaf_0.tar.bz2#384e7fcb3cd162ba3e4aed4b687df566 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h166bdaf_0.tar.bz2#637054603bb7594302e3bf83f0a99879 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-h166bdaf_0.tar.bz2#732e22f1741bccea861f5668cf7342a7 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h166bdaf_0.tar.bz2#0a8e20a8aef954390b9481a527421a8c +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.7.2-h7f98852_0.tar.bz2#12a61e640b8894504326aadafccbb790 +https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.36.0-h3371d22_4.tar.bz2#661e1ed5d92552785d9f8c781ce68685 +https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_7.tar.bz2#3889dec08a472eb0f423e5609c76bde1 +https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.0-hc2a2eb6_1.tar.bz2#139ace7da04f011abbd531cb2a9840ee +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.8-hff1cb4f_1.tar.bz2#a61c6312192e7c9de71548a6706a21e6 +https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.74.0-h6239696_0.tar.bz2#d2db078274532eeab50a06d65172a3c4 +https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h64030ff_2.tar.bz2#112eb9b5b93f0c02e59aea4fd1967363 +https://conda.anaconda.org/conda-forge/linux-64/jack-1.9.18-h8c3723f_1003.tar.bz2#9cb956b6605cfc7d8ee1b15e96bd88ba +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.12-hddcbb42_0.tar.bz2#797117394a4aa588de6d741b06fad80f +https://conda.anaconda.org/conda-forge/linux-64/libclang-14.0.6-default_h2e3cab8_0.tar.bz2#eb70548da697e50cefa7ba939d57d001 +https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h3e49a29_2.tar.bz2#3b88f1d0fe2580594d58d7e44d664617 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.85.0-h7bff187_0.tar.bz2#054fb5981fdbe031caeb612b71d85f84 +https://conda.anaconda.org/conda-forge/linux-64/libpq-14.5-hd77ab85_0.tar.bz2#d3126b425a04ed2360da1e651cef1b2d +https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.2.4-h522a892_0.tar.bz2#802e43f480122a85ae6a34c1909f8f98 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.78-h2350873_0.tar.bz2#ab3df39f96742e6f1a9878b09274c1dc +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-h7d73246_1.tar.bz2#a11b4df9271a8d7917686725aa04c8f2 +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.13-h9a8a25e_0_cpython.tar.bz2#69bc307cc4d7396c5fccb26bbcc9c379 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h166bdaf_0.tar.bz2#c9b568bd804cb2903c6be6f5f68182e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h7f98852_1.tar.bz2#536cc5db4d0a3ba0630541aec064b5e4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.10-h7f98852_1003.tar.bz2#f59c1242cc1dd93e72c2ee2b360979eb +https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.12-py_0.tar.bz2#2489a97287f90176ecdc3ca982b4b0a0 +https://conda.anaconda.org/conda-forge/noarch/attrs-22.1.0-pyh71513ae_1.tar.bz2#6d3ccbc56256204925bfa8378722792f +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-ha61ee94_1014.tar.bz2#d1a88f3ed5b52e1024b80d4bcd26a7a0 +https://conda.anaconda.org/conda-forge/noarch/certifi-2022.9.24-pyhd8ed1ab_0.tar.bz2#f66309b099374af91369e67e84af397d +https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2#ebb5f5f7dc4f1a3780ef7ea7738db08c +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.0-pyhd8ed1ab_0.tar.bz2#a6cf47b09786423200d7982d1faa19eb +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.5-pyhd8ed1ab_0.tar.bz2#c267da48ce208905d7d976d49dfd9433 +https://conda.anaconda.org/conda-forge/linux-64/curl-7.85.0-h7bff187_0.tar.bz2#a8ac96d6b09b8ed5b0ac6563901e2195 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.11.0-pyhd8ed1ab_0.tar.bz2#a50559fad0affdbb33729a68669ca1cb +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.5-pyhd8ed1ab_0.tar.bz2#f15c3912378a07726093cc94d1e13251 +https://conda.anaconda.org/conda-forge/noarch/execnet-1.9.0-pyhd8ed1ab_0.tar.bz2#0e521f7a5e60d508b121d38b04874fb2 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.8.0-pyhd8ed1ab_0.tar.bz2#10f0218dbd493ab2e5dc6759ddea4526 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2022.8.2-pyhd8ed1ab_0.tar.bz2#140dc6615896e7d4be1059a63370be93 +https://conda.anaconda.org/conda-forge/linux-64/glib-2.74.0-h6239696_0.tar.bz2#60e6c8c867cdac0fc5f52fbbdfd7a057 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.12.2-mpi_mpich_h08b82f9_0.tar.bz2#de601caacbaa828d845f758e07e3b85e +https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed +https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-1.1.1-pyh9f0ad1d_0.tar.bz2#39161f81cc5e5ca45b8226fbb06c6905 +https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_0.tar.bz2#18ee9c07cf945a33f92caf1ee3d23ad9 +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h18fbbfe_3.tar.bz2#ea9758cf553476ddf75c789fdd239dc5 +https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 +https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.2-pyhd8ed1ab_1.tar.bz2#2fb3f88922e7aec26ba652fcdfe13950 +https://conda.anaconda.org/conda-forge/noarch/ply-3.11-py_1.tar.bz2#7205635cd71531943440fbfe3b6b5727 +https://conda.anaconda.org/conda-forge/linux-64/proj-9.1.0-h93bde94_0.tar.bz2#255c7204dda39747c3ba380d28b026d7 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-14.0-h0868958_9.tar.bz2#5bca71f0cf9b86ec58dd9d6216a3ffaf +https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054 +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc +https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.1-pyhd8ed1ab_0.tar.bz2#92a889dc236a5197612bc85bee6d7174 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-2_cp39.tar.bz2#39adde4247484de2bb4000122fdcf665 +https://conda.anaconda.org/conda-forge/noarch/pytz-2022.4-pyhd8ed1ab_0.tar.bz2#fc0dcaf9761d042fb8ac9128ce03fddb +https://conda.anaconda.org/conda-forge/noarch/setuptools-65.4.1-pyhd8ed1ab_0.tar.bz2#d61d9f25af23c24002e659b854c6f5ae +https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e +https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.3.2.post1-pyhd8ed1ab_0.tar.bz2#146f4541d643d48fc8a75cacf69f03ae +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.2-py_0.tar.bz2#20b2eaeaeea4ef9a9a0d99770620fd09 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.2-py_0.tar.bz2#68e01cac9d38d0e717cd5c87bc3d2cc9 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.0-pyhd8ed1ab_0.tar.bz2#77dad82eb9c8c1525ff7953e0756d708 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-py_0.tar.bz2#67cd9d9c0382d37479b4d306c369a2d4 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.3-py_0.tar.bz2#d01180388e6d1838c3e1ad029590aa7a +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.5-pyhd8ed1ab_2.tar.bz2#9ff55a0901cf952f05c654394de76bf7 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 +https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a +https://conda.anaconda.org/conda-forge/noarch/wheel-0.37.1-pyhd8ed1ab_0.tar.bz2#1ca02aaf78d9c70d9a81a3bed5752022 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.8.1-pyhd8ed1ab_0.tar.bz2#a3508a0c850745b875de88aea4c40cc5 +https://conda.anaconda.org/conda-forge/linux-64/antlr-python-runtime-4.7.2-py39hf3d152e_1003.tar.bz2#5e8330e806e50bd6137ebd125f4bc1bb +https://conda.anaconda.org/conda-forge/noarch/babel-2.10.3-pyhd8ed1ab_0.tar.bz2#72f1c6d03109d7a70087bc1d029a8eda +https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.11.1-pyha770c72_0.tar.bz2#eeec8814bd97b2681f708bb127478d7d +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py39he91dace_0.tar.bz2#61e961a94c8fd535e4496b17e7452dfe +https://conda.anaconda.org/conda-forge/linux-64/docutils-0.17.1-py39hf3d152e_2.tar.bz2#fea5dea40592ea943aa56f4935308ee4 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.20.3-hd4edc92_2.tar.bz2#153cfb02fb8be7dd7cabcbcb58a63053 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-5.2.0-hf9f4e7c_0.tar.bz2#3c5f4fbd64c7254fbe246ca9d87863b6 +https://conda.anaconda.org/conda-forge/linux-64/importlib-metadata-4.11.4-py39hf3d152e_0.tar.bz2#4c2a0eabf0b8980b2c755646a6f750eb +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py39hf939315_0.tar.bz2#e8d1310648c189d6d11a2e13f73da1fe +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.8.1-mpi_mpich_h06c54e2_4.tar.bz2#491803a7356c6a668a84d71f491c4014 +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.1-py39hb9d737c_1.tar.bz2#7cda413e43b252044a270c2477031c5c +https://conda.anaconda.org/conda-forge/linux-64/mpi4py-3.1.3-py39h32b9844_2.tar.bz2#b809706525f081610469169b671b2600 +https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.7.0-pyhd8ed1ab_0.tar.bz2#fbe1182f650c04513046d6894046cd6c +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.23.3-py39hba7629e_0.tar.bz2#320e25179733ec4a2ecffcebc8abbc80 +https://conda.anaconda.org/conda-forge/noarch/packaging-21.3-pyhd8ed1ab_0.tar.bz2#71f1ab2de48613876becddd496371c85 +https://conda.anaconda.org/conda-forge/noarch/partd-1.3.0-pyhd8ed1ab_0.tar.bz2#af8c82d121e63082926062d61d9abb54 +https://conda.anaconda.org/conda-forge/linux-64/pillow-9.2.0-py39hd5dbb17_2.tar.bz2#3b74a959f6a8008f5901de60b3572c09 +https://conda.anaconda.org/conda-forge/noarch/pip-22.2.2-pyhd8ed1ab_0.tar.bz2#0b43abe4d3ee93e82742d37def53a836 +https://conda.anaconda.org/conda-forge/linux-64/pluggy-1.0.0-py39hf3d152e_3.tar.bz2#c375c89340e563053f3656c7f134d265 +https://conda.anaconda.org/conda-forge/noarch/pockets-0.9.1-py_0.tar.bz2#1b52f0c42e8077e5a33e00fe72269364 +https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.2-py39hb9d737c_0.tar.bz2#1e7ffe59e21862559e06b981817e5058 +https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.4.0-py39h2c22827_1.tar.bz2#a1ca42c2a746601d42f27bbcb7f6acfc +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 +https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.0.0-py39hb9d737c_1.tar.bz2#9f71f72dad4fd7b9da7bcc2ba64505bc +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0-py39hb9d737c_4.tar.bz2#dcc47a3b751508507183d17e569805e5 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.2-py39hb9d737c_0.tar.bz2#a3c57360af28c0d9956622af99a521cd +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026 +https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-14.0.0-py39hb9d737c_1.tar.bz2#ef84376736d1e8a814ccb06d1d814e6f +https://conda.anaconda.org/conda-forge/linux-64/virtualenv-20.16.5-py39hf3d152e_0.tar.bz2#165e71a44187ac22e2e1669fd3ca2392 +https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py39hb9d737c_1004.tar.bz2#05a99367d885ec9990f25e74128a8a08 +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.2-py39h2ae25f5_0.tar.bz2#4b108127973b66b36edd6449aa6afde0 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.0.5-py39hf939315_0.tar.bz2#c9ff0dfb602033b1f1aaf323b58e04fa +https://conda.anaconda.org/conda-forge/linux-64/cryptography-38.0.1-py39hd97740a_0.tar.bz2#db3436b5db460fa721859db55694d8ff +https://conda.anaconda.org/conda-forge/noarch/dask-core-2022.9.2-pyhd8ed1ab_0.tar.bz2#9993f51a02fc8338837421211b53ab19 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.37.4-py39hb9d737c_0.tar.bz2#10ba86e931afab1164deae6b954b5f0d +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.20.3-h57caac4_2.tar.bz2#58838c4ca7d1a5948f5cdcbb8170d753 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37 +https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.2.0-py39hd257fcd_1007.tar.bz2#e7527bcf8da0dad996aaefd046c17480 +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.0-mpi_mpich_hd09bd1e_1.tar.bz2#0b69750bb937cab0db14f6bcef6fd787 +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.0-py39h4661b88_0.tar.bz2#ae807099430cd22b09b869b0536425b7 +https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.11-h382ae3d_0.tar.bz2#509e3f89508398070d3bf7769d9e8b03 +https://conda.anaconda.org/conda-forge/linux-64/pytest-7.1.3-py39hf3d152e_0.tar.bz2#b807481ba94ec32bc742f2fe775d0bff +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.2.post0-py39hd257fcd_2.tar.bz2#644be766007a1dc7590c3277647f81a1 +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.3.0-py39hd257fcd_1.tar.bz2#c4b698994b2d8d2e659ae02202e6abe4 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.9.1-py39h8ba3f38_0.tar.bz2#beed054d4979cd70690aea2b257a6d55 +https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-7.0.5-pyhd8ed1ab_0.tar.bz2#743074b7a216807886f7e8f6d497cceb +https://conda.anaconda.org/conda-forge/linux-64/shapely-1.8.4-py39h68ae834_0.tar.bz2#e871ee7de5bfa95095256e95e30be2a6 +https://conda.anaconda.org/conda-forge/linux-64/sip-6.6.2-py39h5a03fae_0.tar.bz2#e37704c6be07b8b14ffc1ce912802ce0 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-napoleon-0.7-py_0.tar.bz2#0bc25ff6f2e34af63ded59692df5f749 +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py39hf939315_2.tar.bz2#5a3bb9dc2fe08a4a6f2b61548a1431d6 +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.1.1-py39hd257fcd_0.tar.bz2#e0f1f1d3013be31359d3ac635b288469 +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.2.0-mpi_mpich_h5a1934d_102.tar.bz2#bb8bdfa5e3e9e3f6ec861f05cd2ad441 +https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h90689f9_2.tar.bz2#957a0255ab58aaf394a91725d73ab422 +https://conda.anaconda.org/conda-forge/noarch/identify-2.5.6-pyhd8ed1ab_0.tar.bz2#8c3563a8e310ea9a727f07caa0341ec2 +https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.54.4-h7abd40a_0.tar.bz2#921e53675ed5ea352f022b79abab076a +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.6.0-py39hf9fd14e_0.tar.bz2#bdc55b4069ab9d2f938525c4cf90def0 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.0-nompi_py39h6ced12a_102.tar.bz2#b92600d0fef7f12f426935d87d6413e6 +https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.0.0-pyhd8ed1ab_1.tar.bz2#2e7e3630919d29c8216bfa2cd643d79e +https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.11.0-py39h5a03fae_0.tar.bz2#1fd9112714d50ee5be3dbf4fd23964dc +https://conda.anaconda.org/conda-forge/noarch/pytest-forked-1.4.0-pyhd8ed1ab_0.tar.bz2#95286e05a617de9ebfe3246cecbfb72f +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.6-hc525480_0.tar.bz2#abd0f27f5e84cd0d5ae14d22b08795d7 +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.21.0-py39hf5d525c_0.tar.bz2#b99ba7383d1c9dd18445dfff08439c48 +https://conda.anaconda.org/conda-forge/linux-64/esmpy-8.2.0-mpi_mpich_py39h8bb458d_101.tar.bz2#347f324dd99dfb0b1479a466213b55bf +https://conda.anaconda.org/conda-forge/linux-64/graphviz-6.0.1-h5abf519_0.tar.bz2#123c55da3e9ea8664f73c70e13ef08c2 +https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 +https://conda.anaconda.org/conda-forge/linux-64/pre-commit-2.20.0-py39hf3d152e_0.tar.bz2#314c8cb1538706f62ec36cf64370f2b2 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.7-py39h18e9c17_0.tar.bz2#5ed8f83afff3b64fa91f7a6af8d7ff04 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-2.5.0-pyhd8ed1ab_0.tar.bz2#1fdd1f3baccf0deb647385c677a1a48e +https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.11-pyhd8ed1ab_0.tar.bz2#0738978569b10669bdef41c671252dd1 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.6.0-py39hf3d152e_0.tar.bz2#93f29e4d6f852de18384412b0e0d03b5 +https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0 +https://conda.anaconda.org/conda-forge/noarch/sphinx-4.5.0-pyh6c4a22f_0.tar.bz2#46b38d88c4270ff9ba78a89c83c66345 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.8.1-pyhd8ed1ab_0.tar.bz2#7d8390ec71225ea9841b276552fdffba +https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.0-pyhd8ed1ab_0.tar.bz2#4c969cdd5191306c269490f7ff236d9c +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.11.1-pyhd8ed1ab_0.tar.bz2#729254314a5d178eefca50acbc2687b8 +https://conda.anaconda.org/conda-forge/noarch/sphinx-panels-0.6.0-pyhd8ed1ab_0.tar.bz2#6eec6480601f5d15babf9c3b3987f34a diff --git a/requirements/ci/py310.yml b/requirements/ci/py310.yml new file mode 100644 index 0000000000..ae0090881d --- /dev/null +++ b/requirements/ci/py310.yml @@ -0,0 +1,51 @@ +name: iris-dev + +channels: + - conda-forge + +dependencies: + - python =3.10 + +# Setup dependencies. + - setuptools >=64 + - setuptools-scm >=7 + +# Core dependencies. + - cartopy >=0.21 + - cf-units >=3.1 + - cftime >=1.5 + - dask-core >=2.26 + - matplotlib >=3.5 + - netcdf4 !=1.6.1 + - numpy >=1.19 + - python-xxhash + - pyproj + - scipy + - shapely !=1.8.3 + +# Optional dependencies. + - esmpy >=7.0 + - graphviz + - iris-sample-data >=2.4.0 + - mo_pack + - nc-time-axis >=1.4 + - pandas + - pip + - python-stratify + +# Test dependencies. + - filelock + - imagehash >=4.0 + - pre-commit + - psutil + - pytest + - pytest-xdist + - requests + +# Documentation dependencies. + - sphinx + - sphinxcontrib-napoleon + - sphinx-copybutton + - sphinx-gallery >=0.11.0 + - sphinx-panels + - pydata-sphinx-theme = 0.8.1 diff --git a/requirements/ci/py38.yml b/requirements/ci/py38.yml index 6f782a831d..c0ed574c92 100644 --- a/requirements/ci/py38.yml +++ b/requirements/ci/py38.yml @@ -7,19 +7,21 @@ dependencies: - python =3.8 # Setup dependencies. - - setuptools >=40.8.0 + - setuptools >=64 + - setuptools-scm >=7 # Core dependencies. - - cartopy >=0.20 - - cf-units >=3 + - cartopy >=0.21 + - cf-units >=3.1 - cftime >=1.5 - - dask-core >=2 - - matplotlib - - netcdf4 + - dask-core >=2.26 + - matplotlib >=3.5 + - netcdf4 !=1.6.1 - numpy >=1.19 - python-xxhash - pyproj - scipy + - shapely !=1.8.3 # Optional dependencies. - esmpy >=7.0 @@ -44,6 +46,6 @@ dependencies: - sphinx - sphinxcontrib-napoleon - sphinx-copybutton - - sphinx-gallery + - sphinx-gallery >=0.11.0 - sphinx-panels - pydata-sphinx-theme = 0.8.1 diff --git a/requirements/ci/py39.yml b/requirements/ci/py39.yml new file mode 100644 index 0000000000..c79b0ede1d --- /dev/null +++ b/requirements/ci/py39.yml @@ -0,0 +1,51 @@ +name: iris-dev + +channels: + - conda-forge + +dependencies: + - python =3.9 + +# Setup dependencies. + - setuptools >=64 + - setuptools-scm >=7 + +# Core dependencies. + - cartopy >=0.21 + - cf-units >=3.1 + - cftime >=1.5 + - dask-core >=2.26 + - matplotlib >=3.5 + - netcdf4 !=1.6.1 + - numpy >=1.19 + - python-xxhash + - pyproj + - scipy + - shapely !=1.8.3 + +# Optional dependencies. + - esmpy >=7.0 + - graphviz + - iris-sample-data >=2.4.0 + - mo_pack + - nc-time-axis >=1.4 + - pandas + - pip + - python-stratify + +# Test dependencies. + - filelock + - imagehash >=4.0 + - pre-commit + - psutil + - pytest + - pytest-xdist + - requests + +# Documentation dependencies. + - sphinx + - sphinxcontrib-napoleon + - sphinx-copybutton + - sphinx-gallery >=0.11.0 + - sphinx-panels + - pydata-sphinx-theme = 0.8.1 diff --git a/setup.cfg b/setup.cfg index 233b9241d6..ca35a8eb4e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] author = SciTools Developers -author_email = scitools-iris-dev@googlegroups.com +author_email = scitools.pub@gmail.com classifiers = Development Status :: 5 - Production/Stable Intended Audience :: Science/Research @@ -12,6 +12,8 @@ classifiers = Programming Language :: Python Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering Topic :: Scientific/Engineering :: Atmospheric Science @@ -30,7 +32,7 @@ keywords = ugrid visualisation license = LGPL-3.0-or-later -license_file = COPYING.LESSER +license_files = COPYING.LESSER long_description = file: README.md long_description_content_type = text/markdown name = scitools-iris @@ -45,16 +47,17 @@ version = attr: iris.__version__ [options] include_package_data = True install_requires = - cartopy>=0.20 - cf-units>=3 + cartopy>=0.21 + cf-units>=3.1 cftime>=1.5.0 - dask[array]>=2 - matplotlib - netcdf4 + dask[array]>=2.26 + matplotlib>=3.5 + netcdf4!=1.6.1 numpy>=1.19 scipy + shapely!=1.8.3 xxhash -packages = find: +packages = find_namespace: package_dir = =lib python_requires = @@ -68,14 +71,13 @@ where = lib docs = sphinx sphinx-copybutton - sphinx-gallery + sphinx-gallery>=0.11.0 sphinx_rtd_theme sphinxcontrib-napoleon sphinx-panels test = filelock imagehash>=4.0 - pillow<7 pre-commit requests pytest diff --git a/setup.py b/setup.py index f48f3fe25a..061b35c262 100644 --- a/setup.py +++ b/setup.py @@ -1,42 +1,16 @@ -from contextlib import contextmanager import os -from shutil import copyfile import sys from setuptools import Command, setup from setuptools.command.build_py import build_py -from setuptools.command.develop import develop as develop_cmd - - -@contextmanager -def temporary_path(directory): - """ - Context manager that adds and subsequently removes the given directory - to sys.path - - """ - sys.path.insert(0, directory) - try: - yield - finally: - del sys.path[0] - - -# Add full path so Python doesn't load any __init__.py in the intervening -# directories, thereby saving setup.py from additional dependencies. -with temporary_path("lib/iris/tests/runner"): - from _runner import TestRunner # noqa: - - -class SetupTestRunner(TestRunner, Command): - pass +from setuptools.command.develop import develop class BaseCommand(Command): - """A valid no-op command for setuptools & distutils.""" + """A minimal no-op setuptools command.""" - description = "A no-op command." - user_options = [] + description: str = "A no-op command." + user_options: list = [] def initialize_options(self): pass @@ -48,75 +22,65 @@ def run(self): pass -class CleanSource(BaseCommand): - description = "clean orphaned pyc/pyo files from the source directory" - - def run(self): - for root_path, dir_names, file_names in os.walk("lib"): - for file_name in file_names: - if file_name.endswith("pyc") or file_name.endswith("pyo"): - compiled_path = os.path.join(root_path, file_name) - source_path = compiled_path[:-1] - if not os.path.exists(source_path): - print("Cleaning", compiled_path) - os.remove(compiled_path) - - -def copy_copyright(cmd, directory): - # Copy the COPYRIGHT information into the package root - iris_build_dir = os.path.join(directory, "iris") - for fname in ["COPYING", "COPYING.LESSER"]: - copyfile(fname, os.path.join(iris_build_dir, fname)) - +def custom_command(cmd, help=""): + """ + Factory function to generate a custom command that adds additional + behaviour to build the CF standard names module. -def build_std_names(cmd, directory): - # Call out to tools/generate_std_names.py to build std_names module. + """ - script_path = os.path.join("tools", "generate_std_names.py") - xml_path = os.path.join("etc", "cf-standard-name-table.xml") - module_path = os.path.join(directory, "iris", "std_names.py") - args = (sys.executable, script_path, xml_path, module_path) - cmd.spawn(args) + class CustomCommand(cmd): + description = help or cmd.description + def _build_std_names(self, directory): + # Call out to tools/generate_std_names.py to build std_names module. -def custom_cmd(command_to_override, functions, help_doc=""): - """ - Allows command specialisation to include calls to the given functions. + script_path = os.path.join("tools", "generate_std_names.py") + xml_path = os.path.join("etc", "cf-standard-name-table.xml") + module_path = os.path.join(directory, "iris", "std_names.py") + args = (sys.executable, script_path, xml_path, module_path) + self.spawn(args) - """ + def finalize_options(self): + # Execute the parent "cmd" class method. + cmd.finalize_options(self) - class ExtendedCommand(command_to_override): - description = help_doc or command_to_override.description + if ( + not hasattr(self, "editable_mode") + or self.editable_mode is None + ): + # Default to editable i.e., applicable to "std_names" and + # and "develop" commands. + self.editable_mode = True def run(self): - # Run the original command first to make sure all the target - # directories are in place. - command_to_override.run(self) + # Execute the parent "cmd" class method. + cmd.run(self) + + # Determine the target root directory + if self.editable_mode: + # Pick the source dir instead (currently in the sub-dir "lib"). + target = "lib" + msg = "in-place" + else: + # Not editable - must be building. + target = self.build_lib + msg = "as-build" - # build_lib is defined if we are building the package. Otherwise - # we want to to the work in-place. - dest = getattr(self, "build_lib", None) - if dest is None: - print(" [Running in-place]") - # Pick the source dir instead (currently in the sub-dir "lib") - dest = "lib" + print(f"\n[Running {msg}]") - for func in functions: - func(self, dest) + # Build the CF standard names. + self._build_std_names(target) - return ExtendedCommand + return CustomCommand custom_commands = { - "test": SetupTestRunner, - "develop": custom_cmd(develop_cmd, [build_std_names]), - "build_py": custom_cmd(build_py, [build_std_names, copy_copyright]), - "std_names": custom_cmd( - BaseCommand, - [build_std_names], - help_doc="generate CF standard name module", + "develop": custom_command(develop), + "build_py": custom_command(build_py), + "std_names": custom_command( + BaseCommand, help="generate CF standard names" ), - "clean_source": CleanSource, } diff --git a/tools/update_lockfiles.py b/tools/update_lockfiles.py index f05210be87..dc898784ae 100755 --- a/tools/update_lockfiles.py +++ b/tools/update_lockfiles.py @@ -17,6 +17,15 @@ from pathlib import Path import subprocess import sys +from warnings import warn + + +message = ( + "Iris' large requirements may require Mamba to successfully solve. If you " + "don't want to install Mamba, consider using the workflow_dispatch on " + "Iris' GitHub action." +) +warn(message) try: @@ -29,9 +38,9 @@ "Iris Lockfile Generator", ) -parser.add_argument('files', nargs='+', +parser.add_argument('files', nargs='+', help="List of environment.yml files to lock") -parser.add_argument('--output-dir', '-o', default='.', +parser.add_argument('--output-dir', '-o', default='.', help="Directory to save output lock files") args = parser.parse_args() @@ -43,7 +52,7 @@ ftype = fname.split('.')[-1] if ftype.lower() in ('yaml', 'yml'): fname = '.'.join(fname.split('.')[:-1]) - + # conda-lock --filename-template expects a string with a "...{platform}..." # placeholder in it, so we have to build the .lock filname without # using .format