diff --git a/.github/workflows/citation_file_validator.yml b/.github/workflows/citation_file_validator.yml index 43a4d5c444..e957d40f86 100644 --- a/.github/workflows/citation_file_validator.yml +++ b/.github/workflows/citation_file_validator.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out a copy of the repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check whether the citation metadata from CITATION.cff is valid uses: citation-file-format/cffconvert-github-action@2.0.0 diff --git a/.github/workflows/create-condalock-file.yml b/.github/workflows/create-condalock-file.yml index 9aefad7498..a88f919c17 100644 --- a/.github/workflows/create-condalock-file.yml +++ b/.github/workflows/create-condalock-file.yml @@ -20,10 +20,10 @@ jobs: name: Create conda lock file for latest Python runs-on: 'ubuntu-latest' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true activate-environment: esmvaltool-fromlock @@ -35,7 +35,7 @@ jobs: run: | conda update -n base -c conda-forge conda conda --version - # setup-miniconda@v2 installs an old conda and mamba + # setup-miniconda@v3 installs an old conda and mamba # forcing a modern mamba updates both mamba and conda conda install -c conda-forge "mamba>=1.4.8" conda config --show-sources diff --git a/.github/workflows/install-from-conda.yml b/.github/workflows/install-from-conda.yml index 55897e7fe4..b08390040d 100644 --- a/.github/workflows/install-from-conda.yml +++ b/.github/workflows/install-from-conda.yml @@ -20,10 +20,10 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] name: Linux Python ${{ matrix.python-version }} steps: - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python-version }} miniforge-version: "latest" @@ -44,7 +44,7 @@ jobs: esmvaltool version 2>&1 | tee conda_install_linux_artifacts_python_${{ matrix.python-version }}/version.txt - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Conda_Install_Linux_python_${{ matrix.python-version }} path: conda_install_linux_artifacts_python_${{ matrix.python-version }} @@ -56,12 +56,12 @@ jobs: # runs-on: "macos-latest" # strategy: # matrix: -# python-version: ["3.9", "3.10", "3.11"] +# python-version: ["3.10", "3.11"] # fail-fast: false # name: OSX Python ${{ matrix.python-version }} # steps: # - uses: actions/checkout@v2 -# - uses: conda-incubator/setup-miniconda@v2 +# - uses: conda-incubator/setup-miniconda@v3 # with: # python-version: ${{ matrix.python-version }} # miniconda-version: "latest" @@ -82,7 +82,7 @@ jobs: # - run: esmvaltool version 2>&1 | tee conda_install_osx_artifacts_python_${{ matrix.python-version }}/version.txt # - name: Upload artifacts # if: ${{ always() }} # upload artifacts even if fail -# uses: actions/upload-artifact@v2 +# uses: actions/upload-artifact@v4 # with: # name: Conda_Install_OSX_python_${{ matrix.python-version }} # path: conda_install_osx_artifacts_python_${{ matrix.python-version }} diff --git a/.github/workflows/install-from-condalock-file.yml b/.github/workflows/install-from-condalock-file.yml index a209c06f32..a03e297a80 100644 --- a/.github/workflows/install-from-condalock-file.yml +++ b/.github/workflows/install-from-condalock-file.yml @@ -30,14 +30,14 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] fail-fast: false name: Linux Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: activate-environment: esmvaltool-fromlock python-version: ${{ matrix.python-version }} @@ -57,7 +57,7 @@ jobs: - run: pytest -n 2 -m "not installation" - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Source_Install_Linux_python_${{ matrix.python-version }} path: source_install_linux_artifacts_python_${{ matrix.python-version }} diff --git a/.github/workflows/install-from-source.yml b/.github/workflows/install-from-source.yml index 2e24b8f049..3d7456337b 100644 --- a/.github/workflows/install-from-source.yml +++ b/.github/workflows/install-from-source.yml @@ -19,14 +19,14 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] fail-fast: false name: Linux Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: activate-environment: esmvaltool environment-file: environment.yml @@ -47,7 +47,7 @@ jobs: esmvaltool version 2>&1 | tee source_install_linux_artifacts_python_${{ matrix.python-version }}/version.txt - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Source_Install_Linux_python_${{ matrix.python-version }} path: source_install_linux_artifacts_python_${{ matrix.python-version }} @@ -59,12 +59,12 @@ jobs: # runs-on: "macos-latest" # strategy: # matrix: -# python-version: ["3.9", "3.10", "3.11"] +# python-version: ["3.10", "3.11"] # fail-fast: false # name: OSX Python ${{ matrix.python-version }} # steps: # - uses: actions/checkout@v2 -# - uses: conda-incubator/setup-miniconda@v2 +# - uses: conda-incubator/setup-miniconda@v3 # with: # activate-environment: esmvaltool # environment-file: environment.yml @@ -79,7 +79,7 @@ jobs: # - run: esmvaltool version 2>&1 | tee source_install_osx_artifacts_python_${{ matrix.python-version }}/version.txt # - name: Upload artifacts # if: ${{ always() }} # upload artifacts even if fail -# uses: actions/upload-artifact@v2 +# uses: actions/upload-artifact@v4 # with: # name: Source_Install_OSX_python_${{ matrix.python-version }} # path: source_install_osx_artifacts_python_${{ matrix.python-version }} diff --git a/.github/workflows/pypi-build-and-deploy.yml b/.github/workflows/pypi-build-and-deploy.yml index f1ed214e12..4dff1e4d69 100644 --- a/.github/workflows/pypi-build-and-deploy.yml +++ b/.github/workflows/pypi-build-and-deploy.yml @@ -14,7 +14,7 @@ jobs: name: Build and publish ESMValTool on PyPi runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python 3.11 diff --git a/.github/workflows/run-tests-monitor.yml b/.github/workflows/run-tests-monitor.yml index 1efe54a66a..168d8940e5 100644 --- a/.github/workflows/run-tests-monitor.yml +++ b/.github/workflows/run-tests-monitor.yml @@ -23,13 +23,13 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] name: Linux Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: activate-environment: esmvaltool environment-file: environment.yml @@ -42,6 +42,8 @@ jobs: run: | mamba --version 2>&1 | tee test_linux_artifacts_python_${{ matrix.python-version }}/conda_version.txt python -V 2>&1 | tee test_linux_artifacts_python_${{ matrix.python-version }}/python_version.txt + - name: Inspect environment + run: conda list - name: Install pytest-monitor run: pip install pytest-monitor - name: Install ESMValTool @@ -56,7 +58,7 @@ jobs: run: python tests/parse_pymon.py - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Test_Linux_python_${{ matrix.python-version }} path: test_linux_artifacts_python_${{ matrix.python-version }} @@ -65,15 +67,17 @@ jobs: runs-on: "macos-latest" strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] + architecture: ["x64"] # need to force Intel, arm64 builds have issues fail-fast: false name: OSX Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: + architecture: ${{ matrix.architecture }} activate-environment: esmvaltool environment-file: environment_osx.yml python-version: ${{ matrix.python-version }} @@ -87,6 +91,10 @@ jobs: run: | mamba --version 2>&1 | tee test_osx_artifacts_python_${{ matrix.python-version }}/conda_version.txt python -V 2>&1 | tee test_osx_artifacts_python_${{ matrix.python-version }}/python_version.txt + - name: Inspect environment + run: conda list + - name: Install git + run: mamba install -c conda-forge git - name: Install pytest-monitor run: pip install pytest-monitor - name: Install ESMValTool @@ -101,7 +109,7 @@ jobs: run: python tests/parse_pymon.py - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Test_OSX_python_${{ matrix.python-version }} path: test_osx_artifacts_python_${{ matrix.python-version }} diff --git a/.github/workflows/test-development.yml b/.github/workflows/test-development.yml index cab6489548..2dba36577d 100644 --- a/.github/workflows/test-development.yml +++ b/.github/workflows/test-development.yml @@ -12,7 +12,6 @@ on: push: branches: - main - - fix_recipe_filler_bkwds_incompatibility schedule: - cron: '0 0 * * *' @@ -27,13 +26,13 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] name: Linux Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: activate-environment: esmvaltool environment-file: environment.yml @@ -62,7 +61,7 @@ jobs: run: pytest -n 2 -m "not installation" 2>&1 | tee develop_test_linux_artifacts_python_${{ matrix.python-version }}/test_report.txt - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Develop_Test_Linux_python_${{ matrix.python-version }} path: develop_test_linux_artifacts_python_${{ matrix.python-version }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9eec648279..f3822e5449 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,6 @@ on: push: branches: - main - - fix_recipe_filler_bkwds_incompatibility schedule: - cron: '0 0 * * *' @@ -21,13 +20,13 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] name: Linux Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: activate-environment: esmvaltool environment-file: environment.yml @@ -42,6 +41,8 @@ jobs: python -V 2>&1 | tee test_linux_artifacts_python_${{ matrix.python-version }}/python_version.txt # this is how to export variables to the GITHUB var environment echo "pver0=$(python -V)" >> $GITHUB_ENV + - name: Inspect environment + run: conda list - name: Install ESMValTool run: pip install -e .[develop] 2>&1 | tee test_linux_artifacts_python_${{ matrix.python-version }}/install.txt - name: Install Julia dependencies @@ -54,13 +55,15 @@ jobs: echo "Python minor version changed after Julia install" python -V exit 1 + - name: Inspect environment + run: conda list - name: Run flake8 run: flake8 - name: Run tests run: pytest -n 2 -m "not installation" 2>&1 | tee test_linux_artifacts_python_${{ matrix.python-version }}/test_report.txt - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Test_Linux_python_${{ matrix.python-version }} path: test_linux_artifacts_python_${{ matrix.python-version }} @@ -69,15 +72,17 @@ jobs: runs-on: "macos-latest" strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11"] + architecture: ["x64"] # need to force Intel, arm64 builds have issues fail-fast: false name: OSX Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: + architecture: ${{ matrix.architecture }} activate-environment: esmvaltool environment-file: environment_osx.yml python-version: ${{ matrix.python-version }} @@ -91,15 +96,25 @@ jobs: run: | mamba --version 2>&1 | tee test_osx_artifacts_python_${{ matrix.python-version }}/conda_version.txt python -V 2>&1 | tee test_osx_artifacts_python_${{ matrix.python-version }}/python_version.txt + - name: Inspect environment + run: conda list + - name: Determine if git + run: | + which git + git --version + - name: Install git + run: mamba install -c conda-forge git - name: Install ESMValTool run: pip install -e .[develop] 2>&1 | tee test_osx_artifacts_python_${{ matrix.python-version }}/install.txt + - name: Inspect environment + run: conda list - name: Run flake8 run: flake8 - name: Run tests run: pytest -n 2 -m "not installation" 2>&1 | tee test_osx_artifacts_python_${{ matrix.python-version }}/test_report.txt - name: Upload artifacts if: ${{ always() }} # upload artifacts even if fail - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Test_OSX_python_${{ matrix.python-version }} path: test_osx_artifacts_python_${{ matrix.python-version }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f13cea8c72..f3ac440f05 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ exclude: | ^esmvaltool/diag_scripts/cvdp/ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-ast @@ -19,7 +19,7 @@ repos: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - repo: https://github.com/adrienverge/yamllint - rev: 'v1.31.0' + rev: 'v1.35.1' hooks: - id: yamllint - repo: local # nclcodestyle is installed alongside ESMValTool @@ -30,16 +30,16 @@ repos: language: system files: '\.(ncl|NCL)$' - repo: https://github.com/lorenzwalthert/precommit/ # Checks for R - rev: 'v0.3.2.9007' + rev: 'v0.4.2' hooks: - id: style-files # styler - id: lintr - repo: https://github.com/codespell-project/codespell - rev: 'v2.2.4' + rev: 'v2.3.0' hooks: - id: codespell - repo: https://github.com/PyCQA/isort - rev: '5.12.0' + rev: '5.13.2' hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-yapf @@ -49,10 +49,10 @@ repos: additional_dependencies: - 'toml' - repo: https://github.com/myint/docformatter - rev: 'v1.6.5' + rev: 'v1.7.5' hooks: - id: docformatter - repo: https://github.com/pycqa/flake8 - rev: '6.0.0' + rev: '5.0.4' hooks: - id: flake8 diff --git a/.zenodo.json b/.zenodo.json index c6a731981f..c087c4ae21 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -171,6 +171,11 @@ "name": "Hagemann, Stefan", "orcid": "0000-0001-5444-2945" }, + { + "affiliation": "University of Canterbury, New Zealand", + "name": "Hardacre, Catherine", + "orcid": "0000-0001-9093-4656" + }, { "affiliation": "ISAC-CNR, Italy", "name": "von Hardenberg, Jost", @@ -380,15 +385,20 @@ "affiliation": "DLR, Germany", "name": "Bonnet, Pauline", "orcid": "0000-0003-3780-0784" + }, + { + "affiliation": "MetOffice, UK", + "name": "Munday, Gregory", + "orcid": "0000-0003-4750-9923" } ], "description": "ESMValTool: A community diagnostic and performance metrics tool for routine evaluation of Earth system models in CMIP.", "license": { "id": "Apache-2.0" }, - "publication_date": "2023-07-06", + "publication_date": "2024-07-04", "title": "ESMValTool", - "version": "v2.9.0", + "version": "v2.11.0", "communities": [ { "identifier": "is-enes3" diff --git a/CITATION.cff b/CITATION.cff index 5c253e3bb5..22eb3c500e 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -175,6 +175,11 @@ authors: family-names: Hagemann given-names: Stefan orcid: "https://orcid.org/0000-0001-5444-2945" + - + affiliation: "University of Canterbury, New Zealand" + family-names: Hardacre + given-names: Catherine + orcid: "https://orcid.org/0000-0001-9093-4656" - affiliation: "ISAC-CNR, Italy" name-particle: von @@ -386,13 +391,18 @@ authors: family-names: Bonnet given-names: Pauline orcid: "https://orcid.org/0000-0003-3780-0784" + - + affiliation: "MetOffice, UK" + family-names: Munday + given-names: Gregory + orcid: "https://orcid.org/0000-0003-4750-9923" cff-version: 1.2.0 -date-released: 2023-12-20 +date-released: 2024-07-04 doi: "10.5281/zenodo.3401363" license: "Apache-2.0" message: "If you use this software, please cite it using these metadata." repository-code: "https://github.com/ESMValGroup/ESMValTool/" title: ESMValTool -version: "v2.10.0" +version: "v2.11.0" ... diff --git a/README.md b/README.md index 4fbe8aa84e..b196f7fbb8 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,7 @@ [![Chat on Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#ESMValGroup_Lobby:gitter.im) [![CircleCI](https://circleci.com/gh/ESMValGroup/ESMValTool/tree/main.svg?style=svg)](https://circleci.com/gh/ESMValGroup/ESMValTool/tree/main) [![Test in Full Development Mode](https://github.com/ESMValGroup/ESMValTool/actions/workflows/test-development.yml/badge.svg)](https://github.com/ESMValGroup/ESMValTool/actions/workflows/test-development.yml) -[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/79bf6932c2e844eea15d0fb1ed7e415c)](https://www.codacy.com/gh/ESMValGroup/ESMValTool?utm_source=github.com&utm_medium=referral&utm_content=ESMValGroup/ESMValTool&utm_campaign=Badge_Coverage) -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/79bf6932c2e844eea15d0fb1ed7e415c)](https://www.codacy.com/gh/ESMValGroup/ESMValTool?utm_source=github.com&utm_medium=referral&utm_content=ESMValGroup/ESMValTool&utm_campaign=Badge_Grade) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/79bf6932c2e844eea15d0fb1ed7e415c)](https://app.codacy.com/gh/ESMValGroup/ESMValTool/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Docker Build Status](https://img.shields.io/docker/cloud/build/esmvalgroup/esmvaltool.svg)](https://hub.docker.com/r/esmvalgroup/esmvaltool/) [![Anaconda-Server Badge](https://img.shields.io/conda/vn/conda-forge/ESMValTool?color=blue&label=conda-forge&logo=conda-forge&logoColor=white)](https://anaconda.org/conda-forge/esmvaltool) ![stand with Ukraine](https://badgen.net/badge/stand%20with/UKRAINE/?color=0057B8&labelColor=FFD700) diff --git a/conda-linux-64.lock b/conda-linux-64.lock index 0f803ec0ca..af2625f1b7 100644 --- a/conda-linux-64.lock +++ b/conda-linux-64.lock @@ -1,661 +1,689 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: e484ece0f2a2f8e9f3009df8b9de1be258c70868b9df17114bb859f15f903ccf +# input_hash: 6e839dcc54104cc7c8d7d0b0165df84d0b927a0baf129e4169a57ac283fe3f98 @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/_py-xgboost-mutex-2.0-gpu_0.tar.bz2#7702188077361f43a4d61e64c694f850 https://conda.anaconda.org/conda-forge/noarch/_r-mutex-1.0.1-anacondar_1.tar.bz2#19f9db5f4f1b7f5ef5f6d67207f25f38 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda#2f4327a1cbe7f022401b236e915a5fef +https://conda.anaconda.org/conda-forge/noarch/_sysroot_linux-64_curr_repodata_hack-3-h69a702a_16.conda#1c005af0c6ff22814b7c52ee448d4bea +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 https://conda.anaconda.org/conda-forge/noarch/cuda-version-11.8-h70ddcb2_3.conda#670f0e1593b8c1d84f57ad5fe5256799 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-h77eed37_1.conda#6185f640c43843e5ad6fd1c5372c3f80 -https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-2.6.32-he073ed8_17.conda#d731b543793afc0433c4fd593e693fce -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 -https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-13.2.0-ha9c7c90_105.conda#3bc29a967fee57e193ce51f51c598bca -https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.2.0-ha9c7c90_105.conda#66383205c2e1bdf013df52fa9e3e6763 -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-h7e041cc_5.conda#f6f6600d18a4047b54f803cf708b868a -https://conda.anaconda.org/conda-forge/linux-64/pandoc-3.1.12.3-ha770c72_0.conda#cdea66892b19a454f939487318b6c517 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_2.conda#cbbe59391138ea5ad3658c76912e147f +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda#b80f2f396ca2c28b8c14c437a4ed1e74 +https://conda.anaconda.org/conda-forge/linux-64/pandoc-3.4-ha770c72_0.conda#61c94057aaa5ae6145137ce1fddb2c04 https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda#d8d7293c5b37f39b2ac32940621c6592 -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-4_cp311.conda#d786502c97404c94d7d58d258a445a65 -https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda#161081fc7cec0bfda0d86d7cb595f8d8 +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-5_cp311.conda#139a8d40c8a2f430df31048949e450de +https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda#8bfdead4e0fff0383ae4c9c50d0531bd https://conda.anaconda.org/conda-forge/linux-64/xorg-imake-1.0.7-0.tar.bz2#23acfc5a339a6a34cc2241f64e4111be https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 -https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h807b86a_5.conda#d211c42b9ce49aee3734fdc828731689 -https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.12-he073ed8_17.conda#595db67e32b276298ff3d94d07d47fbf +https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-3.10.0-h4a8ded7_16.conda#ff7f38675b226cfb855aebfc32a13e31 +https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.1.0-h5d3d1c9_101.conda#713834677de996ac1bc1b0b305ba46ba +https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_1.conda#23c255b008c4f2ae008f81edcabaca89 +https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.1.0-h5d3d1c9_101.conda#e007246a554aaf42f73fbfd4be8db3e4 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d -https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.40-hf600244_0.conda#33084421a8c0af6aef1b439707f7662a 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-13.2.0-h807b86a_5.conda#d4ff227c46917d3b4565302a2bbb276b -https://conda.anaconda.org/conda-forge/linux-64/aom-3.5.0-h27087fc_0.tar.bz2#a08150fd2298460cd1fcccf626305642 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.8.23-hd590300_0.conda#cc4f06f7eedb1523f3b83fd0fb3942ff -https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda#69b8b6202a07720f448be700e300ccf4 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.27.0-hd590300_0.conda#f6afff0e9ee08d2f1b897881a4f38cdb -https://conda.anaconda.org/conda-forge/linux-64/charls-2.4.2-h59595ed_0.conda#4336bd67920dd504cd8c6761d6a99645 +https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h4a8ded7_16.conda#223fe8a3ff6d5e78484a9d58eb34d055 +https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.40-ha1999f0_7.conda#3f840c7ed70a96b5ebde8044b2f36f32 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.1.0-h77fa898_1.conda#002ef4463dd1e2b44a94a4ace468f5d2 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h69a702a_1.conda#1efc0ad219877a73ef977af7dbb51f17 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.1.0-hc5f4f2c_1.conda#10a0cef64b784d6ab6da50ebca4e984d +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.1.0-hc0a3c3a_1.conda#9dbb9699ea467983ba8a4ba89b08b066 +https://conda.anaconda.org/conda-forge/linux-64/make-4.4.1-hb9d3cd8_1.conda#cd0fbfe1f70b630a94e40007dae3328d +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/tzcode-2024b-hb9d3cd8_0.conda#db124840386e1f842f93372897d1b857 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.9.15-hd590300_0.conda#ad8955a300fd09e97e76c38638ac7157 +https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.33.1-heb4867d_0.conda#0d3c60291342c0c025db231353376dfb https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 -https://conda.anaconda.org/conda-forge/linux-64/freexl-1.0.6-h166bdaf_1.tar.bz2#897e772a157faf3330d72dd291486f62 +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a 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.2-hcb278e6_0.conda#3b8e364995e3575e57960d29c1e5ab14 -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 -https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-he1b5a44_1004.tar.bz2#cddaf2c63ea4a5901cf09524c490ecdc -https://conda.anaconda.org/conda-forge/linux-64/ghostscript-10.03.0-h59595ed_0.conda#cb3c1aca441b476684b240ce43f767fd -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h0b41bf4_3.conda#96f3b11872ef6fad973eac856cd2624f -https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-h59595ed_1.conda#e358c7c5f6824c272b5034b3816438a7 -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-72.1-hcb278e6_0.conda#7c8d20d847bb45f56bd941578fcfa146 +https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-he02047a_3.conda#fcd2016d1d299f654f81021e27496818 +https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6 https://conda.anaconda.org/conda-forge/linux-64/jbig-2.1-h7f98852_2003.tar.bz2#1aa0cee79792fa97b7ff4545110b60bf -https://conda.anaconda.org/conda-forge/linux-64/json-c-0.16-hc379101_0.tar.bz2#0e2bca6857cb73acec30387fef7c3142 +https://conda.anaconda.org/conda-forge/linux-64/json-c-0.17-h1220068_1.conda#f8f0f0c4338bad5c34a4e9e11460481d https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda#5aeabe88534ea4169d4c49998f293d6c 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/libabseil-20230125.3-cxx17_h59595ed_0.conda#d1db1b8be7c3a8983dcbbbfe4f0765de -https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.2-h59595ed_1.conda#127b0be54c1c90760d7fe02ea7a56426 -https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.0.9-h166bdaf_9.conda#61641e239f96eae2b8492dc7e755828c -https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2#c965a5aa0d5c1c37ffc62dff36e28400 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.18-h0b41bf4_0.conda#6aa9c9de5542ecb07fdda9ca626252d8 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.19-hd590300_0.conda#1635570038840ee3f9c71d22aa5b8b6d https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda#e7ba12deb7020dd080c6c70e7b6f6a3d +https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda#a1cfcc585f0c42bf8d5546bb1dfb668d 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/libgfortran5-13.2.0-ha4646dd_5.conda#7a6bd7a12a4bd359e2afe6c0fa1acace +https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-he02047a_3.conda#efab66b82ec976930b96d62a976de8e7 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.1.0-h69a702a_1.conda#591e631bc1ae62c64f2ab4f66178c097 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-2.1.5.1-hd590300_1.conda#323e90742f0f48fc22bea908735f55e6 +https://conda.anaconda.org/conda-forge/linux-64/libnl-3.10.0-h4bc722e_0.conda#6221e705f55cf0533f0777ae54ad86c6 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 -https://conda.anaconda.org/conda-forge/linux-64/libnuma-2.0.18-hd590300_0.conda#8feeecae73aeef0a2985af46b5a2c1df https://conda.anaconda.org/conda-forge/linux-64/libopenlibm4-0.8.1-hd590300_1.conda#e6af610e01d04927a5060c95ce4e0875 -https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.2.0-h7e041cc_5.conda#3f686300a92604d1bdff9a29dd4a6639 -https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.18-h36c2ea0_1.tar.bz2#c3788462a6fbddafdb413a9f9053e58d -https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-h27087fc_0.conda#f204c8ba400ec475452737094fb81d52 -https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.6.2-h9c3ff4c_0.tar.bz2#a730b2badd586580c5752cc73842e068 +https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.1.0-hcba0ae0_1.conda#b56e6664bb9a57a29fd91df582223409 +https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda#a587892d3c13b6621a6091be690dbca2 +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.1.0-h4852527_1.conda#bd2598399a70bb86d8218e95548d735e +https://conda.anaconda.org/conda-forge/linux-64/libtool-2.4.7-he02047a_1.conda#2ca22c3c01cf286675450d3c455c717e +https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.8.0-h166bdaf_0.tar.bz2#ede4266dc02e875fe1ea77b25dd43747 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.1-hd590300_0.conda#82bf6f63eb15ef719b556b63feec3a77 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.2-hd590300_1.conda#049b7df8bae5e184d1de42cdf64855f8 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda#f36c115f1ee199da648e0597ec2047ad -https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 -https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h516909a_1000.tar.bz2#bb14fcb13341b81d5eb386423b9d2bac -https://conda.anaconda.org/conda-forge/linux-64/make-4.3-hd18ef5c_1.tar.bz2#4049ebfd3190b580dffe76daed26155a -https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.5.1-h59595ed_0.conda#a7b444a6e008b804b35521895e3440e2 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda#57d7dc60e9325e3de37ff8dffd18e814 +https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hd590300_1001.conda#ec7398d21e2651e0dcb0044d03b9a339 https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-h59595ed_1007.conda#40ccb8318df2500f83bd868dd8fcd201 -https://conda.anaconda.org/conda-forge/linux-64/nccl-2.20.5.1-h6103f9b_0.conda#bedb0b33c5e3e6fbd4dce4f6f07fea72 -https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda#97da8860a0da5413c7c98a3b3838a645 -https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.5-hd590300_0.conda#a6057a9b8f0bba4ab6ee3347a9b26b94 -https://conda.anaconda.org/conda-forge/linux-64/p7zip-16.02-h9c3ff4c_1001.tar.bz2#941066943c0cac69d5aa52189451aa5f -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 -https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h36c2ea0_1008.tar.bz2#fbef41ff6a4c8140c30057466a1cdd47 +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe +https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda#1bee70681f504ea424fb07cdb090c001 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/rdma-core-28.9-h59595ed_1.conda#aeffb7c06b5f65e55e6c637408dc4100 -https://conda.anaconda.org/conda-forge/linux-64/re2-2023.03.02-h8c504da_0.conda#206f8fa808748f6e90599c3368a1114e +https://conda.anaconda.org/conda-forge/linux-64/rav1e-0.6.6-he8a937b_2.conda#77d9955b4abddb811cb8ab1aa7d743e4 +https://conda.anaconda.org/conda-forge/linux-64/s2n-1.4.12-h06160fa_0.conda#bf1899cfd6dea061a220fa7e96a1f4bd https://conda.anaconda.org/conda-forge/linux-64/sed-4.8-he412f7d_0.tar.bz2#7362f0042e95681f5d371c46c83ebd08 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 -https://conda.anaconda.org/conda-forge/linux-64/tzcode-2024a-h3f72095_0.conda#32146e34aaec3745a08b6f49af3f41b0 -https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.7-h59595ed_1.conda#c5edf07141147789784f89d5b4e4a9ad https://conda.anaconda.org/conda-forge/linux-64/xorg-inputproto-2.3.2-h7f98852_1002.tar.bz2#bcd1b3396ec6960cbc1d2855a9e60b2b 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.1.1-hd590300_0.conda#b462a33c0be1421532f28bfe8f4a7514 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hd590300_0.conda#2c80dc38fface310c9bd81b17037fee5 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-makedepend-1.0.9-h59595ed_0.conda#71c756cfcc6649ed7614eb07712bfce0 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-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 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.2-hd590300_0.conda#f08fb5c89edfc4aadee1c81d4cfb1fa1 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/zfp-1.0.1-h59595ed_0.conda#fd486bffbf0d6841cf1456a8f2e3a995 https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.0.7-h0b41bf4_0.conda#49e8329110001f04923fe7e864990b0c -https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.6.0-h93469e0_0.conda#580a52a05f5be28ce00764149017c6d4 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.2.17-h862ab75_1.conda#0013fcee7acb3cfc801c5929824feb3c -https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.1.11-h862ab75_1.conda#6fbc9bd49434eb36d3a59c5020f4af95 -https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.1.16-h862ab75_1.conda#f883d61afbc95c50f7b3f62546da4235 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda#53fb86322bdb89496d7579fe3f02fd61 -https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-13.2.0-h338b0a0_5.conda#a6be13181cb66a78544b1d5f7bac97d0 -https://conda.anaconda.org/conda-forge/linux-64/glog-0.6.0-h6f12383_0.tar.bz2#b31f3565cb84435407594e548a2fb7b2 +https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda#346722a0be40f6edc53f12640d301338 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.6.11-heb1d5e4_0.conda#98784bb35b316e2ba8698f4a75326e9a +https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.2.18-hce8ee76_3.conda#b19224a5179ecb512c4aac9f8a6d57a7 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.1.15-hce8ee76_3.conda#0c4f0205a1ae4ca6c89af922ec54271c +https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.1.18-hce8ee76_3.conda#9aa734a17b9b0b793c7696435fe7789a +https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 +https://conda.anaconda.org/conda-forge/linux-64/charls-2.4.2-h59595ed_0.conda#4336bd67920dd504cd8c6761d6a99645 +https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-14.1.0-h3c94d91_1.conda#4e32ec060bf4a30c6fff81a920dc0ec9 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.0-h59595ed_0.conda#3fdf79ef322c8379ae83be491d805369 +https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-he1b5a44_1004.tar.bz2#cddaf2c63ea4a5901cf09524c490ecdc +https://conda.anaconda.org/conda-forge/linux-64/ghostscript-10.03.1-h59595ed_0.conda#be973b4541601270b77232bc46249a3a +https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda#c94a5994ef49749880a8139cf9afcbe1 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c +https://conda.anaconda.org/conda-forge/linux-64/gtest-1.14.0-h434a139_2.conda#89971b339bb4dfbf3759f1f2528d81b1 https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h501b40f_6.conda#c3e9338e15d90106f467377017352b97 -https://conda.anaconda.org/conda-forge/linux-64/libavif-0.11.1-h8182462_2.conda#41c399ed4c439e37b844c24ab5621b5a -https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_9.conda#081aa22f4581c08e4372b0b6c2f8478e -https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_9.conda#1f0a03af852a9659ed2bf08f2f1704fd +https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda#cc47e1facc155f91abd89b11e48e72ff +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/libabseil-20240116.2-cxx17_he02047a_1.conda#c48fc56ec03229f294176923c3265c05 +https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa +https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-he8f35ee_3.conda#4fab9799da9571266d05ca5503330655 +https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2#c965a5aa0d5c1c37ffc62dff36e28400 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.12-hf998b51_1.conda#a1cfcc585f0c42bf8d5546bb1dfb668d -https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_5.conda#e73e9cfd1191783392131e6238bdb3e9 -https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-h01aab08_1016.conda#4d0907546d556ef7f14b1dcfa0e217ce +https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-he02047a_3.conda#9aba7960731e6b4547b3a52f812ed801 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.1.0-h69a702a_1.conda#16cec94c5992d7f42ae3f9fa8b25df8d https://conda.anaconda.org/conda-forge/linux-64/libllvm14-14.0.6-hcd5def8_4.conda#73301c133ded2bf71906aa2104edae8b -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_0.conda#9b13d5ee90fc9f09d54fd403247342b4 +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda#700ac6ea6d53d5510591c4344d5c989a https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda#009981dd9cfcaa4dbfa25ffaed86bcae -https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.23.3-hd1fb520_1.conda#78c10e8637a6f8d377f9989327d0267d -https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-h0d5128d_13.conda#e1d6139ff0500977a760567a4bec1ce9 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.2-h2797004_0.conda#866983a220e27a80cb75e85cb30466a1 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.1-hadc24fc_0.conda#36f79405ab16bf271edb55b213836dac https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe -https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 +https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.19.0-hb90f79a_1.conda#8cdb7d41faa0260875ba92414c487e2d +https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.6.2-h9c3ff4c_0.tar.bz2#a730b2badd586580c5752cc73842e068 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.15-h0b41bf4_0.conda#33277193f5b92bad9fdd230eb700929c -https://conda.anaconda.org/conda-forge/linux-64/libxgboost-2.0.3-cuda118_hd3b444d_1.conda#5a03d2c691df2f689f919b5a3693af0b -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.11.5-h0d562d8_0.conda#558ab736404275d7df61c473c1af35aa https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b -https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h9458935_0.conda#4c28f3210b30250037a4a627eeee9e0f +https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 +https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.5.1-h59595ed_0.conda#a7b444a6e008b804b35521895e3440e2 +https://conda.anaconda.org/conda-forge/linux-64/nccl-2.22.3.1-hee583db_1.conda#f6ec6886214a80beace66f0b9fdf7e4b +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 https://conda.anaconda.org/conda-forge/linux-64/openlibm-0.8.1-hd590300_1.conda#6eba22eb06d69e53d0ca01eef42bc675 +https://conda.anaconda.org/conda-forge/linux-64/p7zip-16.02-h9c3ff4c_1001.tar.bz2#941066943c0cac69d5aa52189451aa5f https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda#f2cfec9406850991f4e3d960cc9e3321 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 +https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 +https://conda.anaconda.org/conda-forge/linux-64/rdma-core-53.0-he02047a_0.conda#d60e9a23682287a041a4428927ea7aa5 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 -https://conda.anaconda.org/conda-forge/linux-64/s2n-1.3.46-h06160fa_0.conda#413d96a0b655c8f8aacc36473a2dbb04 +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-hdb0a2a9_1.conda#78b8b85bdf1f42b8a2b3cb577d8742d1 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.2.1-h5888daf_0.conda#0d9c441855be3d8dfdb2e800fe755059 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/ucx-1.14.1-h64cca9d_5.conda#39aa3b356d10d7e5add0c540945a0944 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda#d71d3a66528853c0a1ac2c02d79a0284 https://conda.anaconda.org/conda-forge/linux-64/xorg-fixesproto-5.0-h7f98852_1002.tar.bz2#65ad6e1eb4aed2b0611855aff05e04f6 https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-h7391055_0.conda#93ee23f12bc2e684548181256edd2cf6 -https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h59595ed_1.conda#7fc9d3288d2420bb3637647621018000 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-hd590300_5.conda#68c34ec6149623be41a1933ab996a209 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda#04b88013080254850d6c01ed54810589 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.13.28-h3870b5a_0.conda#b775667301ab249f94ad2bea91fc4223 +https://conda.anaconda.org/conda-forge/linux-64/xorg-makedepend-1.0.9-h59595ed_0.conda#71c756cfcc6649ed7614eb07712bfce0 +https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-hac33072_1.conda#df96b7266e49529d82de467b23977452 +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-h4ab18f5_1.conda#9653f1bf3766164d0e65fa723cabbc54 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.14.7-hbfbeace_6.conda#d6382461de9a91a2665e964f92d8da0a https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.5-h0f2a231_0.conda#009521b7ed97cca25f8f997f9e745976 -https://conda.anaconda.org/conda-forge/linux-64/boost-cpp-1.78.0-h6582d0a_3.conda#d3c3c7698d0b878aab1b86db95407c8e -https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h166bdaf_9.conda#d47dee1856d9cb955b8076eeff304a5b +https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f https://conda.anaconda.org/conda-forge/linux-64/bwidget-1.9.14-ha770c72_1.tar.bz2#5746d6202ba2abad4a4707f2a2462795 -https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.13.2-hb4ffafa_0.conda#976aaf1afd331ed7346d649da5c5c1ee -https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hc118613_108.conda#6fa90698000b05dfe8ce6515794fe71a +https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.12.0-hb4ffafa_0.conda#1a9b16afb84d734a1bb2d196c308d477 +https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_hf1063bd_110.conda#ee3e687b78b778db7b304e5b00a4dca6 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb -https://conda.anaconda.org/conda-forge/linux-64/gfortran_impl_linux-64-13.2.0-h76e1118_5.conda#4685e2c6393800ce0d88d3876ceb7416 -https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-13.2.0-h338b0a0_5.conda#88d0ccab114eb0e837725bd48cdddae5 +https://conda.anaconda.org/conda-forge/linux-64/gfortran_impl_linux-64-14.1.0-he4a1faa_1.conda#0ae35a9298e2475dc877da9adaa8e490 +https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hbabe93e_0.conda#ff862eebdfeb2fd048ae9dc92510baca +https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.1.0-h8d00ecb_1.conda#6ae4069622b29253444c3326613a8e1a https://conda.anaconda.org/conda-forge/linux-64/hdfeos2-2.20-hebf79cf_1003.conda#23bb57b64a629bc3b33379beece7f0d7 -https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78 -https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.6.2-h039dbb9_1.conda#29cf970521d30d113f3425b84cb250f6 -https://conda.anaconda.org/conda-forge/linux-64/libgit2-1.5.1-h1f77430_0.conda#16802fd0c80290248ea79a570bd83b95 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.78.1-hebfc3b9_0.conda#ddd09e8904fde46b85f41896621803e6 -https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.56.2-h3905398_1.conda#0b01e6ff8002994bd4ddbffcdbec7856 -https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.3-default_h554bfaf_1009.conda#f36ddc11ca46958197a45effdd286e45 -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.26-pthreads_h413a1c8_0.conda#760ae35415f5ba8b15d09df5afe8b23a -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-ilp64-0.3.26-pthreads_h384dd9e_0.conda#4510b0d48d80db41d0614726a5683070 -https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.18.1-h8fd135c_2.conda#bbf65f7688512872f063810623b755dc -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.5.1-h8b53f26_1.conda#5b09e13d732dda1a2bc9adc711164f4d -https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.37-h0054252_1.conda#f27960e8873abb5476e96ef33bdbdccd -https://conda.anaconda.org/conda-forge/linux-64/nss-3.98-h1d7d5a4_0.conda#54b56c2fdf973656b748e0378900ec13 -https://conda.anaconda.org/conda-forge/linux-64/orc-1.9.0-h385abfd_1.conda#2cd5aac7ef1b4c6ac51bf521251a89b3 -https://conda.anaconda.org/conda-forge/linux-64/python-3.11.6-hab00c5b_0_cpython.conda#b0dfbe2fcbfdb097d321bfd50ecddab1 -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.45.2-h2c6b66d_0.conda#1423efca06ed343c1da0fc429bae0779 -https://conda.anaconda.org/conda-forge/linux-64/tktable-2.10-h0c5db8f_5.conda#9464044754ea25557a9c93f0327d90a6 -https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.7-h8ee46fc_0.conda#49e482d882669206653b095f5206c05b +https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 +https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-he8f35ee_3.conda#1091193789bb830127ed067a9e01ac57 +https://conda.anaconda.org/conda-forge/linux-64/libavif16-1.1.1-h104a339_1.conda#9ef052c2eee74c792833ac2e820e481e +https://conda.anaconda.org/conda-forge/linux-64/libgit2-1.7.1-hca3a8ce_0.conda#6af97ac284ffaf76d8f63cc1f9d64f7a +https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-hf539b9f_1021.conda#e8c7620cc49de0c6a2349b6dd6e39beb +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.27-pthreads_hac2b453_1.conda#ae05ece66d3924ac3d48b4aa3fa96cec +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-ilp64-0.3.28-pthreads_h3e26593_0.conda#2bd7dc48907a3b6bf766ed87867f3459 +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2023.09.01-h5a48ba9_2.conda#41c69fba59d495e8cf5ffda48a607e35 +https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-hb58d41b_14.conda#264f9a3a4ea52c8f4d3e8ae1213a3335 +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h29866fb_1.conda#4e9afd30f4ccb2f98645e51005f82236 +https://conda.anaconda.org/conda-forge/linux-64/libxgboost-2.1.1-cuda118_h09a87be_2.conda#1ef0261ebd8ecdab6ca149ef568ba0bf +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-h4c95cb1_3.conda#0ac9aff6010a7751961c8e4b863a40e7 +https://conda.anaconda.org/conda-forge/linux-64/minizip-4.0.7-h401b404_0.conda#4474532a312b2245c5c77f1176989b46 +https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h90cbb55_3.conda#2eeb50cab6652538eee8fc0bc3340c81 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.104-hd34e28f_0.conda#0664e59f6937a660eba9f3d2f9123fa8 +https://conda.anaconda.org/conda-forge/linux-64/python-3.11.10-hc5c86c4_0_cpython.conda#43a02ff0a2dafe8a8a1b6a9eacdbd2cc +https://conda.anaconda.org/conda-forge/linux-64/s2geometry-0.10.0-h8413349_4.conda#d19f88cf8812836e6a4a2a7902ed0e77 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.46.1-h9eae976_0.conda#b2b3e737da0ae347e16ef1970a5d3f14 +https://conda.anaconda.org/conda-forge/linux-64/tktable-2.10-h8bc8fbc_6.conda#dff3627fec2c0584ded391205295abf0 +https://conda.anaconda.org/conda-forge/linux-64/ucx-1.15.0-ha691c75_8.conda#3f9bc6137b240642504a6c9b07a10c25 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.9-h8ee46fc_0.conda#077b6e8ad6a3ddb741fce2496dd01bec https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_0.conda#ae5f4ad87126c55ba3f690ef07f81d64 -https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb +https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.4.0-pyhd8ed1ab_0.conda#0482cd2217e27b3ce47676d570ac3d45 +https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_0.conda#7d78a232029458d0077ede6cda30ed0c https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 https://conda.anaconda.org/conda-forge/noarch/asciitree-0.3.3-py_2.tar.bz2#c0481c9de49f040272556e2cedf42816 -https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-hd4edc92_1.tar.bz2#6c72ec3e660a51736913ef6ea68c454b -https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda#5e4c0743c70186509d1412e03c2d8dfa -https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.3.1-h9599702_1.conda#a8820ce2dbe6f7d54f6540d9a3a0028a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.7.11-hbe98c3e_0.conda#067641478d8f706b80a5a434a22b82be -https://conda.anaconda.org/conda-forge/linux-64/backports.zoneinfo-0.2.1-py311h38be061_8.conda#5384590f14dfe6ccd02811236afc9f8e -https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h166bdaf_9.conda#4601544b4982ba1861fa9b9c607b2c06 -https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.0.9-py311ha362b79_9.conda#ced5340f5dc6cff43a80deac8d0e398f -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda#0876280e409658fc6f9e75d035960333 +https://conda.anaconda.org/conda-forge/noarch/attrs-24.2.0-pyh71513ae_0.conda#6732fa52eb8e66e5afeb32db8701a791 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.4.2-h01f5eca_8.conda#afb85fc0f01032d115c57c961950e7d8 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.8.1-hdb68c23_10.conda#cb6065938167da2d2f078c2f08473b84 +https://conda.anaconda.org/conda-forge/linux-64/backports.zoneinfo-0.2.1-py311h38be061_9.conda#6ba5ba862ef1fa30e87292df09e6b73b +https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hfdbb021_2.conda#d21daab070d76490cb39a8f1d1729d79 +https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-h9c3ff4c_0.tar.bz2#c1ac6229d0bfd14f8354ff9ad2a26cad +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 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-3.3.2-pyhd8ed1ab_0.conda#7f4a9e3fcff3f6356ae99244a014da6a https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda#f3ad426304898027fc619827ff428eca https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.0.0-pyhd8ed1ab_0.conda#753d29fe41bb881e4b9c004f0abf973f -https://conda.anaconda.org/conda-forge/noarch/codespell-2.2.6-pyhd8ed1ab_0.conda#a206349b7bb7475ae580f987cb425bdd +https://conda.anaconda.org/conda-forge/noarch/codespell-2.3.0-pyhd8ed1ab_0.conda#6e67fa19bedafa7eb7d6ea91de53e03d https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/config-0.5.1-pyhd8ed1ab_0.tar.bz2#97275d4898af65967b1ad57923cef770 https://conda.anaconda.org/conda-forge/noarch/configargparse-1.7-pyhd8ed1ab_0.conda#0d07dc29b1c1cc973f76b74beb44915f https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 -https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.9-py311hb755f60_0.conda#c49924051b8336f6031eb3d019619cba +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py311hfdbb021_2.conda#e0ee31128372cd4c6873372a756964bb https://conda.anaconda.org/conda-forge/noarch/defusedxml-0.7.1-pyhd8ed1ab_0.tar.bz2#961b3a227b437d82ad7054484cfa71b2 https://conda.anaconda.org/conda-forge/noarch/dill-0.3.8-pyhd8ed1ab_0.conda#78745f157d56877a2c6e7b386f66f3e2 https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 -https://conda.anaconda.org/conda-forge/linux-64/docutils-0.20.1-py311h38be061_3.conda#1c33f55e5cdcc2a2b973c432b5225bfe +https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e https://conda.anaconda.org/conda-forge/noarch/dodgy-0.2.1-py_0.tar.bz2#62a69d073f7446c90f417b0787122f5b https://conda.anaconda.org/conda-forge/noarch/ecmwf-api-client-1.6.3-pyhd8ed1ab_0.tar.bz2#15621abf59053e184114d3e1d4f9d01e https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.4-pyhd8ed1ab_0.tar.bz2#3cf04868fee0a029769bd41f4b2fbf2d https://conda.anaconda.org/conda-forge/noarch/et_xmlfile-1.1.0-pyhd8ed1ab_0.conda#a2f2138597905eaa72e561d8efb42cf3 -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda#8d652ea2ee8eaee02ed8dc820bc794aa -https://conda.anaconda.org/conda-forge/noarch/execnet-2.0.2-pyhd8ed1ab_0.conda#67de0d8241e1060a479e3c37793e26f9 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 https://conda.anaconda.org/conda-forge/noarch/fasteners-0.17.3-pyhd8ed1ab_0.tar.bz2#348e27e78a5e39090031448c72f66d5e -https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda#0c1729b74a8152fde6a38ba0a2ab9f45 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.0-pyhd8ed1ab_0.conda#ec288789b07ae3be555046e099798a56 https://conda.anaconda.org/conda-forge/noarch/findlibs-0.0.5-pyhd8ed1ab_0.conda#8f325f63020af6f7acbe2c4cb4c920db https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.4.1-py311h459d7ec_0.conda#b267e553a337e1878512621e374845c5 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.3.1-pyhca7485f_0.conda#b7f0662ef2c9d4404f0af9eef5ed2fde -https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h6b639ba_2.conda#ee8220db21db8094998005990418fe5b +https://conda.anaconda.org/conda-forge/linux-64/freexl-2.0.0-h743c826_0.conda#12e6988845706b2cfbc3bc35c9a61a95 +https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.4.1-py311h9ecbd09_1.conda#4605a44155b0c25da37e8f40318c78a4 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.9.0-pyhff2d567_0.conda#ace4329fbff4c69ab0309db6da182987 https://conda.anaconda.org/conda-forge/noarch/geographiclib-2.0-pyhd8ed1ab_0.tar.bz2#6b1f32359fc5d2ab7b491d0029bfffeb -https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe +https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-he02047a_3.conda#c7f243bbaea97cd6ea1edd693270100e +https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyhd8ed1ab_6.conda#2ed1fe4b9079da97c44cfe9c2e5078fd -https://conda.anaconda.org/conda-forge/noarch/idna-3.6-pyhd8ed1ab_0.conda#1a76f09108576397c41c0b0c5bd84134 +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 +https://conda.anaconda.org/conda-forge/noarch/idna-3.8-pyhd8ed1ab_0.conda#99e164522f6bdf23c177c8d9ae63f975 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 -https://conda.anaconda.org/conda-forge/noarch/itsdangerous-2.1.2-pyhd8ed1ab_0.tar.bz2#3c3de74912f11d2b590184f03c7cd09b -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.5-py311h9547e67_1.conda#2c65bdf442b0d37aad080c8a4e0d452f +https://conda.anaconda.org/conda-forge/noarch/itsdangerous-2.2.0-pyhd8ed1ab_0.conda#ff7ca04134ee8dde1d7cf491a78ef7c7 +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py311hd18a35c_0.conda#be34c90cce87090d24da64a7c239ca96 https://conda.anaconda.org/conda-forge/linux-64/lazy-object-proxy-1.10.0-py311h459d7ec_0.conda#d39020c78fd00ed774ff9c876e8aba07 -https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.3-pyhd8ed1ab_0.conda#69ea1d0fa7ab33b48c88394ad1dead65 -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-haa2dc70_1.conda#980d8aca0bc23ca73fa8caa3e7c84c28 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-21_linux64_openblas.conda#0ac9f44fc096772b0aa092119b00c3ca -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.1.2-h409715c_0.conda#50c873c9660ed116707ae15b663928d8 -https://conda.anaconda.org/conda-forge/linux-64/libpq-15.3-hbcd7760_1.conda#8afb2a97d256ffde95b91a6283bc598c -https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.3.1-hbf2b3c1_0.conda#4963f3f12db45a576f2b8fbe9a0b8569 -https://conda.anaconda.org/conda-forge/linux-64/llvmlite-0.42.0-py311ha6695c7_1.conda#d6e13a53b4f0cc38f4a348f47bfd5b97 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.15-h7f713cb_2.conda#9ab79924a3760f85a799f21bc99bd655 +https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.7.4-hfca40fe_0.conda#32ddb97f897740641d8d46a829ce1704 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-23_linux64_openblas.conda#96c8450a40aa2b9733073a9460de972c +https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.9.1-hdb1bdb2_0.conda#7da1d242ca3591e174a3c7d82230d3c0 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a +https://conda.anaconda.org/conda-forge/linux-64/libllvm16-16.0.6-hb3ce162_3.conda#a4d48c40dd5c60edbab7fd69c9a88967 +https://conda.anaconda.org/conda-forge/linux-64/libpq-16.4-h2d7952a_1.conda#7e3173fd1299939a02ebf9ec32aa77c4 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.3.2-hdffd6e0_0.conda#a8661c87c873d8c8f90479318ebf0a17 +https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda#e71f31f8cfb0a91439f2086fc8aa0461 +https://conda.anaconda.org/conda-forge/linux-64/llvmlite-0.43.0-py311h9c9ff8c_1.conda#9ab40f5700784bf16ff7cf8012a646e8 https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 -https://conda.anaconda.org/conda-forge/linux-64/lxml-4.9.3-py311h1a07684_1.conda#aab51e50d994e58efdfa5382139b0468 -https://conda.anaconda.org/conda-forge/linux-64/lz4-4.3.3-py311h38e4bf4_0.conda#3910c815fc788621f88b2bdc0fa9f0a6 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py311h459d7ec_0.conda#a322b4185121935c871d201ae00ac143 +https://conda.anaconda.org/conda-forge/linux-64/lz4-4.3.3-py311h2cbdf9a_1.conda#867a4aa23ae6c0e9c84cf9aa4f2df0fe +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py311h9ecbd09_1.conda#c30e9e5aef9e9ff7fb593736ce2a4546 https://conda.anaconda.org/conda-forge/noarch/mccabe-0.7.0-pyhd8ed1ab_0.tar.bz2#34fc335fc50eef0b5ea708f2b5f54e0c https://conda.anaconda.org/conda-forge/noarch/mistune-3.0.2-pyhd8ed1ab_0.conda#5cbee699846772cc939bef23a0d524ed -https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.7-py311h9547e67_0.conda#3ac85c6c226e2a2e4b17864fc2ca88ff -https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py311h459d7ec_0.conda#4288ea5cbe686d1b18fc3efb36c009a5 +https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.0-py311hd18a35c_0.conda#682f76920687f7d9283039eb542fdacf +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.1.0-py311h9ecbd09_0.conda#afada76949d16eb7d7128ca1dc7d2f10 https://conda.anaconda.org/conda-forge/noarch/munch-4.0.0-pyhd8ed1ab_0.conda#376b32e8f9d3eacbd625f37d39bd507d https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_0.conda#4eccaeba205f0aed9ac3a9ea58568ca3 https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhd8ed1ab_0.conda#70959cd1db3cf77b2a27a0836cfd08a7 -https://conda.anaconda.org/conda-forge/noarch/networkx-3.2.1-pyhd8ed1ab_0.conda#425fce3b531bed6ec3c74fab3e5f0a1c -https://conda.anaconda.org/conda-forge/linux-64/openblas-ilp64-0.3.26-pthreads_h3d04fff_0.conda#7f76d98a5d8bb155d1150d817691f320 -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.0-hfec8fc6_2.conda#5ce6a42505c6e9e6151c54c3ec8d68ea -https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda#248f521b64ce055e7feae3105e7abeb8 +https://conda.anaconda.org/conda-forge/noarch/networkx-3.3-pyhd8ed1ab_1.conda#d335fd5704b46f4efb89a6774e81aef0 +https://conda.anaconda.org/conda-forge/linux-64/openblas-ilp64-0.3.28-pthreads_h3d04fff_0.conda#eb2736b14329cf5650917caa43a549c6 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 +https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.0-h1e5e2c1_0.conda#53e8f030579d34e1a36a735d527c021f +https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda#17064acba08d3686f1135b5ec1b32b12 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_1.conda#405678b942f2481cecdb3e010f4925d9 -https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.0-pyhd8ed1ab_0.conda#a0bc3eec34b0fab84be6b2da94e98e20 -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.4.0-pyhd8ed1ab_0.conda#139e9feb65187e916162917bb2484976 -https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.8-py311h459d7ec_0.conda#9bc62d25dcf64eec484974a3123c9d57 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.2-pyhd8ed1ab_0.conda#e1a2dfcd5695f0744f1bcd3bbfe02523 +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf +https://conda.anaconda.org/conda-forge/linux-64/psutil-6.0.0-py311h9ecbd09_1.conda#493e283ab843404fa36add81fcc49f6c https://conda.anaconda.org/conda-forge/noarch/pycodestyle-2.9.1-pyhd8ed1ab_0.tar.bz2#0191dd7efe1a94262812770183b68892 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 https://conda.anaconda.org/conda-forge/noarch/pyflakes-2.5.0-pyhd8ed1ab_0.tar.bz2#1b3bef4313288ae8d35b1dfba4cd84a3 -https://conda.anaconda.org/conda-forge/noarch/pygments-2.17.2-pyhd8ed1ab_0.conda#140a7f159396547e9799aa98f9f0742e -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f +https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.4-pyhd8ed1ab_0.conda#4d91352a50949d049cf9714c8563d433 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/noarch/python-fastjsonschema-2.19.1-pyhd8ed1ab_0.conda#4d3ceee3af4b0f9a1f48f57176bf8625 +https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.20.0-pyhd8ed1ab_0.conda#b98d2018c01ce9980c03ee2850690fab https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.1-pyhd8ed1ab_0.conda#98206ea9954216ee7540f0c773f2104d -https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.4.1-py311h459d7ec_0.conda#60b5332b3989fda37884b92c7afd6a91 +https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.5.0-py311h9ecbd09_1.conda#b1796d741ca619dbacb79917b20e5a05 https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py311h459d7ec_1.conda#52719a74ad130de8fb5d047dc91f247a -https://conda.anaconda.org/conda-forge/linux-64/pyzmq-25.1.2-py311h34ded2d_0.conda#819aa640a0493d4b52faf938e94d129e -https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.18.0-py311h46250e7_0.conda#688a1190531dc4e8c00e25d0d1de4135 +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py311h9ecbd09_1.conda#abeb54d40f439b86f75ea57045ab8496 +https://conda.anaconda.org/conda-forge/linux-64/re2-2023.09.01-h7f4b329_2.conda#8f70e36268dea8eb666ef14c29bd3cda +https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.20.0-py311h9e33e62_1.conda#3989f9a93796221aff20be94300e3b93 https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.8-py311h459d7ec_0.conda#7865c897d89a39abc0056d89e37bd9e9 https://conda.anaconda.org/conda-forge/noarch/semver-3.0.2-pyhd8ed1ab_0.conda#5efb3fccda53974aed800b6d575f72ed https://conda.anaconda.org/conda-forge/noarch/setoptconf-tmp-0.3.1-pyhd8ed1ab_0.tar.bz2#af3e36d4effb85b9b9f93cd1db0963df -https://conda.anaconda.org/conda-forge/noarch/setuptools-69.2.0-pyhd8ed1ab_0.conda#da214ecd521a720a9d521c68047682dc -https://conda.anaconda.org/conda-forge/linux-64/simplejson-3.19.2-py311h459d7ec_0.conda#d6478cbce002db6303f0d749860f3e22 +https://conda.anaconda.org/conda-forge/noarch/setuptools-73.0.1-pyhd8ed1ab_0.conda#f0b618d7673d1b2464f600b34d912f6f +https://conda.anaconda.org/conda-forge/linux-64/simplejson-3.19.3-py311h9ecbd09_1.conda#b208b9b6336362211c787547f92a5464 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.0-pyhd8ed1ab_0.tar.bz2#62f26a3d1387acee31322208f0cfa3e0 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2#6d6552722448103793743dabfbda532d https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 -https://conda.anaconda.org/conda-forge/noarch/sqlparse-0.4.4-pyhd8ed1ab_0.conda#2e2f31b3b1c866c29636377e14f8c4c6 -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.11.0-h00ab1b0_1.conda#4531d2927578e7e254ff3bcf6457518c +https://conda.anaconda.org/conda-forge/noarch/sqlparse-0.5.1-pyhd8ed1ab_0.conda#e8af29e73e8b5906d8882c1f67222d34 https://conda.anaconda.org/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_0.conda#04eedddeb68ad39871c8127dd1c21f4f -https://conda.anaconda.org/conda-forge/noarch/tenacity-8.2.3-pyhd8ed1ab_0.conda#1482e77f87c6a702a7e05ef22c9b197b +https://conda.anaconda.org/conda-forge/noarch/tenacity-9.0.0-pyhd8ed1ab_0.conda#42af51ad3b654ece73572628ad2882ae https://conda.anaconda.org/conda-forge/noarch/termcolor-2.4.0-pyhd8ed1ab_0.conda#a5033708ad9283907c3b1bc1f90d0d0d -https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.4.0-pyhc1e730c_0.conda#b296278eef667c673bf51de6535bad88 +https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd +https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.16.3-hf0b6e87_3.conda#1e28da846782f91a696af3952a2472f9 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/tomlkit-0.12.4-pyha770c72_0.conda#37c47ea93ef00dd80d880fc4ba21256a +https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.13.2-pyha770c72_0.conda#0062a5f3347733f67b0f33ca48cc21dd https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.1-pyhd8ed1ab_0.conda#2fcb582444635e2c402e8569bb94e039 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4-py311h459d7ec_0.conda#cc7727006191b8f3630936b339a76cd0 -https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.2-pyhd8ed1ab_0.conda#af5fa2d2186003472e766a23c46cae04 -https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.3.3-pyhd8ed1ab_0.conda#8ea774e1b108dc9a1a8358a483b4cc6d -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.10.0-pyha770c72_0.conda#16ae769069b380646c47142d719ef466 -https://conda.anaconda.org/conda-forge/linux-64/ujson-5.9.0-py311hb755f60_0.conda#36dda52dc99a4fb9cadd3b738ec24848 -https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-py_0.tar.bz2#1447ead40f2a01733a9c8dfc32988375 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py311h9ecbd09_1.conda#616fed0b6f5c925250be779b05d1d7f7 +https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_0.conda#3df84416a021220d8b5700c613af2dc5 +https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.7.2-pyhd8ed1ab_0.conda#2b9f52c7ecb8d017e50f91852aead307 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 +https://conda.anaconda.org/conda-forge/linux-64/ujson-5.10.0-py311hfdbb021_1.conda#273cf8bedf58f24aec8d960831f89c5a +https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhd8ed1ab_1.conda#6042b782b893029aa40335782584a092 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_2.conda#daf5160ff9cde3a468556965329085b9 -https://conda.anaconda.org/conda-forge/noarch/webob-1.8.7-pyhd8ed1ab_0.tar.bz2#a8192f3585f341ea66c60c189580ac67 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda#1cdea58981c5cbc17b51973bcaddcea7 -https://conda.anaconda.org/conda-forge/linux-64/wrapt-1.16.0-py311h459d7ec_0.conda#6669b5529d206c1f880b642cdd17ae05 -https://conda.anaconda.org/conda-forge/noarch/xlsxwriter-3.1.9-pyhd8ed1ab_0.conda#70e533db62a710ae216fdaccc4a983c8 +https://conda.anaconda.org/conda-forge/noarch/webob-1.8.8-pyhd8ed1ab_0.conda#ae69b699c308c3bd20388219764235b0 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/linux-64/wrapt-1.16.0-py311h9ecbd09_1.conda#810ae646bcc50a017380336d874e4014 +https://conda.anaconda.org/conda-forge/noarch/xlsxwriter-3.2.0-pyhd8ed1ab_0.conda#a1f7264726115a2f8eac9773b1f27eba https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-5.0.3-h7f98852_1004.tar.bz2#e9a21aa4d5e3e5f1aed71e8cefd46b6a https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda#ed67c36f215b310412b2af935bf3e530 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hd590300_1.conda#ae92aab42726eb29d16488924f7312cb -https://conda.anaconda.org/conda-forge/noarch/xyzservices-2023.10.1-pyhd8ed1ab_0.conda#1e0d85c0e2fef9539218da185b285f54 +https://conda.anaconda.org/conda-forge/noarch/xyzservices-2024.9.0-pyhd8ed1ab_0.conda#156c91e778c1d4d57b709f8c5333fd06 +https://conda.anaconda.org/conda-forge/noarch/yapf-0.32.0-pyhd8ed1ab_0.tar.bz2#177cba0b4bdfacad5c5fbb0ed31504c4 +https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-ha4adb4c_5.conda#e8372041ebb377237db9d0d24c7b5962 https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda#2e4d6bc0b14e10f895fc6791a7d9b26a -https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.4-pyhd8ed1ab_0.conda#46a2e6e3dfa718ce3492018d5a110dd6 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.1-pyhd8ed1ab_0.conda#74a4befb4b38897e19a107693e49da20 +https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_0.conda#1bb1ef9806a9a20872434f58b3e7fc1a https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.1-pyhd8ed1ab_0.tar.bz2#d1e1eb7e21a9e2c74279d87dafb68156 -https://conda.anaconda.org/conda-forge/noarch/asgiref-3.8.0-pyhd8ed1ab_0.conda#4d79a1cf292a47ab1681fb7d9cc7e253 +https://conda.anaconda.org/conda-forge/noarch/asgiref-3.8.1-pyhd8ed1ab_0.conda#b5c2e1034ccc76fb14031637924880eb https://conda.anaconda.org/conda-forge/linux-64/astroid-2.15.8-py311h38be061_0.conda#46d70fcb74472aab178991f0231ee3c6 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.7.0-hf8751d9_2.conda#deb12196f0c64c441bb3d083d06d0cf8 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.8.14-h2e270ba_2.conda#58bbee5fd6cf2d4fffbead1bc33a5d3b +https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.7.17-he0b1f16_2.conda#ea6d998135d5f8932cffc91381104690 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.10.3-h50844eb_4.conda#e72fdd8942f266ea79c70ec085661d6c https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda#9669586875baeced8fc30c0826c3270e https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda#332493000404d8411859539a5a630865 https://conda.anaconda.org/conda-forge/noarch/bleach-6.1.0-pyhd8ed1ab_0.conda#0ed9d7c0e9afa7c025807a9a8136ea3e -https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-h9c3ff4c_0.tar.bz2#c1ac6229d0bfd14f8354ff9ad2a26cad -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.16.0-hbbf8b49_1016.conda#c1dd96500b9b1a75e9e511931f415cbc -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py311hb3a22ac_0.conda#b3469563ac5e808b0cd92810d0697043 -https://conda.anaconda.org/conda-forge/linux-64/cfitsio-4.2.0-hd9d235c_0.conda#8c57a9adbafd87f5eff842abde599cb4 +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py311hf29c0ef_0.conda#55553ecd5328336368db611f350b7039 +https://conda.anaconda.org/conda-forge/linux-64/cfitsio-4.3.0-hbdc6101_0.conda#797554b8b7603011e8677884381fbcc5 https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1-py_0.tar.bz2#4fd2c6b53934bd7d96d1f3fdaf99b79f https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_1.tar.bz2#a29b7c141d6b2de4bb67788a5f107734 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.4.4-py311h459d7ec_0.conda#1aa22cb84e68841ec206ee066457bdf0 -https://conda.anaconda.org/conda-forge/linux-64/curl-8.1.2-h409715c_0.conda#9f88cfb15b7d08b25880b138f91e0eb4 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.1-py311h9ecbd09_1.conda#a36ccf0f3d2eb95a0ecc293f5f56e080 +https://conda.anaconda.org/conda-forge/linux-64/curl-8.9.1-h18eb788_0.conda#2e7dedf73dfbfcee662e2a0f6175e4bb https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.3-py311h459d7ec_0.conda#13d385f635d7fbe9acc93600f67a6cb4 https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.5-pyhd8ed1ab_0.conda#3a941b6083e945aa87e739a9b85c82e9 https://conda.anaconda.org/conda-forge/noarch/docrep-0.3.2-pyh44b312d_0.tar.bz2#235523955bc1bfb019d7ec8a2bb58f9a https://conda.anaconda.org/conda-forge/noarch/fire-0.6.0-pyhd8ed1ab_0.conda#e9ed10aa8fa1dd6782940b95c942a6ae -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.50.0-py311h459d7ec_0.conda#fcdef52b45265eece45de756b164a9a7 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.53.1-py311h9ecbd09_1.conda#89ed1820af1523df84171049199ed915 https://conda.anaconda.org/conda-forge/noarch/geopy-2.4.1-pyhd8ed1ab_1.conda#358c17429c97883b2cb9ab5f64bc161b https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.11-pyhd8ed1ab_0.conda#623b19f616f2ca0c261441067e18ae40 -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.0-nompi_hb72d44e_103.conda#975973a4350ab45ff1981fe535a12af5 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda#0896606848b2dc5cebdf111b6543aa04 -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.3.2-pyhd8ed1ab_0.conda#bb8086d3dd1b2cfeebd15f9a7e56f7bd +https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_hdf9ad27_105.conda#7e1729554e209627636a0f6fabcdd115 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.4.0-pyha770c72_0.conda#6e3dbc422d3749ad72659243d6ac8b2b +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_0.conda#c808991d29b9838fb4d96ce8267ec9ec https://conda.anaconda.org/conda-forge/noarch/isodate-0.6.1-pyhd8ed1ab_0.tar.bz2#4a62c93c1b5c0b920508ae3fd285eaf5 https://conda.anaconda.org/conda-forge/noarch/isort-5.13.2-pyhd8ed1ab_0.conda#1d25ed2b95b92b026aaa795eabec8d91 -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.3-pyhd8ed1ab_0.conda#e7d8df6509ba635247ff9aea31134262 -https://conda.anaconda.org/conda-forge/noarch/joblib-1.3.2-pyhd8ed1ab_0.conda#4da50d410f553db77e62ab62ffaa1abc +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f https://conda.anaconda.org/conda-forge/linux-64/jupyter_core-5.7.2-py311h38be061_0.conda#f85e78497dfed6f6a4b865191f42de2e https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.3.0-pyhd8ed1ab_1.conda#afcd1b53bcac8844540358e33f33d28f https://conda.anaconda.org/conda-forge/noarch/latexcodec-2.0.1-pyh9f0ad1d_0.tar.bz2#8d67904973263afd2985ba56aa2d6bb4 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-21_linux64_openblas.conda#4a3816d06451c4946e2db26b86472cb6 -https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-hfa28ad5_6.conda#ef06bee47510a7f5db3c2297a51d6ce2 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-23_linux64_openblas.conda#eede29b40efa878cbe5bdcb767e97310 +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-he9388d3_8.conda#f3abc6e6ab60fa404c23094f5a03ec9b +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.78.1-hebfc3b9_0.conda#ddd09e8904fde46b85f41896621803e6 https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-hac7e632_1003.conda#50c389a09b6b7babaef531eb7cb5e0ca -https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.12.0-h840a212_1.conda#03c225a73835f5aa68c13e62eb360406 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-21_linux64_openblas.conda#1a42f305615c3867684e049e85927531 +https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.62.2-h15f2491_0.conda#8dabe607748cb3d7002ad73cd06f1325 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-23_linux64_openblas.conda#2af0879961951987e464722fd00ec1e0 https://conda.anaconda.org/conda-forge/noarch/logilab-common-1.7.3-py_0.tar.bz2#6eafcdf39a7eb90b6d951cfff59e8d3b +https://conda.anaconda.org/conda-forge/linux-64/lxml-5.3.0-py311hcfaa980_1.conda#b76d6a1a47942ad2021a9d3d7fe527bd https://conda.anaconda.org/conda-forge/noarch/nested-lookup-0.2.25-pyhd8ed1ab_1.tar.bz2#2f59daeb14581d41b1e2dda0895933b2 -https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda#2a75b296096adabbabadd5e9782e5fcc -https://conda.anaconda.org/conda-forge/linux-64/openpyxl-3.1.2-py311h459d7ec_1.conda#5c809fb753f06a04c2f114394404769e -https://conda.anaconda.org/conda-forge/noarch/partd-1.4.1-pyhd8ed1ab_0.conda#acf4b7c0bcd5fa3b0e05801c4d2accd6 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.0.0-py311h0b84326_0.conda#4b24acdc1fbbae9da03147e7d2cf8c8a -https://conda.anaconda.org/conda-forge/noarch/pip-24.0-pyhd8ed1ab_0.conda#f586ac1e56c8638b64f9c8122a7b8a67 -https://conda.anaconda.org/conda-forge/noarch/plotly-5.19.0-pyhd8ed1ab_0.conda#669cd7065794633b9e64e6a9612ec700 -https://conda.anaconda.org/conda-forge/linux-64/postgresql-15.3-hd458b1d_1.conda#4a4b5dede4d2e075e9aa5a44a9fd9f20 -https://conda.anaconda.org/conda-forge/linux-64/proj-9.2.1-ha643af7_0.conda#e992387307f4403ba0ec07d009032550 +https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_0.conda#dfe0528d0f1c16c1f7c528ea5536ab30 +https://conda.anaconda.org/conda-forge/linux-64/openpyxl-3.1.5-py311h50c5138_1.conda#7d777fcd827bbd67fd1b8b01b7f8f333 +https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda#0badf9c54e24cecfb0ad2f99d680c163 +https://conda.anaconda.org/conda-forge/linux-64/pillow-10.0.1-py311h8aef010_1.conda#4d66ee2081a7cd444ff6f30d95873eef +https://conda.anaconda.org/conda-forge/noarch/pip-24.2-pyh8b19718_1.conda#6c78fbb8ddfd64bcb55b5cbafd2d2c43 +https://conda.anaconda.org/conda-forge/noarch/plotly-5.24.0-pyhd8ed1ab_0.conda#80a4a0867ded2a66687e78bca0bc70fc +https://conda.anaconda.org/conda-forge/linux-64/postgresql-16.4-hb2eb5c0_1.conda#1aaec5dbae29b3f0a2c20eeb84e9e38a +https://conda.anaconda.org/conda-forge/linux-64/proj-9.3.0-h1d62c97_2.conda#b5e57a0c643da391bef850922963eece https://conda.anaconda.org/conda-forge/noarch/pydocstyle-6.3.0-pyhd8ed1ab_0.conda#7e23a61a7fbaedfef6eb0e1ac775c8e5 -https://conda.anaconda.org/conda-forge/noarch/pyproject_hooks-1.0.0-pyhd8ed1ab_0.conda#21de50391d584eb7f4441b9de1ad773f -https://conda.anaconda.org/conda-forge/noarch/pytest-8.1.1-pyhd8ed1ab_0.conda#94ff09cdedcb7b17e9cd5097ee2cfcff +https://conda.anaconda.org/conda-forge/noarch/pyproject_hooks-1.1.0-pyhd8ed1ab_0.conda#03736d8ced74deece64e54be348ddd3e +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c https://conda.anaconda.org/conda-forge/noarch/python-utils-3.8.2-pyhd8ed1ab_0.conda#89703b4f38bd1c0353881f085bc8fdaa -https://conda.anaconda.org/conda-forge/noarch/referencing-0.34.0-pyhd8ed1ab_0.conda#e4492c22e314be5c75db3469e3bbf3d9 -https://conda.anaconda.org/conda-forge/noarch/retrying-1.3.3-py_2.tar.bz2#a11f356d6f93b74b4a84e9501afd48b4 +https://conda.anaconda.org/conda-forge/linux-64/pyzmq-26.2.0-py311h7deb3e3_2.conda#5d3fc8b5c5765e1f207c53554a713907 +https://conda.anaconda.org/conda-forge/noarch/referencing-0.35.1-pyhd8ed1ab_0.conda#0fc8b52192a8898627c3efae1003e9f6 +https://conda.anaconda.org/conda-forge/noarch/retrying-1.3.3-pyhd8ed1ab_3.conda#1f7482562f2082f1b2abf8a3e2a41b63 https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.6-py311h459d7ec_0.conda#4dccc0bc3bb4d6e5c30bccbd053c4f90 -https://conda.anaconda.org/conda-forge/noarch/tinycss2-1.2.1-pyhd8ed1ab_0.tar.bz2#7234c9eefff659501cd2fe0d2ede4d48 -https://conda.anaconda.org/conda-forge/noarch/tqdm-4.66.2-pyhd8ed1ab_0.conda#2b8dfb969f984497f3f98409a9545776 -https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.10.0-hd8ed1ab_0.conda#091683b9150d2ebaa62fd7e2c86433da +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 +https://conda.anaconda.org/conda-forge/noarch/tinycss2-1.3.0-pyhd8ed1ab_0.conda#8662629d9a05f9cff364e31ca106c1ac +https://conda.anaconda.org/conda-forge/noarch/tqdm-4.66.5-pyhd8ed1ab_0.conda#c6e94fc2b2ec71ea33fe7c7da259acb4 +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.12.2-hd8ed1ab_0.conda#52d648bd608f5737b123f510bb5514b5 https://conda.anaconda.org/conda-forge/noarch/url-normalize-1.4.3-pyhd8ed1ab_0.tar.bz2#7c4076e494f0efe76705154ac9302ba6 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda#08807a87fa7af10754d46f63b368e016 -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.1-pyhd8ed1ab_0.conda#8797a4e26be36880a603aba29c785352 -https://conda.anaconda.org/conda-forge/linux-64/xerces-c-3.2.4-h8d71039_2.conda#6d5edbe22b07abae2ea0a9065ef6be12 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.7.10-h7f98852_0.tar.bz2#e77615e5141cad5a2acaa043d1cf0ca5 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxmu-1.1.3-h7f98852_0.tar.bz2#3cdb89236358326adfce12be820a8af3 +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.4-pyhd8ed1ab_0.conda#14c15fa7def506fe7d1a0e3abdc212d6 +https://conda.anaconda.org/conda-forge/linux-64/xerces-c-3.2.5-hac6953d_0.conda#63b80ca78d29380fe69e69412dcbe4ac +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.7.10-h4bc722e_1.conda#749baebe7e2ff3360630e069175e528b +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxmu-1.1.3-h4ab18f5_1.conda#4d6c9925cdcda27e9d022e40eb3eac05 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxpm-3.5.17-hd590300_0.conda#12bf78e12f71405775e1c092902959d3 -https://conda.anaconda.org/conda-forge/noarch/yamale-4.0.4-pyh6c4a22f_0.tar.bz2#cc9f59f147740d88679bf1bd94dbe588 +https://conda.anaconda.org/conda-forge/noarch/yamale-5.2.1-pyhca7485f_0.conda#c089f90a086b6214c5606368d0d3bad0 https://conda.anaconda.org/conda-forge/noarch/yamllint-1.35.1-pyhd8ed1ab_0.conda#a1240b99a7ccd953879dc63111823986 -https://conda.anaconda.org/conda-forge/linux-64/yarl-1.9.4-py311h459d7ec_0.conda#fff0f2058e9d86c8bf5848ee93917a8d -https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.9.3-py311h459d7ec_1.conda#7fd17e8947afbddd2855720d643a48f0 +https://conda.anaconda.org/conda-forge/linux-64/yarl-1.11.1-py311h9ecbd09_0.conda#3dfc4a6fef3ef9683494e3266fca27ea +https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.10.5-py311h61187de_0.conda#4b255c4b54de2a41bc8dc63ee78098e4 https://conda.anaconda.org/conda-forge/linux-64/arpack-3.7.0-hdefa2d7_2.tar.bz2#8763fe86163198ef1778d1d8d22bb078 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.3.13-heb0bb06_2.conda#c0866da05d5e7bb3a3f6b68bcbf7537b -https://conda.anaconda.org/conda-forge/noarch/cattrs-23.2.3-pyhd8ed1ab_0.conda#91fc4700dcce4a46d439900a132fe4e5 -https://conda.anaconda.org/conda-forge/linux-64/cryptography-42.0.2-py311hcb13ee4_0.conda#c61fd9e9fcfa599ea5a8b1de42b147a8 -https://conda.anaconda.org/conda-forge/noarch/django-5.0.3-pyhd8ed1ab_0.conda#5242811441d7edca3fa3026693bd9cd8 +https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-hd4edc92_1.tar.bz2#6c72ec3e660a51736913ef6ea68c454b +https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.5.7-hb7bd14b_1.conda#82bd3d7da86d969c62ff541bab19526a +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-h3faef2a_0.conda#f907bb958910dc404647326ca80c263e +https://conda.anaconda.org/conda-forge/noarch/cattrs-24.1.0-pyhd8ed1ab_0.conda#1e5ac693650d3312e6421e766a5abadd +https://conda.anaconda.org/conda-forge/linux-64/cryptography-43.0.1-py311hafd3f86_0.conda#2653b58a992032d6c3ff4d82fc1c6c82 +https://conda.anaconda.org/conda-forge/noarch/django-5.1.1-pyhd8ed1ab_0.conda#d1e2ab198eca6bf9fcd81f6fd790e2c5 https://conda.anaconda.org/conda-forge/noarch/flake8-5.0.4-pyhd8ed1ab_0.tar.bz2#8079ea7dec0a917dd0cb6c257f7ea9ea https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-hac7e632_2.conda#6e553df297f6e64668efb54302e0f139 https://conda.anaconda.org/conda-forge/noarch/funcargparse-0.2.5-pyhd8ed1ab_0.tar.bz2#e557b70d736251fa0bbb7c4497852a92 -https://conda.anaconda.org/conda-forge/linux-64/geotiff-1.7.1-h22adcc9_11.conda#514167b60f598eaed3f7a60e1dceb9ee +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h6c15284_3.conda#06f97c8b69157d91993af0c4f2e16bdc +https://conda.anaconda.org/conda-forge/linux-64/geotiff-1.7.1-hee599c5_13.conda#8c55dacddd589be64b2bd6a5d4264be6 https://conda.anaconda.org/conda-forge/linux-64/git-2.42.0-pl5321h86e50cf_0.conda#96ad24c67e0056d171385859c43218a2 -https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.42-pyhd8ed1ab_0.conda#6bc8e496351bafd761c0922c3ebd989a +https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.43-pyhd8ed1ab_0.conda#0b2154c1818111e17381b1df5b4b0176 https://conda.anaconda.org/conda-forge/linux-64/gsl-2.7-he838d99_0.tar.bz2#fec079ba39c9cca093bf4c00001825de -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-7.3.0-hdb3a94d_0.conda#765bc76c0dfaf24ff9d8a2935b2510df -https://conda.anaconda.org/conda-forge/linux-64/hdfeos5-5.1.16-h8b5b2df_13.conda#29a96d50cb53638a5b4806b5ca6e4b1d -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda#6ef2b72d291b39e479d7694efa2b2b98 +https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe +https://conda.anaconda.org/conda-forge/linux-64/hdfeos5-5.1.16-hf1a501a_15.conda#d2e16a32f41d67c7d280da11b2846328 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.4.0-hd8ed1ab_0.conda#01b7411c765c3d863dcc920207f258bd https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2023.12.1-pyhd8ed1ab_0.conda#a0e4efb5f35786a05af4809a2fb1f855 -https://conda.anaconda.org/conda-forge/linux-64/kealib-1.5.1-h3845be2_3.conda#f38e5e47f62d6633166040192ad420a1 -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h0f3d0bb_105.conda#b5d412441b84305460e9df8a016a3392 -https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.0.1-hca56755_27.conda#918a735059cab21b96fc13a8d04fbcd8 +https://conda.anaconda.org/conda-forge/linux-64/kealib-1.5.3-hf8d3e68_2.conda#ffe68c611ae0ccfda4e7a605195e22b3 +https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.4-pyhd8ed1ab_1.conda#4809b9f4c6ce106d443c3f90b8e10db2 +https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.22.0-h9be4e54_1.conda#4b4e36a91e7dabf7345b82d85767a7c3 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h135f659_114.conda#a908e463c710bd6b10a9eaa89fdf003c +https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.1.0-h090f1da_1.conda#9a2d6acaa8ce6d53a150248e7b11165e https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py311h64a7726_0.conda#a502d7aad449a1206efb366d6a12c52d -https://conda.anaconda.org/conda-forge/linux-64/poppler-23.05.0-hd18248d_1.conda#09e0de1aa7330fe697eed76eaeef666d -https://conda.anaconda.org/conda-forge/noarch/progressbar2-4.4.2-pyhd8ed1ab_0.conda#aca82be28a1c676a3e0365e83892f412 +https://conda.anaconda.org/conda-forge/noarch/progressbar2-4.5.0-pyhd8ed1ab_0.conda#6f9eb38d0a87898cf5a7c91adaccd691 https://conda.anaconda.org/conda-forge/noarch/pybtex-0.24.0-pyhd8ed1ab_2.tar.bz2#2099b86a7399c44c0c61cdb6de6915ba https://conda.anaconda.org/conda-forge/noarch/pylint-2.17.7-pyhd8ed1ab_0.conda#3cab6aee60038b3f621bce3e50f52bed -https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.6.1-py311ha169711_0.conda#ad4b6e9be79a89959bb6d7d308027ff2 -https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.1.0-pyhd8ed1ab_0.conda#06eb685a3a0b146347a58dda979485da -https://conda.anaconda.org/conda-forge/noarch/pytest-env-1.1.3-pyhd8ed1ab_0.conda#1dbdf019d740419852c4a7803fff49d9 +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.6.1-py311h1facc83_4.conda#75d504c6787edc377ebdba087a26a61b +https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda#c54c0107057d67ddf077751339ec2c63 +https://conda.anaconda.org/conda-forge/noarch/pytest-env-1.1.4-pyhd8ed1ab_0.conda#638cfd3bf6904125e868176d89c2ae0b https://conda.anaconda.org/conda-forge/noarch/pytest-metadata-3.1.1-pyhd8ed1ab_0.conda#52b91ecba854d55b28ad916a8b10da24 -https://conda.anaconda.org/conda-forge/noarch/pytest-mock-3.12.0-pyhd8ed1ab_0.conda#ac9fedc9a0c397f2318e82525491dd83 -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.5.0-pyhd8ed1ab_0.conda#d5f595da2daead898ca958ac62f0307b -https://conda.anaconda.org/conda-forge/noarch/python-build-1.1.1-pyhd8ed1ab_0.conda#6b82ada068f6c7e51cf623f4cb6c4034 +https://conda.anaconda.org/conda-forge/noarch/pytest-mock-3.14.0-pyhd8ed1ab_0.conda#4b9b5e086812283c052a9105ab1e254e +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/noarch/python-build-1.2.2-pyhd8ed1ab_0.conda#7309d5de1e4e866df29bcd8ea5550035 https://conda.anaconda.org/conda-forge/noarch/rdflib-7.0.0-pyhd8ed1ab_0.conda#44d14ef95495b3d4438f28998e0296a9 -https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda#a30144e4156cdbb236f99ebb49828f8b https://conda.anaconda.org/conda-forge/noarch/requirements-detector-1.2.2-pyhd8ed1ab_0.conda#6626918380d99292df110f3c91b6e5ec https://conda.anaconda.org/conda-forge/linux-64/suitesparse-5.10.1-h5a4f163_3.conda#f363554b9084fb9d5e3366fbbc0d18e0 -https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.13.2-hd532e3d_0.conda#6d97164f19dbd27575ef1899b02dc1e0 -https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py311h9547e67_4.conda#586da7df03b68640de14dc3e8bcbf76f +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py311hd18a35c_5.conda#4e8447ca8558a203ec0577b4730073f3 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxaw-1.0.14-h7f98852_1.tar.bz2#45b68dc2fc7549c16044d533ceaf340e -https://conda.anaconda.org/conda-forge/noarch/yapf-0.40.1-pyhd8ed1ab_0.conda#f269942e802d5e148632143d4c37acc9 -https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.20.3-he9c0e7f_4.conda#7695770e1d722ce9029a2ea30c060a3d -https://conda.anaconda.org/conda-forge/noarch/cdsapi-0.6.1-pyhd8ed1ab_0.conda#454ed214cec806066097ae245a409171 -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.3-py311h1f0f07a_0.conda#b7e6d52b39e199238c3400cafaabafb3 -https://conda.anaconda.org/conda-forge/noarch/chart-studio-1.1.0-pyh9f0ad1d_0.tar.bz2#acd9a12a35e5a0221bdf39eb6e4811dc +https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py311hbc35293_1.conda#aec590674ba365e50ae83aa2d6e1efae +https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.26.6-hf567797_4.conda#ffb662b31aef333e68a00dd17fda2027 +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py311h9f3472d_1.conda#2c3c4f115d28ed9e001a271d5d8585aa https://conda.anaconda.org/conda-forge/noarch/colorspacious-1.1.2-pyh24bf2e0_0.tar.bz2#b73afa0d009a51cabd3ec99c4d2ef4f3 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.2.0-py311h9547e67_0.conda#40828c5b36ef52433e21f89943e09f33 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.3.1-pyhd8ed1ab_0.conda#52dd56ce3afa6a52c2f3d3116875ff32 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py311hd18a35c_1.conda#f709f23e2b1b93b3b6a20e9e7217a258 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.8.2-pyhd8ed1ab_0.conda#8e7524a2fb561506260db789806c7ee9 https://conda.anaconda.org/conda-forge/noarch/eofs-1.4.1-pyhd8ed1ab_1.conda#5fc43108dee4106f23050acc7a101233 https://conda.anaconda.org/conda-forge/noarch/flake8-polyfill-1.0.2-py_0.tar.bz2#a53db35e3d07f0af2eccd59c2a00bffe -https://conda.anaconda.org/conda-forge/noarch/identify-2.5.35-pyhd8ed1ab_0.conda#9472bfd206a2b7bb8143835e37667054 -https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2023.8.12-py311h67b54e4_0.conda#363e5c2f2c67ff69d717aba54422b03d -https://conda.anaconda.org/conda-forge/noarch/imageio-2.34.0-pyh4b66e23_0.conda#b8853659d596f967c661f544dd89ede7 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.3.0-h3d44ed6_0.conda#5a6f6c00ef982a9bc83558d9ac8f64a0 +https://conda.anaconda.org/conda-forge/noarch/identify-2.6.0-pyhd8ed1ab_0.conda#f80cc5989f445f23b1622d6c455896d9 +https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2023.9.18-py311h9b38416_0.conda#67bed2bd92ffa76b20506d83427706ae +https://conda.anaconda.org/conda-forge/noarch/imageio-2.35.1-pyh12aca89_0.conda#b03ff3631329c8ef17bae35d2bb216f7 https://conda.anaconda.org/conda-forge/linux-64/jasper-4.0.0-h32699f2_1.conda#fdde5424ecef5f7ad310b4242229291c -https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.21.1-pyhd8ed1ab_0.conda#8a3a3d01629da20befa340919e3dd2c4 -https://conda.anaconda.org/conda-forge/linux-64/julia-1.8.5-h783901f_0.conda#98c05ba7ca9c15d22216f730499e167a -https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.1-pyhd8ed1ab_0.conda#c03972cfce69ad913d520c652e5ed908 -https://conda.anaconda.org/conda-forge/linux-64/libgdal-3.7.0-h5418a03_2.conda#30ddbe080c260fb36da8509e3fd6c45f +https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.23.0-pyhd8ed1ab_0.conda#da304c192ad59975202859b367d0f6a2 +https://conda.anaconda.org/conda-forge/linux-64/julia-1.9.3-h06b7c97_0.conda#6214d0563598ae0cc9b954344b9f9c10 +https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.2-pyhd8ed1ab_0.conda#3cdbb2fa84490e5fd44c9f9806c0d292 +https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_1.conda#ec6f70b8a5242936567d4f886726a372 +https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.22.0-hc7a4891_1.conda#7811f043944e010e54640918ea82cecd https://conda.anaconda.org/conda-forge/noarch/magics-python-1.5.8-pyhd8ed1ab_1.conda#3fd7e3db129f12362642108f23fde521 -https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_h4f3791c_100.conda#405c5b3ad4ef53eb0d93043b54206dd7 -https://conda.anaconda.org/conda-forge/linux-64/numba-0.59.0-py311h96b013e_1.conda#488276429185c4fa1266e6a4a24a61af -https://conda.anaconda.org/conda-forge/linux-64/numcodecs-0.12.1-py311hb755f60_0.conda#38a2ff8ea433fe8792279b45e84b3730 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.1-py311h320fe9a_0.conda#aac8d7137fedc2fd5f8320bf50e4204c -https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.14-heaa33ce_1.conda#cde553e0e32389e26595db4eacf859eb +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_h22f9119_106.conda#5b911bfe75855326bae6857451268e59 +https://conda.anaconda.org/conda-forge/linux-64/numba-0.60.0-py311h4bc866e_0.conda#e32a210e9caf97383c35685fd2343512 +https://conda.anaconda.org/conda-forge/linux-64/numcodecs-0.13.0-py311h044e617_0.conda#9d783b29b6fc53e4d9a94f5befdfd34b +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.1.4-py311h320fe9a_0.conda#e44ccb61b6621bf3f8053ae66eba7397 https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.6-pyhd8ed1ab_0.conda#a5b55d1cb110cdcedc748b5c3e16e687 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.1-pyhd8ed1ab_0.conda#d15917f33140f8d2ac9ca44db7ec8a25 +https://conda.anaconda.org/conda-forge/linux-64/poppler-23.08.0-hf2349cb_2.conda#fb75401ae7e2e3f354dff72e9da95cae https://conda.anaconda.org/conda-forge/noarch/pylint-plugin-utils-0.7-pyhd8ed1ab_0.tar.bz2#1657976383aee04dbb3ae3bdf654bb58 -https://conda.anaconda.org/conda-forge/noarch/pyopenssl-24.0.0-pyhd8ed1ab_0.conda#b50aec2c744a5c493c09cce9e2e7533e -https://conda.anaconda.org/conda-forge/noarch/pyroma-4.2-pyhd8ed1ab_0.conda#fe2aca9a5d4cb08105aefc451ef96950 +https://conda.anaconda.org/conda-forge/noarch/pyopenssl-24.2.1-pyhd8ed1ab_2.conda#85fa2fdd26d5a38792eb57bc72463f07 +https://conda.anaconda.org/conda-forge/linux-64/pys2index-0.1.5-py311h92ebd52_0.conda#ee757dff4cdb96bb972200c85b37f9e8 https://conda.anaconda.org/conda-forge/noarch/pytest-html-4.1.1-pyhd8ed1ab_0.conda#4d2040212307d18392a2687772b3a96d -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.4.1-py311h1f0f07a_1.conda#86b71ff85f3e4c8a98b5bace6d9c4565 -https://conda.anaconda.org/conda-forge/noarch/requests-cache-1.2.0-pyhd8ed1ab_0.conda#f9a382d30405f6c874edf866eb814e7c -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.12.0-py311h64a7726_2.conda#24ca5107ab75c5521067b8ba505dfae5 -https://conda.anaconda.org/conda-forge/noarch/seawater-3.3.4-py_1.tar.bz2#a9e101e1601faf5e5a119ab2bd7617a4 -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.1-py311h54d622a_1.conda#a894c65b48676c4973e9ee8b59bceb9e -https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-py_0.tar.bz2#cb83a3d6ecf73f50117635192414426a -https://conda.anaconda.org/conda-forge/linux-64/tempest-remap-2.2.0-h43474b4_0.conda#fd815765a86daf44db1e15c6f6edf5e6 -https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.10.57-hbc2ea52_17.conda#452c7b08c21eea2ef01f4fd364d6affc -https://conda.anaconda.org/conda-forge/noarch/bokeh-3.4.0-pyhd8ed1ab_0.conda#eebbbfdb7eb885ddc751c790c3d0ad64 -https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py311h1f0f07a_4.conda#1e105c1a8ea2163507726144b401eb1b -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.3.1-pyhd8ed1ab_0.conda#b0ad5ef44595ef37c3008fc04ecd2abf -https://conda.anaconda.org/conda-forge/linux-64/eccodes-2.30.2-h1f30a5c_0.conda#21ee8444a7f629924ea8cfe52a622cbd -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.4.2-nompi_h20110ff_0.conda#11f5169aeff54ad7277476be8ba19ff7 -https://conda.anaconda.org/conda-forge/linux-64/gdal-3.7.0-py311h281082f_2.conda#fde4fad3c517cc80f32995696f45198d -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.56.3-h98fae49_0.conda#620e754f4344f4c27259ff460a2b9c50 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.3-py311h54ef318_0.conda#014c115be880802d2372ac6ed665f526 +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.7.0-py311h07ce7c0_0.conda#73a9996e4b765455696b53bf74865b09 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.1-py311he1f765f_0.conda#eb7e2a849cd47483d7e9eeb728c7a8c5 +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.2-py311he06c224_0.conda#c90e2469d7512f3bba893533a82d7a02 +https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_1.conda#5abeaa41ec50d4d1421a8bc8fbc93054 +https://conda.anaconda.org/conda-forge/linux-64/tempest-remap-2.2.0-h13910d2_3.conda#7f10762cd62c8ad03323c4dc3ee544b1 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.2-pyhd8ed1ab_1.conda#e804c43f58255e977093a2298e442bb8 +https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.267-hbf3e495_6.conda#a6caf5a0d9ca940d95f21d40afe8f857 +https://conda.anaconda.org/conda-forge/noarch/bokeh-3.5.2-pyhd8ed1ab_0.conda#38d785787ec83d0431b3855328395113 +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py311h9f3472d_6.conda#ac7dc7f70f8d2c1d96ecb7e4cb196498 +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.8.2-pyhd8ed1ab_0.conda#44d22b5d98a219a4c35cafe9bf3b9ce2 +https://conda.anaconda.org/conda-forge/linux-64/eccodes-2.32.1-h35c6de3_0.conda#09d044f9206700e021916675a16d1e4d +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h4441c20_3.conda#1afc1e85414e228916732df2b8c5d93b +https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a +https://conda.anaconda.org/conda-forge/linux-64/libgdal-3.7.2-h6238fc3_5.conda#2fef4283b2bb45a66f8b81099d36721e +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py311h74b4f7c_0.conda#de8e36c9792f14eed7e11e672f03fbf0 https://conda.anaconda.org/conda-forge/noarch/myproxyclient-2.1.1-pyhd8ed1ab_0.conda#bcdbeb2b693eba886583a907840c6421 -https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.3-pyhd8ed1ab_0.conda#ca3d437c0ef2e87f63d085822c74c49a -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.4-nompi_py311h4d7c953_100.conda#c03492d0342e512e58aa2d6c5fdaaa91 +https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_0.conda#0b57b5368ab7fc7cdc9e3511fa867214 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.1-nompi_py311hae66bec_102.conda#87b59caea7db5b79766e0776953d8c66 +https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.14-ha41ecd1_2.conda#1a66c10f6a0da3dbd2f3a68127e7f6a0 https://conda.anaconda.org/conda-forge/noarch/pep8-naming-0.10.0-pyh9f0ad1d_0.tar.bz2#b3c5536e4f9f58a4b16adb6f1e11732d -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.6.2-pyha770c72_0.conda#61534ee57ffdf26d7b1b514d33daccc4 +https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.8.0-pyha770c72_1.conda#004cff3a7f6fafb0a041fb575de85185 https://conda.anaconda.org/conda-forge/noarch/pylint-celery-0.3-py_1.tar.bz2#e29456a611a62d3f26105a2f9c68f759 https://conda.anaconda.org/conda-forge/noarch/pylint-django-2.5.3-pyhd8ed1ab_0.tar.bz2#00d8853fb1f87195722ea6a582cc9b56 https://conda.anaconda.org/conda-forge/noarch/pylint-flask-0.6-py_0.tar.bz2#5a9afd3d0a61b08d59eed70fab859c1b -https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py311h1f0f07a_1.conda#cd36a89a048ad2bcc6d8b43f648fb1d0 -https://conda.anaconda.org/conda-forge/linux-64/r-base-4.1.3-hfabd6f2_9.conda#0ab4cf54fbddc0cc9ff260c6f77f8c84 -https://conda.anaconda.org/conda-forge/linux-64/rasterio-1.3.8-py311h41e4db2_0.conda#b35deb26af1d7e0d98438c8ac5c6b7b2 -https://conda.anaconda.org/conda-forge/linux-64/scikit-learn-1.4.1.post1-py311hc009520_0.conda#8c27600e1ee43ba6ceff93c6c0e09446 -https://conda.anaconda.org/conda-forge/noarch/sparse-0.15.1-pyhd8ed1ab_1.conda#780a42534f1429b802b5d1f51880b619 -https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.14.1-py311h1f0f07a_0.conda#11ea602c16ad004033edf648ce054f9e -https://conda.anaconda.org/conda-forge/noarch/tifffile-2024.2.12-pyhd8ed1ab_0.conda#d5c8bef52be4e70c48b1400eec3eecc8 -https://conda.anaconda.org/conda-forge/noarch/xarray-2024.2.0-pyhd8ed1ab_0.conda#8e25aab3323476d4fd0b5f6bad05d403 -https://conda.anaconda.org/conda-forge/noarch/zarr-2.17.1-pyhd8ed1ab_0.conda#8c67aa8327cbab135ea576568df3190c -https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.22.0-py311h320fe9a_1.conda#10d1806e20da040c58c36deddf51c70c -https://conda.anaconda.org/conda-forge/noarch/cf_xarray-0.9.0-pyhd8ed1ab_0.conda#33070a578d45591f242a254f78f86f10 -https://conda.anaconda.org/conda-forge/noarch/cmocean-3.1.3-pyhd8ed1ab_0.conda#671543f081d6be0b6b3e99b586386b44 -https://conda.anaconda.org/conda-forge/noarch/dask-jobqueue-0.8.5-pyhd8ed1ab_0.conda#abfb434fb6654f83d740428863ec85a8 -https://conda.anaconda.org/conda-forge/noarch/esgf-pyclient-0.3.1-pyhca7485f_3.conda#1d43833138d38ad8324700ce45a7099a -https://conda.anaconda.org/conda-forge/noarch/esmpy-8.4.2-pyhc1e730c_4.conda#ddcf387719b2e44df0cc4dd467643951 -https://conda.anaconda.org/conda-forge/linux-64/fiona-1.9.4-py311hbac4ec9_0.conda#1d3445f5f7fa002a1c149c405376f012 -https://conda.anaconda.org/conda-forge/linux-64/graphviz-8.1.0-h28d9a01_0.conda#33628e0e3de7afd2c8172f76439894cb -https://conda.anaconda.org/conda-forge/linux-64/libarrow-12.0.1-h657c46f_7_cpu.conda#4de6e12428b7018f1f8a1e8dda555243 -https://conda.anaconda.org/conda-forge/linux-64/magics-4.14.2-hd3d5bb6_0.conda#3c571b994b6ce2b4d2c7b98be77a8ebe +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py311h9f3472d_3.conda#a7c4169b1c920361597ddacb461350fd +https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 +https://conda.anaconda.org/conda-forge/linux-64/scikit-learn-1.5.1-py311hd632256_0.conda#f3928b428ad924ecb8f0e9b71124ed7f +https://conda.anaconda.org/conda-forge/noarch/seawater-3.3.5-pyhd8ed1ab_0.conda#8e1b01f05e8f97b0fcc284f957175903 +https://conda.anaconda.org/conda-forge/noarch/sparse-0.15.4-pyhd8ed1ab_0.conda#846d12530687ba836791dd54db1f45c5 +https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.14.2-py311h18e1886_0.conda#82c29bf38b3fb66da09736106609b5fe +https://conda.anaconda.org/conda-forge/noarch/tifffile-2024.8.30-pyhd8ed1ab_0.conda#330700f370f15c7c5660ef6865e9cc43 +https://conda.anaconda.org/conda-forge/noarch/xarray-2024.7.0-pyhd8ed1ab_0.conda#a7d4ff4bf1502eaba3fbbaeba66969ec +https://conda.anaconda.org/conda-forge/noarch/zarr-2.18.3-pyhd8ed1ab_0.conda#41abde21508578e02e3fd492e82a05cd +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.23.0-py311h14de704_1.conda#27e5956e552c6e71f56cb1ec042617a8 +https://conda.anaconda.org/conda-forge/noarch/cf_xarray-0.9.4-pyhd8ed1ab_0.conda#c8b6a3126f659e311d3b5c61be254d95 +https://conda.anaconda.org/conda-forge/noarch/chart-studio-1.1.0-pyh9f0ad1d_0.tar.bz2#acd9a12a35e5a0221bdf39eb6e4811dc +https://conda.anaconda.org/conda-forge/noarch/cmocean-4.0.3-pyhd8ed1ab_0.conda#53df00540de0348ed1b2a62684dd912b +https://conda.anaconda.org/conda-forge/noarch/dask-jobqueue-0.9.0-pyhd8ed1ab_0.conda#a201de7d36907f2355426e019168d337 +https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.1-pyhc1e730c_0.conda#25a9661177fd68bfdb4314fd658e5c3b +https://conda.anaconda.org/conda-forge/linux-64/gdal-3.7.2-py311h815a124_5.conda#84a14fd830b72b09ef886a23de557a16 +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/libarrow-15.0.2-h176673d_2_cpu.conda#c130ba0c765437749dbc37fa9de85ce5 +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.56.3-he3f83f7_1.conda#03bd1ddcc942867a19528877143b9852 +https://conda.anaconda.org/conda-forge/linux-64/magics-4.14.2-haee2765_1.conda#0c46d548472ee1b043c65d4ab4ad6a83 +https://conda.anaconda.org/conda-forge/noarch/multiurl-0.3.1-pyhd8ed1ab_0.conda#4dff4abb5728f7662ecaaa8bee3a0260 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.10.0-pyhd8ed1ab_0.conda#15b51397e0fe8ea7d7da60d83eb76ebc 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/ncl-6.6.2-hf70af60_47.conda#ee27133164cb9f5e74681bdb8839688f -https://conda.anaconda.org/conda-forge/linux-64/nco-5.1.6-hd62b316_0.conda#af7780f76ee37325d264327e21a478f5 +https://conda.anaconda.org/conda-forge/linux-64/ncl-6.6.2-he3b17a9_50.conda#a37fcb5a2da31cfebe6734b0fda20bd5 +https://conda.anaconda.org/conda-forge/linux-64/nco-5.2.8-hf7c1f58_0.conda#6cd18a9c6b8269b0cd101ba9cc3d02ab +https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.2-pyhd8ed1ab_0.conda#8dab97d8a9616e07d779782995710aed https://conda.anaconda.org/conda-forge/noarch/prospector-1.10.3-pyhd8ed1ab_0.conda#f551d4d859a1d70c6abff8310a655481 -https://conda.anaconda.org/conda-forge/linux-64/psyplot-1.4.3-py311h38be061_1.tar.bz2#f0c9a1067c03e8f05e53ef0c5ad5fab3 -https://conda.anaconda.org/conda-forge/noarch/py-xgboost-2.0.3-cuda118_pyhedeaf28_1.conda#f56da7b20ce1701d239cb82a4f91109f -https://conda.anaconda.org/conda-forge/noarch/r-abind-1.4_5-r41hc72bb7e_1004.tar.bz2#831186670e5786df30f8ddeb5a623c5a -https://conda.anaconda.org/conda-forge/linux-64/r-backports-1.4.1-r41h06615bd_1.tar.bz2#9a00c3283f8fb4bce68deffe08fbe09d -https://conda.anaconda.org/conda-forge/noarch/r-bigmemory.sri-0.1.6-r41hc72bb7e_0.tar.bz2#926471a5be30d287a25f2d10446d6066 -https://conda.anaconda.org/conda-forge/linux-64/r-brio-1.1.3-r41h06615bd_1.tar.bz2#3ba226bad01c3ebed18c4f7b022bf26d -https://conda.anaconda.org/conda-forge/linux-64/r-cli-3.6.1-r41h38f115c_0.conda#16ab92c7ff005c9ac48527b054831e45 -https://conda.anaconda.org/conda-forge/noarch/r-codetools-0.2_19-r41hc72bb7e_0.conda#401ac0ee6310d69deac481b2d2148458 -https://conda.anaconda.org/conda-forge/linux-64/r-colorspace-2.1_0-r41h133d619_0.conda#b6f5d77e5e0334a8adda752364bc760e -https://conda.anaconda.org/conda-forge/linux-64/r-contfrac-1.1_12-r41h06615bd_1003.tar.bz2#c9cbc66278bea99ce3ce9f8be9e8c0ad -https://conda.anaconda.org/conda-forge/noarch/r-cpp11-0.4.7-r41hc72bb7e_0.conda#a81541ceb9c2c3d40695e746b2777961 -https://conda.anaconda.org/conda-forge/noarch/r-crayon-1.5.2-r41hc72bb7e_1.tar.bz2#8cf94f6451aaadf3aa1119b29115b0c7 -https://conda.anaconda.org/conda-forge/linux-64/r-curl-4.3.3-r41hf9611b0_2.conda#c4047e3aa1b795a4cb5adbb5c59b3972 -https://conda.anaconda.org/conda-forge/linux-64/r-desolve-1.35-r41hb20cf53_0.conda#e475d0dbe391fa76fbf742ebee6ad449 -https://conda.anaconda.org/conda-forge/linux-64/r-digest-0.6.31-r41h38f115c_0.conda#eecdd9b7292e968428497bbeb9e68dfe -https://conda.anaconda.org/conda-forge/noarch/r-docopt-0.7.1-r41hc72bb7e_2.tar.bz2#38883e8f3f07ec1c63834a4401098b39 -https://conda.anaconda.org/conda-forge/linux-64/r-dotcall64-1.0_2-r41hac0b197_1.conda#1ae51773e2544dcde64619a03395be84 -https://conda.anaconda.org/conda-forge/noarch/r-evaluate-0.21-r41hc72bb7e_0.conda#c45a9a35d32b9d0f08298e3324ef15fe -https://conda.anaconda.org/conda-forge/linux-64/r-fansi-1.0.4-r41h133d619_0.conda#bdd2dca12682e87ebaee34af4250c718 -https://conda.anaconda.org/conda-forge/linux-64/r-farver-2.1.1-r41h7525677_1.tar.bz2#6c02f6ce0271b25d7936eeca4d06581c -https://conda.anaconda.org/conda-forge/linux-64/r-fs-1.6.2-r41ha503ecb_0.conda#7a1fbec6fb01e6384ec10eab4362cec2 -https://conda.anaconda.org/conda-forge/noarch/r-functional-0.6-r41ha770c72_1003.tar.bz2#b48ece4d136bc4af37b9320d40e9a37c -https://conda.anaconda.org/conda-forge/noarch/r-generics-0.1.3-r41hc72bb7e_1.tar.bz2#91a23d57270d474ab35b970ab153bdf4 -https://conda.anaconda.org/conda-forge/noarch/r-geomapdata-2.0_0-r41hc72bb7e_1.tar.bz2#2336d6504ec4e0f75c60e6176676eb49 -https://conda.anaconda.org/conda-forge/linux-64/r-git2r-0.31.0-r41hb760b46_0.conda#2912060dbb6b86babf9346e73d4feca2 -https://conda.anaconda.org/conda-forge/linux-64/r-glue-1.6.2-r41h06615bd_1.tar.bz2#7f4726fddb7ddc6354f299eeee77217d -https://conda.anaconda.org/conda-forge/linux-64/r-goftest-1.2_3-r41h06615bd_1.tar.bz2#ec4f56c61753d07694a08190a372d078 -https://conda.anaconda.org/conda-forge/linux-64/r-isoband-0.2.7-r41h38f115c_1.conda#2e385f2fb8a78b41ae7bf1854af45242 -https://conda.anaconda.org/conda-forge/noarch/r-iterators-1.0.14-r41hc72bb7e_1.tar.bz2#774088f2c449de9b334b0fc3f8a427a5 -https://conda.anaconda.org/conda-forge/linux-64/r-jsonlite-1.8.5-r41h57805ef_0.conda#6d41262a7460dd158346bc91673c23d7 -https://conda.anaconda.org/conda-forge/noarch/r-labeling-0.4.2-r41hc72bb7e_2.tar.bz2#83807ad3d6daa0c5e88ad3f4e8df4758 -https://conda.anaconda.org/conda-forge/linux-64/r-lattice-0.21_8-r41h133d619_0.conda#daab654f089ad0595f81b6e3ead9d22a -https://conda.anaconda.org/conda-forge/linux-64/r-lazyeval-0.2.2-r41h06615bd_3.tar.bz2#6eb0969ca6d2304194b7f9fad926b325 -https://conda.anaconda.org/conda-forge/linux-64/r-lmom-2.9-r41h8da6f51_1.tar.bz2#3b56e155cfc9611b7e1f0cba68ae795b -https://conda.anaconda.org/conda-forge/noarch/r-logging-0.10_108-r41ha770c72_3.tar.bz2#d0a6a38b084ec13c87eb72124e08b54c -https://conda.anaconda.org/conda-forge/linux-64/r-magrittr-2.0.3-r41h06615bd_1.tar.bz2#02e0e78aaffe86ff8d8824b9c6744f05 -https://conda.anaconda.org/conda-forge/linux-64/r-maps-3.4.1-r41h06615bd_1.conda#594a80fe9ed00caf16654ea76444751e -https://conda.anaconda.org/conda-forge/linux-64/r-mass-7.3_58.3-r41h133d619_0.conda#bc1c1fdac18d5799439626c6b6c1591a -https://conda.anaconda.org/conda-forge/linux-64/r-mba-0.1_0-r41h7525677_0.conda#3be8fba4c63dda03bf34ab17e44a0fab -https://conda.anaconda.org/conda-forge/linux-64/r-mime-0.12-r41h06615bd_1.tar.bz2#9482f375317377b6362deeb045759756 -https://conda.anaconda.org/conda-forge/noarch/r-nbclust-3.0.1-r41hc72bb7e_1.tar.bz2#84a70bc1ed3e58e7a6560a0e7dd99355 -https://conda.anaconda.org/conda-forge/linux-64/r-ncdf4-1.21-r41h0cc7714_3.conda#a0ad99afb73e0ef73bffe6195318df2e -https://conda.anaconda.org/conda-forge/linux-64/r-pcict-0.5_4.4-r41h133d619_0.conda#9c317abaabdf337e1790f1472343825d -https://conda.anaconda.org/conda-forge/noarch/r-pkgconfig-2.0.3-r41hc72bb7e_2.tar.bz2#fceb80e453285589b08efe53174ebe22 -https://conda.anaconda.org/conda-forge/noarch/r-praise-1.0.0-r41hc72bb7e_1006.tar.bz2#28ee09a92c8cb8ccb88205d6b768d3cc -https://conda.anaconda.org/conda-forge/linux-64/r-ps-1.7.5-r41h133d619_0.conda#b1f20d8306209420aac424ac6bd0889f -https://conda.anaconda.org/conda-forge/noarch/r-r.methodss3-1.8.2-r41hc72bb7e_1.tar.bz2#5cff1b8f457c863cc1025bb2b6396678 -https://conda.anaconda.org/conda-forge/noarch/r-r6-2.5.1-r41hc72bb7e_1.tar.bz2#04cf390ece28f6df5c096f78409a9b41 -https://conda.anaconda.org/conda-forge/noarch/r-rcolorbrewer-1.1_3-r41h785f33e_1.tar.bz2#cf94059b05cc67854cb7e704ea751d7f -https://conda.anaconda.org/conda-forge/linux-64/r-rcpp-1.0.10-r41h38f115c_0.conda#2ad2bd8a50f80e4f7420d7d6c83ea3d5 -https://conda.anaconda.org/conda-forge/noarch/r-remotes-2.4.2-r41hc72bb7e_1.tar.bz2#fee357b9269ee696fffdc18109ae8836 -https://conda.anaconda.org/conda-forge/linux-64/r-rlang-1.1.1-r41ha503ecb_0.conda#ce23a8ab960e759dab1e5b00f7967a72 -https://conda.anaconda.org/conda-forge/noarch/r-rpmg-2.2_3-r41hc72bb7e_2.tar.bz2#e13db79c37c068d0117708bccbe2ed9d -https://conda.anaconda.org/conda-forge/noarch/r-rstudioapi-0.14-r41hc72bb7e_1.tar.bz2#3a6725acc73d5a6c3b7d9dd3131b58d8 -https://conda.anaconda.org/conda-forge/noarch/r-snow-0.4_4-r41hc72bb7e_1.tar.bz2#aea71b97f7046d9ab359ec9a0e494a6d -https://conda.anaconda.org/conda-forge/linux-64/r-stringdist-0.9.10-r41h06615bd_0.tar.bz2#db0b1d297278d5ae2787ad6a3e7eadbb -https://conda.anaconda.org/conda-forge/linux-64/r-sys-3.4.2-r41h57805ef_0.conda#903dacb1ef1b8b381fd0fafc3f16b645 -https://conda.anaconda.org/conda-forge/linux-64/r-udunits2-0.13.2.1-r41h133d619_1.conda#77677c475c2422d56dad703fcd6c7401 -https://conda.anaconda.org/conda-forge/linux-64/r-utf8-1.2.3-r41h133d619_0.conda#a990f02e71f6cf7033e4d9b6db5839dc -https://conda.anaconda.org/conda-forge/linux-64/r-uuid-1.1_0-r41h06615bd_1.tar.bz2#a8758fdf001eba9f46350e9ab37471da -https://conda.anaconda.org/conda-forge/noarch/r-viridislite-0.4.1-r41hc72bb7e_1.tar.bz2#9fee3e06b7121f47a946b700ffedddc5 -https://conda.anaconda.org/conda-forge/noarch/r-withr-2.5.0-r41hc72bb7e_1.tar.bz2#23c0e5a3dc9258b9a06928097560adba -https://conda.anaconda.org/conda-forge/linux-64/r-xfun-0.39-r41ha503ecb_0.conda#555ee06849209b9471946da6f09bb98b -https://conda.anaconda.org/conda-forge/noarch/r-xmlparsedata-1.0.5-r41hc72bb7e_1.tar.bz2#921c0ef7104d8df0ab506f1bb81a062c -https://conda.anaconda.org/conda-forge/linux-64/r-yaml-2.3.7-r41h133d619_0.conda#4af88071a607237aa73a3cbd51788a39 -https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.22.0-py311h320fe9a_2.conda#e94b7f09b52628b89e66cdbd8c3029dd -https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_0.conda#0918a9201e824211cdf444dbf8d55752 -https://conda.anaconda.org/conda-forge/linux-64/cdo-2.2.0-he026af2_4.conda#6c00b0a21b3de8a149eee137e83465d3 -https://conda.anaconda.org/conda-forge/linux-64/imagemagick-7.1.1_15-pl5321hf48ede7_0.conda#53c9f7169b61e615d5f41c8d70a72c00 -https://conda.anaconda.org/conda-forge/noarch/iris-3.8.1-pyha770c72_0.conda#b08a116ef1607e7e960a4caa902e3a90 +https://conda.anaconda.org/conda-forge/linux-64/psyplot-1.5.1-py311h38be061_0.conda#b980793f61c0dc532b62faa0a0f0a271 +https://conda.anaconda.org/conda-forge/noarch/py-xgboost-2.1.1-cuda118_pyhf54b869_2.conda#35d99c71383da3c2f88a97d471f79e1f +https://conda.anaconda.org/conda-forge/noarch/pyroma-4.2-pyhd8ed1ab_0.conda#fe2aca9a5d4cb08105aefc451ef96950 +https://conda.anaconda.org/conda-forge/linux-64/r-base-4.2.3-h0887e52_8.conda#34cb3750c8a6da10a490e470f87e670b +https://conda.anaconda.org/conda-forge/linux-64/rasterio-1.3.9-py311h40fbdff_0.conda#dcee6ba4d1ac6af18827d0941b6a1b42 +https://conda.anaconda.org/conda-forge/noarch/requests-cache-1.2.1-pyhd8ed1ab_0.conda#c6089540fed51a9a829aa19590fa925b +https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.24.0-py311h044e617_2.conda#5ea04101a9da03787ba90e9c741eb818 +https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_2.conda#b713b116feaf98acdba93ad4d7f90ca1 +https://conda.anaconda.org/conda-forge/noarch/cads-api-client-1.3.2-pyhd8ed1ab_0.conda#3d0aba33db35ed85eb23ee6948ff79a0 +https://conda.anaconda.org/conda-forge/linux-64/cdo-2.3.0-h24bcfa3_0.conda#238311a432a8e49943d3348e279af714 +https://conda.anaconda.org/conda-forge/noarch/esgf-pyclient-0.3.1-pyhca7485f_3.conda#1d43833138d38ad8324700ce45a7099a +https://conda.anaconda.org/conda-forge/linux-64/fiona-1.9.5-py311hbac4ec9_0.conda#786d3808394b1bdfd3f41f2e2c67279e +https://conda.anaconda.org/conda-forge/linux-64/graphviz-8.1.0-h28d9a01_0.conda#33628e0e3de7afd2c8172f76439894cb +https://conda.anaconda.org/conda-forge/noarch/iris-3.10.0-pyha770c72_1.conda#b7212cd8247ce909631fdcb77015914a +https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-15.0.2-hac33072_2_cpu.conda#12951edff85582aedcd2db0b79393102 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-flight-15.0.2-hd42f311_2_cpu.conda#dcc3a1e12157bbbbae96029d9d34fd0e +https://conda.anaconda.org/conda-forge/linux-64/libarrow-gandiva-15.0.2-hd4ab825_2_cpu.conda#a4aa5cd69e0d1959f7c965437e7ac93d +https://conda.anaconda.org/conda-forge/linux-64/libparquet-15.0.2-h6a7eafb_2_cpu.conda#b06caaa4ef20db071dc832323701e5e3 https://conda.anaconda.org/conda-forge/noarch/lime-0.2.0.1-pyhd8ed1ab_1.tar.bz2#789ce01416721a5533fb74aa4361fd13 https://conda.anaconda.org/conda-forge/noarch/mapgenerator-1.0.7-pyhd8ed1ab_0.conda#d18db96ef2a920b0ecefe30282b0aecf -https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.16.2-pyhd8ed1ab_0.conda#5ab3248dd05c543dc631276455ef6a54 -https://conda.anaconda.org/conda-forge/linux-64/psy-simple-1.4.1-py311h38be061_2.tar.bz2#4c9101d329f6bc09c2617a80e3eb9c89 -https://conda.anaconda.org/conda-forge/noarch/py-cordex-0.7.0-pyhd8ed1ab_0.conda#7ad60b498674a9bff3ba8f3fb335e4f0 -https://conda.anaconda.org/conda-forge/linux-64/pyarrow-12.0.1-py311h39c9aba_7_cpu.conda#d513ab8d10ec5f3ee45b419c836195ec -https://conda.anaconda.org/conda-forge/linux-64/pydot-2.0.0-py311h38be061_0.conda#cdfd23a54a18f3c8d5320d7717f4ed52 -https://conda.anaconda.org/conda-forge/linux-64/r-askpass-1.1-r41h06615bd_3.tar.bz2#c8ec8683302ad9a2345cb31ab28e6c6b -https://conda.anaconda.org/conda-forge/linux-64/r-bigmemory-4.6.1-r41h7525677_1.tar.bz2#6a956b57b027b49b7a9ca48031a8bbd6 -https://conda.anaconda.org/conda-forge/linux-64/r-checkmate-2.2.0-r41h57805ef_0.conda#dc314ad76563387e70e0117c5398a15a -https://conda.anaconda.org/conda-forge/linux-64/r-climdex.pcic-1.1_11-r41h7525677_1.tar.bz2#06d19f02c04ff718b0c80c00b199976e -https://conda.anaconda.org/conda-forge/linux-64/r-diffobj-0.3.5-r41h06615bd_1.tar.bz2#5483435b5f12567c120966137ebb715f -https://conda.anaconda.org/conda-forge/linux-64/r-ellipsis-0.3.2-r41h06615bd_1.tar.bz2#2a63108f4bd95bacd3a9d60af4e7b933 -https://conda.anaconda.org/conda-forge/noarch/r-elliptic-1.4_0-r41hc72bb7e_3.tar.bz2#620fac0a4d3fdcb3b7f9620a121ca0e4 -https://conda.anaconda.org/conda-forge/noarch/r-foreach-1.5.2-r41hc72bb7e_1.tar.bz2#4ac59bcf363990abb478e9d358ea76ff -https://conda.anaconda.org/conda-forge/noarch/r-highr-0.10-r41hc72bb7e_0.conda#c5680c2ac76bcecf2c4c3d598fdea3a8 -https://conda.anaconda.org/conda-forge/noarch/r-lifecycle-1.0.3-r41hc72bb7e_1.tar.bz2#bed96e636722252c2a37c392c5994f9d -https://conda.anaconda.org/conda-forge/linux-64/r-mapproj-1.2.11-r41h133d619_0.conda#ac4d7a80cc1f6e67ed8eefcf6cccf21e -https://conda.anaconda.org/conda-forge/linux-64/r-matrix-1.5_4.1-r41h316c678_0.conda#ecc26aeb7a438e74438c60f4d6404f32 -https://conda.anaconda.org/conda-forge/noarch/r-munsell-0.5.0-r41hc72bb7e_1005.tar.bz2#102b2cf348101fd85afda3b26460b0f3 -https://conda.anaconda.org/conda-forge/noarch/r-ncdf4.helpers-0.3_6-r41hc72bb7e_1.tar.bz2#403ae973d19d3e2f2a4051aca3f12fc3 -https://conda.anaconda.org/conda-forge/linux-64/r-nlme-3.1_162-r41hac0b197_0.conda#76d797cfdad767d5bffaf053efad7f5d -https://conda.anaconda.org/conda-forge/linux-64/r-plyr-1.8.8-r41h7525677_0.tar.bz2#318c3b974ef18cc5c8e46069fd9cb27c -https://conda.anaconda.org/conda-forge/linux-64/r-processx-3.8.1-r41h133d619_0.conda#ce603fd804af2eee220329ab86be0c14 -https://conda.anaconda.org/conda-forge/noarch/r-r.oo-1.25.0-r41hc72bb7e_1.tar.bz2#080778ce659a006984a7a0dbdde9a57a -https://conda.anaconda.org/conda-forge/linux-64/r-rcpparmadillo-0.12.4.0.0-r41h08d816e_0.conda#fd288213a986ef5852160f49086b639b -https://conda.anaconda.org/conda-forge/noarch/r-rex-1.2.1-r41hc72bb7e_1.tar.bz2#e1af0f0eb2278c1a3330c2907eca8f44 -https://conda.anaconda.org/conda-forge/noarch/r-rprojroot-2.0.3-r41hc72bb7e_1.tar.bz2#9f5f482d79c7854068a01945f400a3bf -https://conda.anaconda.org/conda-forge/linux-64/r-sp-1.6_1-r41h57805ef_0.conda#b7943adfe3494b4c4dc8e3b58fc6602d -https://conda.anaconda.org/conda-forge/linux-64/r-spam-2.9_1-r41hb20cf53_1.conda#9eab4a6bfff4bddeee5ed946c47830fa -https://conda.anaconda.org/conda-forge/linux-64/r-timechange-0.2.0-r41h38f115c_0.conda#04a4229419d779a1e27395d70d493571 -https://conda.anaconda.org/conda-forge/linux-64/r-xml2-1.3.4-r41h1ad5fc0_1.conda#82c1446591783493d65273a158e8ce28 -https://conda.anaconda.org/conda-forge/linux-64/r-zoo-1.8_12-r41h133d619_0.conda#1d432d2eba171727afd03507faa5e2f6 -https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_0.conda#fd31ebf5867914de597f9961c478e482 -https://conda.anaconda.org/conda-forge/noarch/xesmf-0.8.4-pyhd8ed1ab_1.conda#9fff981af43f3226bac0c91e9bf67f2e -https://conda.anaconda.org/conda-forge/noarch/xgboost-2.0.3-cuda118_pyh5ebfdf7_1.conda#9ca04fca5cb67e6f2e51d0eb0277cf67 -https://conda.anaconda.org/conda-forge/noarch/dask-expr-1.0.4-pyhd8ed1ab_0.conda#7c68457355bc3c6ae21cc2c17f576d76 -https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.16.2-pyhd8ed1ab_0.conda#7a0bfebd69213722427cb61b077b4187 +https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.16.4-pyhd8ed1ab_1.conda#e2d2abb421c13456a9a9f80272fdf543 +https://conda.anaconda.org/conda-forge/linux-64/psy-simple-1.5.1-py311h38be061_0.conda#65a408ecf84afc51b1d437f888d8e80f +https://conda.anaconda.org/conda-forge/noarch/py-cordex-0.8.0-pyhd8ed1ab_0.conda#fba377622e74ee0bbeb8ccae9fa593d3 +https://conda.anaconda.org/conda-forge/noarch/r-abind-1.4_5-r42hc72bb7e_1005.conda#f2744985b083b1bbffd4df19437cf1e8 +https://conda.anaconda.org/conda-forge/linux-64/r-backports-1.5.0-r42hb1dbf0f_0.conda#d879e1fbd80113312364a5db3682c789 +https://conda.anaconda.org/conda-forge/noarch/r-bigmemory.sri-0.1.8-r42hc72bb7e_0.conda#383f36b5a0b7dd7c467aa1b6b5fe7307 +https://conda.anaconda.org/conda-forge/linux-64/r-cli-3.6.3-r42ha18555a_0.conda#93fc8055b8aee751e201604a02d7d06f +https://conda.anaconda.org/conda-forge/noarch/r-codetools-0.2_20-r42hc72bb7e_0.conda#a9e9276ab95d053b9db56159cfeda2c9 +https://conda.anaconda.org/conda-forge/linux-64/r-colorspace-2.1_0-r42h57805ef_1.conda#68ec691b072953b496ca1a4d83b2bc3d +https://conda.anaconda.org/conda-forge/linux-64/r-contfrac-1.1_12-r42h57805ef_1004.conda#bc308888aa4b4fb4e37a7a17fdc911c9 +https://conda.anaconda.org/conda-forge/noarch/r-cpp11-0.4.7-r42hc72bb7e_0.conda#941d7bcf2b94a682419ea1fbf6789d1f +https://conda.anaconda.org/conda-forge/noarch/r-crayon-1.5.3-r42hc72bb7e_0.conda#4a74a6114bbea1ad8d488e99b83df3da +https://conda.anaconda.org/conda-forge/noarch/r-dbi-1.2.3-r42hc72bb7e_0.conda#b283bb5431a4b960cfa3f82043d1437b +https://conda.anaconda.org/conda-forge/linux-64/r-desolve-1.40-r42hd9ac46e_0.conda#7232f8b5707fc9739cb2f8fdc5b4b64d +https://conda.anaconda.org/conda-forge/linux-64/r-digest-0.6.36-r42ha18555a_0.conda#332551d9a37018826d528cf16701bd2b +https://conda.anaconda.org/conda-forge/noarch/r-docopt-0.7.1-r42hc72bb7e_3.conda#99be998b67c40ef6eb1a5af90e307c1d +https://conda.anaconda.org/conda-forge/linux-64/r-dotcall64-1.1_1-r42h61816a4_0.conda#d83332ff8d9912151d9a4b4972fd1da0 +https://conda.anaconda.org/conda-forge/noarch/r-evaluate-0.24.0-r42hc72bb7e_0.conda#c2a50c427d0febc367122a875239e771 +https://conda.anaconda.org/conda-forge/linux-64/r-fansi-1.0.6-r42h57805ef_0.conda#c12524190662098e2e8a245a3d1bc7dc +https://conda.anaconda.org/conda-forge/linux-64/r-farver-2.1.2-r42ha18555a_0.conda#475d7bcc6de3c5851b112675eb55f497 +https://conda.anaconda.org/conda-forge/noarch/r-functional-0.6-r42ha770c72_1004.conda#9e27c34589b883accd340d651bdeaa02 +https://conda.anaconda.org/conda-forge/noarch/r-generics-0.1.3-r42hc72bb7e_2.conda#c492355d73e184353c82b62f5087a601 +https://conda.anaconda.org/conda-forge/noarch/r-geomapdata-2.0_2-r42hc72bb7e_0.conda#799a671bad7a89ac1d9da5cb98f75367 +https://conda.anaconda.org/conda-forge/linux-64/r-git2r-0.33.0-r42hbae1c7c_0.conda#2cdc8746b3283f02e5ba387bcfc51aa1 +https://conda.anaconda.org/conda-forge/linux-64/r-glue-1.7.0-r42h57805ef_0.conda#eab803a28d66337ae3732b04c5f5604f +https://conda.anaconda.org/conda-forge/linux-64/r-goftest-1.2_3-r42h57805ef_2.conda#4210e40893bbac7533714429ac4d0fe9 +https://conda.anaconda.org/conda-forge/linux-64/r-isoband-0.2.7-r42ha503ecb_2.conda#44979df954a15195470f336cd18b5eb6 +https://conda.anaconda.org/conda-forge/noarch/r-iterators-1.0.14-r42hc72bb7e_2.conda#616ab7b008326d3d76d59ba35b3fb592 +https://conda.anaconda.org/conda-forge/linux-64/r-jsonlite-1.8.8-r42h57805ef_0.conda#d0b27ba963de139270a7b53f897afdf6 +https://conda.anaconda.org/conda-forge/linux-64/r-kernsmooth-2.23_24-r42hc2011d3_0.conda#aac4c7efaa5f2f7013cff5dabe0255eb +https://conda.anaconda.org/conda-forge/noarch/r-labeling-0.4.3-r42hc72bb7e_0.conda#b9b940011dd81d8b60859fcd0d9775f4 +https://conda.anaconda.org/conda-forge/linux-64/r-lattice-0.22_6-r42h57805ef_0.conda#93cee3961cc5277443a3e437f6991010 +https://conda.anaconda.org/conda-forge/linux-64/r-lazyeval-0.2.2-r42h57805ef_4.conda#109112b1c26d932414daa139a45d3a69 +https://conda.anaconda.org/conda-forge/linux-64/r-lmom-3.0-r42h61816a4_0.conda#0cffcf07f72a3be278b236e3b2f451c9 +https://conda.anaconda.org/conda-forge/noarch/r-logging-0.10_108-r42ha770c72_4.conda#d9980750f18496909aa8327037a43f8b +https://conda.anaconda.org/conda-forge/linux-64/r-magrittr-2.0.3-r42h57805ef_2.conda#ea3b13247660dd534a745a26f8d02365 +https://conda.anaconda.org/conda-forge/linux-64/r-maps-3.4.2-r42h57805ef_0.conda#a0367e4720045d5d17cb841a415ada1e +https://conda.anaconda.org/conda-forge/linux-64/r-mass-7.3_60.0.1-r42h57805ef_0.conda#0427fa6c4da6a4b2e43d8dfd022e933b +https://conda.anaconda.org/conda-forge/linux-64/r-mba-0.1_0-r42ha503ecb_1.conda#ab0ffee07ebd556b0e0119017439218a +https://conda.anaconda.org/conda-forge/noarch/r-nbclust-3.0.1-r42hc72bb7e_2.conda#fffd3a5ced3a6949fe7a20af1ff4b2c6 +https://conda.anaconda.org/conda-forge/linux-64/r-ncdf4-1.22-r42h5647f33_0.conda#d23e6cd8fe41079eb1421b6a6d1f1c67 +https://conda.anaconda.org/conda-forge/linux-64/r-pcict-0.5_4.4-r42h57805ef_1.conda#6e5770da5c174a2617096cbc2b8d96f4 +https://conda.anaconda.org/conda-forge/noarch/r-pkgconfig-2.0.3-r42hc72bb7e_3.conda#469b66f84a5d234689b423c9821b188c +https://conda.anaconda.org/conda-forge/linux-64/r-proxy-0.4_27-r42h57805ef_2.conda#1d2ea39d52acbcc9d7db8a0abe5fdf7b +https://conda.anaconda.org/conda-forge/linux-64/r-ps-1.7.6-r42h57805ef_0.conda#3a592c79e0fade3a0c3574696fa143a3 +https://conda.anaconda.org/conda-forge/noarch/r-r.methodss3-1.8.2-r42hc72bb7e_2.conda#305fe9f97f7598d9722c76d6be7bf794 +https://conda.anaconda.org/conda-forge/noarch/r-r6-2.5.1-r42hc72bb7e_2.conda#1473a12b55128f8ac776ae5595a4d0cb +https://conda.anaconda.org/conda-forge/noarch/r-rcolorbrewer-1.1_3-r42h785f33e_2.conda#b7b475c73493f70cbbb9d7213b94aed1 +https://conda.anaconda.org/conda-forge/linux-64/r-rcpp-1.0.12-r42h7df8631_0.conda#096448d673973c0e45b9d803da251971 +https://conda.anaconda.org/conda-forge/noarch/r-remotes-2.5.0-r42hc72bb7e_0.conda#c595028f27588c6ff242fcb0dab79363 +https://conda.anaconda.org/conda-forge/linux-64/r-rlang-1.1.4-r42ha18555a_0.conda#ab6364a17b32268b82c46f09695a9cc9 +https://conda.anaconda.org/conda-forge/noarch/r-rpmg-2.2_7-r42hc72bb7e_0.conda#9e34ca8c73b895781e13b1d399105f35 +https://conda.anaconda.org/conda-forge/noarch/r-rprojroot-2.0.4-r42hc72bb7e_0.conda#c2bb0aa15018f8d9a4bc7b9e459dc94f +https://conda.anaconda.org/conda-forge/noarch/r-snow-0.4_4-r42hc72bb7e_2.conda#97cc50b630391cbc89ea70425ebb6ade +https://conda.anaconda.org/conda-forge/linux-64/r-udunits2-0.13.2.1-r42h57805ef_3.conda#56d551dc25582293fed533026356a79e +https://conda.anaconda.org/conda-forge/linux-64/r-utf8-1.2.4-r42h57805ef_0.conda#1da2e3bcbf75c6ddc3466941d88ff93f +https://conda.anaconda.org/conda-forge/linux-64/r-uuid-1.2_0-r42h57805ef_0.conda#f7585e68687b274880bbd68f34c0524d +https://conda.anaconda.org/conda-forge/noarch/r-viridislite-0.4.2-r42hc72bb7e_1.conda#e7a6483f639fb958747100bd17550ed6 +https://conda.anaconda.org/conda-forge/noarch/r-withr-3.0.0-r42hc72bb7e_0.conda#972eaab581c25fff9ea6986aa6ab281a +https://conda.anaconda.org/conda-forge/linux-64/r-xfun-0.45-r42ha18555a_0.conda#9e13c392bfcee4a261e4b513d6d862e7 +https://conda.anaconda.org/conda-forge/noarch/r-xmlparsedata-1.0.5-r42hc72bb7e_2.conda#2f3614450b54f222c1eff786ec2a45ec +https://conda.anaconda.org/conda-forge/linux-64/r-yaml-2.3.8-r42h57805ef_0.conda#97f60a93ca12f4fdd5f44049dcee4345 +https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_2.conda#a79d8797f62715255308d92d3a91ef2e +https://conda.anaconda.org/conda-forge/noarch/xesmf-0.8.7-pyhd8ed1ab_0.conda#42301f78a4c6d2500f891b9723160d5c +https://conda.anaconda.org/conda-forge/noarch/xgboost-2.1.1-cuda118_pyh98e67c5_2.conda#8c61e30dd8325ea1598e9d0af3eb2582 +https://conda.anaconda.org/conda-forge/noarch/cdsapi-0.7.2-pyhd8ed1ab_1.conda#0b896fef433a120a80f37e4ad57a3850 +https://conda.anaconda.org/conda-forge/linux-64/imagemagick-7.1.1_19-pl5321h7e74ff9_0.conda#a4a0ce7caba20cae61aac9aeacbd76c2 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-15.0.2-hac33072_2_cpu.conda#48c711b4e07664ec7b245a9664be60a1 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-flight-sql-15.0.2-h9241762_2_cpu.conda#97e46f0f20157e19487ca3e65100247a +https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.16.4-hd8ed1ab_1.conda#37cec2cf68f4c09563d8bc833791096b +https://conda.anaconda.org/conda-forge/linux-64/psy-maps-1.5.0-py311h38be061_1.conda#d7901c26884613539e958c10e9973413 +https://conda.anaconda.org/conda-forge/linux-64/psy-reg-1.5.0-py311h38be061_1.conda#1077e7fc4aa594c5896cf8b8fa672f88 +https://conda.anaconda.org/conda-forge/linux-64/pydot-3.0.1-py311h38be061_0.conda#036ce626484c4458cc99b6d55bb036eb +https://conda.anaconda.org/conda-forge/noarch/python-cdo-1.6.0-pyhd8ed1ab_0.conda#3fd1a0b063c1fbbe4b7bd5a5a7601e84 +https://conda.anaconda.org/conda-forge/linux-64/r-bigmemory-4.6.4-r42ha503ecb_0.conda#12b6fa8fe80a6494a948c6ea2f34340d +https://conda.anaconda.org/conda-forge/linux-64/r-checkmate-2.3.1-r42h57805ef_0.conda#9febce7369c72d991e2399d7d28f3390 +https://conda.anaconda.org/conda-forge/linux-64/r-class-7.3_22-r42h57805ef_1.conda#97476afece904fbbe73762b9cf8c4d83 +https://conda.anaconda.org/conda-forge/linux-64/r-climdex.pcic-1.1_11-r42ha503ecb_2.conda#cff1d95fe315f109a1f01a7ef112fdd6 +https://conda.anaconda.org/conda-forge/noarch/r-desc-1.4.3-r42hc72bb7e_0.conda#8c535581a9a3a1e2a0f5ef6d7e4d6a7f +https://conda.anaconda.org/conda-forge/linux-64/r-ellipsis-0.3.2-r42h57805ef_2.conda#1673236a1895ca5cce15c888435ad2f9 +https://conda.anaconda.org/conda-forge/noarch/r-elliptic-1.4_0-r42hc72bb7e_4.conda#8388c500125813b91332f9d3720f3471 +https://conda.anaconda.org/conda-forge/noarch/r-foreach-1.5.2-r42hc72bb7e_2.conda#16f5453742f10816f2964a2b05bc20d3 +https://conda.anaconda.org/conda-forge/noarch/r-highr-0.11-r42hc72bb7e_0.conda#2edda9394885683f7cad76673eeb2025 +https://conda.anaconda.org/conda-forge/noarch/r-lifecycle-1.0.4-r42hc72bb7e_0.conda#7d00a412d44005a8714c192589143b81 +https://conda.anaconda.org/conda-forge/linux-64/r-mapproj-1.2.11-r42h57805ef_1.conda#af943f7f8db88fddf340980fa53ed3e5 +https://conda.anaconda.org/conda-forge/linux-64/r-matrix-1.6_5-r42h316c678_0.conda#4f52f9c56146c8692503a7d2057ba7ba +https://conda.anaconda.org/conda-forge/noarch/r-munsell-0.5.1-r42hc72bb7e_0.conda#e7036a0b18f2ee6b108fe12b908b18f3 +https://conda.anaconda.org/conda-forge/noarch/r-ncdf4.helpers-0.3_6-r42hc72bb7e_2.conda#c7180e87be344175853f1ebfcdce04d0 +https://conda.anaconda.org/conda-forge/linux-64/r-nlme-3.1_165-r42hbcb9c34_0.conda#a83fa459c53c4674ee394b80b7b2fbd5 +https://conda.anaconda.org/conda-forge/linux-64/r-plyr-1.8.9-r42ha503ecb_0.conda#9b63113ec0c6f1a69c53f77d8f8fa4dc +https://conda.anaconda.org/conda-forge/linux-64/r-processx-3.8.4-r42h57805ef_0.conda#97f10f23ade292cb369d5635b119befa +https://conda.anaconda.org/conda-forge/noarch/r-r.oo-1.26.0-r42hc72bb7e_0.conda#8d5929eebbe7d431fa3f989874b090eb +https://conda.anaconda.org/conda-forge/linux-64/r-rcpparmadillo-0.12.8.4.0-r42h58a4165_0.conda#49973fea110c814e316d8277bb08e516 +https://conda.anaconda.org/conda-forge/noarch/r-rex-1.2.1-r42hc72bb7e_2.conda#b45f1b94fd106c19eb79303b24dc9a7c +https://conda.anaconda.org/conda-forge/linux-64/r-sp-2.1_4-r42hb1dbf0f_0.conda#681bb0a7290d86f9f8bf8dc816f114c0 +https://conda.anaconda.org/conda-forge/linux-64/r-spam-2.10_0-r42h9f9f741_0.conda#159d8ab59a2777a26a739f8090b5a80c +https://conda.anaconda.org/conda-forge/linux-64/r-timechange-0.3.0-r42ha503ecb_0.conda#3d62906e9c1fecf61370a3ad6e808e5e +https://conda.anaconda.org/conda-forge/linux-64/r-units-0.8_5-r42ha503ecb_0.conda#90b4c99051df9db2f825d6259dcf12cd +https://conda.anaconda.org/conda-forge/linux-64/r-wk-0.9.1-r42ha503ecb_0.conda#3c5ea742d2069f956ea6ff02a2aadce1 +https://conda.anaconda.org/conda-forge/linux-64/r-xml2-1.3.6-r42hbfba7a4_1.conda#5c3d7a89a2d5e1c0885f92d1aa6fde30 +https://conda.anaconda.org/conda-forge/linux-64/r-zoo-1.8_12-r42h57805ef_1.conda#5367d265c0c9c151dea85f1ccb515ec1 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-15.0.2-h9241762_2_cpu.conda#c18bbb60ed10774dbf9ea86484728a74 +https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.16.4-hd8ed1ab_1.conda#ab83e3b9ca2b111d8f332e9dc8b2170f https://conda.anaconda.org/conda-forge/noarch/prov-2.0.0-pyhd3deb0d_0.tar.bz2#aa9b3ad140f6c0668c646f32e20ccf82 -https://conda.anaconda.org/conda-forge/noarch/psy-maps-1.4.2-pyhd8ed1ab_0.tar.bz2#3ed13103dfd46f71dc870d188bd0b276 -https://conda.anaconda.org/conda-forge/linux-64/psy-reg-1.4.0-py311h38be061_3.conda#6f7871722c07922028043144e8873b37 +https://conda.anaconda.org/conda-forge/linux-64/r-akima-0.6_3.4-r42h61816a4_2.conda#8536251313f441c4d70ff11ad976d294 +https://conda.anaconda.org/conda-forge/noarch/r-callr-3.7.6-r42hc72bb7e_0.conda#4fb1765d6dc531936db81af3f6be316a +https://conda.anaconda.org/conda-forge/noarch/r-doparallel-1.0.17-r42hc72bb7e_2.conda#1cddfbaade4416f0234670391bb31ba2 +https://conda.anaconda.org/conda-forge/linux-64/r-e1071-1.7_14-r42ha503ecb_0.conda#6e147da5592263573409bce2e9c39b3c +https://conda.anaconda.org/conda-forge/noarch/r-gtable-0.3.5-r42hc72bb7e_0.conda#b5cff9c0564c9fcd8b62632430a0cee5 +https://conda.anaconda.org/conda-forge/noarch/r-hypergeo-1.2_13-r42hc72bb7e_1004.conda#7a207a992c606168044d13dcffd80ad4 +https://conda.anaconda.org/conda-forge/noarch/r-knitr-1.47-r42hc72bb7e_0.conda#0a20a2f6546bc0cde246c53a92a7964d +https://conda.anaconda.org/conda-forge/linux-64/r-lmoments-1.3_1-r42h7ce84a7_5.conda#e727f948785d9aad6426e912e135f935 +https://conda.anaconda.org/conda-forge/linux-64/r-lubridate-1.9.3-r42h57805ef_0.conda#01fd816e4231ae7cf2833e5661a92611 +https://conda.anaconda.org/conda-forge/linux-64/r-mgcv-1.9_1-r42h316c678_0.conda#5c3d738118f5948f6cc29ccb63d6e2ff +https://conda.anaconda.org/conda-forge/noarch/r-r.utils-2.12.3-r42hc72bb7e_0.conda#81f505dec8850e227d9b2a7e88fa505f +https://conda.anaconda.org/conda-forge/linux-64/r-reshape-0.8.9-r42hc72bb7e_2.conda#17e75917161bf824248cc54a412b4394 +https://conda.anaconda.org/conda-forge/linux-64/r-s2-1.1.6-r42h5eac2b3_0.conda#c3835d051156c3eacce21caec8061594 +https://conda.anaconda.org/conda-forge/noarch/r-scales-1.3.0-r42hc72bb7e_0.conda#0af4021fe6d0047bbf7a34bf21c50bdd +https://conda.anaconda.org/conda-forge/linux-64/r-specsverification-0.5_3-r42h7525677_2.tar.bz2#1521b8a303852af0496245e368d3c61c +https://conda.anaconda.org/conda-forge/linux-64/r-vctrs-0.6.5-r42ha503ecb_0.conda#5689030c60302fb5bb7a48b54c11dbe8 +https://conda.anaconda.org/conda-forge/linux-64/pyarrow-15.0.2-py311h78dcc79_2_cpu.conda#6f20003320c613f2505cf248bfce48f6 +https://conda.anaconda.org/conda-forge/linux-64/r-classint-0.4_10-r42h61816a4_0.conda#668a2f3e36b373878e698b1387bea45b +https://conda.anaconda.org/conda-forge/noarch/r-cyclocomp-1.1.1-r42hc72bb7e_0.conda#6bd41a85dc43541400311eca03d4e2d4 +https://conda.anaconda.org/conda-forge/noarch/r-gridextra-2.3-r42hc72bb7e_1005.conda#da116b29105a8d48571975a185e9bb94 +https://conda.anaconda.org/conda-forge/noarch/r-lmomco-2.5.1-r42hc72bb7e_0.conda#6efbdfe5d41b3ef5652be1ea2e0a6e3c +https://conda.anaconda.org/conda-forge/noarch/r-multiapply-2.1.4-r42hc72bb7e_1.conda#7aa5a8ca336904418caeb7395fd867e6 +https://conda.anaconda.org/conda-forge/noarch/r-pillar-1.9.0-r42hc72bb7e_1.conda#07d5ce8e710897745f14c951ff947cdd +https://conda.anaconda.org/conda-forge/linux-64/r-purrr-1.0.2-r42h57805ef_0.conda#7985dada48799b7814ca069794d0b1a3 +https://conda.anaconda.org/conda-forge/noarch/r-r.cache-0.16.0-r42hc72bb7e_2.conda#34daac4e8faee056f15abdee858fc721 +https://conda.anaconda.org/conda-forge/noarch/dask-expr-1.1.13-pyhd8ed1ab_0.conda#b77166a6032a2b8e52b3fee90d62ea4d https://conda.anaconda.org/conda-forge/noarch/pyarrow-hotfix-0.6-pyhd8ed1ab_0.conda#ccc06e6ef2064ae129fab3286299abda -https://conda.anaconda.org/conda-forge/noarch/python-cdo-1.6.0-pyhd8ed1ab_0.conda#3fd1a0b063c1fbbe4b7bd5a5a7601e84 -https://conda.anaconda.org/conda-forge/linux-64/r-akima-0.6_2.3-r41h92ddd45_0.tar.bz2#bac0b7627ef744c98f4bc48885f52e72 -https://conda.anaconda.org/conda-forge/noarch/r-callr-3.7.3-r41hc72bb7e_0.tar.bz2#af0891cc9b87e2954c9a3c66f144992d -https://conda.anaconda.org/conda-forge/noarch/r-desc-1.4.2-r41hc72bb7e_1.tar.bz2#35a5cf7ea666e2c13cb6b4a03282e2a3 -https://conda.anaconda.org/conda-forge/noarch/r-doparallel-1.0.17-r41hc72bb7e_1.tar.bz2#a7d2c685223b6538ecac271ecbb2c199 -https://conda.anaconda.org/conda-forge/noarch/r-gtable-0.3.3-r41hc72bb7e_0.conda#f18da5771f11c05df08eed41095d56a5 -https://conda.anaconda.org/conda-forge/noarch/r-hypergeo-1.2_13-r41hc72bb7e_1003.tar.bz2#e0f2b02808243f63bc8c0d8dc2054f37 -https://conda.anaconda.org/conda-forge/noarch/r-knitr-1.43-r41hc72bb7e_0.conda#9a1b185e1cf8286af819f0def11fbafa -https://conda.anaconda.org/conda-forge/linux-64/r-lmoments-1.3_1-r41h37cf8d7_4.tar.bz2#30a0f4289a2570c3b4eccb5c62e0466e -https://conda.anaconda.org/conda-forge/linux-64/r-lubridate-1.9.2-r41h133d619_1.conda#995c8749407f4276d91833c54ea527e7 -https://conda.anaconda.org/conda-forge/linux-64/r-mgcv-1.8_42-r41he1ae0d6_0.conda#41523ce65336ebc723d7aa4e80cd8d27 -https://conda.anaconda.org/conda-forge/linux-64/r-openssl-2.0.6-r41habfbb5e_0.conda#d10bafe86b53c0b74659616a2db7528e -https://conda.anaconda.org/conda-forge/noarch/r-r.utils-2.12.2-r41hc72bb7e_0.tar.bz2#302c316e29b7f426fa2de6f1f21dec75 -https://conda.anaconda.org/conda-forge/linux-64/r-reshape-0.8.9-r41hc72bb7e_1.tar.bz2#acdda9b65715d9b2d7f928145605d283 -https://conda.anaconda.org/conda-forge/noarch/r-scales-1.2.1-r41hc72bb7e_1.tar.bz2#2a557fcc9f60e56e788a6d1293bc8701 -https://conda.anaconda.org/conda-forge/linux-64/r-specsverification-0.5_3-r41ha503ecb_3.conda#2bc51f0d44b98092ba57cf2f8671b490 -https://conda.anaconda.org/conda-forge/linux-64/r-splancs-2.01_43-r41h8da6f51_1.tar.bz2#3a6aad0706541141d10e3b514467a080 -https://conda.anaconda.org/conda-forge/linux-64/r-vctrs-0.6.2-r41ha503ecb_0.conda#1f7610a1863648cab254a9f85bd29dcd -https://conda.anaconda.org/conda-forge/noarch/dask-2024.3.1-pyhd8ed1ab_0.conda#e3f23f17022881c62e75ddbab7a61f9e -https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.16.2-pyhd8ed1ab_0.conda#e14e35cc4a5c90694bb41c5317b576a8 -https://conda.anaconda.org/conda-forge/noarch/r-cyclocomp-1.1.0-r41hc72bb7e_1005.tar.bz2#800e1da5bf774be48934b8865dd78d33 -https://conda.anaconda.org/conda-forge/noarch/r-gridextra-2.3-r41hc72bb7e_1004.tar.bz2#71ebed7e976df735ff3443bb88bd154f -https://conda.anaconda.org/conda-forge/noarch/r-httr-1.4.6-r41hc72bb7e_0.conda#53dbb769c96782db54bf2d414fc9b239 -https://conda.anaconda.org/conda-forge/noarch/r-lmomco-2.4.9-r41hc72bb7e_0.conda#6549671297485ce34797eb4d59fa3657 -https://conda.anaconda.org/conda-forge/noarch/r-multiapply-2.1.4-r41hc72bb7e_0.conda#8e3493535d013080457c90ce0d81714f -https://conda.anaconda.org/conda-forge/noarch/r-pillar-1.9.0-r41hc72bb7e_0.conda#fb91965be4ce5aaf59db0452582f5cea -https://conda.anaconda.org/conda-forge/noarch/r-pkgload-1.3.2-r41hc72bb7e_0.tar.bz2#e23a1a8420ab52056d86a6f9691d23fa -https://conda.anaconda.org/conda-forge/linux-64/r-purrr-1.0.1-r41h133d619_0.conda#d7404238cac0da3c97dc08503d116a2f -https://conda.anaconda.org/conda-forge/noarch/r-r.cache-0.16.0-r41hc72bb7e_1.tar.bz2#aef451160d655cc630d8038d934dced3 -https://conda.anaconda.org/conda-forge/noarch/iris-esmf-regrid-0.9.0-pyhd8ed1ab_0.conda#570f2c6e387fd6dac5356a5152f91b3f -https://conda.anaconda.org/conda-forge/noarch/r-climprojdiags-0.3.2-r41hc72bb7e_0.conda#9922b863cd10035cbb75e3c2edae64a7 -https://conda.anaconda.org/conda-forge/linux-64/r-tibble-3.2.1-r41h133d619_1.conda#3ae9b78fb1d8a44deed24a27cce33ebf -https://conda.anaconda.org/conda-forge/noarch/esmvalcore-2.10.0-pyhd8ed1ab_0.conda#18bc5ed0e0583cb0b212927795debea7 -https://conda.anaconda.org/conda-forge/noarch/r-ggplot2-3.4.2-r41hc72bb7e_0.conda#c2b04f4ff351d84bf51fd5a77b5c9b6c -https://conda.anaconda.org/conda-forge/noarch/r-rematch2-2.1.2-r41hc72bb7e_2.tar.bz2#f67eae0562ffc808b82f1590776c25f5 -https://conda.anaconda.org/conda-forge/noarch/r-styler-1.10.1-r41hc72bb7e_0.conda#c12b81cff8bb8745ffbe7aeb9dfd795f -https://conda.anaconda.org/conda-forge/linux-64/r-tlmoments-0.7.5.3-r41h38f115c_0.conda#d6992015dff73f17ee76a9380b367b9f -https://conda.anaconda.org/conda-forge/noarch/r-viridis-0.6.3-r41hc72bb7e_0.conda#8502ff3a06bb92a4bba056127965f9d9 -https://conda.anaconda.org/conda-forge/noarch/r-waldo-0.5.1-r41hc72bb7e_0.conda#70a78bfe3a730e73308eb0858a78476f -https://conda.anaconda.org/conda-forge/linux-64/r-fields-14.1-r41hac0b197_1.conda#3178d2a57796f6462ea7457ba4b6447c -https://conda.anaconda.org/conda-forge/noarch/r-spei-1.8.1-r41hc72bb7e_0.conda#c928901be40f7694f1237570a148416c -https://conda.anaconda.org/conda-forge/linux-64/r-testthat-3.1.8-r41ha503ecb_0.conda#d0c8f9f62ce32fad40fa9ec17dd21ee0 -https://conda.anaconda.org/conda-forge/linux-64/r-geomap-2.5_0-r41h06615bd_1.tar.bz2#dabe8f942d619075cbd13c1481c8b538 -https://conda.anaconda.org/conda-forge/noarch/r-lintr-3.0.2-r41hc72bb7e_0.tar.bz2#769c2305486b74fd61d85bfef2296f27 -https://conda.anaconda.org/conda-forge/noarch/r-s2dverification-2.10.3-r41hc72bb7e_1.tar.bz2#2253f130c8dab435824d6ddb10a41c73 -https://conda.anaconda.org/conda-forge/noarch/autodocsumm-0.2.6-pyhd8ed1ab_0.tar.bz2#4409dd7e06a62c3b2aa9e96782c49c6d -https://conda.anaconda.org/conda-forge/noarch/nbsphinx-0.9.3-pyhd8ed1ab_0.conda#0dbaa7d08d3d79b2a1a4dd6a02cc4581 -https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.2-pyhd8ed1ab_0.conda#ce99859070b0e17ccc63234ca58f3ed8 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda#611a35a27914fac3aa37611a6fe40bb5 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda#d7e4954df0d3aea2eacc7835ad12671d -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda#7e1e7437273682ada2ed5e9e9714b140 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda#26acae54b06f178681bfb551760f5dd1 -https://conda.anaconda.org/conda-forge/noarch/sphinx-7.2.6-pyhd8ed1ab_0.conda#bbfd1120d1824d2d073bc65935f0e4c0 +https://conda.anaconda.org/conda-forge/noarch/r-climprojdiags-0.3.3-r42hc72bb7e_0.conda#f34d40a3f0f9160fdd2bccaae8e185d1 +https://conda.anaconda.org/conda-forge/noarch/r-lintr-3.1.2-r42hc72bb7e_0.conda#ef49cc606b94a9d5f30b9c48f5f68848 +https://conda.anaconda.org/conda-forge/linux-64/r-sf-1.0_14-r42h85a8d9e_1.conda#ad59b523759f3e8acc6fd623cfbfb5a9 +https://conda.anaconda.org/conda-forge/linux-64/r-tibble-3.2.1-r42h57805ef_2.conda#b1278a5148c9e52679bb72112770cdc3 +https://conda.anaconda.org/conda-forge/noarch/dask-2024.8.2-pyhd8ed1ab_0.conda#3adbad9b363bd0163ef2ac59f095cc13 +https://conda.anaconda.org/conda-forge/noarch/r-ggplot2-3.5.1-r42hc72bb7e_0.conda#77cc0254e0dc92e5e7791ce20a170f74 +https://conda.anaconda.org/conda-forge/noarch/r-rematch2-2.1.2-r42hc72bb7e_3.conda#5ccfee6f3b94e6b247c7e1929b24f1cc +https://conda.anaconda.org/conda-forge/noarch/iris-esmf-regrid-0.11.0-pyhd8ed1ab_0.conda#b30cbc09f81d9dbaf8b74f2c8eacddc5 +https://conda.anaconda.org/conda-forge/noarch/r-styler-1.10.3-r42hc72bb7e_0.conda#1b2b8fa85a9d0556773abac4763d8ef9 +https://conda.anaconda.org/conda-forge/linux-64/r-tlmoments-0.7.5.3-r42ha503ecb_1.conda#6aa1414e06dfffc39d3b5ca78b60b377 +https://conda.anaconda.org/conda-forge/noarch/r-viridis-0.6.5-r42hc72bb7e_0.conda#959f69b6dfd4b620a15489975fa27670 +https://conda.anaconda.org/conda-forge/noarch/esmvalcore-2.11.0-pyhd8ed1ab_0.conda#ae2c9a927475f5519d0164c542cde378 +https://conda.anaconda.org/conda-forge/linux-64/r-fields-15.2-r42h61816a4_0.conda#d84fe2f9e893e92089370b195e2263a0 +https://conda.anaconda.org/conda-forge/noarch/r-spei-1.8.1-r42hc72bb7e_1.conda#7fe060235dac0fc0b3d387f98e79d128 +https://conda.anaconda.org/conda-forge/linux-64/r-geomap-2.5_5-r42h57805ef_0.conda#e58ccf961b56e57d7c1e50995005b0bd +https://conda.anaconda.org/conda-forge/noarch/r-s2dverification-2.10.3-r42hc72bb7e_2.conda#8079a86a913155fe2589ec0b76dc9f5e +https://conda.anaconda.org/conda-forge/noarch/autodocsumm-0.2.13-pyhd8ed1ab_0.conda#b2f4f2f3923646802215b040e63d042e +https://conda.anaconda.org/conda-forge/noarch/nbsphinx-0.9.5-pyhd8ed1ab_0.conda#b808b8a0494c5cca76200c73e260a060 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.4-pyhd8ed1ab_0.conda#c7c50dd5192caa58a05e6a4248a27acb +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/noarch/sphinx-8.0.2-pyhd8ed1ab_0.conda#625004bdab1b171dfd1e29ebb30c40dd https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e diff --git a/config-user-example.yml b/config-user-example.yml index ab9c8f3b4d..c102928db9 100644 --- a/config-user-example.yml +++ b/config-user-example.yml @@ -237,13 +237,38 @@ drs: # CMIP5: /project/champ/data/cmip5/output1 # CMIP6: /project/champ/data/CMIP6 # CORDEX: /project/champ/data/cordex/output -# OBS: /data/users/esmval/ESMValTool/temporary/obs/ -# obs4MIPs: /data/users/esmval/ESMValTool/temporary/obs/ +# OBS: /data/users/esmval/ESMValTool/obs +# OBS6: /data/users/esmval/ESMValTool/obs +# obs4MIPs: /data/users/esmval/ESMValTool/obs # ana4mips: /project/champ/data/ana4MIPs +# native6: /data/users/esmval/ESMValTool/rawobs +# RAWOBS: /data/users/esmval/ESMValTool/rawobs #drs: # CMIP5: BADC # CMIP6: BADC # CORDEX: BADC # OBS: default +# OBS6: default # obs4MIPs: default # ana4mips: BADC +# native6: default + +# Site-specific entries: NCI +# Uncomment the lines below to locate data at NCI. +#rootpath: +# CMIP6: [/g/data/oi10/replicas/CMIP6, /g/data/fs38/publications/CMIP6, /g/data/xp65/public/apps/esmvaltool/replicas/CMIP6] +# CMIP5: [/g/data/r87/DRSv3/CMIP5, /g/data/al33/replicas/CMIP5/combined, /g/data/rr3/publications/CMIP5/output1, /g/data/xp65/public/apps/esmvaltool/replicas/cmip5/output1] +# CMIP3: /g/data/r87/DRSv3/CMIP3 +# OBS: /g/data/ct11/access-nri/replicas/esmvaltool/obsdata-v2 +# OBS6: /g/data/ct11/access-nri/replicas/esmvaltool/obsdata-v2 +# obs4MIPs: /g/data/ct11/access-nri/replicas/esmvaltool/obsdata-v2 +# ana4mips: /g/data/ct11/access-nri/replicas/esmvaltool/obsdata-v2 +# native6: /g/data/xp65/public/apps/esmvaltool/native6 +# +#drs: +# CMIP6: NCI +# CMIP5: NCI +# CMIP3: NCI +# CORDEX: ESGF +# obs4MIPs: default +# ana4mips: default diff --git a/doc/sphinx/source/changelog.rst b/doc/sphinx/source/changelog.rst index d1180d3b8b..76c0a86da5 100644 --- a/doc/sphinx/source/changelog.rst +++ b/doc/sphinx/source/changelog.rst @@ -3,6 +3,135 @@ Changelog ========= +.. _changelog-v2-11-0: + +v2.11.0 +------- +Highlights + +- Two new recipes have been added: + + - Recipe :ref:`recipe_aod_aeronet_assess.yml ` + evaluates model aerosol optical depth (AOD) climatologies against ground + based observations from the AeroNET measurement network. + - Recipe :ref:`recipe_climate_patterns.yml ` + generates climate patterns from CMIP6 model datasets. + +- The ESACCI-WATERVAPOUR CMORizer now includes daily data and uses the + officially released CDR2 data. +- Support for 5 new datasets have been added: + + - AeroNET + - ANU Climate 2.0 Australian data + - Australian Gridded Climate Data(AGCD) precipitation + - NOAA-ERSST + - NSIDC-G02202-sh sea ice fraction + +- NEW TREND: First time release manager shout-outs! + + - This is the first ESMValTool release managed by the Met Office! We want to + shout this out - and for all future first time release managers to + shout-out - to celebrate the growing, thriving ESMValTool community. + +This release includes + +Bug fixes +~~~~~~~~~ + +- Recipe_ocean_quadmap: Update ATSR to match ESGF name (:pull:`3443`) by :user:`rbeucher` +- Fix recipe_bock20jgr_fig_8-10.yml (:pull:`3665`) by :user:`LisaBock` +- Update the list of datasets used in ``recipe_easy_ipcc.yml`` (:pull:`3710`) by :user:`bouweandela` + +Documentation +~~~~~~~~~~~~~ + +- Improve release tools and documentation (:pull:`3462`) by :user:`bouweandela` +- Fix a typo in the references file (:pull:`3499`) by :user:`bouweandela` +- Fix recipe path in ``recipe_perfmetrics.rst`` (:pull:`3532`) by :user:`TomasTorsvik` +- Improved description of model evaluation recipes (:pull:`3541`) by :user:`schlunma` +- Remove double word in cmorizer documentation (:pull:`3553`) by :user:`bettina-gier` +- Fix Codacy badge (:pull:`3558`) by :user:`bouweandela` +- Update the release schedule for v2.11.0 (:pull:`3573`) by :user:`ehogan` +- Improve the formatting of the recipe documentation template (:pull:`3652`) by :user:`mo-gill` +- Add introduction material on the main documentation page (:pull:`3628`) by :user:`bouweandela` +- Avoid warning in documentation build (:pull:`3675`) by :user:`bouweandela` +- Update the list of broken recipes for ``v2.11.0`` (:pull:`3706`) by :user:`ehogan` + +Diagnostics +~~~~~~~~~~~ + +- ``monitor/multi_dataset.py`` improvements: allow data w/o ``timerange`` and improve text formatting (:pull:`3528`) by :user:`schlunma` +- Allow datasets without ``project`` in multi_datasets.py (:pull:`3552`) by :user:`schlunma` +- Prevent overlapping time axis tick labels in monitoring recipe (:pull:`3682`) by :user:`schlunma` + +New recipe +~~~~~~~~~~ + +- Add support for aerosol optical depth climatology metrics to the AutoAssess replacement (:pull:`3048`) by :user:`catherinehardacre` +- CMIP6 climate patterns (:pull:`2785`) by :user:`mo-gregmunday` + +Observational and re-analysis dataset support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Add cmorizer scripts for NOAA-ERSST. (:pull:`1799`) by :user:`bjoernbroetz` +- Update OceanSODA-ETHZ CMORizer with new source file (:pull:`3535`) by :user:`TomasTorsvik` +- Add CMORizer script for NSIDC-G02202-sh sea ice fraction (:pull:`3512`) by :user:`flicj191` +- CMORizer Australian Gridded Climate Data(AGCD) precipitation (:pull:`3445`) by :user:`flicj191` +- Extend CMORizer NCEP-DOE-R2 (:pull:`3469`) by :user:`axel-lauer` +- Add comment to recipe_lauer13jclim regarding UWisc being superseded by MAC-LWP (:pull:`3537`) by :user:`rbeucher` +- Recipe_autoassess_landsurface_surfrad: Remove CERES-EBAF version to fix ESGF search (:pull:`3438`) by :user:`rbeucher` +- Updating ESACCI-WATERVAPOUR cmorizer (:pull:`3282`) by :user:`malininae` +- CMORiser for ANU Climate 2.0 Australian data (:pull:`3511`) by :user:`flicj191` +- Add AERONET cmorizer (:pull:`3227`) by :user:`zklaus` +- Update CRU CMORizer (:pull:`3381`) by :user:`lukruh` +- Fix recipe_check_obs to be aligned with DKRZ (:pull:`3673`) by :user:`LisaBock` +- Update AERONET data version (:pull:`3692`) by :user:`ehogan` + +Automatic testing +~~~~~~~~~~~~~~~~~ + +- Move code into function in batch job generation script (:pull:`3491`) by :user:`bouweandela` +- Fix sklearn tests (:pull:`3506`) by :user:`schlunma` +- Pinned sklearn>=1.4.0 (:pull:`3508`) by :user:`schlunma` +- Update sklearn tests to be compatible with current pytest version (pytest >=8.0.0) (:pull:`3517`) by :user:`schlunma` +- Update sklearn tests to be compatible with current pytest version (pytest >=8.0.0) Part 2 (:pull:`3518`) by :user:`schlunma` +- [Circle/CI]Fix `test_installation_from_conda` Circle CI tests (:pull:`3538`) by :user:`valeriupredoi` +- [Github Actions] install git in OSX and add environment inspection (:pull:`3581`) by :user:`valeriupredoi` +- [CI Github Actions] Update (outdated) actions versions that produce Node.js warnings (:pull:`3586`) by :user:`valeriupredoi` +- Fix ``flake8==7`` linting issues (:pull:`3634`) by :user:`valeriupredoi` +- Use ``importlib`` as the import mode for ``pytest`` (:pull:`3672`) by :user:`ehogan` + +Installation +~~~~~~~~~~~~ + +- Update dependencies (:pull:`3487`) by :user:`bouweandela` +- Merge v2.10.x into main (:pull:`3489`) by :user:`schlunma` +- Add imagehash package as an ESMValTool dependency (:pull:`3557`) by :user:`alistairsellar` +- Unpin ``r-akima`` (:pull:`3564`) by :user:`valeriupredoi` +- Adding pys2index dependency (:pull:`3577`) by :user:`ljoakim` +- Pin esmpy <8.6.0 (:pull:`3585`) by :user:`valeriupredoi` +- Pin R <4.3.0 (:pull:`3689`) by :user:`ehogan` +- Pin importlib_metadata <8 (:pull:`3700`) by :user:`ehogan` +- Pin matplotlib <3.9.0 on ESMValTool release branch (:pull:`3712`) by :user:`ehogan` + +Dependency updates +~~~~~~~~~~~~~~~~~~ + +- Fix for ``recipe_seaice_drift.yml``: fix CRS transformer for "North Pole Stereographic" (:pull:`3531`) by :user:`flicj191` +- Fixed attribute handling in austral_jet/main.ncl for iris>=3.8 (:pull:`3603`) by :user:`schlunma` +- Fixed attribute handling in emergent constraint diagnostic for iris>=3.8 (:pull:`3605`) by :user:`schlunma` +- Update the name of the remapcon2 operator in R recipes (:pull:`3611`) by :user:`ehogan` +- Use ``iris.FUTURE.save_split_attrs = True`` to remove iris warning in many diagnostics (:pull:`3651`) by :user:`schlunma` +- Avoid concatenation error in recipe_pcrglobwb.yml (:pull:`3645`) by :user:`bouweandela` +- Update `scipy.integrate.simps` import (:pull:`3704`) by :user:`ehogan` + +Improvements +~~~~~~~~~~~~ + +- Add native6, OBS6 and RAWOBS rootpaths to metoffice template in config-user-example.yml and remove temporary dir (:pull:`3613`) by :user:`alistairsellar` + +.. _changelog-v2-10-0: + v2.10.0 ------- Highlights diff --git a/doc/sphinx/source/community/release_strategy/release_strategy.rst b/doc/sphinx/source/community/release_strategy/release_strategy.rst index b358fdb7f3..b95bab67b1 100644 --- a/doc/sphinx/source/community/release_strategy/release_strategy.rst +++ b/doc/sphinx/source/community/release_strategy/release_strategy.rst @@ -53,14 +53,25 @@ With the following release schedule, we strive to have three releases per year a Upcoming releases ^^^^^^^^^^^^^^^^^ - -- 2.11.0 (Release Manager: TBD) - -Planned for February or March 2024 +- 2.12.0 (TBD) Past releases ^^^^^^^^^^^^^ +- 2.11.0 (Release Manager: Met Office: `Emma Hogan`_, `Chris Billows`_, `Ed Gillett`_) + ++------------+------------+----------------------------------------+-------------------------------------+ +| Planned | Done | Event | Changelog | ++============+============+========================================+=====================================+ +| 2024-04-22 | | ESMValCore `Feature Freeze`_ | | ++------------+------------+----------------------------------------+-------------------------------------+ +| 2023-05-03 | 2024-07-03 | :esmvalcore-release:`v2.11.0` released | :ref:`esmvalcore:changelog-v2-11-0` | ++------------+------------+----------------------------------------+-------------------------------------+ +| 2023-05-06 | | ESMValTool `Feature Freeze`_ | | ++------------+------------+----------------------------------------+-------------------------------------+ +| 2023-05-17 | 2024-07-04 | :release:`v2.11.0` released | :ref:`changelog-v2-11-0` | ++------------+------------+----------------------------------------+-------------------------------------+ + - 2.10.0 (Release Manager: `Klaus Zimmermann`_) +------------+------------+----------------------------------------+-------------------------------------+ @@ -647,3 +658,6 @@ Changelog .. _Manuel Schlund: https://github.com/schlunma .. _Javier Vegas-Regidor: https://github.com/jvegasbsc .. _Klaus Zimmermann: https://github.com/zklaus +.. _Emma Hogan: https://github.com/ehogan +.. _Chris Billows: https://github.com/chrisbillowsMO +.. _Ed Gillett: https://github.com/mo-gill diff --git a/doc/sphinx/source/conf.py b/doc/sphinx/source/conf.py index 600eaa8253..1af560b576 100644 --- a/doc/sphinx/source/conf.py +++ b/doc/sphinx/source/conf.py @@ -82,6 +82,11 @@ 'autosummary': True, } +# See https://github.com/sphinx-doc/sphinx/issues/12589 +suppress_warnings = [ + 'autosummary.import_cycle', +] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/doc/sphinx/source/index.rst b/doc/sphinx/source/index.rst index 9975172bc4..136c2eba08 100644 --- a/doc/sphinx/source/index.rst +++ b/doc/sphinx/source/index.rst @@ -6,6 +6,27 @@ Welcome to ESMValTool's documentation! ====================================== +To get a first impression of what ESMValTool and ESMValCore can do for you, +have a look at our blog posts +`Analysis-ready climate data with ESMValCore `_ +and +`ESMValTool: Recipes for solid climate science `_. + +A tutorial is available on https://tutorial.esmvaltool.org. + +A series of video lectures has been created by `ACCESS-NRI `_. +While these are tailored for ACCESS users, they are still very informative. + +.. raw:: html + + + +| + +For more detailed information, the documentation is available below. + +Get in touch! Contact information is available :ref:`here `. + .. include:: _sidebar.rst.inc Indices and tables @@ -13,4 +34,3 @@ Indices and tables * :ref:`genindex` * :ref:`search` - diff --git a/doc/sphinx/source/input.rst b/doc/sphinx/source/input.rst index a72bce73aa..798b2ceb27 100644 --- a/doc/sphinx/source/input.rst +++ b/doc/sphinx/source/input.rst @@ -232,8 +232,12 @@ A list of the datasets for which a CMORizers is available is provided in the fol +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | Dataset | Variables (MIP) | Tier | Script language | +==============================+======================================================================================================+======+=================+ +| AERONET | od440aer, od550aer, od870aer (AERmon) | 3 | Python | ++------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | AGCD | pr (Amon) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ +| ANU Climate | pr, tas, tasmin, tasmax (Amon) | 3 | Python | ++------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | APHRO-MA | pr, tas (day), pr, tas (Amon) | 3 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | AURA-TES | tro3 (Amon) | 3 | NCL | @@ -267,7 +271,7 @@ A list of the datasets for which a CMORizers is available is provided in the fol +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | CowtanWay | tasa (Amon) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ -| CRU | tas, pr (Amon) | 2 | Python | +| CRU | tas, tasmin, tasmax, pr, clt (Amon), evspsblpot (Emon) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | CT2019 | co2s (Amon) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ @@ -304,7 +308,7 @@ A list of the datasets for which a CMORizers is available is provided in the fol +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | ESACCI-SEA-SURFACE-SALINITY | sos (Omon) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ -| ESACCI-SOILMOISTURE | dos, dosStderr, sm, smStderr (Lmon) | 2 | NCL | +| ESACCI-SOILMOISTURE | sm (Eday, Lmon), smStderr (Eday) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | ESACCI-SST | ts, tsStderr (Amon) | 2 | NCL | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ diff --git a/doc/sphinx/source/quickstart/installation.rst b/doc/sphinx/source/quickstart/installation.rst index a4f9f2a64c..4fb75b2f4f 100644 --- a/doc/sphinx/source/quickstart/installation.rst +++ b/doc/sphinx/source/quickstart/installation.rst @@ -8,7 +8,7 @@ Installation ESMValTool now uses `mamba` instead of `conda` for the recommended installation. For more information about the change, have a look at :ref:`Move to Mamba`. -ESMValTool supports Python 3.9 and later and requires Linux or MacOS. +ESMValTool supports Python 3.10 and later and requires Linux or MacOS. Successful usage on Windows has been reported by following the Linux installation instructions with `WSL `__. @@ -489,7 +489,7 @@ To check that the installation was successful, run this should show the directory of the source code that you just downloaded. If the command above shows a directory inside your conda environment instead, -e.g. ``~/mambaforge/envs/esmvaltool/lib/python3.9/site-packages/esmvalcore``, +e.g. ``~/mambaforge/envs/esmvaltool/lib/python3.11/site-packages/esmvalcore``, you may need to manually remove that directory and run ``pip install --editable '.[develop]'`` again. @@ -684,40 +684,6 @@ repository, a direct download link can be found `here =3.9, asking for an older Python version, e.g. `python=3.7`, in -this way, it will result in installation failure. - Problems with proxies --------------------- If you are installing ESMValTool from source from behind a proxy that does not @@ -778,7 +744,7 @@ Problems when updating the conda environment -------------------------------------------- Usually mamba is much better at solving new environments than updating older environments, so it is often a good idea to create a new environment if updating -does not work. See also `Mamba fails to solve the environment`_. +does not work. Do not run ``mamba update --update-all`` in the ``esmvaltool`` environment since that will update some packages that are pinned to diff --git a/doc/sphinx/source/recipes/broken_recipe_list.rst b/doc/sphinx/source/recipes/broken_recipe_list.rst index e2c5b874d8..f2c25623ac 100644 --- a/doc/sphinx/source/recipes/broken_recipe_list.rst +++ b/doc/sphinx/source/recipes/broken_recipe_list.rst @@ -9,26 +9,36 @@ More details can be found in the :ref:`broken recipe policy `. .. list-table:: Broken recipes - :widths: 25 25 25 25 + :widths: 25 25 25 25 25 :header-rows: 1 * - Broken recipe - Affected diagnostics + - Broken since release - Problem - GitHub issue - * - `recipe_check_obs.yml` - - `ERA5_native6` - - Derivation of custom variables `rlus` and `rsus` - - `#1388 `_ * - :ref:`recipe_julia.yml ` - `example` - - fill values are not interpreted, resulting in an unusable plot + - v2.5.0 + - Fill values are not interpreted, resulting in an unusable plot - `#2595 `_ - * - :ref:`recipe_seaice_drift.yml ` - - `sea_ice_drift_SCICEX` - - ``shapely 2`` issue - - `#3243 `_ - * - :ref:`recipe_pysplot.yml ` - - `plot_map` - - ``shapely 2`` issue - - `#3483 `_ + * - :ref:`recipe_climwip_brunner2019_med.yml ` + - All (preprocessor issue) + - v2.11.0 + - Failed to run preprocessor function ``fix_metadata`` on the data: Unable to convert units + - `#3694 `_ + * - :ref:`recipe_ocean_amoc.yml ` + - ``diag_timeseries_amoc``, ``diag_transects`` + - v2.11.0 + - CESM1 CMIP5 Omon data no longer available + - `#3693 `_ + * - :ref:`recipe_russell18jgr.yml ` + - ``Figure_4`` + - v2.11.0 + - CESM1 CMIP5 Omon data no longer available + - `#3693 `_ + * - :ref:`recipe_wenzel14jgr.yml ` + - ``diag_tsline_Fig2d`` + - v2.11.0 + - CESM1 CMIP5 Omon data no longer available + - `#3693 `_ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_DJF.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_DJF.png new file mode 100644 index 0000000000..ccf5c4b1c8 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_DJF.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_JJA.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_JJA.png new file mode 100644 index 0000000000..38b09c52f9 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_JJA.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_MAM.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_MAM.png new file mode 100644 index 0000000000..5e7ca417a1 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_MAM.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_SON.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_SON.png new file mode 100644 index 0000000000..ffb666eea2 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_SON.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_scatter.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_scatter.png new file mode 100644 index 0000000000..67c64a3fa7 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_scatter.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_DJF.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_DJF.png new file mode 100644 index 0000000000..f653410e07 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_DJF.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_JJA.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_JJA.png new file mode 100644 index 0000000000..6474acc856 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_JJA.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_MAM.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_MAM.png new file mode 100644 index 0000000000..2e2fda4cca Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_MAM.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_SON.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_SON.png new file mode 100644 index 0000000000..ce4d3fac08 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_SON.png differ diff --git a/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_scatter.png b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_scatter.png new file mode 100644 index 0000000000..9226bca81a Binary files /dev/null and b/doc/sphinx/source/recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_scatter.png differ diff --git a/doc/sphinx/source/recipes/figures/climate_patterns/patterns.png b/doc/sphinx/source/recipes/figures/climate_patterns/patterns.png new file mode 100644 index 0000000000..396fd78830 Binary files /dev/null and b/doc/sphinx/source/recipes/figures/climate_patterns/patterns.png differ diff --git a/doc/sphinx/source/recipes/index.rst b/doc/sphinx/source/recipes/index.rst index edcc48977a..e18ada0fd7 100644 --- a/doc/sphinx/source/recipes/index.rst +++ b/doc/sphinx/source/recipes/index.rst @@ -32,6 +32,7 @@ Atmosphere :maxdepth: 1 recipe_miles + recipe_climate_patterns recipe_clouds recipe_cmug_h2o recipe_crem @@ -62,6 +63,7 @@ Atmosphere recipe_thermodyn_diagtool recipe_validation recipe_radiation_budget + recipe_aod_aeronet_assess Climate metrics ^^^^^^^^^^^^^^^ diff --git a/doc/sphinx/source/recipes/recipe_aod_aeronet_assess.rst b/doc/sphinx/source/recipes/recipe_aod_aeronet_assess.rst new file mode 100644 index 0000000000..fec1bed761 --- /dev/null +++ b/doc/sphinx/source/recipes/recipe_aod_aeronet_assess.rst @@ -0,0 +1,161 @@ +.. _recipe_aod_aeronet_assess: + +AOD AeroNET Assess +================== + +Overview +-------- + +This diagnostic evaluates model aerosol optical depth (AOD) against ground +based observations from the AeroNET measurement network. Monthly mean AOD +data is downloaded from the AeroNET website and formatted (CMORized) using the +AERONET downloader and formatter within ESMValTool. + +Multiannual seasonal means are calculated from the model output and compared +with a multiannual seasonal mean climatology generated from AeroNET +observational data. At each AeroNET station the data are screened for validity +according to the following default criteria: + + * 1. Monthly means must be generated from at least one AOD observation in that + month. + + * 2. Seasonal means for DJF, MAM, JJA and SON must be calculated from three + monthly means, i.e. a monthly mean from December January and Feburary. + + * 3. For a given year to be valid, there must be a seasonal mean for each climate + season i.e. DJF, MAM, JJA and SON. + + * 4. For a multiannual seasonal means there must be at least five seasonaal means + over the time range of interest. + +NOTE: The code is designed to be flexible and the default criteria can be +changed according to the user's requirements (see the user settings below). + +The evaluation is visualised by plotting model output as 2D filled contours and +overlaying AeroNET observations at model grid cells co-located with the AeroNET +measurement stations. Statistical data (root mean square error) is generated +using AeroNET observations at model grid cells co-located with the AeroNET +measurement stations. + +Available recipes and diagnostics +--------------------------------- + +Recipes are stored in esmvaltool/recipes/ + + * recipe_aod_aeronet_assess.yml + +Diagnostics are stored in esmvaltool/diag_scripts/aerosols/ + + * aod_aeronet_assess.py: Plot the AOD evaluation. + * aero_utils.py: Utility functions commonly used by aerosol assessment routines. + + +User settings in recipe +----------------------- + +#. Script aod_aeronet_assess.py + + *Required settings for script* + + * wavel: The wavelength of interest for the evaluation, currently set up for 440nm + * min_days_per_mon: The minimum number of days used to calculate the AOD monthly mean + * min_mon_per_seas: The minimum number of seasons used to calculate each + seasonal mean. This must be between 1 and 3. + * min_seas_per_year: The minimum number of seasonal means in each year. This + must be between 1 and 4. + * min_seas_per_clim: The minimum number of seasonal means used to calculate + the multiannual seasonal mean. This must be btween 1 and the number of years + of available AeroNET data. + + *Optional settings for script* + + * None + + *Required settings for variables* + + * None + + *Optional settings for variables* + + * None + + *Required settings for preprocessor* + + * None + + *Optional settings for preprocessor* + + * None + + *Color tables* + + * brewer_Spectral_11 + + +Variables +--------- + +* od440aer (atmos, monthly mean, longitude latitude time) + + +Observations and reformat scripts +--------------------------------- + +* Note: (1) obs4MIPs data can be used directly without any preprocessing; (2) + see headers of reformat scripts for non-obs4MIPs data for download + instructions. + +* The AeroNET data is downloaded from the AeroNET website using the downloader: + + .. code-block:: yaml + + $ esmvaltool data download AERONET. + +* The AeroNET data is formatteed (CMORized) using the formatter: + + .. code-block:: yaml + + $ esmvaltool data format AERONET. + + + +References +---------- +* Holben B.N., T.F.Eck, I.Slutsker, D.Tanre, J.P.Buis, A.Setzer, E.Vermote, J.A.Reagan, Y.Kaufman, T.Nakajima, F.Lavenu, I.Jankowiak, and A.Smirnov, 1998: AERONET - A federated instrument network and data archive for aerosol characterization, Rem. Sens. Environ., 66, 1-16. + +* Holben, B.N., D.Tanre, A.Smirnov, T.F.Eck, I.Slutsker, N.Abuhassan, W.W.Newcomb, J.Schafer, B.Chatenet, F.Lavenue, Y.J.Kaufman, J.Vande Castle, A.Setzer, B.Markham, D.Clark, R.Frouin, R.Halthore, A.Karnieli, N.T.O'Neill, C.Pietras, R.T.Pinker, K.Voss, and G.Zibordi, 2001: An emerging ground-based aerosol climatology: Aerosol Optical Depth from AERONET, J. Geophys. Res., 106, 12 067-12 097. + +* Mulcahy, J. P., Johnson, C., Jones, C. G., Povey, A. C., Scott, C. E., Sellar, A., Turnock, S. T., Woodhouse, M. T., Abraham, N. L., Andrews, M. B., Bellouin, N., Browse, J., Carslaw, K. S., Dalvi, M., Folberth, G. A., Glover, M., Grosvenor, D. P., Hardacre, C., Hill, R., Johnson, B., Jones, A., Kipling, Z., Mann, G., Mollard, J., O’Connor, F. M., Palmiéri, J., Reddington, C., Rumbold, S. T., Richardson, M., Schitgens, N. A. J., Stier, P., Stringer, M., Tang, Y., Walton, J., Woodward, S., and Yool. A.: Description and evaluation of aerosol in UKESM1 and HadGEM3-GC3.1 CMIP6 historical simulations, Geosci. Model Dev., 13, 6383–6423, 2020 + +Example plots +------------- + +.. _fig_aod_aeronet_assess_1: +.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_DJF.png + :align: center + + Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Dec-Jan-Feb. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. + +.. _fig_aod_aeronet_assess_2: +.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_MAM.png + :align: center + + Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Mar_Apr_May. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. + +.. _fig_aod_aeronet_assess_3: +.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_JJA.png + :align: center + + Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Jun-Jul-Aug. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. + +.. _fig_aod_aeronet_assess_4: +.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_SON.png + :align: center + + Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Sep-Oct-Nov. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. + +.. _fig_aod_aeronet_assess_5: +.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_scatter.png + :align: center + + Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Dec-Jan-Feb, Mar_Apr_May, Jun-Jul-Aug and Sep-Oct-Nov. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. diff --git a/doc/sphinx/source/recipes/recipe_climate_patterns.rst b/doc/sphinx/source/recipes/recipe_climate_patterns.rst new file mode 100644 index 0000000000..f7336c91c4 --- /dev/null +++ b/doc/sphinx/source/recipes/recipe_climate_patterns.rst @@ -0,0 +1,107 @@ +.. _recipes_climate_patterns: + +Generating Climate Patterns from CMIP6 Models +============================================= + +Overview +-------- + +The recipe recipe_climate_patterns generates climate patterns from CMIP6 model +datasets. + +.. note:: + The regrid setting in the recipe is set to a 2.5x3.75 grid. This is done to + match the current resolution in the IMOGEN-JULES model, but can be + adjusted with no issues for a finer/coarser patterns grid. + + +Available recipes and diagnostics +--------------------------------- + +Recipes are stored in esmvaltool/recipes/ + +* recipe_climate_patterns.yml + +Diagnostics are stored in esmvaltool/diag_scripts/climate_patterns/ + +* climate_patterns.py: generates climate patterns from input datasets +* sub_functions.py: set of sub functions to assist with driving scripts +* plotting.py: contains all plotting functions for driving scripts + + +User settings in recipe +----------------------- + +#. Script climate_patterns.py + + *Required settings for script* + + None + + *Optional settings for script* + + * jules_mode: output jules-specific var names + .nc files + * parallelise: parallelise over models or not + * area: calculate the patterns globally, or over land only + + *Required settings for variables* + + * short_name + * additional_datasets + + *Optional settings for variables* + + None + + *Required settings for preprocessor* + + * monthly_statistics: converts data to mean monthly data + + *Optional settings for preprocessor* + + * regrid: regrids data + + +Variables +--------- + +#. Script climate_patterns.py + +* tasmax (atmos, monthly, longitude latitude time) +* tasmin (atmos, monthly, longitude latitude time) +* tas (atmos, monthly, longitude latitude time) +* huss (atmos, monthly, longitude latitude time) +* pr (atmos, monthly, longitude latitude time) +* sfcWind (atmos, monthly, longitude latitude time) +* ps (atmos, monthly, longitude latitude time) +* rsds (atmos, monthly, longitude latitude time) +* rlds (atmos, monthly, longitude latitude time) + + +Observations and reformat scripts +--------------------------------- + +None + +References +---------- + +* Huntingford, C., Cox, P. An analogue model to derive additional climate + change scenarios from existing GCM simulations. + Climate Dynamics 16, 575–586 (2000). https://doi.org/10.1007/s003820000067 + +* Mathison, C. T. et al. A rapid application emissions-to-impacts tool + for scenario assessment: Probabilistic Regional Impacts from Model patterns + and Emissions (PRIME). + EGUsphere [preprint], (2024). https://doi.org/10.5194/egusphere-2023-2932 + +Example plots +------------- + +.. _fig_climate_patterns_2: +.. figure:: /recipes/figures/climate_patterns/patterns.png + :align: center + :width: 80% + + Patterns generated for CMIP6 models, gridded view. Patterns are shown per + variable, for the month of January. \ No newline at end of file diff --git a/doc/sphinx/source/recipes/recipe_seaborn.rst b/doc/sphinx/source/recipes/recipe_seaborn.rst index 3c8fa64357..4eb3c6571c 100644 --- a/doc/sphinx/source/recipes/recipe_seaborn.rst +++ b/doc/sphinx/source/recipes/recipe_seaborn.rst @@ -16,11 +16,11 @@ Available recipes and diagnostics Recipes are stored in recipes/ - * recipe_seaborn.yml +* recipe_seaborn.yml Diagnostics are stored in diag_scripts/ - * :ref:`seaborn_diag.py ` +* :ref:`seaborn_diag.py ` Variables diff --git a/doc/sphinx/source/recipes/recipe_template.rst.template b/doc/sphinx/source/recipes/recipe_template.rst.template index 55e28ddf7e..6c248ed5d7 100644 --- a/doc/sphinx/source/recipes/recipe_template.rst.template +++ b/doc/sphinx/source/recipes/recipe_template.rst.template @@ -14,11 +14,11 @@ Available recipes and diagnostics Recipes are stored in esmvaltool/recipes/ - * recipe_.yml +* recipe_.yml Diagnostics are stored in esmvaltool/diag_scripts// - * : one line scription +* : one line scription User settings in recipe diff --git a/doc/sphinx/source/recipes/recipe_wenzel14jgr.rst b/doc/sphinx/source/recipes/recipe_wenzel14jgr.rst index 7c07c6e1f5..3c7fa86a3a 100644 --- a/doc/sphinx/source/recipes/recipe_wenzel14jgr.rst +++ b/doc/sphinx/source/recipes/recipe_wenzel14jgr.rst @@ -1,3 +1,5 @@ +.. _recipe_wenzel14jgr: + Emergent constraints on carbon cycle feedbacks ============================================== diff --git a/environment.yml b/environment.yml index 1a1c960942..54aa73bcf0 100644 --- a/environment.yml +++ b/environment.yml @@ -11,23 +11,24 @@ channels: dependencies: - aiohttp - cartopy - - cdo >=1.9.7 + - cdo >=2.3.0 - cdsapi - cf-units - cftime - cmocean - cython - - dask + - dask !=2024.8.0 # https://github.com/dask/dask/issues/11296 - distributed - ecmwf-api-client - eofs - - esmpy - - esmvalcore 2.10.* + - esmpy >=8.6.0 # github.com/SciTools-incubator/iris-esmf-regrid/pull/342 + - esmvalcore 2.11.* - fiona - fire + - fsspec - gdal - iris >=3.6.1 - - iris-esmf-regrid >=0.7.0 + - iris-esmf-regrid >=0.10.0 # github.com/SciTools-incubator/iris-esmf-regrid/pull/342 - jinja2 - joblib - lime @@ -40,7 +41,7 @@ dependencies: - numpy !=1.24.3 # severe masking bug - openpyxl - packaging - - pandas + - pandas !=2.2.0,!=2.2.1,!=2.2.2 # github.com/ESMValGroup/ESMValCore/pull/2305 - pip !=21.3 - progressbar2 - prov @@ -49,7 +50,8 @@ dependencies: - psy-reg - psy-simple - pyproj >=2.1 - - python >=3.9 + - pys2index # only from conda-forge + - python >=3.10 - python-cdo - python-dateutil - pyyaml @@ -67,8 +69,8 @@ dependencies: - xgboost >1.6.1 # github.com/ESMValGroup/ESMValTool/issues/2779 - xlsxwriter - zarr - # Python packages needed for testing - - flake8 + # Python packages needed for unit testing + - flake8 ==5.0.4 - pytest >=3.9,!=6.0.0rc1,!=6.0.0 - pytest-cov - pytest-env @@ -82,15 +84,16 @@ dependencies: - sphinx >=6.1.3 - pydata-sphinx-theme # Python packages needed for development - - codespell - - docformatter - - isort + - codespell ==2.3.0 + - docformatter ==1.7.5 + - imagehash + - isort ==5.13.2 - pre-commit - prospector - pyroma # - vprof not on conda-forge - - yamllint - - yapf + - yamllint ==1.35.1 + - yapf ==0.32.0 # NCL and dependencies - ncl @@ -100,9 +103,9 @@ dependencies: # R and dependencies - cdo - - r-base >=3.5 + - r-base >=3.5,<4.3.0 - r-abind - - r-akima <=0.6-2.3 # see https://github.com/ESMValGroup/ESMValTool/issues/2695 + - r-akima - r-climdex.pcic - r-climprojdiags - r-docopt @@ -110,7 +113,6 @@ dependencies: - r-functional - r-ggplot2 - r-gridextra - - r-lintr - r-logging - r-mapproj - r-maps @@ -124,13 +126,12 @@ dependencies: - r-s2dverification - r-snow - r-spei - - r-styler - r-udunits2 - r-yaml # R packages needed for development - r-git2r # dependency of lintr - - r-lintr - - r-styler + - r-lintr ==3.1.2 + - r-styler ==1.10.3 # Julia (dependencies installed by separate script) - julia diff --git a/environment_osx.yml b/environment_osx.yml index 6d14f65227..d89556b593 100644 --- a/environment_osx.yml +++ b/environment_osx.yml @@ -11,23 +11,24 @@ channels: dependencies: - aiohttp - cartopy - - cdo >=1.9.7 + - cdo >=2.3.0 - cdsapi - cf-units - cftime - cmocean - cython - - dask + - dask !=2024.8.0 # https://github.com/dask/dask/issues/11296 - distributed - ecmwf-api-client - eofs - - esmpy - - esmvalcore 2.10.* + - esmpy >=8.6.0 # github.com/SciTools-incubator/iris-esmf-regrid/pull/342 + - esmvalcore 2.11.* - fiona - fire + - fsspec - gdal - iris >=3.6.1 - - iris-esmf-regrid >=0.7.0 + - iris-esmf-regrid >=0.10.0 # github.com/SciTools-incubator/iris-esmf-regrid/pull/342 - jinja2 - joblib - lime @@ -40,7 +41,7 @@ dependencies: - numpy !=1.24.3 # severe masking bug - openpyxl - packaging - - pandas + - pandas !=2.2.0,!=2.2.1,!=2.2.2 # github.com/ESMValGroup/ESMValCore/pull/2305 - pip !=21.3 - progressbar2 - prov @@ -48,8 +49,9 @@ dependencies: - psy-maps - psy-reg - psy-simple - - pyproj>=2.1 - - python >=3.9 + - pyproj >=2.1 + - pys2index # only from conda-forge + - python >=3.10 - python-cdo - python-dateutil - pyyaml @@ -67,8 +69,8 @@ dependencies: - xgboost >1.6.1 # github.com/ESMValGroup/ESMValTool/issues/2779 - xlsxwriter - zarr - # Python packages needed for testing - - flake8 + # Python packages needed for unit testing + - flake8 ==5.0.4 - pytest >=3.9,!=6.0.0rc1,!=6.0.0 - pytest-cov - pytest-env @@ -82,12 +84,13 @@ dependencies: - sphinx >=6.1.3 - pydata-sphinx-theme # Python packages needed for development - - codespell - - docformatter - - isort + - codespell ==2.3.0 + - docformatter ==1.7.5 + - imagehash + - isort ==5.13.2 - pre-commit - prospector - pyroma # - vprof not on conda-forge - - yamllint - - yapf + - yamllint ==1.35.1 + - yapf ==0.32.0 diff --git a/esmvaltool/cmorizers/data/cmor_config/AERONET.yml b/esmvaltool/cmorizers/data/cmor_config/AERONET.yml new file mode 100644 index 0000000000..0e6ebf2934 --- /dev/null +++ b/esmvaltool/cmorizers/data/cmor_config/AERONET.yml @@ -0,0 +1,28 @@ +--- +# Filename +filename: 'AOD_Level20_Monthly_V3.tar.gz' + +# Common global attributes for Cmorizer output +attributes: + dataset_id: AERONET + version: 20240406 + tier: 3 + modeling_realm: atmos + project_id: OBS6 + source: 'https://aeronet.gsfc.nasa.gov/new_web/download_all_v3_aod.html' + reference: 'aeronetv3' + comment: + 'Notice to users: this data has recommended guidelines for use and publication, + please refer to https://aeronet.gsfc.nasa.gov/new_web/data_usage.html.' + +# Variables to cmorize +variables: + od440aer: + mip: AERmon + wavelength: 440 + od550aer: + mip: AERmon + wavelength: 551 + od870aer: + mip: AERmon + wavelength: 870 diff --git a/esmvaltool/cmorizers/data/cmor_config/ANUClimate.yml b/esmvaltool/cmorizers/data/cmor_config/ANUClimate.yml new file mode 100644 index 0000000000..3b5ce35b31 --- /dev/null +++ b/esmvaltool/cmorizers/data/cmor_config/ANUClimate.yml @@ -0,0 +1,32 @@ +--- +filename: 'ANUClimate_{version}_{raw}_{freq}_.*.nc' #yyyymm + +attributes: + project_id: OBS6 + dataset_id: ANUClimate + version: 'v2-0' + tier: 3 + modeling_realm: reanaly + # resolution: '0.01 degree' + source: 'https://dx.doi.org/10.25914/60a10aa56dd1b' + reference: 'anuclimate2' + comment: 'hosted on NCI' + +variables: + pr: + mip: Amon + freq: monthly # daily available + raw: rain + + tasmax: + mip: Amon + freq: monthly + raw: tmax + tasmin: + mip: Amon + freq: monthly + raw: tmin + tas: + mip: Amon + freq: monthly + raw: tavg diff --git a/esmvaltool/cmorizers/data/cmor_config/CRU.yml b/esmvaltool/cmorizers/data/cmor_config/CRU.yml index 92eb5df07d..e57cc4e945 100644 --- a/esmvaltool/cmorizers/data/cmor_config/CRU.yml +++ b/esmvaltool/cmorizers/data/cmor_config/CRU.yml @@ -1,15 +1,20 @@ --- # Filename (will be extended by variable name) -filename: 'cru_ts4.02.1901.2017.{raw_name}.dat.nc' +# filename: 'cru_ts4.02.1901.2017.{raw_name}.dat.nc' +filename: 'cru_ts4.07.1901.2022.{raw_name}.dat.nc' # Common global attributes for Cmorizer output attributes: dataset_id: CRU - version: 'TS4.02' + # version: TS4.02 + version: 'TS4.07' tier: 2 modeling_realm: reanaly - project_id: OBS - source: 'https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/cruts.1811131722.v4.02/' + # project_id: OBS # v4.02 + project_id: OBS6 + # source: 'https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/cruts.1811131722.v4.02/' + # source: 'https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.06/cruts.2205201912.v4.06/' + source: 'https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.07/cruts.2304141047.v4.07/' reference: 'cru' comment: '' @@ -19,7 +24,23 @@ variables: mip: Amon raw: tmp raw_units: celsius + tasmin: + mip: Amon + raw: tmn + raw_units: celsius + tasmax: + mip: Amon + raw: tmx + raw_units: celsius pr: mip: Amon raw: pre raw_units: kg m-2 month-1 + evspsblpot: + mip: Emon + raw: pet + raw_units: kg m-2 day-1 + clt: + mip: Amon + raw: cld + raw_units: percent diff --git a/esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml b/esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml new file mode 100644 index 0000000000..f2b7a1053d --- /dev/null +++ b/esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml @@ -0,0 +1,21 @@ +attributes: + project_id: 'OBS' + dataset_id: 'ESACCI-SOILMOISTURE' + tier: 2 + modeling_realm: sat + institution: 'TU Wien (AUT); VanderSat B.V. (NL); Planet Labs (NL); CESBIO (FR), EODC Gmbh (AUT)' + reference: 'esacci-soilmoisture' + source: 'ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/' + title: 'ESA CCI Soil Moisture' + version: 'L3S-SSMV-COMBINED-v08.1' + comment: '' +variables: + sm: + mip: Eday + raw: sm + filename: ESACCI-SOILMOISTURE-L3S-SSMV-COMBINED-{year}????000000-fv08.1.nc + smStderr: + mip: Eday + raw: sm_uncertainty + filename: ESACCI-SOILMOISTURE-L3S-SSMV-COMBINED-{year}????000000-fv08.1.nc + \ No newline at end of file diff --git a/esmvaltool/cmorizers/data/datasets.yml b/esmvaltool/cmorizers/data/datasets.yml index 52b042c381..95dbe8d47d 100644 --- a/esmvaltool/cmorizers/data/datasets.yml +++ b/esmvaltool/cmorizers/data/datasets.yml @@ -1,6 +1,13 @@ # Dataset information --- datasets: + AERONET: + tier: 3 + source: "https://aeronet.gsfc.nasa.gov/" + last_access: 2024-04-06 + info: | + Aerosol Optical Depth information from a worldwide network of stations. + AGCD: tier: 2 source: "http://dx.doi.org/10.25914/6009600786063" @@ -19,6 +26,17 @@ datasets: Data from NCI (National Computing Infrastructure Australia https://nci.org.au/), requires an NCI account and access to Gadi(Supercomputer in Canberra) and the project found in catalogue record. Access can be requested through NCI. NCI is an ESGF node (https://esgf.nci.org.au/projects/esgf-nci/) + + ANUClimate: + tier: 3 + source: "https://dx.doi.org/10.25914/60a10aa56dd1b" + last_access: 2023-11-21 + info: | + Data from NCI project requiring an NCI account and access to GADI + + ANUClimate 2.0 consists of gridded daily and monthly climate variables across the terrestrial landmass of Australia + from at least 1970 to the present. Rainfall grids are generated from 1900 to the present. The underpinning spatial + models have been developed at the Fenner School of Environment and Society of the Australian National University. APHRO-MA: tier: 3 @@ -263,12 +281,19 @@ datasets: CRU: tier: 2 - source: https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/cruts.1811131722.v4.02/ - last_access: 2019-05-16 + source: https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.07/cruts.2304141047.v4.07/ + last_access: 2023-11-06 info: | - Download the following files: - {raw_name}/cru_ts4.02.1901.2017.{raw_name}.dat.nc.gz + Files can be downloaded using the download script (latest version only) + or manually: + {raw_name}/cru_ts4.07.1901.2022.{raw_name}.dat.nc.gz where {raw_name} is the name of the desired variable(s). + Previous versions can be downloaded from the corresponding folders in + https://crudata.uea.ac.uk/cru/data/hrg/. ESMValTools formatter can be used + for older versions with minor adjustments of + ``esmvaltool/cmorizers/data/cmor_config/CRU.yml`` + Exact time coordinates and number of stations are not available version + TS4.02. CT2019: tier: 2 @@ -506,11 +531,11 @@ datasets: ESACCI-SOILMOISTURE: tier: 2 source: ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/ - last_access: 2019-02-01 + last_access: 2024-06-19 info: | Download the data from: - daily_files/COMBINED/v04.2/ - ancillary/v04.2/ + daily_files/COMBINED/v08.1/ + ancillary/v08.1/ Put all files under a single directory (no subdirectories with years). ESACCI-SEA-SURFACE-SALINITY: diff --git a/esmvaltool/cmorizers/data/downloaders/datasets/aeronet.py b/esmvaltool/cmorizers/data/downloaders/datasets/aeronet.py new file mode 100644 index 0000000000..668a688bb6 --- /dev/null +++ b/esmvaltool/cmorizers/data/downloaders/datasets/aeronet.py @@ -0,0 +1,38 @@ +"""Script to download Aeronet from its webpage.""" +import logging + +from esmvaltool.cmorizers.data.downloaders.wget import WGetDownloader + +logger = logging.getLogger(__name__) + + +def download_dataset(config, dataset, dataset_info, start_date, end_date, + overwrite): + """Download dataset. + + Parameters + ---------- + config : dict + ESMValTool's user configuration + dataset : str + Name of the dataset + dataset_info : dict + Dataset information from the datasets.yml file + start_date : datetime + Start of the interval to download + end_date : datetime + End of the interval to download + overwrite : bool + Overwrite already downloaded files + """ + downloader = WGetDownloader( + config=config, + dataset=dataset, + dataset_info=dataset_info, + overwrite=overwrite, + ) + filename = "AOD_Level20_Monthly_V3.tar.gz" + downloader.download_file( + f"https://aeronet.gsfc.nasa.gov/data_push/V3/AOD/{filename}", + wget_options=[], + ) diff --git a/esmvaltool/cmorizers/data/downloaders/datasets/cru.py b/esmvaltool/cmorizers/data/downloaders/datasets/cru.py index 7f2b3010cb..8fbce3e9a3 100644 --- a/esmvaltool/cmorizers/data/downloaders/datasets/cru.py +++ b/esmvaltool/cmorizers/data/downloaders/datasets/cru.py @@ -7,8 +7,9 @@ logger = logging.getLogger(__name__) -def download_dataset(config, dataset, dataset_info, start_date, end_date, - overwrite): +def download_dataset( + config, dataset, dataset_info, start_date, end_date, overwrite +): """Download dataset. Parameters @@ -32,10 +33,18 @@ def download_dataset(config, dataset, dataset_info, start_date, end_date, dataset_info=dataset_info, overwrite=overwrite, ) - for var in ['tmp', 'pre']: + for var in ['tmp', 'pre', 'pet', 'tmn', 'tmx', 'cld']: downloader.download_file( - 'https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/' - f'cruts.1811131722.v4.02/{var}/' - f'cru_ts4.02.1901.2017.{var}.dat.nc.gz', - wget_options=[]) + "https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.07/" + f"cruts.2304141047.v4.07/{var}/" + f"cru_ts4.07.1901.2022.{var}.dat.nc.gz", + wget_options=[], + ) + # for var in ['tmp', 'pre']: # v TS4.02 + # downloader.download_file( + # "https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/" + # f"cruts.1811131722.v4.02/{var}/" + # f"cru_ts4.02.1901.2017.{var}.dat.nc.gz", + # wget_options=[], + # ) unpack_files_in_folder(downloader.local_folder) diff --git a/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py b/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py index d31f330497..0d29e96ff9 100644 --- a/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py +++ b/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py @@ -26,9 +26,9 @@ def download_dataset(config, dataset, dataset_info, start_date, end_date, Overwrite already downloaded files """ if start_date is None: - start_date = datetime(1979, 1, 1) + start_date = datetime(1978, 11, 1) if end_date is None: - end_date = datetime(2016, 1, 1) + end_date = datetime(2022, 12, 31) loop_date = start_date @@ -40,9 +40,9 @@ def download_dataset(config, dataset, dataset_info, start_date, end_date, ) downloader.ftp_name = 'soil_moisture' downloader.connect() - downloader.set_cwd('ancillary/v04.2/') + downloader.set_cwd('ancillary/v08.1/') downloader.download_folder('.') - downloader.set_cwd('daily_files/COMBINED/v04.2/') + downloader.set_cwd('daily_files/COMBINED/v08.1/') while loop_date <= end_date: year = loop_date.year downloader.download_year(f'{year}') diff --git a/esmvaltool/cmorizers/data/formatters/datasets/aeronet.py b/esmvaltool/cmorizers/data/formatters/datasets/aeronet.py new file mode 100755 index 0000000000..e3b5c968d8 --- /dev/null +++ b/esmvaltool/cmorizers/data/formatters/datasets/aeronet.py @@ -0,0 +1,410 @@ +"""ESMValTool CMORizer for Aeronet data. + +Tier + Tier 3: restricted dataset. + +Source + https://aeronet.gsfc.nasa.gov/ + +Last access + 20240406 + +Download and processing instructions + Download the following file: + https://aeronet.gsfc.nasa.gov/data_push/V3/AOD/AOD_Level20_Monthly_V3.tar.gz +""" + +import logging +import os.path +import re +from datetime import datetime +from typing import NamedTuple + +import cf_units +import dask.array as da +import iris +import iris.coords +import iris.cube +import numpy as np +import pandas as pd +from fsspec.implementations.tar import TarFileSystem +from pys2index import S2PointIndex + +from esmvaltool.cmorizers.data import utilities as utils + +logger = logging.getLogger(__name__) + +AERONET_HEADER = "AERONET Version 3;" +LEVEL_HEADER = "Version 3: AOD Level 2.0" +LEVEL_DESCRIPTION = ( + "The following data are automatically cloud cleared and quality assured " + "with pre-field and post-field calibration applied.") +UNITS_HEADER = ( + "UNITS can be found at,,, https://aeronet.gsfc.nasa.gov/new_web/units.html" +) +DATA_QUALITY_LEVEL = "lev20" + +CONTACT_PATTERN = re.compile( + "Contact: PI=(?P[^;]*); PI Email=(?P.*)") + + +def compress_column(data_frame, name): + """Assert all values in DataFrame column are equal, and return value.""" + compressed = data_frame.pop(name).unique() + if len(compressed) != 1: + raise ValueError( + f"Data frame column '{name}' must only contain" + f" one unique value, found {len(compressed)}" + ) + return compressed[0] + + +class AeronetStation(NamedTuple): + """AERONET station data.""" + + station_name: str + latitude: float + longitude: float + elevation: float + contacts: str + data_frame: pd.DataFrame + + +class AeronetStations(NamedTuple): + """AERONET station data lists.""" + + station_name: list[str] + latitude: list[float] + longitude: list[float] + elevation: list[float] + contacts: list[str] + data_frame: list[pd.DataFrame] + + +def parse_contact(contact): + """Parse and reformat contact information in AERONET file.""" + match = CONTACT_PATTERN.fullmatch(contact) + if match is None: + raise RuntimeError(f"Could not parse contact line {contact}") + names = match.group("names").replace("_", " ").split(" and ") + emails = match.group("emails").split("_and_") + mailboxes = ", ".join([ + f'"{name}" <{email}>' for name, email in zip(names, emails) + ]) + return mailboxes + + +def load_file(filesystem, path_like): + """Load AERONET data from fsspec filesystem instance.""" + with filesystem.open(path_like, mode="rt", encoding="iso-8859-1") as file: + aeronet_header = file.readline().strip() + if aeronet_header != AERONET_HEADER: + raise ValueError( + f"File header identifier is '{aeronet_header}'," + f" expected '{AERONET_HEADER}'" + ) + station_name = file.readline().strip() + level_header = file.readline().strip() + if level_header != LEVEL_HEADER: + raise ValueError( + f"File level string is '{level_header}'," + f" expected '{LEVEL_HEADER}'" + ) + level_description = file.readline().strip() + if level_description != LEVEL_DESCRIPTION: + raise ValueError( + f"File data description string is" + f" '{level_description}', expected '{LEVEL_DESCRIPTION}'" + ) + contact_string = file.readline().strip() + units_header = file.readline().strip() + if units_header != UNITS_HEADER: + raise ValueError( + f"File units info string is '{units_header}'," + f" expected '{UNITS_HEADER}'" + ) + data_frame = pd.read_csv( + file, + index_col=0, + na_values=-999.0, + date_format="%Y-%b", + parse_dates=[0], + usecols=lambda x: "AOD_Empty" not in x, + ) + contacts = parse_contact(contact_string) + elevation = compress_column(data_frame, "Elevation(meters)") + latitude = compress_column(data_frame, "Latitude(degrees)") + longitude = compress_column(data_frame, "Longitude(degrees)") + data_quality_level = compress_column(data_frame, "Data_Quality_Level") + if data_quality_level != DATA_QUALITY_LEVEL: + raise ValueError( + f"File data quality level is '{data_quality_level}'," + f" expected '{DATA_QUALITY_LEVEL}'" + ) + station = AeronetStation( + station_name, + latitude, + longitude, + elevation, + contacts, + data_frame, + ) + return station + + +def sort_data_columns(columns): + """Sort AOD station data columns.""" + data_columns = [c for c in columns if "NUM_" not in c] + if len(columns) != 3 * len(data_columns): + raise ValueError( + "Station data contains unexpected number of columns." + ) + aod_columns = [c for c in data_columns if c.startswith("AOD_")] + precipitable_water_columns = [ + c for c in data_columns if c == "Precipitable_Water(cm)" + ] + angstrom_exponent_columns = [ + c for c in data_columns if "_Angstrom_Exponent" in c + ] + if len(data_columns) != (len(aod_columns) + + len(precipitable_water_columns) + + len(angstrom_exponent_columns)): + raise ValueError( + "Station data contains unexpected number of columns." + ) + return (aod_columns, precipitable_water_columns, angstrom_exponent_columns) + + +def merge_stations(stations): + """Collect and merge station data into AeronetStations instance.""" + columns = {} + for name, dtype in ( + ("station_name", str), + ("latitude", np.float64), + ("longitude", np.float64), + ("elevation", np.float64), + ("contacts", str), + ("data_frame", object), + ): + columns[name] = np.array( + [getattr(station, name) for station in stations], + dtype=dtype, + ) + return AeronetStations(**columns) + + +def assemble_cube(stations, idx, wavelengths=None): + """Assemble Iris cube with station data. + + Parameters + ---------- + stations : AeronetStations + Station data + idx : int + Unique ids of all stations + wavelengths : list, optional + Wavelengths to include in data. + + Returns + ------- + Iris cube + Iris cube with station data. + + Raises + ------ + ValueError + If station data has inconsistent variable names. + """ + min_time = np.array([df.index.min() for df in stations.data_frame]).min() + max_time = np.array([df.index.max() for df in stations.data_frame]).max() + date_index = pd.date_range(min_time, max_time, freq="MS") + data_frames = [df.reindex(index=date_index) for df in stations.data_frame] + all_data_columns = np.unique( + np.array([df.columns for df in data_frames], dtype=str), + axis=0, + ) + if len(all_data_columns) != 1: + raise ValueError( + "Station data frames has different sets of column names." + ) + aod_columns, _, _ = sort_data_columns(all_data_columns[0]) + if wavelengths is None: + wavelengths = sorted([int(c[4:-2]) for c in aod_columns]) + + aod = da.stack([ + da.stack([df[f"AOD_{wl}nm"].values for wl in wavelengths], axis=-1) + for df in data_frames + ], axis=-1)[..., idx] + num_days = da.stack([ + da.stack([ + df[f"NUM_DAYS[AOD_{wl}nm]"].values.astype(np.float32) + for wl in wavelengths + ], axis=-1) for df in data_frames + ], axis=-1)[..., idx] + num_points = da.stack([ + da.stack([ + df[f"NUM_POINTS[AOD_{wl}nm]"].values.astype(np.float32) + for wl in wavelengths + ], axis=-1) for df in data_frames + ], axis=-1)[..., idx] + + wavelength_points = da.array(wavelengths, dtype=np.float64) + wavelength_coord = iris.coords.DimCoord( + points=wavelength_points, + standard_name="radiation_wavelength", + long_name="Wavelength", + var_name="wl", + units="nm", + ) + times = date_index.to_pydatetime() + time_points = np.array( + [datetime(year=t.year, month=t.month, day=15) for t in times]) + time_bounds_lower = times + time_bounds_upper = np.array([ + datetime(year=t.year + (t.month == 12), + month=t.month + 1 - (t.month == 12) * 12, + day=1) for t in times + ]) + time_bounds = np.stack([time_bounds_lower, time_bounds_upper], axis=-1) + time_units = cf_units.Unit("days since 1850-01-01", calendar="standard") + time_coord = iris.coords.DimCoord( + points=time_units.date2num(time_points), + standard_name="time", + long_name="time", + var_name="time", + units=time_units, + bounds=time_units.date2num(time_bounds), + ) + index_coord = iris.coords.DimCoord( + points=da.arange(aod.shape[-1]), + standard_name=None, + long_name="Station index (arbitrary)", + var_name="station_index", + units="1", + ) + name_coord = iris.coords.AuxCoord( + points=stations.station_name[idx], + standard_name="platform_name", + long_name="Aeronet Station Name", + var_name="station_name", + ) + elevation_coord = iris.coords.AuxCoord( + points=stations.elevation[idx], + standard_name="height_above_mean_sea_level", + long_name="Elevation", + var_name="elev", + units="m", + ) + latitude_coord = iris.coords.AuxCoord( + points=stations.latitude[idx], + standard_name="latitude", + long_name="Latitude", + var_name="lat", + units="degrees_north", + ) + longitude_coord = iris.coords.AuxCoord( + points=stations.longitude[idx], + standard_name="longitude", + long_name="Longitude", + var_name="lon", + units="degrees_east", + ) + num_days_ancillary = iris.coords.AncillaryVariable( + data=da.ma.masked_array(num_days, da.isnan(num_days), + fill_value=1.e20), + standard_name=None, + long_name="Number of days", + var_name="num_days", + units="1", + ) + num_points_ancillary = iris.coords.AncillaryVariable( + data=da.ma.masked_array(num_days, + da.isnan(num_points), + fill_value=1.e20), + standard_name="number_of_observations", + long_name="Number of observations", + var_name="num_points", + units="1", + ) + cube = iris.cube.Cube( + data=da.ma.masked_array(aod, da.isnan(aod), fill_value=1.e20), + standard_name=( + "atmosphere_optical_thickness_due_to_ambient_aerosol_particles"), + long_name="Aerosol Optical Thickness", + var_name="aod", + units="1", + dim_coords_and_dims=[ + (time_coord, 0), + (wavelength_coord, 1), + (index_coord, 2), + ], + aux_coords_and_dims=[ + (latitude_coord, 2), + (longitude_coord, 2), + (elevation_coord, 2), + (name_coord, 2), + ], + ancillary_variables_and_dims=[ + (num_days_ancillary, (0, 1, 2)), + (num_points_ancillary, (0, 1, 2)), + ], + ) + return cube + + +def build_cube(filesystem, paths, wavelengths=None): + """Build station data cube.""" + individual_stations = [ + load_file(filesystem, file_path) for file_path in paths + ] + stations = merge_stations(individual_stations) + latlon_points = np.stack([stations.latitude, stations.longitude], axis=-1) + index = S2PointIndex(latlon_points) + cell_ids = index.get_cell_ids() + idx = np.argsort(cell_ids) + cube = assemble_cube(stations, idx, wavelengths) + return cube + + +def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): + """Cmorization func call.""" + raw_filename = cfg['filename'] + + tar_file_system = TarFileSystem(f"{in_dir}/{raw_filename}") + paths = tar_file_system.glob("AOD/AOD20/MONTHLY/*.lev20") + versions = np.unique( + np.array([os.path.basename(p).split("_")[1] for p in paths], + dtype=str)) + if len(versions) != 1: + raise ValueError( + "All station datasets in tar file must have same version." + ) + version = versions[0] + wavelengths = sorted( + [var["wavelength"] for var in cfg['variables'].values()]) + cube = build_cube(tar_file_system, paths, wavelengths) + + attrs = cfg['attributes'].copy() + attrs['version'] = version + attrs['source'] = attrs['source'] + + # Run the cmorization + for (short_name, var) in cfg['variables'].items(): + logger.info("CMORizing variable '%s'", short_name) + + idx = wavelengths.index(var["wavelength"]) + sub_cube = cube[:, idx] + + attrs['mip'] = var['mip'] + # attrs['reference'] = var['reference'] + # Fix metadata + utils.set_global_atts(sub_cube, attrs) + + # Save variable + utils.save_variable( + sub_cube, + short_name, + out_dir, + attrs, + unlimited_dimensions=['time'], + ) diff --git a/esmvaltool/cmorizers/data/formatters/datasets/anuclimate.py b/esmvaltool/cmorizers/data/formatters/datasets/anuclimate.py new file mode 100644 index 0000000000..0077bd17a4 --- /dev/null +++ b/esmvaltool/cmorizers/data/formatters/datasets/anuclimate.py @@ -0,0 +1,125 @@ +"""ESMValTool CMORizer for ANU Climate data. + +Tier + Tier 3: restricted dataset. + +Source + https://dx.doi.org/10.25914/60a10aa56dd1b + +Last access + 20231121 + +Download and processing instructions + Data from NCI project requiring an NCI account and access to GADI + Processing is done on GADI + +""" +import logging +import os +import re +import calendar + +import iris + +from esmvaltool.cmorizers.data import utilities as utils + +logger = logging.getLogger(__name__) + + +def _get_filepaths(in_dir, basename): + """Find correct name of file (extend basename with timestamp).""" + regex = re.compile(basename) + return_files = [] + # Search sub folders of raw data directory + for root, _dir, files in os.walk(in_dir, followlinks=True): + + for filename in files: + if regex.match(filename): + + return_files.append(os.path.join(root, filename)) + + return return_files + + +def fix_data_var(cube, var): + """Convert units in cube for the variable.""" + # get month, year from cube + tcoord = cube.coord('time') + tdate = tcoord.units.num2date(tcoord.points[0]) + no_ofdays = calendar.monthrange(tdate.year, tdate.month)[1] + + if var == 'pr': + + cube = cube / (no_ofdays * 86400) # days in month + cube.units = 'kg m-2 s-1' + + elif var in ['tas', 'tasmin', 'tasmax']: # other variables in v1 + cube = cube + 273.15 + cube.units = 'K' + utils.add_height2m(cube) + + else: + logger.info("Variable %s not converted", var) + + return cube, tdate.year + + +def _extract_variable(cmor_info, attrs, filepaths, out_dir): + """Extract variable.""" + var = cmor_info.short_name + logger.info("Var is %s", var) + cbls_2 = iris.cube.CubeList() + cbls_1 = iris.cube.CubeList() + for filepath in filepaths: + cubes = iris.load(filepath) + + cube, year = fix_data_var(cubes[0], var) + + utils.fix_var_metadata(cube, cmor_info) + + utils.set_global_atts(cube, attrs) + + if year < 2000: # split for cube save + cbls_1.append(cube) + else: + cbls_2.append(cube) + + for cbls in [cbls_1, cbls_2]: + iris.util.equalise_attributes(cbls) + cubesave = cbls.concatenate_cube() + utils.fix_coords(cubesave) + + logger.info("Saving file") + utils.save_variable(cubesave, + var, + out_dir, + attrs, + unlimited_dimensions=['time']) + + +def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): + """Cmorization func call.""" + glob_attrs = cfg['attributes'] + cmor_table = cfg['cmor_table'] + + ver = cfg['attributes']['version'] + logger.info(cfg, cfg_user) + + # Run the cmorization, multiple variables + for (var, var_info) in cfg['variables'].items(): + + glob_attrs['mip'] = var_info['mip'] + + raw_filename = cfg['filename'].format(version=ver, + raw=var_info['raw'], + freq=var_info['freq']) + filepaths = _get_filepaths(in_dir, raw_filename) + + if len(filepaths) == 0: + logger.info("no files for %s pattern: %s", var, raw_filename) + logger.info("directory: %s", in_dir) + else: + logger.info("Found files, count %s", len(filepaths)) + + cmor_info = cmor_table.get_variable(var_info['mip'], var) + _extract_variable(cmor_info, glob_attrs, filepaths, out_dir) diff --git a/esmvaltool/cmorizers/data/formatters/datasets/cru.py b/esmvaltool/cmorizers/data/formatters/datasets/cru.py index ab69aacb4b..03d1ac77f4 100644 --- a/esmvaltool/cmorizers/data/formatters/datasets/cru.py +++ b/esmvaltool/cmorizers/data/formatters/datasets/cru.py @@ -4,21 +4,29 @@ Tier 2: other freely-available dataset. Source - https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/cruts.1811131722.v4.02/ + TS4.02: https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.02/cruts.1811131722.v4.02/ # noqa: E501 + TS4.06: https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.06/cruts.2205201912.v4.06/ # noqa: E501 + TS4.07: https://crudata.uea.ac.uk/cru/data/hrg/cru_ts_4.07/cruts.2304141047.v4.07/ # noqa: E501 Last access - 20190516 + TS4.02: 20190516 + TS4.06: 20231012 + TS4.07: 20231012 Download and processing instructions Download the following files: - {raw_name}/cru_ts4.02.1901.2017.{raw_name}.dat.nc.gz - where {raw_name} is the name of the desired variable(s). + ``{raw_name}/cru_ts4.{X}.1901.{end_year}.{raw_name}.dat.nc.gz`` + where ``{raw_name}`` is the name of the desired variable(s) or run + ``esmvaltool data download CRU`` for the latest version """ import logging import os +import cftime import iris +import numpy as np +from cf_units import Unit from iris import NameConstraint from esmvaltool.cmorizers.data import utilities as utils @@ -26,26 +34,53 @@ logger = logging.getLogger(__name__) +def _center_timecoord(cube): + """Set time coordinates to exact center of each month. + + CRU timepoints are not in the center of the month and added bounds + by utils.fix_coords are incorrect. #1981 + """ + time = cube.coord("time") + times = time.units.num2date(time.points) + + # get bounds + starts = [cftime.DatetimeNoLeap(c.year, c.month, 1) for c in times] + ends = [ + cftime.DatetimeNoLeap(c.year, c.month + 1, 1) + if c.month < 12 else cftime.DatetimeNoLeap(c.year + 1, 1, 1) + for c in times + ] + time.bounds = time.units.date2num(np.stack([starts, ends], -1)) + time.points = [np.mean((t1, t2)) for t1, t2 in time.bounds] + + def _extract_variable(short_name, var, cfg, filepath, out_dir): """Extract variable.""" - raw_var = var.get('raw', short_name) + raw_var = var.get("raw", short_name) + version = cfg["attributes"]["version"] cube = iris.load_cube(filepath, NameConstraint(var_name=raw_var)) # Fix units - if 'raw_units' in var: - cube.units = var['raw_units'] - cmor_info = cfg['cmor_table'].get_variable(var['mip'], short_name) + if "raw_units" in var: + cube.units = var["raw_units"] + cmor_info = cfg["cmor_table"].get_variable(var["mip"], short_name) cube.convert_units(cmor_info.units) - utils.convert_timeunits(cube, 1950) + if version in ["TS4.02"]: + utils.convert_timeunits(cube, 1950) + else: + cube.coord("time").convert_units( + Unit("days since 1950-1-1 00:00:00", calendar="gregorian")) # Fix coordinates utils.fix_coords(cube) - if 'height2m' in cmor_info.dimensions: + if "height2m" in cmor_info.dimensions: utils.add_height2m(cube) + if version not in ["TS4.02"]: + _center_timecoord(cube) # Fix metadata - attrs = cfg['attributes'] - attrs['mip'] = var['mip'] + attrs = cfg["attributes"] + attrs["mip"] = var["mip"] utils.fix_var_metadata(cube, cmor_info) utils.set_global_atts(cube, attrs) @@ -54,17 +89,17 @@ def _extract_variable(short_name, var, cfg, filepath, out_dir): short_name, out_dir, attrs, - unlimited_dimensions=['time']) + unlimited_dimensions=["time"]) def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): """Cmorization func call.""" - raw_filepath = os.path.join(in_dir, cfg['filename']) + raw_filepath = os.path.join(in_dir, cfg["filename"]) # Run the cmorization - for (short_name, var) in cfg['variables'].items(): + for short_name, var in cfg["variables"].items(): logger.info("CMORizing variable '%s'", short_name) - raw_var = var.get('raw', short_name) + raw_var = var.get("raw", short_name) filepath = raw_filepath.format(raw_name=raw_var) if filepath is None: continue diff --git a/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl b/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl deleted file mode 100644 index 96ebe7f648..0000000000 --- a/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl +++ /dev/null @@ -1,174 +0,0 @@ -; ############################################################################# -; ESMValTool CMORizer for ESACCI-SOILMOISTURE data -; ############################################################################# -; -; Tier -; Tier 2: other freely-available dataset. -; -; Source -; ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/ -; -; Last access -; 20190201 -; -; Download and processing instructions -; Download the data from: -; daily_files/COMBINED/v04.2/ -; ancillary/v04.2/ -; Put all files under a single directory (no subdirectories with years). -; -; Modification history -; 20190201-righi_mattia: adapted to v2, use new input data version 4.2. -; 20160824-lauer_axel: added processing of volumetric soil moisture -; content (sm, smStderr). -; 20160721-lauer_axel: use daily files, added processing of uncertainty. -; 20150523-righi_mattia: written. -; -; ############################################################################# -loadscript(getenv("esmvaltool_root") + \ - "/data/formatters/interface.ncl") - -begin - - ; Script name (for logger) - DIAG_SCRIPT = "esacci_soilmoisture.ncl" - - ; Source name - OBSNAME = "ESACCI-SOILMOISTURE" - - ; Tier - TIER = 2 - - ; Period - YEAR1 = get_year(start_year, 1979) - YEAR2 = get_year(end_year, 2016) - - ; Selected variable (standard name) - VAR = (/"sm", "smStderr", "dos", "dosStderr"/) - - ; Name in the raw data - NAME = (/"sm", "sm_uncertainty", "sm", "sm_uncertainty"/) - - ; MIP - MIP = (/"Lmon", "Lmon", "Lmon", "Lmon"/) - - ; Frequency - FREQ = (/"mon", "mon", "mon", "mon"/) - - ; CMOR table - CMOR_TABLE = getenv("cmor_tables") + "/custom/CMOR_" + VAR + ".dat" - - ; Type - TYPE = "sat" - - ; Version - VERSION = "L3S-SSMV-COMBINED-v4.2" - - ; Global attributes - SOURCE = "ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/" - REF = \ - "Liu et al., Hydrol. Earth Syst. Sci., doi:10.5194/hess-15-425-2011, 2011." - COMMENT = "" - -end - -begin - - do vv = 0, dimsizes(VAR) - 1 - - log_info("Processing " + VAR(vv) + " (" + MIP(vv) + ")") - - do yy = YEAR1, YEAR2 - - ; Set list of files - files = systemfunc("ls " + input_dir_path + \ - "ESACCI-SOILMOISTURE-L3S-SSMV-" + \ - "COMBINED-" + yy + "????000000-fv04.2.nc") - f = addfiles(files, "r") - delete(files) - - ; Read data - xx = f[:]->$NAME(vv)$ - if (isatt(xx, "scale_factor")) then - tmp = tofloat(xx * xx@scale_factor) - copy_VarAtts(xx, tmp) - copy_VarCoords(xx, tmp) - delete(xx) - xx = tmp - delete(tmp) - end if - delete(f) - - ; Derive dos using porosity - if (any(VAR(vv).eq.(/"dos", "dosStderr"/))) then - g = addfile(input_dir_path + \ - "/ESACCI-SOILMOISTURE-POROSITY_V01.1.nc", "r") - zz = g->porosity - xx = xx * 100. / conform(xx, zz, (/1, 2/)) - delete(zz) - end if - - ; Add a minor time shift for correct extraction of monthly mean below - xx&time = xx&time + 0.1 - - ; Calculate monthly means - if (isStrSubset(VAR(vv), "Stderr")) then - xx2 = xx - xx2 = xx ^ 2 ; save metadata - tmp = calculate_monthly_values(xx2, "avg", 0, False) - delete(xx) - delete(xx2) - xx = sqrt(tmp) - copy_VarAtts(tmp, xx) - copy_VarCoords(tmp, xx) - delete(tmp) - else - tmp = calculate_monthly_values(xx, "avg", 0, False) - delete(xx) - xx = tmp - delete(tmp) - end if - - ; Append to time-series - if (.not.isdefined("output")) then - output = xx - else - output := array_append_record(output, xx, 0) - end if - delete(xx) - - end do - - ; Format coordinates - output!0 = "time" - output!1 = "lat" - output!2 = "lon" - format_coords(output, YEAR1 + "0101", YEAR2 + "1231", FREQ(vv)) - - ; Set variable attributes - tmp = format_variable(output, VAR(vv), CMOR_TABLE(vv)) - delete(output) - output = tmp - delete(tmp) - - ; Calculate coordinate bounds - bounds = guess_coord_bounds(output, FREQ(vv)) - - ; Set global attributes - gAtt = set_global_atts(OBSNAME, TIER, SOURCE, REF, COMMENT) - - ; Output file - DATESTR = YEAR1 + "01-" + YEAR2 + "12" - fout = output_dir_path + \ - str_join((/"OBS", OBSNAME, TYPE, VERSION, \ - MIP(vv), VAR(vv), DATESTR/), "_") + ".nc" - - ; Write variable - write_nc(fout, VAR(vv), output, bounds, gAtt) - delete(gAtt) - delete(output) - delete(bounds) - - end do - -end diff --git a/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py b/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py new file mode 100644 index 0000000000..66859b420b --- /dev/null +++ b/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py @@ -0,0 +1,149 @@ +"""ESMValTool CMORizer for ESACCI-SOILMOISTURE data. + +Tier + Tier 2: other freely-available dataset. + +Source + ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/ + +Last access + 20240626 + +Download and processing instructions + Download the data from: + daily_files/COMBINED/v08.1/ + ancillary/v08.1/ + Put all files under a single directory (no subdirectories with years). + in ${RAWOBS}/Tier2/ESACCI-SOILMOISTURE + +""" + +import glob +import logging +import os +from datetime import datetime +import iris +from esmvalcore.preprocessor import concatenate, monthly_statistics +from cf_units import Unit + +from ...utilities import ( + fix_var_metadata, + fix_dim_coordnames, + fix_bounds, + save_variable, + set_global_atts +) + +logger = logging.getLogger(__name__) + + +def fix_coords(cube): + """Fix coordinates to CMOR standards. + + Fixes coordinates eg time to have correct units, bounds etc; + longitude to be CMOR-compliant 0-360deg; fixes some attributes + and bounds - the user can avert bounds fixing by using supplied + arguments; if bounds are None they will be fixed regardless. + + Parameters + ---------- + cube: iris.cube.Cube + data cube with coordinates to be fixed. + + + Returns + ------- + cube: iris.cube.Cube + data cube with fixed coordinates. + """ + # First fix any completely missing coord var names + fix_dim_coordnames(cube) + + # Convert longitude from -180...180 to 0...360 + cube = cube.intersection(longitude=(0.0, 360.0)) + + # Fix individual coords + for cube_coord in cube.coords(): + # Fix time + if cube_coord.var_name == 'time': + logger.info("Fixing time...") + cube.coord('time').convert_units( + Unit('days since 1970-01-01T00:00:00+00:00', + calendar='proleptic_gregorian')) + + # Fix latitude + if cube_coord.var_name == 'lat': + logger.info("Fixing latitude...") + cube = iris.util.reverse(cube, cube_coord) + + # Fix bounds of all coordinates + fix_bounds(cube, cube_coord) + + return cube + + +def extract_variable(raw_info): + """Extract variables.""" + rawvar = raw_info['name'] + constraint = iris.Constraint(name=rawvar) + if rawvar == 'sm_uncertainty': + sm_cube = iris.load_cube(raw_info['file'], + iris.NameConstraint(var_name='sm')) + ancillary_var = sm_cube.ancillary_variable( + 'Volumetric Soil Moisture Uncertainty' + ) + cube = sm_cube.copy(ancillary_var.core_data()) + else: + cube = iris.load_cube(raw_info['file'], constraint) + + # Remove dysfunctional ancillary data without standard names + for ancillary_variable in cube.ancillary_variables(): + cube.remove_ancillary_variable(ancillary_variable) + + return cube + + +def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): + """Cmorize data.""" + glob_attrs = cfg['attributes'] + if not start_date: + start_date = datetime(1978, 1, 1) + if not end_date: + end_date = datetime(2022, 12, 31) + + # run the cmorization + for var_name, vals in cfg['variables'].items(): + all_data_cubes = [] + if not isinstance(vals, dict): # Ensure vals is a dictionary + raise ValueError( + f"Invalid format for variable {var_name}: {type(vals)}" + ) + var_info = cfg['cmor_table'].get_variable(vals['mip'], var_name) + glob_attrs['mip'] = vals['mip'] + raw_info = {'name': vals['raw']} + inpfile_pattern = os.path.join(in_dir, vals['filename']) + logger.info("CMORizing var %s from file type %s", + var_name, inpfile_pattern) + + for year in range(start_date.year, end_date.year + 1): + year_inpfile_pattern = inpfile_pattern.format(year=year) + inpfiles = sorted(glob.glob(year_inpfile_pattern)) + for inpfile in inpfiles: + raw_info['file'] = inpfile + cube = extract_variable(raw_info) + all_data_cubes.append(cube) + final_cube = concatenate(all_data_cubes) + fix_var_metadata(final_cube, var_info) + final_cube = fix_coords(final_cube) + set_global_atts(final_cube, glob_attrs) + + save_variable(final_cube, var_name, out_dir, glob_attrs, + unlimited_dimensions=['time']) + + # For sm, also save monthly means + if var_name == 'sm': + monthly_mean_cube = monthly_statistics(final_cube, 'mean') + glob_attrs['mip'] = 'Lmon' + monthly_mean_cube.attributes.update(glob_attrs) + save_variable(monthly_mean_cube, var_name, out_dir, glob_attrs, + unlimited_dimensions=['time']) diff --git a/esmvaltool/cmorizers/data/formatters/datasets/nsidc_g02202_sh.py b/esmvaltool/cmorizers/data/formatters/datasets/nsidc_g02202_sh.py index c206f817cb..202e370043 100644 --- a/esmvaltool/cmorizers/data/formatters/datasets/nsidc_g02202_sh.py +++ b/esmvaltool/cmorizers/data/formatters/datasets/nsidc_g02202_sh.py @@ -27,13 +27,15 @@ import re import numpy as np - import iris from cf_units import Unit from iris.coords import AuxCoord +from esmvalcore.cmor._fixes.common import OceanFixGrid +from esmvalcore.cmor.fixes import get_time_bounds from esmvaltool.cmorizers.data import utilities as utils + logger = logging.getLogger(__name__) @@ -71,7 +73,7 @@ def _create_coord(cubes, var_name, standard_name): standard_name=standard_name, long_name=cube.long_name, var_name=var_name, - units='degrees' # cube.units, + units='degrees' ) return coord @@ -85,24 +87,27 @@ def _extract_variable(raw_var, cmor_info, attrs, filepath, out_dir, latlon): cube = cubes.concatenate_cube() iris.util.promote_aux_coord_to_dim_coord(cube, 'projection_y_coordinate') iris.util.promote_aux_coord_to_dim_coord(cube, 'projection_x_coordinate') - cube.coord('projection_y_coordinate').rename('y') - cube.coord('projection_x_coordinate').rename('x') cube.add_aux_coord(latlon[0], (1, 2)) cube.add_aux_coord(latlon[1], (1, 2)) + # add coord typesi area_type = AuxCoord([1.0], standard_name='area_type', var_name='type', long_name='Sea Ice area type') cube.add_aux_coord(area_type) - # cube.convert_units(cmor_info.units) cube.units = '%' cube.data[cube.data > 100] = np.nan cube = cube * 100 - # utils.fix_coords(cube) #latlon multidimensional utils.fix_var_metadata(cube, cmor_info) utils.set_global_atts(cube, attrs) + # latlon are multidimensional, create bounds + siconc = OceanFixGrid(cmor_info) + cube = siconc.fix_metadata(cubes=[cube])[0] + # time bounds + cube.coord('time').bounds = get_time_bounds(cube.coord('time'), + cmor_info.frequency) utils.save_variable(cube, var, @@ -133,8 +138,9 @@ def _create_areacello(cfg, in_dir, sample_cube, glob_attrs, out_dir): long_name=var_info.long_name, var_name=var_info.short_name, units='m2', - dim_coords_and_dims=[(sample_cube.coord('y'), 0), - (sample_cube.coord('x'), 1)]) + # time is index 0, add cell index dim + dim_coords_and_dims=[(sample_cube.coords()[1], 0), + (sample_cube.coords()[2], 1)]) cube.add_aux_coord(lat_coord, (0, 1)) cube.add_aux_coord(sample_cube.coord('longitude'), (0, 1)) utils.fix_var_metadata(cube, var_info) @@ -152,15 +158,17 @@ def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): cubesaux = iris.load(os.path.join(in_dir, 'G02202-cdr-ancillary-sh.nc')) lat_coord = _create_coord(cubesaux, 'lat', 'latitude') lon_coord = _create_coord(cubesaux, 'lon', 'longitude') + year = 1978 # split by year.. sample_cube = None - while year <= 2022: + for year in range(1979, 2022, 1): filepaths = _get_filepaths(in_dir, cfg['filename'], year) if len(filepaths) > 0: - logger.info("Found %d files in '%s'", len(filepaths), in_dir) + logger.info("Year %d: Found %d files in '%s'", + year, len(filepaths), in_dir) for (var, var_info) in cfg['variables'].items(): logger.info("CMORizing variable '%s'", var) @@ -173,10 +181,8 @@ def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): lon_coord]) else: - logger.info("No files found ") - logger.info("year: %d basename: %s", year, cfg['filename']) - - year += 1 + logger.info("No files found year: %d basename: %s", + year, cfg['filename']) - if sample_cube is not None: - _create_areacello(cfg, in_dir, sample_cube, glob_attrs, out_dir) + if sample_cube is not None: + _create_areacello(cfg, in_dir, sample_cube, glob_attrs, out_dir) diff --git a/esmvaltool/cmorizers/data/utilities.py b/esmvaltool/cmorizers/data/utilities.py index e31add6652..853ebd8526 100644 --- a/esmvaltool/cmorizers/data/utilities.py +++ b/esmvaltool/cmorizers/data/utilities.py @@ -359,7 +359,7 @@ def save_variable(cube, var, outdir, attrs, **kwargs): def extract_doi_value(tags): """Extract doi(s) from a bibtex entry.""" reference_doi = [] - pattern = r'doi\ = {(.*?)\},' + pattern = r'doi\s*=\s*{([^}]+)}' if not isinstance(tags, list): tags = [tags] @@ -368,17 +368,18 @@ def extract_doi_value(tags): bibtex_file = REFERENCES_PATH / f'{tag}.bibtex' if bibtex_file.is_file(): reference_entry = bibtex_file.read_text() - if re.search("doi", reference_entry): - reference_doi.append( - f'doi:{re.search(pattern, reference_entry).group(1)}') + dois = re.findall(pattern, reference_entry) + if dois: + for doi in dois: + reference_doi.append(f'doi:{doi}') else: reference_doi.append('doi not found') - logger.warning('The reference file %s does not have a doi.', - bibtex_file) + logger.warning( + 'The reference file %s does not have a doi.', bibtex_file) else: reference_doi.append('doi not found') - logger.warning('The reference file %s does not exist.', - bibtex_file) + logger.warning( + 'The reference file %s does not exist.', bibtex_file) return ', '.join(reference_doi) @@ -424,7 +425,7 @@ def set_global_atts(cube, attrs): # Additional attributes glob_dict.update(attrs) - cube.attributes = glob_dict + cube.attributes.globals = glob_dict def fix_bounds(cube, dim_coord): @@ -495,7 +496,7 @@ def fix_dtype(cube): cube.dtype) cube.data = cube.core_data().astype(np.float32, casting='same_kind') for coord in cube.coords(): - if coord.dtype != np.float64: + if coord.dtype.kind != "U" and coord.dtype != np.float64: logger.info( "Converting data type of coordinate points of '%s' from '%s' " "to 'float64'", coord.name(), coord.dtype) diff --git a/esmvaltool/config-references.yml b/esmvaltool/config-references.yml index 285ace740e..199dc671e0 100644 --- a/esmvaltool/config-references.yml +++ b/esmvaltool/config-references.yml @@ -252,6 +252,10 @@ authors: name: Hansson, Ulf institute: SMHI, Sweden orcid: + hardacre_catherine: + name: Hardacre, Catherine + institute: University of Canterbury, New Zealand + orcid: https://orcid.org/0000-0001-9093-4656 hassler_birgit: name: Hassler, Birgit institute: DLR, Germany @@ -400,6 +404,11 @@ authors: institute: BSC, Spain orcid: github: emchamarro + munday_gregory: + name: Munday, Gregory + institute: MetOffice, UK + orcid: https://orcid.org/0000-0003-4750-9923 + github: mo-gregmunday nikulin_grigory: name: Nikulin, Grigory institute: SMHI, Sweden diff --git a/esmvaltool/diag_scripts/aerosols/aero_utils.py b/esmvaltool/diag_scripts/aerosols/aero_utils.py new file mode 100644 index 0000000000..623a85f2aa --- /dev/null +++ b/esmvaltool/diag_scripts/aerosols/aero_utils.py @@ -0,0 +1,193 @@ +"""Part of the ESMValTool Aerosol diagnostics. + +This module contains utility functions commonly used by aerosol +assessment routines. +""" + +import iris +import numpy as np + + +class AeroAnsError(Exception): + + """Exception class for errors raised when model data is checked in the + extract_pt module. + """ + + +def add_bounds(cube): + """Add bounds to a cube's latitude and longitude coordinates. + + Parameters + ---------- + cube : Iris cube + Iris cube with latitude and longitude coordinates. + + Returns + ------- + cube : Iris cube. + Iris cube with bounds added to the latitude and longitude coordinates. + """ + + if not cube.coord('latitude').has_bounds(): + cube.coord('latitude').guess_bounds() + if not cube.coord('longitude').has_bounds(): + cube.coord('longitude').guess_bounds() + + return cube + + +def extract_pt(icube, pt_lat, pt_lon, height=None, level=None, nearest=False): + """Extracts given location(s) (3-D) from a cube. + + Method + ------ + Uses Iris module Analysis.Interpolate to extract values, + initially based on horizontal coordinates, and then based on + height, if specified. + + If height ('altitude') is requested, checks if cube heights + include orography, i.e. HybridHeights have been derived. + + Parameters + ---------- + icube : Iris cube + pt_lat, pt_lon : Float or list/array of floats. Latitude and longitude + coordinates of desired points. + args: + height : Float or list/array of floats. Altitude (above geoid) of + point. Initialized to None. + level : Integer . Model level or pseudo level or tile number. + Initialized to None, meaning that all available levels in + the cube are used. + nearest : Boolean. Specify whether to use 'nearest neighbour', instead + of 'linear' method while extracting data. Default is False. + + Returns + ------- + data_out : List + List of single point values, corresponding to each point specified. + + Raises + ------ + AeroAnsError : If the number of latitude and longitude points are + mismatched. OR if both and level and height are passed as args. + OR if the cube contains a time coordinate. OR if a pseudo level + coordinate is requested, but not present in the cube. OR if the numbers + of latitude/longitude and height points are mismatched. OR if height + is requested but the cube does not contain an altitude coordinate. + """ + + # Check that input data is a (single) cube + if not isinstance(icube, iris.cube.Cube): + raise AeroAnsError('Extract_pt:First argument must be a single cube') + + # Check if the cube contains a time dimension, which is + # currently unsupported. + if icube.coords()[0].name() == 'time': + raise AeroAnsError( + 'Extract_pt:Cannot handle time dimension at present') + + # Check that equal number of lat/lon pairs are passed in point coordinates. + # Convert arguments to lists for easier processing if necessary. + pt_lat1 = [] + pt_lon1 = [] + + if not isinstance(pt_lat, list): + pt_lat1.append(pt_lat) + pt_lon1.append(pt_lon) + + else: + for n_lat in np.arange(len(pt_lat)): + pt_lat1.append(pt_lat[n_lat]) + pt_lon1.append(pt_lon[n_lat]) + + if len(pt_lat1) != len(pt_lon1): + raise AeroAnsError('Extract_pt:Mismatch in number of lat/long values') + + # Check that both level and height haven't been requested. + if level is not None and height is not None: + raise AeroAnsError('Extract_pt: Both Level and Height requested') + + # Check that the cube has a level coordinate if level has been requested. + if level is not None and not icube.coord( + 'model_level_number') and not icube.coord('pseudo_level'): + raise AeroAnsError('Extract_pt:Level requested, but not found in cube') + + # Check that the number of height points is equal to the number of + # lat/lon pairs. Convert the argument to a list for easier + # processing if necessary. + if height is not None: + pt_hgt = [] + +# if isinstance(height, list): +# pt_hgt.extend(height) +# else: +# pt_hgt.append(height) + pt_hgt.extend(height) if \ + isinstance(height, list) else \ + pt_hgt.append(height) + + if len(pt_lat1) != len(pt_hgt): + raise AeroAnsError( + 'Extract_pt:Mismatch in number of points for lat/long/height') + + # Check that heights have been merged with orography. + if not icube.coords('altitude'): + raise AeroAnsError( + 'Extract_pt:Height requested but input data does not contain \ + "Altitude" coordinate') + + # Store the min and max altitudes from cube data so that user + # cannot request points located below/ above that. + # Will extract =min/max if beyond limits. + hgt_min = icube.coord('altitude').points.min() + hgt_max = icube.coord('altitude').points.max() + + # ---------- Finished checks -- begin processing ------------------------- + + # If level specified, extract slice first + if level is not None: + + try: + icube = icube.extract( + iris.Constraint(model_level_number=level)) + + except Exception: + print('Model level number not available. Use pseudo level') + + else: + icube = icube.extract( + iris.Constraint(pseudo_level=level)) + + # Extract values for specified points lat/lon + # NOTE: Does not seem to handle multiple points if 3-D + data_out = [] + + # Set lat/lon coordinates for model grid cell interpolation + for n_lat1 in np.arange(len(pt_lat1)): + latlon_coords = [('latitude', pt_lat1[n_lat1]), + ('longitude', pt_lon1[n_lat1])] + + if nearest: + tcube = icube.interpolate(latlon_coords, iris.analysis.Nearest()) + else: + tcube = icube.interpolate(latlon_coords, iris.analysis.Linear()) + + # If height specified, interpolate to requested height + if height is not None: + + # Set vertical coordinates for model grid cell interpolation + point = max(pt_hgt[n_lat1], hgt_min) + point = min(pt_hgt[n_lat1], hgt_max) + hgt_coords = [('altitude', point)] + + if nearest: + tcube = tcube.interpolate(hgt_coords, iris.analysis.Nearest()) + else: + tcube = tcube.interpolate(hgt_coords, iris.analysis.Linear()) + + # Append processed data point + data_out.append(tcube.data) + + return data_out diff --git a/esmvaltool/diag_scripts/aerosols/aod_aeronet_assess.py b/esmvaltool/diag_scripts/aerosols/aod_aeronet_assess.py new file mode 100644 index 0000000000..3866e3c51a --- /dev/null +++ b/esmvaltool/diag_scripts/aerosols/aod_aeronet_assess.py @@ -0,0 +1,448 @@ +"""Implement the AOD climatology metric from ground-based + AeroNet observations. +""" +import logging +import os + +import iris +import iris.plot as iplt +import matplotlib.cm as mpl_cm +import matplotlib.lines as mlines +import matplotlib.pyplot as plt +import numpy as np +import scipy +from matplotlib import colors, gridspec +from numpy import ma + +from esmvaltool.diag_scripts.aerosols.aero_utils import add_bounds, extract_pt +from esmvaltool.diag_scripts.shared import group_metadata, run_diagnostic +from esmvaltool.diag_scripts.shared._base import get_plot_filename + +logger = logging.getLogger(os.path.basename(__file__)) +fontsizedict = {"title": 25, "axis": 20, "legend": 18, "ticklabel": 18} + + +def get_provenance_record(filenames): + """Return a provenance record describing the metric. + + Parameters + ---------- + filenames : List of strings + The filenames containing the data used to create the metric. + + Returns + ------- + dictionary + The provenance record describing the metric. + """ + record = { + "ancestors": filenames, + } + + return record + + +def plot_aod_mod_obs(md_data, obs_data, aeronet_obs_cube, plot_dict): + """Plot AOD contour overlaid with Aeronet climatology. + + Parameters + ---------- + md_data : Iris cube + Model AOD as a cube with latitude and longitude coordinates. + obs_data : List. + Observations of AOD from each AeroNET station. + aeronet_obs_cube : Iris cube. + Holds information about Aeronet measurement stations including + station names, station latitude and station longitude. + plot_dict : Dictionary. + Holds plotting settings. + """ + # Plot model data + cf_plot = iplt.contourf(md_data, + plot_dict["Levels"], + colors=plot_dict["Colours"], + extend="max") + + # Latitude and longitude of stations. + anet_aod_lats = aeronet_obs_cube.coord("latitude").points + anet_aod_lons = ((aeronet_obs_cube.coord("longitude").points + 180) % 360 - + 180) + + # Loop over stations + for istn, stn_data in enumerate(obs_data): + if ma.is_masked(stn_data): + continue + + # Find position of the observed AOD on the colorscale. + # np.searchsorted returns index at which inserting new value will + # maintain a sorted array. We use the color to the left of index. + cid = np.searchsorted(plot_dict["Levels"], stn_data) + cid = max(0, cid - 1) # filter out zero and max when seeking 'left' + cid = min(len(plot_dict["Colours"]) - 1, cid) + pcol = plot_dict["Colours"][cid] + + # Overlay contourf with observations + plt.plot( + anet_aod_lons[istn], + anet_aod_lats[istn], + color=pcol, + marker="o", + markeredgecolor="k", + markeredgewidth=2, + markersize=9, + ) + + # Decorate the plot + plt.title(plot_dict["Title"], size=24) + colbar = plt.colorbar(cf_plot, orientation="horizontal") + colbar.set_ticks(plot_dict["Levels"]) + colbar.set_ticklabels(plot_dict["tick_labels"]) + plt.gca().coastlines(color="#525252") + + # Statistics on plot + plt.figtext( + 0.12, + 0.27, + (f'''Global mean AOD={plot_dict["Mean_aod"]:.3f}; RMSE=''' + f'''{plot_dict["RMS_aod"]:.3f}; Stn mean: md=''' + f'''{plot_dict["Stn_mn_md"]:.3f}; obs=''' + f'''{plot_dict["Stn_mn_obs"]:.3f}'''), + size=16, + ) + + +def aod_analyse(model_data, aeronet_obs_cube, clim_seas, wavel): + """Evaluates AOD vs Aeronet, generates plots and returns evaluation + metrics. + + Parameters + ---------- + model_data : Iris Cube. + Contains model output of AOD with coordinates; time, latitude and + longitude. + aeronet_obs_cube : Iris Cube. + Contains information about Aeronet measurement stations including + station names, station latitude and station longitude. + clim_seas : List. + Strings to denote climate seasons ["DJF", "MAM", "JJA", "SON"] + wavel : String. + AOD wavelength, default = 440nm - translates to pseudo-level. + + Returns + ------- + figures : List. + Contains figure instances for the seasonal contour plots overlaid with + observations of AOD from AeroNET. + fig_scatter : Figure object. + The scatter plot comparing modelled and observed AOD at 440nm. + """ + # Convert wave length nm -> um + wv_mi = str(float(wavel) / 1000.0) + + # Get model run id + if "parent_source_id" in model_data.attributes: + model_id = model_data.attributes["parent_source_id"] + else: + model_id = "Multi-Model-Mean" + + # Add bounds for lat and lon if not present + model_data = add_bounds(model_data) + + # Co-locate model grid points with measurement sites --func from aero_utils + anet_aod_lats = aeronet_obs_cube.coord("latitude").points.tolist() + anet_aod_lons = aeronet_obs_cube.coord("longitude").points.tolist() + aod_at_anet = extract_pt(model_data, anet_aod_lats, anet_aod_lons) + + # Set up seasonal contour plots + figures = [] + + clevs = [0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 2.0] + clabs = [ + "0.0", "", "0.1", "", "0.2", "", "0.3", "", "0.4", "", "0.5", "2.0" + ] + cmapr = mpl_cm.get_cmap("brewer_Spectral_11") + cmap = colors.ListedColormap(cmapr(range(cmapr.N))[-1::-1]) + colours = cmap.colors + + # Set up the figure for scatter plotting + fig_scatter = plt.figure(figsize=(10, 10)) + gs_scatter = gridspec.GridSpec(ncols=1, nrows=1) + ax_scatter = fig_scatter.add_subplot(gs_scatter[0, 0]) + col_scatter = ["#081d58", "#41ab5d", "#fe9929", "#7f0000"] + leg_scatter = [] + + # Loop over seasons + for season in aeronet_obs_cube.slices_over("clim_season"): + + # Match Aeronet obs season with model season number + model_sn = [c.lower() for c in clim_seas + ].index(season.coord("clim_season").points[0]) + model_season = model_data[model_sn] + + logger.info('Analysing AOD for %s: %s', {model_id}, + {clim_seas[model_sn]}) + + # Generate statistics required - area-weighted mean + grid_areas = iris.analysis.cartography.area_weights(model_season) + global_mean = model_season.collapsed( + ["latitude", "longitude"], + iris.analysis.MEAN, + weights=grid_areas, + ) + + # Extract model and obs data for season number (model_sn) + seas_anet_obs = season.data + seas_anet_md = np.array([x[model_sn] for x in aod_at_anet]) + + # Match model data with valid obs data + valid_indices = ma.where(seas_anet_obs) + valid_obs = seas_anet_obs[valid_indices] + valid_md = seas_anet_md[valid_indices] + + # Model - obs statistics (diff, model mean and RMS, r2) + diff = valid_md - valid_obs + stn_mn_obs = np.mean(valid_obs) + stn_mn_md = np.mean(valid_md) + rms_aod = np.sqrt(np.mean(diff**2)) + linreg = scipy.stats.linregress(valid_obs, valid_md) + + # Plot scatter of co-located model and obs data + ax_scatter.scatter(valid_obs, valid_md, color=col_scatter[model_sn]) + + # Legend + label = f"{clim_seas[model_sn]} = {linreg.rvalue**2:.2f}" + leg_scatter.append( + mlines.Line2D( + [0], + [0], + marker="o", + color="w", + label=label, + markersize=15, + markerfacecolor=col_scatter[model_sn], + )) + + # Plot contours overlaid with obs for this run and season + fig_cf = plt.figure(figsize=(11, 8), dpi=300) + + n_stn = str(len(valid_obs)) + title = ("\nTotal Aerosol Optical Depth at " + wv_mi + " microns" + + "\n" + model_id + ", " + clim_seas[model_sn] + + ", N stations=" + n_stn) + + # Plot dictionary + plot_dict = { + "Mean_aod": global_mean.data, + "Stn_mn_obs": stn_mn_obs, + "Stn_mn_md": stn_mn_md, + "RMS_aod": rms_aod, + "Levels": clevs, + "Colours": colours, + "tick_labels": clabs, + "Title": title, + "Season": clim_seas[model_sn], + } + plot_aod_mod_obs(model_season, seas_anet_obs, aeronet_obs_cube, + plot_dict) + + figures.append(fig_cf) + + # Decorate the scatter plot + line = mlines.Line2D([0, 1], [0, 1], color="#696969") + transform = ax_scatter.transAxes + line.set_transform(transform) + ax_scatter.add_line(line) + + ax_scatter.set( + xlim=(0, 1), + xticks=np.linspace(0.0, 1.0, num=6), + ylim=(0, 1), + yticks=np.linspace(0.0, 1.0, num=6), + ) + ax_scatter.set_xlabel("AeroNET AOD", fontsize=fontsizedict["axis"]) + ax_scatter.set_ylabel(model_id + " AOD", fontsize=fontsizedict["axis"]) + + ax_scatter.tick_params(axis="both", + which="major", + labelsize=fontsizedict["ticklabel"]) + + ax_scatter.set_title( + "Model vs obs: Total Aerosol Optical Depth \n at " + wv_mi + + " microns", + fontsize=fontsizedict["title"], + ) + + ax_scatter.legend( + handles=leg_scatter, + loc="lower right", + title="Seasonal R2", + title_fontsize=fontsizedict["legend"], + fontsize=fontsizedict["legend"], + ) + + return figures, fig_scatter + + +def preprocess_aod_obs_dataset(obs_dataset): + """Calculate a multiannual seasonal mean AOD climatology. + + Observational AOD timeseries data from AeroNET are used to generate a + multiannual seasonal mean climatology for each AeroNET station. The + user sets thresholds (or uses the default settings) to specify the + amount of valid data required for the climatology. At this stage + ESMValTool preprocessors are unsuitable for pre-processing the AeroNET + AOD observations because of the bespoke nature and application of the + filtering thresholds. + + Parameters + ---------- + obs_dataset : ESMValTool dictionary. Holds meta data for the observational + AOD dataset. + + Returns + ------- + multiannual_seaonal_mean : Iris cube. Preprocessed observational + AOD climatology. + """ + obs_cube = iris.load_cube(obs_dataset[0]["filename"]) + + # Set up thresholds for generating the multi annual seasonal mean + min_days_per_mon = 1 + min_mon_per_seas = 3 + min_seas_per_year = 4 + min_seas_per_clim = 5 + + # Add the clim_season and season_year coordinates. + iris.coord_categorisation.add_year(obs_cube, 'time', name='year') + + iris.coord_categorisation.add_season(obs_cube, 'time', name='clim_season') + + iris.coord_categorisation.add_season_year(obs_cube, + 'time', + name='season_year') + + # Copy obs cube and mask all months with fewer + # "Number of days" than given threshold. + num_days_var = obs_cube.ancillary_variable("Number of days") + masked_months_obs_cube = obs_cube.copy(data=ma.masked_where( + num_days_var.data < min_days_per_mon, obs_cube.data)) + + # Aggregate (mean) by season. + # The number of unmasked months per season is counted, + # and where there are fewer unmasked months than the + # given threshold, the computed mean is masked. + annual_seasonal_mean = masked_months_obs_cube.aggregated_by( + ['clim_season', 'season_year'], + iris.analysis.MEAN, + ) + annual_seasonal_count = masked_months_obs_cube.aggregated_by( + ['clim_season', 'season_year'], + iris.analysis.COUNT, + function=lambda values: ~ma.getmask(values), + ) + annual_seasonal_mean.data = ma.masked_where( + annual_seasonal_count.data < min_mon_per_seas, + annual_seasonal_mean.data, + ) + + # Aggregate (mean) by multi-annual season. + # The number of unmasked seasons per multi-annual season + # is counted, and where there are fewer unmasked seasons + # than the given threshold, the computed multi-annual + # season is masked. + multi_annual_seasonal_mean = annual_seasonal_mean.aggregated_by( + 'clim_season', + iris.analysis.MEAN, + ) + clim_season_agg_count = annual_seasonal_mean.aggregated_by( + 'clim_season', + iris.analysis.COUNT, + function=lambda values: ~ma.getmask(values), + ) + multi_annual_seasonal_mean.data = ma.masked_where( + clim_season_agg_count.data < min_seas_per_clim, + multi_annual_seasonal_mean.data, + ) + year_agg_count = multi_annual_seasonal_mean.aggregated_by( + 'year', + iris.analysis.COUNT, + function=lambda values: ~ma.getmask(values), + ) + + counter = range(len( + multi_annual_seasonal_mean.coord('clim_season').points)) + for iseas in counter: + multi_annual_seasonal_mean.data[iseas, :] = ma.masked_where( + year_agg_count.data[0, :] < min_seas_per_year, + multi_annual_seasonal_mean.data[iseas, :], + ) + + return multi_annual_seasonal_mean + + +def main(config): + """Produce the AOD climatology metric from ground-based AeroNet + observations. + + Parameters + ---------- + wavel : String. + User defined. Default is "440". + config : dict + The ESMValTool configuration. + """ + input_data = config["input_data"] + datasets = group_metadata(input_data.values(), "dataset") + + # Default wavelength + wavel = "440" + + # Produce climatology for observational dataset + obs_dataset = datasets.pop(config["observational_dataset"]) + obs_cube = preprocess_aod_obs_dataset(obs_dataset) + + for model_dataset, group in datasets.items(): + # 'model_dataset' is the name of the model dataset. + # 'group' is a list of dictionaries containing metadata. + logger.info("Processing data for %s", model_dataset) + logger.info(group) + + for attributes in group: + logger.info(attributes["filename"]) + + input_file = attributes["filename"] + provenance_record = get_provenance_record(input_file) + logger.info(provenance_record) + cube = iris.load_cube(input_file) + + # Set up for analysis and plotting + seasons = ["DJF", "MAM", "JJA", "SON"] + + plot_file_prefix = (model_dataset + "_" + attributes["activity"] + + "_" + attributes["mip"] + "_" + + attributes["exp"] + "_" + + attributes["short_name"] + "_" + + str(attributes["start_year"]) + "_" + + str(attributes["end_year"]) + "_") + + # Analysis and plotting for model-obs comparison + figures, fig_scatter = aod_analyse(cube, + obs_cube, + seasons, + wavel=wavel) + + # Save the scatter plot + output_file = plot_file_prefix + "scatter" + output_path = get_plot_filename(output_file, config) + fig_scatter.savefig(output_path) + + # Save the contour plots + for ifig, seas_fig in enumerate(figures): + output_file = plot_file_prefix + seasons[ifig] + output_path = get_plot_filename(output_file, config) + seas_fig.savefig(output_path) + + +if __name__ == "__main__": + with run_diagnostic() as CONFIG: + main(CONFIG) diff --git a/esmvaltool/diag_scripts/austral_jet/main.ncl b/esmvaltool/diag_scripts/austral_jet/main.ncl index c078830687..1b7604d4f5 100644 --- a/esmvaltool/diag_scripts/austral_jet/main.ncl +++ b/esmvaltool/diag_scripts/austral_jet/main.ncl @@ -342,14 +342,22 @@ begin lat_range = f->lat_bnds end if else - if (isatt(f, "plev") .and. \ + f_var = f->$var0$ + if (isatt(f, "plev") .and. \ ; ESMValCore < 2.11.0 isatt(f, "lat_range_0") .and. \ isatt(f, "lat_range_1")) then lev = f@plev lat_range = (/f@lat_range_0, f@lat_range_1/) + else if (isatt(f_var, "plev") .and. \ ; ESMValCore >= 2.11.0 + isatt(f_var, "lat_range_0") .and. \ + isatt(f_var, "lat_range_1")) then + lev = f_var@plev + lat_range = (/f_var@lat_range_0, f_var@lat_range_1/) else error_msg("f", DIAG_SCRIPT, "", "cannot read plev and latrange") end if + end if + delete(f_var) end if log_info("Retrieved pressure level " + lev + " and latitude range " + \ lat_range(0) + " to " + lat_range(1) + " from preprocessed data") diff --git a/esmvaltool/diag_scripts/autoassess/stratosphere/strat_metrics_1.py b/esmvaltool/diag_scripts/autoassess/stratosphere/strat_metrics_1.py index 91a2defcb5..4690741d39 100644 --- a/esmvaltool/diag_scripts/autoassess/stratosphere/strat_metrics_1.py +++ b/esmvaltool/diag_scripts/autoassess/stratosphere/strat_metrics_1.py @@ -276,8 +276,8 @@ def pnj_strength(cube, winter=True): """ # Extract regions of interest notrop = iris.Constraint(air_pressure=lambda p: p < 8000.) - nh_cons = iris.Constraint(latitude=lambda l: l > 0) - sh_cons = iris.Constraint(latitude=lambda l: l < 0) + nh_cons = iris.Constraint(latitude=lambda lat: lat > 0) + sh_cons = iris.Constraint(latitude=lambda lat: lat < 0) nh_tmp = cube.extract(notrop & nh_cons) sh_tmp = cube.extract(notrop & sh_cons) diff --git a/esmvaltool/diag_scripts/climate_patterns/climate_patterns.py b/esmvaltool/diag_scripts/climate_patterns/climate_patterns.py new file mode 100644 index 0000000000..bc265cda00 --- /dev/null +++ b/esmvaltool/diag_scripts/climate_patterns/climate_patterns.py @@ -0,0 +1,658 @@ +# (C) Crown Copyright 2022-2024, Met Office. +"""Diagnostic script to build climate patterns from CMIP6 models. + +Description +----------- +Builds patterns, anomaly and climatology cubes from CMIP6 models. +This diagnostic needs preprocessed mean monthly cubes, with no +gridding requirements. Default re-grid specification exists to +decrease CPU-load and run-time. + +Author +------ +Gregory Munday (Met Office, UK) + + +Configuration options in recipe +------------------------------- +jules_mode: bool, optional (default: false) + options: true, false + def: outputs extra data (anomaly, climatology) per variable + to drive JULES-IMOGEN configuration +parallelise: bool, optional (default: false) + options: true, false + def: parallelises code to run N models at once +area: str, optional (default: global) + options: global, land + def: area over which to calculate climate patterns +""" + +import logging +import os +from pathlib import Path + +import iris +import iris.coord_categorisation +import iris.cube +import numpy as np +import sklearn.linear_model +from esmvalcore.preprocessor import ( + area_statistics, + climate_statistics, + extract_time, +) + +import esmvaltool.diag_scripts.climate_patterns.sub_functions as sf +from esmvaltool.diag_scripts.climate_patterns.plotting import ( + plot_patterns, + plot_timeseries, +) +from esmvaltool.diag_scripts.shared import run_diagnostic + +logger = logging.getLogger(Path(__file__).stem) + + +def calculate_climatology(cube, syr=1850, eyr=1889): + """Handle aggregation to make climatology. + + Parameters + ---------- + cube : cube + cube loaded from config dictionary + syr : int + set climatology start year + eyr : int + set climatology end year + + Returns + ------- + cube_aggregated : cube + 40 year climatology cube from syr-eyr (default 1850-1889) + """ + cube_40yr = extract_time( + cube, + start_year=syr, + start_month=1, + start_day=1, + end_year=eyr, + end_month=12, + end_day=31 + ) + cube_aggregated = climate_statistics(cube_40yr, 'mean', 'month') + + return cube_aggregated + + +def diurnal_temp_range(cubelist): + """Calculate diurnal range from monthly max and min temperatures. + + Parameters + ---------- + cubelist : cubelist + cubelist of tasmin and tasmax + + Returns + ------- + range_cube : cube + cube of calculated diurnal range + """ + range_cube = cubelist[0] - cubelist[1] + + # check in case cubes are wrong way around + if np.mean(range_cube.data) < 0: + range_cube = -range_cube + + range_cube.rename("Diurnal Range") + range_cube.var_name = "range_tl1" + + return range_cube + + +def calculate_diurnal_range(clim_list, ts_list): + """Facilitate diurnal range calculation and appending. + + Parameters + ---------- + clim_list : cubelist + cubelist of climatology cubes + ts_list : cubelist + cubelist of standard timeseries cubes + + Returns + ------- + clim_list_final : cubelist + cubelist of climatology cubes including diurnal range + ts_list_final : cubelist + cubelist of standard timeseries cubes including diurnal range + """ + temp_range_list_clim = iris.cube.CubeList([]) + temp_range_list_ts = iris.cube.CubeList([]) + comb_list = [clim_list, ts_list] + + for cube_list in comb_list: + for cube in cube_list: + if (cube.var_name in ("tasmax", "tasmin")) and cube in clim_list: + temp_range_list_clim.append(cube) + elif (cube.var_name in ("tasmax", "tasmin")) and cube in ts_list: + temp_range_list_ts.append(cube) + else: + pass + + derived_diurnal_clim = diurnal_temp_range(temp_range_list_clim) + derived_diurnal_ts = diurnal_temp_range(temp_range_list_ts) + + # append diurnal range to lists + clim_list_final, ts_list_final = append_diurnal_range( + derived_diurnal_clim, derived_diurnal_ts, clim_list, ts_list + ) + + return clim_list_final, ts_list_final + + +def append_diurnal_range(derived_diurnal_clim, + derived_diurnal_ts, + clim_list, + ts_list): + """Append diurnal range to cubelists. + + Parameters + ---------- + derived_diurnal_clim : cube + derived diurnal climatology cube + derived_diurnal_ts : cube + derived diurnal timeseries cube + clim_list : cubelist + existing climatology cubelist, no range + ts_list : cubelist + existing timeseries cubelist, no range + + Returns + ------- + clim_list_final : cubelist + cubelist of climatology cubes including diurnal range + ts_list_final : cubelist + cubelist of standard timeseries cubes including diurnal range + """ + # creating cube list without tasmax or tasmin + # (since we just wanted the diurnal range) + clim_list_final = iris.cube.CubeList([]) + ts_list_final = iris.cube.CubeList([]) + + for cube in clim_list: + if cube.var_name not in ("tasmax", "tasmin"): + clim_list_final.append(cube) + + for cube in ts_list: + if cube.var_name not in ("tasmax", "tasmin"): + ts_list_final.append(cube) + + clim_list_final.append(derived_diurnal_clim) + ts_list_final.append(derived_diurnal_ts) + + return clim_list_final, ts_list_final + + +def calculate_anomaly(clim_list, ts_list): + """Calculate variables as anomalies, and adds diurnal range as variable. + + Parameters + ---------- + clim_list : cubelist + cubelist of climatology variables + ts_list : cubelist + cubelist of standard variable timeseries + + Returns + ------- + clim_list_final : cubelist + cubelist of clim. vars, inc. diurnal range + anom_list_final : cubelist + cubelist of anomaly vars, inc. diurnal range + """ + # calculate diurnal temperature range cube + clim_list_final, ts_list_final = calculate_diurnal_range( + clim_list, + ts_list + ) + + anom_list_final = ts_list_final.copy() + + # calc the anom by subtracting the monthly climatology from + # the time series + for i, _ in enumerate(ts_list_final): + i_months = ( + anom_list_final[i].coord("month_number").points - 1 + ) # -1 because months are numbered 1..12 + anom_list_final[i].data -= clim_list_final[i][i_months].data + + return clim_list_final, anom_list_final + + +def regression(tas, cube_data, area, ocean_frac=None, land_frac=None): + """Calculate coeffs of regression between global surf temp and variable. + + Parameters + ---------- + tas : cube + near-surface air temperature + cube_data : arr + cube.data array of a variable + area: str + area over which to calculate patterns + ocean_frac: cube + gridded ocean fraction + land_frac: cube + gridded land fraction + + Returns + ------- + slope_array : arr + array of grid cells with same shape as initial cube, + containing the regression slope + """ + if area == "land": + # calculate average warming over land + tas_data = sf.area_avg_landsea( + tas, ocean_frac, land_frac, land=True, return_cube=False + ) + else: + # calculate global average warming + tas_data = area_statistics(tas, 'mean').data + + # Reshape cube for regression + cube_reshaped = cube_data.reshape(cube_data.shape[0], -1) + + # Perform linear regression on valid values + model = sklearn.linear_model.LinearRegression( + fit_intercept=False, copy_X=True + ) + model.fit(tas_data.reshape(-1, 1), cube_reshaped) + + # Extract regression coefficients + slopes = model.coef_ + + # Reshape the regression coefficients back to the shape of the grid cells + slope_array = slopes.reshape(cube_data.shape[1:]) + + return slope_array + + +def create_cube(tas_cube, ssp_cube, array, month_number, units=None): + """Create a new cube from existing metadata, and new aray data. + + Parameters + ---------- + tas_cube: cube + near-surface air temperature + ssp_cube: cube + cube of a given variable + array: array + output array from regression + month_number: int + month related to the regression array + units: str + units related to the regression variable + + Returns + ------- + cube: cube + cube filled with regression array and metadata + + """ + # assigning dim_coords + coord1 = tas_cube.coord(contains_dimension=1) + coord2 = tas_cube.coord(contains_dimension=2) + dim_coords_and_dims = [(coord1, 0), (coord2, 1)] + + # assigning aux_coord + coord_month = iris.coords.AuxCoord(month_number, var_name="imogen_drive") + aux_coords_and_dims = [(coord_month, ())] + + cube = sf.rename_variables(ssp_cube, has_orig_vars=False) + + # creating cube + cube = iris.cube.Cube( + array, + units=units, + dim_coords_and_dims=dim_coords_and_dims, + aux_coords_and_dims=aux_coords_and_dims, + var_name=cube.var_name, + standard_name=cube.standard_name, + ) + + return cube + + +def calculate_regressions( + anom_list, + area, + ocean_frac=None, + land_frac=None, + yrs=86 +): + """Facilitate the calculation of regression coeffs (climate patterns). + + Also creates of a new cube of patterns per variable. + + Parameters + ---------- + anom_list : cubelist + cube list of variables as anomalies + area: str + area over which to calculate patterns + ocean_frac: cube + gridded ocean fraction + land_frac: cube + gridded land fraction + yrs : int + int to specify length of scenario + + Returns + ------- + regr_var_list : cubelist + cube list of newly created regression slope value cubes, for each var + """ + regr_var_list = iris.cube.CubeList([]) + + for cube in anom_list: + if cube.var_name == "tl1_anom": + # convert years to months when selecting + tas = cube[-yrs * 12:] + + for cube in anom_list: + cube = cube[-yrs * 12:] + month_list = iris.cube.CubeList([]) + + # extracting months, regressing, and merging + for i in range(1, 13): + month_cube = cube.extract(iris.Constraint(imogen_drive=i)) + month_tas = tas.extract(iris.Constraint(imogen_drive=i)) + + if area == 'land': + regr_array = regression( + month_tas, + month_cube.data, + area=area, + ocean_frac=ocean_frac, + land_frac=land_frac, + ) + else: + regr_array = regression( + month_tas, + month_cube.data, + area=area, + ) + + if cube.var_name in ("swdown_anom", "lwdown_anom"): + units = "W m-2 K-1" + else: + units = cube.units / tas.units + + # create, and append cube of regression values + month_list.append( + create_cube(tas, cube.copy(), regr_array, i, units=units) + ) + + month_list = month_list.merge_cube() + regr_var_list.append(month_list) + + return regr_var_list + + +def cube_saver(list_of_cubelists, work_path, name_list, jules_mode): + """Save desired cubelists to work_dir, depending on switch settings. + + Parameters + ---------- + list_of_cubelists : list + list containing desired cubelists + work_path : path + path to work_dir, to save cubelists + name_list : list + list of filename strings for saving + jules_mode : str + switch option passed through by ESMValTool config dict + + Returns + ------- + None + """ + if jules_mode: + for i in range(0, 3): + iris.save( + list_of_cubelists[i], + os.path.join(work_path, name_list[i]) + ) + else: + for i, cube in enumerate(list_of_cubelists[2]): + list_of_cubelists[2][i] = sf.rename_variables( + cube, has_orig_vars=False + ) + iris.save( + list_of_cubelists[2], + os.path.join(work_path, name_list[2]) + ) + + +def save_outputs( + cfg, + list_of_cubelists, + model +): + """Save data and plots to relevant directories. + + Parameters + ---------- + cfg: dict + Dictionary passed in by ESMValTool preprocessors + list_of_cubelists: list + List of cubelists to save + model : str + model name + + Returns + ------- + None + """ + work_path, plot_path = sf.make_model_dirs( + cfg, model + ) + + name_list = [ + "climatology_variables.nc", + "anomaly_variables.nc", + "patterns.nc", + ] + + # saving data + plotting + if cfg["jules_mode"] is True: + plot_timeseries( + list_of_cubelists[0], + plot_path, + "40 Year Climatologies, 1850-1889", + "Climatologies" + ) + plot_timeseries( + list_of_cubelists[1], + plot_path, + "Anomaly Timeseries, 1850-2100", + "Anomalies" + ) + plot_patterns(list_of_cubelists[2], plot_path) + cube_saver( + list_of_cubelists, + work_path, + name_list, + jules_mode=cfg["jules_mode"] + ) + + else: + plot_patterns(list_of_cubelists[2], plot_path) + cube_saver( + list_of_cubelists, + work_path, + name_list, + jules_mode=cfg["jules_mode"] + ) + + +def get_provenance_record(): + """Create a provenance record describing the diagnostic data and plot. + + Parameters + ---------- + None + + Returns + ------- + record : dict + provenance record + """ + record = { + "caption": ["Generating Climate Patterns from CMIP6 Models"], + "statistics": ["mean", "other"], + "domains": ["global"], + "themes": ["carbon"], + "realms": ["atmos"], + "authors": ["munday_gregory"], + } + + return record + + +def extract_data_from_cfg(cfg, model): + """Extract model data from the cfg. + + Parameters + ---------- + cfg: dict + Dictionary passed in by ESMValTool preprocessors + model : str + model name + + Returns + ------- + clim_list: cubelist + cubelist of climatologies + ts_list: cubelist + cubelist of spatial timeseries + sftlf: cube + land fraction cube + """ + clim_list = iris.cube.CubeList([]) + ts_list = iris.cube.CubeList([]) + + for dataset in cfg["input_data"].values(): + if dataset["dataset"] == model: + input_file = dataset["filename"] + + # preparing single cube + cube = sf.load_cube(input_file) + + if dataset["exp"] != "historical-ssp585": + sftlf = cube + else: + # appending to timeseries list + ts_list.append(cube) + + # making climatology + clim_cube = calculate_climatology(cube) + clim_list.append(clim_cube) + + if cfg["area"] == 'land': + return clim_list, ts_list, sftlf + + return clim_list, ts_list, None + + +def patterns(model, cfg): + """Driving function for script, taking in model data and saving parameters. + + Parameters + ---------- + model : str + model name + cfg: dict + Dictionary passed in by ESMValTool preprocessors + + Returns + ------- + None + """ + clim_list, ts_list, sftlf = extract_data_from_cfg(cfg, model) + + if cfg["area"] == 'land': + # calculate land/ocean_fracs + ocean_frac, land_frac = sf.ocean_fraction_calc(sftlf) + + # calculate anomaly over historical + ssp timeseries + clim_list_final, anom_list_final = calculate_anomaly(clim_list, ts_list) + + for i, cube in enumerate(clim_list_final): + clim_list_final[i] = sf.rename_variables( + cube, has_orig_vars=True, new_extension="_clim" + ) + anom_list_final[i] = sf.rename_variables( + anom_list_final[i], has_orig_vars=True, new_extension="_anom" + ) + + if cfg["area"] == 'land': + regressions = calculate_regressions( + anom_list_final, + cfg["area"], + ocean_frac=ocean_frac, + land_frac=land_frac + ) + else: + regressions = calculate_regressions( + anom_list_final, cfg["area"] + ) + + list_of_cubelists = [clim_list_final, anom_list_final, regressions] + + save_outputs(cfg, list_of_cubelists, model) + + # Provenance Logging, removed due to sporadic errors. Fix later. + + # model_work_dir, _ = sf.make_model_dirs( + # cfg, + # model + # ) + + # provenance_record = get_provenance_record() + # path = os.path.join(model_work_dir, "patterns.nc") + # with ProvenanceLogger(cfg) as provenance_logger: + # provenance_logger.log(path, provenance_record) + + +def main(cfg): + """Take in driving data with parallelisation options. + + Parameters + ---------- + cfg : dict + the global config dictionary, passed by ESMValTool. + + Returns + ------- + None + """ + input_data = cfg["input_data"].values() + parallelise = cfg["parallelise"] + + models = [] + for mod in input_data: + model = mod["dataset"] + if model not in models: + models.append(model) + + if parallelise is True: + sf.parallelise(patterns)(models, cfg) + else: + for model in models: + patterns(model, cfg) + + +if __name__ == "__main__": + with run_diagnostic() as config: + main(config) diff --git a/esmvaltool/diag_scripts/climate_patterns/plotting.py b/esmvaltool/diag_scripts/climate_patterns/plotting.py new file mode 100644 index 0000000000..447055a392 --- /dev/null +++ b/esmvaltool/diag_scripts/climate_patterns/plotting.py @@ -0,0 +1,128 @@ +# (C) Crown Copyright 2022-2024, Met Office. +"""Script containing plotting functions for driving scripts. + +Author +------ +Gregory Munday (Met Office, UK) +""" +import os + +import iris.quickplot as qplt +import matplotlib.pyplot as plt +import numpy as np + +from esmvalcore.preprocessor import area_statistics + + +def subplot_positions(j): + """Determine sub-plot positions in a 3x3 figure. + + Parameters + ---------- + j : int + index of cube position in cubelist + + Returns + ------- + x_pos : int + x subplot position + y_pos : int + y subplot position + """ + if j <= 2: + y_pos = j + x_pos = 0 + elif 2 < j <= 5: + y_pos = j - 3 + x_pos = 1 + else: + y_pos = j - 6 + x_pos = 2 + + return x_pos, y_pos + + +def plot_patterns(cube_list, plot_path): + """Plot climate patterns for jules_mode: off. + + Parameters + ---------- + cube_list : cubelist + input cubelist for plotting patterns per variable + plot_path : path + path to plot_dir + + Returns + ------- + None + """ + fig, axis = plt.subplots(3, 3, figsize=(14, 12), sharex=True) + fig.suptitle("Patterns from a random grid-cell", fontsize=18, y=0.98) + + plt.figure(figsize=(14, 12)) + plt.subplots_adjust(hspace=0.5) + plt.suptitle("Global Patterns, January", fontsize=18, y=0.95) + + for j, cube in enumerate(cube_list): + # determining plot positions + x_pos, y_pos = subplot_positions(j) + months = np.arange(1, 13) + # plots patterns for an arbitrary grid cell + axis[x_pos, y_pos].plot(months, cube[:, 50, 50].data) + axis[x_pos, + y_pos].set_ylabel(str(cube.var_name) + " / " + str(cube.units)) + if j > 5: + axis[x_pos, y_pos].set_xlabel("Time") + + # January patterns + plt.subplot(3, 3, j + 1) + qplt.pcolormesh(cube[0]) + + plt.tight_layout() + plt.savefig(os.path.join(plot_path, "Patterns"), dpi=300) + plt.close() + + fig.tight_layout() + fig.savefig(os.path.join(plot_path, "Patterns Timeseries"), dpi=300) + + +def plot_timeseries(cubelist, plot_path, title, save_name): + """Plot timeseries and maps of climatologies, anomalies and patterns. + + Parameters + ---------- + cubelist : cubelist + input cubelist for plotting per variable + plot_path : path + path to plot_dir + title: str + title for the figure + save_name: str + name for the saved figure + + Returns + ------- + None + """ + fig, axs = plt.subplots(3, 3, figsize=(14, 12), sharex=True) + fig.suptitle(f"{title}", fontsize=18, y=0.98) + + for j, cube in enumerate(cubelist): + # determining plot positions + x_pos, y_pos = subplot_positions(j) + yrs = (1850 + np.arange(cube.shape[0])).astype("float") + months = np.arange(1, 13) + + # anomaly timeseries + avg_cube = area_statistics(cube, 'mean').data + if save_name == "Climatologies": + axs[x_pos, y_pos].plot(months, avg_cube) + else: + axs[x_pos, y_pos].plot(yrs, avg_cube) + axs[x_pos, + y_pos].set_ylabel(cube.long_name + " / " + str(cube.units)) + if j > 5: + axs[x_pos, y_pos].set_xlabel("Time") + + fig.tight_layout() + fig.savefig(os.path.join(plot_path, f"{save_name}"), dpi=300) diff --git a/esmvaltool/diag_scripts/climate_patterns/sub_functions.py b/esmvaltool/diag_scripts/climate_patterns/sub_functions.py new file mode 100644 index 0000000000..4b3fe00141 --- /dev/null +++ b/esmvaltool/diag_scripts/climate_patterns/sub_functions.py @@ -0,0 +1,267 @@ +# (C) Crown Copyright 2022-2024, Met Office. +"""Script containing relevant sub-functions for driving scripts. + +Author +------ +Gregory Munday (Met Office, UK) +""" + +import logging +import multiprocessing as mp +import os +from functools import partial +from pathlib import Path + +import iris +import iris.analysis.cartography +import iris.coord_categorisation +import dask as da + +logger = logging.getLogger(Path(__file__).stem) + + +def load_cube(filename): + """Load cube, remove any dimensions of length: 1. + + Parameters + ---------- + filename : path + path to load cube file + + Returns + ------- + cube : cube + a cube + """ + logger.debug("Loading %s", filename) + cube = iris.load_cube(filename) + cube = iris.util.squeeze(cube) + + return cube + + +def ocean_fraction_calc(sftlf): + """Calculate gridded land and ocean fractions. + + Parameters + ---------- + sftlf: cube + land-fraction cube from piControl experiment + + Returns + ------- + ocean_frac: cube + ocean_fraction cube for area-weights + land_frac: cube + land_fraction cube for area-weights + """ + sftlf.coord("latitude").coord_system = iris.coord_systems.GeogCS( + 6371229.0 + ) + sftlf.coord("longitude").coord_system = iris.coord_systems.GeogCS( + 6371229.0 + ) + sftof = 100 - sftlf + + ocean_frac = sftof / 100 + land_frac = sftlf / 100 + + return ocean_frac, land_frac + + +def area_avg_landsea(cube, + ocean_frac, + land_frac, + land=True, + return_cube=False): + """Calculate the global mean of a variable in a cube. + + Parameters + ---------- + cube : cube + input cube + ocean_frac : cube + ocean fraction cube, found from sftlf + land_frac : cube + land fraction cube, sftlf + land : bool + option to weight be land or ocean + return_cube : bool + option to return a cube or array + + Returns + ------- + cube2 : cube + cube with collapsed lat-lons, global mean over time + cube2.data : arr + array with collapsed lat-lons, global mean over time + """ + if not cube.coord("latitude").has_bounds(): + cube.coord("latitude").guess_bounds() + if not cube.coord("longitude").has_bounds(): + cube.coord("longitude").guess_bounds() + + global_weights = iris.analysis.cartography.area_weights( + cube, + normalize=False + ) + + if land is False: + ocean_frac.data = da.array.ma.masked_less(ocean_frac.core_data(), 0.01) + weights = iris.analysis.cartography.area_weights( + ocean_frac, + normalize=False + ) + ocean_area = ( + ocean_frac.collapsed( + ["latitude", "longitude"], iris.analysis.SUM, weights=weights + ) + / 1e12 + ) + cube2 = cube * global_weights * ocean_frac + + cube2 = ( + cube2.collapsed(["latitude", "longitude"], iris.analysis.SUM) + / 1e12 + / ocean_area + ) + + if land: + land_frac.data = da.array.ma.masked_less(land_frac.core_data(), 0.01) + weights = iris.analysis.cartography.area_weights( + land_frac, + normalize=False + ) + land_area = ( + land_frac.collapsed( + ["latitude", "longitude"], iris.analysis.SUM, weights=weights + ) + / 1e12 + ) + + # Iris is too strict so we need to use core_data in this calculation + cube2 = cube * global_weights * land_frac.core_data() + cube2 = ( + cube2.collapsed(["latitude", "longitude"], iris.analysis.SUM) + / 1e12 + / land_area + ) + + if return_cube: + return cube2 + + return cube2.data + + +def make_model_dirs(cfg, model): + """Create directories for each input model for saving. + + Parameters + ---------- + cfg: dict + Dictionary passed in by ESMValTool preprocessors + model : str + model name + + Returns + ------- + model_work_dir : path + path to specific model directory in work_dir + model_plot_dir : path + path to specific plot directory in plot_dir + """ + work_path = cfg["work_dir"] + plot_path = cfg["plot_dir"] + model_work_dir = os.path.join(work_path, model) + model_plot_dir = os.path.join(plot_path, model) + + if not os.path.exists(model_work_dir): + os.mkdir(model_work_dir) + if not os.path.exists(model_plot_dir): + os.mkdir(model_plot_dir) + + return model_work_dir, model_plot_dir + + +def rename_variables(cube, has_orig_vars=True, new_extension=""): + """Rename variables and a coord to fit in JULES framework. + + Parameters + ---------- + cube : cube + input cube + has_orig_vars : bool + if True, rename to new var names with correct extension + new_extension : str + extension to add to variable names + + Returns + ------- + cube : cube + cube with renamed variables + """ + original_var_names = ["tas", "range_tl1", "huss", "pr", + "sfcWind", "ps", "rsds", "rlds"] + new_var_names = ["tl1", "range_tl1", "ql1", "precip", + "wind", "pstar", "swdown", "lwdown"] + long_var_names = [ + "Air Temperature", + "Diurnal Range", + "Specific Humidity", + "Precipitation", + "Wind Speed", + "Surface Pressure", + "Surface Downwelling Shortwave Radiation", + "Surface Downwelling Longwave Radiation" + ] + for orig_var, new_var, long_var in zip( + original_var_names, new_var_names, long_var_names + ): + if has_orig_vars: + if cube.var_name == orig_var: + cube.var_name = f"{new_var}{new_extension}" + cube.coord("month_number").rename("imogen_drive") + return cube + else: + if cube.var_name == f"{new_var}_anom": + cube.rename(long_var) + cube.var_name = f"{new_var}_patt" + return cube + if cube.var_name == f"{new_var}_patt": + cube.rename(long_var) + cube.var_name = orig_var + cube.coord("imogen_drive").rename("month_number") + return cube + + return None + + +def parallelise(function, processes=None): + """Parallelise any function, by George Ford, Met Office. + + Parameters + ---------- + function : function + function to be parallelised + processes : int + number of threads to be used in parallelisation + + Returns + ------- + result : any + results of parallelised elements + """ + if processes is None: + processes = max(1, mp.cpu_count() - 1) + if processes <= 0: + processes = 1 + + def easy_parallise(func, sequence, cfg): + with mp.Pool(processes=processes) as pool: + config_wrapper = partial(func, cfg=cfg) + result = pool.map_async(config_wrapper, sequence).get() + pool.close() + pool.join() + return result + + return partial(easy_parallise, function) diff --git a/esmvaltool/diag_scripts/cmorizers/era5.py b/esmvaltool/diag_scripts/cmorizers/era5.py index 28c3d4ca3a..97f410d54c 100644 --- a/esmvaltool/diag_scripts/cmorizers/era5.py +++ b/esmvaltool/diag_scripts/cmorizers/era5.py @@ -26,6 +26,11 @@ def main(cfg): if CMOR_TABLES['CMIP6'].get_variable(mip, info['short_name']): basename = basename.replace('E1hr', mip) basename = basename.replace('E1hr', 'day') + elif info['diagnostic'] == '3hourly': + for mip in ['3hr', 'E3hr', 'CF3hr']: + if CMOR_TABLES['CMIP6'].get_variable(mip, info['short_name']): + basename = basename.replace('E1hr', mip) + basename = basename.replace('E1hr', '3hr') cube = iris.load_cube(file) try: @@ -36,6 +41,9 @@ def main(cfg): if info['diagnostic'] == "monthly": start = time.cell(0).point.strftime("%Y%m") end = time.cell(-1).point.strftime("%Y%m") + elif "hourly" in info['diagnostic']: + start = time.cell(0).point.strftime("%Y%m%d%H%M") + end = time.cell(-1).point.strftime("%Y%m%d%H%M") else: start = time.cell(0).point.strftime("%Y%m%d") end = time.cell(-1).point.strftime("%Y%m%d") diff --git a/esmvaltool/diag_scripts/emergent_constraints/__init__.py b/esmvaltool/diag_scripts/emergent_constraints/__init__.py index 1949719acb..5a03750bbe 100644 --- a/esmvaltool/diag_scripts/emergent_constraints/__init__.py +++ b/esmvaltool/diag_scripts/emergent_constraints/__init__.py @@ -9,10 +9,16 @@ import matplotlib.pyplot as plt import numpy as np import pandas as pd +import scipy import seaborn as sns import yaml +from packaging.version import Version from scipy import integrate from scipy.stats import linregress +if Version(scipy.version.version) < Version('1.14.0'): + from scipy.integrate import simps as simpson +else: + from scipy.integrate import simpson from esmvaltool.diag_scripts.shared import ( ProvenanceLogger, @@ -297,12 +303,16 @@ def _get_data_frame(var_type, cubes, label_all_data, group_by=None): def _metadata_to_dict(metadata): """Convert :class:`iris.cube.CubeMetadata` to :obj:`dict`.""" - new_dict = {} - for (key, val) in metadata._asdict().items(): - if isinstance(val, dict): - new_dict.update(val) - else: - new_dict[key] = val + new_dict = dict(metadata.attributes) + other_keys = [ + 'standard_name', + 'long_name', + 'var_name', + 'units', + 'cell_methods', + ] + for key in other_keys: + new_dict[key] = getattr(metadata, key) return new_dict @@ -1669,7 +1679,7 @@ def cdf(data, pdf): """ idx_range = range(1, len(data) + 1) - cum_dens = [integrate.simps(pdf[:idx], data[:idx]) for idx in idx_range] + cum_dens = [simpson(pdf[:idx], x=data[:idx]) for idx in idx_range] return np.array(cum_dens) diff --git a/esmvaltool/diag_scripts/ensclus/ens_anom.py b/esmvaltool/diag_scripts/ensclus/ens_anom.py index a3b664d11a..ef9c303786 100644 --- a/esmvaltool/diag_scripts/ensclus/ens_anom.py +++ b/esmvaltool/diag_scripts/ensclus/ens_anom.py @@ -1,12 +1,19 @@ """Computation of ensemble anomalies based on a desired value.""" import os + import numpy as np from scipy import stats # User-defined packages -from read_netcdf import read_iris, save_n_2d_fields -from sel_season_area import sel_area, sel_season +from esmvaltool.diag_scripts.ensclus.read_netcdf import ( + read_iris, + save_n_2d_fields, +) +from esmvaltool.diag_scripts.ensclus.sel_season_area import ( + sel_area, + sel_season, +) def ens_anom(filenames, dir_output, name_outputs, varname, numens, season, diff --git a/esmvaltool/diag_scripts/ensclus/ens_eof_kmeans.py b/esmvaltool/diag_scripts/ensclus/ens_eof_kmeans.py index 2be17195b0..940af71278 100644 --- a/esmvaltool/diag_scripts/ensclus/ens_eof_kmeans.py +++ b/esmvaltool/diag_scripts/ensclus/ens_eof_kmeans.py @@ -10,8 +10,8 @@ from sklearn.cluster import KMeans # User-defined libraries -from eof_tool import eof_computation -from read_netcdf import read_n_2d_fields +from esmvaltool.diag_scripts.ensclus.eof_tool import eof_computation +from esmvaltool.diag_scripts.ensclus.read_netcdf import read_n_2d_fields def ens_eof_kmeans(dir_output, name_outputs, numens, numpcs, perc, numclus): diff --git a/esmvaltool/diag_scripts/ensclus/ens_plots.py b/esmvaltool/diag_scripts/ensclus/ens_plots.py index 55ad420b08..1b06acd671 100644 --- a/esmvaltool/diag_scripts/ensclus/ens_plots.py +++ b/esmvaltool/diag_scripts/ensclus/ens_plots.py @@ -3,12 +3,12 @@ import math import os +import cartopy.crs as ccrs import matplotlib.pyplot as plt import numpy as np -import cartopy.crs as ccrs # User-defined libraries -from read_netcdf import read_n_2d_fields +from esmvaltool.diag_scripts.ensclus.read_netcdf import read_n_2d_fields def ens_plots(dir_output, dir_plot, name_outputs, numclus, diff --git a/esmvaltool/diag_scripts/ensclus/ensclus.py b/esmvaltool/diag_scripts/ensclus/ensclus.py index a669a9a02d..df06ea411c 100644 --- a/esmvaltool/diag_scripts/ensclus/ensclus.py +++ b/esmvaltool/diag_scripts/ensclus/ensclus.py @@ -13,16 +13,21 @@ 20170710-mavilia_irene: routines written. """ -import os import logging +import os + import numpy as np -from esmvaltool.diag_scripts.shared import group_metadata, run_diagnostic -from esmvaltool.diag_scripts.shared import ProvenanceLogger, sorted_metadata # Import user diagnostic routines -from ens_anom import ens_anom -from ens_eof_kmeans import ens_eof_kmeans -from ens_plots import ens_plots +from esmvaltool.diag_scripts.ensclus.ens_anom import ens_anom +from esmvaltool.diag_scripts.ensclus.ens_eof_kmeans import ens_eof_kmeans +from esmvaltool.diag_scripts.ensclus.ens_plots import ens_plots +from esmvaltool.diag_scripts.shared import ( + ProvenanceLogger, + group_metadata, + run_diagnostic, + sorted_metadata, +) logger = logging.getLogger(os.path.basename(__file__)) diff --git a/esmvaltool/diag_scripts/examples/correlate.py b/esmvaltool/diag_scripts/examples/correlate.py index 171a24a51f..052f3d2bdc 100644 --- a/esmvaltool/diag_scripts/examples/correlate.py +++ b/esmvaltool/diag_scripts/examples/correlate.py @@ -6,7 +6,7 @@ from iris.analysis import MEAN from iris.analysis.stats import pearsonr -from diagnostic import plot_diagnostic +from esmvaltool.diag_scripts.examples.diagnostic import plot_diagnostic from esmvaltool.diag_scripts.shared import group_metadata, run_diagnostic logger = logging.getLogger(os.path.basename(__file__)) diff --git a/esmvaltool/diag_scripts/hydrology/pcrglobwb.py b/esmvaltool/diag_scripts/hydrology/pcrglobwb.py index 9209f9e127..932e62cd24 100644 --- a/esmvaltool/diag_scripts/hydrology/pcrglobwb.py +++ b/esmvaltool/diag_scripts/hydrology/pcrglobwb.py @@ -4,6 +4,7 @@ import dask.array as da import iris +from esmvalcore.preprocessor import concatenate from esmvaltool.diag_scripts.shared import (ProvenanceLogger, get_diagnostic_filename, @@ -83,8 +84,7 @@ def add_spinup_year(cube, cube_climatology): coord_climatology.guess_bounds() # Create CubeList and concatenate - cube_list = iris.cube.CubeList([cube, cube_climatology]) - new_cube = iris.cube.CubeList(cube_list).concatenate_cube() + new_cube = concatenate([cube, cube_climatology]) return new_cube diff --git a/esmvaltool/diag_scripts/hyint/hyint_etccdi_preproc.R b/esmvaltool/diag_scripts/hyint/hyint_etccdi_preproc.R index bb14906453..36c09f952d 100644 --- a/esmvaltool/diag_scripts/hyint/hyint_etccdi_preproc.R +++ b/esmvaltool/diag_scripts/hyint/hyint_etccdi_preproc.R @@ -29,7 +29,7 @@ hyint_etccdi_preproc <- sfile_tmp0 <- cdo("delvar", args = "time_bnds", input = sfile) gridf <- tempfile() cdo("griddes", input = hyint_file, stdout = gridf) - sfile_tmp1 <- cdo("remapcon2", + sfile_tmp1 <- cdo("remapscon2", args = gridf, input = sfile_tmp0 ) diff --git a/esmvaltool/diag_scripts/hyint/hyint_functions.R b/esmvaltool/diag_scripts/hyint/hyint_functions.R index 5cc2b9d07e..a1595c2a72 100644 --- a/esmvaltool/diag_scripts/hyint/hyint_functions.R +++ b/esmvaltool/diag_scripts/hyint/hyint_functions.R @@ -626,7 +626,7 @@ create_landseamask <- ## Regridding the topographic map to chosen grid cdo( - "remapcon2", + "remapscon2", args = paste0("'", regrid, "'"), input = ftopo, output = regridded_topo @@ -827,7 +827,7 @@ ncdf_opener_universal <- # nolint rotate = "full", interp2grid = F, grid = "r144x73", - remap_method = "remapcon2", + remap_method = "remapscon2", exportlonlat = TRUE, verbose = F) { # load package @@ -1090,7 +1090,7 @@ ncdf_opener <- function(namefile, rotate = "full", interp2grid = F, grid = "r144x73", - remap_method = "remapcon2", + remap_method = "remapscon2", exportlonlat = T) { field <- ncdf_opener_universal( @@ -1123,7 +1123,7 @@ ncdf_opener_time <- # nolint rotate = "full", interp2grid = F, grid = "r144x73", - remap_method = "remapcon2") { + remap_method = "remapscon2") { # function to open netcdf files. It uses ncdf4 library # time selection of month and years needed automatically rotate matrix # to place greenwich at the center (flag "rotate") diff --git a/esmvaltool/diag_scripts/hyint/hyint_preproc.R b/esmvaltool/diag_scripts/hyint/hyint_preproc.R index ec0807cf70..c8350a061d 100644 --- a/esmvaltool/diag_scripts/hyint/hyint_preproc.R +++ b/esmvaltool/diag_scripts/hyint/hyint_preproc.R @@ -22,7 +22,7 @@ hyint_preproc <- function(work_dir, } else { gridf <- rgrid } - tempf <- cdo("remapcon2", args = gridf, input = climofile) + tempf <- cdo("remapscon2", args = gridf, input = climofile) unlink(gridf) } else { tempf <- cdo("addc", args = "0", input = climofile) diff --git a/esmvaltool/diag_scripts/iht_toa/single_model_diagnostics.py b/esmvaltool/diag_scripts/iht_toa/single_model_diagnostics.py index fc917a8aa5..e56240c67a 100644 --- a/esmvaltool/diag_scripts/iht_toa/single_model_diagnostics.py +++ b/esmvaltool/diag_scripts/iht_toa/single_model_diagnostics.py @@ -16,8 +16,8 @@ import numpy as np from iris import NameConstraint from matplotlib import gridspec, rcParams -from poisson_solver import SphericalPoisson +from esmvaltool.diag_scripts.iht_toa.poisson_solver import SphericalPoisson from esmvaltool.diag_scripts.shared import ( group_metadata, run_diagnostic, diff --git a/esmvaltool/diag_scripts/miles/basis_functions.R b/esmvaltool/diag_scripts/miles/basis_functions.R index 2eb65b0789..adab0c0d6a 100644 --- a/esmvaltool/diag_scripts/miles/basis_functions.R +++ b/esmvaltool/diag_scripts/miles/basis_functions.R @@ -336,7 +336,7 @@ ncdf_opener_universal <- # nolint interp2grid = FALSE, fillmiss = FALSE, grid = "r144x73", - remap_method = "remapcon2", + remap_method = "remapscon2", exportlonlat = TRUE, verbose = TRUE) { # load package @@ -645,7 +645,7 @@ ncdf_opener <- function(namefile, interp2grid = FALSE, fillmiss = FALSE, grid = "r144x73", - remap_method = "remapcon2", + remap_method = "remapscon2", exportlonlat = TRUE, verbose = FALSE) { field <- ncdf_opener_universal( diff --git a/esmvaltool/diag_scripts/monitor/multi_datasets.py b/esmvaltool/diag_scripts/monitor/multi_datasets.py index a760a312f6..879346954c 100644 --- a/esmvaltool/diag_scripts/monitor/multi_datasets.py +++ b/esmvaltool/diag_scripts/monitor/multi_datasets.py @@ -138,12 +138,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the datasets plotted in the - corresponding plot, e.g., ``{short_name}``, ``{exp}``. Facets like - ``{project}`` that vary between the different datasets will be transformed - to something like ``ambiguous_project``. Examples: ``title: 'Awesome Plot - of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. time_format: str, optional (default: None) :func:`~datetime.datetime.strftime` format string that is used to format the time axis using :class:`matplotlib.dates.DateFormatter`. If ``None``, @@ -171,12 +171,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the datasets plotted in the - corresponding plot, e.g., ``{short_name}``, ``{exp}``. Facets like - ``{project}`` that vary between the different datasets will be transformed - to something like ``ambiguous_project``. Examples: ``title: 'Awesome Plot - of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. Configuration options for plot type ``map`` ------------------------------------------- @@ -247,10 +247,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the corresponding dataset, e.g., - ``{project}``, ``{short_name}``, ``{exp}``. Examples: ``title: 'Awesome - Plot of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. rasterize: bool, optional (default: True) If ``True``, use rasterization_ for map plots to produce smaller files. This is only relevant for vector graphics (e.g., ``output_file_type: @@ -326,10 +328,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the corresponding dataset, e.g., - ``{project}``, ``{short_name}``, ``{exp}``. Examples: ``title: 'Awesome - Plot of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. rasterize: bool, optional (default: True) If ``True``, use rasterization_ for profile plots to produce smaller files. This is only relevant for vector graphics (e.g., ``output_file_type: @@ -378,12 +382,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the datasets plotted in the - corresponding plot, e.g., ``{short_name}``, ``{exp}``. Facets like - ``{project}`` that vary between the different datasets will be transformed - to something like ``ambiguous_project``. Examples: ``title: 'Awesome Plot - of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. show_y_minor_ticklabels: bool, optional (default: False) Show tick labels for the minor ticks on the Y axis. @@ -409,12 +413,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the datasets plotted in the - corresponding plot, e.g., ``{short_name}``, ``{exp}``. Facets like - ``{project}`` that vary between the different datasets will be transformed - to something like ``ambiguous_project``. Examples: ``title: 'Awesome Plot - of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. Configuration options for plot type ``hovmoeller_z_vs_time`` ------------------------------------------------------------ @@ -476,10 +480,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the corresponding dataset, e.g., - ``{project}``, ``{short_name}``, ``{exp}``. Examples: ``title: 'Awesome - Plot of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. rasterize: bool, optional (default: True) If ``True``, use rasterization_ for profile plots to produce smaller files. This is only relevant for vector graphics (e.g., ``output_file_type: @@ -559,10 +565,12 @@ pyplot_kwargs: dict, optional Optional calls to functions of :mod:`matplotlib.pyplot`. Dictionary keys are functions of :mod:`matplotlib.pyplot`. Dictionary values are used as - single argument for these functions. String arguments can include facets in - curly brackets which will be derived from the corresponding dataset, e.g., - ``{project}``, ``{short_name}``, ``{exp}``. Examples: ``title: 'Awesome - Plot of {long_name}'``, ``xlabel: '{short_name}'``, ``xlim: [0, 5]``. + argument(s) for these functions (if values are dictionaries, these are + interpreted as keyword arguments; otherwise a single argument is assumed). + String arguments can include facets in curly brackets which will be derived + from the corresponding dataset, e.g., ``{project}``, ``{short_name}``, + ``{exp}``. Examples: ``title: 'Awesome Plot of {long_name}'``, ``xlabel: + '{short_name}'``, ``xlim: [0, 5]``. rasterize: bool, optional (default: True) If ``True``, use rasterization_ for profile plots to produce smaller files. This is only relevant for vector graphics (e.g., ``output_file_type: @@ -575,6 +583,11 @@ :func:`~datetime.datetime.strftime` format string that is used to format the time axis using :class:`matplotlib.dates.DateFormatter`. If ``None``, use the default formatting imposed by the iris plotting function. +time_on: str, optional (default: y-axis) + Optional switch to change the orientation of the plot so that time is on + the x-axis ``time_on: x-axis``. Default orientation is time on y-axis and + lat/lon on x-axis. + .. hint:: @@ -604,6 +617,7 @@ from iris.analysis.cartography import area_weights from iris.coord_categorisation import add_year from iris.coords import AuxCoord +from iris.exceptions import ConstraintMismatchError from matplotlib.colors import CenteredNorm from matplotlib.gridspec import GridSpec from matplotlib.ticker import ( @@ -842,6 +856,7 @@ def __init__(self, config): 'show_x_minor_ticks', True ) self.plots[plot_type].setdefault('time_format', None) + self.plots[plot_type].setdefault('time_on', 'y-axis') # Check that facet_used_for_labels is present for every dataset for dataset in self.input_data: @@ -1099,7 +1114,22 @@ def _load_and_preprocess_data(self): for dataset in input_data: filename = dataset['filename'] logger.info("Loading %s", filename) - cube = iris.load_cube(filename) + cubes = iris.load(filename) + if len(cubes) == 1: + cube = cubes[0] + else: + var_name = dataset['short_name'] + try: + cube = cubes.extract_cube(iris.NameConstraint( + var_name=var_name + )) + except ConstraintMismatchError as exc: + var_names = [c.var_name for c in cubes] + raise ValueError( + f"Cannot load data: multiple variables ({var_names}) " + f"are available in file {filename}, but not the " + f"requested '{var_name}'" + ) from exc # Fix time coordinate if present if cube.coords('time', dim_coords=True): @@ -1626,6 +1656,10 @@ def _plot_hovmoeller_time_vs_lat_or_lon_with_ref(self, plot_func, dataset, ref_cube = ref_dataset['cube'] dim_coords_dat = self._check_cube_dimensions(cube, plot_type) self._check_cube_dimensions(ref_cube, plot_type) + if 'latitude' in dim_coords_dat: + non_time_label = 'latitude [°N]' + else: + non_time_label = 'longitude [°E]' # Create single figure with multiple axes with mpl.rc_context(self._get_custom_mpl_rc_params(plot_type)): @@ -1640,16 +1674,23 @@ def _plot_hovmoeller_time_vs_lat_or_lon_with_ref(self, plot_func, dataset, # Plot dataset (top left) axes_data = fig.add_subplot(gridspec[0:2, 0:2]) plot_kwargs['axes'] = axes_data - coord_names = [coord[0].name() for coord in cube.dim_coords] - if coord_names[0] == "time": - coord_names.reverse() - plot_kwargs['coords'] = coord_names + if self.plots[plot_type]['time_on'] == 'x-axis': + plot_kwargs['coords'] = list(dim_coords_dat) + x_label = 'time' + y_label = non_time_label + time_axis = axes_data.get_xaxis() + else: + plot_kwargs['coords'] = list(reversed(dim_coords_dat)) + x_label = non_time_label + y_label = 'time' + time_axis = axes_data.get_yaxis() plot_data = plot_func(cube, **plot_kwargs) axes_data.set_title(self._get_label(dataset), pad=3.0) - axes_data.set_ylabel('time') + axes_data.set_ylabel(y_label) if self.plots[plot_type]['time_format'] is not None: - axes_data.get_yaxis().set_major_formatter(mdates.DateFormatter( - self.plots[plot_type]['time_format'])) + time_axis.set_major_formatter(mdates.DateFormatter( + self.plots[plot_type]['time_format'] + )) if self.plots[plot_type]['show_y_minor_ticks']: axes_data.get_yaxis().set_minor_locator(AutoMinorLocator()) if self.plots[plot_type]['show_x_minor_ticks']: @@ -1681,17 +1722,14 @@ def _plot_hovmoeller_time_vs_lat_or_lon_with_ref(self, plot_func, dataset, plot_kwargs_bias = self._get_plot_kwargs(plot_type, dataset, bias=True) plot_kwargs_bias['axes'] = axes_bias - plot_kwargs_bias['coords'] = coord_names + plot_kwargs_bias['coords'] = plot_kwargs['coords'] plot_bias = plot_func(bias_cube, **plot_kwargs_bias) axes_bias.set_title( f"{self._get_label(dataset)} - {self._get_label(ref_dataset)}", pad=3.0, ) - axes_bias.set_ylabel('time') - if 'latitude' in dim_coords_dat: - axes_bias.set_xlabel('latitude [°N]') - elif 'longitude' in dim_coords_dat: - axes_bias.set_xlabel('longitude [°E]') + axes_bias.set_xlabel(x_label) + axes_bias.set_ylabel(y_label) cbar_kwargs_bias = self._get_cbar_kwargs(plot_type, bias=True) cbar_bias = fig.colorbar(plot_bias, ax=axes_bias, **cbar_kwargs_bias) @@ -1732,6 +1770,10 @@ def _plot_hovmoeller_time_vs_lat_or_lon_without_ref(self, plot_func, # Make sure that the data has the correct dimensions cube = dataset['cube'] dim_coords_dat = self._check_cube_dimensions(cube, plot_type) + if 'latitude' in dim_coords_dat: + non_time_label = 'latitude [°N]' + else: + non_time_label = 'longitude [°E]' # Create plot with desired settings with mpl.rc_context(self._get_custom_mpl_rc_params(plot_type)): @@ -1740,8 +1782,17 @@ def _plot_hovmoeller_time_vs_lat_or_lon_without_ref(self, plot_func, plot_kwargs = self._get_plot_kwargs(plot_type, dataset) plot_kwargs['axes'] = axes - # Make sure time is on y-axis - plot_kwargs['coords'] = list(reversed(dim_coords_dat)) + # Put time on desired axis + if self.plots[plot_type]['time_on'] == 'x-axis': + plot_kwargs['coords'] = list(dim_coords_dat) + x_label = 'time' + y_label = non_time_label + time_axis = axes.get_xaxis() + else: + plot_kwargs['coords'] = list(reversed(dim_coords_dat)) + x_label = non_time_label + y_label = 'time' + time_axis = axes.get_yaxis() plot_hovmoeller = plot_func(cube, **plot_kwargs) # Setup colorbar @@ -1755,15 +1806,12 @@ def _plot_hovmoeller_time_vs_lat_or_lon_without_ref(self, plot_func, # Customize plot axes.set_title(self._get_label(dataset)) fig.suptitle(dataset['long_name']) - if 'latitude' in dim_coords_dat: - axes.set_xlabel('latitude [°N]') - elif 'longitude' in dim_coords_dat: - axes.set_xlabel('longitude [°E]') - axes.set_ylabel('time') + axes.set_xlabel(x_label) + axes.set_ylabel(y_label) if self.plots[plot_type]['time_format'] is not None: - axes.get_yaxis().set_major_formatter(mdates.DateFormatter( - self.plots[plot_type]['time_format']) - ) + time_axis.set_major_formatter(mdates.DateFormatter( + self.plots[plot_type]['time_format'] + )) if self.plots[plot_type]['show_y_minor_ticks']: axes.get_yaxis().set_minor_locator(AutoMinorLocator()) if self.plots[plot_type]['show_x_minor_ticks']: @@ -1791,6 +1839,8 @@ def _process_pyplot_kwargs(self, plot_type, dataset): ) if arg is None: getattr(plt, func)() + elif isinstance(arg, dict): + getattr(plt, func)(**arg) else: getattr(plt, func)(arg) diff --git a/esmvaltool/diag_scripts/mpqb/mpqb_lineplot.py b/esmvaltool/diag_scripts/mpqb/mpqb_lineplot.py index fe4cf2deb0..b08a2cd012 100644 --- a/esmvaltool/diag_scripts/mpqb/mpqb_lineplot.py +++ b/esmvaltool/diag_scripts/mpqb/mpqb_lineplot.py @@ -7,9 +7,9 @@ import iris import matplotlib.dates as mdates import matplotlib.pyplot as plt -from mpqb_utils import get_mpqb_cfg import esmvaltool.diag_scripts.shared.iris_helpers as ih +from esmvaltool.diag_scripts.mpqb.mpqb_utils import get_mpqb_cfg from esmvaltool.diag_scripts.shared import group_metadata, run_diagnostic from esmvaltool.diag_scripts.shared._base import ( ProvenanceLogger, diff --git a/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_anncyc.py b/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_anncyc.py index e2a5a662b2..d087499d60 100644 --- a/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_anncyc.py +++ b/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_anncyc.py @@ -6,8 +6,8 @@ import iris import matplotlib.pyplot as plt -from mpqb_utils import get_mpqb_cfg +from esmvaltool.diag_scripts.mpqb.mpqb_utils import get_mpqb_cfg from esmvaltool.diag_scripts.shared import group_metadata, run_diagnostic from esmvaltool.diag_scripts.shared._base import ( ProvenanceLogger, diff --git a/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_growthrate.py b/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_growthrate.py index a6ec136966..90662be72b 100644 --- a/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_growthrate.py +++ b/esmvaltool/diag_scripts/mpqb/mpqb_lineplot_growthrate.py @@ -8,9 +8,9 @@ import matplotlib.dates as mdates import matplotlib.pyplot as plt import numpy as np -from mpqb_utils import get_mpqb_cfg import esmvaltool.diag_scripts.shared.iris_helpers as ih +from esmvaltool.diag_scripts.mpqb.mpqb_utils import get_mpqb_cfg from esmvaltool.diag_scripts.shared import group_metadata, run_diagnostic from esmvaltool.diag_scripts.shared._base import ( ProvenanceLogger, diff --git a/esmvaltool/diag_scripts/quantilebias/quantilebias_functions.R b/esmvaltool/diag_scripts/quantilebias/quantilebias_functions.R index 8d520cf545..cbd9e72acf 100644 --- a/esmvaltool/diag_scripts/quantilebias/quantilebias_functions.R +++ b/esmvaltool/diag_scripts/quantilebias/quantilebias_functions.R @@ -62,7 +62,7 @@ ncdf_opener_universal <- # nolint rotate = "full", interp2grid = F, grid = "r144x73", - remap_method = "remapcon2", + remap_method = "remapscon2", exportlonlat = TRUE, verbose = F) { # load package @@ -326,7 +326,7 @@ ncdf_opener <- function(namefile, rotate = "full", interp2grid = F, grid = "r144x73", - remap_method = "remapcon2", + remap_method = "remapscon2", exportlonlat = T) { field <- ncdf_opener_universal( diff --git a/esmvaltool/diag_scripts/shared/_base.py b/esmvaltool/diag_scripts/shared/_base.py index b5fc072875..1789909130 100644 --- a/esmvaltool/diag_scripts/shared/_base.py +++ b/esmvaltool/diag_scripts/shared/_base.py @@ -16,6 +16,8 @@ logger = logging.getLogger(__name__) +iris.FUTURE.save_split_attrs = True + def get_plot_filename(basename, cfg): """Get a valid path for saving a diagnostic plot. diff --git a/esmvaltool/diag_scripts/shared/io.py b/esmvaltool/diag_scripts/shared/io.py index 4889f5b1c1..f3e709bd48 100644 --- a/esmvaltool/diag_scripts/shared/io.py +++ b/esmvaltool/diag_scripts/shared/io.py @@ -22,6 +22,8 @@ 'short_name', ] +iris.FUTURE.save_split_attrs = True + def _has_necessary_attributes(metadata, only_var_attrs=False, diff --git a/esmvaltool/diag_scripts/weighting/climwip/calibrate_sigmas.py b/esmvaltool/diag_scripts/weighting/climwip/calibrate_sigmas.py index 0998346b22..1d85e1f95a 100644 --- a/esmvaltool/diag_scripts/weighting/climwip/calibrate_sigmas.py +++ b/esmvaltool/diag_scripts/weighting/climwip/calibrate_sigmas.py @@ -6,7 +6,13 @@ import matplotlib.pyplot as plt import numpy as np import xarray as xr -from core_functions import ( +from scipy.optimize import brute + +from esmvaltool.diag_scripts.shared import ( + get_diagnostic_filename, + get_plot_filename, +) +from esmvaltool.diag_scripts.weighting.climwip.core_functions import ( area_weighted_mean, calculate_model_distances, calculate_weights, @@ -14,17 +20,11 @@ compute_overall_mean, weighted_quantile, ) -from io_functions import ( +from esmvaltool.diag_scripts.weighting.climwip.io_functions import ( read_metadata, read_model_data, read_model_data_ancestor, ) -from scipy.optimize import brute - -from esmvaltool.diag_scripts.shared import ( - get_diagnostic_filename, - get_plot_filename, -) logger = logging.getLogger(os.path.basename(__file__)) diff --git a/esmvaltool/diag_scripts/weighting/climwip/main.py b/esmvaltool/diag_scripts/weighting/climwip/main.py index 6b22399547..f46db62090 100644 --- a/esmvaltool/diag_scripts/weighting/climwip/main.py +++ b/esmvaltool/diag_scripts/weighting/climwip/main.py @@ -10,15 +10,22 @@ import numpy as np import seaborn as sns import xarray as xr -from calibrate_sigmas import calibrate_performance_sigma -from core_functions import ( + +from esmvaltool.diag_scripts.shared import ( + get_diagnostic_filename, + get_plot_filename, + run_diagnostic, +) +from esmvaltool.diag_scripts.weighting.climwip.calibrate_sigmas import ( + calibrate_performance_sigma, ) +from esmvaltool.diag_scripts.weighting.climwip.core_functions import ( area_weighted_mean, calculate_model_distances, calculate_weights, combine_ensemble_members, compute_overall_mean, ) -from io_functions import ( +from esmvaltool.diag_scripts.weighting.climwip.io_functions import ( log_provenance, read_metadata, read_model_data, @@ -27,11 +34,6 @@ read_observation_data_ancestor, ) -from esmvaltool.diag_scripts.shared import ( - get_diagnostic_filename, - get_plot_filename, - run_diagnostic, -) logger = logging.getLogger(os.path.basename(__file__)) diff --git a/esmvaltool/diag_scripts/weighting/plot_utilities.py b/esmvaltool/diag_scripts/weighting/plot_utilities.py index 706dfd64c9..a071a3c7f0 100644 --- a/esmvaltool/diag_scripts/weighting/plot_utilities.py +++ b/esmvaltool/diag_scripts/weighting/plot_utilities.py @@ -3,7 +3,8 @@ import xarray as xr -from climwip.core_functions import weighted_quantile +from esmvaltool.diag_scripts.weighting.climwip.core_functions import ( + weighted_quantile, ) def read_weights(filename: str) -> dict: diff --git a/esmvaltool/diag_scripts/weighting/weighted_temperature_graph.py b/esmvaltool/diag_scripts/weighting/weighted_temperature_graph.py index 5b871283d7..f5f1086e1e 100644 --- a/esmvaltool/diag_scripts/weighting/weighted_temperature_graph.py +++ b/esmvaltool/diag_scripts/weighting/weighted_temperature_graph.py @@ -10,13 +10,16 @@ import matplotlib.pyplot as plt import numpy as np import xarray as xr -from climwip.io_functions import log_provenance, read_model_data from esmvaltool.diag_scripts.shared import ( get_diagnostic_filename, get_plot_filename, run_diagnostic, ) +from esmvaltool.diag_scripts.weighting.climwip.io_functions import ( + log_provenance, + read_model_data, +) from esmvaltool.diag_scripts.weighting.plot_utilities import ( calculate_percentiles, read_metadata, diff --git a/esmvaltool/diag_scripts/weighting/weighted_temperature_map.py b/esmvaltool/diag_scripts/weighting/weighted_temperature_map.py index 7a161d2535..667a382d94 100644 --- a/esmvaltool/diag_scripts/weighting/weighted_temperature_map.py +++ b/esmvaltool/diag_scripts/weighting/weighted_temperature_map.py @@ -11,13 +11,16 @@ import matplotlib.pyplot as plt import numpy as np from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter -from climwip.io_functions import log_provenance, read_model_data from esmvaltool.diag_scripts.shared import ( get_diagnostic_filename, get_plot_filename, run_diagnostic, ) +from esmvaltool.diag_scripts.weighting.climwip.io_functions import ( + log_provenance, + read_model_data, +) from esmvaltool.diag_scripts.weighting.plot_utilities import ( calculate_percentiles, read_metadata, diff --git a/esmvaltool/diag_scripts/zmnam/zmnam.py b/esmvaltool/diag_scripts/zmnam/zmnam.py index d86ee48458..c0450c117a 100644 --- a/esmvaltool/diag_scripts/zmnam/zmnam.py +++ b/esmvaltool/diag_scripts/zmnam/zmnam.py @@ -20,9 +20,12 @@ from esmvaltool.diag_scripts.shared import ProvenanceLogger, run_diagnostic # Import zmnam diagnostic routines -from zmnam_calc import zmnam_calc -from zmnam_plot import zmnam_plot -from zmnam_preproc import (zmnam_preproc, zmnam_preproc_clean) +from esmvaltool.diag_scripts.zmnam.zmnam_calc import zmnam_calc +from esmvaltool.diag_scripts.zmnam.zmnam_plot import zmnam_plot +from esmvaltool.diag_scripts.zmnam.zmnam_preproc import ( + zmnam_preproc, + zmnam_preproc_clean, +) logger = logging.getLogger(__name__) diff --git a/esmvaltool/recipes/bock20jgr/recipe_bock20jgr_fig_8-10.yml b/esmvaltool/recipes/bock20jgr/recipe_bock20jgr_fig_8-10.yml index a01020e709..bc277209d7 100644 --- a/esmvaltool/recipes/bock20jgr/recipe_bock20jgr_fig_8-10.yml +++ b/esmvaltool/recipes/bock20jgr/recipe_bock20jgr_fig_8-10.yml @@ -434,6 +434,8 @@ diagnostics: exp: historical ensemble: r1i1p1 mip: Amon + modeling_realm: atmos + frequency: mon additional_datasets: *cmip5_all fig_9_cmip6: @@ -446,6 +448,8 @@ diagnostics: exp: historical ensemble: r1i1p1f1 mip: Amon + modeling_realm: atmos + frequency: mon grid: gr additional_datasets: *cmip6_all diff --git a/esmvaltool/recipes/examples/recipe_check_obs.yml b/esmvaltool/recipes/examples/recipe_check_obs.yml index 117a9eb4d3..46c280287b 100644 --- a/esmvaltool/recipes/examples/recipe_check_obs.yml +++ b/esmvaltool/recipes/examples/recipe_check_obs.yml @@ -23,11 +23,10 @@ diagnostics: variables: pr: additional_datasets: - - {project: OBS6, dataset: AGCD, mip: Amon, tier: 3, + - {project: OBS6, dataset: AGCD, mip: Amon, tier: 2, type: ground, version: v2-0-1} scripts: null - BerkeleyEarth: description: BerkeleyEarth check variables: @@ -65,11 +64,33 @@ diagnostics: CRU: description: CRU check variables: - tas: - pr: - additional_datasets: - - {dataset: CRU, project: OBS, mip: Amon, tier: 2, - type: reanaly, version: TS4.02, start_year: 1901, end_year: 2017} + tas: # check older versions + mip: Amon + additional_datasets: + - {dataset: CRU, project: OBS, tier: 2, type: reanaly, + version: TS4.02, start_year: 1901, end_year: 2017} + - {dataset: CRU, project: OBS6, tier: 2, type: reanaly, + version: TS4.07, start_year: 1901, end_year: 2021} + pr: # check older versions + mip: Amon + additional_datasets: + - {dataset: CRU, project: OBS, tier: 2, type: reanaly, + version: TS4.02, start_year: 1901, end_year: 2017} + - {dataset: CRU, project: OBS6, tier: 2, type: reanaly, + version: TS4.07, start_year: 1901, end_year: 2021} + tasmin: + mip: Amon + tasmax: + mip: Amon + clt: + mip: Amon + evspsblpot: + mip: Emon + additional_datasets: # newest version for all variables + - {dataset: CRU, project: OBS6, tier: 2, + type: reanaly, version: TS4.07, start_year: 1901, end_year: 2022} + + scripts: null @@ -275,14 +296,20 @@ diagnostics: ESACCI-SOILMOISTURE: description: ESACCI-SOILMOISTURE check variables: - dos: - dosStderr: - sm: + sm_daily: + short_name: sm + mip: Eday + frequency: day + sm_monthly: + short_name: sm + mip: Lmon + frequency: mon smStderr: + mip: Eday + frequency: day additional_datasets: - - {dataset: ESACCI-SOILMOISTURE, project: OBS, mip: Lmon, tier: 2, - type: sat, version: L3S-SSMV-COMBINED-v4.2, - start_year: 2005, end_year: 2011} + - {dataset: ESACCI-SOILMOISTURE, project: OBS, tier: 2, + type: sat, version: L3S-SSMV-COMBINED-v08.1, start_year: 1978, end_year: 2022} scripts: null @@ -432,7 +459,7 @@ diagnostics: pr: additional_datasets: - {dataset: GPCP-SG, project: OBS, mip: Amon, tier: 2, type: atmos, - version: 2.3, start_year: 1979, end_year: 2022} + version: 2.3, start_year: 1979, end_year: 2022} scripts: null HadCRUT3: @@ -517,7 +544,7 @@ diagnostics: rsutcs: additional_datasets: - {dataset: JRA-25, project: OBS6, mip: Amon, tier: 2, - type: reanaly, version: 1, start_year: 1979, end_year: 2013} + type: reanaly, version: 1, start_year: 1979, end_year: 2007} scripts: null Kadow2020: @@ -905,6 +932,25 @@ diagnostics: ### TIER 3 ################################################################## + AERONET: + description: Aeronet check + variables: + od440aer: + additional_datasets: + - {dataset: AERONET, project: OBS6, mip: AERmon, tier: 3, type: atmos, version: 20240406} + scripts: null + + ANUClimate: + description: ANUClimate check + variables: + pr: + tasmax: + tasmin: + tas: + additional_datasets: + - {dataset: ANUClimate, project: OBS6, mip: Amon, tier: 3, type: reanaly} + scripts: null + APHRO-MA: description: APHRO-MA check variables: @@ -1440,10 +1486,10 @@ diagnostics: short_name: rlns mip: E1hr frequency: 1hr - rlus_E1hr: - short_name: rlus - mip: E1hr - frequency: 1hr + #rlus_E1hr: + # short_name: rlus + # mip: E1hr + # frequency: 1hr rsds_E1hr: short_name: rsds mip: E1hr @@ -1454,10 +1500,10 @@ diagnostics: short_name: rsns mip: E1hr frequency: 1hr - rsus_E1hr: - short_name: rsus - mip: E1hr - frequency: 1hr + #rsus_E1hr: + # short_name: rsus + # mip: E1hr + # frequency: 1hr rss_E1hr: short_name: rss mip: E1hr @@ -1524,9 +1570,9 @@ diagnostics: rlns_Amon: short_name: rlns mip: Amon - rlus_Amon: - short_name: rlus - mip: Amon + #rlus_Amon: + # short_name: rlus + # mip: Amon rsds_Amon: short_name: rsds mip: Amon @@ -1536,9 +1582,9 @@ diagnostics: rsns_Amon: short_name: rsns mip: Amon - rsus_Amon: - short_name: rsus - mip: Amon + #rsus_Amon: + # short_name: rsus + # mip: Amon rss_Amon: short_name: rss mip: Amon diff --git a/esmvaltool/recipes/examples/recipe_easy_ipcc.yml b/esmvaltool/recipes/examples/recipe_easy_ipcc.yml index 40040e2835..af5d711fa8 100644 --- a/esmvaltool/recipes/examples/recipe_easy_ipcc.yml +++ b/esmvaltool/recipes/examples/recipe_easy_ipcc.yml @@ -63,7 +63,7 @@ diagnostics: script: examples/make_plot.py datasets: - - {dataset: ACCESS-CM2, ensemble: 'r(1:5)i1p1f1', grid: gn} + - {dataset: ACCESS-CM2, ensemble: 'r(1:10)i1p1f1', grid: gn} - {dataset: ACCESS-ESM1-5, ensemble: 'r(1:40)i1p1f1', grid: gn} - {dataset: AWI-CM-1-1-MR, ensemble: r1i1p1f1, grid: gn} - {dataset: BCC-CSM2-MR, ensemble: r1i1p1f1, grid: gn} @@ -118,11 +118,11 @@ datasets: - {dataset: MIROC6, ensemble: 'r(1:50)i1p1f1', grid: gn} - {dataset: MPI-ESM1-2-HR, ensemble: 'r1i1p1f1', grid: gn} # - {dataset: MPI-ESM1-2-HR, ensemble: 'r(1:2)i1p1f1', grid: gn} # second ensemble member causes warnings about large graphs in `concatenate` preprocessor step - - {dataset: MPI-ESM1-2-LR, ensemble: 'r(1:30)i1p1f1', grid: gn} + - {dataset: MPI-ESM1-2-LR, ensemble: 'r(1:50)i1p1f1', grid: gn} - {dataset: MRI-ESM2-0, ensemble: 'r(1:5)i1p1f1', grid: gn} # - {dataset: NESM3, ensemble: 'r(1:2)i1p1f1', grid: gn} # cannot be used due to https://github.com/ESMValGroup/ESMValCore/issues/2101 # - {dataset: NorESM2-LM, ensemble: r1i1p1f1, grid: gn} # duplicated areacello file with wrong name - {dataset: NorESM2-MM, ensemble: r1i1p1f1, grid: gn} - - {dataset: TaiESM1, ensemble: r1i1p1f1, grid: gn} + # - {dataset: TaiESM1, ensemble: r1i1p1f1, grid: gn} # download failure of ssp585 - {dataset: UKESM1-0-LL, ensemble: 'r(1:4)i1p1f2', grid: gn} - {dataset: UKESM1-0-LL, ensemble: r8i1p1f2, grid: gn} diff --git a/esmvaltool/recipes/monitor/recipe_monitor_with_refs.yml b/esmvaltool/recipes/monitor/recipe_monitor_with_refs.yml index 681277310c..48c5153287 100644 --- a/esmvaltool/recipes/monitor/recipe_monitor_with_refs.yml +++ b/esmvaltool/recipes/monitor/recipe_monitor_with_refs.yml @@ -225,7 +225,7 @@ diagnostics: ta: preprocessor: global_mean_extract_levels mip: Amon - timerange: '2000/2004' + timerange: '2000/2005' scripts: plot: <<: *plot_multi_dataset_default @@ -238,6 +238,8 @@ diagnostics: log_y: false pyplot_kwargs: ylim: [0, 20000] + xticks: + rotation: 25 plot_time_vs_lat_with_references: description: Plot Hovmoeller time vs. latitude including reference datasets. @@ -245,7 +247,7 @@ diagnostics: tas: mip: Amon preprocessor: zonal_mean_2d - timerange: '2000/2004' + timerange: '2000/2005' scripts: plot: <<: *plot_multi_dataset_default diff --git a/esmvaltool/recipes/recipe_aod_aeronet_assess.yml b/esmvaltool/recipes/recipe_aod_aeronet_assess.yml new file mode 100644 index 0000000000..51cb14759b --- /dev/null +++ b/esmvaltool/recipes/recipe_aod_aeronet_assess.yml @@ -0,0 +1,65 @@ +# ESMValTool +# recipe_aod_aeronet_assess.yml +--- +documentation: + description: | + Recipe to plot seasonal maps of global aerosol optical depth (AOD) at 440nm. + + title: Recipe that runs an AOD diagnostic + + authors: + - hogan_emma + - lillis_jon + - hardacre_catherine + + maintainer: + - hogan_emma + - lillis_jon + - hardacre_catherine + + projects: + - esmval + +preprocessors: + ma_season_mean: + regrid: + target_grid: 2.5x2.5 + scheme: nearest + climate_statistics: + operator: mean + period: season + seasons: ['DJF', 'MAM', 'JJA', 'SON'] + multi_model_statistics: + span: overlap + statistics: [mean] + +diagnostics: + od440aer_climatologies: + description: Visualise spatial multi-annual seasonal means AOD at 440nm. + variables: + + od440aer: &var_od440aer + mip: AERmon + short_name: od440aer + start_year: 1994 + end_year: 2014 + additional_datasets: + - {dataset: AERONET, project: OBS6, mip: AERmon, tier: 3, type: atmos, version: 20240406} + + od440aer_season: + <<: *var_od440aer + preprocessor: ma_season_mean + additional_datasets: + - {dataset: UKESM1-0-LL, project: CMIP6, mip: AERmon, exp: historical, ensemble: r1i1p1f2, grid: gn} + - {dataset: HadGEM3-GC31-LL, project: CMIP6, mip: AERmon, exp: historical, ensemble: r1i1p1f3, grid: gn} + - {dataset: EC-Earth3-AerChem, project: CMIP6, mip: AERmon, exp: historical, ensemble: r1i1p1f1, grid: gn} +# - {dataset: NorESM2-LM, project: CMIP6, mip: AERmon, exp: historical, ensemble: r1i1p1f1, grid: gn} + - {dataset: GFDL-ESM4, project: CMIP6, mip: AERmon, exp: historical, ensemble: r1i1p1f1, grid: gr1} + - {dataset: MPI-ESM-1-2-HAM, project: CMIP6, mip: AERmon, exp: historical, ensemble: r1i1p1f1, grid: gn} + + scripts: + aeronet: + script: aerosols/aod_aeronet_assess.py + observational_dataset: AERONET + quickplot: + plot_type: plot diff --git a/esmvaltool/recipes/recipe_climate_patterns.yml b/esmvaltool/recipes/recipe_climate_patterns.yml new file mode 100644 index 0000000000..08e0c51779 --- /dev/null +++ b/esmvaltool/recipes/recipe_climate_patterns.yml @@ -0,0 +1,249 @@ +# ESMValTool +# recipe_climate_patterns.yml +--- +documentation: + description: Generating climate patterns from CMIP6 models. + title: Generating Climate Patterns + + authors: + - munday_gregory + + maintainer: + - munday_gregory + + references: + - mathison2024gmd + - huntingford2000climdyn + +preprocessors: + global_mean_monthly: + monthly_statistics: + operator: mean + + regrid: + target_grid: {start_longitude: -180, end_longitude: 176.25, step_longitude: 3.75, + start_latitude: -55, end_latitude: 82.5, step_latitude: 2.5} + scheme: linear + + downscale_sftlf: + regrid: + target_grid: {start_longitude: -180, end_longitude: 176.25, step_longitude: 3.75, + start_latitude: -55, end_latitude: 82.5, step_latitude: 2.5} + scheme: linear + +monthly_global_settings: &monthly_global_settings + mip: Amon + project: CMIP6 + preprocessor: global_mean_monthly + +monthly_global_settings_day: &monthly_global_settings_day + mip: day + project: CMIP6 + preprocessor: global_mean_monthly + + +CMIP6_landfrac: &cmip6_landfrac + - {dataset: ACCESS-CM2, exp: piControl, ensemble: r1i1p1f1, grid: gn, institute: CSIRO-ARCCSS} + - {dataset: ACCESS-ESM1-5, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: AWI-CM-1-1-MR, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: BCC-CSM2-MR, exp: hist-resIPO,ensemble: r1i1p1f1, grid: gn} + - {dataset: CanESM5, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: CanESM5-CanOE, exp: piControl, ensemble: r1i1p2f1, grid: gn} + - {dataset: CanESM5-1, exp: piControl, ensemble: r1i1p1f1, grid: gn, institute: CCCma} + # - {dataset: CAS-ESM2-0, exp: piControl, ensemble: r1i1p1f1, grid: gn} # Global only + - {dataset: CMCC-ESM2, exp: piControl, ensemble: r1i1p1f1, grid: gn} + # - {dataset: CMCC-CM2-SR5, exp: piControl, ensemble: r1i1p1f1, grid: gn} # No tasmin/tasmax + - {dataset: CNRM-CM6-1, exp: piControl, ensemble: r1i1p1f2, grid: gr} + - {dataset: CNRM-CM6-1-HR, exp: piControl, ensemble: r1i1p1f2, grid: gr} + - {dataset: CNRM-ESM2-1, exp: piControl, ensemble: r1i1p1f2, grid: gr} + # - {dataset: E3SM-1-0, exp: piControl, ensemble: r1i1p1f1, grid: gr} # Tasmax == tasmin + - {dataset: EC-Earth3, exp: piControl, ensemble: r1i1p1f1, grid: gr} + # - {dataset: EC-Earth3-CC, exp: piControl, ensemble: r1i1p1f1, grid: gr} # Global only + - {dataset: EC-Earth3-Veg, exp: piControl, ensemble: r1i1p1f1, grid: gr} + # - {dataset: FGOALS-f3-L, exp: historical, ensemble: r1i1p1f1, grid: gr} # No tasmin/tasmax + - {dataset: FGOALS-g3, exp: piControl, ensemble: r1i1p1f1, grid: gn} + # - {dataset: FIO-ESM-2-0, exp: piControl, ensemble: r1i1p1f1, grid: gn} # Global only + - {dataset: GFDL-CM4, exp: piControl, ensemble: r1i1p1f1, grid: gr1} + - {dataset: GFDL-ESM4, exp: ssp370, ensemble: r1i1p1f1, grid: gr1} + - {dataset: GISS-E2-1-H, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: GISS-E2-1-G, exp: piControl, ensemble: r1i1p5f1, grid: gn} + - {dataset: GISS-E2-2-G, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: HadGEM3-GC31-LL, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: HadGEM3-GC31-MM, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: INM-CM4-8, exp: piControl, ensemble: r1i1p1f1, grid: gr1} + - {dataset: INM-CM5-0, exp: abrupt-4xCO2, ensemble: r1i1p1f1, grid: gr1} + - {dataset: IPSL-CM6A-LR, exp: piControl, ensemble: r1i1p1f1, grid: gr} + # - {dataset: KACE-1-0-G, exp: piControl, ensemble: r1i1p1f1, grid: gr} # Global only, weird tasmin/tasmax + # - {dataset: KIOST-ESM, exp: piControl, ensemble: r1i1p1f1, grid: gr} # Global only + - {dataset: MIROC6, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: MIROC-ES2L, exp: piControl, ensemble: r1i1p1f2, grid: gn} + - {dataset: MIROC-ES2H, exp: piControl, ensemble: r1i1p4f2, grid: gn} + - {dataset: MPI-ESM1-2-HR, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: MPI-ESM1-2-LR, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: MRI-ESM2-0, exp: piControl, ensemble: r1i1p1f1, grid: gn} + # - {dataset: NorESM2-LM, exp: piControl, ensemble: r1i1p1f1, grid: gn} # Global only, tasmax == tasmin + - {dataset: NorESM2-MM, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: TaiESM1, exp: piControl, ensemble: r1i1p1f1, grid: gn} + - {dataset: UKESM1-0-LL, exp: piControl, ensemble: r1i1p1f2, grid: gn} + +CMIP6_no_tasmax: &cmip6_no_tasmax + # - {dataset: E3SM-1-0, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2099} # bad tasmin/tasmax + # - {dataset: NorESM2-LM, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} # bad tasmin/tasmax + - {dataset: NorESM2-MM, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: TaiESM1, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + +CMIP6_DAY: &cmip6_day + # - {dataset: E3SM-1-0, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2099} # bad tasmin/tasmax + # - {dataset: NorESM2-LM, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} # bad tasmin/tasmax + - {dataset: NorESM2-MM, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: TaiESM1, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + +CMIP6_FULL: &cmip6_full + - {dataset: ACCESS-CM2, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100, institute: CSIRO-ARCCSS} + - {dataset: ACCESS-ESM1-5, exp: [historical, ssp585], ensemble: r3i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: AWI-CM-1-1-MR, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: BCC-CSM2-MR, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: CanESM5, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: CanESM5-1, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100, institute: CCCma} # optional extra + - {dataset: CanESM5-CanOE, exp: [historical, ssp585], ensemble: r1i1p2f1, grid: gn, start_year: 1850, end_year: 2100} + # - {dataset: CAS-ESM2-0, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} # Global only + - {dataset: CMCC-ESM2, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + # - {dataset: CMCC-CM2-SR5, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} # No tasmin/tasmax + - {dataset: CNRM-CM6-1, exp: [historical, ssp585], ensemble: r1i1p1f2, grid: gr, start_year: 1850, end_year: 2100} + - {dataset: CNRM-CM6-1-HR, exp: [historical, ssp585], ensemble: r1i1p1f2, grid: gr, start_year: 1850, end_year: 2100} + - {dataset: CNRM-ESM2-1, exp: [historical, ssp585], ensemble: r1i1p1f2, grid: gr, start_year: 1850, end_year: 2100} + - {dataset: EC-Earth3, exp: [historical, ssp585], ensemble: r11i1p1f1, grid: gr, start_year: 1850, end_year: 2100} + # - {dataset: EC-Earth3-CC, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2100} # Global only + - {dataset: EC-Earth3-Veg, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2100} + # - {dataset: FGOALS-f3-L, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2100} # No tasmin/tasmax + - {dataset: FGOALS-g3, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + # - {dataset: FIO-ESM-2-0, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} # Global only + - {dataset: GFDL-CM4, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr1, start_year: 1850, end_year: 2100} + - {dataset: GFDL-ESM4, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr1, start_year: 1850, end_year: 2100} + - {dataset: GISS-E2-1-H, exp: [historical, ssp585], ensemble: r3i1p1f2, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: GISS-E2-1-G, exp: [historical, ssp585], ensemble: r1i1p5f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: GISS-E2-2-G, exp: [historical, ssp585], ensemble: r1i1p3f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: HadGEM3-GC31-LL, exp: [historical, ssp585], ensemble: r1i1p1f3, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: HadGEM3-GC31-MM, exp: [historical, ssp585], ensemble: r1i1p1f3, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: INM-CM4-8, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr1, start_year: 1850, end_year: 2100} + - {dataset: INM-CM5-0, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr1, start_year: 1850, end_year: 2100} + - {dataset: IPSL-CM6A-LR, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2100} + # - {dataset: KACE-1-0-G, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2100} # bad tasmin/tasmax + # - {dataset: KIOST-ESM, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gr, start_year: 1850, end_year: 2100} # optional extra + - {dataset: MIROC6, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: MIROC-ES2L, exp: [historical, ssp585], ensemble: r1i1p1f2, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: MIROC-ES2H, exp: [historical, ssp585], ensemble: r1i1p4f2, grid: gn, start_year: 1850, end_year: 2100} # optional extra + - {dataset: MPI-ESM1-2-HR, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: MPI-ESM1-2-LR, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: MRI-ESM2-0, exp: [historical, ssp585], ensemble: r1i1p1f1, grid: gn, start_year: 1850, end_year: 2100} + - {dataset: UKESM1-0-LL, exp: [historical, ssp585], ensemble: r1i1p1f2, grid: gn, start_year: 1850, end_year: 2100} + +diagnostics: + monthly_timeseries: + description: Mean monthly variables + + variables: + + # sftlf: + # short_name: sftlf + # mip: fx + # project: CMIP6 + # preprocessor: downscale_sftlf + # additional_datasets: *cmip6_landfrac + + tasmax_585: + short_name: tasmax + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + tasmin_585: + short_name: tasmin + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + tas_585: + short_name: tas + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + huss_585: + short_name: huss + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + pr_585: + short_name: pr + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + sfcWind_585: + short_name: sfcWind + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + ps_585: + short_name: ps + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + rsds_585: + short_name: rsds + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + rlds_585: + short_name: rlds + <<: *monthly_global_settings + additional_datasets: *cmip6_full + + tasmax_585_day: + short_name: tasmax + <<: *monthly_global_settings_day + additional_datasets: *cmip6_day + + tasmin_585_day: + short_name: tasmin + <<: *monthly_global_settings_day + additional_datasets: *cmip6_day + + tas_585_no_tasmax: + short_name: tas + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + huss_585_no_tasmax: + short_name: huss + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + pr_585_no_tasmax: + short_name: pr + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + sfcWind_585_no_tasmax: + short_name: sfcWind + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + ps_585_no_tasmax: + short_name: ps + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + rsds_585_no_tasmax: + short_name: rsds + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + rlds_585_no_tasmax: + short_name: rlds + <<: *monthly_global_settings + additional_datasets: *cmip6_no_tasmax + + scripts: + climate_patterns_script: + script: climate_patterns/climate_patterns.py + jules_mode: false # options: true, false + parallelise: false # options: true, false + area: global # options global, land. If land, uncomment landfrac recipe settings diff --git a/esmvaltool/recipes/recipe_ocean_quadmap.yml b/esmvaltool/recipes/recipe_ocean_quadmap.yml index 4afc2c7bb5..2f20a50015 100644 --- a/esmvaltool/recipes/recipe_ocean_quadmap.yml +++ b/esmvaltool/recipes/recipe_ocean_quadmap.yml @@ -54,12 +54,10 @@ diagnostics: preprocessor: prep_quad_map mip: Omon additional_datasets: -# filename: tos_ATSR_L3_ARC-v1.1.1_199701-201112.nc -# download from: https://datashare.is.ed.ac.uk/handle/10283/536 - - {dataset: ATSR, project: obs4MIPs, level: L3, version: ARC-v1.1.1, start_year: 2001, end_year: 2003, tier: 1} + - {dataset: ARC-SST-1-1, project: obs4MIPs, level: L3, start_year: 2001, end_year: 2003, tier: 1} scripts: Global_Ocean_map: &Global_Ocean_map script: ocean/diagnostic_maps_quad.py control_model: {dataset: HadGEM2-CC, project: CMIP5, mip: Omon, exp: historical, ensemble: r1i1p1} exper_model: {dataset: HadGEM2-ES, project: CMIP5, mip: Omon, exp: historical, ensemble: r1i1p1} - observational_dataset: {dataset: ATSR, project: obs4MIPs,} + observational_dataset: {dataset: ARC-SST-1-1, project: obs4MIPs,} diff --git a/esmvaltool/references/aeronetv3.bibtex b/esmvaltool/references/aeronetv3.bibtex new file mode 100644 index 0000000000..ac05ed0f31 --- /dev/null +++ b/esmvaltool/references/aeronetv3.bibtex @@ -0,0 +1,6 @@ +@misc{aeronetv3, + author = {}, + title = {}, + url = {https://aeronet.gsfc.nasa.gov/new_web/download_all_v3_aod.html}, + year = 2023 +} diff --git a/esmvaltool/references/anuclimate2.bibtex b/esmvaltool/references/anuclimate2.bibtex new file mode 100644 index 0000000000..0c183cd181 --- /dev/null +++ b/esmvaltool/references/anuclimate2.bibtex @@ -0,0 +1,11 @@ +@misc{https://doi.org/10.25914/60a10aa56dd1b, + doi = {10.25914/60A10AA56DD1B}, + url = {https://pid.nci.org.au/doi/f2576_7854_4065_1457}, + author = {Hutchinson, Michael and Xu, Tingbao and Kesteven, Jennifer and Marang, Ian and Evans, Bradley}, + keywords = {Climatology (excl. Climate Change Processes)}, + language = {en}, + title = {ANUClimate 2.0}, + publisher = {NCI Australia}, + year = {2021}, + copyright = {Creative Commons Attribution Share Alike 4.0 International} +} diff --git a/esmvaltool/references/cru.bibtex b/esmvaltool/references/cru.bibtex index 0598abcc00..7de9c36f5e 100644 --- a/esmvaltool/references/cru.bibtex +++ b/esmvaltool/references/cru.bibtex @@ -1,13 +1,16 @@ @article{cru, - doi = {10.1002/joc.3711}, - url = {https://doi.org/10.1002%2Fjoc.3711}, - year = 2013, - month = {may}, - publisher = {Wiley}, - volume = {34}, - number = {3}, - pages = {623--642}, - author = {I. Harris and P.D. Jones and T.J. Osborn and D.H. Lister}, - title = {Updated high-resolution grids of monthly climatic observations - the {CRU} {TS}3.10 Dataset}, - journal = {International Journal of Climatology} -} + title = {Version 4 of the {{CRU TS}} Monthly High-Resolution Gridded Multivariate Climate Dataset}, + author = {Harris, Ian and Osborn, Timothy J. and Jones, Phil and Lister, David}, + date = {2020-04-03}, + year = 2020, + month = {april}, + journaltitle = {Sci Data}, + volume = {7}, + number = {1}, + pages = {109}, + publisher = {{Nature Publishing Group}}, + issn = {2052-4463}, + doi = {10.1038/s41597-020-0453-3}, + url = {https://www.nature.com/articles/s41597-020-0453-3}, + urldate = {2023-10-12}, +} \ No newline at end of file diff --git a/esmvaltool/references/esacci-soilmoisture.bibtex b/esmvaltool/references/esacci-soilmoisture.bibtex index 59e275d6c4..7e4404a8f4 100644 --- a/esmvaltool/references/esacci-soilmoisture.bibtex +++ b/esmvaltool/references/esacci-soilmoisture.bibtex @@ -1,13 +1,115 @@ @article{esacci-soilmoisture, - doi = {10.5194/hess-15-425-2011}, - url = {https://doi.org/10.5194%2Fhess-15-425-2011}, - year = 2011, - month = {feb}, - publisher = {Copernicus {GmbH}}, - volume = {15}, - number = {2}, - pages = {425--436}, - author = {Y. Y. Liu and R. M. Parinussa and W. A. Dorigo and R. A. M. De Jeu and W. Wagner and A. I. J. M. van Dijk and M. F. McCabe and J. P. Evans}, - title = {Developing an improved soil moisture dataset by blending passive and active microwave satellite-based retrievals}, - journal = {Hydrology and Earth System Sciences} + doi = {10.5194/essd-11-717-2019}, + title = {Evolution of the {ESA} {CCI} Soil Moisture climate data records + and their underlying merging methodology}, + author = {Gruber, Alexander and Scanlon, Tracy and van der Schalie, Robin + and Wagner, Wolfgang and Dorigo, Wouter}, + abstract = {The European Space Agency's Climate Change Initiative + for Soil Moisture (ESA CCI SM) merging algorithm generates + consistent quality-controlled long-term (1978--2018) climate + data records for soil moisture, which serves thousands of + scientists and data users worldwide. It harmonises and merges + soil moisture retrievals from multiple satellites into (i) an + active-microwave-based-only product, (ii) a + passive-microwave-based-only product and (iii) a combined + active--passive product, which are sampled to daily global + images on a 0.25∘ regular grid. Since its first release in 2012 + the algorithm has undergone substantial improvements which have + so far not been thoroughly reported in the scientific + literature. This paper fills this gap by reviewing and + discussing the science behind the three major ESA CCI SM merging + algorithms, versions 2 + (https://doi.org/10.5285/3729b3fbbb434930bf65d82f9b00111c; + Wagner et al., 2018), 3 + (https://doi.org/10.5285/b810601740bd4848b0d7965e6d83d26c; + Dorigo et al., 2018) and 4 + (https://doi.org/10.5285/dce27a397eaf47e797050c220972ca0e; + Dorigo et al., 2019), and provides an outlook on the expected + improvements planned for the next algorithm, version 5.}, + journal = {Earth Syst. Sci. Data}, + publisher = {Copernicus GmbH}, + volume = {11}, + number = {2}, + pages = {717--739}, + month = {may}, + year = 2019 } + +@article{esacci-soilmoisture, + doi = {10.1016/j.rse.2017.07.001}, + title = {{ESA} {CCI} Soil Moisture for improved Earth system + understanding: State-of-the art and future directions}, + author = {Dorigo, Wouter and Wagner, Wolfgang and Albergel, Clement and + Albrecht, Franziska and Balsamo, Gianpaolo and Brocca, Luca and + Chung, Daniel and Ertl, Martin and Forkel, Matthias and Gruber, + Alexander and Haas, Eva and Hamer, Paul D and Hirschi, Martin + and Ikonen, Jaakko and de Jeu, Richard and Kidd, Richard and + Lahoz, William and Liu, Yi Y and Miralles, Diego and + Mistelbauer, Thomas and Nicolai-Shaw, Nadine and Parinussa, + Robert and Pratola, Chiara and Reimer, Christoph and van der + Schalie, Robin and Seneviratne, Sonia I and Smolander, Tuomo and + Lecomte, Pascal}, + abstract = {Climate Data Records of soil moisture are fundamental for + improving our understanding of long-term dynamics in the coupled + water, energy, and carbon cycles over land. To respond to this + need, in 2012 the European Space Agency (ESA) released the first + multi-decadal, global satellite-observed soil moisture (SM) + dataset as part of its Climate Change Initiative (CCI) program. + This product, named ESA CCI SM, combines various single-sensor + active and passive microwave soil moisture products into three + harmonised products: a merged ACTIVE, a merged PASSIVE, and a + COMBINED active + passive microwave product. Compared to the + first product release, the latest version of ESA CCI SM includes + a large number of enhancements, incorporates various new + satellite sensors, and extends its temporal coverage to the + period 1978--2015. In this study, we first provide a + comprehensive overview of the characteristics, evolution, and + performance of the ESA CCI SM products. Based on original + research and a review of existing literature we show that the + product quality has steadily increased with each successive + release and that the merged products generally outperform the + single-sensor input products. Although ESA CCI SM generally + agrees well with the spatial and temporal patterns estimated by + land surface models and observed in-situ, we identify surface + conditions (e.g., dense vegetation, organic soils) for which it + still has large uncertainties. Second, capitalising on the + results of > 100 research studies that made use of the ESA CCI + SM data we provide a synopsis of how it has contributed to + improved process understanding in the following Earth system + domains: climate variability and change, land-atmosphere + interactions, global biogeochemical cycles and ecology, + hydrological and land surface modelling, drought applications, + and meteorology. While in some disciplines the use of ESA CCI SM + is already widespread (e.g. in the evaluation of model soil + moisture states) in others (e.g. in numerical weather prediction + or flood forecasting) it is still in its infancy. The latter is + partly related to current shortcomings of the product, e.g., the + lack of near-real-time availability and data gaps in time and + space. This study discloses the discrepancies between current + ESA CCI SM product characteristics and the preferred + characteristics of long-term satellite soil moisture products as + outlined by the Global Climate Observing System (GCOS), and + provides important directions for future ESA CCI SM product + improvements to bridge these gaps.}, + journal = {Remote Sens. Environ.}, + publisher = {Elsevier BV", + volume = {203}, + pages = {185--215}, + month = {dec}, + year = 2017 +} + +@article{esacci-soilmoisture, + doi = {10.1109/TGRS.2020.3012896}, + title = {Homogenization of structural breaks in the global {ESA} {CCI} + soil moisture multisatellite climate data record}, + author = {Preimesberger, Wolfgang and Scanlon, Tracy and Su, Chun-Hsu and + Gruber, Alexander and Dorigo, Wouter}, + journal = {IEEE Trans. Geosci. Remote Sens.}, + publisher = {Institute of Electrical and Electronics Engineers (IEEE)}, + volume = {159}, + number = {14}, + pages = {12845--2862}, + month = {apr}, + year = 2021 +} \ No newline at end of file diff --git a/esmvaltool/references/huntingford2000climdyn.bibtex b/esmvaltool/references/huntingford2000climdyn.bibtex new file mode 100644 index 0000000000..69bc072d49 --- /dev/null +++ b/esmvaltool/references/huntingford2000climdyn.bibtex @@ -0,0 +1,14 @@ +@article{huntingford2000, + title = {An analogue model to derive additional climate change scenarios from existing {GCM} simulations}, + volume = {16}, + issn = {1432-0894}, + url = {https://doi.org/10.1007/s003820000067}, + doi = {10.1007/s003820000067}, + abstract = {Changes in land surface driving variables, predicted by GCM transient climate change experiments, are confirmed to exhibit linearity in the global mean land temperature anomaly, ΔTl. The associated constants of proportionality retain spatial and seasonal characteristics of the GCM output, whilst ΔTlis related to radiative forcing anomalies. The resultant analogue model is shown to be robust between GCM runs and as such provides a computationally efficient technique of extending existing GCM experiments to a large range of climate change scenarios. As an example impacts study, the analogue model is used to drive a terrestrial ecosystem model, and predicted changes in terrestrial carbon are found to be similar to those when using GCM anomalies directly.}, + number = {8}, + journal = {Climate Dynamics}, + author = {Huntingford, C. and Cox, P. M.}, + month = aug, + year = {2000}, + pages = {575--586}, +} diff --git a/esmvaltool/references/mathison2024gmd.bibtex b/esmvaltool/references/mathison2024gmd.bibtex new file mode 100644 index 0000000000..a6090db6c7 --- /dev/null +++ b/esmvaltool/references/mathison2024gmd.bibtex @@ -0,0 +1,10 @@ +@Article{mathison2024, + AUTHOR = {Mathison, C. T. and Burke, E. and Kovacs, E. and Munday, G. and Huntingford, C. and Jones, C. and Smith, C. and Steinert, N. and Wiltshire, A. and Gohar, L. and Varney, R.}, + TITLE = {A rapid application emissions-to-impacts tool for scenario assessment: Probabilistic Regional Impacts from Model patterns and Emissions (PRIME)}, + JOURNAL = {EGUsphere}, + VOLUME = {2024}, + YEAR = {2024}, + PAGES = {1--28}, + URL = {https://egusphere.copernicus.org/preprints/2024/egusphere-2023-2932/}, + DOI = {10.5194/egusphere-2023-2932} +} diff --git a/setup.cfg b/setup.cfg index c738c5d716..e28f8079a0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,6 @@ [tool:pytest] addopts = + --import-mode=importlib --doctest-modules --ignore=doc/sphinx/source/conf.py --cov=esmvaltool diff --git a/setup.py b/setup.py index 16a76cec75..df8477d27f 100755 --- a/setup.py +++ b/setup.py @@ -27,15 +27,16 @@ 'cf-units', 'cftime', 'cmocean', - 'dask', + 'dask!=2024.8.0', # https://github.com/dask/dask/issues/11296 'distributed', 'ecmwf-api-client', 'eofs', - 'ESMPy', + 'ESMPy', # not on PyPI 'esmvalcore', - 'esmf-regrid>=0.7.0', + 'esmf-regrid>=0.10.0', # iris-esmf-regrid #342 'fiona', 'fire', + 'fsspec', 'GDAL', 'jinja2', 'joblib', @@ -49,13 +50,14 @@ 'numpy!=1.24.3', # severe masking bug 'openpyxl', 'packaging', - 'pandas', + 'pandas!=2.2.0,!=2.2.1,!=2.2.2', # ESMValCore PR2305 'progressbar2', 'psyplot', 'psy-maps', 'psy-reg', 'psy-simple', 'pyproj>=2.1', + 'pys2index', 'python-dateutil', 'pyyaml', 'rasterio', @@ -74,8 +76,8 @@ 'xlsxwriter', 'zarr', ], - # Test dependencies - # Execute `pip install .[test]` once and the use `pytest` to run tests + # Test dependencies (unit tests) + # Execute `pip install .[test]` once and then use `pytest` to run tests 'test': [ 'flake8', 'pytest>=3.9,!=6.0.0rc1,!=6.0.0', @@ -98,6 +100,7 @@ 'develop': [ 'codespell', 'docformatter', + 'imagehash', 'isort', 'pre-commit', 'prospector[with_pyroma]!=1.1.6.3,!=1.1.6.4', @@ -218,7 +221,6 @@ def read_description(filename): 'Natural Language :: English', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Topic :: Scientific/Engineering', diff --git a/tests/unit/test_lint.py b/tests/unit/test_lint.py index ea49d6b069..5951a8f32a 100644 --- a/tests/unit/test_lint.py +++ b/tests/unit/test_lint.py @@ -67,5 +67,5 @@ def test_r_lint(monkeypatch): """)) print(ex.output) - assert False,\ + assert False, \ 'Your R code does not follow our formatting standards.'